package io.pcp.parfait.timing;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
public class StepMeasurements {
private final StepMeasurements parent;
private final List<StepMeasurements> children = new ArrayList<StepMeasurements>();
private final List<MetricMeasurement> metricInstances = new ArrayList<MetricMeasurement>();
private final String eventName;
private final String action;
private volatile boolean started = false;
public StepMeasurements(StepMeasurements parent,
String eventName, String action) {
this.parent = parent;
if (parent != null) {
parent.addChildExecution(this);
}
this.eventName = eventName;
this.action = action;
}
public StepMeasurements getParent() {
return parent;
}
public void addMetricInstance(MetricMeasurement metric) {
metricInstances.add(metric);
}
public void startAll() {
for (MetricMeasurement metric : metricInstances) {
metric.startTimer();
}
started = true;
}
public void stopAll() {
started = false;
for (MetricMeasurement metric : metricInstances) {
metric.stopTimer();
}
}
public void pauseAll() {
for (MetricMeasurement metric : metricInstances) {
metric.pauseOwnTime();
}
}
public void resumeAll() {
for (MetricMeasurement metric : metricInstances) {
metric.resumeOwnTime();
}
}
/**
* @return a nicely-formatted list of all the events taken to reach the one under
* measurement (including that one as the last element)
*/
String getBackTrace() {
if (parent == null) {
return stackTraceElement();
}
return parent.getBackTrace() + "/" + stackTraceElement();
}
/**
* @return a nicely-formatted list of all the events invoked after the one under
* measurement (including that one as the first element)
*/
String getForwardTrace() {
if (children.isEmpty()) {
return stackTraceElement();
} else if (children.size() == 1) {
return stackTraceElement() + "/" + children.get(0).getForwardTrace();
} else {
// Handles the 'freak case' where one event may forward directly to MORE than one
// 'child'. I have no idea if this ever happens, but we might as well handle it.
List<String> childTraces = new ArrayList<String>(children.size());
for (StepMeasurements child : children) {
childTraces.add(child.getForwardTrace());
}
return stackTraceElement() + "/{" + Joiner.on('|').join(childTraces) + "}";
}
}
private void addChildExecution(StepMeasurements newTiming) {
children.add(newTiming);
}
private String stackTraceElement() {
return eventName + (Strings.isNullOrEmpty(action) ? "" : ":" + action);
}
String getEventName() {
return eventName;
}
public Collection<MetricMeasurement> getMetricInstances() {
return metricInstances;
}
public Map<ThreadMetric, Long> snapshotValues() {
if (!started) {
return Collections.emptyMap();
}
Collection<MetricMeasurement> snapshot = new ArrayList<MetricMeasurement>(metricInstances);
Map<ThreadMetric, Long> results = new HashMap<ThreadMetric, Long>();
for (MetricMeasurement measurement : snapshot) {
results.put(measurement.getMetricSource(), measurement.inProgressValue());
}
return results;
}
}