Tuesday, July 19, 2011

A mini-framework for Performance Monitoring

Minimalistic set of 3 classes:

import java.util.Collection;

public class PerformanceMeasurement {
 
 RecordByTypeContainer recordByTypeContainer = new RecordByTypeContainer();

 public void record(String type, long elapsed) {
  RecordByType recordByType = recordByTypeContainer.getRecordByType(type);
  recordByType.addEntry(elapsed);
 }

 public long averageExecutionTime() {
  long sum = 0;
  for (RecordByType recordByType : recordByTypeContainer.getAllRecordByType()) {
   sum += recordByType.averageExecutionTime();
  }
  return recordByTypeContainer.size() > 0 ? sum / recordByTypeContainer.size() : 0;
 }

 public Collection getRecordByTypes() {
  return recordByTypeContainer.getAllRecordByType();
 }

 public void reset() {
  for (RecordByType recordByType : recordByTypeContainer.getAllRecordByType()) {
   recordByType.clear();
  }  
 }


}






import java.util.Collections;
import java.util.List;
import java.util.ArrayList;

public class RecordByType {
 private String type;
 private List measurements = Collections.synchronizedList(new ArrayList());

 public RecordByType(String type) {
  this.type = type;
 }

 public synchronized void addEntry(long elapsed) {
  measurements.add(elapsed);
 }

 public long averageExecutionTime() {
  long result = 0;
  synchronized (measurements) {
   for (Long item : measurements) {
    result += item;
   }  
  }

  return measurements.size() > 0 ? result / measurements.size() : 0;
 }

 public int numberOfRecordsAboveThreshold(long i) {
  int count = 0;
  synchronized (measurements) {
   for (Long item : measurements) {
    if (item > i)
     count++;
   }
  }
  return count;
 }

 public synchronized void clear() {
  measurements.clear();
 }

 public String getType() {
  return type;
 }

 public void setType(String type) {
  this.type = type;
 }


}




import java.util.Collection;
import java.util.HashMap;

@SuppressWarnings("serial")
public class RecordByTypeContainer extends HashMap {

 public RecordByType getRecordByType(String type) {
  RecordByType result = get(type);
  if (result == null) {
   result = new RecordByType(type);
   this.put(type, result);
  }
  return result;
 }
 
 public Collection getAllRecordByType() {
  return values();
 }

}






How to use it:

// create tooling
static final PerformanceMeasurement performanceMeasurement = new PerformanceMeasurement();


// reset to a know state
performanceMeasurement.reset();


// do all the tests each of which records the elapsed type

long now = System.currentTimeMillis();
// .... RUN YOUR TEST HERE
long elapsed = (System.currentTimeMillis() - now);
performanceMeasurement.record("TEST_TYPE", elapsed);


// print stats or do asserts

assertTrue("global averageExecutionTime", performanceMeasurement.averageExecutionTime() < 1600);


for (RecordByType recordByType : performanceMeasurement.getRecordByTypes()) {
 assertTrue("individual averageExecutionTime for type "  + recordByType.getType(), recordByType.averageExecutionTime() < 1600);

 assertTrue("execution threshold  for type " + recordByType.getType(), recordByType.numberOfRecordsAboveThreshold(2000) < 10);
}



Works like magic!

No comments: