com.addc.commons.statistcs.collector.Timer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of addc-statistics Show documentation
Show all versions of addc-statistics Show documentation
The addc-statistics library supplies classes for collecting statistics including counters, timers and accumulators and exposing these
as MBeans.
package com.addc.commons.statistcs.collector;
import java.text.NumberFormat;
import java.util.Locale;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import com.addc.commons.Constants;
import com.addc.commons.Mutex;
import com.addc.commons.jmx.JmxBeanImpl;
/**
* The Timer times operations in nano seconds (more or less depending on the OS
* and hardware). It also counts the number of periods it has timed. When a
* timer starts it can only be stopped from the same thread.
*/
public class Timer extends JmxBeanImpl implements IMbTimer {
public static final double MILLI_NANO= Constants.NANOS_PER_MILLI * 1.0d;
public static final double SEC_NANO= MILLI_NANO * 1000.0d;
private static final NumberFormat FORMATTER= NumberFormat.getNumberInstance(Locale.getDefault());
private static final String MS= " ms";
private final ThreadLocal starttime= new ThreadLocal<>();
private long firstStart;
private long lastStop;
private long totalTime;
private long timerCounter;
private long minValue= Long.MAX_VALUE;
private long maxValue;
private double totalSquares;
private final String name;
private final Mutex lock= new Mutex();
static {
FORMATTER.setMaximumFractionDigits(4);
FORMATTER.setMinimumFractionDigits(1);
FORMATTER.setMinimumIntegerDigits(1);
}
/**
* Create new Timer
*
* @param name
* The unique name for this timer
*/
public Timer(String name) {
super(IMbTimer.class);
this.name= name;
}
/**
* Start timing
*/
public void start() {
synchronized (lock) {
if (starttime.get() == null) {
long t= System.nanoTime();
starttime.set(t);
if (firstStart == 0L) {
firstStart= t;
}
}
}
}
/**
* stop timing
*/
public void stop() {
synchronized (lock) {
Long l= starttime.get();
if (l != null) {
starttime.set(null);
lastStop= System.nanoTime();
long time= lastStop - l;
totalTime+= time;
totalSquares+= (time * time);
maxValue= Math.max(maxValue, time);
minValue= Math.min(minValue, time);
timerCounter++;
}
}
}
@Override
public String getAverageTimeMillis() {
synchronized (lock) {
return FORMATTER.format(getAverageTime()) + MS;
}
}
@Override
public String getRmsTimeMillis() {
synchronized (lock) {
return FORMATTER.format(getRmsTime()) + MS;
}
}
@Override
public String getMinValueMillis() {
synchronized (lock) {
return FORMATTER.format(getMinValue()) + MS;
}
}
@Override
public String getMaxValueMillis() {
synchronized (lock) {
return FORMATTER.format(getMaxValue()) + MS;
}
}
@Override
public String getThroughput() {
synchronized (lock) {
return FORMATTER.format(getEventsPerSecond()) + " per second";
}
}
@Override
public long getEventCount() {
long ret;
synchronized (lock) {
ret= timerCounter;
}
return ret;
}
@Override
public String getName() {
return name;
}
@Override
public String getStandardDeviation() {
synchronized (lock) {
return FORMATTER.format(calcSigma()) + MS;
}
}
@Override
protected String getDescription(MBeanInfo info) {
return "Collects timing statistics on sections of code";
}
@Override
protected String getDescription(MBeanAttributeInfo info) {
if ("AverageTimeMillis".equals(info.getName())) {
return "The arithmetical average of the times in milliseconds";
}
if ("RmsTimeMillis".equals(info.getName())) {
return "The RMS average of the times in milliseconds";
}
if ("MinValueMillis".equals(info.getName())) {
return "The minimum value timed in milliseconds";
}
if ("MaxValueMillis".equals(info.getName())) {
return "The maximum value timed in milliseconds";
}
if ("EventCount".equals(info.getName())) {
return "The number events that were timed";
}
if ("Throughput".equals(info.getName())) {
return "The throughput in events/sec";
}
if ("StandardDeviation".equals(info.getName())) {
return "The standard deviation for the current data set";
}
if ("Name".equals(info.getName())) {
return "The name of this Timer";
}
return super.getDescription(info);
}
/**
* Get the standard deviation for the times
*
* @return the standard deviation for the times
*/
public double calcSigma() {
double ret;
synchronized (lock) {
if (timerCounter == 0) {
ret= 0.0d;
} else {
double div= (timerCounter - 1.0d);
ret= (totalSquares / div) - Math.pow((totalTime / div), 2.0d);
}
}
return ret;
}
/**
* Get the arithmetic average time for the operation
*
* @return the arithmetic average time for the operation
*/
public double getAverageTime() {
double ret;
synchronized (lock) {
if (timerCounter == 0) {
ret= 0.0d;
} else {
ret= (((double) totalTime / (double) timerCounter) / MILLI_NANO);
}
}
return ret;
}
/**
* Get the algebraic average time for the operation
*
* @return the algebraic average time for the operation
*/
public double getRmsTime() {
double ret;
synchronized (lock) {
if (timerCounter == 0) {
ret= 0.0d;
} else {
ret= Math.sqrt((totalSquares / timerCounter)) / MILLI_NANO;
}
}
return ret;
}
/**
* Get the minimum value r4ecorde
*
* @return the minimum value r4ecorde
*/
public double getMinValue() {
double ret;
synchronized (lock) {
ret= (minValue / MILLI_NANO);
}
return ret;
}
/**
* Get the maximum value r4ecorde
*
* @return the maximum value r4ecorde
*/
public double getMaxValue() {
double ret;
synchronized (lock) {
ret= (maxValue / MILLI_NANO);
}
return ret;
}
/**
* Get the number of events recorded per second
*
* @return the number of events recorded per second
*/
public double getEventsPerSecond() {
double ret;
synchronized (lock) {
double period= totalTime / SEC_NANO;
ret= (timerCounter / period);
}
return ret;
}
/**
* Clear and reset the timer
*/
public void clear() {
synchronized (lock) {
totalTime= 0L;
timerCounter= 0L;
totalSquares= 0.0d;
firstStart= 0L;
lastStop= 0L;
minValue= Long.MAX_VALUE;
maxValue= 0L;
starttime.set(null);
}
}
}