-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: initial measure module to help client-side processing
- Loading branch information
Showing
6 changed files
with
276 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>net.laprun.sustainability</groupId> | ||
<artifactId>power-server-parent</artifactId> | ||
<version>0.0.9-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>power-server-measure</artifactId> | ||
<name>power-server : measure</name> | ||
<description>A library to gather and analyze power consumption measures</description> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>net.laprun.sustainability</groupId> | ||
<artifactId>power-server-metadata</artifactId> | ||
<version>${project.version}</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<pluginManagement> | ||
<plugins> | ||
<plugin> | ||
<groupId>net.revelc.code.formatter</groupId> | ||
<artifactId>formatter-maven-plugin</artifactId> | ||
<dependencies> | ||
<dependency> | ||
<groupId>net.laprun.sustainability</groupId> | ||
<artifactId>build-tools</artifactId> | ||
<version>0.0.9-SNAPSHOT</version> | ||
</dependency> | ||
</dependencies> | ||
</plugin> | ||
</plugins> | ||
</pluginManagement> | ||
</build> | ||
</project> |
33 changes: 33 additions & 0 deletions
33
measure/src/main/java/net/laprun/sustainability/power/measure/AbstractPowerMeasure.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package net.laprun.sustainability.power.measure; | ||
|
||
import java.util.List; | ||
|
||
import net.laprun.sustainability.power.SensorMetadata; | ||
|
||
public abstract class AbstractPowerMeasure implements PowerMeasure { | ||
private final SensorMetadata sensorMetadata; | ||
private final List<double[]> measures; | ||
|
||
protected AbstractPowerMeasure(SensorMetadata sensorMetadata, List<double[]> measures) { | ||
this.sensorMetadata = sensorMetadata; | ||
this.measures = measures; | ||
} | ||
|
||
@Override | ||
public List<double[]> measures() { | ||
return measures; | ||
} | ||
|
||
@Override | ||
public SensorMetadata metadata() { | ||
return sensorMetadata; | ||
} | ||
|
||
public int numberOfSamples() { | ||
return measures.size(); | ||
} | ||
|
||
double[] getComponentData(int componentIndex) { | ||
return measures.parallelStream().mapToDouble(measure -> measure[componentIndex]).toArray(); | ||
} | ||
} |
67 changes: 67 additions & 0 deletions
67
measure/src/main/java/net/laprun/sustainability/power/measure/OngoingPowerMeasure.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package net.laprun.sustainability.power.measure; | ||
|
||
import java.util.ArrayList; | ||
|
||
import net.laprun.sustainability.power.SensorMetadata; | ||
|
||
public class OngoingPowerMeasure extends AbstractPowerMeasure { | ||
private final long startedAt; | ||
private double minTotal = Double.MAX_VALUE; | ||
private double maxTotal; | ||
private final double[] totals; | ||
private final double[] averages; | ||
|
||
public OngoingPowerMeasure(SensorMetadata sensorMetadata, long duration, long frequency) { | ||
super(sensorMetadata, new ArrayList<>((int) (duration / frequency))); | ||
startedAt = System.currentTimeMillis(); | ||
final var numComponents = metadata().componentCardinality(); | ||
totals = new double[numComponents]; | ||
averages = new double[numComponents]; | ||
} | ||
|
||
public void recordMeasure(double[] components) { | ||
final var recorded = new double[components.length]; | ||
System.arraycopy(components, 0, recorded, 0, components.length); | ||
final var previousSize = numberOfSamples(); | ||
measures().add(recorded); | ||
|
||
for (int i = 0; i < recorded.length; i++) { | ||
totals[i] += recorded[i]; | ||
averages[i] = averages[i] == 0 ? recorded[i] | ||
: (previousSize * averages[i] + recorded[i]) / numberOfSamples(); | ||
} | ||
|
||
// record min / max totals | ||
final var recordedTotal = PowerMeasure.sumOfComponents(recorded); | ||
if (recordedTotal < minTotal) { | ||
minTotal = recordedTotal; | ||
} | ||
if (recordedTotal > maxTotal) { | ||
maxTotal = recordedTotal; | ||
} | ||
} | ||
|
||
@Override | ||
public double total() { | ||
return PowerMeasure.sumOfComponents(totals); | ||
} | ||
|
||
public long duration() { | ||
return System.currentTimeMillis() - startedAt; | ||
} | ||
|
||
@Override | ||
public double minMeasuredTotal() { | ||
return minTotal; | ||
} | ||
|
||
@Override | ||
public double maxMeasuredTotal() { | ||
return maxTotal; | ||
} | ||
|
||
@Override | ||
public double[] averagesPerComponent() { | ||
return averages; | ||
} | ||
} |
91 changes: 91 additions & 0 deletions
91
measure/src/main/java/net/laprun/sustainability/power/measure/PowerMeasure.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package net.laprun.sustainability.power.measure; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.stream.IntStream; | ||
|
||
import net.laprun.sustainability.power.SensorMetadata; | ||
|
||
public interface PowerMeasure { | ||
int numberOfSamples(); | ||
|
||
long duration(); | ||
|
||
default double average() { | ||
return total() / numberOfSamples(); | ||
} | ||
|
||
double total(); | ||
|
||
SensorMetadata metadata(); | ||
|
||
double[] averagesPerComponent(); | ||
|
||
double minMeasuredTotal(); | ||
|
||
double maxMeasuredTotal(); | ||
|
||
static double sumOfComponents(double[] recorded) { | ||
var componentSum = 0.0; | ||
for (double value : recorded) { | ||
componentSum += value; | ||
} | ||
return componentSum; | ||
} | ||
|
||
default StdDev standardDeviations() { | ||
final var cardinality = metadata().componentCardinality(); | ||
final var stdDevs = new double[cardinality]; | ||
final var aggregate = new double[1]; | ||
final var samples = numberOfSamples() - 1; // unbiased so we remove one sample | ||
final var sqrdAverages = Arrays.stream(averagesPerComponent()).map(m -> m * m).toArray(); | ||
final var sqrdAverage = average() * average(); | ||
// need to compute the average of variances then square root that to get the "aggregate" standard deviation, | ||
// see: https://stats.stackexchange.com/a/26647 | ||
// "vectorize" computation of variances: compute the variance for each component in parallel | ||
IntStream.range(0, cardinality).parallel() | ||
// compute variances for each component of the measure | ||
.forEach(component -> { | ||
final var sumOfSquares = measures().stream().parallel().peek(m -> { | ||
// compute the std dev for total measure | ||
final var total = sumOfComponents(m); | ||
aggregate[0] += total * total; | ||
}).mapToDouble(m -> m[component] * m[component]).sum(); | ||
stdDevs[component] = stdDev(sumOfSquares, sqrdAverages[component], samples); | ||
aggregate[0] = stdDev(aggregate[0], sqrdAverage, samples); | ||
}); | ||
return new StdDev(aggregate[0], stdDevs); | ||
} | ||
|
||
private static double stdDev(double sumOfSquares, double squaredAvg, int samples) { | ||
return Math.sqrt((sumOfSquares / samples) - (((samples + 1) * squaredAvg) / samples)); | ||
} | ||
|
||
/** | ||
* Records the standard deviations for the aggregated energy comsumption value (as returned by {@link #total()}) and | ||
* per component | ||
* | ||
* @param aggregate | ||
* @param perComponent | ||
*/ | ||
record StdDev(double aggregate, double[] perComponent) { | ||
} | ||
|
||
static String asString(PowerMeasure measure) { | ||
final var durationInSeconds = measure.duration() / 1000; | ||
final var samples = measure.numberOfSamples(); | ||
final var measuredMilliWatts = measure.total(); | ||
final var stdDevs = measure.standardDeviations(); | ||
return String.format("%s / avg: %s / std dev: %.3f [min: %.3f, max: %.3f] (%ds, %s samples)", | ||
readableWithUnit(measuredMilliWatts), readableWithUnit(measure.average()), stdDevs.aggregate, | ||
measure.minMeasuredTotal(), measure.maxMeasuredTotal(), durationInSeconds, samples); | ||
} | ||
|
||
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); | ||
} | ||
|
||
List<double[]> measures(); | ||
} |
43 changes: 43 additions & 0 deletions
43
measure/src/main/java/net/laprun/sustainability/power/measure/StoppedPowerMeasure.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package net.laprun.sustainability.power.measure; | ||
|
||
public class StoppedPowerMeasure extends AbstractPowerMeasure { | ||
private final long duration; | ||
private final double total; | ||
private final double min; | ||
private final double max; | ||
private final double[] averages; | ||
|
||
public StoppedPowerMeasure(PowerMeasure powerMeasure) { | ||
super(powerMeasure.metadata(), powerMeasure.measures()); | ||
this.duration = powerMeasure.duration(); | ||
this.total = powerMeasure.total(); | ||
this.min = powerMeasure.minMeasuredTotal(); | ||
this.max = powerMeasure.maxMeasuredTotal(); | ||
this.averages = powerMeasure.averagesPerComponent(); | ||
} | ||
|
||
@Override | ||
public long duration() { | ||
return duration; | ||
} | ||
|
||
@Override | ||
public double minMeasuredTotal() { | ||
return min; | ||
} | ||
|
||
@Override | ||
public double maxMeasuredTotal() { | ||
return max; | ||
} | ||
|
||
@Override | ||
public double total() { | ||
return total; | ||
} | ||
|
||
@Override | ||
public double[] averagesPerComponent() { | ||
return averages; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters