Suppress FindBugs concurrency warning which is wrong
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / statistics / ofpspecific / EventsTimeCounter.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.openflowplugin.impl.statistics.ofpspecific;
10
11 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
12 import java.util.ArrayList;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.concurrent.TimeUnit;
17 import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.EventIdentifier;
18
19 public final class EventsTimeCounter {
20
21     private static final Map<String, Map<String, EventTimeCounter>> DEVICES_EVENTS = new HashMap<>();
22
23     private EventsTimeCounter() {
24         // Hiding implicit constructor
25     }
26
27     public static void markStart(final EventIdentifier eventIdentifier) {
28         Map<String, EventTimeCounter> deviceEvents = getOrCreateCountersForDevice(eventIdentifier.getDeviceId());
29         EventTimeCounter eventTimeCounter = getOrCreateEventOfType(eventIdentifier.getEventName(), deviceEvents);
30         eventTimeCounter.markStart();
31     }
32
33     public static void markEnd(final EventIdentifier eventIdentifier) {
34         Map<String, EventTimeCounter> deviceEvents = getOrCreateCountersForDevice(eventIdentifier.getDeviceId());
35         EventTimeCounter eventTimeCounter = getOrCreateEventOfType(eventIdentifier.getEventName(), deviceEvents);
36         eventTimeCounter.markEnd();
37     }
38
39     private static EventTimeCounter getOrCreateEventOfType(final String event,
40                                                            final Map<String, EventTimeCounter> deviceEvents) {
41         return deviceEvents.computeIfAbsent(event, k -> new EventTimeCounter());
42     }
43
44     private static Map<String, EventTimeCounter> getOrCreateCountersForDevice(final String deviceId) {
45         return DEVICES_EVENTS.computeIfAbsent(deviceId, k -> new HashMap<>());
46     }
47
48     public static List<String> provideTimes() {
49         List<String> dump = new ArrayList<>();
50         for (Map.Entry<String, Map<String, EventTimeCounter>> deviceEntry : DEVICES_EVENTS.entrySet()) {
51             Map<String, EventTimeCounter> eventsMap = deviceEntry.getValue();
52             dump.add("================================================");
53             dump.add(String.format("DEVICE : %s", deviceEntry.getKey()));
54             for (Map.Entry<String, EventTimeCounter> eventEntry : eventsMap.entrySet()) {
55                 final String eventName = eventEntry.getKey();
56                 final EventTimeCounter eventTimeCounter = eventEntry.getValue();
57                 dump.add(String.format("%s", eventName));
58                 dump.add(String.format("    MIN TIME (ms):  %d",
59                         TimeUnit.MILLISECONDS.convert(eventTimeCounter.getMinimum(), TimeUnit.NANOSECONDS)));
60                 dump.add(String.format("    MAX TIME (ms):  %d",
61                         TimeUnit.MILLISECONDS.convert(eventTimeCounter.getMaximum(), TimeUnit.NANOSECONDS)));
62                 dump.add(String.format("    AVG TIME (ms):  %d",
63                         TimeUnit.MILLISECONDS.convert(eventTimeCounter.getAverage(), TimeUnit.NANOSECONDS)));
64
65             }
66         }
67         return dump;
68     }
69
70     public static void resetAllCounters() {
71         DEVICES_EVENTS.clear();
72     }
73
74
75     private static final class EventTimeCounter {
76
77         private volatile long delta = 0;
78         private volatile long average = 0;
79         private volatile long minimum = 0;
80         private volatile long maximum = 0;
81         private volatile long summary = 0;
82         private volatile int counter = 0;
83
84         public synchronized void markStart() {
85             delta = System.nanoTime();
86         }
87
88         @SuppressFBWarnings("VO_VOLATILE_INCREMENT") // counter++ is volatile, but this is synchronized, so OK
89         public synchronized void markEnd() {
90             if (0 == delta) {
91                 return;
92             }
93             counter++;
94             delta = System.nanoTime() - delta;
95
96             if (delta < minimum || minimum == 0) {
97                 minimum = delta;
98             }
99             if (delta > maximum) {
100                 maximum = delta;
101             }
102             if (average > 0 && delta > average * 1.8) {
103                 summary += average;
104             } else {
105                 summary += delta;
106             }
107             average = summary / counter;
108         }
109
110         public synchronized void resetCounters() {
111             delta = 0;
112             average = 0;
113             minimum = 0;
114             maximum = 0;
115             summary = 0;
116             counter = 0;
117
118         }
119
120         public synchronized long getAverage() {
121             return average;
122         }
123
124         public synchronized long getMinimum() {
125             return minimum;
126         }
127
128         public synchronized long getMaximum() {
129             return maximum;
130         }
131
132     }
133 }