package com.performizeit.mjprof.model;
import com.performizeit.mjprof.parser.ThreadInfo;
import java.util.*;
import static com.performizeit.mjprof.parser.ThreadInfoProps.*;
public class ThreadInfoAggregator {
private final List<String> props;
HashSet<String> propsMap = new HashSet<String>();
HashMap<List<Object>, ThreadInfo> aggregator = new HashMap<List<Object>, ThreadInfo>();
public ThreadInfoAggregator(List<String> props) {
this.props = props;
for (String prop : props) propsMap.add(prop);
}
public void accumulateThreadInfo(ThreadInfo threadInfo) {
ArrayList<Object> key = generateKey(threadInfo);
ThreadInfo target = aggregator.get(key);
if (target == null) {
aggregator.put(key, threadInfo);
} else {
mergeProfiles(target, threadInfo);
mergeCounts(target, threadInfo);
mergeCPU(target, threadInfo);
mergeNonKeyProps(target, threadInfo);
}
}
public ArrayList<ThreadInfo> getAggrInfos() {
return new ArrayList<ThreadInfo>(aggregator.values());
}
private void mergeCounts(ThreadInfo target, ThreadInfo threadInfo) {
Integer countTarget = (Integer) target.getVal(COUNT);
Integer count = (Integer) threadInfo.getVal(COUNT);
if (count == null) count = 1;
if (countTarget == null) countTarget = 1;
countTarget += count;
target.setVal(COUNT, countTarget);
}
private double percentDouble(long nom, long denom) {
return ((double) (nom * 100 * 100 / denom)) / 100.0;
}
private void mergeCPU(ThreadInfo target, ThreadInfo threadInfo) {
Long cpuTarget = (Long) target.getVal(CPUNS);
Long cpu = (Long) threadInfo.getVal(CPUNS);
if (cpu != null && cpuTarget != null) { // no cpu enrichment
if (cpu == null) cpu = 0l;
if (cpuTarget == null) cpuTarget = 0l;
cpuTarget += cpu;
target.setVal(CPUNS, cpuTarget);
}
Long wallTarget = (Long) target.getVal(WALL);
Long wall = (Long) threadInfo.getVal(WALL);
if (wall != null || wallTarget != null) {
if (wall == null) wall = 0l;
if (wallTarget == null) wallTarget = 0l;
if (wallTarget < wall) wallTarget = wall;
target.setVal(WALL, wallTarget);
}
if ((wall != null || wallTarget != null) && (cpu != null && cpuTarget != null) && wallTarget > 0) {
target.setVal(CPU_PREC, percentDouble(cpuTarget, (wallTarget * 1000 * 1000)));
}
}
private void mergeProfiles(ThreadInfo target, ThreadInfo threadInfo) {
Profile targetProfile = (Profile) target.getVal(STACK);
Profile prof = (Profile) threadInfo.getVal(STACK);
if (prof == null) return;
if (targetProfile == null) target.setVal(STACK, prof);
targetProfile.addMulti(prof);
}
public void mergeNonKeyProps(ThreadInfo target, ThreadInfo threadInfo) {
ArrayList<String> keys = new ArrayList<String>(threadInfo.getProps());
for (String prop1 : keys) {
if (prop1.equals(STACK) || prop1.equals(COUNT) || prop1.equals(CPUNS) ||
prop1.equals(WALL) || prop1.equals(CPU_PREC) || propsMap.contains(prop1))
continue; // already merged to specially
if (propsMap.contains(prop1)) continue; // key properties are not merged
Object valTarget = target.getVal(prop1);
Object val = threadInfo.getVal(prop1);
if (valTarget == null) {
target.setVal(prop1, val);
} else if (!val.equals(valTarget)) { // we have more than one
if (prop1.equals(DAEMON)) {
target.setVal(prop1, false);
}
if (prop1.equals(LOS)) {
target.setVal(prop1, "\t- *");
} else {
target.setVal(prop1, "*");
}
}
}
}
ArrayList<Object> generateKey(ThreadInfo threadInfo) {
ArrayList<Object> key = new ArrayList<Object>();
for (String prop : props) {
key.add(threadInfo.getVal(prop));
}
return key;
}
}