From 482561a2be24e47f1c3a855b3ce69f56130ec57e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksey=20Shipil=C3=ABv?= Date: Fri, 9 Jun 2023 14:43:19 +0200 Subject: [PATCH] 7903492: JMH: Infrastructure code should yield occasionally for virtual executor to make progress --- .../openjdk/jmh/it/control/ControlStopTest.java | 4 ++-- .../jmh/generators/core/BenchmarkGenerator.java | 6 ++++++ .../org/openjdk/jmh/runner/BenchmarkHandler.java | 11 +++++++++++ .../java/org/openjdk/jmh/runner/InfraControl.java | 14 +++++++++++--- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/control/ControlStopTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/control/ControlStopTest.java index 1d5c74117..2f824bf98 100644 --- a/jmh-core-it/src/test/java/org/openjdk/jmh/it/control/ControlStopTest.java +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/control/ControlStopTest.java @@ -43,7 +43,7 @@ public class ControlStopTest { @Group("pingpong") public void ping(Control cnt) { while (!cnt.stopMeasurement) { - // this body is intentionally left blank + Thread.yield(); } } @@ -51,7 +51,7 @@ public void ping(Control cnt) { @Group("pingpong") public void pong(Control cnt) { while (!cnt.stopMeasurement) { - // this body is intentionally left blank + Thread.yield(); } } diff --git a/jmh-core/src/main/java/org/openjdk/jmh/generators/core/BenchmarkGenerator.java b/jmh-core/src/main/java/org/openjdk/jmh/generators/core/BenchmarkGenerator.java index bcbbedb2a..8d4f694cd 100644 --- a/jmh-core/src/main/java/org/openjdk/jmh/generators/core/BenchmarkGenerator.java +++ b/jmh-core/src/main/java/org/openjdk/jmh/generators/core/BenchmarkGenerator.java @@ -568,6 +568,7 @@ private void generateThroughput(PrintWriter writer, Mode benchmarkKind, MethodGr writer.println(ident(4) + emitCall(method, states) + ';'); invocationEpilog(writer, 4, method, states, false); + writer.println(ident(4) + "if (control.shouldYield) Thread.yield();"); writer.println(ident(4) + "res.allOps++;"); writer.println(ident(3) + "}"); writer.println(); @@ -593,6 +594,7 @@ private void generateThroughput(PrintWriter writer, Mode benchmarkKind, MethodGr writer.println(ident(5) + emitCall(method, states) + ';'); invocationEpilog(writer, 5, method, states, false); + writer.println(ident(5) + "if (control.shouldYield) Thread.yield();"); writer.println(ident(5) + "res.allOps++;"); writer.println(ident(4) + "}"); writer.println(ident(3) + "} catch (Throwable e) {"); @@ -702,6 +704,7 @@ private void generateAverageTime(PrintWriter writer, Mode benchmarkKind, MethodG writer.println(ident(4) + emitCall(method, states) + ';'); invocationEpilog(writer, 4, method, states, false); + writer.println(ident(4) + "if (control.shouldYield) Thread.yield();"); writer.println(ident(4) + "res.allOps++;"); writer.println(ident(3) + "}"); writer.println(); @@ -726,6 +729,7 @@ private void generateAverageTime(PrintWriter writer, Mode benchmarkKind, MethodG writer.println(ident(5) + emitCall(method, states) + ';'); invocationEpilog(writer, 5, method, states, false); + writer.println(ident(5) + "if (control.shouldYield) Thread.yield();"); writer.println(ident(5) + "res.allOps++;"); writer.println(ident(4) + "}"); writer.println(ident(3) + "} catch (Throwable e) {"); @@ -860,6 +864,7 @@ private void generateSampleTime(PrintWriter writer, Mode benchmarkKind, MethodGr writer.println(ident(4) + emitCall(method, states) + ';'); invocationEpilog(writer, 4, method, states, false); + writer.println(ident(4) + "if (control.shouldYield) Thread.yield();"); writer.println(ident(4) + "res.allOps++;"); writer.println(ident(3) + "}"); writer.println(); @@ -889,6 +894,7 @@ private void generateSampleTime(PrintWriter writer, Mode benchmarkKind, MethodGr writer.println(ident(5) + emitCall(method, states) + ';'); invocationEpilog(writer, 5, method, states, false); + writer.println(ident(5) + "if (control.shouldYield) Thread.yield();"); writer.println(ident(5) + "res.allOps++;"); writer.println(ident(4) + "}"); writer.println(ident(3) + "} catch (Throwable e) {"); diff --git a/jmh-core/src/main/java/org/openjdk/jmh/runner/BenchmarkHandler.java b/jmh-core/src/main/java/org/openjdk/jmh/runner/BenchmarkHandler.java index 4fe29f844..e5a147d20 100644 --- a/jmh-core/src/main/java/org/openjdk/jmh/runner/BenchmarkHandler.java +++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/BenchmarkHandler.java @@ -204,6 +204,11 @@ boolean stableThreads() { ExecutorService createExecutor(int maxThreads, String prefix) { return Executors.newFixedThreadPool(maxThreads, WorkerThreadFactories.virtualWorkerFactory(prefix)); } + + @Override + boolean shouldYield() { + return true; + } }, /** @@ -236,6 +241,11 @@ ExecutorService createExecutor(int maxThreads, String prefix) throws Exception { * @return Executor always reuses the same threads? */ boolean stableThreads() { return false; } + + /** + * @return Executing threads should yield occasionally to guarantee progress? + */ + boolean shouldYield() { return false; } } protected void startProfilers(BenchmarkParams benchmarkParams, IterationParams iterationParams) { @@ -309,6 +319,7 @@ public IterationResult runIteration(BenchmarkParams benchmarkParams, IterationPa InfraControl control = new InfraControl(benchmarkParams, params, preSetupBarrier, preTearDownBarrier, isFirstIteration, isLastIteration, + EXECUTOR_TYPE.shouldYield(), new Control()); // preparing the worker runnables diff --git a/jmh-core/src/main/java/org/openjdk/jmh/runner/InfraControl.java b/jmh-core/src/main/java/org/openjdk/jmh/runner/InfraControl.java index 7baf11895..49e64d8e8 100644 --- a/jmh-core/src/main/java/org/openjdk/jmh/runner/InfraControl.java +++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/InfraControl.java @@ -49,6 +49,7 @@ public class InfraControl extends InfraControlL4 { Utils.check(InfraControl.class, "preSetup", "preTearDown"); Utils.check(InfraControl.class, "firstIteration"); Utils.check(InfraControl.class, "lastIteration"); + Utils.check(InfraControl.class, "shouldYield"); Utils.check(InfraControl.class, "warmupVisited", "warmdownVisited"); Utils.check(InfraControl.class, "warmupShouldWait", "warmdownShouldWait"); Utils.check(InfraControl.class, "warmupDone", "warmdownDone"); @@ -59,8 +60,9 @@ public class InfraControl extends InfraControlL4 { public InfraControl(BenchmarkParams benchmarkParams, IterationParams iterationParams, CountDownLatch preSetup, CountDownLatch preTearDown, boolean firstIteration, boolean lastIteration, + boolean shouldYield, Control notifyControl) { - super(benchmarkParams, iterationParams, preSetup, preTearDown, firstIteration, lastIteration, notifyControl); + super(benchmarkParams, iterationParams, preSetup, preTearDown, firstIteration, lastIteration, shouldYield, notifyControl); } /** @@ -165,6 +167,7 @@ abstract class InfraControlL2 extends InfraControlL1 { public final CountDownLatch preTearDown; public final boolean firstIteration; public final boolean lastIteration; + public final boolean shouldYield; public final AtomicInteger warmupVisited, warmdownVisited; public volatile boolean warmupShouldWait, warmdownShouldWait; @@ -180,6 +183,7 @@ abstract class InfraControlL2 extends InfraControlL1 { public InfraControlL2(BenchmarkParams benchmarkParams, IterationParams iterationParams, CountDownLatch preSetup, CountDownLatch preTearDown, boolean firstIteration, boolean lastIteration, + boolean shouldYield, Control notifyControl) { warmupVisited = new AtomicInteger(); warmdownVisited = new AtomicInteger(); @@ -199,6 +203,8 @@ public InfraControlL2(BenchmarkParams benchmarkParams, IterationParams iteration this.preTearDown = preTearDown; this.firstIteration = firstIteration; this.lastIteration = lastIteration; + this.shouldYield = shouldYield; + this.benchmarkParams = benchmarkParams; this.iterationParams = iterationParams; } @@ -281,8 +287,9 @@ abstract class InfraControlL3 extends InfraControlL2 { public InfraControlL3(BenchmarkParams benchmarkParams, IterationParams iterationParams, CountDownLatch preSetup, CountDownLatch preTearDown, boolean firstIteration, boolean lastIteration, + boolean shouldYield, Control notifyControl) { - super(benchmarkParams, iterationParams, preSetup, preTearDown, firstIteration, lastIteration, notifyControl); + super(benchmarkParams, iterationParams, preSetup, preTearDown, firstIteration, lastIteration, shouldYield, notifyControl); } } @@ -292,8 +299,9 @@ abstract class InfraControlL4 extends InfraControlL3 { public InfraControlL4(BenchmarkParams benchmarkParams, IterationParams iterationParams, CountDownLatch preSetup, CountDownLatch preTearDown, boolean firstIteration, boolean lastIteration, + boolean shouldYield, Control notifyControl) { - super(benchmarkParams, iterationParams, preSetup, preTearDown, firstIteration, lastIteration, notifyControl); + super(benchmarkParams, iterationParams, preSetup, preTearDown, firstIteration, lastIteration, shouldYield, notifyControl); } }