Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions if-manifest-export/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?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.12-SNAPSHOT</version>
</parent>

<artifactId>power-server-if-manifest-export</artifactId>
<name>power-server : GSF Impact Framework exporter</name>
<description>Exports power measures as an Impact Framework manifest</description>

<dependencies>
<dependency>
<groupId>net.laprun.sustainability</groupId>
<artifactId>if-manifest-java</artifactId>
<version>0.0.2</version>
</dependency>
<dependency>
<groupId>net.laprun.sustainability</groupId>
<artifactId>power-server-measure</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>

<build>
<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>${project.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package net.laprun.sustainability.power.impactframework.export;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import net.laprun.sustainability.impactframework.manifest.Child;
import net.laprun.sustainability.impactframework.manifest.Initialize;
import net.laprun.sustainability.impactframework.manifest.Input;
import net.laprun.sustainability.impactframework.manifest.Manifest;
import net.laprun.sustainability.impactframework.manifest.Metadata;
import net.laprun.sustainability.impactframework.manifest.Plugin;
import net.laprun.sustainability.impactframework.manifest.Tree;
import net.laprun.sustainability.power.SensorMetadata;
import net.laprun.sustainability.power.measure.PowerMeasure;
import net.laprun.sustainability.power.measure.StoppedPowerMeasure;

public enum IFExporter {
;

private final static String prefix = "power-server-";
private final static Initialize defaultInitialize = new Initialize(Map.of("sum", new Plugin("sum", "builtin", "Sum")));
public static final String CHILD_NAME = prefix + "child";

public static Manifest export(StoppedPowerMeasure measure) {
final var ifMetadata = new Metadata("power-server measure", null, Set.of("power-server"));

final var samples = measure.numberOfSamples();
final List<Input> inputs = new ArrayList<>(samples);
final var sensorMetadata = measure.metadata();
final int samplingFrequency = (int) measure.duration().dividedBy(samples).toMillis();

final var components = sensorMetadata.components();
for (int i = 0; i < samples; i++) {
final var values = measure.getNthTimestampedMeasures(i);
inputs.add(toInput(samplingFrequency, values, components));
}

return new Manifest(ifMetadata, defaultInitialize,
new Tree(Map.of(CHILD_NAME, new Child(inputs))));
}

public static String getInputValueName(String componentName) {
return prefix + componentName;
}

private static Input toInput(int samplingFrequency, PowerMeasure.TimestampedMeasures values,
Map<String, SensorMetadata.ComponentMetadata> components) {
final var inputValues = new TreeMap<String, Object>();
components.values().forEach(
component -> inputValues.put(getInputValueName(component.name()), values.measures()[component.index()]));
return new Input(Instant.ofEpochMilli(values.timestamp()), samplingFrequency, inputValues);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package net.laprun.sustainability.power.impactframework.export;

import static org.junit.jupiter.api.Assertions.*;

import java.util.Map;

import org.junit.jupiter.api.Test;

import net.laprun.sustainability.power.SensorMetadata;
import net.laprun.sustainability.power.measure.OngoingPowerMeasure;
import net.laprun.sustainability.power.measure.StoppedPowerMeasure;

class IFExporterTest {
public static final String COMPONENT1_NAME = "c1";
public static final String COMPONENT2_NAME = "c2";
public static final String COMPONENT3_NAME = "c3";
private final static SensorMetadata metadata = new SensorMetadata(Map.of(
COMPONENT1_NAME, new SensorMetadata.ComponentMetadata(COMPONENT1_NAME, 0, "component 1", true, "mW"),
COMPONENT2_NAME, new SensorMetadata.ComponentMetadata(COMPONENT2_NAME, 1, "component 2", true, "mW"),
COMPONENT3_NAME, new SensorMetadata.ComponentMetadata(COMPONENT3_NAME, 2, "always zero", false, "mW")), null,
new int[] { 0, 1, 2 });

@Test
void export() {
final var m1c1 = 10.0;
final var m1c2 = 12.0;
final var m1c3 = 0.0;
final var m2c1 = 8.0;
final var m2c2 = 17.0;
final var m2c3 = 0.0;
final var m3c1 = 5.0;
final var m3c2 = 5.0;
final var m3c3 = 0.0;

final var measure = new OngoingPowerMeasure(metadata);

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

final var manifest = IFExporter.export(new StoppedPowerMeasure(measure));
assertNotNull(manifest);
final var child = manifest.tree().children().get(IFExporter.CHILD_NAME);
assertNotNull(child);
final var inputs = child.inputs();
assertNotNull(inputs);
assertEquals(3, inputs.size());
final var input = inputs.get(1);
final var values = input.values();
assertEquals(m2c1, values.get(IFExporter.getInputValueName(COMPONENT1_NAME)));
assertEquals(m2c2, values.get(IFExporter.getInputValueName(COMPONENT2_NAME)));
assertEquals(m2c3, values.get(IFExporter.getInputValueName(COMPONENT3_NAME)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import java.util.BitSet;
import java.util.Objects;
import java.util.Optional;
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;
Expand All @@ -15,13 +18,13 @@ public class OngoingPowerMeasure implements PowerMeasure {
private final BitSet nonZeroComponents;
private final int[] totalComponents;
private final int totalIndex;
private final double[][] measures;
private final ComponentProcessor[] analyzers;
private double minTotal = Double.MAX_VALUE;
private double maxTotal;
private double accumulatedTotal;
private int samples;
private final double[][] measures;
private long[] timestamps;
private final ComponentProcessor[] analyzers;

public OngoingPowerMeasure(SensorMetadata sensorMetadata, ComponentProcessor... analyzers) {
this.sensorMetadata = sensorMetadata;
Expand Down Expand Up @@ -50,7 +53,6 @@ public SensorMetadata metadata() {
}

public void recordMeasure(double[] components) {
final var previousSize = samples;
samples++;
for (int component = 0; component < components.length; component++) {
final var componentValue = components[component];
Expand Down Expand Up @@ -115,15 +117,51 @@ public double maxMeasuredTotal() {

@Override
public Optional<double[]> getMeasuresFor(int component) {
return measuresFor(component, samples);
}

Optional<double[]> measuresFor(int component, int upToIndex) {
if (nonZeroComponents.get(component)) {
final var dest = new double[samples];
System.arraycopy(measures[component], 0, dest, 0, samples);
final var dest = new double[upToIndex];
System.arraycopy(measures[component], 0, dest, 0, upToIndex);
return Optional.of(dest);
} else {
return Optional.empty();
}
}

@Override
public Stream<TimestampedValue> streamTimestampedMeasuresFor(int component, int upToIndex) {
final var componentMeasures = measures[component];
return indicesFor(component, upToIndex)
.mapToObj(index -> new TimestampedValue(timestamps[index], componentMeasures[index]));
}

@Override
public DoubleStream streamMeasuresFor(int component, int upToIndex) {
final var componentMeasures = measures[component];
return indicesFor(component, upToIndex).mapToDouble(index -> componentMeasures[index]);
}

IntStream indicesFor(int component, int upToIndex) {
upToIndex = Math.min(upToIndex, samples - 1);
if (upToIndex >= 0 && nonZeroComponents.get(component)) {
return IntStream.range(0, upToIndex);
} else {
return IntStream.empty();
}
}

@Override
public TimestampedMeasures getNthTimestampedMeasures(int n) {
n = Math.min(n, samples - 1);
final var result = new double[measures.length];
for (int i = 0; i < measures.length; i++) {
result[i] = measures[i][n];
}
return new TimestampedMeasures(timestamps[n], result);
}

@Override
public ComponentProcessor[] analyzers() {
return analyzers;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.time.Duration;
import java.util.Optional;
import java.util.stream.DoubleStream;
import java.util.stream.Stream;

import net.laprun.sustainability.power.SensorMetadata;
import net.laprun.sustainability.power.analysis.ComponentProcessor;
Expand Down Expand Up @@ -38,5 +40,17 @@ static String readableWithUnit(double milliWatts) {

Optional<double[]> getMeasuresFor(int component);

TimestampedMeasures getNthTimestampedMeasures(int n);

Stream<TimestampedValue> streamTimestampedMeasuresFor(int component, int upToIndex);

DoubleStream streamMeasuresFor(int component, int upToIndex);

record TimestampedValue(long timestamp, double value) {
}

record TimestampedMeasures(long timestamp, double[] measures) {
}

ComponentProcessor[] analyzers();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,30 @@

import java.time.Duration;
import java.util.Optional;
import java.util.stream.DoubleStream;
import java.util.stream.Stream;

import net.laprun.sustainability.power.SensorMetadata;
import net.laprun.sustainability.power.analysis.ComponentProcessor;

@SuppressWarnings("unused")
public class StoppedPowerMeasure implements PowerMeasure {
private final SensorMetadata sensorMetadata;
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 final double[][] measures;
private final ComponentProcessor[] processors;

public StoppedPowerMeasure(PowerMeasure powerMeasure) {
this.sensorMetadata = powerMeasure.metadata();
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();
measures = new double[cardinality][samples];
for (int i = 0; i < cardinality; i++) {
measures[i] = powerMeasure.getMeasuresFor(i).orElse(null);
}
processors = powerMeasure.analyzers();
}

Expand Down Expand Up @@ -59,12 +56,34 @@ public int numberOfSamples() {

@Override
public SensorMetadata metadata() {
return sensorMetadata;
return measure.metadata();
}

@Override
public Optional<double[]> getMeasuresFor(int component) {
return Optional.ofNullable(measures[component]);
return measure.measuresFor(component, samples);
}

@Override
public Stream<TimestampedValue> streamTimestampedMeasuresFor(int component, int upToIndex) {
upToIndex = ensureIndex(upToIndex);
return measure.streamTimestampedMeasuresFor(component, upToIndex);
}

@Override
public DoubleStream streamMeasuresFor(int component, int upToIndex) {
upToIndex = ensureIndex(upToIndex);
return measure.streamMeasuresFor(component, upToIndex);
}

@Override
public TimestampedMeasures getNthTimestampedMeasures(int n) {
n = ensureIndex(n);
return measure.getNthTimestampedMeasures(n);
}

private int ensureIndex(int upToIndex) {
return Math.min(upToIndex, samples - 1);
}

@Override
Expand Down
Loading
Loading