Skip to content

Async profiler: V1 pooled ValueTask instrumentation.#129801

Open
lateralusX wants to merge 2 commits into
dotnet:mainfrom
lateralusX:lateralusX/async-profiler-asyncv1-pooled-value-task-support
Open

Async profiler: V1 pooled ValueTask instrumentation.#129801
lateralusX wants to merge 2 commits into
dotnet:mainfrom
lateralusX:lateralusX/async-profiler-asyncv1-pooled-value-task-support

Conversation

@lateralusX

Copy link
Copy Markdown
Member

Summary

Extends the V1 AsyncProfiler instrumentation (added in #129043) to PoolingAsyncValueTaskMethodBuilder / PoolingAsyncValueTaskMethodBuilder. Previously the pooling builder's reusable StateMachineBox was a no-op for the profiler — GetDiagnosticData was a stub and the box emitted no resume/complete/unwind events — leaving trace gaps wherever the pooling builder is used.

Motivation

The pooling builder backs an async method with a poolable IValueTaskSource-based StateMachineBox rather than a Task derived AsyncStateMachineBox. The existing instrumentation assumed Task-backed boxes, so pooling-builder methods produced incomplete async traces (missing per-method Resume/Complete, empty callstacks, and incorrect suspend/complete context classification). This makes the V1 async profiler consistent across the regular Task/ValueTask builders and the pooling builder.

Changes

Pooling box instrumentation (PoolingAsyncValueTaskMethodBuilderT.cs)

  • Resume hook in StateMachineBox.MoveNext.
  • Complete/unwind hooks in the base StateMachineBox.SetResult/SetException.
  • Implemented GetDiagnosticData (methodId + state machine state via AsyncStateMachineDiagnostics; continuation from the value task source).

Suspend/complete classification for non-Task boxes (AsyncStateMachineDispatcher.cs, AsyncProfiler.cs)

  • A pooling box can be recycled inline before the dispatcher's finally runs, so completion is captured at SetResult/SetException time into a new AsyncProfiler.Info.CurrentContinuationCompleted flag (set before signaling; reset per cascade frame). The dispatcher finally reads this flag uniformly for both Task and pooling boxes instead of probing the box.
  • Consolidated CompleteAsyncMethod/UnwindAsyncFrame to do a single TLS fetch, set the flag, and gate event emission internally.

Callstack walk over pooling chains

  • AsyncStateMachineDispatcher.LastContinuation retyped from Task? to IAsyncStateMachineBox? (removes an unsafe Unsafe.As on non-Task boxes); added a Task fast-path NextContinuationForDiagnostics so the common path stays non-virtual and pooling boxes fall back to GetDiagnosticData.
  • The continuation accessor is read through the existing GetDiagnosticData (no new interface member — saves one vtable slot per state-machine box type).
  • Exposed ManualResetValueTaskSourceCore.ContinuationForDiagnostics for the diagnostic walk.

Cascade guard (ValueTaskAwaiter.cs, ConfiguredValueTaskAwaitable.cs)

  • The IValueTaskSource awaiter paths unconditionally interposed a dispatcher, which split a pooling chain into per-level dispatchers and truncated the callstack to one frame. Added the obj is not IAsyncStateMachineBox guard (mirroring TaskAwaiter.UnsafeOnCompletedInternal) to all four sites, so awaiting one async (pooling) box from another forms a direct box→box continuation cascade the walker can traverse; a dispatcher is interposed only at the true leaf (e.g. await Task.Delay).

Tests

14 new tests in AsyncProfilerV1Tests.cs (13 pooling + 1 regular-ValueTask single-threaded). Each mirrors an existing ValueTask/Task test:

  • Event lifecycle, per-method events, callstack depth/distinct method ids, handled/unhandled exception unwind.
  • Pooling-specific: suspend/complete classification, ConfigureAwait(false), late-parent-registration Append, generic ValueTask, and a check that the pooling builder is genuinely in effect (the pending ValueTask is backed by an IValueTaskSource, not a Task).
  • Single-threaded smoke tests (no thread pool) for ValueTask and pooling ValueTask.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-threading-tasks
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR extends the V1 async-profiler (state-machine / TaskAsync) instrumentation to cover PoolingAsyncValueTaskMethodBuilder / PoolingAsyncValueTaskMethodBuilder<T>, including correct Resume/Complete/Unwind event emission and callstack walking through pooling-box continuation chains, and adds targeted V1 tests for pooling-ValueTask scenarios.

Changes:

  • Add async-profiler hooks to pooling state-machine boxes (resume + complete/unwind) and implement diagnostic-chain exposure for pooling boxes.
  • Update dispatcher completion/suspend classification to work uniformly for Task-backed and pooling-box continuations.
  • Add/extend V1 async-profiler tests to validate pooling ValueTask lifecycle events, callstacks, ConfigureAwait(false), and append behavior.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/System.Runtime.CompilerServices/AsyncProfilerV1Tests.cs Adds pooling-ValueTask coverage and renames/extends ValueTask V1 scenarios to validate event + callstack behavior.
src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs Exposes a continuation object for diagnostic walking from ManualResetValueTaskSourceCore.
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs Avoids dispatcher interposition for IAsyncStateMachineBox continuations to preserve box→box cascades.
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/PoolingAsyncValueTaskMethodBuilderT.cs Adds V1 async-profiler resume/complete/unwind hooks for pooling boxes and implements GetDiagnosticData.
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs Mirrors the awaiter guard to prevent unnecessary dispatcher insertion for box continuations.
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs Consolidates complete/unwind paths to route through the updated dispatcher helpers with flags.
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncStateMachineDispatcher.cs Tracks completion via TLS flag (works for pooling boxes) and retypes continuation tracking to IAsyncStateMachineBox.
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncProfiler.cs Uses the new continuation accessor path for append/callstack walking and removes Task-only assumptions.

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.

2 participants