Java tutorial
/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.caliper.runner; import com.google.caliper.Benchmark; import com.google.caliper.Environment; import com.google.caliper.MeasurementSet; import com.google.caliper.MeasurementType; import com.google.caliper.Result; import com.google.caliper.Runner; import com.google.caliper.Scenario; import com.google.caliper.ScenarioResult; import com.google.caliper.ScenarioSelection; import com.google.caliper.SuiteRun; import com.google.caliper.util.DebugMeasurer; import com.google.caliper.util.CommandLineParser; import com.google.caliper.util.InterleavedReader; import com.google.caliper.report.ReportGenerator; import com.google.caliper.vm.Vm; import com.google.caliper.vm.VmFactory; import com.google.caliper.exception.ConfigurationException; import com.google.caliper.exception.UserException; import com.google.caliper.exception.UserException.DisplayUsageException; import com.google.caliper.exception.UserException.ExceptionFromUserCodeException; import com.google.caliper.report.DefaultRendererRegistry; import com.google.caliper.report.RendererRegistry; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ObjectArrays; import com.google.common.io.Closeables; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.regex.Pattern; /** * Creates, executes and reports benchmark runs. */ public final class DefaultRunner implements Runner { private static final Splitter ARGUMENT_SPLITTER = Splitter.on(Pattern.compile("\\s+")).omitEmptyStrings(); /** Command line arguments to the process */ private CommandLineParser arguments; private ScenarioSelection scenarioSelection; private final String DEFAULT_PLUGIN_LOCATION = "plugin"; public void run(String... args) { this.arguments = CommandLineParser.parse(args); this.scenarioSelection = new ScenarioSelection(arguments); if (arguments.getDebug()) { debug(); return; } File pluginFolder = arguments.getPluginFolder(); RendererRegistry registry = new DefaultRendererRegistry( (null != pluginFolder) ? pluginFolder : new File(DEFAULT_PLUGIN_LOCATION), arguments); final String reportType = arguments.getReportType(); if (registry.containsRenderer(reportType)) { Result result = runOutOfProcess(); new ReportGenerator(result.getRun(), registry, arguments).displayResults(); } else { System.out.println("No renderers found for type: " + reportType); System.out.println("Available renderers are:"); for (String renderer : registry.listRenderers()) { System.out.println(" - " + renderer + " : v" + registry.getRenderer(renderer).getVersion()); } } } private ScenarioResult runScenario(Scenario scenario) { MeasurementResult timeMeasurementResult = measure(scenario, MeasurementType.TIME); MeasurementSet allocationMeasurements = null; String allocationEventLog = null; MeasurementSet memoryMeasurements = null; String memoryEventLog = null; if (arguments.getMeasureMemory()) { MeasurementResult allocationsMeasurementResult = measure(scenario, MeasurementType.INSTANCE); allocationMeasurements = allocationsMeasurementResult.getMeasurements(); allocationEventLog = allocationsMeasurementResult.getEventLog(); MeasurementResult memoryMeasurementResult = measure(scenario, MeasurementType.MEMORY); memoryMeasurements = memoryMeasurementResult.getMeasurements(); memoryEventLog = memoryMeasurementResult.getEventLog(); } return new ScenarioResult(timeMeasurementResult.getMeasurements(), timeMeasurementResult.getEventLog(), allocationMeasurements, allocationEventLog, memoryMeasurements, memoryEventLog); } private class MeasurementResult { private final MeasurementSet measurements; private final String eventLog; MeasurementResult(MeasurementSet measurements, String eventLog) { this.measurements = measurements; this.eventLog = eventLog; } public MeasurementSet getMeasurements() { return measurements; } public String getEventLog() { return eventLog; } } private MeasurementResult measure(Scenario scenario, MeasurementType type) { Vm vm = new VmFactory().createVm(scenario); // this must be done before starting the forked process on certain VMs List<String> command = createCommand(scenario, vm, type); Process timeProcess = startForkedProcess(command); MeasurementSet measurementSet = null; StringBuilder eventLog = new StringBuilder(); InterleavedReader reader = null; try { reader = new InterleavedReader(arguments.getMarker(), new InputStreamReader(timeProcess.getInputStream())); Object o; while ((o = reader.read()) != null) { if (o instanceof String) { eventLog.append(o); } else if (measurementSet == null) { measurementSet = (MeasurementSet) o; } else { throw new RuntimeException("Unexpected value: " + o); } } } catch (Exception e) { throw new RuntimeException(e); } finally { Closeables.closeQuietly(reader); timeProcess.destroy(); } if (measurementSet == null) { String message = "Failed to execute " + Joiner.on(" ").join(command); System.err.println(" " + message); System.err.println(eventLog.toString()); throw new ConfigurationException(message); } return new MeasurementResult(measurementSet, eventLog.toString()); } private List<String> createCommand(Scenario scenario, Vm vm, MeasurementType type) { String classPath = System.getProperty("java.class.path"); if (classPath == null || classPath.length() == 0) { throw new IllegalStateException("java.class.path is undefined in " + System.getProperties()); } ImmutableList.Builder<String> command = ImmutableList.builder(); command.addAll(ARGUMENT_SPLITTER.split(scenario.getVariables().get(Scenario.VM_KEY))); command.add("-cp").add(classPath); if (type == MeasurementType.INSTANCE || type == MeasurementType.MEMORY) { String allocationJarFile = System.getenv("ALLOCATION_JAR"); command.add("-javaagent:" + allocationJarFile); } command.addAll(vm.getVmSpecificOptions(type, arguments)); Map<String, String> vmParameters = scenario.getVariables(scenarioSelection.getVmParameterNames()); for (String vmParameter : vmParameters.values()) { command.addAll(ARGUMENT_SPLITTER.split(vmParameter)); } command.add(InProcessRunner.class.getName()); createCommand(command, scenario, type); return command.build(); } private void createCommand(ImmutableList.Builder<String> command, Scenario scenario, MeasurementType type) { command.add("--warmupMillis").add(Long.toString(arguments.getWarmupMillis())); command.add("--runMillis").add(Long.toString(arguments.getRunMillis())); Map<String, String> userParameters = scenario.getVariables(scenarioSelection.getUserParameterNames()); for (Entry<String, String> entry : userParameters.entrySet()) { command.add("-D" + entry.getKey() + "=" + entry.getValue()); } command.add("--measurementType").add(type.toString()); command.add("--marker").add(arguments.getMarker()); command.add(arguments.getSuiteClassName()); } private Process startForkedProcess(List<String> command) { ProcessBuilder builder = new ProcessBuilder(); builder.command(command); builder.redirectErrorStream(true); builder.directory(new File(System.getProperty("user.dir"))); try { return builder.start(); } catch (IOException e) { throw new RuntimeException("failed to start subprocess", e); } } private void debug() { try { int debugReps = arguments.getDebugReps(); InProcessRunner runner = new InProcessRunner(); DebugMeasurer measurer = new DebugMeasurer(debugReps); for (Scenario scenario : scenarioSelection.select()) { runner.run(scenarioSelection, scenario, measurer); } } catch (Exception e) { throw new ExceptionFromUserCodeException(e); } } private Result runOutOfProcess() { Date executedDate = new Date(); ImmutableMap.Builder<Scenario, ScenarioResult> resultsBuilder = ImmutableMap.builder(); try { List<Scenario> scenarios = scenarioSelection.select(); int i = 0; for (Scenario scenario : scenarios) { beforeMeasurement(i++, scenarios.size(), scenario); ScenarioResult scenarioResult = runScenario(scenario); afterMeasurement(arguments.getMeasureMemory(), scenarioResult); resultsBuilder.put(scenario, scenarioResult); } Environment environment = new EnvironmentGetter().getEnvironmentSnapshot(); return new Result(new SuiteRun(resultsBuilder.build(), arguments.getSuiteClassName(), executedDate), environment); } catch (Exception e) { throw new ExceptionFromUserCodeException(e); } } private void beforeMeasurement(int index, int total, Scenario scenario) { double percentDone = (double) index / total; System.out.printf("%2.0f%% %s", percentDone * 100, scenario); } private void afterMeasurement(boolean memoryMeasured, ScenarioResult scenarioResult) { String memoryMeasurements = ""; if (memoryMeasured) { MeasurementSet instanceMeasurementSet = scenarioResult.getMeasurementSet(MeasurementType.INSTANCE); String instanceUnit = ReportGenerator.UNIT_ORDERING .min(instanceMeasurementSet.getUnitNames().entrySet()).getKey(); MeasurementSet memoryMeasurementSet = scenarioResult.getMeasurementSet(MeasurementType.MEMORY); String memoryUnit = ReportGenerator.UNIT_ORDERING.min(memoryMeasurementSet.getUnitNames().entrySet()) .getKey(); memoryMeasurements = String.format(", allocated %s%s for a total of %s%s", Math.round(instanceMeasurementSet.medianUnits()), instanceUnit, Math.round(memoryMeasurementSet.medianUnits()), memoryUnit); } MeasurementSet timeMeasurementSet = scenarioResult.getMeasurementSet(MeasurementType.TIME); String unit = ReportGenerator.UNIT_ORDERING.min(timeMeasurementSet.getUnitNames().entrySet()).getKey(); System.out.printf(" %.2f %s; \u03C3=%.2f %s @ %d trials%s%n", timeMeasurementSet.medianUnits(), unit, timeMeasurementSet.standardDeviationUnits(), unit, timeMeasurementSet.getMeasurements().size(), memoryMeasurements); } public static void main(String... args) { try { new DefaultRunner().run(args); System.exit(0); // user code may have leave non-daemon threads behind! } catch (DisplayUsageException e) { e.display(); System.exit(0); } catch (UserException e) { e.display(); System.exit(1); } } public static void main(Class<? extends Benchmark> suite, String... args) { main(ObjectArrays.concat(args, suite.getName())); } }