blob: 3721ceb4c476ab9fc9d07b2816ab79a51286191b [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 {
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080015 private final static ConcurrentHashMap<String, Queue<Measurement>> map = new ConcurrentHashMap<>();;
Brian O'Connor8fdfb062014-01-08 17:47:57 -080016 private final static Logger log = LoggerFactory.getLogger(PerformanceMonitor.class);
Brian O'Connor2daf7a92014-01-14 11:26:35 -080017 private static long overhead;
18 private static long experimentStart = Long.MAX_VALUE;
19 private final static double normalization = Math.pow(10, 6);
20
Brian O'Connor8fdfb062014-01-08 17:47:57 -080021 /**
22 * Start a performance measurement, identified by a tag
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080023 *
Brian O'Connor8fdfb062014-01-08 17:47:57 -080024 * Note: Only a single measurement can use the same tag at a time.
Brian O'Connor2daf7a92014-01-14 11:26:35 -080025 * ..... not true anymore.
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080026 *
Brian O'Connor8fdfb062014-01-08 17:47:57 -080027 * @param tag for performance measurement
28 */
Brian O'Connor2daf7a92014-01-14 11:26:35 -080029 public static Measurement start(String tag) {
Brian O'Connor8fdfb062014-01-08 17:47:57 -080030 long start = System.nanoTime();
Brian O'Connor2daf7a92014-01-14 11:26:35 -080031 if(start < experimentStart) {
32 experimentStart = start;
Brian O'Connor8fdfb062014-01-08 17:47:57 -080033 }
Brian O'Connora5e5f832014-01-15 16:58:14 -080034 Queue<Measurement> list = map.get(tag);
Brian O'Connor2daf7a92014-01-14 11:26:35 -080035 if(list == null) {
Brian O'Connora5e5f832014-01-15 16:58:14 -080036 list = new ConcurrentLinkedQueue<Measurement>();
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080037 Queue<Measurement> existing_list = map.putIfAbsent(tag, list);
38 if (existing_list != null) {
39 // someone concurrently added, using theirs
40 list = existing_list;
41 }
Brian O'Connor2daf7a92014-01-14 11:26:35 -080042 }
43 Measurement m = new Measurement();
44 list.add(m);
Brian O'Connor8fdfb062014-01-08 17:47:57 -080045 m.start();
46 overhead += System.nanoTime() - start;
Brian O'Connor2daf7a92014-01-14 11:26:35 -080047 return m;
Brian O'Connor8fdfb062014-01-08 17:47:57 -080048 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080049
Brian O'Connor8fdfb062014-01-08 17:47:57 -080050 /**
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080051 * Stop a performance measurement.
52 *
Brian O'Connor8fdfb062014-01-08 17:47:57 -080053 * You must have already started a measurement with tag.
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080054 *
Brian O'Connor8fdfb062014-01-08 17:47:57 -080055 * @param tag for performance measurement
56 */
57 public static void stop(String tag) {
58 long time = System.nanoTime();
Brian O'Connora5e5f832014-01-15 16:58:14 -080059 Queue<Measurement> list = map.get(tag);
brian6df88232014-01-14 17:05:07 -080060 if(list == null || list.size() == 0) {
Brian O'Connor8fdfb062014-01-08 17:47:57 -080061 log.error("Tag {} does not exist", tag);
62 }
Brian O'Connora5e5f832014-01-15 16:58:14 -080063 list.peek().stop(time);
brian6df88232014-01-14 17:05:07 -080064 if(list.size() > 1) {
Brian O'Connor2daf7a92014-01-14 11:26:35 -080065 log.error("Tag {} has multiple measurements", tag);
Brian O'Connor8fdfb062014-01-08 17:47:57 -080066 }
67 overhead += System.nanoTime() - time;
68 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080069
Brian O'Connor8fdfb062014-01-08 17:47:57 -080070 /**
71 * Clear all performance measurements.
72 */
73 public static void clear() {
74 map.clear();
75 overhead = 0;
Brian O'Connor2daf7a92014-01-14 11:26:35 -080076 experimentStart = Long.MAX_VALUE;
Brian O'Connor8fdfb062014-01-08 17:47:57 -080077 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -080078
Brian O'Connor8fdfb062014-01-08 17:47:57 -080079 /**
80 * Write all performance measurements to the log
81 */
82 public static void report() {
Brian O'Connor2daf7a92014-01-14 11:26:35 -080083 String result = "Performance Results: (avg/start/stop/count)\n";
Brian O'Connor0d9963f2014-01-14 14:44:21 -080084 if(map.size() == 0) {
85 result += "No Measurements";
86 log.error(result);
87 return;
88 }
Brian O'Connor2daf7a92014-01-14 11:26:35 -080089 long experimentEnd = -1;
Brian O'Connora5e5f832014-01-15 16:58:14 -080090 for(Entry<String, Queue<Measurement>> e : map.entrySet()) {
Brian O'Connor2daf7a92014-01-14 11:26:35 -080091 String key = e.getKey();
Brian O'Connora5e5f832014-01-15 16:58:14 -080092 Queue<Measurement> list = e.getValue();
Brian O'Connorc7518832014-01-16 10:50:04 -080093 long total = 0, count = 0;
Brian O'Connor2daf7a92014-01-14 11:26:35 -080094 long start = Long.MAX_VALUE, stop = -1;
95 for(Measurement m : list) {
brian6df88232014-01-14 17:05:07 -080096 if(m.stop < 0) {
97 continue; // measurement has not been stopped
98 }
Brian O'Connor2daf7a92014-01-14 11:26:35 -080099 // Collect overall start and end times
100 if(m.start < start) {
101 start = m.start;
102 }
103 if(m.stop > stop) {
104 stop = m.stop;
105 if(stop > experimentEnd) {
106 experimentEnd = stop;
107 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800108 }
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800109 // Collect statistics for average
110 total += m.elapsed();
111 count++;
112 }
113 double avg = (double) total / count;
114 // Normalize start/stop
115 start -= experimentStart;
116 stop -= experimentStart;
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800117 result += key + '=' +
118 (avg / normalization) + '/' +
119 (start / normalization) + '/' +
120 (stop / normalization) + '/' +
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800121 count + '\n';
122 }
123 double overheadMs = overhead / normalization;
124 double experimentElapsed = (experimentEnd - experimentStart) / normalization;
125 result += "TotalTime:" + experimentElapsed + "/Overhead:" + overheadMs;
126 log.error(result);
127// log.error("Performance Results: {} with measurement overhead: {} ms", map, overheadMilli);
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800128 }
Pavlin Radoslavovb5e31782014-01-12 20:11:46 -0800129
130 /**
131 * Write the performance measurement for a tag to the log
132 *
133 * @param tag the tag name.
134 */
135 public static void report(String tag) {
Brian O'Connora5e5f832014-01-15 16:58:14 -0800136 Queue<Measurement> list = map.get(tag);
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800137 if(list == null) {
138 return; //TODO
139 }
140 //TODO: fix this;
Brian O'Connora5e5f832014-01-15 16:58:14 -0800141 Measurement m = list.peek();
Pavlin Radoslavovb5e31782014-01-12 20:11:46 -0800142 if (m != null) {
Brian O'Connor0d9963f2014-01-14 14:44:21 -0800143 log.error("Performance Result: tag = {} start = {} stop = {} elapsed = {}",
Pavlin Radoslavovb5e31782014-01-12 20:11:46 -0800144 tag, m.start, m.stop, m.toString());
145 } else {
Brian O'Connor0d9963f2014-01-14 14:44:21 -0800146 log.error("Performance Result: unknown tag {}", tag);
Pavlin Radoslavovb5e31782014-01-12 20:11:46 -0800147 }
148 }
149
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800150 /**
151 * A single performance measurement
152 */
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800153 public static class Measurement {
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800154 long start;
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800155 long stop = -1;
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800156
157 /**
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800158 * Start the measurement
159 */
160 public void start() {
brian6df88232014-01-14 17:05:07 -0800161 if(start <= 0) {
162 start = System.nanoTime();
163 }
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800164 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800165
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800166 /**
167 * Stop the measurement
168 */
169 public void stop() {
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800170 long now = System.nanoTime();
171 stop(now);
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800172 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800173
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800174 /**
175 * Stop the measurement at a specific time
176 * @param time to stop
177 */
178 public void stop(long time){
brian6df88232014-01-14 17:05:07 -0800179 if(stop <= 0) {
180 stop = time;
181 }
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800182 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800183
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800184 /**
185 * Compute the elapsed time of the measurement in nanoseconds
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800186 *
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800187 * @return the measurement time in nanoseconds, or -1 if the measurement is stil running.
188 */
189 public long elapsed() {
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800190 if(stop <= 0) {
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800191 return -1;
192 }
193 else {
194 return stop - start;
195 }
196 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800197
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800198 /**
199 * Returns the number of milliseconds for the measurement as a String.
200 */
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800201 @Override
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800202 public String toString() {
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800203 double milli = elapsed() / normalization;
204 double startMs = start / normalization;
205 double stopMs = stop / normalization;
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800206
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800207 return milli + "ms/" + startMs + '/' + stopMs;
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800208 }
209 }
Yuta HIGUCHIa7188f22014-02-18 12:48:06 -0800210
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800211 public static void main(String args[]){
212 // test the measurement overhead
213 String tag;
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800214 for(int i = 0; i < 2; i++){
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800215 tag = "foo foo foo";
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800216 Measurement m;
217 m = start(tag); System.out.println(tag); m.stop();
218 m = start(tag); System.out.println(tag); m.stop();
219 m = start(tag); System.out.println(tag); m.stop();
220 m = start(tag); System.out.println(tag); m.stop();
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800221 tag = "bar";
222 start(tag); stop(tag);
223 tag = "baz";
224 start(tag); stop(tag);
225 report();
226 clear();
227 }
brian6df88232014-01-14 17:05:07 -0800228 for(int i = 0; i < 100; i++){
229 tag = "a";
230 start(tag); stop(tag);
231 start(tag); stop(tag);
232
233 start(tag); stop(tag);
234 start(tag); stop(tag);
235 start(tag); stop(tag);
236 start(tag); stop(tag);
237 start(tag); stop(tag);
238 start(tag); stop(tag);
239
240 tag = "b";
241 start(tag); stop(tag);
242 tag = "c";
243 start(tag); stop(tag);
244 report();
245 clear();
246 }
Brian O'Connor8fdfb062014-01-08 17:47:57 -0800247 }
248}