com.ajjpj.asysmon.measure.scalar.ACpuUtilizationMeasurer Maven / Gradle / Ivy
package com.ajjpj.asysmon.measure.scalar;
import com.ajjpj.abase.function.AFunction1;
import com.ajjpj.abase.io.AFile;
import com.ajjpj.asysmon.data.AScalarDataPoint;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author arno
*/
public class ACpuUtilizationMeasurer implements AScalarMeasurer {
public static final AFile PROC_STAT_FILE = new AFile("/proc/stat", Charset.defaultCharset());
public static final AFile PROC_CPUINFO_FILE = new AFile("/proc/cpuinfo", Charset.defaultCharset());
public static final String KEY_PREFIX = "cpu:";
public static final String KEY_MEMENTO = KEY_PREFIX;
public static final String KEY_AVAILABLE = KEY_PREFIX + "available";
public static final String KEY_ALL_USED = KEY_PREFIX + "all-used";
public static final String KEY_PREFIX_MHZ = KEY_PREFIX + "freq-mhz:";
@Override public void prepareMeasurements(Map mementos) throws IOException {
mementos.put(KEY_MEMENTO, createSnapshot());
}
@Override public void contributeMeasurements(Map data, long timestamp, Map mementos) throws IOException {
final Map allCurrent = createSnapshot();
@SuppressWarnings("unchecked")
final Map allPrev = (Map) mementos.get(KEY_MEMENTO);
final int numCpus = allCurrent.size() - 1;
final Snapshot current = allCurrent.get("cpu");
final Snapshot prev = allPrev.get("cpu");
final long diffTime = current.timestamp - prev.timestamp;
if(diffTime <= 0) {
return;
}
final long idleJiffies = current.idle - prev.idle;
final long stolenJiffies = current.stolen - prev.stolen;
// 'baseline' - 100% for a single CPU, <# cpus>*100% for 'total'
final long fullJiffies = diffTime * numCpus / 10;
// reduce the theoretical 'full' capacity by 'stolen' cycles
final long availJiffies = fullJiffies - stolenJiffies;
final long usedJiffies = availJiffies - idleJiffies;
final long usedPerMill = usedJiffies * 10;
data.put(KEY_AVAILABLE, new AScalarDataPoint(timestamp, KEY_AVAILABLE, availJiffies / (diffTime / 10) * 1000, 1));
data.put(KEY_ALL_USED, new AScalarDataPoint(timestamp, KEY_ALL_USED, usedPerMill, 1));
contributeFreq(data, timestamp);
}
private void contributeFreq(Map data, long timestamp) throws IOException {
final Map counter = new HashMap();
for(String line: PROC_CPUINFO_FILE.lines()) {
if(! line.contains("MHz")) {
continue;
}
final String mhz = line.substring(line.indexOf(':') + 1).trim();
if(! counter.containsKey(mhz)) {
counter.put(mhz, new AtomicInteger());
}
counter.get(mhz).incrementAndGet();
}
for(String mhz: counter.keySet()) {
final String key = KEY_PREFIX_MHZ + mhz;
data.put(key, new AScalarDataPoint(timestamp, key, counter.get(mhz).intValue(), 0));
}
}
private Map createSnapshot() throws IOException {
return PROC_STAT_FILE.iterate(new AFunction1, Map, RuntimeException>() { //TODO nothrow
@Override public Map apply(Iterator iter) {
final Map result = new HashMap();
while(iter.hasNext()) {
final String line = iter.next();
final String[] split = line.split("\\s+");
if(split[0].startsWith("cpu")) {
final long idle = Long.valueOf(split[4]);
final long stolen = split.length >= 8 ? Long.valueOf(split[8]) : 0;
result.put(split[0], new Snapshot(idle, stolen));
}
}
return result;
}
});
}
@Override public void shutdown() throws Exception {
}
static class Snapshot {
public final long timestamp = System.currentTimeMillis();
public final long idle;
public final long stolen;
Snapshot(long idle, long stolen) {
this.idle = idle;
this.stolen = stolen;
}
}
}