blob: fa0553647206f9985f5530f313c1f52eaf235054 [file] [log] [blame]
package net.onrc.onos.core.util;
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 Logger log = LoggerFactory.getLogger(PerformanceMonitor.class);
// experiment name -> PerformanceMonitor
private static final ConcurrentHashMap<String, PerformanceMonitor> perfMons = new ConcurrentHashMap<>();
public static PerformanceMonitor experiment(String name) {
PerformanceMonitor pm = perfMons.get(name);
if (pm == null) {
pm = new PerformanceMonitor();
PerformanceMonitor existing = perfMons.putIfAbsent(name, pm);
if (existing != null) {
pm = existing;
}
}
return pm;
}
// tag -> Measurements
private final ConcurrentHashMap<String, Queue<Measurement>> map = new ConcurrentHashMap<>();
private long overhead;
private long experimentStart = Long.MAX_VALUE;
private final static double normalization = Math.pow(10, 6);
/**
* Start a performance measurement, identified by a tag
* <p/>
* Note: Only a single measurement can use the same tag at a time.
* ..... not true anymore.
*
* @param tag for performance measurement
*/
public Measurement startStep(String tag) {
long start = System.nanoTime();
if (start < experimentStart) {
experimentStart = start;
}
Queue<Measurement> list = map.get(tag);
if (list == null) {
list = new ConcurrentLinkedQueue<Measurement>();
Queue<Measurement> existing_list = map.putIfAbsent(tag, list);
if (existing_list != null) {
// someone concurrently added, using theirs
list = existing_list;
}
}
Measurement m = new Measurement();
list.add(m);
m.start();
overhead += System.nanoTime() - start;
return m;
}
/**
* Stop a performance measurement.
* <p/>
* You must have already started a measurement with tag.
*
* @param tag for performance measurement
*/
public void stopStep(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 void reset() {
map.clear();
overhead = 0;
experimentStart = Long.MAX_VALUE;
}
/**
* Write all performance measurements to the log
*/
public void reportAll() {
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 void reportStep(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.
*/
@Override
public String toString() {
double milli = elapsed() / normalization;
double startMs = start / normalization;
double stopMs = stop / normalization;
return milli + "ms/" + startMs + '/' + stopMs;
}
}
@Deprecated
private static final PerformanceMonitor theInstance = new PerformanceMonitor();
@Deprecated
public static Measurement start(String tag) {
return theInstance.startStep(tag);
}
@Deprecated
public static void stop(String tag) {
theInstance.stopStep(tag);
;
}
@Deprecated
public static void clear() {
theInstance.reset();
;
}
@Deprecated
public static void report() {
theInstance.reportAll();
;
}
@Deprecated
public static void report(String tag) {
theInstance.reportStep(tag);
}
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();
}
}
}