Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: better robustness of commands #12

Merged
merged 1 commit into from
Nov 2, 2023
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
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);
}
}