changeset 1:06dbd0d0fe69

CLI interface, and synchronizers rootset benchmark.
author shade
date Thu, 24 Nov 2016 10:41:10 +0100
parents f8496889e1ac
children 89dd4770a404
files src/main/java/org/openjdk/gcbench/GCBench.java src/main/java/org/openjdk/gcbench/roots/Synchronizers.java src/main/java/org/openjdk/gcbench/wip/Synchronizers.java
diffstat 3 files changed, 261 insertions(+), 116 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/org/openjdk/gcbench/GCBench.java	Wed Nov 23 16:04:53 2016 +0100
+++ b/src/main/java/org/openjdk/gcbench/GCBench.java	Thu Nov 24 10:41:10 2016 +0100
@@ -1,9 +1,13 @@
 package org.openjdk.gcbench;
 
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+import joptsimple.OptionSpec;
 import org.openjdk.gcbench.alloc.ratelimited.Objects;
 import org.openjdk.gcbench.alloc.ratelimited.PrimArray;
 import org.openjdk.gcbench.alloc.ratelimited.RefArray;
 import org.openjdk.gcbench.fragger.ArrayFragger;
+import org.openjdk.gcbench.roots.Synchronizers;
 import org.openjdk.gcbench.util.Dummy;
 import org.openjdk.jmh.annotations.Threads;
 import org.openjdk.jmh.profile.GCProfiler;
@@ -12,31 +16,190 @@
 import org.openjdk.jmh.results.RunResult;
 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 org.openjdk.jmh.runner.options.TimeValue;
-import org.openjdk.jmh.runner.options.VerboseMode;
+import org.openjdk.jmh.runner.options.*;
+import org.openjdk.jmh.util.Utils;
+import org.openjdk.jmh.util.Version;
 
+import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 
 public class GCBench {
 
     private final PrintWriter pw;
-    private final Options baseOpts;
+    private Options baseOpts;
     private int maxHeapMB;
+    private List<Test> tests;
 
-    public static void main(String... args) throws RunnerException {
-        GCBench bench = new GCBench();
+    public static void main(String... args) throws RunnerException, IOException {
+        GCBench bench = new GCBench(args);
         bench.run();
     }
 
-    private void run() throws RunnerException {
-        maxHeapMB = calibrateMaxHeap();
+    public GCBench(String[] args) throws RunnerException, IOException {
+        pw = new PrintWriter(System.out, true);
+
+        pw.println("GC Benchmarks Suite");
+        pw.println("----------------------------------------------------------------------------------------------------------");
+        pw.println();
+
+        pw.println("# " + Version.getVersion());
+        pw.println("# " + Utils.getCurrentJvmVersion());
+        pw.println("# " + Utils.getCurrentOSVersion());
+        pw.println();
+
+        Utils.reflow(pw,
+                "These tests assess the garbage collector performance. These tests implicitly test other aspects of system " +
+                        "under test, including hardware, OS and JVM tuning. Some tests may implicitly test the testing infrastructure " +
+                        "itself, although the benchmark code tries to reduce the infrastructural impact as much as possible.",
+                80, 2);
+        pw.println();
+
+        Utils.reflow(pw,
+                "If you are sharing this report, please share it in full, including the JVM version, OS flavor and version, " +
+                        "plus some data on used hardware.",
+                80, 2);
+
+        pw.println();
+
+        pw.println("  Use -h to get help on available options.");
+        pw.println();
+
+        OptionParser parser = new OptionParser();
+        parser.formatHelpWith(new OptionFormatter());
+
+        OptionSpec<Test> optTests = parser.accepts("t", "Test names.")
+                .withRequiredArg().ofType(Test.class).withValuesSeparatedBy(',').describedAs("string")
+                .defaultsTo(Test.values());
+
+        OptionSpec<Mode> optMode = parser.accepts("m", "Running mode, one of " + Arrays.toString(Mode.values()) + ".")
+                .withRequiredArg().ofType(Mode.class).describedAs("mode")
+                .defaultsTo(Mode.normal);
+
+        OptionSpec<Integer> optMaxHeap = parser.accepts("mh", "Max heap to be used for tests. Leave unset to enable auto-detection")
+                .withRequiredArg().ofType(Integer.class).describedAs("MB");
+
+        parser.accepts("h", "Print help.");
+
+        OptionSet set = parser.parse(args);
+        if (set.has("h")) {
+            parser.printHelpOn(System.out);
+            return;
+        }
+
+        if (set.has(optMaxHeap)) {
+            maxHeapMB = set.valueOf(optMaxHeap);
+        } else {
+            maxHeapMB = calibrateMaxHeap();
+        }
+
+        Options opts = new OptionsBuilder()
+                .detectJvmArgs()
+                .threads(Threads.MAX)
+                .addProfiler(GCProfiler.class)
+                .addProfiler(SafepointsProfiler.class)
+                .verbosity(VerboseMode.SILENT)
+                .build();
 
-//        runAllocationPressure_Peak();
-//        runAllocationPressure_RateLimited();
-        runFraggers_RateLimited();
+        switch (set.valueOf(optMode)) {
+            case quick:
+                opts = new OptionsBuilder()
+                        .parent(opts)
+                        .warmupIterations(3)
+                        .warmupTime(TimeValue.seconds(1))
+                        .measurementIterations(3)
+                        .measurementTime(TimeValue.seconds(1))
+                        .forks(1)
+                        .build();
+                break;
+            case normal:
+                opts = new OptionsBuilder()
+                        .parent(opts)
+                        .warmupIterations(3)
+                        .warmupTime(TimeValue.seconds(1))
+                        .measurementIterations(5)
+                        .measurementTime(TimeValue.seconds(5))
+                        .forks(5)
+                        .build();
+                break;
+            default:
+                throw new IllegalStateException();
+        }
+
+        baseOpts = opts;
+        tests = set.valuesOf(optTests);
+    }
+
+    public enum Test {
+        alloc_peak,
+        alloc_ratelimit,
+        fraggers,
+        roots_synch,
+    }
+
+    public enum Mode {
+        quick,
+        normal,
+    }
+
+    public void run() throws RunnerException {
+        for (Test test : tests) {
+            switch (test) {
+                case alloc_peak:
+                    runAllocationPressure_Peak();
+                    break;
+                case alloc_ratelimit:
+                    runAllocationPressure_RateLimited();
+                    break;
+                case fraggers:
+                    runFraggers_RateLimited();
+                    break;
+                case roots_synch:
+                    runRoots_Synch();
+                    break;
+                default:
+                    throw new IllegalStateException("Unknown test: " + test);
+            }
+        }
+    }
+
+    private void runRoots_Synch() {
+        pw.println("=== ROOTSET: SYNCHRONIZER ROOTS");
+        pw.println();
+
+        for (int size = 0; size < 40000; size++) {
+            Options opts = new OptionsBuilder()
+                    .parent(baseOpts)
+                    .include(Synchronizers.class.getCanonicalName())
+                    .threads(Threads.MAX)
+                    .param("size", String.valueOf(size))
+                    .build();
+
+            try {
+                RunResult result = new Runner(opts).runSingle();
+
+                Result prim = result.getPrimaryResult();
+                Map<String, Result> sec = result.getSecondaryResults();
+
+                pw.printf("%-10d %-45s %-45s %12s %12s %12s %12s      %12s %12s %12s %12s %n",
+                        size,
+                        prim,
+                        sec.get("·gc.alloc.rate"),
+                        sec.get("·safepoints.pause"),
+                        sec.get("·safepoints.pause.p0.99"),
+                        sec.get("·safepoints.pause.p0.999"),
+                        sec.get("·safepoints.pause.p0.9999"),
+                        sec.get("·safepoints.ttsp"),
+                        sec.get("·safepoints.ttsp.p0.99"),
+                        sec.get("·safepoints.ttsp.p0.999"),
+                        sec.get("·safepoints.ttsp.p0.9999")
+                );
+            } catch (RunnerException e) {
+                // OOME, fail
+            }
+        }
     }
 
     private void runAllocationPressure_Peak() throws RunnerException {
@@ -97,24 +260,6 @@
         pw.println();
     }
 
-    public GCBench() {
-        pw = new PrintWriter(System.out, true);
-
-        baseOpts = new OptionsBuilder()
-                .detectJvmArgs()
-                .warmupIterations(1)
-                .warmupTime(TimeValue.seconds(1))
-                .measurementIterations(3)
-                .measurementTime(TimeValue.seconds(1))
-                .forks(1)
-                .threads(Threads.MAX)
-//                .threads(1)
-                .addProfiler(GCProfiler.class)
-                .addProfiler(SafepointsProfiler.class)
-                .verbosity(VerboseMode.SILENT)
-                .build();
-    }
-
     private int calibrateMaxHeap() {
         pw.println("=== Calibrating the target heap size");
         pw.println();
@@ -131,7 +276,7 @@
                 Options opts = new OptionsBuilder()
                         .include(Dummy.class.getCanonicalName())
                         .threads(1)
-                        .jvmArgsAppend("-Xmx" + heapGB + "m", "-Xms" + heapGB + "m")
+                        .jvmArgsAppend("-Xmx" + heapGB + "m", "-Xms" + heapGB + "m", "-XX:+AlwaysPreTouch")
                         .verbosity(VerboseMode.SILENT)
                         .build();
                 try {
@@ -184,7 +329,7 @@
     }
 
     private void doRun_ThreadsHeapX(Class<?> benchmark, Options baseOpts) {
-        pw.printf("%-10s %-20s %-40s %-40s %-44s %-44s %n",
+        pw.printf("%-10s %-20s %-45s %-45s %-52s      %-52s %n",
                 "threads",
                 "heap, MB",
                 "performance",
@@ -198,7 +343,7 @@
             pw.println();
             int margin = maxHeapMB / 8;
             int step = maxHeapMB / 8;
-            for (int heapMB = margin; heapMB < maxHeapMB - margin; heapMB += step) {
+            for (int heapMB = margin; heapMB <= maxHeapMB - margin; heapMB += step) {
                 Options opts = new OptionsBuilder()
                         .parent(baseOpts)
                         .include(benchmark.getName())
@@ -212,7 +357,7 @@
                     Result prim = result.getPrimaryResult();
                     Map<String, Result> sec = result.getSecondaryResults();
 
-                    pw.printf("%-10d %-20d %-40s %-40s %10s %10s %10s %10s %10s %10s %10s %10s %n",
+                    pw.printf("%-10d %-20d %-45s %-45s %12s %12s %12s %12s      %12s %12s %12s %12s %n",
                             threads,
                             heapMB,
                             prim,
@@ -252,13 +397,13 @@
     }
 
     private void doRun_AllocRateX(Class<?> benchmark, Options baseOpts) throws RunnerException {
-        pw.printf("%-10s %-20s %-40s %-40s %-44s %-44s %n",
+        pw.printf("%-10s %-20s %-45s %-45s %-52s      %-52s %n",
                 "size",
                 "target rate",
                 "actual rate",
                 "allocation rate",
-                "pauses",
-                "ttsp"
+                "pauses (sum, 99%, 99.9%, 99.99%)",
+                "ttsp (sum, 99%, 99.9%, 99.99%)"
                 );
 
         for (int size = 1; size <= 1000000; size *= 100) {
@@ -278,7 +423,7 @@
                 Result prim = result.getPrimaryResult();
                 Map<String, Result> sec = result.getSecondaryResults();
 
-                pw.printf("%-10d %-20d %-40s %-40s %10s %10s %10s %10s %10s %10s %10s %10s %n",
+                pw.printf("%-10d %-20d %-45s %-45s %12s %12s %12s %12s      %12s %12s %12s %12s %n",
                         size,
                         rate,
                         prim,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/org/openjdk/gcbench/roots/Synchronizers.java	Thu Nov 24 10:41:10 2016 +0100
@@ -0,0 +1,78 @@
+package org.openjdk.gcbench.roots;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.infra.Blackhole;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Fork(value = 1, jvmArgsAppend = "-Xss32m")
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@Threads(Threads.MAX)
+@State(Scope.Benchmark)
+public class Synchronizers {
+
+    List<Object> list;
+
+    @Param({"40000"})
+    private int size;
+
+    @Setup
+    public void setup() {
+        list = new ArrayList<>();
+        for (int c = 0; c < size; c++) {
+            list.add(new Object());
+        }
+    }
+
+    @Benchmark
+    public void test(Blackhole bh) throws InterruptedException {
+        recursiveLock(bh, list, 0);
+    }
+
+    private void recursiveLock(Blackhole bh, List<Object> list, int i) {
+        if (i < list.size()) {
+            Object o0 = list.get(i + 0);
+            Object o1 = list.get(i + 1);
+            Object o2 = list.get(i + 2);
+            Object o3 = list.get(i + 3);
+            Object o4 = list.get(i + 4);
+            Object o5 = list.get(i + 5);
+            Object o6 = list.get(i + 6);
+            Object o7 = list.get(i + 7);
+            Object o8 = list.get(i + 8);
+            Object o9 = list.get(i + 9);
+            synchronized (o0) {
+                synchronized (o1) {
+                    synchronized (o2) {
+                        synchronized (o3) {
+                            synchronized (o4) {
+                                synchronized (o5) {
+                                    synchronized (o6) {
+                                        synchronized (o7) {
+                                            synchronized (o8) {
+                                                synchronized (o9) {
+                                                    recursiveLock(bh, list, i + 10);
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } else {
+            for (int c = 0; c < size; c++) {
+                bh.consume(list.get(c).hashCode());
+                list.set(c, new Object());
+            }
+        }
+    }
+
+}
--- a/src/main/java/org/openjdk/gcbench/wip/Synchronizers.java	Wed Nov 23 16:04:53 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-package org.openjdk.gcbench.wip;
-
-import org.openjdk.jmh.annotations.*;
-import org.openjdk.jmh.infra.Blackhole;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
-@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
-@Fork(value = 1, jvmArgsAppend = "-Xss32m")
-@BenchmarkMode(Mode.AverageTime)
-@OutputTimeUnit(TimeUnit.MILLISECONDS)
-@Threads(Threads.MAX)
-@State(Scope.Benchmark)
-public class Synchronizers {
-
-    List<Object> list;
-
-    @Param({"40000"})
-    private int size;
-
-    @Setup
-    public void setup() {
-        list = new ArrayList<>();
-        for (int c = 0; c < size; c++) {
-            list.add(new Object());
-        }
-    }
-
-    @Benchmark
-    public void test(Blackhole bh) throws InterruptedException {
-        recursiveLock(bh, list, 0);
-    }
-
-    private void recursiveLock(Blackhole bh, List<Object> list, int i) {
-        if (i < list.size()) {
-            Object o0 = list.get(i + 0);
-            Object o1 = list.get(i + 1);
-            Object o2 = list.get(i + 2);
-            Object o3 = list.get(i + 3);
-            Object o4 = list.get(i + 4);
-            Object o5 = list.get(i + 5);
-            Object o6 = list.get(i + 6);
-            Object o7 = list.get(i + 7);
-            Object o8 = list.get(i + 8);
-            Object o9 = list.get(i + 9);
-            synchronized (o0) {
-                synchronized (o1) {
-                    synchronized (o2) {
-                        synchronized (o3) {
-                            synchronized (o4) {
-                                synchronized (o5) {
-                                    synchronized (o6) {
-                                        synchronized (o7) {
-                                            synchronized (o8) {
-                                                synchronized (o9) {
-                                                    recursiveLock(bh, list, i + 10);
-                                                }
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        } else {
-            for (int c = 0; c < size; c++) {
-                bh.consume(list.get(c).hashCode());
-                list.set(c, new Object());
-            }
-        }
-    }
-
-}