changeset 1160:ea66b1770352

7901346: Profilers should be able to know the actual warmup/measurement durations
author shade
date Thu, 19 Mar 2015 18:54:37 +0300
parents 02fedaf27367
children 9d9c35e9cf04
files jmh-core-it/src/test/java/org/openjdk/jmh/it/ccontrol/LogConsumeProfiler.java jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/ItExternalProfiler.java jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/AbstractExternalProfiler.java jmh-core/src/main/java/org/openjdk/jmh/profile/AbstractPerfAsmProfiler.java jmh-core/src/main/java/org/openjdk/jmh/profile/ExternalProfiler.java jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfProfiler.java jmh-core/src/main/java/org/openjdk/jmh/profile/WinPerfAsmProfiler.java jmh-core/src/main/java/org/openjdk/jmh/results/BenchmarkResult.java jmh-core/src/main/java/org/openjdk/jmh/results/BenchmarkResultMetaData.java jmh-core/src/main/java/org/openjdk/jmh/results/BenchmarkTaskResult.java jmh-core/src/main/java/org/openjdk/jmh/results/HandlerResult.java jmh-core/src/main/java/org/openjdk/jmh/runner/BaseRunner.java jmh-core/src/main/java/org/openjdk/jmh/runner/BenchmarkHandler.java jmh-core/src/main/java/org/openjdk/jmh/runner/ForkedRunner.java jmh-core/src/main/java/org/openjdk/jmh/runner/IterationResultAcceptor.java jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java jmh-core/src/main/java/org/openjdk/jmh/runner/link/BinaryLinkClient.java jmh-core/src/main/java/org/openjdk/jmh/runner/link/BinaryLinkServer.java jmh-core/src/main/java/org/openjdk/jmh/runner/link/ResultMetadataFrame.java
diffstat 19 files changed, 313 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/jmh-core-it/src/test/java/org/openjdk/jmh/it/ccontrol/LogConsumeProfiler.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/ccontrol/LogConsumeProfiler.java	Thu Mar 19 18:54:37 2015 +0300
@@ -28,6 +28,7 @@
 import org.openjdk.jmh.profile.ExternalProfiler;
 import org.openjdk.jmh.results.AggregationPolicy;
 import org.openjdk.jmh.results.Aggregator;
+import org.openjdk.jmh.results.BenchmarkResult;
 import org.openjdk.jmh.results.Result;
 import org.openjdk.jmh.results.ResultRole;
 import org.openjdk.jmh.util.FileUtils;
@@ -58,7 +59,7 @@
     }
 
     @Override
-    public Collection<? extends Result> afterTrial(BenchmarkParams benchmarkParams, long pid, File stdOut, File stdErr) {
+    public Collection<? extends Result> afterTrial(BenchmarkResult br, long pid, File stdOut, File stdErr) {
         try {
             return Arrays.asList(
                     new LogConsumeResult("out", FileUtils.readAllLines(stdOut)),
--- a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/ItExternalProfiler.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/ItExternalProfiler.java	Thu Mar 19 18:54:37 2015 +0300
@@ -27,6 +27,7 @@
 import junit.framework.Assert;
 import org.openjdk.jmh.infra.BenchmarkParams;
 import org.openjdk.jmh.profile.ExternalProfiler;
+import org.openjdk.jmh.results.BenchmarkResult;
 import org.openjdk.jmh.results.Result;
 
 import java.io.File;
@@ -52,7 +53,7 @@
     }
 
     @Override
-    public Collection<? extends Result> afterTrial(BenchmarkParams benchmarkParams, long pid, File stdOut, File stdErr) {
+    public Collection<? extends Result> afterTrial(BenchmarkResult br, long pid, File stdOut, File stdErr) {
         Assert.assertFalse("Forked VM PID is not 0", pid == 0);
         return Collections.emptyList();
     }
--- a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/AbstractExternalProfiler.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/AbstractExternalProfiler.java	Thu Mar 19 18:54:37 2015 +0300
@@ -26,6 +26,7 @@
 
 import org.openjdk.jmh.infra.BenchmarkParams;
 import org.openjdk.jmh.profile.ExternalProfiler;
+import org.openjdk.jmh.results.BenchmarkResult;
 import org.openjdk.jmh.results.Result;
 
 import java.io.File;
@@ -75,7 +76,7 @@
     }
 
     @Override
-    public Collection<? extends Result> afterTrial(BenchmarkParams benchmarkParams, long pid, File stdOut, File stdErr) {
+    public Collection<? extends Result> afterTrial(BenchmarkResult br, long pid, File stdOut, File stdErr) {
         stop = System.nanoTime();
         try {
             TimeUnit.MILLISECONDS.sleep(100);
--- a/jmh-core/src/main/java/org/openjdk/jmh/profile/AbstractPerfAsmProfiler.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/profile/AbstractPerfAsmProfiler.java	Thu Mar 19 18:54:37 2015 +0300
@@ -25,8 +25,11 @@
 package org.openjdk.jmh.profile;
 
 import org.openjdk.jmh.infra.BenchmarkParams;
+import org.openjdk.jmh.infra.IterationParams;
 import org.openjdk.jmh.results.AggregationPolicy;
 import org.openjdk.jmh.results.Aggregator;
+import org.openjdk.jmh.results.BenchmarkResult;
+import org.openjdk.jmh.results.BenchmarkResultMetaData;
 import org.openjdk.jmh.results.Result;
 import org.openjdk.jmh.results.ResultRole;
 import org.openjdk.jmh.util.FileUtils;
@@ -227,8 +230,8 @@
     }
 
     @Override
-    public Collection<? extends Result> afterTrial(BenchmarkParams params, long pid, File stdOut, File stdErr) {
-        PerfResult result = processAssembly(params, stdOut, stdErr);
+    public Collection<? extends Result> afterTrial(BenchmarkResult br, long pid, File stdOut, File stdErr) {
+        PerfResult result = processAssembly(br, stdOut, stdErr);
 
         return Collections.singleton(result);
     }
@@ -263,7 +266,7 @@
      */
     protected abstract String perfBinaryExtension();
 
-    private PerfResult processAssembly(BenchmarkParams params, File stdOut, File stdErr) {
+    private PerfResult processAssembly(BenchmarkResult br, File stdOut, File stdErr) {
         /**
          * 1. Parse binary events.
          */
@@ -296,9 +299,16 @@
 
         long delayNs;
         if (DELAY_MSEC == -1) { // not set
-            delayNs = params.getWarmup().getCount() *
-                params.getWarmup().getTime().convertTo(TimeUnit.NANOSECONDS)
-                + TimeUnit.SECONDS.toNanos(1); // loosely account for the JVM lag
+            BenchmarkResultMetaData md = br.getMetadata();
+            if (md != null) {
+                // try to ask harness itself:
+                delayNs = TimeUnit.MILLISECONDS.toNanos(md.getMeasurementTime() - md.getStartTime());
+            } else {
+                // metadata is not available, let's make a guess:
+                IterationParams wp = br.getParams().getWarmup();
+                delayNs = wp.getCount() * wp.getTime().convertTo(TimeUnit.NANOSECONDS)
+                        + TimeUnit.SECONDS.toNanos(1); // loosely account for the JVM lag
+            }
         } else {
             delayNs = TimeUnit.MILLISECONDS.toNanos(DELAY_MSEC);
         }
@@ -526,7 +536,7 @@
          */
         if (SAVE_PERF_OUTPUT) {
             String target = (SAVE_PERF_OUTPUT_TO_FILE == null) ?
-                SAVE_PERF_OUTPUT_TO + "/" + params.id() + ".perf" :
+                SAVE_PERF_OUTPUT_TO + "/" + br.getParams().id() + ".perf" :
                 SAVE_PERF_OUTPUT_TO_FILE;
             try {
                 FileUtils.copy(perfParsedData, target);
@@ -541,7 +551,7 @@
          */
         if (SAVE_PERF_BIN_OUTPUT) {
             String target = (SAVE_PERF_BIN_OUTPUT_TO_FILE == null) ?
-                SAVE_PERF_BIN_OUTPUT_TO + "/" + params.id() + perfBinaryExtension() :
+                SAVE_PERF_BIN_OUTPUT_TO + "/" + br.getParams().id() + perfBinaryExtension() :
                 SAVE_PERF_BIN_OUTPUT_TO_FILE;
             try {
                 FileUtils.copy(perfBinData, target);
@@ -556,7 +566,7 @@
          */
         if (SAVE_LOG_OUTPUT) {
             String target = (SAVE_LOG_OUTPUT_TO_FILE == null) ?
-                SAVE_LOG_OUTPUT_TO + "/" + params.id() + ".log" :
+                SAVE_LOG_OUTPUT_TO + "/" + br.getParams().id() + ".log" :
                 SAVE_LOG_OUTPUT_TO_FILE;
             FileOutputStream asm;
             try {
--- a/jmh-core/src/main/java/org/openjdk/jmh/profile/ExternalProfiler.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/profile/ExternalProfiler.java	Thu Mar 19 18:54:37 2015 +0300
@@ -25,6 +25,7 @@
 package org.openjdk.jmh.profile;
 
 import org.openjdk.jmh.infra.BenchmarkParams;
+import org.openjdk.jmh.results.BenchmarkResult;
 import org.openjdk.jmh.results.Result;
 
 import java.io.File;
@@ -67,12 +68,12 @@
      * Run this code after the trial is done. This method will execute
      * after benchmark JVM had stopped.
      *
-     * @param benchmarkParams benchmark parameters used for current launch
+     * @param br benchmark result that was the result of the trial
      * @param stdOut file containing the standard output from the benchmark JVM
      * @param stdErr file containing the standard error from the benchmark JVM
      * @return profiler results
      */
-    Collection<? extends Result> afterTrial(BenchmarkParams benchmarkParams, long pid, File stdOut, File stdErr);
+    Collection<? extends Result> afterTrial(BenchmarkResult br, long pid, File stdOut, File stdErr);
 
     /**
      * If target VM communicates with profiler with standard output, this method
--- a/jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfProfiler.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfProfiler.java	Thu Mar 19 18:54:37 2015 +0300
@@ -27,6 +27,7 @@
 import org.openjdk.jmh.infra.BenchmarkParams;
 import org.openjdk.jmh.results.AggregationPolicy;
 import org.openjdk.jmh.results.Aggregator;
+import org.openjdk.jmh.results.BenchmarkResult;
 import org.openjdk.jmh.results.Result;
 import org.openjdk.jmh.results.ResultRole;
 import org.openjdk.jmh.util.FileUtils;
@@ -81,7 +82,7 @@
     }
 
     @Override
-    public Collection<? extends Result> afterTrial(BenchmarkParams params, long pid, File stdOut, File stdErr) {
+    public Collection<? extends Result> afterTrial(BenchmarkResult br, long pid, File stdOut, File stdErr) {
         PerfResult result = process(stdOut, stdErr);
         return Collections.singleton(result);
     }
--- a/jmh-core/src/main/java/org/openjdk/jmh/profile/WinPerfAsmProfiler.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/profile/WinPerfAsmProfiler.java	Thu Mar 19 18:54:37 2015 +0300
@@ -25,6 +25,7 @@
 package org.openjdk.jmh.profile;
 
 import org.openjdk.jmh.infra.BenchmarkParams;
+import org.openjdk.jmh.results.BenchmarkResult;
 import org.openjdk.jmh.results.Result;
 import org.openjdk.jmh.util.Deduplicator;
 import org.openjdk.jmh.util.FileUtils;
@@ -71,7 +72,7 @@
  * argument, but it's sole purpose is to start profiling before the process is started, so that one can be sure that
  * none events generated by this process are missed. It does not filter events from other processes anyhow. For this
  * reason, this profiler doesn't alter forked JVM startup command. Instead, it starts {@code xperf} recording in
- * {@link #beforeTrial(BenchmarkParams)} method, and stops in {@link #afterTrial(BenchmarkParams, long, File, File)}. This
+ * {@link #beforeTrial(BenchmarkParams)} method, and stops in {@link ExternalProfiler#afterTrial(org.openjdk.jmh.results.BenchmarkResult, long, java.io.File, java.io.File)}. This
  * leaves possibility to run this profiler in conjunction with some other profiler requiring startup command
  * alteration.
  * <p>
@@ -161,12 +162,12 @@
     }
 
     @Override
-    public Collection<? extends Result> afterTrial(BenchmarkParams params, long pid, File stdOut, File stdErr) {
+    public Collection<? extends Result> afterTrial(BenchmarkResult br, long pid, File stdOut, File stdErr) {
         if (pid == 0) {
             throw new IllegalStateException(label() + " needs the forked VM PID, but it is not initialized.");
         }
         this.pid = String.valueOf(pid);
-        return super.afterTrial(params, pid, stdOut, stdErr);
+        return super.afterTrial(br, pid, stdOut, stdErr);
     }
 
     @Override
--- a/jmh-core/src/main/java/org/openjdk/jmh/results/BenchmarkResult.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/results/BenchmarkResult.java	Thu Mar 19 18:54:37 2015 +0300
@@ -47,13 +47,26 @@
     private final Collection<IterationResult> iterationResults;
     private final Multimap<String, Result> benchmarkResults;
     private final BenchmarkParams params;
+    private final BenchmarkResultMetaData metadata;
 
     public BenchmarkResult(BenchmarkParams params, Collection<IterationResult> data) {
+        this(params, data, null);
+    }
+
+    public BenchmarkResult(BenchmarkParams params, Collection<IterationResult> data, BenchmarkResultMetaData md) {
+        this.metadata = md;
         this.benchmarkResults = new HashMultimap<String, Result>();
         this.iterationResults = data;
         this.params = params;
     }
 
+    /**
+     * @return returns the benchmark metadata, "null" otherwise
+     */
+    public BenchmarkResultMetaData getMetadata() {
+        return metadata;
+    }
+
     public void addBenchmarkResult(Result r) {
         benchmarkResults.put(r.getLabel(), r);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/results/BenchmarkResultMetaData.java	Thu Mar 19 18:54:37 2015 +0300
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, 2015, 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.results;
+
+import java.io.Serializable;
+
+public class BenchmarkResultMetaData implements Serializable {
+
+    private final long startTime;
+    private final long measurementTime;
+    private final long stopTime;
+    private final long warmupOps;
+    private final long measurementOps;
+
+    public BenchmarkResultMetaData(long startTime, long measurementTime, long stopTime, long warmupOps, long measurementOps) {
+        this.startTime = startTime;
+        this.measurementTime = measurementTime;
+        this.stopTime = stopTime;
+        this.warmupOps = warmupOps;
+        this.measurementOps = measurementOps;
+    }
+
+    public long getStartTime() {
+        return startTime;
+    }
+
+    public long getMeasurementTime() {
+        return measurementTime;
+    }
+
+    public long getStopTime() {
+        return stopTime;
+    }
+
+    public long getMeasurementOps() {
+        return measurementOps;
+    }
+
+    public long getWarmupOps() {
+        return warmupOps;
+    }
+}
--- a/jmh-core/src/main/java/org/openjdk/jmh/results/BenchmarkTaskResult.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/results/BenchmarkTaskResult.java	Thu Mar 19 18:54:37 2015 +0300
@@ -54,4 +54,12 @@
     public Collection<Result> getResults() {
         return results;
     }
+
+    public long getAllOps() {
+        return allOperations;
+    }
+
+    public long getMeasuredOps() {
+        return measuredOperations;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/results/HandlerResult.java	Thu Mar 19 18:54:37 2015 +0300
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, 2015, 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.results;
+
+import org.openjdk.jmh.infra.BenchmarkParams;
+import org.openjdk.jmh.infra.IterationParams;
+
+import java.util.Collection;
+
+public class HandlerResult {
+
+    private final IterationResult res;
+    private volatile long allOps;
+    private volatile long measuredOps;
+
+    public HandlerResult(BenchmarkParams benchmarkParams, IterationParams params) {
+        this.res = new IterationResult(benchmarkParams, params);
+    }
+
+    public void add(Result r) {
+        res.addResult(r);
+    }
+
+    public IterationResult getResult() {
+        return res;
+    }
+
+    public void addResults(Collection<? extends Result> rs) {
+        res.addResults(rs);
+    }
+
+    public void addMeasuredOps(long v) {
+        measuredOps += v;
+    }
+
+    public void addAllOps(long v) {
+        allOps += v;
+    }
+
+    public long getMeasuredOps() {
+        return measuredOps;
+    }
+
+    public long getAllOps() {
+        return allOps;
+    }
+}
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/BaseRunner.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/BaseRunner.java	Thu Mar 19 18:54:37 2015 +0300
@@ -28,6 +28,8 @@
 import org.openjdk.jmh.infra.BenchmarkParams;
 import org.openjdk.jmh.infra.IterationParams;
 import org.openjdk.jmh.results.BenchmarkResult;
+import org.openjdk.jmh.results.BenchmarkResultMetaData;
+import org.openjdk.jmh.results.HandlerResult;
 import org.openjdk.jmh.results.IterationResult;
 import org.openjdk.jmh.runner.format.OutputFormat;
 import org.openjdk.jmh.runner.options.Options;
@@ -103,18 +105,24 @@
             out.println("# Fork: N/A, test runs in the existing VM");
 
             final List<IterationResult> res = new ArrayList<IterationResult>();
+            final List<BenchmarkResultMetaData> mds = new ArrayList<BenchmarkResultMetaData>();
 
             IterationResultAcceptor acceptor = new IterationResultAcceptor() {
                 @Override
                 public void accept(IterationResult iterationData) {
                     res.add(iterationData);
                 }
+
+                @Override
+                public void acceptMeta(BenchmarkResultMetaData md) {
+                    mds.add(md);
+                }
             };
 
             doSingle(params, mode, acceptor);
 
             if (!res.isEmpty()) {
-                BenchmarkResult br = new BenchmarkResult(params, res);
+                BenchmarkResult br = new BenchmarkResult(params, res, mds.get(0));
                 results.put(params, br);
                 out.endBenchmark(br);
             }
@@ -240,6 +248,11 @@
     }
 
     protected void runBenchmark(BenchmarkParams benchParams, BenchmarkHandler handler, IterationResultAcceptor acceptor) {
+        long startTime = System.currentTimeMillis();
+
+        long allWarmup = 0;
+        long allMeasurement = 0;
+
         // warmup
         IterationParams wp = benchParams.getWarmup();
         for (int i = 1; i <= wp.getCount(); i++) {
@@ -250,10 +263,14 @@
 
             out.iteration(benchParams, wp, i);
             boolean isLastIteration = (benchParams.getMeasurement().getCount() == 0);
-            IterationResult iterData = handler.runIteration(benchParams, wp, isLastIteration);
-            out.iterationResult(benchParams, wp, i, iterData);
+            HandlerResult hr = handler.runIteration(benchParams, wp, isLastIteration);
+            out.iterationResult(benchParams, wp, i, hr.getResult());
+
+            allWarmup += hr.getAllOps();
         }
 
+        long measurementTime = System.currentTimeMillis();
+
         // measurement
         IterationParams mp = benchParams.getMeasurement();
         for (int i = 1; i <= mp.getCount(); i++) {
@@ -266,13 +283,25 @@
             out.iteration(benchParams, mp, i);
 
             boolean isLastIteration = (i == mp.getCount());
-            IterationResult iterData = handler.runIteration(benchParams, mp, isLastIteration);
-            out.iterationResult(benchParams, mp, i, iterData);
+            HandlerResult hr = handler.runIteration(benchParams, mp, isLastIteration);
+            out.iterationResult(benchParams, mp, i, hr.getResult());
+
+            allMeasurement += hr.getAllOps();
 
             if (acceptor != null) {
-                acceptor.accept(iterData);
+                acceptor.accept(hr.getResult());
             }
         }
+
+        long stopTime = System.currentTimeMillis();
+
+        BenchmarkResultMetaData md = new BenchmarkResultMetaData(
+                startTime, measurementTime, stopTime,
+                allWarmup, allMeasurement);
+
+        if (acceptor != null) {
+            acceptor.acceptMeta(md);
+        }
     }
 
     /**
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/BenchmarkHandler.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/BenchmarkHandler.java	Thu Mar 19 18:54:37 2015 +0300
@@ -31,7 +31,7 @@
 import org.openjdk.jmh.profile.Profiler;
 import org.openjdk.jmh.profile.ProfilerFactory;
 import org.openjdk.jmh.results.BenchmarkTaskResult;
-import org.openjdk.jmh.results.IterationResult;
+import org.openjdk.jmh.results.HandlerResult;
 import org.openjdk.jmh.runner.format.OutputFormat;
 import org.openjdk.jmh.runner.options.Options;
 import org.openjdk.jmh.runner.options.TimeValue;
@@ -282,7 +282,7 @@
         }
     }
 
-    protected void stopProfilers(BenchmarkParams benchmarkParams, IterationParams iterationParams, IterationResult iterationResults) {
+    protected void stopProfilers(BenchmarkParams benchmarkParams, IterationParams iterationParams, HandlerResult iterationResults) {
         // stop profilers
         for (InternalProfiler prof : profilersRev) {
             try {
@@ -324,7 +324,7 @@
      * @param last    Should this iteration considered to be the last
      * @return IterationResult
      */
-    public IterationResult runIteration(BenchmarkParams benchmarkParams, IterationParams params, boolean last) {
+    public HandlerResult runIteration(BenchmarkParams benchmarkParams, IterationParams params, boolean last) {
         int numThreads = benchmarkParams.getThreads();
         TimeValue runtime = params.getTime();
 
@@ -332,7 +332,7 @@
         CountDownLatch preTearDownBarrier = new CountDownLatch(numThreads);
 
         // result object to accumulate the results in
-        IterationResult iterationResults = new IterationResult(benchmarkParams, params);
+        HandlerResult iterationResults = new HandlerResult(benchmarkParams, params);
 
         InfraControl control = new InfraControl(benchmarkParams, params, preSetupBarrier, preTearDownBarrier, last);
 
@@ -417,7 +417,10 @@
         // all the results ready without the exceptions.
         for (Future<BenchmarkTaskResult> fr : results.values()) {
             try {
-                iterationResults.addResults(fr.get().getResults());
+                BenchmarkTaskResult btr = fr.get();
+                iterationResults.addAllOps(btr.getAllOps());
+                iterationResults.addMeasuredOps(btr.getMeasuredOps());
+                iterationResults.addResults(btr.getResults());
             } catch (InterruptedException ex) {
                 throw new IllegalStateException("Impossible to be here");
             } catch (ExecutionException ex) {
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/ForkedRunner.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/ForkedRunner.java	Thu Mar 19 18:54:37 2015 +0300
@@ -24,6 +24,7 @@
  */
 package org.openjdk.jmh.runner;
 
+import org.openjdk.jmh.results.BenchmarkResultMetaData;
 import org.openjdk.jmh.results.IterationResult;
 import org.openjdk.jmh.runner.link.BinaryLinkClient;
 import org.openjdk.jmh.runner.options.Options;
@@ -56,6 +57,16 @@
                         throw new SavedIOException(e);
                     }
                 }
+
+                @Override
+                public void acceptMeta(BenchmarkResultMetaData md) {
+                    try {
+                        link.pushResultMetadata(md);
+                    } catch (IOException e) {
+                        // link had probably failed
+                        throw new SavedIOException(e);
+                    }
+                }
             };
 
             runBenchmarksForked(actionPlan, acceptor);
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/IterationResultAcceptor.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/IterationResultAcceptor.java	Thu Mar 19 18:54:37 2015 +0300
@@ -24,8 +24,11 @@
  */
 package org.openjdk.jmh.runner;
 
+import org.openjdk.jmh.results.BenchmarkResultMetaData;
 import org.openjdk.jmh.results.IterationResult;
 
 interface IterationResultAcceptor {
     void accept(IterationResult iterationData);
+
+    void acceptMeta(BenchmarkResultMetaData md);
 }
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java	Thu Mar 19 18:54:37 2015 +0300
@@ -32,6 +32,7 @@
 import org.openjdk.jmh.profile.Profiler;
 import org.openjdk.jmh.profile.ProfilerFactory;
 import org.openjdk.jmh.results.BenchmarkResult;
+import org.openjdk.jmh.results.BenchmarkResultMetaData;
 import org.openjdk.jmh.results.IterationResult;
 import org.openjdk.jmh.results.Result;
 import org.openjdk.jmh.results.RunResult;
@@ -657,13 +658,14 @@
                 if (!result.isEmpty()) {
                     long pid = server.getClientPid();
 
-                    BenchmarkResult br = new BenchmarkResult(params, result);
+                    BenchmarkResultMetaData md = server.getMetadata();
+                    BenchmarkResult br = new BenchmarkResult(params, result, md);
 
                     if (!profilersRev.isEmpty()) {
                         out.print("# Processing profiler results: ");
                         for (ExternalProfiler profiler : profilersRev) {
                             out.print(profiler.label() + " ");
-                            for (Result profR : profiler.afterTrial(params, pid, stdOut, stdErr)) {
+                            for (Result profR : profiler.afterTrial(br, pid, stdOut, stdErr)) {
                                 br.addBenchmarkResult(profR);
                             }
                         }
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/link/BinaryLinkClient.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/link/BinaryLinkClient.java	Thu Mar 19 18:54:37 2015 +0300
@@ -24,6 +24,7 @@
  */
 package org.openjdk.jmh.runner.link;
 
+import org.openjdk.jmh.results.BenchmarkResultMetaData;
 import org.openjdk.jmh.results.IterationResult;
 import org.openjdk.jmh.runner.ActionPlan;
 import org.openjdk.jmh.runner.BenchmarkException;
@@ -178,6 +179,10 @@
         pushFrame(new ExceptionFrame(error));
     }
 
+    public void pushResultMetadata(BenchmarkResultMetaData res) throws IOException {
+        pushFrame(new ResultMetadataFrame(res));
+    }
+
     public PrintStream getOutStream() {
         return streamOut;
     }
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/link/BinaryLinkServer.java	Thu Mar 19 16:51:09 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/link/BinaryLinkServer.java	Thu Mar 19 18:54:37 2015 +0300
@@ -24,6 +24,7 @@
  */
 package org.openjdk.jmh.runner.link;
 
+import org.openjdk.jmh.results.BenchmarkResultMetaData;
 import org.openjdk.jmh.results.IterationResult;
 import org.openjdk.jmh.runner.ActionPlan;
 import org.openjdk.jmh.runner.BenchmarkException;
@@ -72,6 +73,7 @@
     private final Acceptor acceptor;
     private final AtomicReference<Handler> handler;
     private final AtomicReference<List<IterationResult>> results;
+    private final AtomicReference<BenchmarkResultMetaData> metadata;
     private final AtomicReference<BenchmarkException> exception;
     private final AtomicReference<ActionPlan> plan;
     private volatile long clientPid;
@@ -100,6 +102,7 @@
         acceptor.start();
 
         handler = new AtomicReference<Handler>();
+        metadata = new AtomicReference<BenchmarkResultMetaData>();
         results = new AtomicReference<List<IterationResult>>(new ArrayList<IterationResult>());
         exception = new AtomicReference<BenchmarkException>();
         plan = new AtomicReference<ActionPlan>();
@@ -147,6 +150,10 @@
         }
     }
 
+    public BenchmarkResultMetaData getMetadata() {
+        return metadata.getAndSet(null);
+    }
+
     public void setPlan(ActionPlan actionPlan) {
         this.plan.set(actionPlan);
     }
@@ -300,6 +307,9 @@
                     if (obj instanceof OutputFrame) {
                         handleOutput((OutputFrame) obj);
                     }
+                    if (obj instanceof ResultMetadataFrame) {
+                        handleResultMetadata((ResultMetadataFrame) obj);
+                    }
                     if (obj instanceof FinishingFrame) {
                         // close the streams
                         break;
@@ -317,6 +327,12 @@
             }
         }
 
+        private void handleResultMetadata(ResultMetadataFrame obj) {
+            if (!metadata.compareAndSet(null, obj.getMD())) {
+                throw new IllegalStateException("Metadata had been already received");
+            }
+        }
+
         private void handleOutput(OutputFrame obj) {
             try {
                 switch (obj.getType()) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/link/ResultMetadataFrame.java	Thu Mar 19 18:54:37 2015 +0300
@@ -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.runner.link;
+
+import org.openjdk.jmh.results.BenchmarkResultMetaData;
+
+import java.io.Serializable;
+
+class ResultMetadataFrame implements Serializable {
+    private static final long serialVersionUID = -5627086531281515824L;
+
+    private final BenchmarkResultMetaData md;
+
+    public ResultMetadataFrame(BenchmarkResultMetaData md) {
+        this.md = md;
+    }
+
+    public BenchmarkResultMetaData getMD() {
+        return md;
+    }
+}