changeset 144:ad7c8952983b

Split out Options interface.
author shade
date Mon, 26 Aug 2013 18:45:19 +0400
parents 17b018e40f33
children 917ec73e859d
files jmh-api-samples/src/main/java/org/openjdk/jmh/MyAPIBench.java jmh-api-samples/src/main/java/org/openjdk/jmh/SimpleTest.java jmh-core/src/main/java/org/openjdk/jmh/runner/BaseMicroBenchmarkHandler.java jmh-core/src/main/java/org/openjdk/jmh/runner/BaseRunner.java jmh-core/src/main/java/org/openjdk/jmh/runner/ForkedRunner.java jmh-core/src/main/java/org/openjdk/jmh/runner/LoopMicroBenchmarkHandler.java jmh-core/src/main/java/org/openjdk/jmh/runner/MicroBenchmarkHandlers.java jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java jmh-core/src/main/java/org/openjdk/jmh/runner/options/BaseOptions.java jmh-core/src/main/java/org/openjdk/jmh/runner/options/DefaultBuilder.java jmh-core/src/main/java/org/openjdk/jmh/runner/options/ForkedOptions.java jmh-core/src/main/java/org/openjdk/jmh/runner/options/HarnessOptions.java jmh-core/src/main/java/org/openjdk/jmh/runner/options/Options.java jmh-core/src/main/java/org/openjdk/jmh/runner/options/OptionsBuilder.java jmh-core/src/main/java/org/openjdk/jmh/runner/options/WarmupMode.java jmh-core/src/main/java/org/openjdk/jmh/runner/parameters/MicroBenchmarkParametersFactory.java jmh-core/src/main/java/org/openjdk/jmh/util/Utils.java
diffstat 17 files changed, 1099 insertions(+), 145 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-api-samples/src/main/java/org/openjdk/jmh/MyAPIBench.java	Mon Aug 26 18:45:19 2013 +0400
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh;
+
+import org.openjdk.jmh.annotations.GenerateMicroBenchmark;
+
+public class MyAPIBench {
+
+    @GenerateMicroBenchmark
+    public void myTest() {
+
+    }
+
+}
--- a/jmh-api-samples/src/main/java/org/openjdk/jmh/SimpleTest.java	Fri Aug 23 18:00:09 2013 +0400
+++ b/jmh-api-samples/src/main/java/org/openjdk/jmh/SimpleTest.java	Mon Aug 26 18:45:19 2013 +0400
@@ -26,12 +26,13 @@
 
 import org.openjdk.jmh.runner.Runner;
 import org.openjdk.jmh.runner.RunnerException;
-import org.openjdk.jmh.runner.options.HarnessOptions;
+import org.openjdk.jmh.runner.options.DefaultBuilder;
+import org.openjdk.jmh.runner.options.Options;
 
 public class SimpleTest {
 
     public static void main(String[] args) throws RunnerException {
-        HarnessOptions options = HarnessOptions.newInstance();
-        new Runner(options).run();
+        Options opts = DefaultBuilder.start().addBenchmark(".*").shouldBeVerbose(true).end();
+        new Runner(opts).run();
     }
 }
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/BaseMicroBenchmarkHandler.java	Fri Aug 23 18:00:09 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/BaseMicroBenchmarkHandler.java	Mon Aug 26 18:45:19 2013 +0400
@@ -28,7 +28,7 @@
 import org.openjdk.jmh.output.format.OutputFormat;
 import org.openjdk.jmh.profile.Profiler;
 import org.openjdk.jmh.profile.ProfilerFactory;
-import org.openjdk.jmh.runner.options.BaseOptions;
+import org.openjdk.jmh.runner.options.Options;
 import org.openjdk.jmh.runner.parameters.MicroBenchmarkParameters;
 
 import java.lang.reflect.Constructor;
@@ -64,7 +64,7 @@
 
     private final List<Profiler> registeredProfilers;
 
-    public BaseMicroBenchmarkHandler(OutputFormat format, BenchmarkRecord microbenchmark, final Class<?> clazz, BaseOptions options, MicroBenchmarkParameters executionParams) {
+    public BaseMicroBenchmarkHandler(OutputFormat format, BenchmarkRecord microbenchmark, final Class<?> clazz, Options options, MicroBenchmarkParameters executionParams) {
         this.microbenchmark = microbenchmark;
         this.registeredProfilers = createProfilers(options);
         this.executor = EXECUTOR_TYPE.createExecutor(executionParams.getThreads(), microbenchmark.getUsername());
@@ -78,7 +78,7 @@
         this.timeUnit = options.getTimeUnit();
     }
 
-    private static List<Profiler> createProfilers(BaseOptions options) {
+    private static List<Profiler> createProfilers(Options options) {
         List<Profiler> list = new ArrayList<Profiler>();
         // register the profilers
         for (ProfilerFactory.Profilers prof : options.getProfilers()) {
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/BaseRunner.java	Fri Aug 23 18:00:09 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/BaseRunner.java	Mon Aug 26 18:45:19 2013 +0400
@@ -29,7 +29,7 @@
 import org.openjdk.jmh.logic.results.internal.RunResult;
 import org.openjdk.jmh.output.format.IterationType;
 import org.openjdk.jmh.output.format.OutputFormat;
-import org.openjdk.jmh.runner.options.BaseOptions;
+import org.openjdk.jmh.runner.options.Options;
 import org.openjdk.jmh.runner.parameters.IterationParams;
 import org.openjdk.jmh.runner.parameters.MicroBenchmarkParameters;
 import org.openjdk.jmh.runner.parameters.MicroBenchmarkParametersFactory;
@@ -51,11 +51,11 @@
 public abstract class BaseRunner {
 
     /** Class holding all our runtime options/arguments */
-    private final BaseOptions options;
+    private final Options options;
 
     protected final OutputFormat out;
 
-    public BaseRunner(BaseOptions options, OutputFormat handler) {
+    public BaseRunner(Options options, OutputFormat handler) {
         this.options = options;
         this.out = handler;
     }
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/ForkedRunner.java	Fri Aug 23 18:00:09 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/ForkedRunner.java	Mon Aug 26 18:45:19 2013 +0400
@@ -26,6 +26,7 @@
 
 import org.openjdk.jmh.output.OutputFormatFactory;
 import org.openjdk.jmh.runner.options.ForkedOptions;
+import org.openjdk.jmh.runner.options.Options;
 
 /**
  * Runner frontend class. Responsible for running micro benchmarks in forked JVM.
@@ -34,9 +35,9 @@
  */
 public class ForkedRunner extends BaseRunner {
 
-    private final ForkedOptions options;
+    private final Options options;
 
-    public ForkedRunner(ForkedOptions options) {
+    public ForkedRunner(Options options) {
         super(options, OutputFormatFactory.createBinaryHook(options.getHostName(), options.getHostPort()));
         this.options = options;
     }
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/LoopMicroBenchmarkHandler.java	Fri Aug 23 18:00:09 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/LoopMicroBenchmarkHandler.java	Mon Aug 26 18:45:19 2013 +0400
@@ -30,7 +30,7 @@
 import org.openjdk.jmh.logic.results.IterationData;
 import org.openjdk.jmh.logic.results.Result;
 import org.openjdk.jmh.output.format.OutputFormat;
-import org.openjdk.jmh.runner.options.BaseOptions;
+import org.openjdk.jmh.runner.options.Options;
 import org.openjdk.jmh.runner.parameters.MicroBenchmarkParameters;
 import org.openjdk.jmh.runner.parameters.TimeValue;
 
@@ -60,7 +60,7 @@
     private final boolean shouldSynchIterations;
     private final boolean shouldFailOnError;
 
-    LoopMicroBenchmarkHandler(OutputFormat format, BenchmarkRecord microbenchmark, Class<?> clazz, Method method, BaseOptions options, MicroBenchmarkParameters executionParams) {
+    LoopMicroBenchmarkHandler(OutputFormat format, BenchmarkRecord microbenchmark, Class<?> clazz, Method method, Options options, MicroBenchmarkParameters executionParams) {
         super(format, microbenchmark, clazz, options, executionParams);
         this.method = method;
         this.shouldSynchIterations = (microbenchmark.getMode() != Mode.SingleShotTime) && executionParams.shouldSynchIterations();
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/MicroBenchmarkHandlers.java	Fri Aug 23 18:00:09 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/MicroBenchmarkHandlers.java	Mon Aug 26 18:45:19 2013 +0400
@@ -27,7 +27,7 @@
 import org.openjdk.jmh.logic.InfraControl;
 import org.openjdk.jmh.logic.results.Result;
 import org.openjdk.jmh.output.format.OutputFormat;
-import org.openjdk.jmh.runner.options.BaseOptions;
+import org.openjdk.jmh.runner.options.Options;
 import org.openjdk.jmh.runner.parameters.MicroBenchmarkParameters;
 import org.openjdk.jmh.util.ClassUtils;
 
@@ -67,7 +67,7 @@
         return method;
     }
 
-    public static MicroBenchmarkHandler getInstance(OutputFormat out, BenchmarkRecord microbenchmark, Class<?> clazz, Method method, MicroBenchmarkParameters executionParams, BaseOptions options) {
+    public static MicroBenchmarkHandler getInstance(OutputFormat out, BenchmarkRecord microbenchmark, Class<?> clazz, Method method, MicroBenchmarkParameters executionParams, Options options) {
         return new LoopMicroBenchmarkHandler(out, microbenchmark, clazz, method, options, executionParams);
     }
 
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java	Fri Aug 23 18:00:09 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java	Mon Aug 26 18:45:19 2013 +0400
@@ -24,13 +24,14 @@
  */
 package org.openjdk.jmh.runner;
 
+import org.openjdk.jmh.ForkedMain;
 import org.openjdk.jmh.annotations.Fork;
 import org.openjdk.jmh.annotations.Mode;
-import org.openjdk.jmh.logic.results.internal.RunResult;
 import org.openjdk.jmh.output.OutputFormatFactory;
 import org.openjdk.jmh.output.format.OutputFormat;
 import org.openjdk.jmh.output.format.internal.BinaryOutputFormatReader;
-import org.openjdk.jmh.runner.options.HarnessOptions;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.WarmupMode;
 import org.openjdk.jmh.runner.parameters.Defaults;
 import org.openjdk.jmh.util.AnnotationUtils;
 import org.openjdk.jmh.util.InputStreamDrainer;
@@ -42,11 +43,14 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintStream;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Properties;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.logging.Level;
@@ -62,18 +66,18 @@
 public class Runner extends BaseRunner {
 
     /** Class holding all our runtime options/arguments */
-    private final HarnessOptions options;
+    private final Options options;
 
     private final MicroBenchmarkList list;
 
-    public Runner(HarnessOptions options) {
+    public Runner(Options options) {
         super(options, createOutputFormat(options));
         this.list = MicroBenchmarkList.defaultList();
         this.options = options;
     }
 
     /** Setup helper method, creates OutputFormat according to argv options. */
-    private static OutputFormat createOutputFormat(HarnessOptions options) {
+    private static OutputFormat createOutputFormat(Options options) {
         PrintStream out;
         // setup OutputFormat singleton
         if (options.getOutput() == null) {
@@ -145,7 +149,7 @@
         // exit if list only, else run benchmarks
         if (!options.shouldList()) {
             if ((!options.getWarmupMicros().isEmpty()) ||
-                    (options.getWarmupMode() == HarnessOptions.WarmupMode.BEFOREANY)) {
+                    (options.getWarmupMode() == WarmupMode.BEFOREANY)) {
                 runBulkWarmupBenchmarks(benchmarks);
             } else {
                 runBenchmarks(benchmarks);
@@ -170,7 +174,7 @@
         if (warmupMicrosRegexp != null && !warmupMicrosRegexp.isEmpty()) {
             warmupMicros.addAll(list.find(out, warmupMicrosRegexp, Collections.<String>emptyList()));
         }
-        if (options.getWarmupMode() == HarnessOptions.WarmupMode.BEFOREANY) {
+        if (options.getWarmupMode() == WarmupMode.BEFOREANY) {
             warmupMicros.addAll(benchmarks);
         }
 
@@ -292,7 +296,7 @@
             annJvmArgsPrepend = forkAnnotation.jvmArgsPrepend().trim();
         }
 
-        String[] commandString = options.getSeparateExecutionCommand(benchmark, annJvmArgs, annJvmArgsPrepend, annJvmArgsAppend, host, port);
+        String[] commandString = getSeparateExecutionCommand(benchmark, annJvmArgs, annJvmArgsPrepend, annJvmArgsAppend, host, port);
 
         int forkCount = decideForks(options.getForkCount(), benchForks(benchmark));
         int warmupForkCount = decideWarmupForks(options.getWarmupForkCount(), forkAnnotation);
@@ -345,4 +349,104 @@
         }
     }
 
+    /**
+     * Helper method for assembling the command to execute the forked JVM with
+     *
+     * @param benchmark benchmark to execute
+     * @param host host VM host
+     * @param port host VM port
+     * @return the final command to execute
+     */
+    public String[] getSeparateExecutionCommand(BenchmarkRecord benchmark, String annJvmArgs, String annJvmArgsPrepend, String annJvmArgsAppend, String host, int port) {
+
+        Properties props = System.getProperties();
+        String javaHome = (String) props.get("java.home");
+        String separator = File.separator;
+        String osName = props.getProperty("os.name");
+        boolean isOnWindows = osName.contains("indows");
+        String platformSpecificBinaryPostfix = isOnWindows ? ".exe" : "";
+
+        String classPath;
+
+        if (options.getJvmClassPath() != null) {
+            classPath = options.getJvmClassPath();
+        } else {
+            classPath = (String) props.get("java.class.path");
+        }
+
+        if (isOnWindows) {
+            classPath = '"' + classPath + '"';
+        }
+
+        List<String> command = new ArrayList<String>();
+
+        // use supplied jvm if given
+        if (options.getJvm() != null) {
+            command.add(options.getJvm());
+        } else {
+            // else find out which one parent is and use that
+            StringBuilder javaExecutable = new StringBuilder();
+            javaExecutable.append(javaHome);
+            javaExecutable.append(separator);
+            javaExecutable.append("bin");
+            javaExecutable.append(separator);
+            javaExecutable.append("java");
+            javaExecutable.append(platformSpecificBinaryPostfix);
+            command.add(javaExecutable.toString());
+        }
+
+        if (options.getJvmArgs() != null) { // use supplied jvm args if given in cmd line
+            command.addAll(Arrays.asList(options.getJvmArgs().split("[ ]+")));
+        } else if (annJvmArgs != null) { // use jvm args supplied in annotation which shuns implicit args
+            command.addAll(Arrays.asList(annJvmArgs.split("[ ]+")));
+        } else {
+            // else use same jvm args given to this runner
+            RuntimeMXBean RuntimemxBean = ManagementFactory.getRuntimeMXBean();
+            List<String> args = RuntimemxBean.getInputArguments();
+
+            // prepend jvm args
+            if (annJvmArgsPrepend != null) {
+                command.addAll(Arrays.asList(annJvmArgsPrepend.split(" ")));
+            }
+
+            for (String arg : args) {
+                command.add(arg);
+            }
+
+            // append jvm args
+            if (annJvmArgsAppend != null) {
+                command.addAll(Arrays.asList(annJvmArgsAppend.split(" ")));
+            }
+        }
+
+        // add any compiler oracle hints
+        {
+            Set<String> hints = CompilerHints.defaultList().get();
+            if (!hints.isEmpty()) {
+                command.add("-XX:CompileCommand=quiet ");
+            }
+            for (String l : hints) {
+                command.add("-XX:CompileCommand=" + l);
+            }
+        }
+
+        // assemble final process command
+        command.add("-cp");
+        command.add(classPath);
+        command.add(ForkedMain.class.getName());
+
+        // if user supplied micro flags, give those as well
+        Collections.addAll(command, options.toCommandLine());
+
+        command.add(benchmark.toLine());
+
+        command.add("--hostName");
+        command.add(host);
+        command.add("--hostPort");
+        command.add(String.valueOf(port));
+
+        return command.toArray(new String[command.size()]);
+    }
+
+
 }
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/options/BaseOptions.java	Fri Aug 23 18:00:09 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/options/BaseOptions.java	Mon Aug 26 18:45:19 2013 +0400
@@ -56,7 +56,7 @@
  *
  * @author sergey.kuksenko@oracle.com
  */
-public class BaseOptions {
+public abstract class BaseOptions implements Options {
 
 
     /*
@@ -315,6 +315,7 @@
      *
      * @return the value
      */
+    @Override
     public int getIterations() {
         return iterations;
     }
@@ -324,6 +325,7 @@
      *
      * @return the value
      */
+    @Override
     public TimeValue getRuntime() {
         return runTime;
     }
@@ -333,6 +335,7 @@
      *
      * @return the value
      */
+    @Override
     public TimeValue getWarmupTime() {
         return warmupTime;
     }
@@ -342,6 +345,7 @@
      *
      * @return the value
      */
+    @Override
     public int getWarmupIterations() {
         return warmupIterations;
     }
@@ -351,6 +355,7 @@
      *
      * @return the value
      */
+    @Override
     public int getThreads() {
         return threads;
     }
@@ -360,6 +365,7 @@
      *
      * @return the value
      */
+    @Override
     public boolean shouldDoGC() {
         return gcEachIteration;
     }
@@ -369,6 +375,7 @@
      *
      * @return the value
      */
+    @Override
     public Boolean getSynchIterations() {
         return synchIterations;
     }
@@ -378,6 +385,7 @@
      *
      * @return the value
      */
+    @Override
     public boolean isVerbose() {
         return verbose;
     }
@@ -387,6 +395,7 @@
      *
      * @return the value
      */
+    @Override
     public TimeUnit getTimeUnit() {
         return timeUnit;
     }
@@ -396,6 +405,7 @@
      *
      * @return the value
      */
+    @Override
     public boolean shouldOutputDetailedResults() {
         return outputDetailedResults;
     }
@@ -404,6 +414,7 @@
      * Should fail the harness on test error?
      * @return the value
      */
+    @Override
     public boolean shouldFailOnError() {
         return failOnError;
     }
@@ -412,10 +423,12 @@
      * Getter
      * @return the value
      */
+    @Override
     public Set<ProfilerFactory.Profilers> getProfilers() {
         return profilers;
     }
 
+    @Override
     public Collection<Mode> getBenchModes() {
         return benchMode;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/options/DefaultBuilder.java	Mon Aug 26 18:45:19 2013 +0400
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.runner.options;
+
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.output.OutputFormatType;
+import org.openjdk.jmh.profile.ProfilerFactory;
+import org.openjdk.jmh.runner.parameters.TimeValue;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+public class DefaultBuilder implements Options, OptionsBuilder {
+
+    public static OptionsBuilder start() {
+        return new DefaultBuilder();
+    }
+
+    private boolean finalized;
+
+    private void checkFinalized() {
+        if (finalized) {
+            throw new IllegalStateException("The builder is already finalized");
+        }
+    }
+
+    @Override
+    public Options end() {
+        finalized = true;
+        return this;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private final List<String> regexps = new ArrayList<String>();
+
+    @Override
+    public OptionsBuilder addBenchmark(String regexp) {
+        checkFinalized();
+        regexps.add(regexp);
+        return this;
+    }
+
+    @Override
+    public List<String> getRegexps() {
+        return regexps;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private final List<String> excludes = new ArrayList<String>();
+
+    @Override
+    public OptionsBuilder addExclude(String regexp) {
+        excludes.add(regexp);
+        return this;
+    }
+
+    @Override
+    public List<String> getExcludes() {
+        return excludes;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private OutputFormatType ofType = OutputFormatType.Pretty;
+
+    @Override
+    public OptionsBuilder outputFormat(OutputFormatType type) {
+        ofType = type;
+        return this;
+    }
+
+    @Override
+    public OutputFormatType getOutputFormat() {
+        return ofType;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private String output;
+
+    @Override
+    public OptionsBuilder setOutput(String filename) {
+        this.output = filename;
+        return this;
+    }
+
+    @Override
+    public String getOutput() {
+        return output;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private boolean shouldDoGC;
+
+    @Override
+    public OptionsBuilder shouldDoGC(boolean value) {
+        shouldDoGC = value;
+        return this;
+    }
+
+    @Override
+    public boolean shouldDoGC() {
+        return shouldDoGC;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private boolean shouldList;
+
+    @Override
+    public OptionsBuilder shouldList(boolean value) {
+        shouldList = value;
+        return this;
+    }
+
+    @Override
+    public boolean shouldList() {
+        return shouldList;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private EnumSet<ProfilerFactory.Profilers> profilers = EnumSet.noneOf(ProfilerFactory.Profilers.class);
+
+    @Override
+    public OptionsBuilder addProfiler(ProfilerFactory.Profilers prof) {
+        this.profilers.add(prof);
+        return this;
+    }
+
+    @Override
+    public Set<ProfilerFactory.Profilers> getProfilers() {
+        return profilers;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private boolean isVerbose;
+
+    @Override
+    public OptionsBuilder shouldBeVerbose(boolean value) {
+        isVerbose = value;
+        return this;
+    }
+
+    @Override
+    public boolean isVerbose() {
+        return isVerbose;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private boolean shouldFailOnError;
+
+    @Override
+    public OptionsBuilder shouldFailOnError(boolean value) {
+        shouldFailOnError = value;
+        return this;
+    }
+
+    @Override
+    public boolean shouldFailOnError() {
+        return shouldFailOnError;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private boolean shouldOutputDetails;
+
+    @Override
+    public OptionsBuilder shouldOutputDetails(boolean value) {
+        shouldOutputDetails = value;
+        return this;
+    }
+
+    @Override
+    public boolean shouldOutputDetailedResults() {
+        return shouldOutputDetails;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private int threads = -1;
+
+    @Override
+    public OptionsBuilder threads(int count) {
+        this.threads = count;
+        return this;
+    }
+
+    @Override
+    public int getThreads() {
+        return threads;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private Boolean syncIterations;
+
+    @Override
+    public OptionsBuilder shouldSyncIterations(boolean value) {
+        this.syncIterations = value;
+        return this;
+    }
+
+    @Override
+    public Boolean getSynchIterations() {
+        return syncIterations;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private int warmupIterations = -1;
+
+    @Override
+    public OptionsBuilder warmupIterations(int value) {
+        this.warmupIterations = value;
+        return this;
+    }
+
+    @Override
+    public int getWarmupIterations() {
+        return warmupIterations;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private TimeValue warmupTime;
+
+    @Override
+    public OptionsBuilder warmupTime(TimeValue value) {
+        this.warmupTime = value;
+        return this;
+    }
+
+    @Override
+    public TimeValue getWarmupTime() {
+        return warmupTime;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private WarmupMode warmupMode = WarmupMode.BEFOREEACH;
+
+    @Override
+    public OptionsBuilder warmupMode(WarmupMode mode) {
+        this.warmupMode = mode;
+        return this;
+    }
+
+    @Override
+    public WarmupMode getWarmupMode() {
+        return warmupMode;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private final List<String> warmupMicros = new ArrayList<String>();
+
+    @Override
+    public OptionsBuilder addWarmupMicro(String regexp) {
+        warmupMicros.add(regexp);
+        return this;
+    }
+
+    @Override
+    public List<String> getWarmupMicros() {
+        return warmupMicros;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private int iterations = -1;
+
+    @Override
+    public OptionsBuilder iterations(int count) {
+        this.iterations = count;
+        return this;
+    }
+
+    @Override
+    public int getIterations() {
+        return iterations;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private TimeValue measurementTime;
+
+    @Override
+    public OptionsBuilder measurementTime(TimeValue value) {
+        this.measurementTime = value;
+        return this;
+    }
+
+    @Override
+    public TimeValue getRuntime() {
+        return measurementTime;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private EnumSet<Mode> benchModes;
+
+    @Override
+    public OptionsBuilder addMode(Mode mode) {
+        if (benchModes == null) {
+            benchModes = EnumSet.noneOf(Mode.class);
+        }
+        benchModes.add(mode);
+        return this;
+    }
+
+    @Override
+    public Collection<Mode> getBenchModes() {
+        return benchModes;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private TimeUnit timeUnit;
+
+    @Override
+    public OptionsBuilder setTimeUnit(TimeUnit tu) {
+        this.timeUnit = tu;
+        return this;
+    }
+
+    @Override
+    public TimeUnit getTimeUnit() {
+        return timeUnit;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private int forks = -1;
+
+    @Override
+    public OptionsBuilder forks(int value) {
+        this.forks = value;
+        return this;
+    }
+
+    @Override
+    public int getForkCount() {
+        return forks;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private int warmupForks = -1;
+
+    @Override
+    public OptionsBuilder warmupForks(int value) {
+        this.warmupForks = value;
+        return this;
+    }
+
+    @Override
+    public int getWarmupForkCount() {
+        return warmupForks;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private String jvmClassPath;
+
+    @Override
+    public OptionsBuilder classpath(String value) {
+        this.jvmClassPath = value;
+        return this;
+    }
+
+    @Override
+    public String getJvmClassPath() {
+        return jvmClassPath;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private String jvmBinary;
+
+    @Override
+    public OptionsBuilder jvmBinary(String path) {
+        this.jvmBinary = path;
+        return this;
+    }
+
+    @Override
+    public String getJvm() {
+        return jvmBinary;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    private String jvmArgs;
+
+    @Override
+    public OptionsBuilder jvmArgs(String value) {
+        this.jvmArgs = value;
+        return this;
+    }
+
+    @Override
+    public String getJvmArgs() {
+        return jvmArgs;
+    }
+
+    // ---------------------------------------------------------------------------
+
+    @Override
+    public String[] toCommandLine() {
+        // FIXME: Need to convert to proper representation
+        List<String> results = new ArrayList<String>();
+
+        return results.toArray(new String[results.size()]);
+    }
+
+    // ---------------------------------------------------------------------------
+
+    @Override
+    public String getHostName() {
+        throw new UnsupportedOperationException();
+    }
+
+    // ---------------------------------------------------------------------------
+
+    @Override
+    public int getHostPort() {
+        throw new UnsupportedOperationException();
+    }
+
+    // ---------------------------------------------------------------------------
+
+    @Override
+    public String getBenchmark() {
+        throw new UnsupportedOperationException();
+    }
+}
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/options/ForkedOptions.java	Fri Aug 23 18:00:09 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/options/ForkedOptions.java	Mon Aug 26 18:45:19 2013 +0400
@@ -28,6 +28,9 @@
 import org.kohsuke.args4j.CmdLineException;
 import org.kohsuke.args4j.CmdLineParser;
 import org.kohsuke.args4j.Option;
+import org.openjdk.jmh.output.OutputFormatType;
+
+import java.util.List;
 
 /**
  * Class that handles options and arguments for forked JVM
@@ -70,15 +73,79 @@
         parser.parseArgument(argv);
     }
 
+    @Override
     public String getBenchmark() {
         return benchmark;
     }
 
+    @Override
     public int getHostPort() {
         return hostPort;
     }
 
+    @Override
     public String getHostName() {
         return hostName;
     }
+
+    @Override
+    public String getOutput() {
+        throw new UnsupportedOperationException("Asking for harness option");
+    }
+
+    @Override
+    public OutputFormatType getOutputFormat() {
+        throw new UnsupportedOperationException("Asking for harness option");
+    }
+
+    @Override
+    public List<String> getRegexps() {
+        throw new UnsupportedOperationException("Asking for harness option");
+    }
+
+    @Override
+    public List<String> getExcludes() {
+        throw new UnsupportedOperationException("Asking for harness option");
+    }
+
+    @Override
+    public boolean shouldList() {
+        throw new UnsupportedOperationException("Asking for harness option");
+    }
+
+    @Override
+    public List<String> getWarmupMicros() {
+        throw new UnsupportedOperationException("Asking for harness option");
+    }
+
+    @Override
+    public WarmupMode getWarmupMode() {
+        throw new UnsupportedOperationException("Asking for harness option");
+    }
+
+    @Override
+    public int getForkCount() {
+        throw new UnsupportedOperationException("Asking for harness option");
+    }
+
+    @Override
+    public int getWarmupForkCount() {
+        throw new UnsupportedOperationException("Asking for harness option");
+    }
+
+    @Override
+    public String getJvmClassPath() {
+        throw new UnsupportedOperationException("Asking for harness option");
+    }
+
+    @Override
+    public String getJvm() {
+        throw new UnsupportedOperationException("Asking for harness option");
+    }
+
+    @Override
+    public String getJvmArgs() {
+        throw new UnsupportedOperationException("Asking for harness option");
+    }
+
 }
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/options/HarnessOptions.java	Fri Aug 23 18:00:09 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/options/HarnessOptions.java	Mon Aug 26 18:45:19 2013 +0400
@@ -28,21 +28,12 @@
 import org.kohsuke.args4j.CmdLineException;
 import org.kohsuke.args4j.CmdLineParser;
 import org.kohsuke.args4j.Option;
-import org.openjdk.jmh.ForkedMain;
 import org.openjdk.jmh.output.OutputFormatType;
-import org.openjdk.jmh.runner.BenchmarkRecord;
-import org.openjdk.jmh.runner.CompilerHints;
 import org.openjdk.jmh.runner.options.handlers.ForkOptionHandler;
 
-import java.io.File;
-import java.lang.management.ManagementFactory;
-import java.lang.management.RuntimeMXBean;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Properties;
-import java.util.Set;
 
 /**
  * Class that handles all the options and arguments specific to the harness JVM.
@@ -105,13 +96,6 @@
     protected boolean listProfilers = false;
 
     /**
-     * Warmup Mode enum
-     */
-    public enum WarmupMode {
-        BEFOREANY, BEFOREEACH
-    }
-
-    /**
      * Kawaguchi's parser
      */
     private CmdLineParser parser;
@@ -146,110 +130,11 @@
     }
 
     /**
-     * Helper method for assembling the command to execute the forked JVM with
-     *
-     * @param benchmark benchmark to execute
-     * @param host host VM host
-     * @param port host VM port
-     * @return the final command to execute
-     */
-    public String[] getSeparateExecutionCommand(BenchmarkRecord benchmark, String annJvmArgs, String annJvmArgsPrepend, String annJvmArgsAppend, String host, int port) {
-
-        Properties props = System.getProperties();
-        String javaHome = (String) props.get("java.home");
-        String separator = File.separator;
-        String osName = props.getProperty("os.name");
-        boolean isOnWindows = osName.contains("indows");
-        String platformSpecificBinaryPostfix = isOnWindows ? ".exe" : "";
-
-        String classPath;
-
-        if (getJvmClassPath() != null) {
-            classPath = getJvmClassPath();
-        } else {
-            classPath = (String) props.get("java.class.path");
-        }
-
-        if (isOnWindows) {
-            classPath = '"' + classPath + '"';
-        }
-
-        List<String> command = new ArrayList<String>();
-
-        // use supplied jvm if given
-        if (getJvm() != null) {
-            command.add(getJvm());
-        } else {
-            // else find out which one parent is and use that
-            StringBuilder javaExecutable = new StringBuilder();
-            javaExecutable.append(javaHome);
-            javaExecutable.append(separator);
-            javaExecutable.append("bin");
-            javaExecutable.append(separator);
-            javaExecutable.append("java");
-            javaExecutable.append(platformSpecificBinaryPostfix);
-            command.add(javaExecutable.toString());
-        }
-
-        if (getJvmArgs() != null) { // use supplied jvm args if given in cmd line
-            command.addAll(Arrays.asList(getJvmArgs().split("[ ]+")));
-        } else if (annJvmArgs != null) { // use jvm args supplied in annotation which shuns implicit args
-            command.addAll(Arrays.asList(annJvmArgs.split("[ ]+")));
-        } else {
-            // else use same jvm args given to this runner
-            RuntimeMXBean RuntimemxBean = ManagementFactory.getRuntimeMXBean();
-            List<String> args = RuntimemxBean.getInputArguments();
-
-            // prepend jvm args
-            if (annJvmArgsPrepend != null) {
-                command.addAll(Arrays.asList(annJvmArgsPrepend.split(" ")));
-            }
-
-            for (String arg : args) {
-                command.add(arg);
-            }
-
-            // append jvm args
-            if (annJvmArgsAppend != null) {
-                command.addAll(Arrays.asList(annJvmArgsAppend.split(" ")));
-            }
-        }
-
-        // add any compiler oracle hints
-        {
-            Set<String> hints = CompilerHints.defaultList().get();
-            if (!hints.isEmpty()) {
-                command.add("-XX:CompileCommand=quiet ");
-            }
-            for (String l : hints) {
-                command.add("-XX:CompileCommand=" + l);
-            }
-        }
-
-        // assemble final process command
-        command.add("-cp");
-        command.add(classPath);
-        command.add(ForkedMain.class.getName());
-
-        // if user supplied micro flags, give those as well
-        Collections.addAll(command, toCommandLine());
-
-        command.add(benchmark.toLine());
-
-        command.add("--hostName");
-        command.add(host);
-        command.add("--hostPort");
-        command.add(String.valueOf(port));
-
-        return command.toArray(new String[command.size()]);
-    }
-
-
-    /**
      * Getter
      *
      * @return the value
      */
+    @Override
     public WarmupMode getWarmupMode() {
         return warmupMode;
     }
@@ -259,6 +144,7 @@
      *
      * @return the value
      */
+    @Override
     public List<String> getRegexps() {
         if (!regexps.isEmpty()) {
             return regexps;
@@ -273,6 +159,7 @@
      *
      * @return the value
      */
+    @Override
     public List<String> getExcludes() {
         return excludes;
     }
@@ -282,6 +169,7 @@
      *
      * @return the value
      */
+    @Override
     public List<String> getWarmupMicros() {
         if (warmupMicros == null) {
             return Collections.emptyList();
@@ -295,6 +183,7 @@
      *
      * @return the value
      */
+    @Override
     public boolean shouldList() {
         return list;
     }
@@ -304,6 +193,7 @@
      *
      * @return the value
      */
+    @Override
     public String getJvm() {
         return jvm;
     }
@@ -313,6 +203,7 @@
      *
      * @return the value
      */
+    @Override
     public String getJvmArgs() {
         return jvmArgs;
     }
@@ -322,6 +213,7 @@
      *
      * @return the value
      */
+    @Override
     public String getJvmClassPath() {
         return jvmClassPath;
     }
@@ -331,6 +223,7 @@
      *
      * @return the value
      */
+    @Override
     public int getForkCount() {
         return fork;
     }
@@ -340,6 +233,7 @@
      *
      * @return the value
      */
+    @Override
     public int getWarmupForkCount() {
         return warmupFork;
     }
@@ -349,6 +243,7 @@
      *
      * @return the value
      */
+    @Override
     public String getOutput() {
         return output;
     }
@@ -358,6 +253,7 @@
      *
      * @return the value
      */
+    @Override
     public OutputFormatType getOutputFormat() {
         return outputFormat;
     }
@@ -390,4 +286,19 @@
         return listProfilers;
     }
 
+    @Override
+    public String getHostName() {
+        throw new UnsupportedOperationException("Asking for forked VM options");
+    }
+
+    @Override
+    public int getHostPort() {
+        throw new UnsupportedOperationException("Asking for forked VM options");
+    }
+
+    @Override
+    public String getBenchmark() {
+        throw new UnsupportedOperationException("Asking for forked VM options");
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/options/Options.java	Mon Aug 26 18:45:19 2013 +0400
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.runner.options;
+
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.output.OutputFormatType;
+import org.openjdk.jmh.profile.ProfilerFactory;
+import org.openjdk.jmh.runner.parameters.TimeValue;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+public interface Options {
+
+    /**
+     * Which benchmarks to execute?
+     * @return list of regexps matching the requested benchmarks
+     */
+    List<String> getRegexps();
+
+    /**
+     * Which benchmarks to omit?
+     * @return list of regexps matching the ignored benchmarks
+     */
+    List<String> getExcludes();
+
+    /**
+     * Output format to use
+     * TODO: Rework for null => default
+     * @return format type
+     */
+    OutputFormatType getOutputFormat();
+
+    /**
+     * Which file to use for dumping the output
+     * @return file name; null if not defined
+     */
+    String getOutput();
+
+    /**
+     * Should force GC between iterations?
+     * @return should GC?
+     */
+    boolean shouldDoGC();
+
+    /**
+     * Should list benchmarks?
+     * TODO: Deprecate
+     * @return should list?
+     */
+    boolean shouldList();
+
+    /**
+     * Profilers to use for the run.
+     * TODO: Rework Profilers enum
+     * @return profilers to use; empty set if no profilers are required
+     */
+    Collection<ProfilerFactory.Profilers> getProfilers();
+
+    /**
+     * Should be extra verbose?
+     * @return should be verbose?
+     */
+    boolean isVerbose();
+
+    /**
+     * Should harness terminate on first error encountered?
+     * @return should terminate?
+     */
+    boolean shouldFailOnError();
+
+    /**
+     * Should harness output extra details for the run?
+     * @return should it?
+     */
+    boolean shouldOutputDetailedResults();
+
+    /**
+     * Number of threads to run
+     * @return number of threads; 0 to use maximum number of threads; -1 to use default
+     */
+    int getThreads();
+
+    /**
+     * Should synchronize iterations?
+     * TODO: Rework "null" interface?
+     * @return should we? "null" if not defined
+     */
+    Boolean getSynchIterations();
+
+    /**
+     * Number of warmup iterations
+     * @return number of warmup iterations; -1 to use default
+     */
+    int getWarmupIterations();
+
+    /**
+     * The duration for warmup iterations
+     * @return duration; null, if use default
+     */
+    TimeValue getWarmupTime();
+
+    /**
+     * Warmup mode.
+     * TODO: null for "default"
+     * @return warmup mode
+     */
+    WarmupMode getWarmupMode();
+
+    /**
+     * Which benchmarks to warmup before doing the run.
+     * @return list of regexps matching the relevant benchmarks; null if no benchmarks are defined
+     */
+    List<String> getWarmupMicros();
+
+    /**
+     * Number of measurement iterations
+     * @return number of measurement iterations; -1 to use default
+     */
+    int getIterations();
+
+    /**
+     * The duration for measurement iterations
+     * @return duration; null, if use default
+     */
+    TimeValue getRuntime();
+
+    /**
+     * Benchmarks modes to execute.
+     * @return modes to execute the benchmarks in; null to use the default mode
+     */
+    Collection<Mode> getBenchModes();
+
+    /**
+     * Timeunit to use in units.
+     * @return timeunit; null to use the default timeunit
+     */
+    TimeUnit getTimeUnit();
+
+    /**
+     * Fork count
+     * @return fork count; 0, to prohibit forking
+     */
+    int getForkCount();
+
+    /**
+     * Number of initial forks to ignore the results for
+     * @return initial fork count; 0, to disable
+     */
+    int getWarmupForkCount();
+
+    /**
+     * Additional JVM classpath
+     * TODO: Deprecate this?
+     * @return additional JVM classpath to add to forked VM
+     */
+    String getJvmClassPath();
+
+    /**
+     * JVM to use for forks
+     * @return JVM binary location
+     */
+    String getJvm();
+
+    /**
+     * JVM parameters to use with forks
+     * @return JVM parameters
+     */
+    String getJvmArgs();
+
+    /**
+     * Convert options to command line.
+     * TODO: Rework and deprecate this
+     * @return the array of command line elements.
+     */
+    String[] toCommandLine();
+
+    /**
+     * Forked VM specific: get the address of control VM
+     * @return address of the host VM
+     */
+    String getHostName();
+
+    /**
+     * Forked VM specific: get the port for control VM
+     * @return control VM port
+     */
+    int getHostPort();
+
+    /**
+     * Forked VM specific: get the benchmark info to invoke
+     * @return which benchmark to execute
+     */
+    String getBenchmark();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/options/OptionsBuilder.java	Mon Aug 26 18:45:19 2013 +0400
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.runner.options;
+
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.output.OutputFormatType;
+import org.openjdk.jmh.profile.ProfilerFactory;
+import org.openjdk.jmh.runner.parameters.TimeValue;
+
+import java.util.concurrent.TimeUnit;
+
+public interface OptionsBuilder {
+    Options end();
+
+    OptionsBuilder addBenchmark(String regexp);
+
+    OptionsBuilder addExclude(String regexp);
+
+    OptionsBuilder outputFormat(OutputFormatType type);
+
+    OptionsBuilder setOutput(String filename);
+
+    OptionsBuilder shouldDoGC(boolean value);
+
+    OptionsBuilder shouldList(boolean value);
+
+    OptionsBuilder addProfiler(ProfilerFactory.Profilers prof);
+
+    OptionsBuilder shouldBeVerbose(boolean value);
+
+    OptionsBuilder shouldFailOnError(boolean value);
+
+    OptionsBuilder shouldOutputDetails(boolean value);
+
+    OptionsBuilder threads(int count);
+
+    OptionsBuilder shouldSyncIterations(boolean value);
+
+    OptionsBuilder warmupIterations(int value);
+
+    OptionsBuilder warmupTime(TimeValue value);
+
+    OptionsBuilder warmupMode(WarmupMode mode);
+
+    OptionsBuilder addWarmupMicro(String regexp);
+
+    OptionsBuilder iterations(int count);
+
+    OptionsBuilder measurementTime(TimeValue value);
+
+    OptionsBuilder addMode(Mode mode);
+
+    OptionsBuilder setTimeUnit(TimeUnit tu);
+
+    OptionsBuilder forks(int value);
+
+    OptionsBuilder warmupForks(int value);
+
+    OptionsBuilder classpath(String value);
+
+    OptionsBuilder jvmBinary(String path);
+
+    OptionsBuilder jvmArgs(String value);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/options/WarmupMode.java	Mon Aug 26 18:45:19 2013 +0400
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.runner.options;
+
+/**
+ * Warmup Mode enum
+ */
+public enum WarmupMode {
+    BEFOREANY, BEFOREEACH
+}
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/parameters/MicroBenchmarkParametersFactory.java	Fri Aug 23 18:00:09 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/parameters/MicroBenchmarkParametersFactory.java	Mon Aug 26 18:45:19 2013 +0400
@@ -29,7 +29,7 @@
 import org.openjdk.jmh.annotations.Threads;
 import org.openjdk.jmh.annotations.Warmup;
 import org.openjdk.jmh.runner.BenchmarkRecord;
-import org.openjdk.jmh.runner.options.BaseOptions;
+import org.openjdk.jmh.runner.options.Options;
 
 import java.io.Serializable;
 import java.lang.reflect.Method;
@@ -39,7 +39,7 @@
     private MicroBenchmarkParametersFactory() {
     }
 
-    public static MicroBenchmarkParameters makeParams(BaseOptions options, BenchmarkRecord benchmark, Method method, boolean doWarmup, boolean doMeasurement) {
+    public static MicroBenchmarkParameters makeParams(Options options, BenchmarkRecord benchmark, Method method, boolean doWarmup, boolean doMeasurement) {
         boolean shouldSynchIterations = getBoolean(options.getSynchIterations(), Defaults.SHOULD_SYNCH_ITERATIONS);
 
         int threads = getThreads(options, method);
@@ -61,7 +61,7 @@
                 threads);
     }
 
-    private static IterationParams getWarmup(BaseOptions options, BenchmarkRecord benchmark, Method method, int threads) {
+    private static IterationParams getWarmup(Options options, BenchmarkRecord benchmark, Method method, int threads) {
         boolean isSingleShot = (benchmark.getMode() == Mode.SingleShotTime);
         Warmup warAnn = method.getAnnotation(Warmup.class);
         int iters = (warAnn == null) ? -1 : warAnn.iterations();
@@ -83,7 +83,7 @@
         }
     }
 
-    private static IterationParams getMeasurement(BaseOptions options, BenchmarkRecord benchmark, Method method, int threads) {
+    private static IterationParams getMeasurement(Options options, BenchmarkRecord benchmark, Method method, int threads) {
         boolean isSingleShot = (benchmark.getMode() == Mode.SingleShotTime);
         Measurement meAnn = method.getAnnotation(Measurement.class);
         int iters = (meAnn == null) ? -1 : meAnn.iterations();
@@ -107,7 +107,7 @@
         }
     }
 
-    private static int getThreads(BaseOptions options, Method method) {
+    private static int getThreads(Options options, Method method) {
         Threads threadsAnn = method.getAnnotation(Threads.class);
         return getInteger(options.getThreads(), (threadsAnn == null) ? -1 : threadsAnn.value(), Defaults.THREADS);
 
--- a/jmh-core/src/main/java/org/openjdk/jmh/util/Utils.java	Fri Aug 23 18:00:09 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/util/Utils.java	Mon Aug 26 18:45:19 2013 +0400
@@ -24,6 +24,8 @@
  */
 package org.openjdk.jmh.util;
 
+import java.util.Collection;
+
 public class Utils {
 
     private Utils() {
@@ -36,4 +38,18 @@
         System.arraycopy(t2, 0, r, t1.length, t2.length);
         return r;
     }
+
+    public static String join(Collection<String> src, String delim) {
+        StringBuilder sb = new StringBuilder();
+        boolean first = true;
+        for (String s : src) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(delim);
+            }
+            sb.append(s);
+        }
+        return sb.toString();
+    }
 }