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
7 changes: 4 additions & 3 deletions analysis/src/test/java/ComputeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Random;
import java.util.random.RandomGenerator;

import net.laprun.sustainability.power.SensorUnit;
import org.junit.jupiter.api.Test;

import net.laprun.sustainability.power.SensorMetadata;
Expand All @@ -13,9 +14,9 @@

public class ComputeTest {
private final static SensorMetadata metadata = SensorMetadata
.withNewComponent("cp1", null, true, "mW", false)
.withNewComponent("cp2", null, true, "mW", false)
.withNewComponent("cp3", null, true, "mW", false)
.withNewComponent("cp1", null, true, SensorUnit.mW)
.withNewComponent("cp2", null, true, SensorUnit.mW)
.withNewComponent("cp3", null, true, "mW")
.build();

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ class IFExporterTest {
public static final String COMPONENT2_NAME = "c2";
public static final String COMPONENT3_NAME = "c3";
private final static SensorMetadata metadata = SensorMetadata
.withNewComponent(COMPONENT1_NAME, "component 1", true, "mW", true)
.withNewComponent(COMPONENT2_NAME, "component 2", true, "mW", true)
.withNewComponent(COMPONENT3_NAME, "component 3", true, "mW", true)
.withNewComponent(COMPONENT1_NAME, "component 1", true, "mW")
.withNewComponent(COMPONENT2_NAME, "component 2", true, "mW")
.withNewComponent(COMPONENT3_NAME, "component 3", true, "mW")
.build();

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ class TotalMeasureProcessorTest {
void totalShouldFailIfAllComponentsAreNotCommensurable() {
final var inError = "cp2";
final var metadata = SensorMetadata
.withNewComponent("cp1", null, true, "mW", true)
.withNewComponent(inError, null, true, "mJ", true)
.withNewComponent("cp1", null, true, "mW")
.withNewComponent(inError, null, true, "mJ")
.build();

final var expectedResultUnit = SensorUnit.W;
Expand All @@ -29,9 +29,9 @@ void totalShouldFailIfAllComponentsAreNotCommensurable() {
@Test
void testTotal() {
final var metadata = SensorMetadata
.withNewComponent("cp1", null, true, "mW", true)
.withNewComponent("cp2", null, true, "mW", true)
.withNewComponent("cp3", null, true, "mW", true)
.withNewComponent("cp1", null, true, "mW")
.withNewComponent("cp2", null, true, "mW")
.withNewComponent("cp3", null, true, "mW")
.build();

final var m1c1 = 10.0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,11 @@

public class OngoingPowerMeasureTest {
private final static SensorMetadata metadata = SensorMetadata
.withNewComponent("cp1", null, true, "mW", true)
.withNewComponent("cp2", null, true, "mW", true)
.withNewComponent("cp3", null, true, "mW", true)
.withNewComponent("cp1", null, true, "mW")
.withNewComponent("cp2", null, true, "mW")
.withNewComponent("cp3", null, true, "mW")
.build();

@Test
void checkThatTotalComponentIsProperlyAdded() {
final var metadata = SensorMetadata
.withNewComponent("cp1", null, true, "mW", false)
.withNewComponent("cp2", null, true, "mW", false)
.withNewComponent("cp3", null, true, "mW", false)
.build();
var measure = new OngoingPowerMeasure(metadata);
assertThat(measure.metadata().totalComponents()).isEmpty();
}

@Test
void testBasics() {
final var m1c1 = 10.0;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package net.laprun.sustainability.power;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.Comparator;
Expand All @@ -22,9 +21,6 @@ public class SensorMetadata {
private final Map<String, ComponentMetadata> components;
@JsonProperty("documentation")
private final String documentation;
// todo: remove
@JsonProperty("totalComponents")
private final int[] totalComponents;

/**
* Initializes sensor metadata information
Expand All @@ -36,24 +32,23 @@ public class SensorMetadata {
*/
public SensorMetadata(List<ComponentMetadata> components, String documentation) {
Objects.requireNonNull(components, "Must provide components");
if (components.isEmpty()) {
throw new IllegalArgumentException("Must provide at least one component");
}

final var cardinality = components.size();
this.components = new HashMap<>(cardinality);
this.documentation = documentation;
final var errors = new Errors();
final var indices = new BitSet(cardinality);
final var totalIndices = new BitSet(cardinality);
final var baseUnit = new SensorUnit[1];
components.forEach(component -> {
// check that index is valid
final var index = component.index;
boolean indexValid = true;
if (index < 0 || index >= cardinality) {
errors.addError(index + " is not a valid index: must be between 0 and " + (cardinality - 1));
indexValid = false;
} else if (indices.get(index)) {
errors.addError("Multiple components are using index " + index + ": "
+ components.stream().filter(cm -> index == cm.index).toList());
indexValid = false;
} else {
// record index as known
indices.set(index);
Expand All @@ -78,35 +73,29 @@ public SensorMetadata(List<ComponentMetadata> components, String documentation)
if (errors.hasErrors()) {
throw new IllegalArgumentException(errors.formatErrors());
}

this.totalComponents = totalIndices.stream().toArray();
}

@JsonCreator
SensorMetadata(Map<String, ComponentMetadata> components, String documentation, int[] totalComponents) {
SensorMetadata(Map<String, ComponentMetadata> components, String documentation) {
this.components = components;
this.documentation = documentation;
this.totalComponents = totalComponents;
}

public static SensorMetadata.Builder withNewComponent(String name, String description, boolean isAttributed,
String unitSymbol,
boolean participatesInTotal) {
return new SensorMetadata.Builder().withNewComponent(name, description, isAttributed, unitSymbol, participatesInTotal);
String unitSymbol) {
return new SensorMetadata.Builder().withNewComponent(name, description, isAttributed, unitSymbol);
}

public static SensorMetadata.Builder withNewComponent(String name, String description, boolean isAttributed,
SensorUnit unit,
boolean participatesInTotal) {
return new SensorMetadata.Builder().withNewComponent(name, description, isAttributed, unit, participatesInTotal);
SensorUnit unit) {
return new SensorMetadata.Builder().withNewComponent(name, description, isAttributed, unit);
}

public static SensorMetadata.Builder from(SensorMetadata sensorMetadata) {
final var builder = new Builder();
sensorMetadata.components.values().stream().sorted(Comparator.comparing(ComponentMetadata::index))
.forEach(component -> builder.withNewComponent(component.name, component.description, component.isAttributed,
component.unit,
component.isIncludedInTotal));
component.unit));
return builder;
}

Expand All @@ -117,8 +106,7 @@ public String toString() {
.forEach(cm -> sb.append("- ").append(cm).append("\n"));
return "components:\n"
+ sb
+ "documentation: " + documentation + "\n"
+ "totalComponents: " + Arrays.toString(totalComponents);
+ "documentation: " + documentation;
}

/**
Expand Down Expand Up @@ -174,15 +162,6 @@ public String documentation() {
return documentation;
}

/**
* Retrieves the indices of the components that can be used to compute a total
*
* @return the indices of the components that can be used to compute a total
*/
public int[] totalComponents() {
return totalComponents;
}

/**
* Retrieves the metadata associated with the specified component index if it exists.
*
Expand All @@ -203,16 +182,14 @@ public static class Builder {
private int currentIndex = 0;
private String documentation;

public Builder withNewComponent(String name, String description, boolean isAttributed, String unitSymbol,
boolean isIncludedInTotal) {
public Builder withNewComponent(String name, String description, boolean isAttributed, String unitSymbol) {
components
.add(new ComponentMetadata(name, currentIndex++, description, isAttributed, unitSymbol, isIncludedInTotal));
.add(new ComponentMetadata(name, currentIndex++, description, isAttributed, unitSymbol));
return this;
}

public Builder withNewComponent(String name, String description, boolean isAttributed, SensorUnit unit,
boolean isIncludedInTotal) {
components.add(new ComponentMetadata(name, currentIndex++, description, isAttributed, unit, isIncludedInTotal));
public Builder withNewComponent(String name, String description, boolean isAttributed, SensorUnit unit) {
components.add(new ComponentMetadata(name, currentIndex++, description, isAttributed, unit));
return this;
}

Expand All @@ -239,12 +216,8 @@ public SensorMetadata build() {
* attributed share for each process needs to be performed. This is needed because some sensors only provide
* system-wide measures instead of on a per-process basis.
* @param unit a textual representation of the unit used for measures associated with this component (e.g. mW)
* @param isIncludedInTotal whether or not this component takes part in the computation to get a total power consumption
* metric for that sensor. Components that take part of the total computation must use a unit commensurable with
* {@link SensorUnit#W}
*/
public record ComponentMetadata(String name, int index, String description, boolean isAttributed, SensorUnit unit,
boolean isIncludedInTotal) {
public record ComponentMetadata(String name, int index, String description, boolean isAttributed, SensorUnit unit) {

public ComponentMetadata {
if (name == null) {
Expand All @@ -255,9 +228,8 @@ public record ComponentMetadata(String name, int index, String description, bool
}
}

public ComponentMetadata(String name, int index, String description, boolean isAttributed, String unitSymbol,
boolean isIncludedInTotal) {
this(name, index, description, isAttributed, SensorUnit.of(unitSymbol), isIncludedInTotal);
public ComponentMetadata(String name, int index, String description, boolean isAttributed, String unitSymbol) {
this(name, index, description, isAttributed, SensorUnit.of(unitSymbol));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ void shouldFailIfTotalComponentsAreOutOfRange() {
final var name = "comp0";
final var e = assertThrows(IllegalArgumentException.class,
() -> new SensorMetadata(
List.of(new SensorMetadata.ComponentMetadata(name, -1, null, true, SensorUnit.W, true)), ""));
List.of(new SensorMetadata.ComponentMetadata(name, -1, null, true, SensorUnit.W)), ""));
final var message = e.getMessage();
assertTrue(message.contains("range"));
assertTrue(message.contains("-1"));
Expand All @@ -23,7 +23,7 @@ void shouldFailIfTotalComponentsAreOutOfRange() {
void shouldFailIfComponentHasNullName() {
final var e = assertThrows(IllegalArgumentException.class,
() -> new SensorMetadata(
List.of(new SensorMetadata.ComponentMetadata(null, -1, null, true, (SensorUnit) null, true)), ""));
List.of(new SensorMetadata.ComponentMetadata(null, -1, null, true, (SensorUnit) null)), ""));
final var message = e.getMessage();
assertTrue(message.contains("Component name cannot be null"));
}
Expand All @@ -32,7 +32,7 @@ void shouldFailIfComponentHasNullName() {
void shouldFailIfComponentHasNullUnit() {
final var e = assertThrows(IllegalArgumentException.class,
() -> new SensorMetadata(
List.of(new SensorMetadata.ComponentMetadata("invalid", -1, null, true, (SensorUnit) null, true)), ""));
List.of(new SensorMetadata.ComponentMetadata("invalid", -1, null, true, (SensorUnit) null)), ""));
final var message = e.getMessage();
assertTrue(message.contains("Component unit cannot be null"));
}
Expand All @@ -42,8 +42,8 @@ void shouldFailOnDuplicatedComponentNames() {
final var name = "component";
final var e = assertThrows(IllegalArgumentException.class,
() -> new SensorMetadata(List.of(
new SensorMetadata.ComponentMetadata(name, 0, null, true, "mW", false),
new SensorMetadata.ComponentMetadata(name, 1, null, true, "mW", false)), ""));
new SensorMetadata.ComponentMetadata(name, 0, null, true, "mW"),
new SensorMetadata.ComponentMetadata(name, 1, null, true, "mW")), ""));
final var message = e.getMessage();
assertTrue(message.contains(name) && message.contains("0") && message.contains("1"));
}
Expand All @@ -52,8 +52,8 @@ void shouldFailOnDuplicatedComponentNames() {
void shouldFailIfComponentsDoNotCoverFullRange() {
final var e = assertThrows(IllegalArgumentException.class,
() -> new SensorMetadata(List.of(
new SensorMetadata.ComponentMetadata("foo", 0, null, true, "mW", false),
new SensorMetadata.ComponentMetadata("component2", 0, null, true, "mW", false)), ""));
new SensorMetadata.ComponentMetadata("foo", 0, null, true, "mW"),
new SensorMetadata.ComponentMetadata("component2", 0, null, true, "mW")), ""));
final var message = e.getMessage();
assertTrue(message.contains("Multiple components are using index 0"));
assertTrue(message.contains("foo"));
Expand All @@ -64,8 +64,11 @@ void shouldFailIfComponentsDoNotCoverFullRange() {
@Test
void shouldFailIfNoComponentsAreProvided() {
final var e = assertThrows(NullPointerException.class,
() -> new SensorMetadata(null, ""));
final var message = e.getMessage();
assertTrue(message.contains("Must provide components"));
() -> new SensorMetadata((List<SensorMetadata.ComponentMetadata>) null, ""));
assertEquals("Must provide components", e.getMessage());

final var e2 = assertThrows(IllegalArgumentException.class,
() -> new SensorMetadata(List.of(), ""));
assertEquals("Must provide at least one component", e2.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ private IntelRAPLSensor(SortedMap<String, RAPLFile> files) {
final var metadata = new ArrayList<SensorMetadata.ComponentMetadata>(rawOffset * 2);
int fileNb = 0;
for (String name : files.keySet()) {
metadata.add(new SensorMetadata.ComponentMetadata(name, fileNb, name, false, mW, true));
metadata.add(new SensorMetadata.ComponentMetadata(name, fileNb, name, false, mW));
final var rawName = name + "_uj";
metadata.add(new SensorMetadata.ComponentMetadata(rawName, fileNb + rawOffset,
name + " (raw micro Joule data)", false, µJ, false));
name + " (raw micro Joule data)", false, µJ));
fileNb++;
}
this.metadata = new SensorMetadata(metadata,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@

class AppleSiliconCPU extends CPU {
private static final SensorMetadata.ComponentMetadata cpuComponent = new SensorMetadata.ComponentMetadata(CPU, 0,
"CPU power", true, mW, true);
"CPU power", true, mW);
private static final SensorMetadata.ComponentMetadata gpuComponent = new SensorMetadata.ComponentMetadata(GPU, 1,
"GPU power", true, mW, true);
"GPU power", true, mW);
private static final SensorMetadata.ComponentMetadata aneComponent = new SensorMetadata.ComponentMetadata(ANE, 2,
"Apple Neural Engine power", false, mW, true);
"Apple Neural Engine power", false, mW);
private static final SensorMetadata.ComponentMetadata cpuShareComponent = new SensorMetadata.ComponentMetadata(CPU_SHARE, 3,
"Computed share of CPU", false, decimalPercentage, false);
"Computed share of CPU", false, decimalPercentage);
private static final String COMBINED = "Combined";
private static final String POWER_INDICATOR = " Power: ";
private static final int POWER_INDICATOR_LENGTH = POWER_INDICATOR.length();
Expand Down Expand Up @@ -44,7 +44,7 @@ private void addComponentTo(String name, List<SensorMetadata.ComponentMetadata>
break;
default:
final var index = components.size();
components.add(new SensorMetadata.ComponentMetadata(name, index, name, false, mW, true));
components.add(new SensorMetadata.ComponentMetadata(name, index, name, false, mW));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
class IntelCPU extends CPU {

private static final SensorMetadata.ComponentMetadata packageComponent = new SensorMetadata.ComponentMetadata(PACKAGE, 0,
"Intel energy model derived package power (CPUs+GT+SA)", true, W, true);
"Intel energy model derived package power (CPUs+GT+SA)", true, W);
private static final SensorMetadata.ComponentMetadata cpuShareComponent = new SensorMetadata.ComponentMetadata(CPU_SHARE, 1,
"Computed share of CPU", false, decimalPercentage, false);
"Computed share of CPU", false, decimalPercentage);

@Override
public boolean doneExtractingPowerComponents(String line, HashMap<String, Number> powerComponents) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
public class TestPowerSensor extends AbstractPowerSensor<MapMeasures> {
public static final String CPU = "cpu";
public static final SensorMetadata DEFAULT = new SensorMetadata(
List.of(new SensorMetadata.ComponentMetadata(CPU, 0, "CPU", true, mW, true)),
List.of(new SensorMetadata.ComponentMetadata(CPU, 0, "CPU", true, mW)),
"Test PowerSensor returning random values for a single 'cpu' component");
private final SensorMetadata metadata;
private boolean started;
Expand Down
Loading