package io.vivarium.scripts;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import io.vivarium.core.GridWorld;
import io.vivarium.core.GridWorldBlueprint;
import io.vivarium.core.simulation.Simulation;
import io.vivarium.util.Rand;
import io.vivarium.util.concurrency.ThreadRandAllocator;
public class RunBenchmark extends CommonsScript
{
public RunBenchmark(String[] args)
{
super(args);
}
@Override
protected List<Option> getScriptSpecificOptions()
{
LinkedList<Option> options = new LinkedList<>();
return options;
}
@Override
protected String getExtraArgString()
{
return "";
}
@Override
protected String getUsageHeader()
{
return "Run a benchmark to determine a computers throughput for Vivarium simulations.";
}
@Override
protected void run(CommandLine commandLine)
{
try
{
// System.out.println("Running benchmarks:");
System.out.println("threads,cts,cts/thread,std.dev");
// If we're running multi-threaded code, we need to use a multi-threaded random allocator
Rand.setAllocator(new ThreadRandAllocator());
// Do this just to give the JIT Compiler some stuff to optimize
threadTest(4, 10, 100);
// inlineTest(100);
// Now run the actual benchmarks now that the the Java VM is warmed up
int iterations = 1000;
int size = 40;
double[] results;
for (int threadCount = 1; threadCount <= 16; threadCount++)
{
results = threadTest(threadCount, iterations, size);
int resultCount = threadCount * iterations;
double total = 0;
for (int i = 0; i < resultCount; i++)
{
total += results[i];
}
double average = total / iterations;
double averagePerThread = total / resultCount;
double sumSquares = 0;
for (int i = 0; i < resultCount; i++)
{
sumSquares += Math.pow(results[i] - averagePerThread, 2);
}
double standardDeviation = Math.sqrt(sumSquares / resultCount);
System.out.println(threadCount + "," + (int) average + "," + (int) averagePerThread + ","
+ (int) standardDeviation);
/*
* System.out.print(String.format("%sx%s (%s threads):%n Creature Ticks / Second: %4.3e%n%n ~ %s", size,
* size, threadCount, result, (int) result));
*/
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
private static double[] threadTest(int threadPoolSize, int iterationsPerThread, int size)
throws InterruptedException
{
double[] results = new double[threadPoolSize * iterationsPerThread];
BenchmarkThread[] threads = new BenchmarkThread[threadPoolSize];
for (int i = 0; i < threadPoolSize; i++)
{
threads[i] = new BenchmarkThread(iterationsPerThread, size);
}
for (int i = 0; i < threadPoolSize; i++)
{
threads[i].start();
}
for (int i = 0; i < threadPoolSize; i++)
{
threads[i].join();
double[] threadResults = threads[i].getResults();
System.arraycopy(threadResults, 0, results, i * iterationsPerThread, iterationsPerThread);
}
return results;
}
private static class BenchmarkThread extends Thread
{
private final int _iterations;
private final int _size;
private double[] results;
public BenchmarkThread(int iterations, int size)
{
_iterations = iterations;
_size = size;
}
public double[] getResults()
{
return results;
}
@Override
public void run()
{
results = iterateTest(_iterations, _size);
}
}
private static double[] iterateTest(int iterations, int size)
{
// Tests, by size
double[] results = new double[iterations];
for (int i = 0; i < iterations; i++)
{
results[i] = inlineTest(size);
}
return results;
}
private static double inlineTest(int size)
{
GridWorldBlueprint worldBlueprint = GridWorldBlueprint.makeDefault();
worldBlueprint.setSize(size);
worldBlueprint.getCreatureBlueprints().get(0).setMaximumFood(Integer.MAX_VALUE); // Increase max food to prevent
// creatures from
// starving during the benchmark
GridWorld world = new GridWorld(worldBlueprint);
int tickCount = 2000;
int worldPopulation = world.getCreatureCount();
long startTime = System.currentTimeMillis();
Simulation.runForUpTo(world, tickCount);
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
double creatureTicksPerSeconds = worldPopulation * tickCount / (totalTime / 1000.0);
return creatureTicksPerSeconds;
}
public static void main(String[] args)
{
new RunBenchmark(args);
}
}