diff --git a/measure/pom.xml b/measure/pom.xml
index dff0b6ea..446166ed 100644
--- a/measure/pom.xml
+++ b/measure/pom.xml
@@ -23,6 +23,11 @@
commons-math3
3.6.1
+
+ org.hdrhistogram
+ HdrHistogram
+ 2.2.2
+
diff --git a/measure/src/main/java/net/laprun/sustainability/power/measure/DescriptiveStatisticsMeasureStore.java b/measure/src/main/java/net/laprun/sustainability/power/measure/DescriptiveStatisticsMeasureStore.java
new file mode 100644
index 00000000..0e08df85
--- /dev/null
+++ b/measure/src/main/java/net/laprun/sustainability/power/measure/DescriptiveStatisticsMeasureStore.java
@@ -0,0 +1,54 @@
+package net.laprun.sustainability.power.measure;
+
+import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
+
+class DescriptiveStatisticsMeasureStore implements MeasureStore {
+ private final int totalIndex;
+ private final DescriptiveStatistics[] measures;
+
+ public DescriptiveStatisticsMeasureStore(int componentsNumber, int initialWindow) {
+ this.measures = new DescriptiveStatistics[componentsNumber + 1];
+ totalIndex = componentsNumber;
+ for (int i = 0; i < measures.length; i++) {
+ measures[i] = new DescriptiveStatistics(initialWindow);
+ }
+ }
+
+ @Override
+ public void recordComponentValue(int component, double value) {
+ getMeasure(component).addValue(value);
+ }
+
+ private DescriptiveStatistics getMeasure(int component) {
+ return measures[component];
+ }
+
+ private DescriptiveStatistics getTotalMeasure() {
+ return getMeasure(totalIndex);
+ }
+
+ @Override
+ public void recordTotal(double value) {
+ getTotalMeasure().addValue(value);
+ }
+
+ @Override
+ public double getMeasuredTotal() {
+ return getTotalMeasure().getSum();
+ }
+
+ @Override
+ public double getComponentStandardDeviation(int component) {
+ return getMeasure(component).getStandardDeviation();
+ }
+
+ @Override
+ public double getTotalStandardDeviation() {
+ return getTotalMeasure().getStandardDeviation();
+ }
+
+ @Override
+ public double[] getComponentRawValues(int component) {
+ return getMeasure(component).getValues();
+ }
+}
diff --git a/measure/src/main/java/net/laprun/sustainability/power/measure/HdrHistogramMeasureStore.java b/measure/src/main/java/net/laprun/sustainability/power/measure/HdrHistogramMeasureStore.java
new file mode 100644
index 00000000..1d5c5663
--- /dev/null
+++ b/measure/src/main/java/net/laprun/sustainability/power/measure/HdrHistogramMeasureStore.java
@@ -0,0 +1,69 @@
+package net.laprun.sustainability.power.measure;
+
+import org.HdrHistogram.HistogramIterationValue;
+import org.HdrHistogram.IntCountsHistogram;
+
+public class HdrHistogramMeasureStore implements MeasureStore {
+ private static final int HIGHEST_TRACKABLE_VALUE = 1_000_000;
+ private static final int NUMBER_OF_SIGNIFICANT_VALUE_DIGITS = 4;
+ private static final int CONVERSION_FACTOR = 1000;
+ private final IntCountsHistogram[] measures;
+ private final int totalIndex;
+ private double accumulatedTotal;
+
+ public HdrHistogramMeasureStore(int componentsNumber, int initialWindow) {
+ totalIndex = componentsNumber;
+ measures = new IntCountsHistogram[componentsNumber + 1];
+ for (int i = 0; i < measures.length; i++) {
+ measures[i] = new IntCountsHistogram(HIGHEST_TRACKABLE_VALUE,
+ NUMBER_OF_SIGNIFICANT_VALUE_DIGITS);
+ }
+ }
+
+ private IntCountsHistogram getMeasure(int component) {
+ return measures[component];
+ }
+
+ private IntCountsHistogram getTotalMeasure() {
+ return getMeasure(totalIndex);
+ }
+
+ @Override
+ public void recordComponentValue(int component, double value) {
+ getMeasure(component).recordValue((long) (CONVERSION_FACTOR * value));
+ }
+
+ @Override
+ public void recordTotal(double value) {
+ getTotalMeasure().recordValue((long) (CONVERSION_FACTOR * value));
+ accumulatedTotal += value;
+ }
+
+ @Override
+ public double getMeasuredTotal() {
+ return accumulatedTotal;
+ }
+
+ @Override
+ public double getComponentStandardDeviation(int component) {
+ return getMeasure(component).getStdDeviation() / CONVERSION_FACTOR;
+ }
+
+ @Override
+ public double getTotalStandardDeviation() {
+ // not unbiased so tests will fail
+ return getTotalMeasure().getStdDeviation();
+ }
+
+ @Override
+ public double[] getComponentRawValues(int component) {
+ final var measure = getMeasure(component);
+ final var totalCount = measure.getTotalCount();
+ final var result = new double[(int) totalCount];
+ int index = 0;
+ for (HistogramIterationValue value : measure.recordedValues()) {
+ result[index++] = (double) value.getValueIteratedTo() / CONVERSION_FACTOR;
+ }
+ return result;
+ }
+}
diff --git a/measure/src/main/java/net/laprun/sustainability/power/measure/MeasureStore.java b/measure/src/main/java/net/laprun/sustainability/power/measure/MeasureStore.java
new file mode 100644
index 00000000..c878b434
--- /dev/null
+++ b/measure/src/main/java/net/laprun/sustainability/power/measure/MeasureStore.java
@@ -0,0 +1,15 @@
+package net.laprun.sustainability.power.measure;
+
+interface MeasureStore {
+ void recordComponentValue(int component, double value);
+
+ void recordTotal(double value);
+
+ double getMeasuredTotal();
+
+ double getComponentStandardDeviation(int component);
+
+ double getTotalStandardDeviation();
+
+ double[] getComponentRawValues(int component);
+}
diff --git a/measure/src/main/java/net/laprun/sustainability/power/measure/OngoingPowerMeasure.java b/measure/src/main/java/net/laprun/sustainability/power/measure/OngoingPowerMeasure.java
index f3e21db4..fef448fb 100644
--- a/measure/src/main/java/net/laprun/sustainability/power/measure/OngoingPowerMeasure.java
+++ b/measure/src/main/java/net/laprun/sustainability/power/measure/OngoingPowerMeasure.java
@@ -4,17 +4,15 @@
import java.util.HashSet;
import java.util.Set;
-import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
-
import net.laprun.sustainability.power.SensorMetadata;
public class OngoingPowerMeasure implements PowerMeasure {
private final SensorMetadata sensorMetadata;
- private final DescriptiveStatistics[] measures;
- private final DescriptiveStatistics total;
+ private final MeasureStore measures;
private final long startedAt;
private final double[] averages;
private final Set nonZeroComponents;
+ private final int[] totalComponents;
private double minTotal = Double.MAX_VALUE;
private double maxTotal;
private int samples;
@@ -26,13 +24,10 @@ public OngoingPowerMeasure(SensorMetadata sensorMetadata, Duration duration, Dur
averages = new double[numComponents];
final var initialWindow = (int) (duration.toMillis() / frequency.toMillis());
- total = new DescriptiveStatistics(initialWindow);
- this.measures = new DescriptiveStatistics[numComponents];
- for (int i = 0; i < measures.length; i++) {
- measures[i] = new DescriptiveStatistics(initialWindow);
- }
+ measures = new DescriptiveStatisticsMeasureStore(numComponents, initialWindow);
nonZeroComponents = new HashSet<>(numComponents);
+ totalComponents = sensorMetadata.totalComponents();
}
@Override
@@ -54,14 +49,14 @@ public void recordMeasure(double[] components) {
if (componentValue != 0) {
nonZeroComponents.add(component);
}
- measures[component].addValue(componentValue);
+ measures.recordComponentValue(component, componentValue);
averages[component] = averages[component] == 0 ? componentValue
: (previousSize * averages[component] + componentValue) / samples;
}
// record min / max totals
- final var recordedTotal = PowerMeasure.sumOfSelectedComponents(components, metadata().totalComponents());
- total.addValue(recordedTotal);
+ final var recordedTotal = PowerMeasure.sumOfSelectedComponents(components, totalComponents);
+ measures.recordTotal(recordedTotal);
if (recordedTotal < minTotal) {
minTotal = recordedTotal;
}
@@ -72,7 +67,7 @@ public void recordMeasure(double[] components) {
@Override
public double total() {
- return total.getSum();
+ return measures.getMeasuredTotal();
}
public Duration duration() {
@@ -99,13 +94,13 @@ public StdDev standardDeviations() {
final var stdDevs = new double[cardinality];
nonZeroComponents.stream()
.parallel()
- .forEach(component -> stdDevs[component] = measures[component].getStandardDeviation());
+ .forEach(component -> stdDevs[component] = measures.getComponentStandardDeviation(component));
- return new StdDev(total.getStandardDeviation(), stdDevs);
+ return new StdDev(measures.getTotalStandardDeviation(), stdDevs);
}
@Override
public double[] getMeasuresFor(int component) {
- return measures[component].getValues();
+ return measures.getComponentRawValues(component);
}
}