blob: c81e407297fdc22514cfc75edd94e36b313d6535 [file] [log] [blame]
/*
* Copyright (C) 2011 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 static com.google.common.collect.ObjectArrays.concat;
import com.google.caliper.config.InvalidConfigurationException;
import com.google.caliper.options.CaliperOptions;
import com.google.caliper.options.OptionsModule;
import com.google.caliper.util.InvalidCommandException;
import com.google.caliper.util.OutputModule;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.util.concurrent.ServiceManager;
import java.io.PrintWriter;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.annotation.Nullable;
/**
* Primary entry point for the caliper benchmark runner application; run with {@code --help} for
* details. This class's only purpose is to take care of anything that's specific to command-line
* invocation and then hand off to {@code CaliperRun}. That is, a hypothetical GUI benchmark runner
* might still use {@code CaliperRun} but would skip using this class.
*/
public final class CaliperMain {
/**
* Your benchmark classes can implement main() like this: <pre> {@code
*
* public static void main(String[] args) {
* CaliperMain.main(MyBenchmark.class, args);
* }}</pre>
*
* Note that this method does invoke {@link System#exit} when it finishes. Consider {@link
* #exitlessMain} if you don't want that.
*
* <p>Measurement is handled in a subprocess, so it will not use {@code benchmarkClass} itself;
* the class is provided here only as a shortcut for specifying the full class <i>name</i>. The
* class that gets loaded later could be completely different.
*/
public static void main(Class<?> benchmarkClass, String[] args) {
main(concat(args, benchmarkClass.getName()));
}
/**
* Entry point for the caliper benchmark runner application; run with {@code --help} for details.
*/
public static void main(String[] args) {
PrintWriter stdout = new PrintWriter(System.out, true);
PrintWriter stderr = new PrintWriter(System.err, true);
int code = 1; // pessimism!
try {
exitlessMain(args, stdout, stderr);
code = 0;
} catch (InvalidCommandException e) {
e.display(stderr);
code = e.exitCode();
} catch (InvalidBenchmarkException e) {
e.display(stderr);
} catch (InvalidConfigurationException e) {
e.display(stderr);
} catch (Throwable t) {
t.printStackTrace(stderr);
stdout.println();
stdout.println("An unexpected exception has been thrown by the caliper runner.");
stdout.println("Please see https://sites.google.com/site/caliperusers/issues");
}
stdout.flush();
stderr.flush();
System.exit(code);
}
private static final String LEGACY_ENV = "USE_LEGACY_CALIPER";
public static void exitlessMain(String[] args, PrintWriter stdout, PrintWriter stderr)
throws InvalidCommandException, InvalidBenchmarkException, InvalidConfigurationException {
@Nullable String legacyCaliperEnv = System.getenv(LEGACY_ENV);
if (!Strings.isNullOrEmpty(legacyCaliperEnv)) {
System.err.println("Legacy Caliper is no more. " + LEGACY_ENV + " has no effect.");
}
try {
MainComponent mainComponent = DaggerMainComponent.builder()
.optionsModule(OptionsModule.withBenchmarkClass(args))
.outputModule(new OutputModule(stdout, stderr))
.build();
CaliperOptions options = mainComponent.getCaliperOptions();
if (options.printConfiguration()) {
stdout.println("Configuration:");
ImmutableSortedMap<String, String> sortedProperties =
ImmutableSortedMap.copyOf(mainComponent.getCaliperConfig().properties());
for (Entry<String, String> entry : sortedProperties.entrySet()) {
stdout.printf(" %s = %s%n", entry.getKey(), entry.getValue());
}
}
// check that the parameters are valid
mainComponent.getBenchmarkClass().validateParameters(options.userParameters());
ServiceManager serviceManager = mainComponent.getServiceManager();
serviceManager.startAsync().awaitHealthy();
try {
CaliperRun run = mainComponent.getCaliperRun();
run.run(); // throws IBE
} finally {
try {
// We have some shutdown logic to ensure that files are cleaned up so give it a chance to
// run
serviceManager.stopAsync().awaitStopped(10, TimeUnit.SECONDS);
} catch (TimeoutException e) {
// That's fine
}
}
} finally {
// courtesy flush
stderr.flush();
stdout.flush();
}
}
}