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

feat: add warm-up support #15

Merged
merged 1 commit into from
Nov 7, 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 @@ -12,6 +12,7 @@

public class PowerMeasurer<M extends IncrementableMeasure> {
private static final OperatingSystemMXBean osBean;

static {
osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
// take two measures to avoid initial zero values
Expand All @@ -26,6 +27,7 @@ public class PowerMeasurer<M extends IncrementableMeasure> {
private final PowerSensor<M> sensor;
private OngoingPowerMeasure<M> measure;
private StoppedPowerMeasure<M> lastMeasure;
private StoppedPowerMeasure<M> baseline;

private final static PowerMeasurer<? extends SensorMeasure> instance = new PowerMeasurer<>(
PowerSensorProducer.determinePowerSensor());
Expand All @@ -52,20 +54,36 @@ public boolean isRunning() {
return measure != null;
}

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

if (duration > 0) {
executor.schedule(() -> stop(out), duration, TimeUnit.SECONDS);
void start(long durationInSeconds, long frequencyInMilliseconds, boolean skipBaseline, PowerSensor.Writer out)
throws Exception {
if (!isRunning()) {
if (!skipBaseline && baseline == null) {
out.println("Establishing baseline for 30s, please do not use your application until done.");
out.println("Power measurement will start as configured after this initial measure is done.");
doStart(30, 1000, out, () -> baselineDone(durationInSeconds, frequencyInMilliseconds, out));
} else {
doStart(durationInSeconds, frequencyInMilliseconds, out, () -> stop(out));
}

scheduled = executor.scheduleAtFixedRate(() -> update(out),
0, frequency,
TimeUnit.MILLISECONDS);
}
}

private void doStart(long duration, long frequency, PowerSensor.Writer out, Runnable doneAction) throws Exception {
measure = sensor.start(duration, frequency, out);

if (duration > 0) {
executor.schedule(doneAction, duration, TimeUnit.SECONDS);
}

scheduled = executor.scheduleAtFixedRate(() -> update(out),
0, frequency,
TimeUnit.MILLISECONDS);
}

private void update(PowerSensor.Writer out) {
sensor.update(measure, out);
measure.incrementSamples();
Expand All @@ -75,12 +93,28 @@ public void stop(PowerSensor.Writer out) {
if (isRunning()) {
sensor.stop();
scheduled.cancel(true);
outputConsumptionSinceStarted(out);
outputConsumptionSinceStarted(out, false);
lastMeasure = new StoppedPowerMeasure<>(measure);
measure = null;
}
}

private void baselineDone(long durationInSeconds, long frequencyInMilliseconds, PowerSensor.Writer out) {
if (isRunning()) {
sensor.stop();
scheduled.cancel(true);
outputConsumptionSinceStarted(out, true);
baseline = new StoppedPowerMeasure<>(measure);
out.println("Baseline established! You can now interact with your application normally.");
measure = null;
try {
doStart(durationInSeconds, frequencyInMilliseconds, out, () -> stop(out));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

public PowerMeasure<M> current() {
// use the ongoing power measure if it exists
if (measure == null) {
Expand All @@ -95,10 +129,20 @@ public PowerMeasure<M> current() {
}
}

private void outputConsumptionSinceStarted(PowerSensor.Writer out) {
private void outputConsumptionSinceStarted(PowerSensor.Writer out, boolean isBaseline) {
out = out == null ? System.out::println : out;
out.println("Consumed " + measure.total() + " mW over " + (measure.duration() / 1000)
final var durationInSeconds = measure.duration() / 1000;
final var title = isBaseline ? "Baseline power: " : "Measured power: ";
out.println(title + getReadablePower(measure) + " over " + durationInSeconds
+ " seconds (" + measure.numberOfSamples() + " samples)");
sensor.additionalInfo(measure, out);
if (!isBaseline) {
sensor.additionalInfo(measure, out);
out.println("Baseline power was " + getReadablePower(baseline));
}
}

private static String getReadablePower(PowerMeasure<?> measure) {
final var measuredMilliWatts = measure.total();
return measuredMilliWatts >= 1000 ? (measuredMilliWatts / 1000) + " W" : measuredMilliWatts + "mW";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void startShouldAccumulateOverSpecifiedDurationAndStop() throws Exception {
sensor = Mockito.spy(sensor);
final var measurer = new PowerMeasurer<>(sensor);

measurer.start(1, 100, null);
measurer.start(1, 100, true, null);
Thread.sleep(2000);
final var measure = measurer.current();
assertEquals(10, measure.numberOfSamples());
Expand Down