com.google.caliper.util.CommandLineParser.java Source code

Java tutorial

Introduction

Here is the source code for com.google.caliper.util.CommandLineParser.java

Source

/*
 * Copyright (C) 2010 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.util;

import com.google.caliper.MeasurementType;
import com.google.caliper.ReportSettings;

import com.google.caliper.exception.UserException;
import com.google.caliper.exception.UserException.DisplayUsageException;
import com.google.caliper.exception.UserException.IncompatibleArgumentsException;
import com.google.caliper.exception.UserException.InvalidParameterValueException;
import com.google.caliper.exception.UserException.MultipleBenchmarkClassesException;
import com.google.caliper.exception.UserException.NoBenchmarkClassException;
import com.google.caliper.exception.UserException.UnrecognizedOptionException;

import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import java.io.File;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * Parse command line arguments for the runner and in-process runner.
 *
 * @author somebody@google
 * @author Renat.Gilmanov
 */
public final class CommandLineParser implements ReportSettings {

    private String suiteClassName;

    /** JVMs to run in the benchmark */
    private final Set<String> userVms = Sets.newLinkedHashSet();
    /**
     * Parameter values specified by the user on the command line. Parameters with
     * no value in this multimap will get their values from the benchmark suite.
     */
    private final Multimap<String, String> userParameters = LinkedHashMultimap.create();
    /**
     * VM parameters like {memory=[-Xmx64,-Xmx128],jit=[-client,-server]}
     */
    private final Multimap<String, String> vmParameters = LinkedHashMultimap.create();
    private int trials = 1;
    private long warmupMillis = 3000;
    private long runMillis = 1000;
    private String timeUnit = null;
    private String instanceUnit = null;
    private String reportType = null;
    private String memoryUnit = null;
    private File outputFile = null;
    private File pluginFolder = null;
    private boolean captureVmLog = false;
    private boolean printScore = false;
    private boolean measureMemory = false;
    private boolean useBenchmarkName = false;
    private boolean debug = false;
    private int debugReps = defaultDebugReps;
    private MeasurementType measurementType;
    private MeasurementType primaryMeasurementType;

    /**
     * A signal that indicates a XML object interleaved with the process output.
     * Should be short, but unlikely to show up in the processes natural output.
     */
    private String marker = "//ZxJ/";

    private static final String RESULT_EXTENSION = ".result";

    private static final String defaultDelimiter = ",";
    private static final int defaultDebugReps = 1000;

    public String getSuiteClassName() {
        return suiteClassName;
    }

    public Set<String> getUserVms() {
        return userVms;
    }

    public int getTrials() {
        return trials;
    }

    public String getReportType() {
        return reportType;
    }

    public Multimap<String, String> getVmParameters() {
        return vmParameters;
    }

    public Multimap<String, String> getUserParameters() {
        return userParameters;
    }

    public long getWarmupMillis() {
        return warmupMillis;
    }

    public long getRunMillis() {
        return runMillis;
    }

    public String getTimeUnit() {
        return timeUnit;
    }

    public String getInstanceUnit() {
        return instanceUnit;
    }

    public String getMemoryUnit() {
        return memoryUnit;
    }

    @Override
    public File getOutputFile() {
        File result = outputFile;
        if (useBenchmarkName) {

            String parentPath = (outputFile.isDirectory()) ? outputFile.getPath() : outputFile.getParent();
            result = new File(parentPath + File.separator + suiteClassName + RESULT_EXTENSION);
        }
        return result;
    }

    public boolean getCaptureVmLog() {
        return captureVmLog;
    }

    public boolean printScore() {
        return printScore;
    }

    public boolean getMeasureMemory() {
        return measureMemory;
    }

    public MeasurementType getMeasurementType() {
        return measurementType;
    }

    public MeasurementType getPrimaryMeasurementType() {
        return primaryMeasurementType;
    }

    public boolean getDebug() {
        return debug;
    }

    public int getDebugReps() {
        return debugReps;
    }

    public String getMarker() {
        return marker;
    }

    public File getPluginFolder() {
        return pluginFolder;
    }

    /**
     *
     * @param argsArray
     * @return
     */
    public static CommandLineParser parse(String[] argsArray) {
        CommandLineParser result = new CommandLineParser();

        Iterator<String> args = Iterators.forArray(argsArray);
        String delimiter = defaultDelimiter;
        Map<String, String> userParameterStrings = Maps.newLinkedHashMap();
        Map<String, String> vmParameterStrings = Maps.newLinkedHashMap();
        String vmString = null;
        boolean standardRun = false;

        while (args.hasNext()) {
            String arg = args.next();

            if ("--help".equals(arg)) {
                throw new DisplayUsageException();
            }

            if (arg.startsWith("-D") || arg.startsWith("-J")) {

                /*
                 * Handle user parameters (-D) and VM parameters (-J) of these forms:
                 *
                 * -Dlength=100
                 * -Jmemory=-Xmx1024M
                 * -Dlength=100,200
                 * -Jmemory=-Xmx1024M,-Xmx2048M
                 * -Dlength 100
                 * -Jmemory -Xmx1024M
                 * -Dlength 100,200
                 * -Jmemory -Xmx1024M,-Xmx2048M
                 */

                String name;
                String value;
                int equalsSign = arg.indexOf('=');
                if (equalsSign == -1) {
                    name = arg.substring(2);
                    value = args.next();
                } else {
                    name = arg.substring(2, equalsSign);
                    value = arg.substring(equalsSign + 1);
                }

                String previousValue;
                if (arg.startsWith("-D")) {
                    previousValue = userParameterStrings.put(name, value);
                } else {
                    previousValue = vmParameterStrings.put(name, value);
                }
                if (previousValue != null) {
                    throw new UserException.DuplicateParameterException(arg);
                }
                standardRun = true;

                // TODO: move warmup/run to caliperrc
            } else if ("--captureVmLog".equals(arg)) {
                result.captureVmLog = true;
                standardRun = true;
            } else if ("--warmupMillis".equals(arg)) {
                result.warmupMillis = Long.parseLong(args.next());
                standardRun = true;
            } else if ("--runMillis".equals(arg)) {
                result.runMillis = Long.parseLong(args.next());
                standardRun = true;
            } else if ("--trials".equals(arg)) {
                String value = args.next();
                try {
                    result.trials = Integer.parseInt(value);
                    if (result.trials < 1) {
                        throw new UserException.InvalidTrialsException(value);
                    }
                } catch (NumberFormatException e) {
                    throw new UserException.InvalidTrialsException(value);
                }
                standardRun = true;
            } else if ("--vm".equals(arg)) {
                if (vmString != null) {
                    throw new UserException.DuplicateParameterException(arg);
                }
                vmString = args.next();
                standardRun = true;
            } else if ("--delimiter".equals(arg)) {
                delimiter = args.next();
                standardRun = true;
            } else if ("--useBenchmarkName".equals(arg)) {
                result.useBenchmarkName = true;
                standardRun = true;
            } else if ("--timeUnit".equals(arg)) {
                result.timeUnit = args.next();
                standardRun = true;
            } else if ("--instanceUnit".equals(arg)) {
                result.instanceUnit = args.next();
                standardRun = true;
            } else if ("--memoryUnit".equals(arg)) {
                result.memoryUnit = args.next();
                standardRun = true;
            } else if ("--reportType".equals(arg)) {
                result.reportType = args.next();
                System.out.println("Report type: " + result.reportType);
            } else if ("--pluginFolder".equals(arg)) {
                result.pluginFolder = new File(args.next());
            } else if ("--saveResults".equals(arg) || "--xmlSave".equals(arg)) {
                // TODO: unsupport legacy --xmlSave
                result.outputFile = new File(args.next());
                standardRun = true;
            } else if ("--printScore".equals(arg)) {
                result.printScore = true;
                standardRun = true;
            } else if ("--measureMemory".equals(arg)) {
                result.measureMemory = true;
                standardRun = true;
            } else if ("--debug".equals(arg)) {
                result.debug = true;
            } else if ("--debug-reps".equals(arg)) {
                String value = args.next();
                try {
                    result.debugReps = Integer.parseInt(value);
                    if (result.debugReps < 1) {
                        throw new UserException.InvalidDebugRepsException(value);
                    }
                } catch (NumberFormatException e) {
                    throw new UserException.InvalidDebugRepsException(value);
                }
            } else if ("--marker".equals(arg)) {
                result.marker = args.next();
            } else if ("--measurementType".equals(arg)) {
                String measurementType = args.next();
                try {
                    result.measurementType = MeasurementType.valueOf(measurementType);
                } catch (Exception e) {
                    throw new InvalidParameterValueException(arg, measurementType);
                }
                standardRun = true;
            } else if ("--primaryMeasurementType".equals(arg)) {
                String measurementType = args.next().toUpperCase();
                try {
                    result.primaryMeasurementType = MeasurementType.valueOf(measurementType);
                } catch (Exception e) {
                    throw new InvalidParameterValueException(arg, measurementType);
                }
                standardRun = true;
            } else if (arg.startsWith("-")) {
                throw new UnrecognizedOptionException(arg);

            } else {
                if (result.suiteClassName != null) {
                    throw new MultipleBenchmarkClassesException(result.suiteClassName, arg);
                }
                result.suiteClassName = arg;
            }
        }

        Splitter delimiterSplitter = Splitter.on(delimiter);

        if (vmString != null) {
            Iterables.addAll(result.userVms, delimiterSplitter.split(vmString));
        }

        Set<String> duplicates = Sets.intersection(userParameterStrings.keySet(), vmParameterStrings.keySet());
        if (!duplicates.isEmpty()) {
            throw new UserException.DuplicateParameterException(duplicates);
        }

        for (Map.Entry<String, String> entry : userParameterStrings.entrySet()) {
            result.userParameters.putAll(entry.getKey(), delimiterSplitter.split(entry.getValue()));
        }
        for (Map.Entry<String, String> entry : vmParameterStrings.entrySet()) {
            result.vmParameters.putAll(entry.getKey(), delimiterSplitter.split(entry.getValue()));
        }

        if (result.suiteClassName == null) {
            throw new NoBenchmarkClassException();
        }

        if (result.primaryMeasurementType != null && result.primaryMeasurementType != MeasurementType.TIME
                && !result.measureMemory) {
            throw new IncompatibleArgumentsException(
                    "--primaryMeasurementType " + result.primaryMeasurementType.toString().toLowerCase());
        }

        return result;
    }

    public static void printUsage() {
        System.out.println();
        System.out.println("Usage: Runner [OPTIONS...] <benchmark>");
        System.out.println();
        System.out.println("  <benchmark>: a benchmark class or suite");
        System.out.println();
        System.out.println("OPTIONS");
        System.out.println();
        System.out.println("  -D<param>=<value>: fix a benchmark parameter to a given value.");
        System.out.println("        Multiple values can be supplied by separating them with the");
        System.out.println("        delimiter specified in the --delimiter argument.");
        System.out.println();
        System.out.println("        For example: \"-Dfoo=bar,baz,bat\"");
        System.out.println();
        System.out.println("        \"benchmark\" is a special parameter that can be used to specify");
        System.out.println("        which benchmark methods to run. For example, if a benchmark has");
        System.out.println("        the method \"timeFoo\", it can be run alone by using");
        System.out.println("        \"-Dbenchmark=Foo\". \"benchmark\" also accepts a delimiter");
        System.out.println("        separated list of methods to run.");
        System.out.println();
        System.out.println("  -J<param>=<value>: set a JVM argument to the given value.");
        System.out.println("        Multiple values can be supplied by separating them with the");
        System.out.println("        delimiter specified in the --delimiter argument.");
        System.out.println();
        System.out.println("        For example: \"-JmemoryMax=-Xmx32M,-Xmx512M\"");
        System.out.println();
        System.out.println("  --delimiter <delimiter>: character or string to use as a delimiter");
        System.out.println("        for parameter and vm values.");
        System.out.println("        Default: \"" + defaultDelimiter + "\"");
        System.out.println();
        System.out.println("  --warmupMillis <millis>: duration to warmup each benchmark");
        System.out.println();
        System.out.println("  --runMillis <millis>: duration to execute each benchmark");
        System.out.println();
        System.out.println("  --captureVmLog: record the VM's just-in-time compiler and GC logs.");
        System.out.println("        This may slow down or break benchmark display tools.");
        System.out.println();
        System.out.println("  --measureMemory: measure the number of allocations done and the amount of");
        System.out.println("        memory used by invocations of the benchmark.");
        System.out.println("        Default: off");
        System.out.println();
        System.out.println("  --vm <vm>: executable to test benchmark on. Multiple VMs may be passed");
        System.out.println("        in as a list separated by the delimiter specified in the");
        System.out.println("        --delimiter argument.");
        System.out.println();
        System.out.println("  --timeUnit <unit>: unit of time to use for result. Depends on the units");
        System.out.println("        defined in the benchmark's timeUnitNames method, if defined.");
        System.out.println("        Default Options: ns, us, ms, s");
        System.out.println();
        System.out.println("  --instanceUnit <unit>: unit to use for allocation instances result.");
        System.out.println("        Depends on the units defined in the benchmark's instanceUnitNames");
        System.out.println("        method, if defined.");
        System.out.println("        Default Options: instances, K instances, M instances, B instances");
        System.out.println();
        System.out.println("  --memoryUnit <unit>: unit to use for allocation memory size result.");
        System.out.println("        Depends on the units defined in the benchmark's memoryUnitNames");
        System.out.println("        method, if defined.");
        System.out.println("        Default Options: B, KB, MB, GB");
        System.out.println();
        System.out.println("  --saveResults <file/dir>: write results to this file or directory");
        System.out.println();
        System.out.println("  --printScore: if present, also display an aggregate score for this run,");
        System.out.println("        where higher is better. This number has no particular meaning,");
        System.out.println("        but can be compared to scores from other runs that use the exact");
        System.out.println("        same arguments.");
        System.out.println();
        System.out.println("  --debug: run without measurement for use with debugger or profiling.");
        System.out.println();
        System.out.println("  --debug-reps: fixed number of reps to run with --debug.");
        System.out.println("        Default: \"" + defaultDebugReps + "\"");

        // adding new options? don't forget to update executeForked()
    }
}