Skip to content

Conversation

@jakobbotsch
Copy link
Member

This adds an optimization that tries to reuse the continuation instance that was used to resume a runtime async function if it suspends again.

This optimization is not reliable. It only kicks in if the same suspension point resumes and then suspends again. However, it is useful to get an idea of how costly the continuation allocation part is when looking at the gap between
async1 and runtime async in raw suspension/resumption performance.

The optimization is controlled by DOTNET_JitOpportunisticContinuationReuse and is disabled by default.

Despite the above this is not a very costly transformation, so we may consider enabling it even if it does not kick in very reliably.

Example benchmark that measures raw suspension/resumption performance (best case for async1, worst case for runtime async):

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

public class Program
{
    static void Main()
    {
        NullAwaiter na = new NullAwaiter();

        Task t = Foo(100_000_000, na);
        while (!t.IsCompleted)
        {
            na.Continue();
        }
        Console.WriteLine("Finished");
    }

    static async Task Foo(int n, NullAwaiter na)
    {
        Stopwatch timer = Stopwatch.StartNew();
        for (int i = 0; i < n; i++)
        {
            await na;
        }
        Console.WriteLine("Took {0:F1} ms", timer.Elapsed.TotalMilliseconds);
    }

    private class NullAwaiter : ICriticalNotifyCompletion
    {
        public Action Continue;

        public NullAwaiter GetAwaiter() => this;

        public bool IsCompleted => false;

        public void GetResult()
        {
        }

        public void UnsafeOnCompleted(Action continuation)
        {
            Continue = continuation;
        }

        public void OnCompleted(Action continuation)
        {
            throw new NotImplementedException();
        }
    }
}

With DOTNET_JitOpportunisticContinuationReuse=0: Took 5788.9 ms
With DOTNET_JitOpportunisticContinuationReuse=1: Took 4611.5 ms
Async1: Took 3433.7 ms

This adds an optimization that tries to reuse the continuation instance
that was used to resume a runtime async function if it suspends again.

This optimization is not reliable. It only kicks in if the same
suspension point resumes and then suspends again. However, it is useful
to get an idea of how costly the continuation allocation part is when
looking at the gap between async1 and runtime async in raw
suspension/resumption performance.

The optimization is controlled by
`DOTNET_JitOpportunisticContinuationReuse` and is disabled by default.

Despite the above this is not a very costly transformation, so we may
consider enabling it even if it does not kick in very reliably.
@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Oct 25, 2025
@jakobbotsch jakobbotsch added area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI runtime-async and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Oct 25, 2025
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

@jakobbotsch
Copy link
Member Author

jakobbotsch commented Oct 25, 2025

I plan to also build a "mega continuation" mode, just so that we have the ability to try it out on scenarios. Mega continuations would be able to be reused always, so it would make the optimization reliable, but it comes with larger continuations which is a more tangible downside.

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

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI runtime-async

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant