changeset 187:5aa156267caa

Asymmetric benchmarks to treat @Threads(0) properly. (Plumbing fix, should redo the entire thing cleaner)
author shade
date Thu, 26 Sep 2013 20:17:25 +0400
parents 78de3267fb5a
children 90631ae36974
files jmh-core-it/src/test/java/org/openjdk/jmh/it/asymm/ExactThreadCountTest.java jmh-core-it/src/test/java/org/openjdk/jmh/it/asymm/Zero1ThreadCountTest.java jmh-core-it/src/test/java/org/openjdk/jmh/it/asymm/Zero2ThreadCountTest.java jmh-core/src/main/java/org/openjdk/jmh/processor/internal/GenerateMicroBenchmarkProcessor.java
diffstat 4 files changed, 300 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/asymm/ExactThreadCountTest.java	Thu Sep 26 20:17:25 2013 +0400
@@ -0,0 +1,96 @@
+/*
+ * 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.it.asymm;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.openjdk.jmh.Main;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.GenerateMicroBenchmark;
+import org.openjdk.jmh.annotations.Group;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Threads;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.it.Fixtures;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.All)
+@Warmup(iterations = 0)
+@Measurement(iterations = 5, time = 100, timeUnit = TimeUnit.MILLISECONDS)
+@State(Scope.Benchmark)
+public class ExactThreadCountTest {
+
+    private Set<Thread> test1threads = Collections.synchronizedSet(new HashSet<Thread>());
+    private Set<Thread> test2threads = Collections.synchronizedSet(new HashSet<Thread>());
+
+    @TearDown
+    public void check() {
+        Assert.assertEquals(1, test1threads.size());
+        Assert.assertEquals(2, test2threads.size());
+    }
+
+    @GenerateMicroBenchmark
+    @Group("test")
+    @Threads(1)
+    public void test1() {
+        test1threads.add(Thread.currentThread());
+        Fixtures.work();
+    }
+
+    @GenerateMicroBenchmark
+    @Group("test")
+    @Threads(2)
+    public void test2() {
+        test2threads.add(Thread.currentThread());
+        Fixtures.work();
+    }
+
+    @Test
+    public void invokeCL() {
+        Main.testMain(Fixtures.getTestMask(this.getClass()) + ".*test" + " -foe");
+    }
+
+    @Test
+    public void invokeAPI() throws RunnerException {
+        Options opt = new OptionsBuilder()
+                .include(Fixtures.getTestMask(this.getClass())+".*test")
+                .failOnError(true)
+                .build();
+        new Runner(opt).run();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/asymm/Zero1ThreadCountTest.java	Thu Sep 26 20:17:25 2013 +0400
@@ -0,0 +1,96 @@
+/*
+ * 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.it.asymm;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.openjdk.jmh.Main;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.GenerateMicroBenchmark;
+import org.openjdk.jmh.annotations.Group;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Threads;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.it.Fixtures;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.All)
+@Warmup(iterations = 0)
+@Measurement(iterations = 5, time = 100, timeUnit = TimeUnit.MILLISECONDS)
+@State(Scope.Benchmark)
+public class Zero1ThreadCountTest {
+
+    private Set<Thread> test1threads = Collections.synchronizedSet(new HashSet<Thread>());
+    private Set<Thread> test2threads = Collections.synchronizedSet(new HashSet<Thread>());
+
+    @TearDown
+    public void check() {
+        Assert.assertEquals(0, test1threads.size());
+        Assert.assertEquals(2, test2threads.size());
+    }
+
+    @GenerateMicroBenchmark
+    @Group("test")
+    @Threads(0)
+    public void test1() {
+        test1threads.add(Thread.currentThread());
+        Fixtures.work();
+    }
+
+    @GenerateMicroBenchmark
+    @Group("test")
+    @Threads(2)
+    public void test2() {
+        test2threads.add(Thread.currentThread());
+        Fixtures.work();
+    }
+
+    @Test
+    public void invokeCL() {
+        Main.testMain(Fixtures.getTestMask(this.getClass()) + ".*test" + " -foe");
+    }
+
+    @Test
+    public void invokeAPI() throws RunnerException {
+        Options opt = new OptionsBuilder()
+                .include(Fixtures.getTestMask(this.getClass())+".*test")
+                .failOnError(true)
+                .build();
+        new Runner(opt).run();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/asymm/Zero2ThreadCountTest.java	Thu Sep 26 20:17:25 2013 +0400
@@ -0,0 +1,96 @@
+/*
+ * 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.it.asymm;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.openjdk.jmh.Main;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.GenerateMicroBenchmark;
+import org.openjdk.jmh.annotations.Group;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Threads;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.it.Fixtures;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.All)
+@Warmup(iterations = 0)
+@Measurement(iterations = 5, time = 100, timeUnit = TimeUnit.MILLISECONDS)
+@State(Scope.Benchmark)
+public class Zero2ThreadCountTest {
+
+    private Set<Thread> test1threads = Collections.synchronizedSet(new HashSet<Thread>());
+    private Set<Thread> test2threads = Collections.synchronizedSet(new HashSet<Thread>());
+
+    @TearDown
+    public void check() {
+        Assert.assertEquals(1, test1threads.size());
+        Assert.assertEquals(0, test2threads.size());
+    }
+
+    @GenerateMicroBenchmark
+    @Group("test")
+    @Threads(1)
+    public void test1() {
+        test1threads.add(Thread.currentThread());
+        Fixtures.work();
+    }
+
+    @GenerateMicroBenchmark
+    @Group("test")
+    @Threads(0)
+    public void test2() {
+        test2threads.add(Thread.currentThread());
+        Fixtures.work();
+    }
+
+    @Test
+    public void invokeCL() {
+        Main.testMain(Fixtures.getTestMask(this.getClass()) + ".*test" + " -foe");
+    }
+
+    @Test
+    public void invokeAPI() throws RunnerException {
+        Options opt = new OptionsBuilder()
+                .include(Fixtures.getTestMask(this.getClass())+".*test")
+                .failOnError(true)
+                .build();
+        new Runner(opt).run();
+    }
+
+}
--- a/jmh-core/src/main/java/org/openjdk/jmh/processor/internal/GenerateMicroBenchmarkProcessor.java	Thu Sep 26 20:03:59 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/processor/internal/GenerateMicroBenchmarkProcessor.java	Thu Sep 26 20:17:25 2013 +0400
@@ -661,12 +661,13 @@
 
         methodProlog(writer, methodGroup);
 
+        boolean isSingleMethod = (methodGroup.methods().size() == 1);
         int threadTally = 0;
 
         for (Element method : methodGroup.methods()) {
 
             // determine the sibling bounds
-            int threads = Math.max(1, methodGroup.getMethodThreads(method));
+            int threads = Math.max(isSingleMethod ? 1 : 0, methodGroup.getMethodThreads(method));
             int loId = threadTally;
             int hiId = threadTally + threads;
             threadTally = hiId;
@@ -717,7 +718,7 @@
             // iteration prolog
             iterationEpilog(writer, 3, method, states);
 
-            ResultRole mode = (methodGroup.methods().size() == 1) ? ResultRole.PRIMARY : ResultRole.BOTH;
+            ResultRole mode = isSingleMethod ? ResultRole.PRIMARY : ResultRole.BOTH;
             writer.println(ident(3) + "return new OpsPerTimeUnit(ResultRole." + mode + ", \"" + method.getSimpleName() + "\", res.operations, res.time, (control.timeUnit != null) ? control.timeUnit : TimeUnit." + timeUnit + ");");
             writer.println(ident(2) + "} else");
         }
@@ -752,11 +753,12 @@
 
         methodProlog(writer, methodGroup);
 
+        boolean isSingleMethod = (methodGroup.methods().size() == 1);
         int threadTally = 0;
         for (Element method : methodGroup.methods()) {
 
             // determine the sibling bounds
-            int threads = Math.max(1, methodGroup.getMethodThreads(method));
+            int threads = Math.max(isSingleMethod ? 1 : 0, methodGroup.getMethodThreads(method));
             int loId = threadTally;
             int hiId = threadTally + threads;
             threadTally = hiId;
@@ -806,7 +808,7 @@
 
             iterationEpilog(writer, 3, method, states);
 
-            ResultRole mode = (methodGroup.methods().size() == 1) ? ResultRole.PRIMARY : ResultRole.BOTH;
+            ResultRole mode = isSingleMethod ? ResultRole.PRIMARY : ResultRole.BOTH;
             writer.println(ident(3) + "return new AverageTimePerOp(ResultRole." + mode + ", \"" + method.getSimpleName() + "\", res.operations, res.time, (control.timeUnit != null) ? control.timeUnit : TimeUnit." + timeUnit + ");");
             writer.println(ident(2) + "} else");
         }
@@ -862,10 +864,11 @@
 
         methodProlog(writer, methodGroup);
 
+        boolean isSingleMethod = (methodGroup.methods().size() == 1);
         int threadTally = 0;
         for (Element method : methodGroup.methods()) {
             // determine the sibling bounds
-            int threads = Math.max(1, methodGroup.getMethodThreads(method));
+            int threads = Math.max(isSingleMethod ? 1 : 0, methodGroup.getMethodThreads(method));
             int loId = threadTally;
             int hiId = threadTally + threads;
             threadTally = hiId;
@@ -954,7 +957,7 @@
 
             writer.println("        } while(!control.isDone);");
 
-            ResultRole mode = (methodGroup.methods().size() == 1) ? ResultRole.PRIMARY : ResultRole.BOTH;
+            ResultRole mode = isSingleMethod ? ResultRole.PRIMARY : ResultRole.BOTH;
             writer.println("        return new SampleTimePerOp(ResultRole." + mode + ", \"" + method.getSimpleName() + "\", buffer, (control.timeUnit != null) ? control.timeUnit : TimeUnit." + timeUnit + ");");
             writer.println("    }");
             writer.println();
@@ -968,11 +971,12 @@
 
         writer.println(ident(2) + "long realTime = 0;");
 
+        boolean isSingleMethod = (methodGroup.methods().size() == 1);
         int threadTally = 0;
         for (Element method : methodGroup.methods()) {
 
             // determine the sibling bounds
-            int threads = Math.max(1, methodGroup.getMethodThreads(method));
+            int threads = Math.max(isSingleMethod ? 1 : 0, methodGroup.getMethodThreads(method));
             int loId = threadTally;
             int hiId = threadTally + threads;
             threadTally = hiId;
@@ -991,7 +995,7 @@
 
             iterationEpilog(writer, 3, method, states);
 
-            ResultRole mode = (methodGroup.methods().size() == 1) ? ResultRole.PRIMARY : ResultRole.BOTH;
+            ResultRole mode = isSingleMethod ? ResultRole.PRIMARY : ResultRole.BOTH;
             writer.println(ident(3) + "return new SingleShotTime(ResultRole." + mode + ",\"" + method.getSimpleName() + "\", (realTime > 0) ? realTime : (time2 - time1), (control.timeUnit != null) ? control.timeUnit : TimeUnit." + timeUnit + ");");
             writer.println(ident(2) + "} else");
         }