blob: 6acf8255323086ab40ac449ec2227e817b619cee [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.ArrayList;
4import java.util.List;
Brian O'Connor8fdfb062014-01-08 17:47:57 -08005import java.util.Map;
Brian O'Connor2daf7a92014-01-14 11:26:35 -08006import java.util.Map.Entry;
Brian O'Connora5e5f832014-01-15 16:58:14 -08007import java.util.Queue;
Brian O'Connor8fdfb062014-01-08 17:47:57 -08008import java.util.concurrent.ConcurrentHashMap;
Brian O'Connora5e5f832014-01-15 16:58:14 -08009import java.util.concurrent.ConcurrentLinkedQueue;
Brian O'Connor8fdfb062014-01-08 17:47:57 -080010
11import org.slf4j.Logger;
12import org.slf4j.LoggerFactory;
13
14/**
15 * Class for collecting performance measurements
16 */
17public class PerformanceMonitor {
Brian O'Connora5e5f832014-01-15 16:58:14 -080018 private final static Map<String, Queue<Measurement>> map = new ConcurrentHashMap<>();;
Brian O'Connor8fdfb062014-01-08 17:47:57 -080019 private final static Logger log = LoggerFactory.getLogger(PerformanceMonitor.class);
Brian O'Connor2daf7a92014-01-14 11:26:35 -080020 private static long overhead;
21 private static long experimentStart = Long.MAX_VALUE;
22 private final static double normalization = Math.pow(10, 6);
23
Brian O'Connor8fdfb062014-01-08 17:47:57 -080024 /**
25 * Start a performance measurement, identified by a tag
26 *
27 * Note: Only a single measurement can use the same tag at a time.
Brian O'Connor2daf7a92014-01-14 11:26:35 -080028 * ..... not true anymore.
Brian O'Connor8fdfb062014-01-08 17:47:57 -080029 *
30 * @param tag for performance measurement
31 */
Brian O'Connor2daf7a92014-01-14 11:26:35 -080032 public static Measurement start(String tag) {
Brian O'Connor8fdfb062014-01-08 17:47:57 -080033 long start = System.nanoTime();
Brian O'Connor2daf7a92014-01-14 11:26:35 -080034 if(start < experimentStart) {
35 experimentStart = start;
Brian O'Connor8fdfb062014-01-08 17:47:57 -080036 }
Brian O'Connora5e5f832014-01-15 16:58:14 -080037 Queue<Measurement> list = map.get(tag);
Brian O'Connor2daf7a92014-01-14 11:26:35 -080038 if(list == null) {
Brian O'Connora5e5f832014-01-15 16:58:14 -080039 list = new ConcurrentLinkedQueue<Measurement>();
Brian O'Connor2daf7a92014-01-14 11:26:35 -080040 map.put(tag, list);
41 }
42 Measurement m = new Measurement();
43 list.add(m);
Brian O'Connor8fdfb062014-01-08 17:47:57 -080044 m.start();
45 overhead += System.nanoTime() - start;
Brian O'Connor2daf7a92014-01-14 11:26:35 -080046 return m;
Brian O'Connor8fdfb062014-01-08 17:47:57 -080047 }
48
49 /**
50 * Stop a performance measurement.
51 *
52 * You must have already started a measurement with tag.
53 *
54 * @param tag for performance measurement
55 */
56 public static void stop(String tag) {
57 long time = System.nanoTime();
Brian O'Connora5e5f832014-01-15 16:58:14 -080058 Queue<Measurement> list = map.get(tag);
brian6df88232014-01-14 17:05:07 -080059 if(list == null || list.size() == 0) {
Brian O'Connor8fdfb062014-01-08 17:47:57 -080060 log.error("Tag {} does not exist", tag);
61 }
Brian O'Connora5e5f832014-01-15 16:58:14 -080062 list.peek().stop(time);
brian6df88232014-01-14 17:05:07 -080063 if(list.size() > 1) {
Brian O'Connor2daf7a92014-01-14 11:26:35 -080064 log.error("Tag {} has multiple measurements", tag);
Brian O'Connor8fdfb062014-01-08 17:47:57 -080065 }
66 overhead += System.nanoTime() - time;
67 }
Brian O'Connor2daf7a92014-01-14 11:26:35 -080068
Brian O'Connor8fdfb062014-01-08 17:47:57 -080069 /**
70 * Clear all performance measurements.
71 */
72 public static void clear() {
73 map.clear();
74 overhead = 0;
Brian O'Connor2daf7a92014-01-14 11:26:35 -080075 experimentStart = Long.MAX_VALUE;
Brian O'Connor8fdfb062014-01-08 17:47:57 -080076 }
77
78 /**
79 * Write all performance measurements to the log
80 */
81 public static void report() {
Brian O'Connor2daf7a92014-01-14 11:26:35 -080082 String result = "Performance Results: (avg/start/stop/count)\n";
Brian O'Connor0d9963f2014-01-14 14:44:21 -080083 if(map.size() == 0) {
84 result += "No Measurements";
85 log.error(result);
86 return;
87 }
Brian O'Connor2daf7a92014-01-14 11:26:35 -080088 long experimentEnd = -1;
Brian O'Connora5e5f832014-01-15 16:58:14 -080089 for(Entry<String, Queue<Measurement>> e : map.entrySet()) {
Brian O'Connor2daf7a92014-01-14 11:26:35 -080090 String key = e.getKey();
Brian O'Connora5e5f832014-01-15 16:58:14 -080091 Queue<Measurement> list = e.getValue();
Brian O'Connor2daf7a92014-01-14 11:26:35 -080092 int total = 0, count = 0;
93 long start = Long.MAX_VALUE, stop = -1;
94 for(Measurement m : list) {
brian6df88232014-01-14 17:05:07 -080095 if(m.stop < 0) {
96 continue; // measurement has not been stopped
97 }
Brian O'Connor2daf7a92014-01-14 11:26:35 -080098 // Collect overall start and end times
99 if(m.start < start) {
100 start = m.start;
101 }
102 if(m.stop > stop) {
103 stop = m.stop;
104 if(stop > experimentEnd) {
105 experimentEnd = stop;
106 }
brian6df88232014-01-14 17:05:07 -0800107 }
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800108 // Collect statistics for average
109 total += m.elapsed();
110 count++;
111 }
112 double avg = (double) total / count;
113 // Normalize start/stop
114 start -= experimentStart;
115 stop -= experimentStart;
116 result += key + '=' +
117 (avg / normalization) + '/' +
118 (start / normalization) + '/' +
119 (stop / normalization) + '/' +
120 count + '\n';
121 }
122 double overheadMs = overhead / normalization;
123 double experimentElapsed = (experimentEnd - experimentStart) / normalization;
124 result += "TotalTime:" + experimentElapsed + "/Overhead:" + overheadMs;
125 log.error(result);
126// log.error("Performance Results: {} with measurement overhead: {} ms", map, overheadMilli);
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800127 }
Pavlin Radoslavovb5e31782014-01-12 20:11:46 -0800128
129 /**
130 * Write the performance measurement for a tag to the log
131 *
132 * @param tag the tag name.
133 */
134 public static void report(String tag) {
Brian O'Connora5e5f832014-01-15 16:58:14 -0800135 Queue<Measurement> list = map.get(tag);
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800136 if(list == null) {
137 return; //TODO
138 }
139 //TODO: fix this;
Brian O'Connora5e5f832014-01-15 16:58:14 -0800140 Measurement m = list.peek();
Pavlin Radoslavovb5e31782014-01-12 20:11:46 -0800141 if (m != null) {
Brian O'Connor0d9963f2014-01-14 14:44:21 -0800142 log.error("Performance Result: tag = {} start = {} stop = {} elapsed = {}",
Pavlin Radoslavovb5e31782014-01-12 20:11:46 -0800143 tag, m.start, m.stop, m.toString());
144 } else {
Brian O'Connor0d9963f2014-01-14 14:44:21 -0800145 log.error("Performance Result: unknown tag {}", tag);
Pavlin Radoslavovb5e31782014-01-12 20:11:46 -0800146 }
147 }
148
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800149 /**
150 * A single performance measurement
151 */
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800152 public static class Measurement {
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800153 long start;
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800154 long stop = -1;
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800155
156 /**
157 * Start the measurement
158 */
159 public void start() {
brian6df88232014-01-14 17:05:07 -0800160 if(start <= 0) {
161 start = System.nanoTime();
162 }
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800163 }
164
165 /**
166 * Stop the measurement
167 */
168 public void stop() {
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800169 long now = System.nanoTime();
170 stop(now);
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800171 }
172
173 /**
174 * Stop the measurement at a specific time
175 * @param time to stop
176 */
177 public void stop(long time){
brian6df88232014-01-14 17:05:07 -0800178 if(stop <= 0) {
179 stop = time;
180 }
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800181 }
182
183 /**
184 * Compute the elapsed time of the measurement in nanoseconds
185 *
186 * @return the measurement time in nanoseconds, or -1 if the measurement is stil running.
187 */
188 public long elapsed() {
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800189 if(stop <= 0) {
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800190 return -1;
191 }
192 else {
193 return stop - start;
194 }
195 }
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800196
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800197 /**
198 * Returns the number of milliseconds for the measurement as a String.
199 */
200 public String toString() {
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800201 double milli = elapsed() / normalization;
202 double startMs = start / normalization;
203 double stopMs = stop / normalization;
204
205 return milli + "ms/" + startMs + '/' + stopMs;
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800206 }
207 }
208
209 public static void main(String args[]){
210 // test the measurement overhead
211 String tag;
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800212 for(int i = 0; i < 2; i++){
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800213 tag = "foo foo foo";
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800214 Measurement m;
215 m = start(tag); System.out.println(tag); m.stop();
216 m = start(tag); System.out.println(tag); m.stop();
217 m = start(tag); System.out.println(tag); m.stop();
218 m = start(tag); System.out.println(tag); m.stop();
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800219 tag = "bar";
220 start(tag); stop(tag);
221 tag = "baz";
222 start(tag); stop(tag);
223 report();
224 clear();
225 }
brian6df88232014-01-14 17:05:07 -0800226 for(int i = 0; i < 100; i++){
227 tag = "a";
228 start(tag); stop(tag);
229 start(tag); stop(tag);
230
231 start(tag); stop(tag);
232 start(tag); stop(tag);
233 start(tag); stop(tag);
234 start(tag); stop(tag);
235 start(tag); stop(tag);
236 start(tag); stop(tag);
237
238 tag = "b";
239 start(tag); stop(tag);
240 tag = "c";
241 start(tag); stop(tag);
242 report();
243 clear();
244 }
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800245 }
246}