blob: c81e407297fdc22514cfc75edd94e36b313d6535 [file] [log] [blame]
Paul Duffine2363012015-11-30 16:20:41 +00001/*
2 * Copyright (C) 2011 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14
15package com.google.caliper.runner;
16
17import static com.google.common.collect.ObjectArrays.concat;
18
19import com.google.caliper.config.InvalidConfigurationException;
20import com.google.caliper.options.CaliperOptions;
21import com.google.caliper.options.OptionsModule;
22import com.google.caliper.util.InvalidCommandException;
23import com.google.caliper.util.OutputModule;
24import com.google.common.base.Strings;
25import com.google.common.collect.ImmutableSortedMap;
26import com.google.common.util.concurrent.ServiceManager;
27
28import java.io.PrintWriter;
29import java.util.Map.Entry;
30import java.util.concurrent.TimeUnit;
31import java.util.concurrent.TimeoutException;
32
33import javax.annotation.Nullable;
34
35/**
36 * Primary entry point for the caliper benchmark runner application; run with {@code --help} for
37 * details. This class's only purpose is to take care of anything that's specific to command-line
38 * invocation and then hand off to {@code CaliperRun}. That is, a hypothetical GUI benchmark runner
39 * might still use {@code CaliperRun} but would skip using this class.
40 */
41public final class CaliperMain {
42 /**
43 * Your benchmark classes can implement main() like this: <pre> {@code
44 *
45 * public static void main(String[] args) {
46 * CaliperMain.main(MyBenchmark.class, args);
47 * }}</pre>
48 *
49 * Note that this method does invoke {@link System#exit} when it finishes. Consider {@link
50 * #exitlessMain} if you don't want that.
51 *
52 * <p>Measurement is handled in a subprocess, so it will not use {@code benchmarkClass} itself;
53 * the class is provided here only as a shortcut for specifying the full class <i>name</i>. The
54 * class that gets loaded later could be completely different.
55 */
56 public static void main(Class<?> benchmarkClass, String[] args) {
57 main(concat(args, benchmarkClass.getName()));
58 }
59
60 /**
61 * Entry point for the caliper benchmark runner application; run with {@code --help} for details.
62 */
63 public static void main(String[] args) {
64 PrintWriter stdout = new PrintWriter(System.out, true);
65 PrintWriter stderr = new PrintWriter(System.err, true);
66 int code = 1; // pessimism!
67
68 try {
69 exitlessMain(args, stdout, stderr);
70 code = 0;
71
72 } catch (InvalidCommandException e) {
73 e.display(stderr);
74 code = e.exitCode();
75
76 } catch (InvalidBenchmarkException e) {
77 e.display(stderr);
78
79 } catch (InvalidConfigurationException e) {
80 e.display(stderr);
81
82 } catch (Throwable t) {
83 t.printStackTrace(stderr);
84 stdout.println();
85 stdout.println("An unexpected exception has been thrown by the caliper runner.");
86 stdout.println("Please see https://sites.google.com/site/caliperusers/issues");
87 }
88
89 stdout.flush();
90 stderr.flush();
91 System.exit(code);
92 }
93
94 private static final String LEGACY_ENV = "USE_LEGACY_CALIPER";
95
96 public static void exitlessMain(String[] args, PrintWriter stdout, PrintWriter stderr)
97 throws InvalidCommandException, InvalidBenchmarkException, InvalidConfigurationException {
98 @Nullable String legacyCaliperEnv = System.getenv(LEGACY_ENV);
99 if (!Strings.isNullOrEmpty(legacyCaliperEnv)) {
100 System.err.println("Legacy Caliper is no more. " + LEGACY_ENV + " has no effect.");
101 }
102 try {
103 MainComponent mainComponent = DaggerMainComponent.builder()
104 .optionsModule(OptionsModule.withBenchmarkClass(args))
105 .outputModule(new OutputModule(stdout, stderr))
106 .build();
107 CaliperOptions options = mainComponent.getCaliperOptions();
108 if (options.printConfiguration()) {
109 stdout.println("Configuration:");
110 ImmutableSortedMap<String, String> sortedProperties =
111 ImmutableSortedMap.copyOf(mainComponent.getCaliperConfig().properties());
112 for (Entry<String, String> entry : sortedProperties.entrySet()) {
113 stdout.printf(" %s = %s%n", entry.getKey(), entry.getValue());
114 }
115 }
116 // check that the parameters are valid
117 mainComponent.getBenchmarkClass().validateParameters(options.userParameters());
118 ServiceManager serviceManager = mainComponent.getServiceManager();
119 serviceManager.startAsync().awaitHealthy();
120 try {
121 CaliperRun run = mainComponent.getCaliperRun();
122 run.run(); // throws IBE
123 } finally {
124 try {
125 // We have some shutdown logic to ensure that files are cleaned up so give it a chance to
126 // run
127 serviceManager.stopAsync().awaitStopped(10, TimeUnit.SECONDS);
128 } catch (TimeoutException e) {
129 // That's fine
130 }
131 }
132 } finally {
133 // courtesy flush
134 stderr.flush();
135 stdout.flush();
136 }
137 }
138}