• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
15 package com.google.caliper.runner;
16 
17 import static com.google.common.collect.ObjectArrays.concat;
18 
19 import com.google.caliper.config.InvalidConfigurationException;
20 import com.google.caliper.options.CaliperOptions;
21 import com.google.caliper.options.OptionsModule;
22 import com.google.caliper.util.InvalidCommandException;
23 import com.google.caliper.util.OutputModule;
24 import com.google.common.base.Strings;
25 import com.google.common.collect.ImmutableSortedMap;
26 import com.google.common.util.concurrent.ServiceManager;
27 
28 import java.io.PrintWriter;
29 import java.util.Map.Entry;
30 import java.util.concurrent.TimeUnit;
31 import java.util.concurrent.TimeoutException;
32 
33 import 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  */
41 public 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    */
main(Class<?> benchmarkClass, String[] args)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    */
main(String[] args)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 
exitlessMain(String[] args, PrintWriter stdout, PrintWriter stderr)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 }
139