Skip to content

Commit

Permalink
fix: better robustness of commands
Browse files Browse the repository at this point in the history
  • Loading branch information
metacosm committed Nov 2, 2023
1 parent f7bc200 commit fe96c2d
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,18 @@ public StartCommand(PowerMeasurer<? extends SensorMeasure> sensor) {
@Override
public CommandResult doExecute(CommandInvocation commandInvocation) throws CommandException, InterruptedException {
try {
if (duration > 0) {
commandInvocation.println("Measuring power for " + duration + " seconds, every " + frequency + " milliseconds");
if (!sensor.isRunning()) {
if (duration > 0) {
commandInvocation
.println("Measuring power for " + duration + " seconds, every " + frequency + " milliseconds");
} else {
commandInvocation.println("Measuring power every " + frequency
+ " milliseconds. Execute 'power stop' to stop measurements and get the results.");
}
sensor.start(duration, frequency, commandInvocation::println);
} else {
commandInvocation.println("Measuring power every " + frequency
+ " milliseconds. Execute 'power stop' to stop measurements and get the results.");
commandInvocation.println("Power measurement is already ongoing. Execute 'power stop' to stop it now.");
}
sensor.start(duration, frequency, commandInvocation::println);
} catch (Exception e) {
commandInvocation.println("Couldn't start power measure: " + e.getMessage());
return CommandResult.FAILURE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ public StopCommand(PowerMeasurer<? extends SensorMeasure> sensor) {

@Override
public CommandResult doExecute(CommandInvocation commandInvocation) throws CommandException, InterruptedException {
sensor.stop(commandInvocation::println);
if (sensor.isRunning()) {
sensor.stop(commandInvocation::println);
} else {
commandInvocation.println("Power measurement hasn't started. Execute 'power start' to start it first.");
}

return CommandResult.SUCCESS;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@

import com.sun.management.OperatingSystemMXBean;

import io.quarkiverse.power.runtime.sensors.IncrementableMeasure;
import io.quarkiverse.power.runtime.sensors.OngoingPowerMeasure;
import io.quarkiverse.power.runtime.sensors.PowerSensor;
import io.quarkiverse.power.runtime.sensors.PowerSensorProducer;
import io.quarkiverse.power.runtime.sensors.*;

public class PowerMeasurer<M extends IncrementableMeasure> {
public static final OperatingSystemMXBean osBean;
Expand All @@ -24,6 +21,7 @@ public class PowerMeasurer<M extends IncrementableMeasure> {
private ScheduledFuture<?> scheduled;
private final PowerSensor<M> sensor;
private OngoingPowerMeasure<M> measure;
private StoppedPowerMeasure<M> lastMeasure;

private final static PowerMeasurer<? extends SensorMeasure> instance = new PowerMeasurer<>(
PowerSensorProducer.determinePowerSensor());
Expand All @@ -36,8 +34,12 @@ public PowerMeasurer(PowerSensor<M> sensor) {
this.sensor = sensor;
}

public boolean isRunning() {
return measure != null;
}

public void start(long duration, long frequency, PowerSensor.Writer out) throws Exception {
if (measure == null) {
if (!isRunning()) {
measure = sensor.start(duration, frequency, out);

if (duration > 0) {
Expand All @@ -55,23 +57,34 @@ private void update(PowerSensor.Writer out) {
measure.incrementSamples();
}

public PowerMeasure<M> stop(PowerSensor.Writer out) {
if (measure != null) {
public void stop(PowerSensor.Writer out) {
if (isRunning()) {
sensor.stop();
scheduled.cancel(true);
outputConsumptionSinceStarted(out);
lastMeasure = new StoppedPowerMeasure<>(measure);
measure = null;
}
outputConsumptionSinceStarted(out);
return measure;
}

public PowerMeasure<M> current() {
return measure;
// use the ongoing power measure if it exists
if (measure == null) {
// or use the last recorded measure if we have one
if (lastMeasure != null) {
return lastMeasure;
} else {
throw new IllegalStateException("No power measure found. Please start it first.");
}
} else {
return measure;
}
}

private void outputConsumptionSinceStarted(PowerSensor.Writer out) {
out = out == null ? System.out::println : out;
out.println("Consumed " + measure.total() + " mW over " + (measure.duration() / 1000)
+ " seconds (" + measure.numberOfSamples() + " samples)");
sensor.additionalInfo(out);
sensor.additionalInfo(measure, out);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.quarkiverse.power.runtime.sensors;

import io.quarkiverse.power.runtime.PowerMeasure;

public interface PowerSensor<T extends IncrementableMeasure> {

OngoingPowerMeasure<T> start(long duration, long frequency, Writer out) throws Exception;
Expand All @@ -9,7 +11,7 @@ default void stop() {

void update(OngoingPowerMeasure<T> ongoingMeasure, Writer out);

default void additionalInfo(Writer out) {
default void additionalInfo(PowerMeasure<T> measure, Writer out) {
}

interface Writer {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package io.quarkiverse.power.runtime.sensors;

import java.util.Optional;

import io.quarkiverse.power.runtime.PowerMeasure;
import io.quarkiverse.power.runtime.SensorMeasure;

public class StoppedPowerMeasure<M extends SensorMeasure> implements SensorMeasure, PowerMeasure<M> {
private final M measure;
private final long duration;
private final int samples;

public StoppedPowerMeasure(PowerMeasure<M> powerMeasure) {
this.measure = powerMeasure.sensorMeasure();
this.duration = powerMeasure.duration();
this.samples = powerMeasure.numberOfSamples();
}

@Override
public double cpu() {
return measure.cpu();
}

@Override
public Optional<Double> gpu() {
return measure.gpu();
}

@Override
public Optional<Double> byKey(String key) {
return measure.byKey(key);
}

@Override
public double total() {
return measure.total();
}

@Override
public int numberOfSamples() {
return samples;
}

@Override
public long duration() {
return duration;
}

@Override
public M sensorMeasure() {
return measure;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.io.InputStream;
import java.io.InputStreamReader;

import io.quarkiverse.power.runtime.PowerMeasure;
import io.quarkiverse.power.runtime.sensors.OngoingPowerMeasure;
import io.quarkiverse.power.runtime.sensors.PowerSensor;
import io.quarkiverse.power.runtime.sensors.macos.AppleSiliconMeasure;
Expand All @@ -14,7 +15,7 @@ public class MacOSPowermetricsSensor implements PowerSensor<AppleSiliconMeasure>
private Process powermetrics;
public static PowerSensor<AppleSiliconMeasure> instance = new MacOSPowermetricsSensor();
private final static String pid = " " + ProcessHandle.current().pid() + " ";
private double accumulatedCPUShareDiff;
private double accumulatedCPUShareDiff = 0.0;

private static class ProcessRecord {
final double cpu;
Expand Down Expand Up @@ -117,6 +118,7 @@ public OngoingPowerMeasure<AppleSiliconMeasure> start(long duration, long freque
powermetrics = Runtime.getRuntime()
.exec("sudo powermetrics --samplers cpu_power,tasks --show-process-samp-norm --show-process-gpu -i "
+ freq);
accumulatedCPUShareDiff = 0.0;
return new OngoingPowerMeasure<>(new AppleSiliconMeasure());
}

Expand All @@ -125,7 +127,8 @@ public void stop() {
powermetrics.destroy();
}

public void additionalInfo(Writer out) {
@Override
public void additionalInfo(PowerMeasure<AppleSiliconMeasure> measure, Writer out) {
out.println("Powermetrics vs JMX CPU share accumulated difference: " + accumulatedCPUShareDiff);
}
}

0 comments on commit fe96c2d

Please sign in to comment.