Skip to content

Conversation

@timcassell
Copy link
Collaborator

@timcassell timcassell commented Jan 5, 2026

Core changes:

  1. Added BenchmarkRunner.RunAsync/BenchmarkSwitcher.Run*Async APIs.
    • They still run synchronously the same as the existing APIs for all out-of-process toolchains and in-process toolchains with synchronous benchmarks.
    • They only run asynchronously for in-process toolchains with async benchmarks.
  2. Async benchmarks are now properly awaited instead of synchronously blocked
  3. IterationSetup/Cleanup now support async methods.
  4. IClock is passed to the WorkloadActionNoUnroll etc. benchmark methods and they pass back ClockSpan, instead of the Engine starting and stopping the clock.
    • This is to avoid measuring workload setup before the core loop and async continuations for more accurate measurements. (It also helps to simplify the jit stage.)

Behavior changes:

  1. await Task.Yield() continues on the current synchronization context if it exists, or the current task scheduler. Previously this meant it continued on a ThreadPool thread, now it means it will likely run on the same thread via the new BenchmarkSynchronizationContext. This should be benign.

Breaking changes:

  1. IEngine
    • RunResults Run() changed to ValueTask<RunResults> RunAsync()
  2. EngineParameters
    • WorkloadActionNoUnroll etc. changed from Action<long> to Func<long, IClock, ValueTask<ClockSpan>>
    • GlobalSetupAction etc. changed from Action to Func<ValueTask>
  3. IExecutor
    • ExecuteResult Execute(ExecuteParameters executeParameters) changed to ValueTask<ExecuteResult> ExecuteAsync(ExecuteParameters executeParameters)
  4. IDiagnoser, IToolchain, IValidator
    • IEnumerable<ValidationError> Validate(ValidationParameters validationParameters) changed to IAsyncEnumerable<ValidationError> ValidateAsync(ValidationParameters validationParameters);
      • This was necessary for the ExecutionValidator and ReturnValueValidator that call user code that could be async.

Other Changes:

  1. Added support for custom awaitable returns
    • Not supported in InProcessNoEmitToolchain
    • Does not include extension await
  2. New attributes
    • [AsyncCallerType] allows users to override the type used in the async method that calls their benchmark method.
      • Not supported in InProcessNoEmitToolchain
    • [AggressivelyOptimizeMethods] instructs the assembly weaver to apply AggressiveOptimization to all methods in the annotated type and nested types.
      • This is intended for internal use, but users can also use it. It's needed because C# doesn't allow to apply attributes to compiler-generated async state machines.
  3. Simplified EngineJitStage
  4. ReturnValueValidator is now able to validate async results.

Fixes #2442
Unblocks #1808

@timcassell timcassell added this to the v0.16.0 milestone Jan 5, 2026

partial class RunnableEmitter
{
// TODO: update this to support runtime-async.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@VSadov Should we emit runtime-async methods for this? Is it supported already? If so, what's the pattern?

@timcassell
Copy link
Collaborator Author

@copilot review

This comment was marked as off-topic.

@timcassell
Copy link
Collaborator Author

I did the minimum changes required for proper async benchmarks, but I'm not sure if we want to take it further. We could make all interface methods async (IGenerator.GenerateProjectAsync, IBuilder.BuildAsync, etc), and we could maybe add CancellationToken support (I'm not sure the best way to signal cancellation to the child process, though).

@stephentoub Can we get your input here?

@stephentoub
Copy link
Member

@stephentoub Can we get your input here?

Input on what specifically?

@timcassell
Copy link
Collaborator Author

@stephentoub Can we get your input here?

Input on what specifically?

On the whole async API design. More specifically my previous comment about how much of the surface we should make async and whether it even makes sense to add cancelation token support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Please, add async support for iteration setup and cleanup

3 participants