blob: 15e5cdc729fc7eb06aa32d6063d1f1a801bb3d07 [file] [log] [blame]
Brian O'Connor8fdfb062014-01-08 17:47:57 -08001package net.onrc.onos.ofcontroller.flowmanager;
2
Brian O'Connor2daf7a92014-01-14 11:26:35 -08003import java.util.Map.Entry;
Brian O'Connora5e5f832014-01-15 16:58:14 -08004import java.util.Queue;
Brian O'Connor8fdfb062014-01-08 17:47:57 -08005import java.util.concurrent.ConcurrentHashMap;
Brian O'Connora5e5f832014-01-15 16:58:14 -08006import java.util.concurrent.ConcurrentLinkedQueue;
Brian O'Connor8fdfb062014-01-08 17:47:57 -08007
8import org.slf4j.Logger;
9import org.slf4j.LoggerFactory;
10
11/**
12 * Class for collecting performance measurements
13 */
14public class PerformanceMonitor {
Brian O'Connor8fdfb062014-01-08 17:47:57 -080015 private final static Logger log = LoggerFactory.getLogger(PerformanceMonitor.class);
Yuta HIGUCHI8f281452014-02-18 16:08:04 -080016
17 // experiment name -> PerformanceMonitor
18 private static final ConcurrentHashMap<String,PerformanceMonitor> perfMons = new ConcurrentHashMap<>();
19 public static PerformanceMonitor experiment(String name) {
20 PerformanceMonitor pm = perfMons.get(name);
21 if (pm == null) {
22 pm = new PerformanceMonitor();
23 PerformanceMonitor existing = perfMons.putIfAbsent(name, pm);
24 if (existing != null) {
25 pm = existing;
26 }
27 }
28 return pm;
29 }
30
31 // tag -> Measurements
32 private final ConcurrentHashMap<String, Queue<Measurement>> map = new ConcurrentHashMap<>();
33 private long overhead;
34 private long experimentStart = Long.MAX_VALUE;
Brian O'Connor2daf7a92014-01-14 11:26:35 -080035 private final static double normalization = Math.pow(10, 6);
36
Brian O'Connor8fdfb062014-01-08 17:47:57 -080037 /**
38 * Start a performance measurement, identified by a tag
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080039 *
Brian O'Connor8fdfb062014-01-08 17:47:57 -080040 * Note: Only a single measurement can use the same tag at a time.
Brian O'Connor2daf7a92014-01-14 11:26:35 -080041 * ..... not true anymore.
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080042 *
Brian O'Connor8fdfb062014-01-08 17:47:57 -080043 * @param tag for performance measurement
44 */
Yuta HIGUCHI8f281452014-02-18 16:08:04 -080045 public Measurement startStep(String tag) {
Brian O'Connor8fdfb062014-01-08 17:47:57 -080046 long start = System.nanoTime();
Brian O'Connor2daf7a92014-01-14 11:26:35 -080047 if(start < experimentStart) {
48 experimentStart = start;
Brian O'Connor8fdfb062014-01-08 17:47:57 -080049 }
Brian O'Connora5e5f832014-01-15 16:58:14 -080050 Queue<Measurement> list = map.get(tag);
Brian O'Connor2daf7a92014-01-14 11:26:35 -080051 if(list == null) {
Brian O'Connora5e5f832014-01-15 16:58:14 -080052 list = new ConcurrentLinkedQueue<Measurement>();
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080053 Queue<Measurement> existing_list = map.putIfAbsent(tag, list);
54 if (existing_list != null) {
55 // someone concurrently added, using theirs
56 list = existing_list;
57 }
Brian O'Connor2daf7a92014-01-14 11:26:35 -080058 }
59 Measurement m = new Measurement();
60 list.add(m);
Brian O'Connor8fdfb062014-01-08 17:47:57 -080061 m.start();
62 overhead += System.nanoTime() - start;
Brian O'Connor2daf7a92014-01-14 11:26:35 -080063 return m;
Brian O'Connor8fdfb062014-01-08 17:47:57 -080064 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080065
Brian O'Connor8fdfb062014-01-08 17:47:57 -080066 /**
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080067 * Stop a performance measurement.
68 *
Brian O'Connor8fdfb062014-01-08 17:47:57 -080069 * You must have already started a measurement with tag.
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080070 *
Brian O'Connor8fdfb062014-01-08 17:47:57 -080071 * @param tag for performance measurement
72 */
Yuta HIGUCHI8f281452014-02-18 16:08:04 -080073 public void stopStep(String tag) {
Brian O'Connor8fdfb062014-01-08 17:47:57 -080074 long time = System.nanoTime();
Brian O'Connora5e5f832014-01-15 16:58:14 -080075 Queue<Measurement> list = map.get(tag);
brian6df88232014-01-14 17:05:07 -080076 if(list == null || list.size() == 0) {
Brian O'Connor8fdfb062014-01-08 17:47:57 -080077 log.error("Tag {} does not exist", tag);
78 }
Brian O'Connora5e5f832014-01-15 16:58:14 -080079 list.peek().stop(time);
brian6df88232014-01-14 17:05:07 -080080 if(list.size() > 1) {
Brian O'Connor2daf7a92014-01-14 11:26:35 -080081 log.error("Tag {} has multiple measurements", tag);
Brian O'Connor8fdfb062014-01-08 17:47:57 -080082 }
83 overhead += System.nanoTime() - time;
84 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080085
Brian O'Connor8fdfb062014-01-08 17:47:57 -080086 /**
87 * Clear all performance measurements.
88 */
Yuta HIGUCHI8f281452014-02-18 16:08:04 -080089 public void reset() {
Brian O'Connor8fdfb062014-01-08 17:47:57 -080090 map.clear();
91 overhead = 0;
Brian O'Connor2daf7a92014-01-14 11:26:35 -080092 experimentStart = Long.MAX_VALUE;
Brian O'Connor8fdfb062014-01-08 17:47:57 -080093 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080094
Brian O'Connor8fdfb062014-01-08 17:47:57 -080095 /**
96 * Write all performance measurements to the log
97 */
Yuta HIGUCHI8f281452014-02-18 16:08:04 -080098 public void reportAll() {
Brian O'Connor2daf7a92014-01-14 11:26:35 -080099 String result = "Performance Results: (avg/start/stop/count)\n";
Brian O'Connor0d9963f2014-01-14 14:44:21 -0800100 if(map.size() == 0) {
101 result += "No Measurements";
102 log.error(result);
103 return;
104 }
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800105 long experimentEnd = -1;
Brian O'Connora5e5f832014-01-15 16:58:14 -0800106 for(Entry<String, Queue<Measurement>> e : map.entrySet()) {
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800107 String key = e.getKey();
Brian O'Connora5e5f832014-01-15 16:58:14 -0800108 Queue<Measurement> list = e.getValue();
Brian O'Connorc7518832014-01-16 10:50:04 -0800109 long total = 0, count = 0;
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800110 long start = Long.MAX_VALUE, stop = -1;
111 for(Measurement m : list) {
brian6df88232014-01-14 17:05:07 -0800112 if(m.stop < 0) {
113 continue; // measurement has not been stopped
114 }
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800115 // Collect overall start and end times
116 if(m.start < start) {
117 start = m.start;
118 }
119 if(m.stop > stop) {
120 stop = m.stop;
121 if(stop > experimentEnd) {
122 experimentEnd = stop;
123 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800124 }
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800125 // Collect statistics for average
126 total += m.elapsed();
127 count++;
128 }
129 double avg = (double) total / count;
130 // Normalize start/stop
131 start -= experimentStart;
132 stop -= experimentStart;
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800133 result += key + '=' +
134 (avg / normalization) + '/' +
135 (start / normalization) + '/' +
136 (stop / normalization) + '/' +
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800137 count + '\n';
138 }
139 double overheadMs = overhead / normalization;
140 double experimentElapsed = (experimentEnd - experimentStart) / normalization;
141 result += "TotalTime:" + experimentElapsed + "/Overhead:" + overheadMs;
142 log.error(result);
143// log.error("Performance Results: {} with measurement overhead: {} ms", map, overheadMilli);
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800144 }
Pavlin Radoslavovb5e31782014-01-12 20:11:46 -0800145
146 /**
147 * Write the performance measurement for a tag to the log
148 *
149 * @param tag the tag name.
150 */
Yuta HIGUCHI8f281452014-02-18 16:08:04 -0800151 public void reportStep(String tag) {
Brian O'Connora5e5f832014-01-15 16:58:14 -0800152 Queue<Measurement> list = map.get(tag);
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800153 if(list == null) {
154 return; //TODO
155 }
156 //TODO: fix this;
Brian O'Connora5e5f832014-01-15 16:58:14 -0800157 Measurement m = list.peek();
Pavlin Radoslavovb5e31782014-01-12 20:11:46 -0800158 if (m != null) {
Brian O'Connor0d9963f2014-01-14 14:44:21 -0800159 log.error("Performance Result: tag = {} start = {} stop = {} elapsed = {}",
Pavlin Radoslavovb5e31782014-01-12 20:11:46 -0800160 tag, m.start, m.stop, m.toString());
161 } else {
Brian O'Connor0d9963f2014-01-14 14:44:21 -0800162 log.error("Performance Result: unknown tag {}", tag);
Pavlin Radoslavovb5e31782014-01-12 20:11:46 -0800163 }
164 }
165
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800166 /**
167 * A single performance measurement
168 */
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800169 public static class Measurement {
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800170 long start;
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800171 long stop = -1;
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800172
173 /**
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800174 * Start the measurement
175 */
176 public void start() {
brian6df88232014-01-14 17:05:07 -0800177 if(start <= 0) {
178 start = System.nanoTime();
179 }
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800180 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800181
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800182 /**
183 * Stop the measurement
184 */
185 public void stop() {
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800186 long now = System.nanoTime();
187 stop(now);
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800188 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800189
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800190 /**
191 * Stop the measurement at a specific time
192 * @param time to stop
193 */
194 public void stop(long time){
brian6df88232014-01-14 17:05:07 -0800195 if(stop <= 0) {
196 stop = time;
197 }
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800198 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800199
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800200 /**
201 * Compute the elapsed time of the measurement in nanoseconds
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800202 *
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800203 * @return the measurement time in nanoseconds, or -1 if the measurement is stil running.
204 */
205 public long elapsed() {
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800206 if(stop <= 0) {
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800207 return -1;
208 }
209 else {
210 return stop - start;
211 }
212 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800213
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800214 /**
215 * Returns the number of milliseconds for the measurement as a String.
216 */
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800217 @Override
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800218 public String toString() {
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800219 double milli = elapsed() / normalization;
220 double startMs = start / normalization;
221 double stopMs = stop / normalization;
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800222
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800223 return milli + "ms/" + startMs + '/' + stopMs;
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800224 }
225 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800226
Yuta HIGUCHI8f281452014-02-18 16:08:04 -0800227 @Deprecated
228 private static final PerformanceMonitor theInstance = new PerformanceMonitor();
229
230 @Deprecated
231 public static Measurement start(String tag) {
232 return theInstance.startStep(tag);
233 }
234
235 @Deprecated
236 public static void stop(String tag) {
237 theInstance.stopStep(tag);;
238 }
239
240 @Deprecated
241 public static void clear() {
242 theInstance.reset();;
243 }
244
245 @Deprecated
246 public static void report() {
247 theInstance.reportAll();;
248 }
249
250 @Deprecated
251 public static void report(String tag) {
252 theInstance.reportStep(tag);
253 }
254
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800255 public static void main(String args[]){
256 // test the measurement overhead
257 String tag;
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800258 for(int i = 0; i < 2; i++){
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800259 tag = "foo foo foo";
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800260 Measurement m;
261 m = start(tag); System.out.println(tag); m.stop();
262 m = start(tag); System.out.println(tag); m.stop();
263 m = start(tag); System.out.println(tag); m.stop();
264 m = start(tag); System.out.println(tag); m.stop();
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800265 tag = "bar";
266 start(tag); stop(tag);
267 tag = "baz";
268 start(tag); stop(tag);
269 report();
270 clear();
271 }
brian6df88232014-01-14 17:05:07 -0800272 for(int i = 0; i < 100; i++){
273 tag = "a";
274 start(tag); stop(tag);
275 start(tag); stop(tag);
276
277 start(tag); stop(tag);
278 start(tag); stop(tag);
279 start(tag); stop(tag);
280 start(tag); stop(tag);
281 start(tag); stop(tag);
282 start(tag); stop(tag);
283
284 tag = "b";
285 start(tag); stop(tag);
286 tag = "c";
287 start(tag); stop(tag);
288 report();
289 clear();
290 }
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800291 }
292}