io.hyperfoil.api.statistics.StatisticsSnapshot Maven / Gradle / Ivy
package io.hyperfoil.api.statistics;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.DoubleStream;
import org.HdrHistogram.Histogram;
/**
* Non-thread safe mutable set of values.
*/
public class StatisticsSnapshot implements Serializable {
public int sequenceId = -1;
public final Histogram histogram = new Histogram(TimeUnit.MINUTES.toNanos(1), 2);
public int requestCount;
public int responseCount;
public int invalid;
public int connectionErrors;
public int requestTimeouts;
public int internalErrors;
public long blockedTime;
public final Map extensions = new HashMap<>();
public boolean isEmpty() {
return requestCount + responseCount + invalid + connectionErrors + requestTimeouts + internalErrors == 0 &&
extensions.values().stream().allMatch(StatsExtension::isNull);
}
public void reset() {
histogram.reset();
requestCount = 0;
responseCount = 0;
invalid = 0;
connectionErrors = 0;
requestTimeouts = 0;
internalErrors = 0;
blockedTime = 0;
for (StatsExtension value : extensions.values()) {
if (value != null) {
value.reset();
}
}
}
public StatisticsSnapshot clone() {
StatisticsSnapshot copy = new StatisticsSnapshot();
copy.sequenceId = sequenceId;
copy.add(this);
return copy;
}
public void add(StatisticsSnapshot other) {
histogram.add(other.histogram);
requestCount += other.requestCount;
responseCount += other.responseCount;
invalid += other.invalid;
connectionErrors += other.connectionErrors;
requestTimeouts += other.requestTimeouts;
internalErrors += other.internalErrors;
blockedTime += other.blockedTime;
for (String key : other.extensions.keySet()) {
StatsExtension their = other.extensions.get(key);
StatsExtension my = extensions.get(key);
if (their == null) {
// noop
} else if (my == null) {
extensions.put(key, their.clone());
} else {
my.add(their);
}
}
}
public void subtract(StatisticsSnapshot other) {
histogram.subtract(other.histogram);
requestCount -= other.requestCount;
responseCount -= other.responseCount;
invalid -= other.invalid;
connectionErrors -= other.connectionErrors;
requestTimeouts -= other.requestTimeouts;
internalErrors -= other.internalErrors;
blockedTime -= other.blockedTime;
for (String key : other.extensions.keySet()) {
StatsExtension their = other.extensions.get(key);
StatsExtension my = extensions.get(key);
if (their == null) {
// noop
} else if (my == null) {
my = their.clone();
my.reset();
my.subtract(their);
extensions.put(key, my);
} else {
my.subtract(their);
}
}
}
public StatisticsSummary summary(double[] percentiles) {
TreeMap percentilesMap = getPercentiles(percentiles);
return new StatisticsSummary(histogram.getStartTimeStamp(), histogram.getEndTimeStamp(),
histogram.getMinValue(), (long) histogram.getMean(), histogram.getMaxValue(),
percentilesMap, requestCount, responseCount,
invalid, connectionErrors, requestTimeouts, internalErrors, blockedTime, new TreeMap<>(extensions));
}
public TreeMap getPercentiles(double[] percentiles) {
return DoubleStream.of(percentiles).collect(TreeMap::new,
(map, p) -> map.put(p * 100, histogram.getValueAtPercentile(p * 100)), TreeMap::putAll);
}
public long errors() {
return connectionErrors + requestTimeouts + internalErrors;
}
@Override
public String toString() {
return "StatisticsSnapshot{" +
"sequenceId=" + sequenceId +
", start=" + histogram.getStartTimeStamp() +
", end=" + histogram.getEndTimeStamp() +
", requestCount=" + requestCount +
", responseCount=" + responseCount +
", invalid=" + invalid +
", connectionErrors=" + connectionErrors +
", requestTimeouts=" + requestTimeouts +
", internalErrors=" + internalErrors +
", blockedTime=" + blockedTime +
", extensions=" + extensions + '}';
}
}