package com.subhajit.metering;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.util.concurrent.locks.ReentrantLock;
import com.subhajit.common.jmx.util.AggregateData;
import com.subhajit.common.jmx.util.Timer;
/**
* Measures total and per-request CPU-utilization.
*
* <p>
* The following code-snippet measures the CPU-utilization of the given block of
* code
*
* <pre>
* cpuMeter.beginRequest();
* try {
* return method.invoke(target, args);
* } finally {
* cpuMeter.endRequest();
* }
* </pre>
*
* The <tt>cpuMeter</tt> object tracks the aggregated CPU-usage in
* {@link #perRequestCpuUtilization} (accessible via
* {@link #getPerRequestUtilization()} and the total CPU-usage in
* {@link #totalCpuUtilization} (accessible via {@link #getTotalUtilization()}.
* </p>
*
* <p>
* The {@link #perRequestCpuUtilization} is measured using an
* {@link AggregateData} object.
* </p>
*
* @author sdasgupta
*
*/
public class CpuMeter {
private final ThreadMXBean mxbean;
/**
* Aggregated CPU utilization per-request.
*/
private final AggregateData<Long> perRequestCpuUtilization;
/**
* Total CPU utilization by all threads using this instance.
*/
private long totalCpuUtilization;
/**
* Locks internal data members during update.
*/
private final ReentrantLock lock;
public CpuMeter() {
super();
this.mxbean = ManagementFactory.getThreadMXBean();
if (!mxbean.isCurrentThreadCpuTimeSupported()) {
throw new UnsupportedOperationException(
"Current-thread CPU-time is not supported.");
}
if (!mxbean.isThreadCpuTimeEnabled()) {
mxbean.setThreadCpuTimeEnabled(true);
}
perRequestCpuUtilization = new Timer();
lock = new ReentrantLock();
}
public void beginRequest() {
lock.lock();
try {
totalCpuUtilization = mxbean.getCurrentThreadCpuTime();
} finally {
lock.unlock();
}
}
public void endRequest() {
lock.lock();
try {
long value = mxbean.getCurrentThreadCpuTime();
long delta = value - totalCpuUtilization;
if (delta != 0) {
perRequestCpuUtilization.addData(delta);
totalCpuUtilization = value;
}
} finally {
lock.unlock();
}
}
public AggregateData<Long> getPerRequestUtilization() {
return perRequestCpuUtilization;
}
public long getTotalUtilization() {
return totalCpuUtilization;
}
@Override
public String toString() {
return "CpuMeter [totalCpuUtilization=" + totalCpuUtilization
+ ", perRequestCpuUtilization=" + perRequestCpuUtilization
+ "]";
}
public void reset() {
lock.lock();
try {
perRequestCpuUtilization.reset();
totalCpuUtilization = 0;
} finally {
lock.unlock();
}
}
}