| package net.onrc.onos.ofcontroller.flowmanager; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Queue; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.ConcurrentLinkedQueue; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * Class for collecting performance measurements |
| */ |
| public class PerformanceMonitor { |
| private final static Map<String, Queue<Measurement>> map = new ConcurrentHashMap<>();; |
| private final static Logger log = LoggerFactory.getLogger(PerformanceMonitor.class); |
| private static long overhead; |
| private static long experimentStart = Long.MAX_VALUE; |
| private final static double normalization = Math.pow(10, 6); |
| |
| /** |
| * Start a performance measurement, identified by a tag |
| * |
| * Note: Only a single measurement can use the same tag at a time. |
| * ..... not true anymore. |
| * |
| * @param tag for performance measurement |
| */ |
| public static Measurement start(String tag) { |
| long start = System.nanoTime(); |
| if(start < experimentStart) { |
| experimentStart = start; |
| } |
| Queue<Measurement> list = map.get(tag); |
| if(list == null) { |
| list = new ConcurrentLinkedQueue<Measurement>(); |
| map.put(tag, list); |
| } |
| Measurement m = new Measurement(); |
| list.add(m); |
| m.start(); |
| overhead += System.nanoTime() - start; |
| return m; |
| } |
| |
| /** |
| * Stop a performance measurement. |
| * |
| * You must have already started a measurement with tag. |
| * |
| * @param tag for performance measurement |
| */ |
| public static void stop(String tag) { |
| long time = System.nanoTime(); |
| Queue<Measurement> list = map.get(tag); |
| if(list == null || list.size() == 0) { |
| log.error("Tag {} does not exist", tag); |
| } |
| list.peek().stop(time); |
| if(list.size() > 1) { |
| log.error("Tag {} has multiple measurements", tag); |
| } |
| overhead += System.nanoTime() - time; |
| } |
| |
| /** |
| * Clear all performance measurements. |
| */ |
| public static void clear() { |
| map.clear(); |
| overhead = 0; |
| experimentStart = Long.MAX_VALUE; |
| } |
| |
| /** |
| * Write all performance measurements to the log |
| */ |
| public static void report() { |
| String result = "Performance Results: (avg/start/stop/count)\n"; |
| if(map.size() == 0) { |
| result += "No Measurements"; |
| log.error(result); |
| return; |
| } |
| long experimentEnd = -1; |
| for(Entry<String, Queue<Measurement>> e : map.entrySet()) { |
| String key = e.getKey(); |
| Queue<Measurement> list = e.getValue(); |
| long total = 0, count = 0; |
| long start = Long.MAX_VALUE, stop = -1; |
| for(Measurement m : list) { |
| if(m.stop < 0) { |
| continue; // measurement has not been stopped |
| } |
| // Collect overall start and end times |
| if(m.start < start) { |
| start = m.start; |
| } |
| if(m.stop > stop) { |
| stop = m.stop; |
| if(stop > experimentEnd) { |
| experimentEnd = stop; |
| } |
| } |
| // Collect statistics for average |
| total += m.elapsed(); |
| count++; |
| } |
| double avg = (double) total / count; |
| // Normalize start/stop |
| start -= experimentStart; |
| stop -= experimentStart; |
| result += key + '=' + |
| (avg / normalization) + '/' + |
| (start / normalization) + '/' + |
| (stop / normalization) + '/' + |
| count + '\n'; |
| } |
| double overheadMs = overhead / normalization; |
| double experimentElapsed = (experimentEnd - experimentStart) / normalization; |
| result += "TotalTime:" + experimentElapsed + "/Overhead:" + overheadMs; |
| log.error(result); |
| // log.error("Performance Results: {} with measurement overhead: {} ms", map, overheadMilli); |
| } |
| |
| /** |
| * Write the performance measurement for a tag to the log |
| * |
| * @param tag the tag name. |
| */ |
| public static void report(String tag) { |
| Queue<Measurement> list = map.get(tag); |
| if(list == null) { |
| return; //TODO |
| } |
| //TODO: fix this; |
| Measurement m = list.peek(); |
| if (m != null) { |
| log.error("Performance Result: tag = {} start = {} stop = {} elapsed = {}", |
| tag, m.start, m.stop, m.toString()); |
| } else { |
| log.error("Performance Result: unknown tag {}", tag); |
| } |
| } |
| |
| /** |
| * A single performance measurement |
| */ |
| public static class Measurement { |
| long start; |
| long stop = -1; |
| |
| /** |
| * Start the measurement |
| */ |
| public void start() { |
| if(start <= 0) { |
| start = System.nanoTime(); |
| } |
| } |
| |
| /** |
| * Stop the measurement |
| */ |
| public void stop() { |
| long now = System.nanoTime(); |
| stop(now); |
| } |
| |
| /** |
| * Stop the measurement at a specific time |
| * @param time to stop |
| */ |
| public void stop(long time){ |
| if(stop <= 0) { |
| stop = time; |
| } |
| } |
| |
| /** |
| * Compute the elapsed time of the measurement in nanoseconds |
| * |
| * @return the measurement time in nanoseconds, or -1 if the measurement is stil running. |
| */ |
| public long elapsed() { |
| if(stop <= 0) { |
| return -1; |
| } |
| else { |
| return stop - start; |
| } |
| } |
| |
| /** |
| * Returns the number of milliseconds for the measurement as a String. |
| */ |
| public String toString() { |
| double milli = elapsed() / normalization; |
| double startMs = start / normalization; |
| double stopMs = stop / normalization; |
| |
| return milli + "ms/" + startMs + '/' + stopMs; |
| } |
| } |
| |
| public static void main(String args[]){ |
| // test the measurement overhead |
| String tag; |
| for(int i = 0; i < 2; i++){ |
| tag = "foo foo foo"; |
| Measurement m; |
| m = start(tag); System.out.println(tag); m.stop(); |
| m = start(tag); System.out.println(tag); m.stop(); |
| m = start(tag); System.out.println(tag); m.stop(); |
| m = start(tag); System.out.println(tag); m.stop(); |
| tag = "bar"; |
| start(tag); stop(tag); |
| tag = "baz"; |
| start(tag); stop(tag); |
| report(); |
| clear(); |
| } |
| for(int i = 0; i < 100; i++){ |
| tag = "a"; |
| start(tag); stop(tag); |
| start(tag); stop(tag); |
| |
| start(tag); stop(tag); |
| start(tag); stop(tag); |
| start(tag); stop(tag); |
| start(tag); stop(tag); |
| start(tag); stop(tag); |
| start(tag); stop(tag); |
| |
| tag = "b"; |
| start(tag); stop(tag); |
| tag = "c"; |
| start(tag); stop(tag); |
| report(); |
| clear(); |
| } |
| } |
| } |