Mercurial > hg > gc-bench
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()); - } - } - } - -}