diff --git a/narayana/ArjunaCore/arjuna/pom.xml b/narayana/ArjunaCore/arjuna/pom.xml index 8d801a35..899a31fe 100644 --- a/narayana/ArjunaCore/arjuna/pom.xml +++ b/narayana/ArjunaCore/arjuna/pom.xml @@ -107,5 +107,12 @@ org.jboss.logging jboss-logging-processor + + + tools.profiler + async-profiler + 4.3 + compile + \ No newline at end of file diff --git a/narayana/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/performance/VTPerformanceTest.java b/narayana/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/performance/VTPerformanceTest.java index d11c48d8..f5045314 100644 --- a/narayana/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/performance/VTPerformanceTest.java +++ b/narayana/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/performance/VTPerformanceTest.java @@ -12,6 +12,7 @@ import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; @@ -20,6 +21,12 @@ import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Threads; import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.profile.JavaFlightRecorderProfiler; +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 java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -39,8 +46,8 @@ @Warmup(iterations = VTPerformanceTest.ITERATIONS, time = VTPerformanceTest.TIME_PER_ITER, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = VTPerformanceTest.ITERATIONS, time = VTPerformanceTest.TIME_PER_ITER, timeUnit = TimeUnit.SECONDS) public class VTPerformanceTest { - static final int THREADS = 10;//_000; //Threads.MAX; - static final int FORKS = 2; + static final int THREADS = 240;//10;//_000; //Threads.MAX; + static final int FORKS = 1; static final int ITERATIONS = 5; static final int TIME_PER_ITER = 2; @@ -51,6 +58,32 @@ public class VTPerformanceTest { private static MethodHandle shutdownExecutorMH; // method handle to shut down the executor private static boolean isVirtualThreadPerTaskExecutor; + public static void main(String[] args) throws RunnerException { + // Sometimes it is useful to run the benchmark directly from an IDE: + Options opt = new OptionsBuilder() + .include(VTPerformanceTest.class.getSimpleName() + ".standardThreadsBenchmark") + .timeUnit(TimeUnit.SECONDS) + .threads(THREADS) + .forks(FORKS) + .mode(Mode.Throughput) + .warmupIterations(1) + .warmupTime(TimeValue.seconds(1)) + .measurementIterations(ITERATIONS) + .measurementTime(TimeValue.seconds(TIME_PER_ITER)) + .param("networkDelay", "0") // don't simulate network using MS_DELAY + .shouldDoGC(true) + // use JFR as the profiler, the recording will appear in the User working directory with the + // name "-xxx/profile.jfr", which you can change to "wherever" using + // addProfiler(JavaFlightRecorderProfiler.class, "dir=wherever"). Java Flight Recorder data files + // can be viewed with the jmc graphical tool or with the jfr command line tool which is in the java + // bin directory + .addProfiler(JavaFlightRecorderProfiler.class) + .jvmArgs("-Djmh.executor=FJP") // ForkJoinPool + .build(); + + new Runner(opt).run(); + } + @State(Scope.Benchmark) public static class VTBenchmarkState { @Param({"0", MS_DELAY}) // run the benchmark twice with and without simulating a network delay @@ -129,6 +162,11 @@ private void twoPhase(int msDelay) { public static void beforeClass(String msg, boolean async, boolean enableVT) { CoordinatorEnvironmentBean configBean = arjPropertyManager.getCoordinatorEnvironmentBean(); + // size the standard TwoPhaseCommit thread pool to match the number of threads used for the benchmark, + // this provides a fairer comparison between the standard fork-join pool and the virtual threads executor, + // refer to the various TwoPhaseCommitThreadPool implementations for details + configBean.setMaxTwoPhaseCommitThreads(THREADS); + configBean.setAsyncPrepare(async); configBean.setAsyncCommit(async); configBean.setAsyncRollback(async); diff --git a/narayana/README.md b/narayana/README.md index 00fcf9f6..5e3d6410 100644 --- a/narayana/README.md +++ b/narayana/README.md @@ -33,6 +33,14 @@ Here we have overridden the defaults and specified "-i 1 -wi 2 -f 1 -t 2 -r 10" We also passed in a wild card (.\*) to say run all benchmark methods contained in the class VolatileStoreBenchmark. +To run the benchmark with a profiler pass the appropriate profiler options via the java command line. For example to the run the VTPerformanceTest using the JFR profiler use the following options: + + java -XX:+FlightRecorder -XX:StartFlightRecording=duration=200s,filename=flight.jfr -jar ArjunaCore/arjuna/target/benchmarks.jar com.hp.mwtests.ts.arjuna.performance.VTPerformanceTest + +Some benchmarks, such as the one just referenced, also have a main method to simplify profiling and running from an IDE. + +Profiler data can be viewed with tools specific to the profiler, for example JFR data can be viewed with the jmc graphical tool or with the jfr command line tool located in the java bin directory. + And finally, to debug a benchmark use the surefire debug property, for example `mvn clean test -Dtest=TestBenchmark#testImprovement -Dmaven.surefire.debug` It is straightforward to write your own benchmark code, just tell the framework which methods are benchmarks by annotating them with @Benchmark. There are plenty of examples in this git repository.