changeset 150:a3aef9af97ce

Use bi-directional binary link to propagate Options instead of marshalling them back to command line.
author shade
date Tue, 27 Aug 2013 17:43:33 +0400
parents 9b447ea48fa3
children 81c3deb0f69f
files jmh-api-samples/src/main/java/org/openjdk/jmh/SimpleTest.java jmh-core/src/main/java/org/openjdk/jmh/ForkedMain.java jmh-core/src/main/java/org/openjdk/jmh/Main.java jmh-core/src/main/java/org/openjdk/jmh/link/BinaryLinkClient.java jmh-core/src/main/java/org/openjdk/jmh/link/BinaryLinkServer.java jmh-core/src/main/java/org/openjdk/jmh/link/CallInfo.java jmh-core/src/main/java/org/openjdk/jmh/link/ClassConventions.java jmh-core/src/main/java/org/openjdk/jmh/link/InfraRequest.java jmh-core/src/main/java/org/openjdk/jmh/link/OptionsReply.java jmh-core/src/main/java/org/openjdk/jmh/output/OutputFormatFactory.java jmh-core/src/main/java/org/openjdk/jmh/output/format/internal/BinaryOutputFormatReader.java jmh-core/src/main/java/org/openjdk/jmh/output/format/internal/BinaryOutputFormatWriter.java jmh-core/src/main/java/org/openjdk/jmh/output/format/internal/CallInfo.java jmh-core/src/main/java/org/openjdk/jmh/output/format/internal/ClassConventions.java jmh-core/src/main/java/org/openjdk/jmh/runner/BenchmarkRecord.java jmh-core/src/main/java/org/openjdk/jmh/runner/ForkedRunner.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/CommandLineOptions.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/test/java/org/openjdk/jmh/runner/options/TestOptions.java
diffstat 24 files changed, 1027 insertions(+), 1424 deletions(-) [+]
line wrap: on
line diff
--- a/jmh-api-samples/src/main/java/org/openjdk/jmh/SimpleTest.java	Tue Aug 27 14:39:52 2013 +0400
+++ b/jmh-api-samples/src/main/java/org/openjdk/jmh/SimpleTest.java	Tue Aug 27 17:43:33 2013 +0400
@@ -32,7 +32,7 @@
 public class SimpleTest {
 
     public static void main(String[] args) throws RunnerException {
-        Options opts = DefaultBuilder.start().addBenchmark(".*").shouldBeVerbose(true).end();
+        Options opts = DefaultBuilder.start().addBenchmark(".*").shouldBeVerbose(true).jvmArgs("-server").end();
         new Runner(opts).run();
     }
 }
--- a/jmh-core/src/main/java/org/openjdk/jmh/ForkedMain.java	Tue Aug 27 14:39:52 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/ForkedMain.java	Tue Aug 27 17:43:33 2013 +0400
@@ -24,9 +24,12 @@
  */
 package org.openjdk.jmh;
 
-import org.kohsuke.args4j.CmdLineException;
+import org.openjdk.jmh.link.BinaryLinkClient;
+import org.openjdk.jmh.runner.BenchmarkRecord;
 import org.openjdk.jmh.runner.ForkedRunner;
-import org.openjdk.jmh.runner.options.ForkedOptions;
+import org.openjdk.jmh.runner.options.Options;
+
+import java.io.IOException;
 
 /**
  * Main program entry point for forked JVM instance
@@ -41,17 +44,21 @@
      * @param argv Command line arguments
      */
     public static void main(String[] argv) {
-        ForkedOptions options = ForkedOptions.newInstance();
-
         if (argv.length == 0) {
             throw new IllegalArgumentException("Empty arguments for forked VM");
         } else {
             try {
-                options.parseArguments(argv);
+                String hostname = argv[0];
+                int hostPort = Integer.valueOf(argv[1]);
+                BenchmarkRecord benchmark = new BenchmarkRecord(argv[2]);
 
-                ForkedRunner runner = new ForkedRunner(options);
-                runner.run();
-            } catch (CmdLineException ex) {
+                BinaryLinkClient link = new BinaryLinkClient(hostname, hostPort);
+                Options options = link.requestOptions();
+                ForkedRunner runner = new ForkedRunner(options, link);
+                runner.run(benchmark);
+            } catch (IOException ex) {
+                throw new IllegalArgumentException(ex.getMessage());
+            } catch (ClassNotFoundException ex) {
                 throw new IllegalArgumentException(ex.getMessage());
             }
         }
--- a/jmh-core/src/main/java/org/openjdk/jmh/Main.java	Tue Aug 27 14:39:52 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/Main.java	Tue Aug 27 17:43:33 2013 +0400
@@ -27,10 +27,9 @@
 import org.kohsuke.args4j.CmdLineException;
 import org.openjdk.jmh.output.OutputFormatType;
 import org.openjdk.jmh.profile.ProfilerFactory;
-import org.openjdk.jmh.runner.MicroBenchmarkList;
 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.CommandLineOptions;
 
 /**
  * Main program entry point
@@ -45,7 +44,7 @@
      * @param argv Command line arguments
      */
     public static void main(String[] argv) {
-        HarnessOptions cmdOptions = HarnessOptions.newInstance();
+        CommandLineOptions cmdOptions = CommandLineOptions.newInstance();
 
         try {
             cmdOptions.parseArguments(argv);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/link/BinaryLinkClient.java	Tue Aug 27 17:43:33 2013 +0400
@@ -0,0 +1,72 @@
+/*
+ * 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.link;
+
+import org.openjdk.jmh.runner.options.Options;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.net.Socket;
+
+public final class BinaryLinkClient implements InvocationHandler {
+
+    private final Socket clientSocket;
+
+    private final ObjectOutputStream oos;
+    private final ObjectInputStream ois;
+
+    public BinaryLinkClient(String hostName, int hostPort) throws IOException {
+        this.clientSocket = new Socket(hostName, hostPort);
+        this.oos = new ObjectOutputStream(clientSocket.getOutputStream());
+        this.ois = new ObjectInputStream(clientSocket.getInputStream());
+    }
+
+    public Options requestOptions() throws IOException, ClassNotFoundException {
+        oos.writeObject(new InfraRequest(InfraRequest.Type.OPTIONS_REQUEST));
+        Object reply = ois.readObject();
+        if (reply instanceof OptionsReply) {
+            return (((OptionsReply) reply).getOpts());
+        } else {
+            throw new IllegalStateException("Got the erroneous reply: " + reply);
+        }
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        oos.writeObject(new CallInfo(ClassConventions.getMethodName(method), args));
+        oos.flush();
+
+        if (method.getName().equals("close")) {
+            // other side is notified, close ourselves
+            oos.close();
+            clientSocket.close();
+        }
+
+        return null; // expect null
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/link/BinaryLinkServer.java	Tue Aug 27 17:43:33 2013 +0400
@@ -0,0 +1,261 @@
+/*
+ * 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.link;
+
+import org.openjdk.jmh.output.format.OutputFormat;
+import org.openjdk.jmh.runner.options.Options;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Accepts the OutputFormat calls from the network and forwards those to given local OutputFormat
+ */
+public class BinaryLinkServer {
+
+    private final Options opts;
+    private final OutputFormat out;
+    private final Map<String, Method> methods;
+    private final Set<String> forbidden;
+    private final Set<String> finishing;
+    private final Acceptor acceptor;
+    private final List<Handler> registeredHandlers;
+
+    public BinaryLinkServer(Options opts, OutputFormat out) throws IOException {
+        this.opts = opts;
+        this.out = out;
+        this.methods = new HashMap<String, Method>();
+        this.forbidden = new HashSet<String>();
+        this.finishing = new HashSet<String>();
+
+        // enumerate methods
+        for (Method m : out.getClass().getMethods()) {
+
+            // start/end run callbacks are banned, since their effects are enforced by parent instead
+            if (m.getName().equals("startRun")) { forbidden.add(ClassConventions.getMethodName(m)); }
+            if (m.getName().equals("endRun"))   { forbidden.add(ClassConventions.getMethodName(m)); }
+
+            // receiving close has a special meaning
+            if (m.getName().equals("close"))    { finishing.add(ClassConventions.getMethodName(m)); }
+
+            Method prev = methods.put(ClassConventions.getMethodName(m), m);
+            if (prev != null) {
+                out.println("WARNING: Duplicate methods: " + m + " vs. " + prev);
+                throw new IllegalStateException("WARNING: Duplicate methods: " + m + " vs. " + prev);
+            }
+        }
+
+        registeredHandlers = Collections.synchronizedList(new ArrayList<Handler>());
+
+        acceptor = new Acceptor();
+        acceptor.start();
+    }
+
+    public void terminate() {
+        acceptor.close();
+
+        for (Handler r : registeredHandlers) {
+            r.close();
+        }
+
+        try {
+            acceptor.join();
+            for (Handler r : registeredHandlers) {
+                r.join();
+            }
+        } catch (InterruptedException e) {
+            // ignore
+        }
+    }
+
+    public void waitFinish() {
+        for (Iterator<Handler> iterator = registeredHandlers.iterator(); iterator.hasNext(); ) {
+            Handler r = iterator.next();
+            try {
+                r.join();
+                iterator.remove();
+            } catch (InterruptedException e) {
+                // ignore
+            }
+        }
+    }
+
+    private final class Acceptor extends Thread {
+
+        private final ServerSocket server;
+
+        public Acceptor() throws IOException {
+            server = new ServerSocket(0);
+        }
+
+        @Override
+        public void run() {
+            try {
+                while (!Thread.interrupted()) {
+                    Socket clientSocket = server.accept();
+                    Handler r = new Handler(clientSocket);
+                    registeredHandlers.add(r);
+                    r.start();
+                }
+            } catch (SocketException e) {
+                // assume this is "Socket closed", return
+            } catch (IOException e) {
+                throw new IllegalStateException(e);
+            } finally {
+                close();
+            }
+        }
+
+        public String getHost() {
+            try {
+                return InetAddress.getLocalHost().getHostAddress();
+            } catch (UnknownHostException e) {
+                throw new IllegalStateException("Unable to resolve local host", e);
+            }
+        }
+
+        public int getPort() {
+            return server.getLocalPort();
+        }
+
+        public void close() {
+            try {
+                server.close();
+            } catch (IOException e) {
+                // do nothing
+            }
+        }
+    }
+
+    public String getHost() {
+        return acceptor.getHost();
+    }
+
+    public int getPort() {
+        return acceptor.getPort();
+    }
+
+    private final class Handler extends Thread {
+        private final InputStream is;
+        private final Socket socket;
+        private ObjectInputStream ois;
+        private final OutputStream os;
+        private ObjectOutputStream oos;
+
+        public Handler(Socket socket) throws IOException {
+            this.socket = socket;
+            this.is = socket.getInputStream();
+            this.os = socket.getOutputStream();
+        }
+
+        @Override
+        public void run() {
+            try {
+                // late OIS initialization, otherwise we'll block reading the header
+                ois = new ObjectInputStream(is);
+                oos = new ObjectOutputStream(os);
+
+                Object obj;
+                while ((obj = ois.readObject()) != null) {
+                    if (obj instanceof CallInfo) {
+                        CallInfo frame = (CallInfo) obj;
+
+                        Method m = methods.get(frame.method);
+
+                        if (finishing.contains(frame.method)) {
+                            break;
+                        }
+
+                        if (forbidden.contains(frame.method)) {
+                            continue;
+                        }
+
+                        if (m == null) {
+                            out.println("WARNING: Unknown method to forward: " + frame.method);
+                            continue;
+                        }
+
+                        m.invoke(out, frame.args);
+                    }
+
+                    if (obj instanceof InfraRequest) {
+                        switch (((InfraRequest) obj).getType()) {
+                            case OPTIONS_REQUEST:
+                                oos.writeObject(new OptionsReply(opts));
+                                oos.flush();
+                                break;
+                            default:
+                                throw new IllegalStateException("Unknown infrastructure request: " + obj);
+                        }
+                    }
+                }
+            } catch (ObjectStreamException e) {
+                throw new IllegalStateException(e);
+            } catch (InterruptedIOException e) {
+                throw new IllegalStateException(e);
+            } catch (IOException e) {
+                throw new IllegalStateException(e);
+            } catch (ClassNotFoundException e) {
+                throw new IllegalStateException(e);
+            } catch (InvocationTargetException e) {
+                throw new IllegalStateException(e);
+            } catch (IllegalAccessException e) {
+                throw new IllegalStateException(e);
+            } finally {
+                close();
+            }
+        }
+
+        public void close() {
+            try {
+                socket.close();
+            } catch (IOException e) {
+                // ignore
+            }
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/link/CallInfo.java	Tue Aug 27 17:43:33 2013 +0400
@@ -0,0 +1,43 @@
+/*
+ * 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.link;
+
+import java.io.Serializable;
+
+/**
+ * Call info:
+ *   - method name
+ *   - arguments (assumed to be serializable)
+ */
+public class CallInfo implements Serializable {
+    private static final long serialVersionUID = -7151852354574635295L;
+    public final String method;
+    public final Object[] args;
+
+    public CallInfo(String method, Object[] args) {
+        this.method = method;
+        this.args = args;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/link/ClassConventions.java	Tue Aug 27 17:43:33 2013 +0400
@@ -0,0 +1,41 @@
+/*
+ * 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.link;
+
+import java.lang.reflect.Method;
+
+public class ClassConventions {
+
+    public static String getMethodName(Method m) {
+        StringBuilder builder = new StringBuilder();
+        builder.append(m.getName());
+        for (Class<?> paramType : m.getParameterTypes()) {
+            builder.append(paramType.getName());
+            builder.append(",");
+        }
+        return builder.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/link/InfraRequest.java	Tue Aug 27 17:43:33 2013 +0400
@@ -0,0 +1,45 @@
+/*
+ * 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.link;
+
+import java.io.Serializable;
+
+public class InfraRequest implements Serializable {
+
+    private final Type type;
+
+    public InfraRequest(Type type) {
+        this.type = type;
+    }
+
+    public Type getType() {
+        return type;
+    }
+
+    public enum Type {
+        OPTIONS_REQUEST,
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/link/OptionsReply.java	Tue Aug 27 17:43:33 2013 +0400
@@ -0,0 +1,42 @@
+/*
+ * 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.link;
+
+import org.openjdk.jmh.runner.options.Options;
+
+import java.io.Serializable;
+
+public class OptionsReply implements Serializable {
+
+    private final Options opts;
+
+    public OptionsReply(Options opts) {
+        this.opts = opts;
+    }
+
+    public Options getOpts() {
+        return opts;
+    }
+}
--- a/jmh-core/src/main/java/org/openjdk/jmh/output/OutputFormatFactory.java	Tue Aug 27 14:39:52 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/output/OutputFormatFactory.java	Tue Aug 27 17:43:33 2013 +0400
@@ -29,7 +29,7 @@
 import org.openjdk.jmh.output.format.PrettyPrintFormat;
 import org.openjdk.jmh.output.format.SilentFormat;
 import org.openjdk.jmh.output.format.TextReportFormat;
-import org.openjdk.jmh.output.format.internal.BinaryOutputFormatWriter;
+import org.openjdk.jmh.link.BinaryLinkClient;
 
 import java.io.IOException;
 import java.io.PrintStream;
@@ -62,20 +62,14 @@
 
     /**
      * Factory method - returns output format for forked JVM.
-     * @param hostName
-     * @param hostPort
      * @return
      */
-    public static OutputFormat createBinaryHook(String hostName, int hostPort) {
-        try {
-            return (OutputFormat) Proxy.newProxyInstance(
-                    Thread.currentThread().getContextClassLoader(),
-                    new Class[]{OutputFormat.class},
-                    new BinaryOutputFormatWriter(hostName, hostPort)
-            );
-        } catch (IOException e) {
-            throw new IllegalStateException(e);
-        }
+    public static OutputFormat createBinaryHook(BinaryLinkClient link) {
+        return (OutputFormat) Proxy.newProxyInstance(
+                Thread.currentThread().getContextClassLoader(),
+                new Class[]{OutputFormat.class},
+                link
+        );
     }
 
     public static OutputFormat createFormatInstance(boolean verbose) {
--- a/jmh-core/src/main/java/org/openjdk/jmh/output/format/internal/BinaryOutputFormatReader.java	Tue Aug 27 14:39:52 2013 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,239 +0,0 @@
-/*
- * 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.output.format.internal;
-
-import org.openjdk.jmh.output.format.OutputFormat;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InterruptedIOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectStreamException;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.InetAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Accepts the OutputFormat calls from the network and forwards those to given local OutputFormat
- */
-public class BinaryOutputFormatReader {
-
-    private final OutputFormat out;
-    private final Map<String, Method> methods;
-    private final Set<String> forbidden;
-    private final Set<String> finishing;
-    private final Acceptor acceptor;
-    private final List<Reader> registeredReaders;
-
-    public BinaryOutputFormatReader(OutputFormat out) throws IOException {
-        this.out = out;
-        this.methods = new HashMap<String, Method>();
-        this.forbidden = new HashSet<String>();
-        this.finishing = new HashSet<String>();
-
-        // enumerate methods
-        for (Method m : out.getClass().getMethods()) {
-
-            // start/end run callbacks are banned, since their effects are enforced by parent instead
-            if (m.getName().equals("startRun")) { forbidden.add(ClassConventions.getMethodName(m)); }
-            if (m.getName().equals("endRun"))   { forbidden.add(ClassConventions.getMethodName(m)); }
-
-            // receiving close has a special meaning
-            if (m.getName().equals("close"))    { finishing.add(ClassConventions.getMethodName(m)); }
-
-            Method prev = methods.put(ClassConventions.getMethodName(m), m);
-            if (prev != null) {
-                out.println("WARNING: Duplicate methods: " + m + " vs. " + prev);
-                throw new IllegalStateException("WARNING: Duplicate methods: " + m + " vs. " + prev);
-            }
-        }
-
-        registeredReaders = Collections.synchronizedList(new ArrayList<Reader>());
-
-        acceptor = new Acceptor();
-        acceptor.start();
-    }
-
-    public void terminate() {
-        acceptor.close();
-
-        for (Reader r : registeredReaders) {
-            r.close();
-        }
-
-        try {
-            acceptor.join();
-            for (Reader r : registeredReaders) {
-                r.join();
-            }
-        } catch (InterruptedException e) {
-            // ignore
-        }
-    }
-
-    public void waitFinish() {
-        for (Iterator<Reader> iterator = registeredReaders.iterator(); iterator.hasNext(); ) {
-            Reader r = iterator.next();
-            try {
-                r.join();
-                iterator.remove();
-            } catch (InterruptedException e) {
-                // ignore
-            }
-        }
-    }
-
-    private final class Acceptor extends Thread {
-
-        private final ServerSocket server;
-
-        public Acceptor() throws IOException {
-            server = new ServerSocket(0);
-        }
-
-        @Override
-        public void run() {
-            try {
-                while (!Thread.interrupted()) {
-                    Socket clientSocket = server.accept();
-                    Reader r = new Reader(clientSocket);
-                    registeredReaders.add(r);
-                    r.start();
-                }
-            } catch (SocketException e) {
-                // assume this is "Socket closed", return
-            } catch (IOException e) {
-                throw new IllegalStateException(e);
-            } finally {
-                close();
-            }
-        }
-
-        public String getHost() {
-            try {
-                return InetAddress.getLocalHost().getHostAddress();
-            } catch (UnknownHostException e) {
-                throw new IllegalStateException("Unable to resolve local host", e);
-            }
-        }
-
-        public int getPort() {
-            return server.getLocalPort();
-        }
-
-        public void close() {
-            try {
-                server.close();
-            } catch (IOException e) {
-                // do nothing
-            }
-        }
-    }
-
-    public String getHost() {
-        return acceptor.getHost();
-    }
-
-    public int getPort() {
-        return acceptor.getPort();
-    }
-
-    private final class Reader extends Thread {
-        private final InputStream is;
-        private final Socket socket;
-        private ObjectInputStream ois;
-
-        public Reader(Socket socket) throws IOException {
-            this.socket = socket;
-            this.is = socket.getInputStream();
-        }
-
-        @Override
-        public void run() {
-            try {
-                // late OIS initialization, otherwise we'll block reading the header
-                ois = new ObjectInputStream(is);
-
-                Object obj;
-                while ((obj = ois.readObject()) != null) {
-                    CallInfo frame = (CallInfo) obj;
-
-                    Method m = methods.get(frame.method);
-
-                    if (finishing.contains(frame.method)) {
-                        break;
-                    }
-
-                    if (forbidden.contains(frame.method)) {
-                        continue;
-                    }
-
-                    if (m == null) {
-                        out.println("WARNING: Unknown method to forward: " + frame.method);
-                        continue;
-                    }
-
-                    m.invoke(out, frame.args);
-                }
-            } catch (ObjectStreamException e) {
-                throw new IllegalStateException(e);
-            } catch (InterruptedIOException e) {
-                throw new IllegalStateException(e);
-            } catch (IOException e) {
-                throw new IllegalStateException(e);
-            } catch (ClassNotFoundException e) {
-                throw new IllegalStateException(e);
-            } catch (InvocationTargetException e) {
-                throw new IllegalStateException(e);
-            } catch (IllegalAccessException e) {
-                throw new IllegalStateException(e);
-            } finally {
-                close();
-            }
-        }
-
-        public void close() {
-            try {
-                socket.close();
-            } catch (IOException e) {
-                // ignore
-            }
-        }
-
-    }
-
-}
--- a/jmh-core/src/main/java/org/openjdk/jmh/output/format/internal/BinaryOutputFormatWriter.java	Tue Aug 27 14:39:52 2013 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * 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.output.format.internal;
-
-import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.net.Socket;
-
-public final class BinaryOutputFormatWriter implements InvocationHandler {
-
-    private final ObjectOutputStream oos;
-    private final Socket clientSocket;
-
-    public BinaryOutputFormatWriter(String hostName, int hostPort) throws IOException {
-        this.clientSocket = new Socket(hostName, hostPort);
-        this.oos = new ObjectOutputStream(clientSocket.getOutputStream());
-    }
-
-    @Override
-    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-        oos.writeObject(new CallInfo(ClassConventions.getMethodName(method), args));
-        oos.flush();
-
-        if (method.getName().equals("close")) {
-            // other side is notified, close ourselves
-            oos.close();
-            clientSocket.close();
-        }
-
-        return null; // expect null
-    }
-}
--- a/jmh-core/src/main/java/org/openjdk/jmh/output/format/internal/CallInfo.java	Tue Aug 27 14:39:52 2013 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * 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.output.format.internal;
-
-import java.io.Serializable;
-
-/**
- * Call info:
- *   - method name
- *   - arguments (assumed to be serializable)
- */
-public class CallInfo implements Serializable {
-    private static final long serialVersionUID = -7151852354574635295L;
-    public final String method;
-    public final Object[] args;
-
-    public CallInfo(String method, Object[] args) {
-        this.method = method;
-        this.args = args;
-    }
-}
--- a/jmh-core/src/main/java/org/openjdk/jmh/output/format/internal/ClassConventions.java	Tue Aug 27 14:39:52 2013 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * 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.output.format.internal;
-
-import java.lang.reflect.Method;
-
-public class ClassConventions {
-
-    public static String getMethodName(Method m) {
-        StringBuilder builder = new StringBuilder();
-        builder.append(m.getName());
-        for (Class<?> paramType : m.getParameterTypes()) {
-            builder.append(paramType.getName());
-            builder.append(",");
-        }
-        return builder.toString();
-    }
-
-}
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/BenchmarkRecord.java	Tue Aug 27 14:39:52 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/BenchmarkRecord.java	Tue Aug 27 17:43:33 2013 +0400
@@ -53,7 +53,7 @@
     }
 
     public String toLine() {
-        return userName + ", " + generatedName + ", " + mode;
+        return userName + "," + generatedName + "," + mode;
     }
 
     public BenchmarkRecord cloneWith(Mode mode) {
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/ForkedRunner.java	Tue Aug 27 14:39:52 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/ForkedRunner.java	Tue Aug 27 17:43:33 2013 +0400
@@ -24,8 +24,8 @@
  */
 package org.openjdk.jmh.runner;
 
+import org.openjdk.jmh.link.BinaryLinkClient;
 import org.openjdk.jmh.output.OutputFormatFactory;
-import org.openjdk.jmh.runner.options.ForkedOptions;
 import org.openjdk.jmh.runner.options.Options;
 
 /**
@@ -37,14 +37,13 @@
 
     private final Options options;
 
-    public ForkedRunner(Options options) {
-        super(options, OutputFormatFactory.createBinaryHook(options.getHostName(), options.getHostPort()));
+    public ForkedRunner(Options options, BinaryLinkClient link) {
+        super(options, OutputFormatFactory.createBinaryHook(link));
         this.options = options;
     }
 
-    public void run() {
+    public void run(BenchmarkRecord benchmark) {
         // expect the tuple from the parent process
-        BenchmarkRecord benchmark = new BenchmarkRecord(options.getBenchmark());
         if (options.isVerbose()) {
             out.println("Benchmarks: ");
             out.println(benchmark.getUsername());
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java	Tue Aug 27 14:39:52 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java	Tue Aug 27 17:43:33 2013 +0400
@@ -29,7 +29,7 @@
 import org.openjdk.jmh.annotations.Mode;
 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.link.BinaryLinkServer;
 import org.openjdk.jmh.runner.options.Options;
 import org.openjdk.jmh.runner.options.WarmupMode;
 import org.openjdk.jmh.runner.parameters.Defaults;
@@ -245,9 +245,9 @@
     }
 
     private void runSeparate(Set<BenchmarkRecord> benchmarksToFork) {
-        BinaryOutputFormatReader reader = null;
+        BinaryLinkServer reader = null;
         try {
-            reader = new BinaryOutputFormatReader(out);
+            reader = new BinaryLinkServer(options, out);
             for (BenchmarkRecord benchmark : benchmarksToFork) {
                 runSeparateMicroBenchmark(reader, benchmark, reader.getHost(), reader.getPort());
             }
@@ -276,7 +276,7 @@
      * @param host host VM host
      * @param port host VM port
      */
-    private void runSeparateMicroBenchmark(BinaryOutputFormatReader reader, BenchmarkRecord benchmark, String host, int port) {
+    private void runSeparateMicroBenchmark(BinaryLinkServer reader, BenchmarkRecord benchmark, String host, int port) {
 
         // Running microbenchmark in separate JVM requires to read some options from annotations.
 
@@ -317,7 +317,7 @@
         }
     }
 
-    private void doFork(BinaryOutputFormatReader reader, String[] commandString) {
+    private void doFork(BinaryLinkServer reader, String[] commandString) {
         try {
             Process p = Runtime.getRuntime().exec(commandString);
 
@@ -437,16 +437,11 @@
         command.add(classPath);
         command.add(ForkedMain.class.getName());
 
-        // if user supplied micro flags, give those as well
-        Collections.addAll(command, options.toCommandLine());
+        command.add(host);
+        command.add(String.valueOf(port));
 
         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	Tue Aug 27 14:39:52 2013 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,434 +0,0 @@
-/*
- * 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.kohsuke.args4j.Option;
-import org.openjdk.jmh.annotations.Mode;
-import org.openjdk.jmh.profile.ProfilerType;
-import org.openjdk.jmh.runner.options.handlers.BenchmarkModeTypeOptionHandler;
-import org.openjdk.jmh.runner.options.handlers.BooleanOptionHandler;
-import org.openjdk.jmh.runner.options.handlers.ProfilersOptionHandler;
-import org.openjdk.jmh.runner.options.handlers.ThreadsOptionHandler;
-import org.openjdk.jmh.runner.options.handlers.TimeUnitOptionHandler;
-import org.openjdk.jmh.runner.options.handlers.TimeValueOptionHandler;
-import org.openjdk.jmh.runner.parameters.Defaults;
-import org.openjdk.jmh.runner.parameters.TimeValue;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Class that handles options which are omni-present everywhere.
- *
- * Boolean/boolean options getters name conventions:
- * - method name is prefixed by "is" or "should" when the Option class gives exact answer
- * - method name is prefixed by "get" when the method is just a getter and meaning of the option clarified somewhere else
- *
- * @author sergey.kuksenko@oracle.com
- */
-public abstract class BaseOptions implements Options {
-
-
-    /*
-     *  Conventions for options processing (unless otherwise specified):
-     *  - int options:
-     *              negative value means unset
-     *  - Boolean options:
-     *              null means unset, TRUE/FALSE means true/false;
-     *              default values should be processed explicitly
-     *  - boolean options:
-     *              may be used only for options with false default value
-     *              may be set to true in cmdLine, can't be set to false explicitly
-     *
-     */
-
-    @Option(name = "-i", aliases = {"--iterations"}, metaVar = "INT", usage = "Number of iterations.")
-    protected int iterations = -1;
-
-    @Option(name = "-r", aliases = {"--runtime"}, metaVar = "TIME", usage = "Run time for each iteration. Examples: 100s, 200ms; defaults to " + Defaults.ITERATION_TIME_SECS + "s", handler = TimeValueOptionHandler.class)
-    protected TimeValue runTime = null;
-
-    @Option(name = "-wi", aliases = {"--warmupiterations"}, metaVar = "INT", usage = "Number of warmup iterations to run.")
-    protected int warmupIterations = -1;
-
-    @Option(name = "-w", aliases = {"--warmup"}, metaVar = "TIME", usage = "Run time for warmup iterations. Result not used when calculating score. Examples 100s, 200ms; defaults to " + Defaults.WARMUP_TIME_SECS + "", handler = TimeValueOptionHandler.class)
-    protected TimeValue warmupTime = null;
-
-    @Option(name = "-bm", aliases = {"--mode"}, multiValued = false, metaVar = "MODE", usage = "Benchmark mode", handler = BenchmarkModeTypeOptionHandler.class)
-    protected List<Mode> benchMode = null;
-
-    @Option(name = "-t", aliases = {"--threads"}, usage = "Number of threads to run the microbenchmark with. Special value \"max\" or 0 will use Runtime.availableProcessors()", handler = ThreadsOptionHandler.class)
-    protected int threads = -1;
-
-    @Option(name = "-si", aliases = {"--synciterations"}, usage = "Should the harness continue to load each thread with work untill all threads are done with their measured work? Default is " + Defaults.SHOULD_SYNCH_ITERATIONS, handler = BooleanOptionHandler.class)
-    protected Boolean synchIterations = null; // true
-
-    @Option(name = "-gc", usage = "Should do System.gc() between iterations?", handler = BooleanOptionHandler.class)
-    protected boolean gcEachIteration = false;
-
-    @Option(name = "-v", aliases = {"--verbose"}, usage = "Verbose mode, default off", handler = BooleanOptionHandler.class)
-    protected boolean verbose = false;
-
-    @Option(name = "-odr", aliases = {"--outputdetailedresults"}, usage = "Output detailed results. Default is false", handler = BooleanOptionHandler.class)
-    protected boolean outputDetailedResults = false;
-
-    @Option(name = "-foe", usage = "Fail the harness on benchmark erro?", handler = BooleanOptionHandler.class)
-    protected boolean failOnError = false;
-
-    @Option(name = "-prof", aliases = {"--useprofiler"}, multiValued = false, usage = "Use profilers for collecting additional info, use --listprofilers to list available profilers", handler = ProfilersOptionHandler.class)
-    protected Set<ProfilerType> profilers = EnumSet.noneOf(ProfilerType.class);
-
-    @Option(name = "-tu", aliases = {"--timeunit"}, usage = "Output time unit. Available values: m, s, ms, us, ns", handler = TimeUnitOptionHandler.class)
-    protected TimeUnit timeUnit = null;
-
-    /**
-     * returns canonical command line containing all options (differ than default value)
-     *
-     * @return
-     */
-    public String[] toCommandLine() {
-        List<String> sb = new ArrayList<String>();
-        List<Field> fields = getOptionFields();
-        for (Field f : fields) {
-            String opImage = fieldToCommandLineImage(f);
-            if (opImage != null && !opImage.isEmpty()) {
-                Collections.addAll(sb, opImage.split("[ ]+"));
-            }
-        }
-        return sb.toArray(new String[sb.size()]);
-    }
-
-    /**
-     * returns list of option fields sorted alphabetically by their option names
-     *
-     * @return
-     */
-    private List<Field> getOptionFields() {
-        Field[] fields = BaseOptions.class.getDeclaredFields();
-        List<Field> optionFields = new ArrayList<Field>();
-        // find fields (and thus, options) to not send to the forked process
-        for (Field field : fields) {
-            if (field.getAnnotation(Option.class) != null) {
-                optionFields.add(field);
-            }
-        }
-        Collections.sort(optionFields, new Comparator<Field>() {
-            @Override
-            public int compare(Field f1, Field f2) {
-                Option o1 = f1.getAnnotation(Option.class);
-                Option o2 = f2.getAnnotation(Option.class);
-                return o1.name().compareTo(o2.name());
-            }
-        });
-        return optionFields;
-    }
-
-    private String fieldToCommandLineImage(Field f) {
-        Class<?> t = f.getType();
-        if (Integer.TYPE.equals(t)) {
-            return intFieldToString(f);
-        }
-        if (Boolean.class.equals(t)) {
-            return bigBoolFieldToString(f);
-        }
-        if (Boolean.TYPE.equals(t)) {
-            return primitiveBoolFieldToString(f);
-        }
-        if (List.class.equals(t)) {
-            return listFieldToString(f);
-        }
-        if (Set.class.equals(t)) {
-            return setFieldToString(f);
-        }
-        if (TimeValue.class.equals(t)) {
-            return timeValueFieldToString(f);
-        }
-        if (TimeUnit.class.equals(t)) {
-            return timeUnitFieldToString(f);
-        }
-        if (Mode.class.equals(t)) {
-            return benchTypeFieldToString(f);
-        }
-        throw new IllegalArgumentException("Unknown forwarding field type, field="+f.toString());
-    }
-
-    private String intFieldToString(Field f) {
-        try {
-            Object value = f.get(this);
-            if (value != null && value instanceof Integer && (Integer) value >= 0) {
-                return f.getAnnotation(Option.class).name() + " " + value;
-            } else {
-                return null;
-            }
-        } catch (IllegalAccessException e) {
-            throw new IllegalAccessError("Caused by: " + e.getMessage());
-        }
-    }
-
-    private String bigBoolFieldToString(Field f) {
-        try {
-            Object value = f.get(this);
-            if (value != null && value instanceof Boolean) {
-                return f.getAnnotation(Option.class).name() + " " + value;
-            } else {
-                return null;
-            }
-        } catch (IllegalAccessException e) {
-            throw new IllegalAccessError("Caused by: " + e.getMessage());
-        }
-    }
-
-    private String primitiveBoolFieldToString(Field f) {
-        try {
-            Object value = f.get(this);
-            if (value != null && value instanceof Boolean && (Boolean) value) {
-                return f.getAnnotation(Option.class).name() + " " + value;
-            } else {
-                return null;
-            }
-        } catch (IllegalAccessException e) {
-            throw new IllegalAccessError("Caused by: " + e.getMessage());
-        }
-    }
-
-    private String listFieldToString(Field f) {
-        try {
-            Object value = f.get(this);
-            if (value != null && value instanceof List && !((List) value).isEmpty()) {
-                StringBuilder sb = new StringBuilder();
-                sb.append(f.getAnnotation(Option.class).name()).append(' ');
-                boolean isTail = false;
-                for (Object o : (List) value) {
-                    if (isTail) {
-                        sb.append(',');
-                    }
-                    sb.append(o);
-                    isTail = true;
-                }
-                return sb.toString();
-            } else {
-                return null;
-            }
-        } catch (IllegalAccessException e) {
-            throw new IllegalAccessError("Caused by: " + e.getMessage());
-        }
-    }
-
-    private String setFieldToString(Field f) {
-        try {
-            Object value = f.get(this);
-            if (value != null && value instanceof Set && !((Set) value).isEmpty()) {
-                StringBuilder sb = new StringBuilder();
-                sb.append(f.getAnnotation(Option.class).name()).append(' ');
-                boolean isTail = false;
-                for (Object o : (Set) value) {
-                    if (isTail) {
-                        sb.append(',');
-                    }
-                    if( o instanceof ProfilerType) {
-                        sb.append(((ProfilerType) o).id());
-                    } else {
-                        sb.append(o);
-                    }
-                    isTail = true;
-                }
-                return sb.toString();
-            } else {
-                return null;
-            }
-        } catch (IllegalAccessException e) {
-            throw new IllegalAccessError("Caused by: " + e.getMessage());
-        }
-    }
-
-    private String timeValueFieldToString(Field f) {
-        try {
-            Object value = f.get(this);
-            if (value != null && value instanceof TimeValue) {
-                return f.getAnnotation(Option.class).name() + " " + ((TimeValue) value).toCommandLine();
-            } else {
-                return null;
-            }
-        } catch (IllegalAccessException e) {
-            throw new IllegalAccessError("Caused by: " + e.getMessage());
-        }
-    }
-
-    private String timeUnitFieldToString(Field f) {
-        try {
-            Object value = f.get(this);
-            if (value != null && value instanceof TimeUnit) {
-                return f.getAnnotation(Option.class).name() + " " + TimeUnitOptionHandler.toString((TimeUnit)value);
-            } else {
-                return null;
-            }
-        } catch (IllegalAccessException e) {
-            throw new IllegalAccessError("Caused by: " + e.getMessage());
-        }
-    }
-
-    private String benchTypeFieldToString(Field f) {
-        try {
-            Object value = f.get(this);
-            if (value != null && value instanceof Mode) {
-                return f.getAnnotation(Option.class).name() + " " + value;
-            } else {
-                return null;
-            }
-        } catch (IllegalAccessException e) {
-            throw new IllegalAccessError("Caused by: " + e.getMessage());
-        }
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public int getIterations() {
-        return iterations;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public TimeValue getRuntime() {
-        return runTime;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public TimeValue getWarmupTime() {
-        return warmupTime;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public int getWarmupIterations() {
-        return warmupIterations;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public int getThreads() {
-        return threads;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public boolean shouldDoGC() {
-        return gcEachIteration;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public Boolean getSynchIterations() {
-        return synchIterations;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public boolean isVerbose() {
-        return verbose;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public TimeUnit getTimeUnit() {
-        return timeUnit;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public boolean shouldOutputDetailedResults() {
-        return outputDetailedResults;
-    }
-
-    /**
-     * Should fail the harness on test error?
-     * @return the value
-     */
-    @Override
-    public boolean shouldFailOnError() {
-        return failOnError;
-    }
-
-    /**
-     * Getter
-     * @return the value
-     */
-    @Override
-    public Set<ProfilerType> 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/CommandLineOptions.java	Tue Aug 27 17:43:33 2013 +0400
@@ -0,0 +1,479 @@
+/*
+ * 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.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.Option;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.output.OutputFormatType;
+import org.openjdk.jmh.profile.ProfilerType;
+import org.openjdk.jmh.runner.options.handlers.BenchmarkModeTypeOptionHandler;
+import org.openjdk.jmh.runner.options.handlers.BooleanOptionHandler;
+import org.openjdk.jmh.runner.options.handlers.ForkOptionHandler;
+import org.openjdk.jmh.runner.options.handlers.ProfilersOptionHandler;
+import org.openjdk.jmh.runner.options.handlers.ThreadsOptionHandler;
+import org.openjdk.jmh.runner.options.handlers.TimeUnitOptionHandler;
+import org.openjdk.jmh.runner.options.handlers.TimeValueOptionHandler;
+import org.openjdk.jmh.runner.parameters.Defaults;
+import org.openjdk.jmh.runner.parameters.TimeValue;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Class that handles all the options and arguments specific to the harness JVM.
+ *
+ * Boolean/boolean options getters name conventions:
+ *   - method name is prefixed by "is" or "should" when the Option class gives exact answer
+ *   - method name is prefixed by "get" when the method is just a getter and meaning of the option clarified somewhere else
+ *
+ * @author anders.astrand@oracle.com
+ * @author sergey.kuksenko@oracle.com
+ */
+public class CommandLineOptions implements Options {
+
+        /*
+     *  Conventions for options processing (unless otherwise specified):
+     *  - int options:
+     *              negative value means unset
+     *  - Boolean options:
+     *              null means unset, TRUE/FALSE means true/false;
+     *              default values should be processed explicitly
+     *  - boolean options:
+     *              may be used only for options with false default value
+     *              may be set to true in cmdLine, can't be set to false explicitly
+     *
+     */
+
+    @Option(name = "-i", aliases = {"--iterations"}, metaVar = "INT", usage = "Number of iterations.")
+    protected int iterations = -1;
+
+    @Option(name = "-r", aliases = {"--runtime"}, metaVar = "TIME", usage = "Run time for each iteration. Examples: 100s, 200ms; defaults to " + Defaults.ITERATION_TIME_SECS + "s", handler = TimeValueOptionHandler.class)
+    protected TimeValue runTime = null;
+
+    @Option(name = "-wi", aliases = {"--warmupiterations"}, metaVar = "INT", usage = "Number of warmup iterations to run.")
+    protected int warmupIterations = -1;
+
+    @Option(name = "-w", aliases = {"--warmup"}, metaVar = "TIME", usage = "Run time for warmup iterations. Result not used when calculating score. Examples 100s, 200ms; defaults to " + Defaults.WARMUP_TIME_SECS + "", handler = TimeValueOptionHandler.class)
+    protected TimeValue warmupTime = null;
+
+    @Option(name = "-bm", aliases = {"--mode"}, multiValued = false, metaVar = "MODE", usage = "Benchmark mode", handler = BenchmarkModeTypeOptionHandler.class)
+    protected List<Mode> benchMode = null;
+
+    @Option(name = "-t", aliases = {"--threads"}, usage = "Number of threads to run the microbenchmark with. Special value \"max\" or 0 will use Runtime.availableProcessors()", handler = ThreadsOptionHandler.class)
+    protected int threads = -1;
+
+    @Option(name = "-si", aliases = {"--synciterations"}, usage = "Should the harness continue to load each thread with work untill all threads are done with their measured work? Default is " + Defaults.SHOULD_SYNCH_ITERATIONS, handler = BooleanOptionHandler.class)
+    protected Boolean synchIterations = null; // true
+
+    @Option(name = "-gc", usage = "Should do System.gc() between iterations?", handler = BooleanOptionHandler.class)
+    protected boolean gcEachIteration = false;
+
+    @Option(name = "-v", aliases = {"--verbose"}, usage = "Verbose mode, default off", handler = BooleanOptionHandler.class)
+    protected boolean verbose = false;
+
+    @Option(name = "-odr", aliases = {"--outputdetailedresults"}, usage = "Output detailed results. Default is false", handler = BooleanOptionHandler.class)
+    protected boolean outputDetailedResults = false;
+
+    @Option(name = "-foe", usage = "Fail the harness on benchmark erro?", handler = BooleanOptionHandler.class)
+    protected boolean failOnError = false;
+
+    @Option(name = "-prof", aliases = {"--useprofiler"}, multiValued = false, usage = "Use profilers for collecting additional info, use --listprofilers to list available profilers", handler = ProfilersOptionHandler.class)
+    protected Set<ProfilerType> profilers = EnumSet.noneOf(ProfilerType.class);
+
+    @Option(name = "-tu", aliases = {"--timeunit"}, usage = "Output time unit. Available values: m, s, ms, us, ns", handler = TimeUnitOptionHandler.class)
+    protected TimeUnit timeUnit = null;
+
+    // test selection options
+    @Argument(metaVar = "REGEXP", usage = "Microbenchmarks to run. Regexp filtering out classes or methods which are MicroBenchmarks.")
+    protected List<String> regexps = new ArrayList<String>();
+
+    // micro options
+
+    @Option(name = "-f", aliases = {"--fork"}, metaVar = "{ INT }", usage = "Start each benchmark in new JVM, forking from the same JDK unless --jvm is set. Optional parameter specifies number of times harness should fork. Zero forks means \"no fork\", also \"false\" is accepted", handler = ForkOptionHandler.class)
+    protected int fork = -1;
+
+    @Option(name = "-wf", aliases = {"--warmupfork"}, metaVar = "{ INT }", usage = "Number of warmup fork executions. (warmup fork execution results are ignored).")
+    protected int warmupFork = -1;
+
+    @Option(name = "-o", aliases = {"--output"}, metaVar = "FILE", usage = "Redirect output to FILE")
+    protected String output = null;
+
+    @Option(name = "-of", aliases = {"--outputformat"}, metaVar = "FORMAT", usage = "Format to use for output, use --listformats to list available formats")
+    protected OutputFormatType outputFormat = OutputFormatType.defaultType();
+
+    @Option(name = "--jvm", metaVar = "JVM", usage = "Custom JVM to use with fork.")
+    protected String jvm = null;
+
+    @Option(name = "--jvmargs", metaVar = "JVMARGS", usage = "Custom JVM arguments for --jvm, default is to use parent process's arguments")
+    protected String jvmArgs = null;
+
+    @Option(name = "--jvmclasspath", metaVar = "CLASSPATH", usage = "Custom classpath for --jvm, default is to use parent process's classpath")
+    protected String jvmClassPath = null;
+
+    @Option(name = "-e", aliases = {"--exclude"}, multiValued = true, metaVar = "REGEXP", usage = "Microbenchmarks to exclude. Regexp filtering out classes or methods which are MicroBenchmarks.")
+    protected List<String> excludes = new ArrayList<String>();
+
+    @Option(name = "-wm", aliases = {"--warmupmode"}, usage = "Warmup mode for warming up selected micro benchmarks. Warmup modes are BeforeAny (measurements) or BeforeEach (measurement) (original mode)")
+    protected WarmupMode warmupMode = WarmupMode.defaultMode();
+
+    @Option(name = "-wmb", aliases = {"--warmupmicrobenchmarks"}, multiValued = true, metaVar = "REGEXP", usage = "Microbenchmarks to run for warmup before running any other benchmarks. These micros may be different from the target micros to warm up the harness or other parts of the JVM prior to running the target micro benchmarks. Regexp filtering out classes or methods which are MicroBenchmarks.")
+    protected List<String> warmupMicros = new ArrayList<String>();
+
+    // show something options
+    @Option(name = "-l", aliases = {"--list"}, usage = "List available microbenchmarks and exit. Filter using available regexps.")
+    protected boolean list = false;
+
+    @Option(name = "--listformats", usage = "List available output formats")
+    protected boolean listFormats = false;
+
+    @Option(name = "-h", aliases = {"--help"}, usage = "Display help")
+    protected boolean help = false;
+
+    @Option(name = "--listprofilers", usage = "List available profilers")
+    protected boolean listProfilers = false;
+
+    /**
+     * Kawaguchi's parser
+     */
+    private transient CmdLineParser parser;
+
+    public static CommandLineOptions newInstance() {
+        CommandLineOptions opts = new CommandLineOptions();
+        opts.parser = new CmdLineParser(opts);
+        return opts;
+    }
+
+    protected CommandLineOptions() {
+    }
+
+    /**
+     * Print Usage
+     *
+     * @param message Message to print at the top
+     */
+    public void printUsage(String message) {
+        System.err.println(message);
+        System.err.println("Usage: [options] [benchmark regexp]*");
+        parser.printUsage(System.err);
+    }
+
+    /**
+     * parse arguments and set fields in the Options instance
+     *
+     * @throws CmdLineException
+     */
+    public void parseArguments(String[] argv) throws CmdLineException {
+        parser.parseArgument(argv);
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public WarmupMode getWarmupMode() {
+        return warmupMode;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public List<String> getRegexps() {
+        if (!regexps.isEmpty()) {
+            return regexps;
+        } else {
+            // assume user requested all benchmarks
+            return Collections.singletonList(".*");
+        }
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public List<String> getExcludes() {
+        return excludes;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public List<String> getWarmupMicros() {
+        if (warmupMicros == null) {
+            return Collections.emptyList();
+        } else {
+            return warmupMicros;
+        }
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    public boolean shouldList() {
+        return list;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public String getJvm() {
+        return jvm;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public String getJvmArgs() {
+        return jvmArgs;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public String getJvmClassPath() {
+        return jvmClassPath;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public int getForkCount() {
+        return fork;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public int getWarmupForkCount() {
+        return warmupFork;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public String getOutput() {
+        return output;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public OutputFormatType getOutputFormat() {
+        return outputFormat;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    public boolean shouldListFormats() {
+        return listFormats;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    public boolean shouldHelp() {
+        return help;
+    }
+
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    public boolean shouldListProfilers() {
+        return listProfilers;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public int getIterations() {
+        return iterations;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public TimeValue getRuntime() {
+        return runTime;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public TimeValue getWarmupTime() {
+        return warmupTime;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public int getWarmupIterations() {
+        return warmupIterations;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public int getThreads() {
+        return threads;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public boolean shouldDoGC() {
+        return gcEachIteration;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public Boolean getSynchIterations() {
+        return synchIterations;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public boolean isVerbose() {
+        return verbose;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public TimeUnit getTimeUnit() {
+        return timeUnit;
+    }
+
+    /**
+     * Getter
+     *
+     * @return the value
+     */
+    @Override
+    public boolean shouldOutputDetailedResults() {
+        return outputDetailedResults;
+    }
+
+    /**
+     * Should fail the harness on test error?
+     * @return the value
+     */
+    @Override
+    public boolean shouldFailOnError() {
+        return failOnError;
+    }
+
+    /**
+     * Getter
+     * @return the value
+     */
+    @Override
+    public Set<ProfilerType> getProfilers() {
+        return profilers;
+    }
+
+    @Override
+    public Collection<Mode> getBenchModes() {
+        return benchMode;
+    }
+
+
+}
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/options/DefaultBuilder.java	Tue Aug 27 14:39:52 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/options/DefaultBuilder.java	Tue Aug 27 17:43:33 2013 +0400
@@ -420,34 +420,4 @@
         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	Tue Aug 27 14:39:52 2013 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,146 +0,0 @@
-/*
- * 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.kohsuke.args4j.Argument;
-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
- *
- * @author sergey.kuksenko@oracle.com
- */
-public class ForkedOptions extends BaseOptions {
-
-
-    @Argument(metaVar = "benchmark", usage = "Microbenchmarks to run")
-    protected String benchmark = null;
-
-    @Option(name = "--hostName", metaVar = "String", usage = "The IP address of host JVM")
-    protected String hostName = null;
-
-    @Option(name = "--hostPort", metaVar = "INT", usage = "The IP port of host JVM")
-    protected int hostPort = 0;
-
-    /**
-     * Kawaguchi's parser
-     */
-    private CmdLineParser parser;
-
-    public static ForkedOptions newInstance() {
-        ForkedOptions opts = new ForkedOptions();
-        opts.parser = new CmdLineParser(opts);
-        return opts;
-    }
-
-    protected ForkedOptions() {
-    }
-
-    /**
-     * parse arguments and set fields in the Options instance
-     *
-     * @throws org.kohsuke.args4j.CmdLineException
-     *
-     */
-    public void parseArguments(String[] argv) throws CmdLineException {
-        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 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	Tue Aug 27 14:39:52 2013 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,303 +0,0 @@
-/*
- * 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.kohsuke.args4j.Argument;
-import org.kohsuke.args4j.CmdLineException;
-import org.kohsuke.args4j.CmdLineParser;
-import org.kohsuke.args4j.Option;
-import org.openjdk.jmh.output.OutputFormatType;
-import org.openjdk.jmh.runner.options.handlers.ForkOptionHandler;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Class that handles all the options and arguments specific to the harness JVM.
- *
- * @author anders.astrand@oracle.com
- * @author sergey.kuksenko@oracle.com
- */
-public class HarnessOptions extends BaseOptions {
-
-
-    // test selection options
-    @Argument(metaVar = "REGEXP", usage = "Microbenchmarks to run. Regexp filtering out classes or methods which are MicroBenchmarks.")
-    protected List<String> regexps = new ArrayList<String>();
-
-    // micro options
-    // the following list of options are not forwarding into forked JVM.
-    // "forwarding option should be declared in BaseOptions class" (c) capt. O.
-
-    @Option(name = "-f", aliases = {"--fork"}, metaVar = "{ INT }", usage = "Start each benchmark in new JVM, forking from the same JDK unless --jvm is set. Optional parameter specifies number of times harness should fork. Zero forks means \"no fork\", also \"false\" is accepted", handler = ForkOptionHandler.class)
-    protected int fork = -1;
-
-    @Option(name = "-wf", aliases = {"--warmupfork"}, metaVar = "{ INT }", usage = "Number of warmup fork executions. (warmup fork execution results are ignored).")
-    protected int warmupFork = -1;
-
-    @Option(name = "-o", aliases = {"--output"}, metaVar = "FILE", usage = "Redirect output to FILE")
-    protected String output = null;
-
-    @Option(name = "-of", aliases = {"--outputformat"}, metaVar = "FORMAT", usage = "Format to use for output, use --listformats to list available formats")
-    protected OutputFormatType outputFormat = OutputFormatType.defaultType();
-
-    @Option(name = "--jvm", metaVar = "JVM", usage = "Custom JVM to use with fork.")
-    protected String jvm = null;
-
-    @Option(name = "--jvmargs", metaVar = "JVMARGS", usage = "Custom JVM arguments for --jvm, default is to use parent process's arguments")
-    protected String jvmArgs = null;
-
-    @Option(name = "--jvmclasspath", metaVar = "CLASSPATH", usage = "Custom classpath for --jvm, default is to use parent process's classpath")
-    protected String jvmClassPath = null;
-
-    @Option(name = "-e", aliases = {"--exclude"}, multiValued = true, metaVar = "REGEXP", usage = "Microbenchmarks to exclude. Regexp filtering out classes or methods which are MicroBenchmarks.")
-    protected List<String> excludes = new ArrayList<String>();
-
-    @Option(name = "-wm", aliases = {"--warmupmode"}, usage = "Warmup mode for warming up selected micro benchmarks. Warmup modes are BeforeAny (measurements) or BeforeEach (measurement) (original mode)")
-    protected WarmupMode warmupMode = WarmupMode.defaultMode();
-
-    @Option(name = "-wmb", aliases = {"--warmupmicrobenchmarks"}, multiValued = true, metaVar = "REGEXP", usage = "Microbenchmarks to run for warmup before running any other benchmarks. These micros may be different from the target micros to warm up the harness or other parts of the JVM prior to running the target micro benchmarks. Regexp filtering out classes or methods which are MicroBenchmarks.")
-    protected List<String> warmupMicros = new ArrayList<String>();
-
-    // show something options
-    @Option(name = "-l", aliases = {"--list"}, usage = "List available microbenchmarks and exit. Filter using available regexps.")
-    protected boolean list = false;
-
-    @Option(name = "--listformats", usage = "List available output formats")
-    protected boolean listFormats = false;
-
-    @Option(name = "-h", aliases = {"--help"}, usage = "Display help")
-    protected boolean help = false;
-
-    @Option(name = "--listprofilers", usage = "List available profilers")
-    protected boolean listProfilers = false;
-
-    /**
-     * Kawaguchi's parser
-     */
-    private CmdLineParser parser;
-
-    public static HarnessOptions newInstance() {
-        HarnessOptions opts = new HarnessOptions();
-        opts.parser = new CmdLineParser(opts);
-        return opts;
-    }
-
-    protected HarnessOptions() {
-    }
-
-    /**
-     * Print Usage
-     *
-     * @param message Message to print at the top
-     */
-    public void printUsage(String message) {
-        System.err.println(message);
-        System.err.println("Usage: [options] [benchmark regexp]*");
-        parser.printUsage(System.err);
-    }
-
-    /**
-     * parse arguments and set fields in the Options instance
-     *
-     * @throws CmdLineException
-     */
-    public void parseArguments(String[] argv) throws CmdLineException {
-        parser.parseArgument(argv);
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public WarmupMode getWarmupMode() {
-        return warmupMode;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public List<String> getRegexps() {
-        if (!regexps.isEmpty()) {
-            return regexps;
-        } else {
-            // assume user requested all benchmarks
-            return Collections.singletonList(".*");
-        }
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public List<String> getExcludes() {
-        return excludes;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public List<String> getWarmupMicros() {
-        if (warmupMicros == null) {
-            return Collections.emptyList();
-        } else {
-            return warmupMicros;
-        }
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    public boolean shouldList() {
-        return list;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public String getJvm() {
-        return jvm;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public String getJvmArgs() {
-        return jvmArgs;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public String getJvmClassPath() {
-        return jvmClassPath;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public int getForkCount() {
-        return fork;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public int getWarmupForkCount() {
-        return warmupFork;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public String getOutput() {
-        return output;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    @Override
-    public OutputFormatType getOutputFormat() {
-        return outputFormat;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    public boolean shouldListFormats() {
-        return listFormats;
-    }
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    public boolean shouldHelp() {
-        return help;
-    }
-
-
-    /**
-     * Getter
-     *
-     * @return the value
-     */
-    public boolean shouldListProfilers() {
-        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");
-    }
-
-}
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/options/Options.java	Tue Aug 27 14:39:52 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/options/Options.java	Tue Aug 27 17:43:33 2013 +0400
@@ -29,11 +29,12 @@
 import org.openjdk.jmh.profile.ProfilerType;
 import org.openjdk.jmh.runner.parameters.TimeValue;
 
+import java.io.Serializable;
 import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-public interface Options {
+public interface Options extends Serializable {
 
     /**
      * Which benchmarks to execute?
@@ -180,28 +181,4 @@
      */
     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();
 }
--- a/jmh-core/src/test/java/org/openjdk/jmh/runner/options/TestOptions.java	Tue Aug 27 14:39:52 2013 +0400
+++ b/jmh-core/src/test/java/org/openjdk/jmh/runner/options/TestOptions.java	Tue Aug 27 17:43:33 2013 +0400
@@ -28,15 +28,9 @@
 import org.kohsuke.args4j.CmdLineException;
 import org.openjdk.jmh.annotations.Fork;
 import org.openjdk.jmh.annotations.Measurement;
-import org.openjdk.jmh.annotations.Mode;
 import org.openjdk.jmh.annotations.Threads;
-import org.openjdk.jmh.runner.BenchmarkRecord;
-import org.openjdk.jmh.runner.parameters.MicroBenchmarkParameters;
-import org.openjdk.jmh.runner.parameters.MicroBenchmarkParametersFactory;
 import org.openjdk.jmh.runner.parameters.TimeValue;
 
-import java.util.Arrays;
-import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 import static org.junit.Assert.assertEquals;
@@ -52,61 +46,8 @@
 
     public static final String ORACLE_FORKED_MAIN_CLASS = "org.openjdk.jmh.ForkedMain";
 
-    private static String getForked(String[] argv) throws Exception{
-        HarnessOptions options =  HarnessOptions.newInstance();
-        options.parseArguments(argv);
-        StringBuilder sb = new StringBuilder();
-        for (String l : options.toCommandLine()) {
-            sb.append(l).append(' ');
-        }
-        // with sweet love from Sweden: remove final delimiter
-        if (sb.length() > 0) {
-            sb.setLength(sb.length() - 1);
-        }
-        return sb.toString();
-    }
-
-    @Test
-    public void testGetForkArguments() throws Exception {
-        String[] argv = {"-e", ".*Apa.*", ".*SPECjbb2005.*", "-f", "-v"};
-        assertEquals("-v true", getForked(argv));
-
-
-        String[] argv2 = {".*Hash.*", "-e", ".*Apa.*", "-f", "-e", ".*a.*", "-v", "-i", "10", "-r", "100", "-t", "2"};
-        assertEquals("-i 10 -r 100s -t 2 -v true", getForked(argv2));
-
-
-        String[] argv3 = {"--jvmargs", "\"-Xmx31337g -Xms31337g\"", "--jvm", "/opt/java/konrad/bin/java", "-l", "-e", ".*Apa.*", "-f", "-e", ".*a.*", "-v", "-i", "10", "-r", "100", "-t", "2", ".*Hash.*"};
-        assertEquals("-i 10 -r 100s -t 2 -v true", getForked(argv3));
-
-
-        String[] argv4 = {"-f"};
-        assertEquals("", getForked(argv4));
-
-
-        String[] argv5 = {"-e", ".*Apa.*", ".*SPECjbb2005.*", "-f", "-v", "-o", "SPECjbb2005"};
-        assertEquals("-v true", getForked(argv5));
-
-
-        String[] argv6 = {".*Apa.*", ".*SPECjbb2006.*", "-f", "-v", "-o", "SPECjbb2006"};
-        assertEquals("-v true", getForked(argv6));
-
-
-        String[] argv7 = {".*Apa.*", ".*SPECjbb2007.*", "-w", "100", "-f", "-v", "-o", "SPECjbb2007"};
-        assertEquals("-v true -w 100s", getForked(argv7));
-
-
-        String[] argv8 = {".*Apa.*", ".*SPECjbb2008.*", "-w", "100", "-l", "-f", "-v", "-o", "SPECjbb2008"};
-        assertEquals("-v true -w 100s", getForked(argv8));
-
-
-        String[] argv9 = {"-i", "10", "-r", "10", "-w", "10", "-t", "10", "-si", "-l", "-v", "-o", "SPECjbb2005", "-of", "csv"};
-        assertEquals("-i 10 -r 10s -si true -t 10 -v true -w 10s", getForked(argv9));
-    }
-
-
-    private static HarnessOptions getOptions(String[] argv) throws Exception {
-        HarnessOptions opts = HarnessOptions.newInstance();
+    private static CommandLineOptions getOptions(String[] argv) throws Exception {
+        CommandLineOptions opts = CommandLineOptions.newInstance();
         opts.parseArguments(argv);
         return opts;
     }
@@ -114,7 +55,7 @@
     @Test
     public void testThreadsMax() throws Exception {
         String[] argv = {"-t", "max"};
-        HarnessOptions options = getOptions(argv);
+        CommandLineOptions options = getOptions(argv);
         assertEquals(0, options.getThreads());
     }
 
@@ -123,7 +64,7 @@
         String parameter = "maxx";
         String[] argv = {"-t", parameter};
         try {
-            HarnessOptions options = getOptions(argv);
+            CommandLineOptions options = getOptions(argv);
         } catch (CmdLineException e) {
             assertTrue("Exception message did not contain parameter value", e.getMessage().contains(parameter));
             return;
@@ -146,7 +87,7 @@
     @Test
     public void testWarmupWithArg() throws Exception {
         String[] argv = {"-w", "100"};
-        HarnessOptions options = getOptions(argv);
+        CommandLineOptions options = getOptions(argv);
 
         assertEquals(new TimeValue(100, TimeUnit.SECONDS), options.getWarmupTime());