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); } }