blob: 7c38a3c81cc24f53d4dd76912a1ec028e57c9809 [file] [log] [blame]
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.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class for collecting performance measurements
*/
public class PerformanceMonitor {
private final static Map<String, List<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;
}
List<Measurement> list = map.get(tag);
if(list == null) {
list = new ArrayList<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();
List<Measurement> list = map.get(tag);
if(list == null) {
log.error("Tag {} does not exist", tag);
}
else if(list.size() == 1) {
list.get(0).stop(time);
}
else {
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, List<Measurement>> e : map.entrySet()) {
String key = e.getKey();
List<Measurement> list = e.getValue();
int total = 0, count = 0;
long start = Long.MAX_VALUE, stop = -1;
for(Measurement m : list) {
// 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) {
List<Measurement> list = map.get(tag);
if(list == null) {
return; //TODO
}
//TODO: fix this;
Measurement m = list.get(0);
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() {
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){
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);
// tag = "b";
// start(tag); stop(tag);
// tag = "c";
// start(tag); stop(tag);
// report();
// clear();
// }
}
}