diff options
Diffstat (limited to 'src/com/google/caliper/Runner.java')
-rw-r--r-- | src/com/google/caliper/Runner.java | 363 |
1 files changed, 98 insertions, 265 deletions
diff --git a/src/com/google/caliper/Runner.java b/src/com/google/caliper/Runner.java index 72442db..e359df8 100644 --- a/src/com/google/caliper/Runner.java +++ b/src/com/google/caliper/Runner.java @@ -16,180 +16,113 @@ package com.google.caliper; +import com.google.caliper.UserException.ExceptionFromUserCodeException; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.LinkedHashMultimap; -import com.google.common.collect.Multimap; - +import com.google.common.collect.ImmutableMap.Builder; +import com.google.common.collect.ObjectArrays; import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.UUID; /** * Creates, executes and reports benchmark runs. */ public final class Runner { - private String suiteClassName; - private Benchmark suite; - - /** Effective parameters to run in the benchmark. */ - private Multimap<String, String> parameters = LinkedHashMultimap.create(); - - /** JVMs to run in the benchmark */ - private Set<String> userVms = new LinkedHashSet<String>(); - - /** - * Parameter values specified by the user on the command line. Parameters with - * no value in this multimap will get their values from the benchmark suite. - */ - private Multimap<String, String> userParameters = LinkedHashMultimap.create(); - - /** - * True if each benchmark should run in process. - */ - private boolean inProcess; - - private long warmupMillis = 5000; - private long runMillis = 5000; + /** Command line arguments to the process */ + private Arguments arguments; + private ScenarioSelection scenarioSelection; /** - * Sets the named parameter to the specified value. This value will replace - * the benchmark suite's default values for the parameter. Multiple calls to - * this method will cause benchmarks for each value to be run. + * Returns the UUID of the executing host. Multiple runs by the same user on + * the same machine should yield the same result. */ - void setParameter(String name, String value) { - userParameters.put(name, value); - } - - private void prepareSuite() { + private String getExecutedByUuid() { try { - @SuppressWarnings("unchecked") // guarded by the if statement that follows - Class<? extends Benchmark> suiteClass - = (Class<? extends Benchmark>) Class.forName(suiteClassName); - if (!Benchmark.class.isAssignableFrom(suiteClass)) { - throw new ConfigurationException(suiteClass + " is not a benchmark suite."); + File dotCaliperRc = new File(System.getProperty("user.home"), ".caliperrc"); + Properties properties = new Properties(); + if (dotCaliperRc.exists()) { + properties.load(new FileInputStream(dotCaliperRc)); } - Constructor<? extends Benchmark> constructor = suiteClass.getDeclaredConstructor(); - suite = constructor.newInstance(); - } catch (InvocationTargetException e) { - throw new ExecutionException(e.getCause()); - } catch (Exception e) { - throw new ConfigurationException(e); - } - } - - private void prepareParameters() { - for (String key : suite.parameterNames()) { - // first check if the user has specified values - Collection<String> userValues = userParameters.get(key); - if (!userValues.isEmpty()) { - parameters.putAll(key, userValues); - // TODO: type convert 'em to validate? - - } else { // otherwise use the default values from the suite - Set<String> values = suite.parameterValues(key); - if (values.isEmpty()) { - throw new ConfigurationException(key + " has no values"); - } - parameters.putAll(key, values); + String userUuid = properties.getProperty("userUuid"); + if (userUuid == null) { + userUuid = UUID.randomUUID().toString(); + properties.setProperty("userUuid", userUuid); + properties.store(new FileOutputStream(dotCaliperRc), ""); } + + return userUuid; + } catch (IOException e) { + throw new RuntimeException(e); } } - private ImmutableSet<String> defaultVms() { - return "Dalvik".equals(System.getProperty("java.vm.name")) - ? ImmutableSet.of("dalvikvm") - : ImmutableSet.of("java"); + public void run(String... args) { + this.arguments = Arguments.parse(args); + this.scenarioSelection = new ScenarioSelection(arguments); + Run run = runOutOfProcess(); + new ConsoleReport(run).displayResults(); + postResults(run); } - /** - * Returns a complete set of runs with every combination of values and - * benchmark classes. - */ - private List<Run> createRuns() throws Exception { - List<RunBuilder> builders = new ArrayList<RunBuilder>(); - - // create runs for each VMs - Set<String> vms = userVms.isEmpty() - ? defaultVms() - : userVms; - for (String vm : vms) { - RunBuilder runBuilder = new RunBuilder(); - runBuilder.vm = vm; - builders.add(runBuilder); + private void postResults(Run run) { + String postHost = arguments.getPostHost(); + if ("none".equals(postHost)) { + return; } - for (Map.Entry<String, Collection<String>> parameter : parameters.asMap().entrySet()) { - Iterator<String> values = parameter.getValue().iterator(); - if (!values.hasNext()) { - throw new ConfigurationException("Not enough values for " + parameter); - } - - String key = parameter.getKey(); - - String firstValue = values.next(); - for (RunBuilder builder : builders) { - builder.parameters.put(key, firstValue); + try { + URL url = new URL(postHost + run.getExecutedByUuid() + "/" + run.getBenchmarkName()); + HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); + urlConnection.setDoOutput(true); + Xml.runToXml(run, urlConnection.getOutputStream()); + if (urlConnection.getResponseCode() == 200) { + System.out.println(""); + System.out.println("View current and previous benchmark results online:"); + System.out.println(" " + url); + return; } - // multiply the size of the specs by the number of alternate values - int size = builders.size(); - while (values.hasNext()) { - String alternate = values.next(); - for (int s = 0; s < size; s++) { - RunBuilder copy = builders.get(s).copy(); - copy.parameters.put(key, alternate); - builders.add(copy); - } + System.out.println("Posting to " + postHost + " failed: " + + urlConnection.getResponseMessage()); + BufferedReader reader = new BufferedReader( + new InputStreamReader(urlConnection.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + System.out.println(line); } - } - - List<Run> result = new ArrayList<Run>(); - for (RunBuilder builder : builders) { - result.add(builder.build()); - } - - return result; - } - - static class RunBuilder { - Map<String, String> parameters = new LinkedHashMap<String, String>(); - String vm; - - RunBuilder copy() { - RunBuilder result = new RunBuilder(); - result.parameters.putAll(parameters); - result.vm = vm; - return result; - } - - public Run build() { - return new Run(parameters, vm); + } catch (IOException e) { + throw new RuntimeException(e); } } - private double executeForked(Run run) { + private double executeForked(Scenario scenario) { ProcessBuilder builder = new ProcessBuilder(); List<String> command = builder.command(); - command.addAll(Arrays.asList(run.getVm().split("\\s+"))); + command.addAll(Arrays.asList(scenario.getVariables().get(Scenario.VM_KEY).split("\\s+"))); command.add("-cp"); command.add(System.getProperty("java.class.path")); - command.add(Runner.class.getName()); + command.add(InProcessRunner.class.getName()); command.add("--warmupMillis"); - command.add(String.valueOf(warmupMillis)); + command.add(String.valueOf(arguments.getWarmupMillis())); command.add("--runMillis"); - command.add(String.valueOf(runMillis)); - command.add("--inProcess"); - for (Map.Entry<String, String> entry : run.getParameters().entrySet()) { + command.add(String.valueOf(arguments.getRunMillis())); + for (Entry<String, String> entry : scenario.getParameters().entrySet()) { command.add("-D" + entry.getKey() + "=" + entry.getValue()); } - command.add(suiteClassName); + command.add(arguments.getSuiteClassName()); BufferedReader reader = null; try { @@ -202,7 +135,7 @@ public final class Runner { Double nanosPerTrial = null; try { nanosPerTrial = Double.valueOf(firstLine); - } catch (NumberFormatException e) { + } catch (NumberFormatException ignore) { } String anotherLine = reader.readLine(); @@ -229,163 +162,63 @@ public final class Runner { } } - private Result runOutOfProcess() { - ImmutableMap.Builder<Run, Double> resultsBuilder = ImmutableMap.builder(); + // TODO: check if this is platform-independent + @SuppressWarnings("HardcodedLineSeparator") + private static final String RETURN = "\r"; + + private Run runOutOfProcess() { + String executedByUuid = getExecutedByUuid(); + Date executedDate = new Date(); + Builder<Scenario, Double> resultsBuilder = ImmutableMap.builder(); try { - List<Run> runs = createRuns(); + List<Scenario> scenarios = scenarioSelection.select(); int i = 0; - for (Run run : runs) { - beforeRun(i++, runs.size(), run); - double nanosPerTrial = executeForked(run); - afterRun(nanosPerTrial); - resultsBuilder.put(run, nanosPerTrial); + for (Scenario scenario : scenarios) { + beforeMeasurement(i++, scenarios.size(), scenario); + double nanosPerTrial = executeForked(scenario); + afterMeasurement(nanosPerTrial); + resultsBuilder.put(scenario, nanosPerTrial); } // blat out our progress bar - System.out.print("\r"); + System.out.print(RETURN); for (int j = 0; j < 80; j++) { System.out.print(" "); } - System.out.print("\r"); + System.out.print(RETURN); - return new Result(resultsBuilder.build()); + return new Run(resultsBuilder.build(), arguments.getSuiteClassName(), executedByUuid, executedDate); } catch (Exception e) { - throw new ExecutionException(e); + throw new ExceptionFromUserCodeException(e); } } - private void beforeRun(int index, int total, Run run) { + private void beforeMeasurement(int index, int total, Scenario scenario) { double percentDone = (double) index / total; int runStringLength = 63; // so the total line length is 80 - String runString = String.valueOf(run); + String runString = String.valueOf(scenario); if (runString.length() > runStringLength) { runString = runString.substring(0, runStringLength); } - System.out.printf("\r%2.0f%% %-" + runStringLength + "s", + System.out.printf(RETURN + "%2.0f%% %-" + runStringLength + "s", percentDone * 100, runString); } - private void afterRun(double nanosPerTrial) { + private void afterMeasurement(double nanosPerTrial) { System.out.printf(" %10.0fns", nanosPerTrial); } - private void runInProcess() { + public static void main(String... args) { try { - Caliper caliper = new Caliper(warmupMillis, runMillis); - - for (Run run : createRuns()) { - double result; - TimedRunnable timedRunnable = suite.createBenchmark(run.getParameters()); - double warmupNanosPerTrial = caliper.warmUp(timedRunnable); - result = caliper.run(timedRunnable, warmupNanosPerTrial); - double nanosPerTrial = result; - System.out.println(nanosPerTrial); - } - } catch (Exception e) { - throw new ExecutionException(e); - } - } - - private boolean parseArgs(String[] args) throws Exception { - for (int i = 0; i < args.length; i++) { - if ("--help".equals(args[i])) { - return false; - - } else if ("--inProcess".equals(args[i])) { - inProcess = true; - - } else if (args[i].startsWith("-D")) { - int equalsSign = args[i].indexOf('='); - if (equalsSign == -1) { - System.out.println("Malformed parameter " + args[i]); - return false; - } - String name = args[i].substring(2, equalsSign); - String value = args[i].substring(equalsSign + 1); - setParameter(name, value); - - } else if ("--warmupMillis".equals(args[i])) { - warmupMillis = Long.parseLong(args[++i]); - - } else if ("--runMillis".equals(args[i])) { - runMillis = Long.parseLong(args[++i]); - - } else if ("--vm".equals(args[i])) { - userVms.add(args[++i]); - - } else if (args[i].startsWith("-")) { - System.out.println("Unrecognized option: " + args[i]); - return false; - - } else { - if (suiteClassName != null) { - System.out.println("Too many benchmark classes!"); - return false; - } - suiteClassName = args[i]; - } - } - - if (inProcess && !userVms.isEmpty()) { - System.out.println("Cannot customize VM when running in process"); - return false; - } - - if (suiteClassName == null) { - System.out.println("No benchmark class provided."); - return false; - } - - return true; - } - - private void printUsage() { - System.out.println("Usage: Runner [OPTIONS...] <benchmark>"); - System.out.println(); - System.out.println(" <benchmark>: a benchmark class or suite"); - System.out.println(); - System.out.println("OPTIONS"); - System.out.println(); - System.out.println(" --D<param>=<value>: fix a benchmark parameter to a given value."); - System.out.println(" When multiple values for the same parameter are given (via"); - System.out.println(" multiple --Dx=y args), all supplied values are used."); - System.out.println(); - System.out.println(" --inProcess: run the benchmark in the same JVM rather than spawning"); - System.out.println(" another with the same classpath. By default each benchmark is"); - System.out.println(" run in a separate VM"); - System.out.println(); - System.out.println(" --warmupMillis <millis>: duration to warmup each benchmark"); - System.out.println(); - System.out.println(" --runMillis <millis>: duration to execute each benchmark"); - System.out.println(); - System.out.println(" --vm <vm>: executable to test benchmark on"); - - // adding new options? don't forget to update executeForked() - } - - public static void main(String... args) throws Exception { // TODO: cleaner error reporting - Runner runner = new Runner(); - if (!runner.parseArgs(args)) { - runner.printUsage(); - return; + new Runner().run(args); + } catch (UserException e) { + e.display(); + System.exit(1); } - - runner.prepareSuite(); - runner.prepareParameters(); - if (runner.inProcess) { - runner.runInProcess(); - return; - } - - Result result = runner.runOutOfProcess(); - new ConsoleReport(result).displayResults(); } - public static void main(Class<? extends Benchmark> suite, String... args) throws Exception { - String[] argsWithSuiteName = new String[args.length + 1]; - System.arraycopy(args, 0, argsWithSuiteName, 0, args.length); - argsWithSuiteName[args.length] = suite.getName(); - main(argsWithSuiteName); + public static void main(Class<? extends Benchmark> suite, String... args) { + main(ObjectArrays.concat(args, suite.getName())); } } |