changeset 229:d8cf91cbbdda

Rewire the BinaryLinkServer/Runner bindings. Removes the plumbing for the warmup forks problem.
author shade
date Tue, 05 Nov 2013 12:12:27 +0100
parents 964327327052
children 31265352e637
files jmh-core/src/main/java/org/openjdk/jmh/link/BinaryLinkServer.java jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java
diffstat 2 files changed, 80 insertions(+), 93 deletions(-) [+]
line wrap: on
line diff
--- a/jmh-core/src/main/java/org/openjdk/jmh/link/BinaryLinkServer.java	Mon Nov 04 13:01:06 2013 +0100
+++ b/jmh-core/src/main/java/org/openjdk/jmh/link/BinaryLinkServer.java	Tue Nov 05 12:12:27 2013 +0100
@@ -31,10 +31,7 @@
 import org.openjdk.jmh.link.frames.ResultsFrame;
 import org.openjdk.jmh.logic.results.BenchResult;
 import org.openjdk.jmh.output.format.OutputFormat;
-import org.openjdk.jmh.runner.BenchmarkRecord;
 import org.openjdk.jmh.runner.options.Options;
-import org.openjdk.jmh.util.internal.Multimap;
-import org.openjdk.jmh.util.internal.TreeMultimap;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -50,17 +47,16 @@
 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;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
- * Accepts the OutputFormat calls from the network and forwards those to given local OutputFormat
+ * Accepts the binary data from the forked VM and pushes it to parent VM
+ * as appropriate. This server assumes there is only the one and only
+ * client at any given point of time.
  */
 public class BinaryLinkServer {
 
@@ -69,9 +65,8 @@
     private final Map<String, Method> methods;
     private final Set<String> forbidden;
     private final Acceptor acceptor;
-    private final List<Handler> registeredHandlers;
-    private final Multimap<BenchmarkRecord, BenchResult> results;
-    private volatile boolean ignoreNextResult;
+    private final AtomicReference<Handler> handler;
+    private final AtomicReference<BenchResult> result;
 
     public BinaryLinkServer(Options opts, OutputFormat out) throws IOException {
         this.opts = opts;
@@ -93,26 +88,25 @@
             }
         }
 
-        registeredHandlers = Collections.synchronizedList(new ArrayList<Handler>());
-        synchronized (this) {
-            results = new TreeMultimap<BenchmarkRecord, BenchResult>();
-        }
-
         acceptor = new Acceptor();
         acceptor.start();
+
+        handler = new AtomicReference<Handler>();
+        result = new AtomicReference<BenchResult>();
     }
 
     public void terminate() {
         acceptor.close();
 
-        for (Handler r : registeredHandlers) {
-            r.close();
+        Handler h = handler.getAndSet(null);
+        if (h != null) {
+            h.close();
         }
 
         try {
             acceptor.join();
-            for (Handler r : registeredHandlers) {
-                r.join();
+            if (h != null) {
+                h.join();
             }
         } catch (InterruptedException e) {
             // ignore
@@ -120,27 +114,25 @@
     }
 
     public void waitFinish() {
-        for (Iterator<Handler> iterator = registeredHandlers.iterator(); iterator.hasNext(); ) {
-            Handler r = iterator.next();
+        Handler h = handler.getAndSet(null);
+        if (h != null) {
             try {
-                r.join();
-                iterator.remove();
+                h.join();
             } catch (InterruptedException e) {
                 // ignore
             }
         }
     }
 
-    public Multimap<BenchmarkRecord, BenchResult> getResults() {
-        synchronized (this) {
-            return results;
+    public BenchResult getResult() {
+        BenchResult res = result.getAndSet(null);
+        if (res != null) {
+            return res;
+        } else {
+            throw new IllegalStateException("Acquiring the null result");
         }
     }
 
-    public void ignoreNextResult() {
-        ignoreNextResult = true;
-    }
-
     private final class Acceptor extends Thread {
 
         private final ServerSocket server;
@@ -155,7 +147,9 @@
                 while (!Thread.interrupted()) {
                     Socket clientSocket = server.accept();
                     Handler r = new Handler(clientSocket);
-                    registeredHandlers.add(r);
+                    if (!handler.compareAndSet(null, r)) {
+                        throw new IllegalStateException("The handler is already registered");
+                    }
                     r.start();
                 }
             } catch (SocketException e) {
@@ -250,12 +244,8 @@
         }
 
         private void handleResults(ResultsFrame obj) {
-            synchronized (this) {
-                if (!ignoreNextResult) {
-                    results.put(obj.getRecord(), obj.getResult());
-                } else {
-                    ignoreNextResult = false;
-                }
+            if (!result.compareAndSet(null, obj.getResult())) {
+                throw new IllegalStateException("The result has been already set.");
             }
         }
 
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java	Mon Nov 04 13:01:06 2013 +0100
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java	Tue Nov 05 12:12:27 2013 +0100
@@ -39,7 +39,7 @@
 import org.openjdk.jmh.runner.parameters.Defaults;
 import org.openjdk.jmh.util.AnnotationUtils;
 import org.openjdk.jmh.util.InputStreamDrainer;
-import org.openjdk.jmh.util.Utils;
+import org.openjdk.jmh.util.internal.HashMultimap;
 import org.openjdk.jmh.util.internal.Multimap;
 import org.openjdk.jmh.util.internal.TreeMultimap;
 
@@ -320,14 +320,56 @@
         return result;
     }
 
-    private Multimap<BenchmarkRecord, BenchResult> runSeparate(Set<BenchmarkRecord> benchmarksToFork) {
+    private Multimap<BenchmarkRecord, BenchResult> runSeparate(Set<BenchmarkRecord> benchmarks) {
+        Multimap<BenchmarkRecord, BenchResult> results = new HashMultimap<BenchmarkRecord, BenchResult>();
+
+        if (benchmarks.isEmpty()) {
+            return results;
+        }
+
         BinaryLinkServer server = null;
         try {
             server = new BinaryLinkServer(options, out);
-            for (BenchmarkRecord benchmark : benchmarksToFork) {
-                runSeparateMicroBenchmark(server, benchmark, server.getHost(), server.getPort());
+
+            for (BenchmarkRecord benchmark : benchmarks) {
+                // Running microbenchmark in separate JVM requires to read some options from annotations.
+                final Method benchmarkMethod = MicroBenchmarkHandlers.findBenchmarkMethod(benchmark);
+                Fork forkAnnotation = benchmarkMethod.getAnnotation(Fork.class);
+
+                String annJvmArgs = null;
+                if (forkAnnotation != null && AnnotationUtils.isSet(forkAnnotation.jvmArgs())) {
+                    annJvmArgs = forkAnnotation.jvmArgs().trim();
+                }
+
+                String annJvmArgsAppend = null;
+                if (forkAnnotation != null && AnnotationUtils.isSet(forkAnnotation.jvmArgsAppend())) {
+                    annJvmArgsAppend = forkAnnotation.jvmArgsAppend().trim();
+                }
+
+                String annJvmArgsPrepend = null;
+                if (forkAnnotation != null && AnnotationUtils.isSet(forkAnnotation.jvmArgsPrepend())) {
+                    annJvmArgsPrepend = forkAnnotation.jvmArgsPrepend().trim();
+                }
+
+                String[] commandString = getSeparateExecutionCommand(benchmark, annJvmArgs, annJvmArgsPrepend, annJvmArgsAppend, server.getHost(), server.getPort());
+
+                int forkCount = decideForks(options.getForkCount(), benchForks(benchmark));
+                int warmupForkCount = decideWarmupForks(options.getWarmupForkCount(), forkAnnotation);
+                if (warmupForkCount > 0) {
+                    out.verbosePrintln("Warmup forking " + warmupForkCount + " times using command: " + Arrays.toString(commandString));
+                    for (int i = 0; i < warmupForkCount; i++) {
+                        out.println("# Warmup Fork: " + (i + 1) + " of " + forkCount);
+                        doFork(server, commandString);
+                    }
+                }
+
+                out.verbosePrintln("Forking " + forkCount + " times using command: " + Arrays.toString(commandString));
+                for (int i = 0; i < forkCount; i++) {
+                    out.println("# Fork: " + (i + 1) + " of " + forkCount);
+                    BenchResult result = doFork(server, commandString);
+                    results.put(benchmark, result);
+                }
             }
-            return server.getResults();
         } catch (IOException e) {
             throw new IllegalStateException(e);
         } finally {
@@ -335,6 +377,8 @@
                 server.terminate();
             }
         }
+
+        return results;
     }
 
     /**
@@ -346,56 +390,7 @@
         return (fork != null) ? fork.value() : -1;
     }
 
-    /**
-     * Run the micro benchmark in a separate JVM process
-     *
-     * @param benchmark micro to run
-     * @param host host VM host
-     * @param port host VM port
-     */
-    private void runSeparateMicroBenchmark(BinaryLinkServer reader, BenchmarkRecord benchmark, String host, int port) {
-
-        // Running microbenchmark in separate JVM requires to read some options from annotations.
-
-        final Method benchmarkMethod = MicroBenchmarkHandlers.findBenchmarkMethod(benchmark);
-        Fork forkAnnotation = benchmarkMethod.getAnnotation(Fork.class);
-
-        String annJvmArgs = null;
-        if (forkAnnotation != null && AnnotationUtils.isSet(forkAnnotation.jvmArgs())) {
-            annJvmArgs = forkAnnotation.jvmArgs().trim();
-        }
-
-        String annJvmArgsAppend = null;
-        if (forkAnnotation != null && AnnotationUtils.isSet(forkAnnotation.jvmArgsAppend())) {
-            annJvmArgsAppend = forkAnnotation.jvmArgsAppend().trim();
-        }
-
-        String annJvmArgsPrepend = null;
-        if (forkAnnotation != null && AnnotationUtils.isSet(forkAnnotation.jvmArgsPrepend())) {
-            annJvmArgsPrepend = forkAnnotation.jvmArgsPrepend().trim();
-        }
-
-        String[] commandString = getSeparateExecutionCommand(benchmark, annJvmArgs, annJvmArgsPrepend, annJvmArgsAppend, host, port);
-
-        int forkCount = decideForks(options.getForkCount(), benchForks(benchmark));
-        int warmupForkCount = decideWarmupForks(options.getWarmupForkCount(), forkAnnotation);
-        if (warmupForkCount > 0) {
-            out.verbosePrintln("Warmup forking " + warmupForkCount + " times using command: " + Arrays.toString(commandString));
-            for (int i = 0; i < warmupForkCount; i++) {
-                out.println("# Warmup Fork: " + (i+1) + " of " + forkCount);
-                reader.ignoreNextResult();
-                doFork(reader, commandString);
-            }
-        }
-
-        out.verbosePrintln("Forking " + forkCount + " times using command: " + Arrays.toString(commandString));
-        for (int i = 0; i < forkCount; i++) {
-            out.println("# Fork: " + (i+1) + " of " + forkCount);
-            doFork(reader, commandString);
-        }
-    }
-
-    private void doFork(BinaryLinkServer reader, String[] commandString) {
+    private BenchResult doFork(BinaryLinkServer reader, String[] commandString) {
         try {
             Process p = Runtime.getRuntime().exec(commandString);
 
@@ -427,6 +422,8 @@
         } catch (InterruptedException ex) {
             out.exception(ex);
         }
+
+        return reader.getResult();
     }
 
     /**