Paul Duffin | e236301 | 2015-11-30 16:20:41 +0000 | [diff] [blame^] | 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 | */ |
| 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 | } |