From 7fc7ecdfcd068863e7de0afb3b5e8a5400b05483 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Mon, 25 Nov 2024 16:16:37 +0100 Subject: [PATCH 1/4] fix: remove misleading initial window constructor parameter Contrary to what the name implied, this doesn't set an initial size for measure's underlying array, it fixed that size, which led to errors if we actually wanted to record more measures. --- ...DescriptiveStatisticsComponentMeasure.java | 10 ++---- .../measure/OngoingPowerMeasureTest.java | 35 ++++++++++++++----- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/measure/src/main/java/net/laprun/sustainability/power/measure/DescriptiveStatisticsComponentMeasure.java b/measure/src/main/java/net/laprun/sustainability/power/measure/DescriptiveStatisticsComponentMeasure.java index 4518620..71b9521 100644 --- a/measure/src/main/java/net/laprun/sustainability/power/measure/DescriptiveStatisticsComponentMeasure.java +++ b/measure/src/main/java/net/laprun/sustainability/power/measure/DescriptiveStatisticsComponentMeasure.java @@ -5,8 +5,8 @@ public class DescriptiveStatisticsComponentMeasure implements ComponentMeasure { private final DescriptiveStatistics statistics; - public DescriptiveStatisticsComponentMeasure(int initialWindow) { - statistics = new DescriptiveStatistics(initialWindow); + public DescriptiveStatisticsComponentMeasure() { + statistics = new DescriptiveStatistics(); } @Override @@ -15,11 +15,7 @@ public void recordComponentValue(double value) { } @Override - public double[] getComponentRawValues() { + public double[] getComponentValues() { return statistics.getValues(); } - - public static Factory factory(int initialWindow) { - return () -> new DescriptiveStatisticsComponentMeasure(initialWindow); - } } diff --git a/measure/src/test/java/net/laprun/sustainability/power/measure/OngoingPowerMeasureTest.java b/measure/src/test/java/net/laprun/sustainability/power/measure/OngoingPowerMeasureTest.java index dbf2ed0..5493046 100644 --- a/measure/src/test/java/net/laprun/sustainability/power/measure/OngoingPowerMeasureTest.java +++ b/measure/src/test/java/net/laprun/sustainability/power/measure/OngoingPowerMeasureTest.java @@ -1,9 +1,11 @@ package net.laprun.sustainability.power.measure; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.List; import java.util.Map; +import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -20,7 +22,7 @@ public int componentCardinality() { }; static List> factories() { - return List.of(DescriptiveStatisticsComponentMeasure.factory(2), HdrHistogramComponentMeasure::new); + return List.of(DescriptiveStatisticsComponentMeasure::new, HdrHistogramComponentMeasure::new); } @ParameterizedTest @@ -29,9 +31,15 @@ void testStatistics(ComponentMeasure.Factory factory) { final var m1c1 = 10.0; final var m1c2 = 12.0; final var m1c3 = 0.0; + final var m1total = m1c1 + m1c2 + m1c3; final var m2c1 = 8.0; final var m2c2 = 17.0; final var m2c3 = 0.0; + final var m2total = m2c1 + m2c2 + m2c3; + final var m3c1 = 5.0; + final var m3c2 = 5.0; + final var m3c3 = 0.0; + final var m3total = m3c1 + m3c2 + m3c3; final var measure = new OngoingPowerMeasure(metadata, factory); @@ -46,19 +54,28 @@ void testStatistics(ComponentMeasure.Factory factory) { components[2] = m2c3; measure.recordMeasure(components); - assertEquals(m1c1 + m1c2 + m2c1 + m2c2 + m1c3 + m2c3, measure.total()); - assertEquals((m1c1 + m1c2 + m2c1 + m2c2 + m1c3 + m2c3) / 2, measure.average()); - assertEquals(Math.min(m1c1 + m1c2 + m1c3, m2c1 + m2c2 + m2c3), measure.minMeasuredTotal()); - assertEquals(Math.max(m1c1 + m1c2 + m1c3, m2c1 + m2c2 + m2c3), measure.maxMeasuredTotal()); + components[0] = m3c1; + components[1] = m3c2; + components[2] = m3c3; + measure.recordMeasure(components); + +// assertArrayEquals(new double[] {m1c1, m2c1}, measure.getMeasuresFor(0)); +// assertArrayEquals(new double[] {m1c2, m2c2}, measure.getMeasuresFor(1)); +// assertArrayEquals(new double[] {m1c3, m2c3}, measure.getMeasuresFor(2)); + + assertEquals(m1c1 + m1c2 + m1c3 + m2c1 + m2c2 + m2c3 + m3c1 + m3c2 + m3c3, measure.total()); + assertEquals((m1c1 + m1c2 + m1c3 + m2c1 + m2c2 + m2c3 + m3c1 + m3c2 + m3c3) / 3, measure.average()); + assertEquals(Stream.of(m1total, m2total, m3total).min(Double::compareTo).orElseThrow(), measure.minMeasuredTotal()); + assertEquals(Stream.of(m1total, m2total, m3total).max(Double::compareTo).orElseThrow(), measure.maxMeasuredTotal()); final var c1Avg = measure.averagesPerComponent()[0]; final var c2Avg = measure.averagesPerComponent()[1]; final var c3Avg = measure.averagesPerComponent()[2]; - assertEquals((m1c1 + m2c1) / 2, c1Avg); - assertEquals((m1c2 + m2c2) / 2, c2Avg); + assertEquals((m1c1 + m2c1 + m3c1) / 3, c1Avg); + assertEquals((m1c2 + m2c2 + m3c2) / 3, c2Avg); assertEquals(0, c3Avg); - final var stdVarForC1 = Math.sqrt((Math.pow(m1c1 - c1Avg, 2) + Math.pow(m2c1 - c1Avg, 2)) / (2 - 1)); - final var stdVarForC2 = Math.sqrt((Math.pow(m1c2 - c2Avg, 2) + Math.pow(m2c2 - c2Avg, 2)) / (2 - 1)); + final var stdVarForC1 = Math.sqrt((Math.pow(m1c1 - c1Avg, 2) + Math.pow(m2c1 - c1Avg, 2) + Math.pow(m3c1 - c1Avg, 2)) / (3 - 1)); + final var stdVarForC2 = Math.sqrt((Math.pow(m1c2 - c2Avg, 2) + Math.pow(m2c2 - c2Avg, 2) + Math.pow(m3c2 - c2Avg, 2)) / (3 - 1)); assertEquals(stdVarForC1, measure.standardDeviations().perComponent()[0], 0.0001, "Standard Deviation did not match the expected value"); From 6856c2baed9e837f9900334cd4e4c21dc00af60f Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Tue, 26 Nov 2024 16:26:32 +0100 Subject: [PATCH 2/4] refactor: OngoingPowerMeasure now records raw measures & timestamps --- .../power/measure/OngoingPowerMeasure.java | 49 +++++++++++++------ .../measure/OngoingPowerMeasureTest.java | 27 +++++----- 2 files changed, 45 insertions(+), 31 deletions(-) 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 3b15e26..77c9106 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 @@ -9,8 +9,8 @@ import net.laprun.sustainability.power.SensorMetadata; public class OngoingPowerMeasure implements PowerMeasure { + private static final int DEFAULT_SIZE = 32; private final SensorMetadata sensorMetadata; - private final ComponentMeasure[] measures; private final long startedAt; private final double[] averages; private final Set nonZeroComponents; @@ -20,18 +20,18 @@ public class OngoingPowerMeasure implements PowerMeasure { private double maxTotal; private double accumulatedTotal; private int samples; + private final double[][] measures; + private long[] timestamps; - public OngoingPowerMeasure(SensorMetadata sensorMetadata, ComponentMeasure.Factory componentMeasureFactory) { + public OngoingPowerMeasure(SensorMetadata sensorMetadata) { this.sensorMetadata = sensorMetadata; startedAt = System.currentTimeMillis(); final var numComponents = sensorMetadata.componentCardinality(); // we also record the aggregated total for each component participating in the aggregated value final var measuresNb = numComponents + 1; - measures = new ComponentMeasure[measuresNb]; - for (int i = 0; i < measuresNb; i++) { - measures[i] = componentMeasureFactory.create(); - } + measures = new double[measuresNb][DEFAULT_SIZE]; + timestamps = new long[DEFAULT_SIZE]; totalIndex = numComponents; averages = new double[measuresNb]; // we don't need to record the total component as a non-zero component since it's almost never zero and we compute the std dev separately @@ -58,14 +58,14 @@ public void recordMeasure(double[] components) { if (componentValue != 0) { nonZeroComponents.add(component); } - measures[component].recordComponentValue(componentValue); + recordComponentValue(component, componentValue); averages[component] = averages[component] == 0 ? componentValue : (previousSize * averages[component] + componentValue) / samples; } // record min / max totals final var recordedTotal = PowerMeasure.sumOfSelectedComponents(components, totalComponents); - measures[totalIndex].recordComponentValue(recordedTotal); + recordComponentValue(totalIndex, recordedTotal); accumulatedTotal += recordedTotal; averages[components.length] = averages[components.length] == 0 ? recordedTotal : (previousSize * averages[components.length] + recordedTotal) / samples; @@ -77,6 +77,23 @@ public void recordMeasure(double[] components) { } } + private void recordComponentValue(int component, double value) { + final var currentSize = measures[component].length; + if (currentSize <= samples) { + final var newSize = currentSize * 2; + for (int index = 0; index < measures.length; index++) { + final var newArray = new double[newSize]; + System.arraycopy(measures[index], 0, newArray, 0, currentSize); + measures[index] = newArray; + } + final var newTimestamps = new long[newSize]; + System.arraycopy(timestamps, 0, newTimestamps, 0, currentSize); + timestamps = newTimestamps; + } + timestamps[component] = System.currentTimeMillis(); + measures[component][samples - 1] = value; + } + @Override public double total() { return accumulatedTotal; @@ -113,21 +130,23 @@ public StdDev standardDeviations() { } private double standardDeviation(int component) { - final var values = measures[component].getComponentRawValues(); + final var values = measures[component]; if (samples <= 1) { return 0.0; } final double mean = averages[component]; - double geometric_deviation_total = 0.0; - for (double value : values) { - double deviation = value - mean; - geometric_deviation_total += (deviation * deviation); + double geometricDeviationTotal = 0.0; + for (int index = 0; index < samples; index++) { + double deviation = values[index] - mean; + geometricDeviationTotal += (deviation * deviation); } - return FastMath.sqrt(geometric_deviation_total / (samples - 1)); + return FastMath.sqrt(geometricDeviationTotal / (samples - 1)); } @Override public double[] getMeasuresFor(int component) { - return measures[component].getComponentRawValues(); + final var dest = new double[samples]; + System.arraycopy(measures[component], 0, dest, 0, samples); + return dest; } } diff --git a/measure/src/test/java/net/laprun/sustainability/power/measure/OngoingPowerMeasureTest.java b/measure/src/test/java/net/laprun/sustainability/power/measure/OngoingPowerMeasureTest.java index 5493046..039426f 100644 --- a/measure/src/test/java/net/laprun/sustainability/power/measure/OngoingPowerMeasureTest.java +++ b/measure/src/test/java/net/laprun/sustainability/power/measure/OngoingPowerMeasureTest.java @@ -3,12 +3,10 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; -import java.util.List; import java.util.Map; import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.Test; import net.laprun.sustainability.power.SensorMetadata; @@ -21,13 +19,8 @@ public int componentCardinality() { } }; - static List> factories() { - return List.of(DescriptiveStatisticsComponentMeasure::new, HdrHistogramComponentMeasure::new); - } - - @ParameterizedTest - @MethodSource("factories") - void testStatistics(ComponentMeasure.Factory factory) { + @Test + void testStatistics() { final var m1c1 = 10.0; final var m1c2 = 12.0; final var m1c3 = 0.0; @@ -41,7 +34,7 @@ void testStatistics(ComponentMeasure.Factory factory) { final var m3c3 = 0.0; final var m3total = m3c1 + m3c2 + m3c3; - final var measure = new OngoingPowerMeasure(metadata, factory); + final var measure = new OngoingPowerMeasure(metadata); final var components = new double[metadata.componentCardinality()]; components[0] = m1c1; @@ -59,9 +52,9 @@ void testStatistics(ComponentMeasure.Factory factory) { components[2] = m3c3; measure.recordMeasure(components); -// assertArrayEquals(new double[] {m1c1, m2c1}, measure.getMeasuresFor(0)); -// assertArrayEquals(new double[] {m1c2, m2c2}, measure.getMeasuresFor(1)); -// assertArrayEquals(new double[] {m1c3, m2c3}, measure.getMeasuresFor(2)); + assertArrayEquals(new double[] { m1c1, m2c1, m3c1 }, measure.getMeasuresFor(0)); + assertArrayEquals(new double[] { m1c2, m2c2, m3c2 }, measure.getMeasuresFor(1)); + assertArrayEquals(new double[] { m1c3, m2c3, m3c3 }, measure.getMeasuresFor(2)); assertEquals(m1c1 + m1c2 + m1c3 + m2c1 + m2c2 + m2c3 + m3c1 + m3c2 + m3c3, measure.total()); assertEquals((m1c1 + m1c2 + m1c3 + m2c1 + m2c2 + m2c3 + m3c1 + m3c2 + m3c3) / 3, measure.average()); @@ -74,8 +67,10 @@ void testStatistics(ComponentMeasure.Factory factory) { assertEquals((m1c2 + m2c2 + m3c2) / 3, c2Avg); assertEquals(0, c3Avg); - final var stdVarForC1 = Math.sqrt((Math.pow(m1c1 - c1Avg, 2) + Math.pow(m2c1 - c1Avg, 2) + Math.pow(m3c1 - c1Avg, 2)) / (3 - 1)); - final var stdVarForC2 = Math.sqrt((Math.pow(m1c2 - c2Avg, 2) + Math.pow(m2c2 - c2Avg, 2) + Math.pow(m3c2 - c2Avg, 2)) / (3 - 1)); + final var stdVarForC1 = Math + .sqrt((Math.pow(m1c1 - c1Avg, 2) + Math.pow(m2c1 - c1Avg, 2) + Math.pow(m3c1 - c1Avg, 2)) / (3 - 1)); + final var stdVarForC2 = Math + .sqrt((Math.pow(m1c2 - c2Avg, 2) + Math.pow(m2c2 - c2Avg, 2) + Math.pow(m3c2 - c2Avg, 2)) / (3 - 1)); assertEquals(stdVarForC1, measure.standardDeviations().perComponent()[0], 0.0001, "Standard Deviation did not match the expected value"); From b9002a635e8c6ed31737552a7f6b5f885089c17c Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Tue, 26 Nov 2024 18:48:52 +0100 Subject: [PATCH 3/4] refactor: use BitSet to record non-zero components instead of HashSet --- .../power/measure/OngoingPowerMeasure.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) 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 77c9106..d672bbe 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 @@ -1,8 +1,7 @@ package net.laprun.sustainability.power.measure; import java.time.Duration; -import java.util.HashSet; -import java.util.Set; +import java.util.BitSet; import org.apache.commons.math3.util.FastMath; @@ -13,7 +12,7 @@ public class OngoingPowerMeasure implements PowerMeasure { private final SensorMetadata sensorMetadata; private final long startedAt; private final double[] averages; - private final Set nonZeroComponents; + private final BitSet nonZeroComponents; private final int[] totalComponents; private final int totalIndex; private double minTotal = Double.MAX_VALUE; @@ -35,7 +34,7 @@ public OngoingPowerMeasure(SensorMetadata sensorMetadata) { totalIndex = numComponents; averages = new double[measuresNb]; // we don't need to record the total component as a non-zero component since it's almost never zero and we compute the std dev separately - nonZeroComponents = new HashSet<>(numComponents); + nonZeroComponents = new BitSet(numComponents); totalComponents = sensorMetadata.totalComponents(); } @@ -56,7 +55,7 @@ public void recordMeasure(double[] components) { final var componentValue = components[component]; // record that the value is not zero if (componentValue != 0) { - nonZeroComponents.add(component); + nonZeroComponents.set(component); } recordComponentValue(component, componentValue); averages[component] = averages[component] == 0 ? componentValue From ad91eb7e1c21d94d2fe8cb3286b3ff0cf39a3e33 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Tue, 26 Nov 2024 19:09:57 +0100 Subject: [PATCH 4/4] feat: ComponentMeasure -> Analyzer for data analysis instead of measure --- .../power/measure/Analyzer.java | 5 +++ .../power/measure/ComponentMeasure.java | 11 ------ ...ava => DescriptiveStatisticsAnalyzer.java} | 12 +++---- .../power/measure/HdrHistogramAnalyzer.java | 20 +++++++++++ .../measure/HdrHistogramComponentMeasure.java | 35 ------------------- .../power/measure/OngoingPowerMeasure.java | 16 +++++++-- .../power/measure/PowerMeasure.java | 2 ++ .../power/measure/StoppedPowerMeasure.java | 7 ++++ 8 files changed, 52 insertions(+), 56 deletions(-) create mode 100644 measure/src/main/java/net/laprun/sustainability/power/measure/Analyzer.java delete mode 100644 measure/src/main/java/net/laprun/sustainability/power/measure/ComponentMeasure.java rename measure/src/main/java/net/laprun/sustainability/power/measure/{DescriptiveStatisticsComponentMeasure.java => DescriptiveStatisticsAnalyzer.java} (50%) create mode 100644 measure/src/main/java/net/laprun/sustainability/power/measure/HdrHistogramAnalyzer.java delete mode 100644 measure/src/main/java/net/laprun/sustainability/power/measure/HdrHistogramComponentMeasure.java diff --git a/measure/src/main/java/net/laprun/sustainability/power/measure/Analyzer.java b/measure/src/main/java/net/laprun/sustainability/power/measure/Analyzer.java new file mode 100644 index 0000000..fb7f63e --- /dev/null +++ b/measure/src/main/java/net/laprun/sustainability/power/measure/Analyzer.java @@ -0,0 +1,5 @@ +package net.laprun.sustainability.power.measure; + +public interface Analyzer { + void recordComponentValue(double value, long timestamp); +} diff --git a/measure/src/main/java/net/laprun/sustainability/power/measure/ComponentMeasure.java b/measure/src/main/java/net/laprun/sustainability/power/measure/ComponentMeasure.java deleted file mode 100644 index 45e1e6c..0000000 --- a/measure/src/main/java/net/laprun/sustainability/power/measure/ComponentMeasure.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.laprun.sustainability.power.measure; - -public interface ComponentMeasure { - void recordComponentValue(double value); - - double[] getComponentRawValues(); - - interface Factory { - T create(); - } -} diff --git a/measure/src/main/java/net/laprun/sustainability/power/measure/DescriptiveStatisticsComponentMeasure.java b/measure/src/main/java/net/laprun/sustainability/power/measure/DescriptiveStatisticsAnalyzer.java similarity index 50% rename from measure/src/main/java/net/laprun/sustainability/power/measure/DescriptiveStatisticsComponentMeasure.java rename to measure/src/main/java/net/laprun/sustainability/power/measure/DescriptiveStatisticsAnalyzer.java index 71b9521..56fb7ea 100644 --- a/measure/src/main/java/net/laprun/sustainability/power/measure/DescriptiveStatisticsComponentMeasure.java +++ b/measure/src/main/java/net/laprun/sustainability/power/measure/DescriptiveStatisticsAnalyzer.java @@ -2,20 +2,16 @@ import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; -public class DescriptiveStatisticsComponentMeasure implements ComponentMeasure { +@SuppressWarnings("unused") +public class DescriptiveStatisticsAnalyzer implements Analyzer { private final DescriptiveStatistics statistics; - public DescriptiveStatisticsComponentMeasure() { + public DescriptiveStatisticsAnalyzer() { statistics = new DescriptiveStatistics(); } @Override - public void recordComponentValue(double value) { + public void recordComponentValue(double value, long timestamp) { statistics.addValue(value); } - - @Override - public double[] getComponentValues() { - return statistics.getValues(); - } } diff --git a/measure/src/main/java/net/laprun/sustainability/power/measure/HdrHistogramAnalyzer.java b/measure/src/main/java/net/laprun/sustainability/power/measure/HdrHistogramAnalyzer.java new file mode 100644 index 0000000..402e2f2 --- /dev/null +++ b/measure/src/main/java/net/laprun/sustainability/power/measure/HdrHistogramAnalyzer.java @@ -0,0 +1,20 @@ +package net.laprun.sustainability.power.measure; + +import org.HdrHistogram.IntCountsHistogram; + +@SuppressWarnings("unused") +public class HdrHistogramAnalyzer implements Analyzer { + 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 histogram; + + public HdrHistogramAnalyzer() { + histogram = new IntCountsHistogram(HIGHEST_TRACKABLE_VALUE, NUMBER_OF_SIGNIFICANT_VALUE_DIGITS); + } + + @Override + public void recordComponentValue(double value, long timestamp) { + histogram.recordValue((long) (CONVERSION_FACTOR * value)); + } +} diff --git a/measure/src/main/java/net/laprun/sustainability/power/measure/HdrHistogramComponentMeasure.java b/measure/src/main/java/net/laprun/sustainability/power/measure/HdrHistogramComponentMeasure.java deleted file mode 100644 index 1f9d175..0000000 --- a/measure/src/main/java/net/laprun/sustainability/power/measure/HdrHistogramComponentMeasure.java +++ /dev/null @@ -1,35 +0,0 @@ -package net.laprun.sustainability.power.measure; - -import org.HdrHistogram.HistogramIterationValue; -import org.HdrHistogram.IntCountsHistogram; - -public class HdrHistogramComponentMeasure implements ComponentMeasure { - 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 histogram; - - public HdrHistogramComponentMeasure() { - histogram = new IntCountsHistogram(HIGHEST_TRACKABLE_VALUE, NUMBER_OF_SIGNIFICANT_VALUE_DIGITS); - } - - @Override - public void recordComponentValue(double value) { - histogram.recordValue((long) (CONVERSION_FACTOR * value)); - } - - @Override - public double[] getComponentRawValues() { - final var totalCount = histogram.getTotalCount(); - if (totalCount == 0) { - return new double[0]; - } - - final var result = new double[(int) totalCount]; - int index = 0; - for (HistogramIterationValue value : histogram.recordedValues()) { - result[index++] = (double) value.getValueIteratedTo() / CONVERSION_FACTOR; - } - return result; - } -} 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 d672bbe..d5ba159 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 @@ -2,6 +2,7 @@ import java.time.Duration; import java.util.BitSet; +import java.util.Objects; import org.apache.commons.math3.util.FastMath; @@ -21,8 +22,9 @@ public class OngoingPowerMeasure implements PowerMeasure { private int samples; private final double[][] measures; private long[] timestamps; + private final Analyzer[] analyzers; - public OngoingPowerMeasure(SensorMetadata sensorMetadata) { + public OngoingPowerMeasure(SensorMetadata sensorMetadata, Analyzer... analyzers) { this.sensorMetadata = sensorMetadata; startedAt = System.currentTimeMillis(); @@ -36,6 +38,7 @@ public OngoingPowerMeasure(SensorMetadata sensorMetadata) { // we don't need to record the total component as a non-zero component since it's almost never zero and we compute the std dev separately nonZeroComponents = new BitSet(numComponents); totalComponents = sensorMetadata.totalComponents(); + this.analyzers = Objects.requireNonNullElseGet(analyzers, () -> new Analyzer[0]); } @Override @@ -89,8 +92,12 @@ private void recordComponentValue(int component, double value) { System.arraycopy(timestamps, 0, newTimestamps, 0, currentSize); timestamps = newTimestamps; } - timestamps[component] = System.currentTimeMillis(); + final var timestamp = System.currentTimeMillis(); + timestamps[component] = timestamp; measures[component][samples - 1] = value; + for (var analyzer : analyzers) { + analyzer.recordComponentValue(value, timestamp); + } } @Override @@ -148,4 +155,9 @@ public double[] getMeasuresFor(int component) { System.arraycopy(measures[component], 0, dest, 0, samples); return dest; } + + @Override + public Analyzer[] analyzers() { + return analyzers; + } } diff --git a/measure/src/main/java/net/laprun/sustainability/power/measure/PowerMeasure.java b/measure/src/main/java/net/laprun/sustainability/power/measure/PowerMeasure.java index 1e06e9d..eea3d70 100644 --- a/measure/src/main/java/net/laprun/sustainability/power/measure/PowerMeasure.java +++ b/measure/src/main/java/net/laprun/sustainability/power/measure/PowerMeasure.java @@ -63,6 +63,8 @@ default double average() { double[] getMeasuresFor(int component); + Analyzer[] analyzers(); + /** * Records the standard deviations for the aggregated energy comsumption value (as returned by {@link #total()}) and * per component diff --git a/measure/src/main/java/net/laprun/sustainability/power/measure/StoppedPowerMeasure.java b/measure/src/main/java/net/laprun/sustainability/power/measure/StoppedPowerMeasure.java index 92a613e..0682840 100644 --- a/measure/src/main/java/net/laprun/sustainability/power/measure/StoppedPowerMeasure.java +++ b/measure/src/main/java/net/laprun/sustainability/power/measure/StoppedPowerMeasure.java @@ -15,6 +15,7 @@ public class StoppedPowerMeasure implements PowerMeasure { private final double[] averages; private final StdDev standardDeviations; private final double[][] measures; + private final Analyzer[] analyzers; public StoppedPowerMeasure(PowerMeasure powerMeasure) { this.sensorMetadata = powerMeasure.metadata(); @@ -30,6 +31,7 @@ public StoppedPowerMeasure(PowerMeasure powerMeasure) { for (int i = 0; i < cardinality; i++) { measures[i] = powerMeasure.getMeasuresFor(i); } + analyzers = powerMeasure.analyzers(); } @Override @@ -76,4 +78,9 @@ public StdDev standardDeviations() { public double[] getMeasuresFor(int component) { return measures[component]; } + + @Override + public Analyzer[] analyzers() { + return analyzers; + } }