Skip to content

Commit cafb70e

Browse files
committed
refactor: simplify by merging OngoingPowerMeasure with MeasureStore
1 parent 31b2219 commit cafb70e

File tree

8 files changed

+130
-163
lines changed

8 files changed

+130
-163
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package net.laprun.sustainability.power.measure;
2+
3+
public interface ComponentMeasure {
4+
void recordComponentValue(double value);
5+
6+
double[] getComponentRawValues();
7+
8+
interface Factory<T extends ComponentMeasure> {
9+
T create();
10+
}
11+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package net.laprun.sustainability.power.measure;
2+
3+
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
4+
5+
public class DescriptiveStatisticsComponentMeasure implements ComponentMeasure {
6+
private final DescriptiveStatistics statistics;
7+
8+
public DescriptiveStatisticsComponentMeasure(int initialWindow) {
9+
statistics = new DescriptiveStatistics(initialWindow);
10+
}
11+
12+
@Override
13+
public void recordComponentValue(double value) {
14+
statistics.addValue(value);
15+
}
16+
17+
@Override
18+
public double[] getComponentRawValues() {
19+
return statistics.getValues();
20+
}
21+
22+
public static Factory<DescriptiveStatisticsComponentMeasure> factory(int initialWindow) {
23+
return () -> new DescriptiveStatisticsComponentMeasure(initialWindow);
24+
}
25+
}

measure/src/main/java/net/laprun/sustainability/power/measure/DescriptiveStatisticsMeasureStore.java

Lines changed: 0 additions & 54 deletions
This file was deleted.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package net.laprun.sustainability.power.measure;
2+
3+
import org.HdrHistogram.HistogramIterationValue;
4+
import org.HdrHistogram.IntCountsHistogram;
5+
6+
public class HdrHistogramComponentMeasure implements ComponentMeasure {
7+
private static final int HIGHEST_TRACKABLE_VALUE = 1_000_000;
8+
private static final int NUMBER_OF_SIGNIFICANT_VALUE_DIGITS = 4;
9+
private static final int CONVERSION_FACTOR = 1000;
10+
private final IntCountsHistogram histogram;
11+
12+
public HdrHistogramComponentMeasure() {
13+
histogram = new IntCountsHistogram(HIGHEST_TRACKABLE_VALUE, NUMBER_OF_SIGNIFICANT_VALUE_DIGITS);
14+
}
15+
16+
@Override
17+
public void recordComponentValue(double value) {
18+
histogram.recordValue((long) (CONVERSION_FACTOR * value));
19+
}
20+
21+
@Override
22+
public double[] getComponentRawValues() {
23+
final var totalCount = histogram.getTotalCount();
24+
if (totalCount == 0) {
25+
return new double[0];
26+
}
27+
28+
final var result = new double[(int) totalCount];
29+
int index = 0;
30+
for (HistogramIterationValue value : histogram.recordedValues()) {
31+
result[index++] = (double) value.getValueIteratedTo() / CONVERSION_FACTOR;
32+
}
33+
return result;
34+
}
35+
}

measure/src/main/java/net/laprun/sustainability/power/measure/HdrHistogramMeasureStore.java

Lines changed: 0 additions & 69 deletions
This file was deleted.

measure/src/main/java/net/laprun/sustainability/power/measure/MeasureStore.java

Lines changed: 0 additions & 15 deletions
This file was deleted.

measure/src/main/java/net/laprun/sustainability/power/measure/OngoingPowerMeasure.java

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,37 @@
44
import java.util.HashSet;
55
import java.util.Set;
66

7+
import org.apache.commons.math3.util.FastMath;
8+
79
import net.laprun.sustainability.power.SensorMetadata;
810

911
public class OngoingPowerMeasure implements PowerMeasure {
1012
private final SensorMetadata sensorMetadata;
11-
private final MeasureStore measures;
13+
private final ComponentMeasure[] measures;
1214
private final long startedAt;
1315
private final double[] averages;
1416
private final Set<Integer> nonZeroComponents;
1517
private final int[] totalComponents;
18+
private final int totalIndex;
1619
private double minTotal = Double.MAX_VALUE;
1720
private double maxTotal;
21+
private double accumulatedTotal;
1822
private int samples;
1923

20-
public OngoingPowerMeasure(SensorMetadata sensorMetadata, Duration duration, Duration frequency) {
24+
public OngoingPowerMeasure(SensorMetadata sensorMetadata, ComponentMeasure.Factory<?> componentMeasureFactory) {
2125
this.sensorMetadata = sensorMetadata;
2226
startedAt = System.currentTimeMillis();
23-
final var numComponents = metadata().componentCardinality();
24-
averages = new double[numComponents];
25-
26-
final var initialWindow = (int) (duration.toMillis() / frequency.toMillis());
27-
measures = new DescriptiveStatisticsMeasureStore(numComponents, initialWindow);
2827

28+
final var numComponents = sensorMetadata.componentCardinality();
29+
// we also record the aggregated total for each component participating in the aggregated value
30+
final var measuresNb = numComponents + 1;
31+
measures = new ComponentMeasure[measuresNb];
32+
for (int i = 0; i < measuresNb; i++) {
33+
measures[i] = componentMeasureFactory.create();
34+
}
35+
totalIndex = numComponents;
36+
averages = new double[measuresNb];
37+
// 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
2938
nonZeroComponents = new HashSet<>(numComponents);
3039
totalComponents = sensorMetadata.totalComponents();
3140
}
@@ -49,14 +58,17 @@ public void recordMeasure(double[] components) {
4958
if (componentValue != 0) {
5059
nonZeroComponents.add(component);
5160
}
52-
measures.recordComponentValue(component, componentValue);
61+
measures[component].recordComponentValue(componentValue);
5362
averages[component] = averages[component] == 0 ? componentValue
5463
: (previousSize * averages[component] + componentValue) / samples;
5564
}
5665

5766
// record min / max totals
5867
final var recordedTotal = PowerMeasure.sumOfSelectedComponents(components, totalComponents);
59-
measures.recordTotal(recordedTotal);
68+
measures[totalIndex].recordComponentValue(recordedTotal);
69+
accumulatedTotal += recordedTotal;
70+
averages[components.length] = averages[components.length] == 0 ? recordedTotal
71+
: (previousSize * averages[components.length] + recordedTotal) / samples;
6072
if (recordedTotal < minTotal) {
6173
minTotal = recordedTotal;
6274
}
@@ -67,7 +79,7 @@ public void recordMeasure(double[] components) {
6779

6880
@Override
6981
public double total() {
70-
return measures.getMeasuredTotal();
82+
return accumulatedTotal;
7183
}
7284

7385
public Duration duration() {
@@ -94,13 +106,28 @@ public StdDev standardDeviations() {
94106
final var stdDevs = new double[cardinality];
95107
nonZeroComponents.stream()
96108
.parallel()
97-
.forEach(component -> stdDevs[component] = measures.getComponentStandardDeviation(component));
109+
.forEach(component -> stdDevs[component] = standardDeviation(component));
98110

99-
return new StdDev(measures.getTotalStandardDeviation(), stdDevs);
111+
final double aggregate = maxTotal == 0 ? 0 : standardDeviation(totalIndex);
112+
return new StdDev(aggregate, stdDevs);
113+
}
114+
115+
private double standardDeviation(int component) {
116+
final var values = measures[component].getComponentRawValues();
117+
if (samples <= 1) {
118+
return 0.0;
119+
}
120+
final double mean = averages[component];
121+
double geometric_deviation_total = 0.0;
122+
for (double value : values) {
123+
double deviation = value - mean;
124+
geometric_deviation_total += (deviation * deviation);
125+
}
126+
return FastMath.sqrt(geometric_deviation_total / (samples - 1));
100127
}
101128

102129
@Override
103130
public double[] getMeasuresFor(int component) {
104-
return measures.getComponentRawValues(component);
131+
return measures[component].getComponentRawValues();
105132
}
106133
}

measure/src/test/java/net/laprun/sustainability/power/measure/OngoingPowerMeasureTest.java

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,38 @@
22

33
import static org.junit.jupiter.api.Assertions.assertEquals;
44

5-
import java.time.Duration;
5+
import java.util.List;
66
import java.util.Map;
77

8-
import org.junit.jupiter.api.Test;
8+
import org.junit.jupiter.params.ParameterizedTest;
9+
import org.junit.jupiter.params.provider.MethodSource;
910

1011
import net.laprun.sustainability.power.SensorMetadata;
1112

1213
public class OngoingPowerMeasureTest {
14+
private final static SensorMetadata metadata = new SensorMetadata(Map.of(), null, new int[0]) {
1315

14-
@Test
15-
void testStatistics() {
16+
@Override
17+
public int componentCardinality() {
18+
return 3;
19+
}
20+
};
21+
22+
static List<ComponentMeasure.Factory<?>> factories() {
23+
return List.of(DescriptiveStatisticsComponentMeasure.factory(2), HdrHistogramComponentMeasure::new);
24+
}
25+
26+
@ParameterizedTest
27+
@MethodSource("factories")
28+
void testStatistics(ComponentMeasure.Factory<?> factory) {
1629
final var m1c1 = 10.0;
1730
final var m1c2 = 12.0;
1831
final var m1c3 = 0.0;
1932
final var m2c1 = 8.0;
2033
final var m2c2 = 17.0;
2134
final var m2c3 = 0.0;
22-
final var metadata = new SensorMetadata(Map.of(), null, new int[0]) {
23-
24-
@Override
25-
public int componentCardinality() {
26-
return 3;
27-
}
28-
};
29-
final var measure = new OngoingPowerMeasure(metadata, Duration.ofSeconds(1), Duration.ofMillis(500));
35+
36+
final var measure = new OngoingPowerMeasure(metadata, factory);
3037

3138
final var components = new double[metadata.componentCardinality()];
3239
components[0] = m1c1;

0 commit comments

Comments
 (0)