package org.radargun.stages;
import org.radargun.DistStageAck;
import org.radargun.config.Property;
import org.radargun.config.Stage;
import org.radargun.stages.test.Blackhole;
import org.radargun.state.ServiceListener;
/**
* @author Radim Vansa <rvansa@redhat.com>
*/
@Stage(doc = "Burns CPU time in several threads to simulate CPU intensive app.")
public class CpuBurnStage extends AbstractDistStage {
@Property(doc = "Number of threads burning CPU.")
public int numThreads;
@Property(doc = "If set to true, all threads are stopped and the num-threads attribute is ignored.")
public boolean stop = false;
@Override
public DistStageAck executeOnSlave() {
State state = (State) slaveState.remove(CpuBurnStage.class.getName());
if (stop) {
if (state != null) {
state.stop();
} else {
log.warn("There are no running threads!");
}
} else {
if (state != null) {
log.warn("There are already running threads!");
// stop the old threads even if stop = false, otherwise we would leak them
state.stop();
}
if (numThreads <= 0) {
return errorResponse("Cannot use num-threads <= 0!");
}
slaveState.put(CpuBurnStage.class.getName(), new State(numThreads));
}
return successfulResponse();
}
private class State implements ServiceListener{
final Thread[] threads;
volatile boolean terminate = false;
private State(int numThreads) {
threads = new Thread[numThreads];
for (int i = 0; i < numThreads; ++i) {
threads[i] = new Thread(() -> {
while (!terminate) {
Blackhole.consumeCpu();
}
}, "CpuBurner-" + i);
threads[i].start();
}
slaveState.addListener(this);
}
public void stop() {
terminate = true;
for (Thread t : threads) {
try {
t.join();
} catch (InterruptedException e) {
log.warn("Interrupted while waiting for thread to finish", e);
Thread.currentThread().interrupt();
}
}
slaveState.removeListener(this);
}
@Override
public void beforeServiceStop(boolean graceful) {
stop();
}
}
}