From d707888ee7122326f7a15e578782c9cc1e937e10 Mon Sep 17 00:00:00 2001 From: Tim Cassell Date: Sun, 29 Mar 2026 21:51:28 -0400 Subject: [PATCH 1/3] Fix stack size variance between iterations. --- src/BenchmarkDotNet/Engines/Engine.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/BenchmarkDotNet/Engines/Engine.cs b/src/BenchmarkDotNet/Engines/Engine.cs index 567125dfdf..567774442a 100644 --- a/src/BenchmarkDotNet/Engines/Engine.cs +++ b/src/BenchmarkDotNet/Engines/Engine.cs @@ -1,4 +1,4 @@ -using BenchmarkDotNet.Attributes.CompilerServices; +using BenchmarkDotNet.Attributes.CompilerServices; using BenchmarkDotNet.Characteristics; using BenchmarkDotNet.Helpers; using BenchmarkDotNet.Jobs; @@ -89,16 +89,18 @@ public async ValueTask RunAsync() } // This method is extra long because the helper methods were inlined in order to prevent extra async allocations on each iteration. - private async ValueTask RunCore() + private async Task RunCore() { + // We need to force an async yield here to ensure each benchmark invocation is called with a constant stack size. #1120 + await Task.Yield(); + var measurements = new List(); if (EngineEventSource.Log.IsEnabled()) EngineEventSource.Log.BenchmarkStart(Parameters.BenchmarkName); IterationData extraIterationData = default; - // Enumerate the stages and run iterations in a loop to ensure each benchmark invocation is called with a constant stack size. - // #1120 + // Enumerate the stages and run iterations in a loop to ensure each benchmark invocation is called with a constant stack size. #1120 foreach (var stage in EngineStage.EnumerateStages(Parameters)) { if (stage.Stage == IterationStage.Actual && stage.Mode == IterationMode.Workload) From bf00a3451e05493d6452fb7a769c777f2c7978ae Mon Sep 17 00:00:00 2001 From: Tim Cassell Date: Sun, 29 Mar 2026 21:59:33 -0400 Subject: [PATCH 2/3] Check cancellation after yield. --- src/BenchmarkDotNet/Engines/Engine.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BenchmarkDotNet/Engines/Engine.cs b/src/BenchmarkDotNet/Engines/Engine.cs index 567774442a..7cfb8e90fb 100644 --- a/src/BenchmarkDotNet/Engines/Engine.cs +++ b/src/BenchmarkDotNet/Engines/Engine.cs @@ -93,6 +93,7 @@ private async Task RunCore() { // We need to force an async yield here to ensure each benchmark invocation is called with a constant stack size. #1120 await Task.Yield(); + Host.CancellationToken.ThrowIfCancellationRequested(); var measurements = new List(); From d484c4d62faf103d18dba6039d9847bb71979eb9 Mon Sep 17 00:00:00 2001 From: Tim Cassell Date: Mon, 30 Mar 2026 12:39:58 -0400 Subject: [PATCH 3/3] Fix test --- .../Toolchains/InProcess/NoEmit/InProcessNoEmitRunner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitRunner.cs b/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitRunner.cs index b899244fbe..b5e8b75cac 100644 --- a/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitRunner.cs +++ b/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitRunner.cs @@ -36,7 +36,7 @@ public static async ValueTask Run(IHost host, ExecuteParameters parameters, var methodInfo = type.GetMethod(nameof(Runnable.RunCore), BindingFlags.Public | BindingFlags.Static) ?? throw new InvalidOperationException($"Bug: method {nameof(Runnable.RunCore)} in {inProcessRunnableTypeName} not found."); - await ((ValueTask) methodInfo.Invoke(null, [host, parameters, benchmarkActionFactory])!).ConfigureAwait(false); + await ((ValueTask) methodInfo.Invoke(null, [host, parameters, benchmarkActionFactory])!).ConfigureAwait(true); return 0; }