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