diff --git a/analysis/src/test/java/ComputeTest.java b/analysis/src/test/java/ComputeTest.java index d601634..5433fc2 100644 --- a/analysis/src/test/java/ComputeTest.java +++ b/analysis/src/test/java/ComputeTest.java @@ -78,9 +78,12 @@ void averageShouldWork() { final var m3c3 = 0.0; final var measure = new OngoingPowerMeasure(metadata); - measure.registerProcessorFor(0, new MeanComponentProcessor()); - measure.registerProcessorFor(1, new MeanComponentProcessor()); - measure.registerProcessorFor(2, new MeanComponentProcessor()); + final var avgProc1 = new MeanComponentProcessor(); + measure.registerProcessorFor(0, avgProc1); + final var avgProc2 = new MeanComponentProcessor(); + measure.registerProcessorFor(1, avgProc2); + final var avgProc3 = new MeanComponentProcessor(); + measure.registerProcessorFor(2, avgProc3); final var components = new double[metadata.componentCardinality()]; components[0] = m1c1; @@ -104,17 +107,13 @@ void averageShouldWork() { assertEquals((m1c1 + m2c1 + m3c1) / 3, c1Avg, 0.0001, "Average did not match the expected value"); - final var processors = measure.processors(); - assertEquals(c1Avg, - processors.processorFor(0, MeanComponentProcessor.class).map(MeanComponentProcessor::mean).orElseThrow()); + assertEquals(c1Avg, avgProc1.mean()); assertEquals((m1c2 + m2c2 + m3c2) / 3, c2Avg, 0.0001, "Average did not match the expected value"); - assertEquals(c2Avg, - processors.processorFor(1, MeanComponentProcessor.class).map(MeanComponentProcessor::mean).orElseThrow()); + assertEquals(c2Avg, avgProc2.mean()); assertEquals(0, c3Avg, 0.0001, "Average did not match the expected value"); - assertEquals(0, - processors.processorFor(2, MeanComponentProcessor.class).map(MeanComponentProcessor::mean).orElseThrow()); + assertEquals(0, avgProc3.mean()); System.out.println(PowerMeasure.asString(measure)); } diff --git a/measure/src/main/java/net/laprun/sustainability/power/analysis/ComponentProcessor.java b/measure/src/main/java/net/laprun/sustainability/power/analysis/ComponentProcessor.java index 716b978..d436a03 100644 --- a/measure/src/main/java/net/laprun/sustainability/power/analysis/ComponentProcessor.java +++ b/measure/src/main/java/net/laprun/sustainability/power/analysis/ComponentProcessor.java @@ -1,14 +1,6 @@ package net.laprun.sustainability.power.analysis; -public interface ComponentProcessor { +public interface ComponentProcessor extends Outputable { default void recordComponentValue(double value, long timestamp) { } - - default String name() { - return this.getClass().getSimpleName(); - } - - default String output() { - return ""; - } } diff --git a/measure/src/main/java/net/laprun/sustainability/power/analysis/DefaultProcessors.java b/measure/src/main/java/net/laprun/sustainability/power/analysis/DefaultProcessors.java index 0caf66f..2707ef2 100644 --- a/measure/src/main/java/net/laprun/sustainability/power/analysis/DefaultProcessors.java +++ b/measure/src/main/java/net/laprun/sustainability/power/analysis/DefaultProcessors.java @@ -3,13 +3,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.Optional; import net.laprun.sustainability.power.SensorMetadata; public class DefaultProcessors implements Processors { private final List[] processors; - private ComponentProcessor totalProcessor; + private List measureProcessors; @SuppressWarnings("unchecked") public DefaultProcessors(int componentCardinality) { @@ -18,6 +17,10 @@ public DefaultProcessors(int componentCardinality) { @Override public void recordMeasure(double[] components, long timestamp) { + if (measureProcessors != null) { + measureProcessors.forEach(processor -> processor.recordMeasure(components, timestamp)); + } + for (var index = 0; index < components.length; index++) { final var fIndex = index; final var componentProcessors = processors[index]; @@ -39,23 +42,6 @@ public void registerProcessorFor(int componentIndex, ComponentProcessor processo } } - @Override - public void registerTotalProcessor(ComponentProcessor processor) { - this.totalProcessor = processor; - } - - @Override - public void recordTotal(double total, long timestamp) { - if (totalProcessor != null) { - totalProcessor.recordComponentValue(total, timestamp); - } - } - - @Override - public Optional totalProcessor() { - return Optional.ofNullable(totalProcessor); - } - @Override public List processorsFor(int componentIndex) { final var componentProcessors = processors[componentIndex]; @@ -63,19 +49,24 @@ public List processorsFor(int componentIndex) { } @Override - public Optional processorFor(int componentIndex, Class expectedType) { - final var componentProcessors = processors[componentIndex]; - if (componentProcessors != null) { - return componentProcessors.stream().filter(expectedType::isInstance).map(expectedType::cast).findFirst(); - } else { - return Optional.empty(); + public void registerMeasureProcessor(MeasureProcessor processor) { + if (processor != null) { + if (measureProcessors == null) { + measureProcessors = new ArrayList<>(); + } + measureProcessors.add(processor); } } + @Override + public List measureProcessors() { + return Objects.requireNonNullElseGet(measureProcessors, List::of); + } + @Override public String output(SensorMetadata metadata) { StringBuilder builder = new StringBuilder(); - builder.append("# Processors\n"); + builder.append("# Component Processors\n"); for (int i = 0; i < processors.length; i++) { final var name = metadata.metadataFor(i).name(); builder.append(" - ").append(name).append(" component:\n"); diff --git a/measure/src/main/java/net/laprun/sustainability/power/analysis/MeasureProcessor.java b/measure/src/main/java/net/laprun/sustainability/power/analysis/MeasureProcessor.java new file mode 100644 index 0000000..0b5f52f --- /dev/null +++ b/measure/src/main/java/net/laprun/sustainability/power/analysis/MeasureProcessor.java @@ -0,0 +1,6 @@ +package net.laprun.sustainability.power.analysis; + +public interface MeasureProcessor extends Outputable { + default void recordMeasure(double[] measure, long timestamp) { + } +} diff --git a/measure/src/main/java/net/laprun/sustainability/power/analysis/Outputable.java b/measure/src/main/java/net/laprun/sustainability/power/analysis/Outputable.java new file mode 100644 index 0000000..258b48a --- /dev/null +++ b/measure/src/main/java/net/laprun/sustainability/power/analysis/Outputable.java @@ -0,0 +1,11 @@ +package net.laprun.sustainability.power.analysis; + +public interface Outputable { + default String name() { + return this.getClass().getSimpleName(); + } + + default String output() { + return ""; + } +} diff --git a/measure/src/main/java/net/laprun/sustainability/power/analysis/Processors.java b/measure/src/main/java/net/laprun/sustainability/power/analysis/Processors.java index 372bf57..6901d86 100644 --- a/measure/src/main/java/net/laprun/sustainability/power/analysis/Processors.java +++ b/measure/src/main/java/net/laprun/sustainability/power/analysis/Processors.java @@ -1,10 +1,10 @@ package net.laprun.sustainability.power.analysis; import java.util.List; -import java.util.Optional; import net.laprun.sustainability.power.SensorMetadata; +@SuppressWarnings("unused") public interface Processors { Processors empty = new Processors() { }; @@ -12,27 +12,20 @@ public interface Processors { default void recordMeasure(double[] components, long timestamp) { } - default void recordTotal(double total, long timestamp) { - } - default void registerProcessorFor(int componentIndex, ComponentProcessor processor) { } - default void registerTotalProcessor(ComponentProcessor processor) { + default List processorsFor(int componentIndex) { + return List.of(); } - default Optional totalProcessor() { - return Optional.empty(); + default void registerMeasureProcessor(MeasureProcessor processor) { } - default List processorsFor(int componentIndex) { + default List measureProcessors() { return List.of(); } - default Optional processorFor(int componentIndex, Class expectedType) { - return Optional.empty(); - } - default String output(SensorMetadata metadata) { return ""; } diff --git a/measure/src/main/java/net/laprun/sustainability/power/analysis/TotalMeasureProcessor.java b/measure/src/main/java/net/laprun/sustainability/power/analysis/TotalMeasureProcessor.java new file mode 100644 index 0000000..6a767e2 --- /dev/null +++ b/measure/src/main/java/net/laprun/sustainability/power/analysis/TotalMeasureProcessor.java @@ -0,0 +1,90 @@ +package net.laprun.sustainability.power.analysis; + +import java.util.Arrays; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +import net.laprun.sustainability.power.Errors; +import net.laprun.sustainability.power.SensorMetadata; +import net.laprun.sustainability.power.SensorUnit; + +public class TotalMeasureProcessor implements MeasureProcessor { + private final String name; + private double minTotal = Double.MAX_VALUE; + private double maxTotal; + private double accumulatedTotal; + private final Function formula; + + public TotalMeasureProcessor(SensorMetadata metadata, int... totalComponentIndices) { + Objects.requireNonNull(totalComponentIndices, "Must specify component indices that will aggregated in a total"); + + final var errors = new Errors(); + final var totalComponents = Arrays.stream(totalComponentIndices) + .mapToObj(i -> toTotalComponent(metadata, i, errors)) + .toArray(TotalComponent[]::new); + name = Arrays.stream(totalComponents) + .map(TotalComponent::name) + .collect(Collectors.joining(" + ", "Aggregated total from (", ")")); + formula = components -> { + double result = 0; + for (var totalComponent : totalComponents) { + result += components[totalComponent.index] * totalComponent.factor; + } + return result; + }; + + if (errors.hasErrors()) { + throw new IllegalArgumentException(errors.formatErrors()); + } + } + + private TotalComponent toTotalComponent(SensorMetadata metadata, int index, Errors errors) { + final var cm = metadata.metadataFor(index); + final var name = cm.name(); + if (!cm.isWattCommensurable()) { + errors.addError("Component " + name + + " is not commensurate with a power measure. It needs to be expressible in Watts."); + } + + final var factor = SensorUnit.of(cm.unit()).getUnit().factor(); + return new TotalComponent(name, index, factor); + } + + public double total() { + return accumulatedTotal; + } + + public double minMeasuredTotal() { + return minTotal; + } + + public double maxMeasuredTotal() { + return maxTotal; + } + + private record TotalComponent(String name, int index, double factor) { + } + + @Override + public String name() { + return name; + } + + @Override + public String output() { + return MeasureProcessor.super.output(); + } + + @Override + public void recordMeasure(double[] measure, long timestamp) { + final double recordedTotal = formula.apply(measure); + accumulatedTotal += recordedTotal; + if (recordedTotal < minTotal) { + minTotal = recordedTotal; + } + if (recordedTotal > maxTotal) { + maxTotal = recordedTotal; + } + } +} 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 04a2b2f..3e7cd5f 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,63 +1,29 @@ package net.laprun.sustainability.power.measure; import java.time.Duration; -import java.util.Arrays; import java.util.BitSet; import java.util.Optional; -import java.util.stream.Collectors; import java.util.stream.DoubleStream; import java.util.stream.IntStream; import java.util.stream.Stream; import net.laprun.sustainability.power.SensorMetadata; -import net.laprun.sustainability.power.analysis.ComponentProcessor; -import net.laprun.sustainability.power.analysis.DefaultProcessors; -import net.laprun.sustainability.power.analysis.Processors; -public class OngoingPowerMeasure implements PowerMeasure { +public class OngoingPowerMeasure extends ProcessorAware implements PowerMeasure { private static final int DEFAULT_SIZE = 32; private final SensorMetadata metadata; private final long startedAt; private final BitSet nonZeroComponents; - private final int totalIndex; private final double[][] measures; - private final boolean shouldComputeTotals; - private double minTotal = Double.MAX_VALUE; - private double maxTotal; - private double accumulatedTotal; private int samples; private long[] timestamps; - private Processors processors = Processors.empty; public OngoingPowerMeasure(SensorMetadata metadata) { startedAt = System.currentTimeMillis(); + this.metadata = metadata; final var numComponents = metadata.componentCardinality(); - - // check if we need to add an aggregated total component - final var totalComponents = metadata.totalComponents(); - final int measuresNb; - if (totalComponents.length > 0) { - shouldComputeTotals = true; - measuresNb = numComponents + 1; - - final var sumMsg = Arrays.stream(totalComponents) - .mapToObj(i -> metadata.metadataFor(i).name()) - .collect(Collectors.joining("+", "Aggregated total from (", ")")); - - // todo: compute total component properly (same unit, convert to base unit all components) - this.metadata = SensorMetadata.from(metadata) - .withNewComponent("total", sumMsg, true, "mW", false) - .build(); - totalIndex = numComponents; - } else { - shouldComputeTotals = false; - measuresNb = numComponents; - this.metadata = metadata; - totalIndex = -1; - } - - measures = new double[measuresNb][DEFAULT_SIZE]; + measures = new double[numComponents][DEFAULT_SIZE]; timestamps = new long[DEFAULT_SIZE]; // 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); @@ -85,21 +51,7 @@ public void recordMeasure(double[] components) { recordComponentValue(component, componentValue, timestamp); } - // record min / max totals - if (shouldComputeTotals) { - final double recordedTotal = Compute.sumOfSelectedComponents(components, metadata.totalComponents()); - recordComponentValue(totalIndex, recordedTotal, timestamp); - accumulatedTotal += recordedTotal; - if (recordedTotal < minTotal) { - minTotal = recordedTotal; - } - if (recordedTotal > maxTotal) { - maxTotal = recordedTotal; - } - processors.recordTotal(recordedTotal, timestamp); - } - - processors.recordMeasure(components, timestamp); + processors().recordMeasure(components, timestamp); } private void recordComponentValue(int component, double value, long timestamp) { @@ -119,25 +71,10 @@ private void recordComponentValue(int component, double value, long timestamp) { measures[component][samples - 1] = value; } - @Override - public double total() { - return accumulatedTotal; - } - public Duration duration() { return Duration.ofMillis(System.currentTimeMillis() - startedAt); } - @Override - public double minMeasuredTotal() { - return minTotal; - } - - @Override - public double maxMeasuredTotal() { - return maxTotal; - } - @Override public Optional getMeasuresFor(int component) { return measuresFor(component, samples); @@ -184,29 +121,4 @@ public TimestampedMeasures getNthTimestampedMeasures(int n) { } return new TimestampedMeasures(timestamps[n], result); } - - @Override - public Processors processors() { - return processors; - } - - @Override - public void registerProcessorFor(int component, ComponentProcessor processor) { - if (processor != null) { - if (Processors.empty == processors) { - processors = new DefaultProcessors(metadata.componentCardinality()); - } - processors.registerProcessorFor(component, processor); - } - } - - @Override - public void registerTotalProcessor(ComponentProcessor processor) { - if (processor != null) { - if (Processors.empty == processors) { - processors = new DefaultProcessors(metadata.componentCardinality()); - } - processors.registerTotalProcessor(processor); - } - } } 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 a8688d2..a79579b 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 @@ -7,6 +7,7 @@ import net.laprun.sustainability.power.SensorMetadata; import net.laprun.sustainability.power.analysis.ComponentProcessor; +import net.laprun.sustainability.power.analysis.MeasureProcessor; import net.laprun.sustainability.power.analysis.Processors; public interface PowerMeasure { @@ -15,31 +16,16 @@ public interface PowerMeasure { static String asString(PowerMeasure measure) { final var durationInSeconds = measure.duration().getSeconds(); final var samples = measure.numberOfSamples(); - final var measuredMilliWatts = measure.total(); - return String.format("%s [min: %.3f, max: %.3f] (%ds, %s samples)\n---\n%s", - readableWithUnit(measuredMilliWatts), - measure.minMeasuredTotal(), measure.maxMeasuredTotal(), durationInSeconds, samples, + return String.format("%ds, %s samples\n---\n%s", durationInSeconds, samples, measure.processors().output(measure.metadata())); } - static String readableWithUnit(double milliWatts) { - String unit = milliWatts >= 1000 ? "W" : "mW"; - double power = milliWatts >= 1000 ? milliWatts / 1000 : milliWatts; - return String.format("%.3f%s", power, unit); - } - int numberOfSamples(); Duration duration(); - double total(); - SensorMetadata metadata(); - double minMeasuredTotal(); - - double maxMeasuredTotal(); - Optional getMeasuresFor(int component); TimestampedMeasures getNthTimestampedMeasures(int n); @@ -58,5 +44,5 @@ record TimestampedMeasures(long timestamp, double[] measures) { void registerProcessorFor(int component, ComponentProcessor processor); - void registerTotalProcessor(ComponentProcessor processor); + void registerMeasureProcessor(MeasureProcessor processor); } diff --git a/measure/src/main/java/net/laprun/sustainability/power/measure/ProcessorAware.java b/measure/src/main/java/net/laprun/sustainability/power/measure/ProcessorAware.java new file mode 100644 index 0000000..f627df1 --- /dev/null +++ b/measure/src/main/java/net/laprun/sustainability/power/measure/ProcessorAware.java @@ -0,0 +1,35 @@ +package net.laprun.sustainability.power.measure; + +import net.laprun.sustainability.power.SensorMetadata; +import net.laprun.sustainability.power.analysis.ComponentProcessor; +import net.laprun.sustainability.power.analysis.DefaultProcessors; +import net.laprun.sustainability.power.analysis.MeasureProcessor; +import net.laprun.sustainability.power.analysis.Processors; + +abstract class ProcessorAware { + private Processors processors = Processors.empty; + + public abstract SensorMetadata metadata(); + + public Processors processors() { + return processors; + } + + public void registerProcessorFor(int component, ComponentProcessor processor) { + if (processor != null) { + if (Processors.empty == processors) { + processors = new DefaultProcessors(metadata().componentCardinality()); + } + processors.registerProcessorFor(component, processor); + } + } + + public void registerMeasureProcessor(MeasureProcessor processor) { + if (processor != null) { + if (Processors.empty == processors) { + processors = new DefaultProcessors(metadata().componentCardinality()); + } + processors.registerMeasureProcessor(processor); + } + } +} 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 74d2c92..df5d1c8 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 @@ -6,29 +6,18 @@ import java.util.stream.Stream; import net.laprun.sustainability.power.SensorMetadata; -import net.laprun.sustainability.power.analysis.ComponentProcessor; -import net.laprun.sustainability.power.analysis.DefaultProcessors; -import net.laprun.sustainability.power.analysis.Processors; @SuppressWarnings("unused") -public class StoppedPowerMeasure implements PowerMeasure { +public class StoppedPowerMeasure extends ProcessorAware implements PowerMeasure { private final OngoingPowerMeasure measure; private final int samples; private final Duration duration; - private final double total; - private final double min; - private final double max; - private Processors processors; public StoppedPowerMeasure(OngoingPowerMeasure powerMeasure) { this.measure = powerMeasure; this.duration = powerMeasure.duration(); - this.total = powerMeasure.total(); - this.min = powerMeasure.minMeasuredTotal(); - this.max = powerMeasure.maxMeasuredTotal(); this.samples = powerMeasure.numberOfSamples(); final var cardinality = metadata().componentCardinality(); - processors = powerMeasure.processors(); } @Override @@ -36,21 +25,6 @@ public Duration duration() { return duration; } - @Override - public double minMeasuredTotal() { - return min; - } - - @Override - public double maxMeasuredTotal() { - return max; - } - - @Override - public double total() { - return total; - } - @Override public int numberOfSamples() { return samples; @@ -87,29 +61,4 @@ public TimestampedMeasures getNthTimestampedMeasures(int n) { private int ensureIndex(int upToIndex) { return Math.min(upToIndex, samples - 1); } - - @Override - public Processors processors() { - return processors; - } - - @Override - public void registerProcessorFor(int component, ComponentProcessor processor) { - if (processor != null) { - if (Processors.empty == processors) { - processors = new DefaultProcessors(metadata().componentCardinality()); - } - processors.registerProcessorFor(component, processor); - } - } - - @Override - public void registerTotalProcessor(ComponentProcessor processor) { - if (processor != null) { - if (Processors.empty == processors) { - processors = new DefaultProcessors(metadata().componentCardinality()); - } - processors.registerTotalProcessor(processor); - } - } } 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 bab89cf..57fc368 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 @@ -13,12 +13,13 @@ import net.laprun.sustainability.power.SensorMetadata; import net.laprun.sustainability.power.analysis.ComponentProcessor; +import net.laprun.sustainability.power.analysis.TotalMeasureProcessor; public class OngoingPowerMeasureTest { private final static SensorMetadata metadata = SensorMetadata .withNewComponent("cp1", null, true, "mW", true) - .withNewComponent("cp2", null, true, "W", true) - .withNewComponent("cp3", null, true, "kW", true) + .withNewComponent("cp2", null, true, "mW", true) + .withNewComponent("cp3", null, true, "mW", true) .build(); @Test @@ -37,15 +38,12 @@ void testBasics() { 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); @@ -70,15 +68,51 @@ void testBasics() { assertThat(measure.getMeasuresFor(2)).isEmpty(); var measures = measure.getNthTimestampedMeasures(0); - assertThat(measures.measures()).isEqualTo(new double[] { m1c1, m1c2, m1c3, m1total }); + assertThat(measures.measures()).isEqualTo(new double[] { m1c1, m1c2, m1c3 }); measures = measure.getNthTimestampedMeasures(1); - assertThat(measures.measures()).isEqualTo(new double[] { m2c1, m2c2, m2c3, m2total }); + assertThat(measures.measures()).isEqualTo(new double[] { m2c1, m2c2, m2c3 }); measures = measure.getNthTimestampedMeasures(2); - assertThat(measures.measures()).isEqualTo(new double[] { m3c1, m3c2, m3c3, m3total }); + assertThat(measures.measures()).isEqualTo(new double[] { m3c1, m3c2, m3c3 }); + } - assertEquals(m1c1 + m1c2 + m1c3 + m2c1 + m2c2 + m2c3 + m3c1 + m3c2 + m3c3, measure.total()); - assertEquals(Stream.of(m1total, m2total, m3total).min(Double::compareTo).orElseThrow(), measure.minMeasuredTotal()); - assertEquals(Stream.of(m1total, m2total, m3total).max(Double::compareTo).orElseThrow(), measure.maxMeasuredTotal()); + @Test + void testTotal() { + 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); + final var totalProc = new TotalMeasureProcessor(metadata, 0, 1, 2); + measure.registerMeasureProcessor(totalProc); + + final var components = new double[metadata.componentCardinality()]; + components[0] = m1c1; + components[1] = m1c2; + components[2] = m1c3; + measure.recordMeasure(components); + + components[0] = m2c1; + components[1] = m2c2; + components[2] = m2c3; + measure.recordMeasure(components); + + components[0] = m3c1; + components[1] = m3c2; + components[2] = m3c3; + measure.recordMeasure(components); + + assertEquals(m1c1 + m1c2 + m1c3 + m2c1 + m2c2 + m2c3 + m3c1 + m3c2 + m3c3, totalProc.total()); + assertEquals(Stream.of(m1total, m2total, m3total).min(Double::compareTo).orElseThrow(), totalProc.minMeasuredTotal()); + assertEquals(Stream.of(m1total, m2total, m3total).max(Double::compareTo).orElseThrow(), totalProc.maxMeasuredTotal()); } @Test @@ -90,10 +124,8 @@ void processorsShouldBeCalled() { final var m2c2 = random.nextDouble(); final var measure = new OngoingPowerMeasure(metadata); - measure.registerProcessorFor(0, new TestComponentProcessor()); - - // check that we can also associate a processor for the totals - measure.registerTotalProcessor(new TestComponentProcessor()); + final var testProc = new TestComponentProcessor(); + measure.registerProcessorFor(0, testProc); final var components = new double[metadata.componentCardinality()]; components[0] = m1c1; @@ -109,17 +141,8 @@ void processorsShouldBeCalled() { assertThat(processors.processorsFor(1)).isEmpty(); assertThat(processors.processorsFor(2)).isEmpty(); - var maybeProc = processors.processorFor(0, TestComponentProcessor.class); - assertThat(maybeProc).isPresent(); - var processor = maybeProc.get(); - assertThat(processor.values.getFirst().value()).isEqualTo(m1c1); - assertThat(processor.values.getLast().value()).isEqualTo(m2c1); - - maybeProc = processors.totalProcessor().map(TestComponentProcessor.class::cast); - assertThat(maybeProc).isPresent(); - processor = maybeProc.get(); - assertThat(processor.values.getFirst().value()).isEqualTo(m1c1 + m1c2); - assertThat(processor.values.getLast().value()).isEqualTo(m2c1 + m2c2); + assertThat(testProc.values.getFirst().value()).isEqualTo(m1c1); + assertThat(testProc.values.getLast().value()).isEqualTo(m2c1); } private static class TestComponentProcessor implements ComponentProcessor { diff --git a/metadata/src/main/java/net/laprun/sustainability/power/Errors.java b/metadata/src/main/java/net/laprun/sustainability/power/Errors.java new file mode 100644 index 0000000..460e768 --- /dev/null +++ b/metadata/src/main/java/net/laprun/sustainability/power/Errors.java @@ -0,0 +1,27 @@ +package net.laprun.sustainability.power; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class Errors { + private List errors; + + public void addError(String error) { + if (errors == null) { + errors = new ArrayList<>(); + } + errors.add(error); + } + + public boolean hasErrors() { + return errors != null && !errors.isEmpty(); + } + + public String formatErrors() { + if (errors == null) { + return ""; + } + return errors.stream().collect(Collectors.joining("\n- ", "\n- ", "")); + } +} diff --git a/metadata/src/main/java/net/laprun/sustainability/power/SensorMetadata.java b/metadata/src/main/java/net/laprun/sustainability/power/SensorMetadata.java index 44d0393..e0f114e 100644 --- a/metadata/src/main/java/net/laprun/sustainability/power/SensorMetadata.java +++ b/metadata/src/main/java/net/laprun/sustainability/power/SensorMetadata.java @@ -9,7 +9,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.stream.Collectors; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -202,6 +201,7 @@ public ComponentMetadata metadataFor(int componentIndex) { .orElseThrow(() -> new IllegalArgumentException("No component was found for index " + componentIndex)); } + @SuppressWarnings("unused") public static class Builder { private final List components = new ArrayList<>(); private int currentIndex = 0; @@ -223,28 +223,6 @@ public SensorMetadata build() { } } - private static class Errors { - private List errors; - - void addError(String error) { - if (errors == null) { - errors = new ArrayList<>(); - } - errors.add(error); - } - - boolean hasErrors() { - return errors != null && !errors.isEmpty(); - } - - String formatErrors() { - if (errors == null) { - return ""; - } - return errors.stream().collect(Collectors.joining("\n- ", "\n- ", "")); - } - } - /** * The information associated with a recorded component *