Skip to content

Commit 393ee99

Browse files
committed
feat: NuProcess-based ProcessWrapper implementation
1 parent b823d80 commit 393ee99

File tree

6 files changed

+111
-6
lines changed

6 files changed

+111
-6
lines changed

backend/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
<artifactId>quarkus-junit5</artifactId>
2727
<scope>test</scope>
2828
</dependency>
29+
<dependency>
30+
<groupId>com.zaxxer</groupId>
31+
<artifactId>nuprocess</artifactId>
32+
<version>2.0.6</version>
33+
</dependency>
2934
</dependencies>
3035
<build>
3136
<plugins>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package net.laprun.sustainability.power.sensors.macos.powermetrics;
2+
3+
import java.nio.ByteBuffer;
4+
5+
class GrowableBuffer {
6+
private ByteBuffer buffer = ByteBuffer.allocate(20000);
7+
8+
public void put(ByteBuffer input) {
9+
if (buffer.remaining() < input.remaining()) {
10+
var newBuffer = ByteBuffer.allocate(buffer.capacity() + input.remaining());
11+
buffer.flip();
12+
newBuffer.put(buffer);
13+
buffer = newBuffer;
14+
} else {
15+
buffer.put(input);
16+
}
17+
}
18+
19+
public byte[] array() {
20+
return buffer.array();
21+
}
22+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package net.laprun.sustainability.power.sensors.macos.powermetrics;
2+
3+
import java.io.InputStream;
4+
import java.util.concurrent.ExecutionException;
5+
6+
import com.zaxxer.nuprocess.NuProcess;
7+
import com.zaxxer.nuprocess.NuProcessBuilder;
8+
9+
public class NuProcessWrapper implements ProcessWrapper {
10+
private final PowermetricsProcessHandler metadataHandler;
11+
private PowermetricsProcessHandler measureHandler;
12+
private String periodInMilliSecondsAsString;
13+
private long periodInMilliSeconds;
14+
15+
public NuProcessWrapper() {
16+
metadataHandler = new PowermetricsProcessHandler("cpu_power", "-i", "10", "-n", "1");
17+
}
18+
19+
private NuProcess exec(PowermetricsProcessHandler handler) {
20+
if (handler == null)
21+
throw new IllegalArgumentException("Handler cannot be null");
22+
return new NuProcessBuilder(handler, handler.comand()).start();
23+
}
24+
25+
@Override
26+
public InputStream streamForMetadata() {
27+
exec(metadataHandler);
28+
try {
29+
return metadataHandler.getInputStream().get();
30+
} catch (InterruptedException | ExecutionException e) {
31+
throw new RuntimeException(e);
32+
}
33+
}
34+
35+
@Override
36+
public void start(long periodInMilliSeconds) {
37+
// todo? check if asked period is the same as the current used one
38+
this.periodInMilliSeconds = periodInMilliSeconds > 100 ? periodInMilliSeconds - 50 : periodInMilliSeconds;
39+
this.periodInMilliSecondsAsString = Long.toString(this.periodInMilliSeconds);
40+
}
41+
42+
@Override
43+
public void stop() {
44+
if (measureHandler != null) {
45+
measureHandler.stop();
46+
measureHandler = null;
47+
}
48+
}
49+
50+
@Override
51+
public boolean isRunning() {
52+
return measureHandler != null && measureHandler.isRunning();
53+
}
54+
55+
@Override
56+
public InputStream streamForMeasure() {
57+
if (!isRunning()) {
58+
measureHandler = new PowermetricsProcessHandler("cpu_power,tasks",
59+
"--show-process-samp-norm", "--show-process-gpu", "-i",
60+
periodInMilliSecondsAsString, "-n", "1");
61+
exec(measureHandler);
62+
try {
63+
return measureHandler.getInputStream().get();
64+
} catch (InterruptedException | ExecutionException e) {
65+
throw new RuntimeException(e);
66+
}
67+
}
68+
throw new IllegalStateException("Measure is still running");
69+
}
70+
}

backend/src/main/java/net/laprun/sustainability/power/sensors/macos/powermetrics/PowermetricsProcessHandler.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import java.io.InputStream;
55
import java.nio.ByteBuffer;
66
import java.util.Arrays;
7+
import java.util.concurrent.CompletableFuture;
8+
import java.util.concurrent.Future;
79
import java.util.concurrent.TimeUnit;
810

911
import com.zaxxer.nuprocess.NuAbstractProcessHandler;
@@ -13,7 +15,8 @@ public class PowermetricsProcessHandler extends NuAbstractProcessHandler {
1315
private String errorMsg;
1416
private NuProcess process;
1517
private final String[] command;
16-
private ByteArrayInputStream bais;
18+
private final GrowableBuffer stdOutBuffer = new GrowableBuffer();
19+
private final CompletableFuture<InputStream> output = new CompletableFuture<>();
1720

1821
public PowermetricsProcessHandler(String... command) {
1922
if (command == null || command.length == 0) {
@@ -63,8 +66,12 @@ public void stop() {
6366

6467
@Override
6568
public void onStdout(ByteBuffer buffer, boolean closed) {
66-
if (!closed) {
67-
bais = new ByteArrayInputStream(buffer.array());
69+
if (buffer.hasRemaining()) {
70+
stdOutBuffer.put(buffer);
71+
}
72+
73+
if (closed) {
74+
output.complete(new ByteArrayInputStream(stdOutBuffer.array()));
6875
}
6976
}
7077

@@ -78,8 +85,8 @@ public void onStderr(ByteBuffer buffer, boolean closed) {
7885
super.onStderr(buffer, closed);
7986
}
8087

81-
public InputStream getInputStream() {
82-
return bais;
88+
public Future<InputStream> getInputStream() {
89+
return output;
8390
}
8491

8592
public boolean isRunning() {

backend/src/main/java/net/laprun/sustainability/power/sensors/macos/powermetrics/ProcessMacOSPowermetricsSensor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import java.io.InputStream;
44

55
public class ProcessMacOSPowermetricsSensor extends MacOSPowermetricsSensor {
6-
private final ProcessWrapper processWrapper = new JavaProcessWrapper();
6+
private final ProcessWrapper processWrapper = new NuProcessWrapper();
77

88
public ProcessMacOSPowermetricsSensor() {
99
// extract metadata

server/src/main/java/net/laprun/sustainability/power/PowerMeasurer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ private RegisteredPID track(long pid) throws Exception {
4040
sensor.start(samplingPeriod.toMillis());
4141
periodicSensorCheck = Multi.createFrom().ticks()
4242
.every(samplingPeriod)
43+
.log()
4344
.map(sensor::update)
4445
.broadcast()
4546
.withCancellationAfterLastSubscriberDeparture()

0 commit comments

Comments
 (0)