changed report API and chart generator
This commit is contained in:
parent
3a0af9e2ee
commit
b191320ecc
|
@ -1,5 +1,6 @@
|
||||||
package net.engio.pips.lab;
|
package net.engio.pips.lab;
|
||||||
|
|
||||||
|
import net.engio.pips.data.DataCollectorManager;
|
||||||
import net.engio.pips.data.IDataCollector;
|
import net.engio.pips.data.IDataCollector;
|
||||||
import net.engio.pips.lab.workload.Workload;
|
import net.engio.pips.lab.workload.Workload;
|
||||||
import net.engio.pips.reports.IReporter;
|
import net.engio.pips.reports.IReporter;
|
||||||
|
@ -7,10 +8,7 @@ import net.engio.pips.reports.IReporter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A benchmark is the container for all information of a formerly executed performance
|
* A benchmark is the container for all information of a formerly executed performance
|
||||||
|
@ -20,7 +18,7 @@ import java.util.Map;
|
||||||
* @author bennidi
|
* @author bennidi
|
||||||
* Date: 2/11/14
|
* Date: 2/11/14
|
||||||
*/
|
*/
|
||||||
public class Experiment {
|
public class Benchmark {
|
||||||
|
|
||||||
public static final class Properties{
|
public static final class Properties{
|
||||||
public static final String TimeoutInSeconds = "Timeout in seconds";
|
public static final String TimeoutInSeconds = "Timeout in seconds";
|
||||||
|
@ -29,11 +27,9 @@ public class Experiment {
|
||||||
public static final String LogStream = "Log stream";
|
public static final String LogStream = "Log stream";
|
||||||
public static final String Title = "Title";
|
public static final String Title = "Title";
|
||||||
public static final String ReportBaseDir = "Report base dir";
|
public static final String ReportBaseDir = "Report base dir";
|
||||||
public static final String Collectors = "collectors:";
|
|
||||||
public static final String ExecutionTimers = Collectors + "execution-timer:";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExecutionContext context = new ExecutionContext(this);
|
private ExecutionContext rootContext = new ExecutionContext(this);
|
||||||
|
|
||||||
private List<IReporter> reporters = new LinkedList<IReporter>();
|
private List<IReporter> reporters = new LinkedList<IReporter>();
|
||||||
|
|
||||||
|
@ -43,12 +39,18 @@ public class Experiment {
|
||||||
|
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
public Experiment(String title) {
|
private DataCollectorManager collectors = new DataCollectorManager();
|
||||||
|
|
||||||
|
public Benchmark(String title) {
|
||||||
if (title == null || title.isEmpty())
|
if (title == null || title.isEmpty())
|
||||||
throw new IllegalArgumentException("Please provide a title that is a valid identifier for a directory");
|
throw new IllegalArgumentException("Please provide a title that is a valid identifier for a directory");
|
||||||
this.title = title;
|
this.title = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <V> IDataCollector<V> addCollector(IDataCollector<V> collector){
|
||||||
|
return collectors.addCollector(collector);
|
||||||
|
}
|
||||||
|
|
||||||
public void setExecutions(Executions executions) {
|
public void setExecutions(Executions executions) {
|
||||||
this.executions = executions;
|
this.executions = executions;
|
||||||
}
|
}
|
||||||
|
@ -57,12 +59,65 @@ public class Experiment {
|
||||||
return executions;
|
return executions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<IDataCollector> getCollectors(){
|
public DataCollectorManager getCollectorManager(){
|
||||||
return executions.getMatching(Properties.Collectors);
|
return collectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<IDataCollector> getCollectors(String collectorId){
|
public List<IDataCollector> getCollectors(){
|
||||||
return executions.getMatching(Experiment.Properties.Collectors + collectorId);
|
return getCollectors("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IDataCollector> getCollectors(String collectorId){
|
||||||
|
return collectors.getCollectors(collectorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void verifyWorkloads(){
|
||||||
|
// TOdo: check start/duration dependencies
|
||||||
|
|
||||||
|
for(Workload workload : getWorkloads()){
|
||||||
|
if(workload.getITaskFactory() == null)
|
||||||
|
throw new LabException("Workload has no task factory:" + workload, LabException.ErrorCode.WLWithoutFactory);
|
||||||
|
if(workload.getStartCondition() == null)
|
||||||
|
throw new LabException("Workload has no start condition specified:" + workload, LabException.ErrorCode.WLWithoutStart);
|
||||||
|
if(workload.getDuration() == null)
|
||||||
|
throw new LabException("Workload has no duration specified:" + workload, LabException.ErrorCode.WLWithoutDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify dependency graph
|
||||||
|
for(Workload workload : getWorkloads()){
|
||||||
|
// since there is always a finite number of workloads
|
||||||
|
// traversing the links will either end in cycle or terminate with a workload that specifies an absolute start/duration
|
||||||
|
if(!willStart(workload))
|
||||||
|
throw new LabException("Cycle in workload start condition" + workload, LabException.ErrorCode.WLWithCycleInStart);
|
||||||
|
if(!willEnd(workload))
|
||||||
|
throw new LabException("Cycle in workload duration: " + workload, LabException.ErrorCode.WLWithCycleInDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean willStart(Workload workload){
|
||||||
|
if(workload.getStartCondition().isImmediately() || workload.getStartCondition().isTimebased())
|
||||||
|
return true;
|
||||||
|
Set<Workload> preceeding = new HashSet<Workload>();
|
||||||
|
while(workload.getStartCondition().getPreceedingWorkload() != null){
|
||||||
|
if(!preceeding.add(workload.getStartCondition().getPreceedingWorkload()))
|
||||||
|
return false; // workload was reached before -> cycle
|
||||||
|
else workload = workload.getStartCondition().getPreceedingWorkload();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean willEnd(Workload workload){
|
||||||
|
if(workload.getDuration().isRepetitive() || workload.getDuration().isTimeBased())
|
||||||
|
return true;
|
||||||
|
Set<Workload> preceeding = new HashSet<Workload>();
|
||||||
|
while(workload.getDuration().getDependingOn() != null){
|
||||||
|
if(!preceeding.add(workload.getDuration().getDependingOn()))
|
||||||
|
return false;
|
||||||
|
else workload = workload.getDuration().getDependingOn();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,27 +129,29 @@ public class Experiment {
|
||||||
* @param value - The value to associate with the key
|
* @param value - The value to associate with the key
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Experiment register(String key, Object value) {
|
public Benchmark setProperty(String key, Object value) {
|
||||||
context.bind(key, value);
|
rootContext.bind(key, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Experiment addWorkload(Workload... workload) {
|
public Benchmark addWorkload(Workload... workload) {
|
||||||
for (Workload wl : workload)
|
for (Workload wl : workload){
|
||||||
workloads.add(wl);
|
if(wl.hasTasksToRun())workloads.add(wl);
|
||||||
|
//else getLogStream() // TODO: log warning
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public Experiment addReport(IReporter reporter) {
|
public Benchmark addReporter(IReporter reporter) {
|
||||||
reporters.add(reporter);
|
reporters.add(reporter);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generateReports() throws Exception {
|
public void generateReports(IReporter ...reporters) throws Exception {
|
||||||
PrintWriter log = new PrintWriter(getLogStream(), true);
|
PrintWriter log = new PrintWriter(getLogStream(), true);
|
||||||
if (reporters.isEmpty()) {
|
if (reporters.length == 0) {
|
||||||
log.println("Skipping report generation because no reporters have been registered");
|
log.println("Skipping report generation because no reporters have been registered");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -117,31 +174,23 @@ public class Experiment {
|
||||||
return baseDir.getAbsolutePath() + File.separator;
|
return baseDir.getAbsolutePath() + File.separator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T get(String key) {
|
|
||||||
return context.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Workload> getWorkloads() {
|
public List<Workload> getWorkloads() {
|
||||||
return workloads;
|
return workloads;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDefined(String key) {
|
public boolean isDefined(String key) {
|
||||||
return context.containsKey(key);
|
return rootContext.containsKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T getProperty(String key) {
|
public <T> T getProperty(String key) {
|
||||||
return (T) context.get(key);
|
return (T) rootContext.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSampleInterval() {
|
public Benchmark setBasePath(String basePath) {
|
||||||
return getProperty(Properties.SampleInterval);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Experiment setBasePath(String basePath) {
|
|
||||||
return setProperty(Properties.BasePath, basePath);
|
return setProperty(Properties.BasePath, basePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Experiment setSampleInterval(int sampleInterval) {
|
public Benchmark setSampleInterval(int sampleInterval) {
|
||||||
return setProperty(Properties.SampleInterval, sampleInterval);
|
return setProperty(Properties.SampleInterval, sampleInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,17 +198,12 @@ public class Experiment {
|
||||||
return getProperty(Properties.TimeoutInSeconds);
|
return getProperty(Properties.TimeoutInSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Experiment setProperty(String key, Object value) {
|
|
||||||
context.bind(key, value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public OutputStream getLogStream() {
|
public OutputStream getLogStream() {
|
||||||
return isDefined(Properties.LogStream) ? (OutputStream) getProperty(Properties.LogStream) : System.out;
|
return isDefined(Properties.LogStream) ? (OutputStream) getProperty(Properties.LogStream) : System.out;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Experiment setLogStream(OutputStream out) {
|
public Benchmark setLogStream(OutputStream out) {
|
||||||
return setProperty(Properties.LogStream, out);
|
return setProperty(Properties.LogStream, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +212,7 @@ public class Experiment {
|
||||||
StringBuilder exp = new StringBuilder();
|
StringBuilder exp = new StringBuilder();
|
||||||
exp.append("Experiment ");
|
exp.append("Experiment ");
|
||||||
exp.append(title);
|
exp.append(title);
|
||||||
exp.append("with ");
|
exp.append(" with ");
|
||||||
exp.append(workloads.size() + " workloads");
|
exp.append(workloads.size() + " workloads");
|
||||||
exp.append("\n");
|
exp.append("\n");
|
||||||
|
|
||||||
|
@ -178,7 +222,7 @@ public class Experiment {
|
||||||
}
|
}
|
||||||
exp.append("\n");
|
exp.append("\n");
|
||||||
exp.append("and additional parameters:\n");
|
exp.append("and additional parameters:\n");
|
||||||
for(Map.Entry entry : context.getProperties().entrySet()){
|
for(Map.Entry entry : rootContext.getProperties().entrySet()){
|
||||||
exp.append("\t");
|
exp.append("\t");
|
||||||
exp.append(entry.getKey());
|
exp.append(entry.getKey());
|
||||||
exp.append(":");
|
exp.append(":");
|
||||||
|
@ -196,7 +240,7 @@ public class Experiment {
|
||||||
|
|
||||||
|
|
||||||
public ExecutionContext getClobalContext() {
|
public ExecutionContext getClobalContext() {
|
||||||
return context;
|
return rootContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,14 @@ import java.util.*;
|
||||||
*/
|
*/
|
||||||
public class ExecutionContext {
|
public class ExecutionContext {
|
||||||
|
|
||||||
private Experiment experiment;
|
private Benchmark benchmark;
|
||||||
private ExecutionContext parent;
|
private ExecutionContext parent;
|
||||||
private Map<String, Object> properties = new HashMap<String, Object>();
|
private Map<String, Object> properties = new HashMap<String, Object>();
|
||||||
private long started;
|
private long started;
|
||||||
private long finished;
|
private long finished;
|
||||||
|
|
||||||
public ExecutionContext(Experiment experiment) {
|
public ExecutionContext(Benchmark benchmark) {
|
||||||
this.experiment = experiment;
|
this.benchmark = benchmark;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void started(){
|
public void started(){
|
||||||
|
@ -43,15 +43,15 @@ public class ExecutionContext {
|
||||||
|
|
||||||
public ExecutionTimer createExecutionTimer(String timerId){
|
public ExecutionTimer createExecutionTimer(String timerId){
|
||||||
DataCollector<Long> timings = createLocalCollector(timerId);
|
DataCollector<Long> timings = createLocalCollector(timerId);
|
||||||
Sampler sampler = Sampler.<Long>timeBased((Integer)get(Experiment.Properties.SampleInterval));
|
Sampler sampler = Sampler.<Long>timeBased((Integer)get(Benchmark.Properties.SampleInterval));
|
||||||
sampler.pipeInto(timings);
|
sampler.connectTo(timings);
|
||||||
ExecutionTimer timer = new ExecutionTimer(sampler);
|
ExecutionTimer timer = new ExecutionTimer(sampler);
|
||||||
return timer;
|
return timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <V> DataCollector<V> createLocalCollector(String collectorId){
|
public <V> DataCollector<V> createLocalCollector(String collectorId){
|
||||||
DataCollector<V> collector = new DataCollector(collectorId);
|
DataCollector<V> collector = new DataCollector(collectorId);
|
||||||
bind(Experiment.Properties.ExecutionTimers + collectorId, collector);
|
bind(collectorId, collector);
|
||||||
return collector;
|
return collector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ public class ExecutionContext {
|
||||||
|
|
||||||
|
|
||||||
public ExecutionContext getChild(){
|
public ExecutionContext getChild(){
|
||||||
ExecutionContext child = new ExecutionContext(experiment);
|
ExecutionContext child = new ExecutionContext(benchmark);
|
||||||
child.parent = this;
|
child.parent = this;
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package net.engio.pips.lab;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 3/25/14
|
||||||
|
*/
|
||||||
|
public class LabException extends RuntimeException {
|
||||||
|
|
||||||
|
private ErrorCode code;
|
||||||
|
|
||||||
|
public LabException(String message, ErrorCode code) {
|
||||||
|
super(message);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LabException(String message, Throwable cause, ErrorCode code) {
|
||||||
|
super(message, cause);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrorCode getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum ErrorCode{
|
||||||
|
WLWithoutFactory,
|
||||||
|
WLWithCycleInDuration,
|
||||||
|
WLWithCycleInStart,
|
||||||
|
WLWithoutStart,
|
||||||
|
WLWithoutDuration
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,14 @@
|
||||||
package net.engio.pips.lab;
|
package net.engio.pips.lab;
|
||||||
|
|
||||||
import net.engio.pips.lab.workload.*;
|
import net.engio.pips.lab.workload.ExecutionEvent;
|
||||||
|
import net.engio.pips.lab.workload.ExecutionHandler;
|
||||||
|
import net.engio.pips.lab.workload.Workload;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.ThreadFactory;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,34 +17,51 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
*/
|
*/
|
||||||
public class Laboratory {
|
public class Laboratory {
|
||||||
|
|
||||||
public void run(Experiment... experiments) throws Exception {
|
public void run(Benchmark... benchmarks) throws Exception {
|
||||||
for(Experiment experiment : experiments){
|
for(Benchmark benchmark : benchmarks){
|
||||||
// TODO: verify workload configuration (at least one timebased/immediate wl)
|
benchmark.verifyWorkloads();
|
||||||
measure(experiment);
|
|
||||||
PrintWriter log = new PrintWriter(experiment.getLogStream(), true);
|
|
||||||
log.println("Generating reports....");
|
|
||||||
experiment.generateReports();
|
|
||||||
}
|
}
|
||||||
|
for(Benchmark benchmark : benchmarks){
|
||||||
|
measure(benchmark);
|
||||||
|
/*
|
||||||
|
PrintWriter log = new PrintWriter(benchmark.getLogStream(), true);
|
||||||
|
log.println("Generating reports....");
|
||||||
|
benchmark.generateReports(); */
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.sleep(3000); // wait for shutdown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void measure(final Experiment experiment) {
|
|
||||||
|
|
||||||
|
public void measure(final Benchmark benchmark) {
|
||||||
// each workload will run in its own thread
|
// each workload will run in its own thread
|
||||||
final ExecutorService executor = Executors.newFixedThreadPool(experiment.getWorkloads().size());
|
final ExecutorService executor = Executors.newFixedThreadPool(benchmark.getWorkloads().size(), new ThreadFactory() {
|
||||||
|
|
||||||
|
private ThreadGroup group = new ThreadGroup("scheduler");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable runnable) {
|
||||||
|
Thread thread = new Thread(group, runnable, "Workload scheduler");
|
||||||
|
thread.setPriority(Thread.MIN_PRIORITY);
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// keeping track of workloads and their corresponding executables
|
// keeping track of workloads and their corresponding executables
|
||||||
final Map<Workload, WorkloadManager> workloads = new HashMap<Workload, WorkloadManager>(experiment.getWorkloads().size());
|
final Map<Workload, WorkloadManager> workloads = new HashMap<Workload, WorkloadManager>(benchmark.getWorkloads().size());
|
||||||
//final Map<Workload, Future<Long>> scheduled = Collections.synchronizedMap(new HashMap<Workload, Future<Long>>(experiment.getWorkloads().size()));
|
//final Map<Workload, Future<Long>> scheduled = Collections.synchronizedMap(new HashMap<Workload, Future<Long>>(experiment.getWorkloads().size()));
|
||||||
final AtomicInteger finishedWorkloads = new AtomicInteger(0);
|
final AtomicInteger finishedWorkloads = new AtomicInteger(0);
|
||||||
|
|
||||||
final PrintWriter log = new PrintWriter(experiment.getLogStream(), true);
|
final PrintWriter log = new PrintWriter(benchmark.getLogStream(), true);
|
||||||
final Timer timer = new Timer(true);
|
final Timer timer = new Timer(true);
|
||||||
|
|
||||||
Date start = new Date(System.currentTimeMillis());
|
Date start = new Date(System.currentTimeMillis());
|
||||||
log.println("Starting experiment at " + start );
|
log.println("Starting experiment at " + start );
|
||||||
// prepare workloads
|
// prepare workloads
|
||||||
for(final Workload workload : experiment.getWorkloads()){
|
for(final Workload workload : benchmark.getWorkloads()){
|
||||||
workloads.put(workload, new WorkloadManager(workload, experiment));
|
workloads.put(workload, new WorkloadManager(workload, benchmark));
|
||||||
|
|
||||||
// keep track of finished workloads
|
// keep track of finished workloads
|
||||||
workload.handle(ExecutionEvent.WorkloadCompletion, new ExecutionHandler() {
|
workload.handle(ExecutionEvent.WorkloadCompletion, new ExecutionHandler() {
|
||||||
|
@ -93,7 +111,7 @@ public class Laboratory {
|
||||||
}
|
}
|
||||||
|
|
||||||
// schedule workloads
|
// schedule workloads
|
||||||
for(final Workload workload : experiment.getWorkloads()){
|
for(final Workload workload : benchmark.getWorkloads()){
|
||||||
// either now
|
// either now
|
||||||
if(workload.getStartCondition().isImmediately()){
|
if(workload.getStartCondition().isImmediately()){
|
||||||
workloads.get(workload).start(executor);
|
workloads.get(workload).start(executor);
|
||||||
|
@ -111,7 +129,7 @@ public class Laboratory {
|
||||||
|
|
||||||
// wait until all tasks have been executed
|
// wait until all tasks have been executed
|
||||||
try {
|
try {
|
||||||
while(finishedWorkloads.get() < experiment.getWorkloads().size())
|
while(finishedWorkloads.get() < benchmark.getWorkloads().size())
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -122,130 +140,12 @@ public class Laboratory {
|
||||||
// merge contexts
|
// merge contexts
|
||||||
Executions executions = new Executions();
|
Executions executions = new Executions();
|
||||||
for(WorkloadManager workMan : workloads.values())
|
for(WorkloadManager workMan : workloads.values())
|
||||||
executions.addAll(workMan.contexts);
|
executions.addAll(workMan.getContexts());
|
||||||
experiment.setExecutions(executions);
|
benchmark.setExecutions(executions);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static class WorkloadManager{
|
|
||||||
|
|
||||||
private Workload workload;
|
|
||||||
private Callable<Long> scheduler;
|
|
||||||
private ExecutorService workloadExecutor;
|
|
||||||
private List<Future> scheduledTasks = new LinkedList<Future>();
|
|
||||||
private Future scheduledWorkload;
|
|
||||||
private List<ExecutionContext> contexts = new LinkedList<ExecutionContext>();
|
|
||||||
private volatile boolean stopped = false;
|
|
||||||
|
|
||||||
private WorkloadManager(Workload workload, Experiment experiment) {
|
|
||||||
this.workload = workload;
|
|
||||||
createScheduler(experiment, experiment.getClobalContext().getChild());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stop(){
|
|
||||||
stopped = true;
|
|
||||||
for(Future task : scheduledTasks)
|
|
||||||
task.cancel(true); // this doesn't seem to have any effect
|
|
||||||
System.out.println("Canceling workload" + workload);
|
|
||||||
scheduledWorkload.cancel(true);
|
|
||||||
workloadExecutor.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Future start(ExecutorService executor){
|
|
||||||
return scheduledWorkload = executor.submit(scheduler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a single executable unit which will run the tasks from the given workload
|
|
||||||
// in its own thread pool
|
|
||||||
private Callable<Long> createScheduler(final Experiment experiment, final ExecutionContext workloadContext){
|
|
||||||
workloadExecutor = Executors.newFixedThreadPool(workload.getParallelUnits());
|
|
||||||
scheduler = new Callable<Long>() {
|
|
||||||
@Override
|
|
||||||
public Long call() {
|
|
||||||
final AtomicInteger scheduled = new AtomicInteger(0);// number of scheduled tasks
|
|
||||||
final AtomicInteger finished = new AtomicInteger(0); // number of finished tasks
|
|
||||||
//final ResultCollector collector = experiment.getResults();
|
|
||||||
final ITaskFactory tasks = workload.getITaskFactory();
|
|
||||||
final PrintWriter log = new PrintWriter(experiment.getLogStream(), true);
|
|
||||||
|
|
||||||
log.println("Starting workload " + workload.getName());
|
|
||||||
// call initialization handlers before scheduling the actual tasks
|
|
||||||
workload.started();
|
|
||||||
workload.getHandler(ExecutionEvent.WorkloadInitialization).handle(workloadContext);
|
|
||||||
// create the tasks and schedule for execution
|
|
||||||
for (int i = 0; i < workload.getParallelUnits() ; i++) {
|
|
||||||
log.println("Scheduling unit " + scheduled.incrementAndGet());
|
|
||||||
final int taskNumber = i+1;
|
|
||||||
final ExecutionContext taskContext = workloadContext.getChild();
|
|
||||||
contexts.add(taskContext);
|
|
||||||
// simply submit a runnable as return values are not important
|
|
||||||
scheduledTasks.add(workloadExecutor.submit(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
ITask task = tasks.create(taskContext);
|
|
||||||
log.println("Executing task " + taskNumber);
|
|
||||||
if (workload.getDuration().isRepetitive()) {
|
|
||||||
for (int i = 0; i < workload.getDuration().getRepetitions(); i++)
|
|
||||||
task.run(taskContext);
|
|
||||||
} else {
|
|
||||||
while (!stopped) {
|
|
||||||
task.run(taskContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.println("Task" + taskNumber + " threw an exception will orderly execution: " + e.toString());
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} finally {
|
|
||||||
finished.incrementAndGet();
|
|
||||||
log.println("Finished task: " + taskNumber);
|
|
||||||
log.println("Tasks left:" + (scheduled.get() - finished.get()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait until all tasks have been executed
|
|
||||||
try {
|
|
||||||
while(scheduled.get() > finished.get())
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
if(workload.getDuration().isDependent() && !workload.getDuration().getDependingOn().isFinished()){
|
|
||||||
log.println(workload + " interrupted although dependent workload not finished");
|
|
||||||
e.printStackTrace(); // something was wrong here
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!workload.getDuration().isTimeBased()
|
|
||||||
&& !workload.getDuration().isDependent()){
|
|
||||||
log.println(workload + " interrupted although no time based duration specified");
|
|
||||||
e.printStackTrace(); // something was wrong here
|
|
||||||
}
|
|
||||||
if(workload.getDuration().isTimeBased()
|
|
||||||
// interrupted before duration ends
|
|
||||||
&& System.currentTimeMillis() < workload.getDuration().inMillisecs() + workload.getStarted()){
|
|
||||||
log.println(workload + " interrupted before timer finished");
|
|
||||||
e.printStackTrace(); // something was wrong here
|
|
||||||
}
|
|
||||||
|
|
||||||
}finally {
|
|
||||||
// signal end
|
|
||||||
workload.finished();
|
|
||||||
log.println("Finished workload: " + workload);
|
|
||||||
workload.getHandler(ExecutionEvent.WorkloadCompletion).handle(workloadContext);
|
|
||||||
}
|
|
||||||
return 1L;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
return scheduler;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
package net.engio.pips.lab;
|
||||||
|
|
||||||
|
import net.engio.pips.lab.workload.ExecutionEvent;
|
||||||
|
import net.engio.pips.lab.workload.ITask;
|
||||||
|
import net.engio.pips.lab.workload.ITaskFactory;
|
||||||
|
import net.engio.pips.lab.workload.Workload;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Todo: Add javadoc
|
||||||
|
*
|
||||||
|
* @author bennidi
|
||||||
|
* Date: 6/19/14
|
||||||
|
*/
|
||||||
|
class WorkloadManager {
|
||||||
|
|
||||||
|
private Workload workload;
|
||||||
|
private Callable<Long> scheduler;
|
||||||
|
private ExecutorService workloadExecutor;
|
||||||
|
private List<Future> scheduledTasks = new LinkedList<Future>();
|
||||||
|
private Future scheduledWorkload;
|
||||||
|
private List<ExecutionContext> contexts = new LinkedList<ExecutionContext>();
|
||||||
|
private volatile boolean stopped = false;
|
||||||
|
|
||||||
|
WorkloadManager(Workload workload, Benchmark benchmark) {
|
||||||
|
this.workload = workload;
|
||||||
|
createScheduler(benchmark, benchmark.getClobalContext().getChild());
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop() {
|
||||||
|
stopped = true;
|
||||||
|
for (Future task : scheduledTasks)
|
||||||
|
task.cancel(true); // this doesn't seem to have any effect
|
||||||
|
System.out.println("Canceling workload " + workload.getName());
|
||||||
|
scheduledWorkload.cancel(true);
|
||||||
|
workloadExecutor.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future start(ExecutorService executor) {
|
||||||
|
return scheduledWorkload = executor.submit(scheduler);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ExecutionContext> getContexts() {
|
||||||
|
return contexts;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a single executable unit which will run the tasks from the given workload
|
||||||
|
// in its own thread pool
|
||||||
|
private Callable<Long> createScheduler(final Benchmark benchmark, final ExecutionContext workloadContext) {
|
||||||
|
workloadExecutor = Executors.newFixedThreadPool(workload.getParallelUnits(), new ThreadFactory() {
|
||||||
|
|
||||||
|
private ThreadGroup group = new ThreadGroup(workload.getName());
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable runnable) {
|
||||||
|
Thread thread = new Thread(group, runnable, workload.getName());
|
||||||
|
thread.setPriority(Thread.NORM_PRIORITY);
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
scheduler = new Callable<Long>() {
|
||||||
|
@Override
|
||||||
|
public Long call() {
|
||||||
|
final AtomicInteger scheduled = new AtomicInteger(0);// number of scheduled tasks
|
||||||
|
final AtomicInteger finished = new AtomicInteger(0); // number of finished tasks
|
||||||
|
//final ResultCollector collector = experiment.getResults();
|
||||||
|
final ITaskFactory tasks = workload.getITaskFactory();
|
||||||
|
final PrintWriter log = new PrintWriter(benchmark.getLogStream(), true);
|
||||||
|
|
||||||
|
log.println("Starting workload " + workload);
|
||||||
|
// call initialization handlers before scheduling the actual tasks
|
||||||
|
workload.started();
|
||||||
|
workload.getHandler(ExecutionEvent.WorkloadInitialization).handle(workloadContext);
|
||||||
|
// create the tasks and schedule for execution
|
||||||
|
for (int i = 0; i < workload.getParallelUnits(); i++) {
|
||||||
|
log.println("Scheduling task " + workload.getName() + "[" + scheduled.incrementAndGet() + "]");
|
||||||
|
final int taskNumber = i + 1;
|
||||||
|
final ExecutionContext taskContext = workloadContext.getChild();
|
||||||
|
contexts.add(taskContext);
|
||||||
|
// simply submit a runnable as return values are not important
|
||||||
|
// the runnable creates a new task and keeps executing it according to specified duration
|
||||||
|
scheduledTasks.add(workloadExecutor.submit(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
ITask task = tasks.create(taskContext);
|
||||||
|
log.println("Executing task " + workload.getName() + "[" + taskNumber + "]");
|
||||||
|
int round = 0;
|
||||||
|
// execute number of times specified
|
||||||
|
if (workload.getDuration().isRepetitive()) {
|
||||||
|
for (int i = 0; i < workload.getDuration().getRepetitions(); i++) {
|
||||||
|
execute(task, workload, taskContext, log, taskNumber, ++round);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { // or as long as depending task has not yet finished
|
||||||
|
while (!stopped) {
|
||||||
|
execute(task, workload, taskContext, log, taskNumber, ++round);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(InterruptedException e){
|
||||||
|
// this happens when the workload is shutdown
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.println("Task" + workload.getName() + "[" + taskNumber + "]" + " threw an exception while orderly execution: " + e.toString());
|
||||||
|
e.printStackTrace();
|
||||||
|
//throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
finished.incrementAndGet();
|
||||||
|
log.println("Finished task: " + workload.getName() + "[" + taskNumber + "]");
|
||||||
|
log.println("Tasks left in " + workload.getName() + ": " + (scheduled.get() - finished.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait until all tasks have been executed
|
||||||
|
try {
|
||||||
|
while (scheduled.get() > finished.get())
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
if (workload.getDuration().isDependent() && !workload.getDuration().getDependingOn().isFinished()) {
|
||||||
|
log.println(workload + " interrupted although dependent workload not finished");
|
||||||
|
e.printStackTrace(); // something was wrong here
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!workload.getDuration().isTimeBased()
|
||||||
|
&& !workload.getDuration().isDependent()) {
|
||||||
|
log.println(workload + " interrupted although no time based duration specified");
|
||||||
|
e.printStackTrace(); // something was wrong here
|
||||||
|
}
|
||||||
|
if (workload.getDuration().isTimeBased()
|
||||||
|
// interrupted before duration ends
|
||||||
|
&& System.currentTimeMillis() < workload.getDuration().inMillisecs() + workload.getStarted()) {
|
||||||
|
log.println(workload + " interrupted before timer finished");
|
||||||
|
e.printStackTrace(); // something was wrong here
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
// signal end
|
||||||
|
workload.finished();
|
||||||
|
log.println("Finished workload: " + workload);
|
||||||
|
workload.getHandler(ExecutionEvent.WorkloadCompletion).handle(workloadContext);
|
||||||
|
}
|
||||||
|
return 1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void execute(ITask task, Workload workload, ExecutionContext taskContext, PrintWriter log, int taskNumber, int round) throws InterruptedException {
|
||||||
|
try {
|
||||||
|
log.println(workload.getName() + "[" + taskNumber + "]->" + round);
|
||||||
|
task.run(taskContext);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.println("Task" + workload.getName() + "[" + taskNumber + "]" + " threw an exception while orderly execution: " + e.toString());
|
||||||
|
e.printStackTrace();
|
||||||
|
//throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
if (workload.hasDelay())
|
||||||
|
Thread.sleep(workload.getDelay());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package net.engio.pips.lab;
|
package net.engio.pips.lab.common;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
|
@ -1,4 +1,4 @@
|
||||||
package net.engio.pips.lab;
|
package net.engio.pips.lab.common;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
|
@ -9,8 +9,8 @@ import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A single workload defines a set of {@link ITask} to be executed as part of an {@link net.engio.pips.lab.Experiment}.
|
* A single workload defines a set of {@link ITask} to be executed as part of an {@link net.engio.pips.lab.Benchmark}.
|
||||||
* Tasks are potentially run in parallel depending on the configuration of {@code setParallelTasks}.
|
* Multiple tasks are run in parallel (see {@code setParallelTasks}).
|
||||||
* Tasks are created using the corresponding {@link net.engio.pips.lab.workload.ITaskFactory}.
|
* Tasks are created using the corresponding {@link net.engio.pips.lab.workload.ITaskFactory}.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
@ -25,7 +25,7 @@ public class Workload {
|
||||||
|
|
||||||
private Duration duration;
|
private Duration duration;
|
||||||
|
|
||||||
private StartCondition starting = new StartCondition();
|
private StartCondition starting;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@ -33,6 +33,8 @@ public class Workload {
|
||||||
|
|
||||||
private volatile long finished;
|
private volatile long finished;
|
||||||
|
|
||||||
|
private long delay = -1;
|
||||||
|
|
||||||
private Map<ExecutionEvent, ExecutionHandlerWrapper> handlers = new HashMap<ExecutionEvent, ExecutionHandlerWrapper>();
|
private Map<ExecutionEvent, ExecutionHandlerWrapper> handlers = new HashMap<ExecutionEvent, ExecutionHandlerWrapper>();
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,6 +54,15 @@ public class Workload {
|
||||||
return finished != -1;
|
return finished != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Workload setDelay(long ms){
|
||||||
|
delay = ms;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasDelay(){
|
||||||
|
return delay > 0;
|
||||||
|
}
|
||||||
|
|
||||||
public long getExecutionTime(){
|
public long getExecutionTime(){
|
||||||
return isFinished() ? finished - started : -1;
|
return isFinished() ? finished - started : -1;
|
||||||
}
|
}
|
||||||
|
@ -60,8 +71,19 @@ public class Workload {
|
||||||
return parallelUnits;
|
return parallelUnits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasTasksToRun(){
|
||||||
|
return parallelUnits > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define how many task should run in parallel. Tasks are created using the
|
||||||
|
* specified {@link ITaskFactory}
|
||||||
|
*
|
||||||
|
* @param parallelUnits
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Workload setParallelTasks(int parallelUnits) {
|
public Workload setParallelTasks(int parallelUnits) {
|
||||||
if(parallelUnits < 1 )throw new IllegalArgumentException("At least one task must run");
|
//if(parallelUnits < 1 )throw new IllegalArgumentException("At least one task must run");
|
||||||
this.parallelUnits = parallelUnits;
|
this.parallelUnits = parallelUnits;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -74,12 +96,25 @@ public class Workload {
|
||||||
return ITaskFactory;
|
return ITaskFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the task factory that will be used to create the single tasks of this workload.
|
||||||
|
*
|
||||||
|
* @param ITaskFactory The task factory to be used for task creation
|
||||||
|
* @return This workload
|
||||||
|
*/
|
||||||
public Workload setITaskFactory(ITaskFactory ITaskFactory) {
|
public Workload setITaskFactory(ITaskFactory ITaskFactory) {
|
||||||
this.ITaskFactory = ITaskFactory;
|
this.ITaskFactory = ITaskFactory;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an event handler to this workload. Depending on the type of event
|
||||||
|
* the handler will be called automatically by the {@link net.engio.pips.lab.Laboratory}
|
||||||
|
*
|
||||||
|
* @param event The type of event
|
||||||
|
* @param handler The handler to be invoked when the event occurs
|
||||||
|
* @return This workload
|
||||||
|
*/
|
||||||
public Workload handle(ExecutionEvent event, ExecutionHandler handler){
|
public Workload handle(ExecutionEvent event, ExecutionHandler handler){
|
||||||
if(handlers.containsKey(event)){
|
if(handlers.containsKey(event)){
|
||||||
handlers.get(event).delegate.add(handler);
|
handlers.get(event).delegate.add(handler);
|
||||||
|
@ -134,6 +169,11 @@ public class Workload {
|
||||||
return started;
|
return started;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getDelay() {
|
||||||
|
return delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
// intermediate class for clean API
|
||||||
public class StartSpecification{
|
public class StartSpecification{
|
||||||
|
|
||||||
public Workload after(int timeout, TimeUnit unit){
|
public Workload after(int timeout, TimeUnit unit){
|
||||||
|
@ -153,6 +193,7 @@ public class Workload {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// intermediate class for clean API
|
||||||
public class DurationSpecification{
|
public class DurationSpecification{
|
||||||
|
|
||||||
public Workload lasts(int timeout, TimeUnit unit){
|
public Workload lasts(int timeout, TimeUnit unit){
|
||||||
|
@ -172,6 +213,7 @@ public class Workload {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrap multiple execution handlers
|
||||||
public static class ExecutionHandlerWrapper implements ExecutionHandler{
|
public static class ExecutionHandlerWrapper implements ExecutionHandler{
|
||||||
|
|
||||||
private List<ExecutionHandler> delegate = new LinkedList<ExecutionHandler>();
|
private List<ExecutionHandler> delegate = new LinkedList<ExecutionHandler>();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package net.engio.pips.reports;
|
package net.engio.pips.reports;
|
||||||
|
|
||||||
import net.engio.pips.data.IDataCollector;
|
import net.engio.pips.data.IDataCollector;
|
||||||
import net.engio.pips.lab.Experiment;
|
import net.engio.pips.lab.Benchmark;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
@ -12,20 +12,20 @@ import java.io.PrintWriter;
|
||||||
*/
|
*/
|
||||||
public class CSVFileExporter implements IReporter {
|
public class CSVFileExporter implements IReporter {
|
||||||
|
|
||||||
public void generate(Experiment experiment) throws Exception {
|
public void generate(Benchmark benchmark) throws Exception {
|
||||||
String reportDirectory = experiment.getReportBaseDir();
|
String reportDirectory = benchmark.getReportBaseDir();
|
||||||
File report = new File(reportDirectory + "report.txt");
|
File report = new File(reportDirectory + "report.txt");
|
||||||
PrintWriter writer = new PrintWriter(report);
|
PrintWriter writer = new PrintWriter(report);
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// write report header
|
// write report header
|
||||||
writer.println("###### EXPERIMENT ##########");
|
writer.println("###### EXPERIMENT ##########");
|
||||||
writer.println(experiment);
|
writer.println(benchmark);
|
||||||
|
|
||||||
// write data of collectors
|
// write data of collectors
|
||||||
writer.println();
|
writer.println();
|
||||||
writer.println("##### COLLECTORS ########");
|
writer.println("##### COLLECTORS ########");
|
||||||
for (IDataCollector collector: experiment.getCollectors()) {
|
for (IDataCollector collector: benchmark.getCollectors()) {
|
||||||
writer.println(collector);
|
writer.println(collector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
package net.engio.pips.reports;
|
package net.engio.pips.reports;
|
||||||
|
|
||||||
import net.engio.pips.lab.Experiment;
|
import net.engio.pips.lab.Benchmark;
|
||||||
import org.jfree.chart.ChartFactory;
|
import org.jfree.chart.ChartFactory;
|
||||||
import org.jfree.chart.ChartUtilities;
|
import org.jfree.chart.ChartUtilities;
|
||||||
import org.jfree.chart.JFreeChart;
|
import org.jfree.chart.JFreeChart;
|
||||||
|
import org.jfree.chart.axis.AxisLocation;
|
||||||
import org.jfree.chart.axis.NumberAxis;
|
import org.jfree.chart.axis.NumberAxis;
|
||||||
import org.jfree.chart.plot.XYPlot;
|
import org.jfree.chart.plot.XYPlot;
|
||||||
|
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
||||||
import org.jfree.data.time.TimeSeriesCollection;
|
import org.jfree.data.time.TimeSeriesCollection;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -50,29 +50,16 @@ public class ChartGenerator implements IReporter {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public ChartGenerator draw(SeriesGroup seriesGroup) {
|
||||||
* Configure a new group that will be treated as a single dataset in the chart.
|
|
||||||
* Each dataset has its own range axis.
|
|
||||||
* @param collectorId : The id used to retrieve associated data collectors from the result collector
|
|
||||||
* @param groupLabel : The label used for the range axis
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public SeriesGroup addGroup(String groupLabel, String collectorId){
|
|
||||||
SeriesGroup g = new SeriesGroup(groupLabel, collectorId);
|
|
||||||
groups.add(g);
|
|
||||||
return g;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChartGenerator add(SeriesGroup seriesGroup) {
|
|
||||||
groups.add(seriesGroup);
|
groups.add(seriesGroup);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generate(Experiment experiment){
|
public void generate(Benchmark benchmark){
|
||||||
Map<String, Integer> groupAxis = new HashMap<String, Integer>();
|
Map<String, Integer> groupAxis = new HashMap<String, Integer>();
|
||||||
// process default group
|
// process default group
|
||||||
SeriesGroup defaultGroup = this.groups.get(0);
|
SeriesGroup defaultGroup = this.groups.get(0);
|
||||||
TimeSeriesCollection collection = defaultGroup.createDataSet(experiment);
|
TimeSeriesCollection collection = defaultGroup.createDataSet(benchmark);
|
||||||
int maxNumberOfDatapoints = defaultGroup.getSize();
|
int maxNumberOfDatapoints = defaultGroup.getSize();
|
||||||
groupAxis.put(defaultGroup.getLabel(), 0);
|
groupAxis.put(defaultGroup.getLabel(), 0);
|
||||||
|
|
||||||
|
@ -94,20 +81,25 @@ public class ChartGenerator implements IReporter {
|
||||||
plot.setDomainGridlinesVisible(true);
|
plot.setDomainGridlinesVisible(true);
|
||||||
plot.setDomainGridlinePaint(Color.BLACK);
|
plot.setDomainGridlinePaint(Color.BLACK);
|
||||||
plot.setBackgroundPaint(Color.DARK_GRAY);
|
plot.setBackgroundPaint(Color.DARK_GRAY);
|
||||||
|
plot.setRenderer(0, getRandomRenderer());
|
||||||
// add other groups
|
// add other groups
|
||||||
List<SeriesGroup> groups = this.groups.subList(1, this.groups.size());
|
List<SeriesGroup> groups = this.groups.subList(1, this.groups.size());
|
||||||
int axisIndex = 1,
|
int axisIndex = 1,
|
||||||
dataSetIndex = 1;
|
dataSetIndex = 1;
|
||||||
for(SeriesGroup group : groups){
|
for(SeriesGroup group : groups){
|
||||||
plot.setDataset(dataSetIndex, group.createDataSet(experiment));
|
plot.setDataset(dataSetIndex, group.createDataSet(benchmark));
|
||||||
|
plot.setRenderer(dataSetIndex, getRandomRenderer());
|
||||||
|
|
||||||
// if the group does not share a range axis with an already mapped group
|
// if the group does not share a range axis with an already mapped group
|
||||||
if(!groupAxis.containsKey(group.getLabel())){
|
if(!groupAxis.containsKey(group.getLabel())){
|
||||||
final NumberAxis axis2 = new NumberAxis(group.getLabel());
|
final NumberAxis axis2 = new NumberAxis(group.getLabel());
|
||||||
// prevent the axis to be scaled from zero if the dataset begins with higher values
|
// prevent the axis to be scaled from zero if the dataset begins with higher values
|
||||||
axis2.setAutoRangeIncludesZero(false);
|
axis2.setAutoRangeIncludesZero(true);
|
||||||
plot.setRangeAxis(axisIndex, axis2);
|
plot.setRangeAxis(axisIndex, axis2);
|
||||||
plot.mapDatasetToRangeAxis(dataSetIndex, axisIndex);
|
plot.mapDatasetToRangeAxis(dataSetIndex, axisIndex);
|
||||||
|
plot.setRangeAxisLocation(axisIndex, group.getOrientation() == SeriesGroup.Orientation.Left
|
||||||
|
? AxisLocation.BOTTOM_OR_LEFT
|
||||||
|
: AxisLocation.BOTTOM_OR_RIGHT);
|
||||||
groupAxis.put(group.getLabel(), axisIndex); // remember this axis for subsequent groups
|
groupAxis.put(group.getLabel(), axisIndex); // remember this axis for subsequent groups
|
||||||
axisIndex++;
|
axisIndex++;
|
||||||
}
|
}
|
||||||
|
@ -124,12 +116,25 @@ public class ChartGenerator implements IReporter {
|
||||||
int width = maxNumberOfDatapoints * pixelPerDatapoint;
|
int width = maxNumberOfDatapoints * pixelPerDatapoint;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String path = experiment.getReportBaseDir() + filename;
|
String path = benchmark.getReportBaseDir() + filename;
|
||||||
ChartUtilities.saveChartAsJPEG(new File(path), chart, width <= 1024 ? 1024 : width, 1024);
|
ChartUtilities.saveChartAsJPEG(new File(path), chart, width <= 1024 ? 1024 : width, 1024);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.err.println("Problem occurred creating chart.");
|
System.err.println("Problem occurred creating chart.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Random rand = new Random();
|
||||||
|
private Color getRandomColor(){
|
||||||
|
return new Color(Math.abs(rand.nextInt()) % 256,// r
|
||||||
|
Math.abs(rand.nextInt()) % 256, // g
|
||||||
|
Math.abs(rand.nextInt()) % 256); //b
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private XYLineAndShapeRenderer getRandomRenderer(){
|
||||||
|
XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
|
||||||
|
renderer.setSeriesPaint(0, getRandomColor());
|
||||||
|
return renderer;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package net.engio.pips.reports;
|
package net.engio.pips.reports;
|
||||||
|
|
||||||
import net.engio.pips.lab.Experiment;
|
import net.engio.pips.lab.Benchmark;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take the benchmark and create some output. This may be everything from logging
|
* Take the benchmark and create some output. This may be everything from logging
|
||||||
|
@ -11,5 +11,5 @@ import net.engio.pips.lab.Experiment;
|
||||||
*/
|
*/
|
||||||
public interface IReporter {
|
public interface IReporter {
|
||||||
|
|
||||||
void generate(Experiment experiment) throws Exception;
|
void generate(Benchmark benchmark) throws Exception;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
package net.engio.pips.reports;
|
package net.engio.pips.reports;
|
||||||
|
|
||||||
import net.engio.pips.data.DataCollector;
|
|
||||||
import net.engio.pips.data.IDataCollector;
|
import net.engio.pips.data.IDataCollector;
|
||||||
import net.engio.pips.data.IDataProcessor;
|
|
||||||
import net.engio.pips.data.aggregator.Average;
|
|
||||||
import net.engio.pips.data.utils.ItemCounter;
|
|
||||||
import net.engio.pips.data.utils.TimeBasedAggregator;
|
import net.engio.pips.data.utils.TimeBasedAggregator;
|
||||||
import net.engio.pips.lab.Experiment;
|
import net.engio.pips.lab.Benchmark;
|
||||||
import org.jfree.data.time.TimeSeries;
|
import org.jfree.data.time.TimeSeries;
|
||||||
import org.jfree.data.time.TimeSeriesCollection;
|
import org.jfree.data.time.TimeSeriesCollection;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A series group is used to configure a set of data collectors for being included in a time series
|
* A series group is used to configure a set of data collectors for being included in a time series
|
||||||
|
@ -25,30 +20,44 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
public class SeriesGroup {
|
public class SeriesGroup {
|
||||||
|
|
||||||
private String collectorId;
|
public static enum Orientation{
|
||||||
|
Left, Right
|
||||||
|
}
|
||||||
|
|
||||||
private String label;
|
private String label;
|
||||||
|
|
||||||
private Map<String, IDataProcessor> aggregators = new HashMap<String, IDataProcessor>();
|
|
||||||
|
|
||||||
private Collection<IDataCollector> collectors = new ArrayList<IDataCollector>();
|
private Collection<IDataCollector> collectors = new ArrayList<IDataCollector>();
|
||||||
|
|
||||||
private int size;
|
private int size;
|
||||||
|
|
||||||
private String yAxis = "";
|
private String yAxis = "";
|
||||||
|
|
||||||
private int collectorSampleSize = 1;
|
private Orientation orientation = Orientation.Left;
|
||||||
|
|
||||||
public SeriesGroup(String collectorId, String label) {
|
public SeriesGroup(String label) {
|
||||||
this.collectorId = collectorId;
|
|
||||||
this.label = label;
|
this.label = label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SeriesGroup setYAxisOrientation(Orientation orientation){
|
||||||
|
this.orientation = orientation;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Orientation getOrientation() {
|
||||||
|
return orientation;
|
||||||
|
}
|
||||||
|
|
||||||
public SeriesGroup addCollector(IDataCollector collector){
|
public SeriesGroup addCollector(IDataCollector collector){
|
||||||
collectors.add(collector);
|
collectors.add(collector);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SeriesGroup addCollectors(List<IDataCollector> collectors){
|
||||||
|
for(IDataCollector collector : collectors)
|
||||||
|
addCollector(collector);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
@ -57,15 +66,6 @@ public class SeriesGroup {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCollectorId() {
|
|
||||||
return collectorId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SeriesGroup aggregate(String name, IDataProcessor aggregator){
|
|
||||||
aggregators.put(name, aggregator);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getyAxis() {
|
public String getyAxis() {
|
||||||
return yAxis;
|
return yAxis;
|
||||||
}
|
}
|
||||||
|
@ -75,45 +75,21 @@ public class SeriesGroup {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SeriesGroup setDrawEveryNthGraph(int factor) {
|
|
||||||
this.collectorSampleSize = factor;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TimeSeriesCollection createDataSet(Experiment experiment){
|
|
||||||
Collection<IDataCollector> collectors = experiment.getCollectors(collectorId);
|
public TimeSeriesCollection createDataSet(Benchmark benchmark){
|
||||||
collectors.addAll(this.collectors);
|
|
||||||
TimeSeriesCollection collection = new TimeSeriesCollection();
|
TimeSeriesCollection collection = new TimeSeriesCollection();
|
||||||
TimeBasedAggregator aggregator = new TimeBasedAggregator();
|
TimeBasedAggregator aggregator = new TimeBasedAggregator();
|
||||||
// create a series from each data collector
|
// create a series from each data collector
|
||||||
int numberOfCollectors = 1;
|
|
||||||
for(IDataCollector collector : collectors){
|
for(IDataCollector collector : collectors){
|
||||||
// ignore empty data collectors as well as according to sample size
|
// ignore empty data collectors as well as according to sample size
|
||||||
if(collector == null || collector.size() == 0)continue;
|
if(collector == null || collector.size() == 0)continue;
|
||||||
if(numberOfCollectors % collectorSampleSize != 0){
|
|
||||||
numberOfCollectors++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeSeriesConsumer wrapper = new TimeSeriesConsumer(collector.getId());
|
TimeSeriesConsumer wrapper = new TimeSeriesConsumer(collector.getId());
|
||||||
collector.feed(wrapper);
|
collector.feed(wrapper);
|
||||||
TimeSeries series = wrapper.getSeries();
|
TimeSeries series = wrapper.getSeries();
|
||||||
collection.addSeries(series);
|
collection.addSeries(series);
|
||||||
// prepare the time based aggregator
|
if(size < collector.size())size = collector.size();
|
||||||
if(!aggregators.isEmpty())
|
|
||||||
aggregator.consume(collector);
|
|
||||||
numberOfCollectors++;
|
|
||||||
}
|
}
|
||||||
DataCollector average = aggregator.fold(new Average());
|
|
||||||
ItemCounter numberOfDatapoints = new ItemCounter();
|
|
||||||
for(Map.Entry<String, IDataProcessor> aggregation : aggregators.entrySet()){
|
|
||||||
TimeSeriesConsumer series = new TimeSeriesConsumer(aggregation.getKey());
|
|
||||||
IDataProcessor aggregate = aggregation.getValue();
|
|
||||||
aggregate.pipeInto(numberOfDatapoints).pipeInto(series);
|
|
||||||
average.feed(aggregate);
|
|
||||||
collection.addSeries(series.getSeries());
|
|
||||||
}
|
|
||||||
size = numberOfDatapoints.getItemCount();
|
|
||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package net.engio.lab;
|
package net.engio.lab;
|
||||||
|
|
||||||
|
import net.engio.pips.lab.Benchmark;
|
||||||
import net.engio.pips.lab.ExecutionContext;
|
import net.engio.pips.lab.ExecutionContext;
|
||||||
import net.engio.pips.lab.Executions;
|
import net.engio.pips.lab.Executions;
|
||||||
import net.engio.pips.lab.Experiment;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -20,12 +20,12 @@ public class ExecutionContextTest extends UnitTest{
|
||||||
Map<String, Object> bindings = new HashMap<String, Object>();
|
Map<String, Object> bindings = new HashMap<String, Object>();
|
||||||
bindings.put(ExecutionContext.class.toString(), ExecutionContext.class);
|
bindings.put(ExecutionContext.class.toString(), ExecutionContext.class);
|
||||||
bindings.put(UnitTest.class.toString(), UnitTest.class);
|
bindings.put(UnitTest.class.toString(), UnitTest.class);
|
||||||
bindings.put(Experiment.class.toString(), Experiment.class);
|
bindings.put(Benchmark.class.toString(), Benchmark.class);
|
||||||
return bindings;
|
return bindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExecutionContext getInitialContext(Map<String, Object> bindings){
|
private ExecutionContext getInitialContext(Map<String, Object> bindings){
|
||||||
ExecutionContext ctx = new ExecutionContext(new Experiment("test"));
|
ExecutionContext ctx = new ExecutionContext(new Benchmark("test"));
|
||||||
ctx.bindAll(bindings);
|
ctx.bindAll(bindings);
|
||||||
|
|
||||||
assertBindingsExist(bindings, ctx);
|
assertBindingsExist(bindings, ctx);
|
||||||
|
@ -104,7 +104,7 @@ public class ExecutionContextTest extends UnitTest{
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetMatching(){
|
public void testGetMatching(){
|
||||||
ExecutionContext ctx = new ExecutionContext(new Experiment("test"));
|
ExecutionContext ctx = new ExecutionContext(new Benchmark("test"));
|
||||||
Object[] bindings = new Object[]{"root", "root:lvl1", "root:lvl1:lvl2", "none"};
|
Object[] bindings = new Object[]{"root", "root:lvl1", "root:lvl1:lvl2", "none"};
|
||||||
ctx.bind(bindings);
|
ctx.bind(bindings);
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ public class ExecutionContextTest extends UnitTest{
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExecutions(){
|
public void testExecutions(){
|
||||||
ExecutionContext ctx = new ExecutionContext(new Experiment("test"));
|
ExecutionContext ctx = new ExecutionContext(new Benchmark("test"));
|
||||||
Object[] bindings = new Object[]{"root", "root:lvl1", "root:lvl1:lvl2", "none"};
|
Object[] bindings = new Object[]{"root", "root:lvl1", "root:lvl1:lvl2", "none"};
|
||||||
ctx.bind(bindings);
|
ctx.bind(bindings);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
package net.engio.lab;
|
package net.engio.lab;
|
||||||
|
|
||||||
|
import net.engio.pips.lab.Benchmark;
|
||||||
import net.engio.pips.lab.ExecutionContext;
|
import net.engio.pips.lab.ExecutionContext;
|
||||||
import net.engio.pips.lab.Experiment;
|
import net.engio.pips.lab.LabException;
|
||||||
import net.engio.pips.lab.Laboratory;
|
import net.engio.pips.lab.Laboratory;
|
||||||
import net.engio.pips.lab.workload.*;
|
import net.engio.pips.lab.workload.*;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -29,8 +30,81 @@ public class LaboratoryTest extends UnitTest{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidWorkloadSetups() throws Exception {
|
||||||
|
Workload withoutFactory = new Workload("without factory")
|
||||||
|
.starts().immediately()
|
||||||
|
.duration().repetitions(1);
|
||||||
|
|
||||||
|
Workload withoutStart = new Workload("without start")
|
||||||
|
.setITaskFactory(NoOperation)
|
||||||
|
.duration().repetitions(1);
|
||||||
|
|
||||||
|
Workload withoutDuration = new Workload("without duration")
|
||||||
|
.starts().immediately()
|
||||||
|
.setITaskFactory(NoOperation);
|
||||||
|
|
||||||
|
|
||||||
|
Workload cyclicStart1 = new Workload("without duration");
|
||||||
|
Workload cyclicStart2 = new Workload("without duration");
|
||||||
|
cyclicStart1
|
||||||
|
.starts().after(cyclicStart2)
|
||||||
|
.duration().repetitions(1)
|
||||||
|
.setITaskFactory(NoOperation);
|
||||||
|
cyclicStart2
|
||||||
|
.starts().after(cyclicStart1)
|
||||||
|
.duration().repetitions(1)
|
||||||
|
.setITaskFactory(NoOperation);
|
||||||
|
|
||||||
|
Workload cyclicDuration1 = new Workload("without duration");
|
||||||
|
Workload cyclicDuration2 = new Workload("without duration");
|
||||||
|
cyclicDuration1
|
||||||
|
.starts().immediately()
|
||||||
|
.duration().depends(cyclicDuration2)
|
||||||
|
.setITaskFactory(NoOperation);
|
||||||
|
cyclicDuration2
|
||||||
|
.starts().immediately()
|
||||||
|
.duration().depends(cyclicDuration1)
|
||||||
|
.setITaskFactory(NoOperation);
|
||||||
|
|
||||||
|
Laboratory lab = new Laboratory();
|
||||||
|
|
||||||
|
try {
|
||||||
|
lab.run(new Benchmark("Invalid").addWorkload(withoutFactory));
|
||||||
|
fail();
|
||||||
|
} catch (LabException e) {
|
||||||
|
assertEquals(e.getCode(), LabException.ErrorCode.WLWithoutFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
lab.run(new Benchmark("Invalid").addWorkload(withoutStart));
|
||||||
|
fail();
|
||||||
|
} catch (LabException e) {
|
||||||
|
assertEquals(e.getCode(), LabException.ErrorCode.WLWithoutStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
lab.run(new Benchmark("Invalid").addWorkload(withoutDuration));
|
||||||
|
fail();
|
||||||
|
} catch (LabException e) {
|
||||||
|
assertEquals(e.getCode(), LabException.ErrorCode.WLWithoutDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
lab.run(new Benchmark("Invalid").addWorkload(cyclicStart1, cyclicStart2));
|
||||||
|
fail();
|
||||||
|
} catch (LabException e) {
|
||||||
|
assertEquals(e.getCode(), LabException.ErrorCode.WLWithCycleInStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
lab.run(new Benchmark("Invalid").addWorkload(cyclicDuration1, cyclicDuration2));
|
||||||
|
fail();
|
||||||
|
} catch (LabException e) {
|
||||||
|
assertEquals(e.getCode(), LabException.ErrorCode.WLWithCycleInDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWorkloadSchedulingStartingAfter() throws Exception {
|
public void testWorkloadSchedulingStartingAfter() throws Exception {
|
||||||
|
@ -75,17 +149,18 @@ public class LaboratoryTest extends UnitTest{
|
||||||
.starts().after(first);
|
.starts().after(first);
|
||||||
|
|
||||||
Laboratory lab = new Laboratory();
|
Laboratory lab = new Laboratory();
|
||||||
lab.run(new Experiment("test").addWorkload(first, second));
|
lab.run(new Benchmark("test").addWorkload(first, second));
|
||||||
|
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
// both have run in the end
|
// both have run in the end
|
||||||
assertEquals(0, counter.get());
|
assertEquals(0, counter.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
//@Test
|
||||||
public void testWorkloadShutdownCancelsTasks() throws Exception {
|
// TODO: this invalid start/end dependency tree must be fixed
|
||||||
final AtomicInteger counter = new AtomicInteger(1);
|
public void testWorkloadSchedulingStartingAfterDelayed() throws Exception {
|
||||||
Workload countUp = new Workload("First workload")
|
final AtomicInteger counter = new AtomicInteger(0);
|
||||||
|
Workload first = new Workload("First workload")
|
||||||
.setParallelTasks(15)
|
.setParallelTasks(15)
|
||||||
.setITaskFactory(new ITaskFactory() {
|
.setITaskFactory(new ITaskFactory() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -98,6 +173,58 @@ public class LaboratoryTest extends UnitTest{
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.duration().repetitions(1)
|
||||||
|
.starts().after(2, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
Workload second = new Workload("Second Workload")
|
||||||
|
.setParallelTasks(15)
|
||||||
|
.setITaskFactory(new ITaskFactory() {
|
||||||
|
@Override
|
||||||
|
public ITask create(ExecutionContext context) {
|
||||||
|
return new ITask() {
|
||||||
|
@Override
|
||||||
|
public void run(ExecutionContext context) throws Exception {
|
||||||
|
counter.decrementAndGet();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.handle(ExecutionEvent.WorkloadInitialization, new ExecutionHandler() {
|
||||||
|
@Override
|
||||||
|
public void handle(ExecutionContext context) {
|
||||||
|
// the first workload
|
||||||
|
assertEquals(15, counter.get());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.duration().depends(first)
|
||||||
|
.starts().after(first);
|
||||||
|
|
||||||
|
Laboratory lab = new Laboratory();
|
||||||
|
lab.run(new Benchmark("test").addWorkload(first, second));
|
||||||
|
|
||||||
|
Thread.sleep(4000);
|
||||||
|
// both have run in the end
|
||||||
|
assertEquals(0, counter.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWorkloadShutdownCancelsTasks() throws Exception {
|
||||||
|
final AtomicInteger first = new AtomicInteger(1);
|
||||||
|
final AtomicInteger second = new AtomicInteger(1);
|
||||||
|
|
||||||
|
Workload countUp = new Workload("First workload")
|
||||||
|
.setParallelTasks(15)
|
||||||
|
.setITaskFactory(new ITaskFactory() {
|
||||||
|
@Override
|
||||||
|
public ITask create(ExecutionContext context) {
|
||||||
|
return new ITask() {
|
||||||
|
@Override
|
||||||
|
public void run(ExecutionContext context) throws Exception {
|
||||||
|
first.incrementAndGet();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})
|
||||||
.duration().lasts(5, TimeUnit.SECONDS)
|
.duration().lasts(5, TimeUnit.SECONDS)
|
||||||
.starts().immediately();
|
.starts().immediately();
|
||||||
|
|
||||||
|
@ -109,7 +236,7 @@ public class LaboratoryTest extends UnitTest{
|
||||||
return new ITask() {
|
return new ITask() {
|
||||||
@Override
|
@Override
|
||||||
public void run(ExecutionContext context) throws Exception {
|
public void run(ExecutionContext context) throws Exception {
|
||||||
counter.decrementAndGet();
|
second.incrementAndGet();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -118,14 +245,16 @@ public class LaboratoryTest extends UnitTest{
|
||||||
.starts().immediately();
|
.starts().immediately();
|
||||||
|
|
||||||
Laboratory lab = new Laboratory();
|
Laboratory lab = new Laboratory();
|
||||||
lab.run(new Experiment("test").addWorkload(countUp, countDown));
|
lab.run(new Benchmark("test").addWorkload(countUp, countDown));
|
||||||
|
|
||||||
int count = counter.get();
|
int firstVal = first.get();
|
||||||
|
int secondVal = second.get();
|
||||||
// no threads that change the counter are running anymore
|
// no threads that change the counter are running anymore
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
assertEquals(count, counter.get());
|
assertEquals(firstVal, first.get());
|
||||||
// both have run in the end
|
assertEquals(secondVal, second.get());
|
||||||
assertTrue(counter.get() < 16);
|
assertTrue(firstVal > 1);
|
||||||
|
assertTrue(secondVal > 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -166,7 +295,7 @@ public class LaboratoryTest extends UnitTest{
|
||||||
.starts().immediately();
|
.starts().immediately();
|
||||||
|
|
||||||
Laboratory lab = new Laboratory();
|
Laboratory lab = new Laboratory();
|
||||||
lab.run(new Experiment("test").addWorkload(first, second));
|
lab.run(new Benchmark("test").addWorkload(first, second));
|
||||||
|
|
||||||
// first workload has run at least duration seconds
|
// first workload has run at least duration seconds
|
||||||
assertTrue(finish.get() - start.get() >= duration * 1000);
|
assertTrue(finish.get() - start.get() >= duration * 1000);
|
||||||
|
@ -203,7 +332,7 @@ public class LaboratoryTest extends UnitTest{
|
||||||
});
|
});
|
||||||
|
|
||||||
Laboratory lab = new Laboratory();
|
Laboratory lab = new Laboratory();
|
||||||
lab.run(new Experiment("test").addWorkload(first, second, third));
|
lab.run(new Benchmark("test").addWorkload(first, second, third));
|
||||||
|
|
||||||
assertTrue(finished.get());
|
assertTrue(finished.get());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue