From b83dc1db81fc5b2e0a408cfa0fd7b59b38901ad5 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Thu, 30 Oct 2025 19:38:44 +0100 Subject: [PATCH 1/2] refactor: move PowerMeasurer to backend module and reuse in server --- backend/pom.xml | 19 +++-- .../power/sensors}/PowerMeasurer.java | 5 +- cli/pom.xml | 5 -- .../net/laprun/sustainability/cli/Power.java | 4 +- server/pom.xml | 5 -- .../sustainability/power/PowerMeasurer.java | 83 ------------------- .../sustainability/power/PowerResource.java | 6 +- .../power/MockPowerMeasurer.java | 1 + .../power/PowerResourceTest.java | 1 + 9 files changed, 23 insertions(+), 106 deletions(-) rename {cli/src/main/java/net/laprun/sustainability/cli => backend/src/main/java/net/laprun/sustainability/power/sensors}/PowerMeasurer.java (94%) delete mode 100644 server/src/main/java/net/laprun/sustainability/power/PowerMeasurer.java diff --git a/backend/pom.xml b/backend/pom.xml index c53220db..e2f4c2a0 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -11,6 +11,10 @@ power-server : backend Power consumption measuring backend + + 3.0.0 + + net.laprun.sustainability @@ -18,18 +22,23 @@ ${project.version} - io.quarkus - quarkus-arc + net.laprun.sustainability + power-server-persistence + ${project.version} io.quarkus - quarkus-junit5 - test + quarkus-arc com.zaxxer nuprocess - 3.0.0 + ${nuprocess.version} + + + io.quarkus + quarkus-junit5 + test diff --git a/cli/src/main/java/net/laprun/sustainability/cli/PowerMeasurer.java b/backend/src/main/java/net/laprun/sustainability/power/sensors/PowerMeasurer.java similarity index 94% rename from cli/src/main/java/net/laprun/sustainability/cli/PowerMeasurer.java rename to backend/src/main/java/net/laprun/sustainability/power/sensors/PowerMeasurer.java index 3ce4633a..e4d038a3 100644 --- a/cli/src/main/java/net/laprun/sustainability/cli/PowerMeasurer.java +++ b/backend/src/main/java/net/laprun/sustainability/power/sensors/PowerMeasurer.java @@ -1,4 +1,4 @@ -package net.laprun.sustainability.cli; +package net.laprun.sustainability.power.sensors; import java.time.Duration; import java.util.Map; @@ -15,9 +15,6 @@ import net.laprun.sustainability.power.SensorMeasure; import net.laprun.sustainability.power.SensorMetadata; import net.laprun.sustainability.power.persistence.Persistence; -import net.laprun.sustainability.power.sensors.Measures; -import net.laprun.sustainability.power.sensors.PowerSensor; -import net.laprun.sustainability.power.sensors.RegisteredPID; @ApplicationScoped public class PowerMeasurer { diff --git a/cli/pom.xml b/cli/pom.xml index fb8c759a..e339d881 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -21,11 +21,6 @@ power-server-measure ${project.version} - - net.laprun.sustainability - power-server-persistence - ${project.version} - io.quarkus quarkus-picocli diff --git a/cli/src/main/java/net/laprun/sustainability/cli/Power.java b/cli/src/main/java/net/laprun/sustainability/cli/Power.java index 29afcf99..c6530e95 100644 --- a/cli/src/main/java/net/laprun/sustainability/cli/Power.java +++ b/cli/src/main/java/net/laprun/sustainability/cli/Power.java @@ -30,9 +30,9 @@ public class Power implements Runnable { "--command" }, required = true, description = "Command to measure energy consumption for") String cmd; - private final PowerMeasurer measurer; + private final net.laprun.sustainability.power.sensors.PowerMeasurer measurer; - public Power(PowerMeasurer measurer) throws IOException { + public Power(net.laprun.sustainability.power.sensors.PowerMeasurer measurer) throws IOException { this.measurer = measurer; } diff --git a/server/pom.xml b/server/pom.xml index b89df8b3..a91bc16c 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -19,11 +19,6 @@ power-server-backend ${project.version} - - net.laprun.sustainability - power-server-persistence - ${project.version} - io.quarkus quarkus-rest-jackson diff --git a/server/src/main/java/net/laprun/sustainability/power/PowerMeasurer.java b/server/src/main/java/net/laprun/sustainability/power/PowerMeasurer.java deleted file mode 100644 index b41e8501..00000000 --- a/server/src/main/java/net/laprun/sustainability/power/PowerMeasurer.java +++ /dev/null @@ -1,83 +0,0 @@ -package net.laprun.sustainability.power; - -import java.time.Duration; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import org.eclipse.microprofile.config.inject.ConfigProperty; - -import io.smallrye.mutiny.Multi; -import io.smallrye.mutiny.infrastructure.Infrastructure; -import io.smallrye.mutiny.subscription.Cancellable; -import net.laprun.sustainability.power.persistence.Persistence; -import net.laprun.sustainability.power.sensors.Measures; -import net.laprun.sustainability.power.sensors.PowerSensor; -import net.laprun.sustainability.power.sensors.RegisteredPID; - -@ApplicationScoped -public class PowerMeasurer { - - public static final String DEFAULT_SAMPLING_PERIOD = "PT0.5S"; - @Inject - PowerSensor sensor; - - @Inject - Persistence persistence; - - @ConfigProperty(name = "net.laprun.sustainability.power.sampling-period", defaultValue = DEFAULT_SAMPLING_PERIOD) - Duration samplingPeriod; - - private Multi periodicSensorCheck; - - public Multi stream(String pid) throws Exception { - final var parsedPID = validPIDOrFail(pid); - return uncheckedStream(parsedPID); - } - - public Multi uncheckedStream(long pid) throws Exception { - final var registeredPID = track(pid); - return periodicSensorCheck.map(measures -> measures.getOrDefault(registeredPID)); - } - - public Cancellable startTrackingApp(String appName, long pid) throws Exception { - return uncheckedStream(pid).subscribe().with(m -> persistence.save(m, appName)); - } - - public Cancellable startTrackingProcess(Process process) throws Exception { - return startTrackingApp(process.info().commandLine().orElseThrow(), process.pid()); - } - - private RegisteredPID track(long pid) throws Exception { - if (!sensor.isStarted()) { - sensor.start(samplingPeriod.toMillis()); - periodicSensorCheck = Multi.createFrom().ticks() - .every(samplingPeriod) - .log() - .map(sensor::update) - .broadcast() - .withCancellationAfterLastSubscriberDeparture() - .toAtLeast(1) - .runSubscriptionOn(Infrastructure.getDefaultWorkerPool()); - } - final var registeredPID = sensor.register(pid); - // todo: the timing of things could make it so that the pid has been removed before the map operation occurs so - // currently return -1 instead of null but this needs to be properly addressed - periodicSensorCheck = periodicSensorCheck.onCancellation().invoke(() -> sensor.unregister(registeredPID)); - return registeredPID; - } - - public long validPIDOrFail(String pid) { - final var parsedPID = Long.parseLong(pid); - ProcessHandle.of(parsedPID).orElseThrow(() -> new IllegalArgumentException("Unknown process: " + pid)); - return parsedPID; - } - - public SensorMetadata metadata() { - return sensor.metadata(); - } - - public Duration getSamplingPeriod() { - return samplingPeriod; - } -} diff --git a/server/src/main/java/net/laprun/sustainability/power/PowerResource.java b/server/src/main/java/net/laprun/sustainability/power/PowerResource.java index c07a65eb..6e267368 100644 --- a/server/src/main/java/net/laprun/sustainability/power/PowerResource.java +++ b/server/src/main/java/net/laprun/sustainability/power/PowerResource.java @@ -18,6 +18,8 @@ import io.quarkus.runtime.StartupEvent; import io.smallrye.mutiny.Multi; import net.laprun.sustainability.power.persistence.Measure; +import net.laprun.sustainability.power.persistence.Persistence; +import net.laprun.sustainability.power.sensors.PowerMeasurer; @Path("/power") public class PowerResource { @@ -44,7 +46,7 @@ public Multi streamMeasuresFor(@PathParam("pid") String pid) thro @Path("start/{appName}/{pid}") public void startMeasure(@PathParam("appName") String appName, @PathParam("pid") String pid) throws Exception { try { - measurer.startTrackingApp(appName, measurer.validPIDOrFail(pid)); + measurer.startTrackingApp(appName, measurer.validPIDOrFail(pid), Persistence.defaultSession(appName)); } catch (IllegalArgumentException e) { throw new NotFoundException("Unknown process: " + pid); } @@ -59,7 +61,7 @@ public SensorMetadata metadata() { @GET @Path("sampling") public Duration samplingPeriod() { - return measurer.getSamplingPeriod(); + return measurer.samplingPeriod(); } @GET diff --git a/server/src/test/java/net/laprun/sustainability/power/MockPowerMeasurer.java b/server/src/test/java/net/laprun/sustainability/power/MockPowerMeasurer.java index b0800603..47ac5cb4 100644 --- a/server/src/test/java/net/laprun/sustainability/power/MockPowerMeasurer.java +++ b/server/src/test/java/net/laprun/sustainability/power/MockPowerMeasurer.java @@ -1,6 +1,7 @@ package net.laprun.sustainability.power; import io.quarkus.test.Mock; +import net.laprun.sustainability.power.sensors.PowerMeasurer; @Mock @SuppressWarnings("unused") diff --git a/server/src/test/java/net/laprun/sustainability/power/PowerResourceTest.java b/server/src/test/java/net/laprun/sustainability/power/PowerResourceTest.java index 1642b0d5..008f598e 100644 --- a/server/src/test/java/net/laprun/sustainability/power/PowerResourceTest.java +++ b/server/src/test/java/net/laprun/sustainability/power/PowerResourceTest.java @@ -23,6 +23,7 @@ import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.junit.QuarkusTest; +import net.laprun.sustainability.power.sensors.PowerMeasurer; @QuarkusTest public class PowerResourceTest { From 32364dde64824464ac33cc103226803253c526ab Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Thu, 30 Oct 2025 19:40:48 +0100 Subject: [PATCH 2/2] refactor: rename PowerMeasurer to SamplingMeasurer --- .../sensors/{PowerMeasurer.java => SamplingMeasurer.java} | 2 +- cli/src/main/java/net/laprun/sustainability/cli/Power.java | 5 +++-- .../java/net/laprun/sustainability/power/PowerResource.java | 4 ++-- .../{MockPowerMeasurer.java => MockSamplingMeasurer.java} | 4 ++-- .../net/laprun/sustainability/power/PowerResourceTest.java | 4 ++-- 5 files changed, 10 insertions(+), 9 deletions(-) rename backend/src/main/java/net/laprun/sustainability/power/sensors/{PowerMeasurer.java => SamplingMeasurer.java} (99%) rename server/src/test/java/net/laprun/sustainability/power/{MockPowerMeasurer.java => MockSamplingMeasurer.java} (62%) diff --git a/backend/src/main/java/net/laprun/sustainability/power/sensors/PowerMeasurer.java b/backend/src/main/java/net/laprun/sustainability/power/sensors/SamplingMeasurer.java similarity index 99% rename from backend/src/main/java/net/laprun/sustainability/power/sensors/PowerMeasurer.java rename to backend/src/main/java/net/laprun/sustainability/power/sensors/SamplingMeasurer.java index e4d038a3..f0029afc 100644 --- a/backend/src/main/java/net/laprun/sustainability/power/sensors/PowerMeasurer.java +++ b/backend/src/main/java/net/laprun/sustainability/power/sensors/SamplingMeasurer.java @@ -17,7 +17,7 @@ import net.laprun.sustainability.power.persistence.Persistence; @ApplicationScoped -public class PowerMeasurer { +public class SamplingMeasurer { public static final String DEFAULT_SAMPLING_PERIOD = "PT0.5S"; @Inject diff --git a/cli/src/main/java/net/laprun/sustainability/cli/Power.java b/cli/src/main/java/net/laprun/sustainability/cli/Power.java index c6530e95..37024eba 100644 --- a/cli/src/main/java/net/laprun/sustainability/cli/Power.java +++ b/cli/src/main/java/net/laprun/sustainability/cli/Power.java @@ -14,6 +14,7 @@ import net.laprun.sustainability.power.analysis.total.TotalSyntheticComponent; import net.laprun.sustainability.power.nuprocess.BaseProcessHandler; import net.laprun.sustainability.power.persistence.Persistence; +import net.laprun.sustainability.power.sensors.SamplingMeasurer; import picocli.CommandLine; @CommandLine.Command @@ -30,9 +31,9 @@ public class Power implements Runnable { "--command" }, required = true, description = "Command to measure energy consumption for") String cmd; - private final net.laprun.sustainability.power.sensors.PowerMeasurer measurer; + private final SamplingMeasurer measurer; - public Power(net.laprun.sustainability.power.sensors.PowerMeasurer measurer) throws IOException { + public Power(SamplingMeasurer measurer) { this.measurer = measurer; } diff --git a/server/src/main/java/net/laprun/sustainability/power/PowerResource.java b/server/src/main/java/net/laprun/sustainability/power/PowerResource.java index 6e267368..5dc23683 100644 --- a/server/src/main/java/net/laprun/sustainability/power/PowerResource.java +++ b/server/src/main/java/net/laprun/sustainability/power/PowerResource.java @@ -19,12 +19,12 @@ import io.smallrye.mutiny.Multi; import net.laprun.sustainability.power.persistence.Measure; import net.laprun.sustainability.power.persistence.Persistence; -import net.laprun.sustainability.power.sensors.PowerMeasurer; +import net.laprun.sustainability.power.sensors.SamplingMeasurer; @Path("/power") public class PowerResource { @Inject - PowerMeasurer measurer; + SamplingMeasurer measurer; public void onStartup(@Observes StartupEvent event) { Log.info("\nConfigured sampling period: " + samplingPeriod() + diff --git a/server/src/test/java/net/laprun/sustainability/power/MockPowerMeasurer.java b/server/src/test/java/net/laprun/sustainability/power/MockSamplingMeasurer.java similarity index 62% rename from server/src/test/java/net/laprun/sustainability/power/MockPowerMeasurer.java rename to server/src/test/java/net/laprun/sustainability/power/MockSamplingMeasurer.java index 47ac5cb4..2fb17f44 100644 --- a/server/src/test/java/net/laprun/sustainability/power/MockPowerMeasurer.java +++ b/server/src/test/java/net/laprun/sustainability/power/MockSamplingMeasurer.java @@ -1,11 +1,11 @@ package net.laprun.sustainability.power; import io.quarkus.test.Mock; -import net.laprun.sustainability.power.sensors.PowerMeasurer; +import net.laprun.sustainability.power.sensors.SamplingMeasurer; @Mock @SuppressWarnings("unused") -public class MockPowerMeasurer extends PowerMeasurer { +public class MockSamplingMeasurer extends SamplingMeasurer { @Override public long validPIDOrFail(String pid) { diff --git a/server/src/test/java/net/laprun/sustainability/power/PowerResourceTest.java b/server/src/test/java/net/laprun/sustainability/power/PowerResourceTest.java index 008f598e..972fa13f 100644 --- a/server/src/test/java/net/laprun/sustainability/power/PowerResourceTest.java +++ b/server/src/test/java/net/laprun/sustainability/power/PowerResourceTest.java @@ -23,7 +23,7 @@ import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.junit.QuarkusTest; -import net.laprun.sustainability.power.sensors.PowerMeasurer; +import net.laprun.sustainability.power.sensors.SamplingMeasurer; @QuarkusTest public class PowerResourceTest { @@ -61,7 +61,7 @@ public void samplingPeriod() { .then() .statusCode(200) .extract().body().as(Duration.class); - assertEquals(Duration.parse(PowerMeasurer.DEFAULT_SAMPLING_PERIOD), duration); + assertEquals(Duration.parse(SamplingMeasurer.DEFAULT_SAMPLING_PERIOD), duration); } protected long getPid() {