Skip to content

Harden async-profiler dispatcher/wrapper frame name contract for callstack stitching. - #131963

Merged
lateralusX merged 1 commit into
dotnet:mainfrom
lateralusX:lateralusX/async-profiler-contract-validation
Aug 7, 2026
Merged

Harden async-profiler dispatcher/wrapper frame name contract for callstack stitching.#131963
lateralusX merged 1 commit into
dotnet:mainfrom
lateralusX:lateralusX/async-profiler-contract-validation

Conversation

@lateralusX

Copy link
Copy Markdown
Member

Changes

Runtime (System.Private.CoreLib)

  • Add [StackTraceHidden] to the V1 dispatch frames (InstrumentedMoveNext, MoveNextAsDispatcher, AsyncStateMachineDispatcher.MoveNext) so V1 matches the already-hidden V2 dispatch frames. These frames stay out of managed stack traces but remain in the physical stack and in stack-trace metadata.
  • Add name-contract comments (placed uniformly below the attribute) on the methods and types diagnostic tooling depends on by name.
  • Rename the (not-yet-shipped) env var DOTNET_AsyncProfilerEventSource_EventBufferSizeDOTNET_AsyncProfiler_EventBufferSize; remove an unused using.

Tests (System.Threading.Tasks.Tests)

  • Name-contract tests pin the identifiers the stitcher hardcodes: V1/V2 dispatch methods, and the V2 continuation wrappers (all 32 exist, none beyond — hardcoded rather than reflected so drift can't pass silently).
  • Frame-capture tests capture the unfiltered physical managed stack from inside a resumed continuation and assert the boundary frames appear in the expected leaf→root order:
    • RuntimeAsync_ResumeDispatchStack (V2 single-yield)
    • StateMachineAsync_ResumeDispatchStack (V1 single-yield)
    • StateMachineAsync_PoolingResumeDispatchStack (V1 pooling → standalone
      AsyncStateMachineDispatcher)
    • StateMachineAsync_InlineCompletionClimb (V1 inline completion, child frames remain beneath the resuming parent)
  • Frame identity is resolved via DiagnosticMethodInfo (stack-trace metadata) rather than StackFrame.GetMethod() (reflection), so the tests work on CoreCLR, Mono, and NativeAOT — the latter trims reflection metadata but preserves stack-trace metadata (including names for [StackTraceHidden] Ecma methods).

Tests are gated by runtime capability: V1 tests run on CoreCLR + Mono; V2 tests run on CoreCLR (+ NativeAOT for the frame-capture test); reflection-based name-contract tests are CoreCLR/Mono only.

Risk / compatibility

  • No change to async dispatch behavior. [StackTraceHidden] only affects stack-trace display, and the newly-hidden V1 InstrumentedMoveNext frames are only present when the async profiler is active.
  • The env-var rename targets an unshipped diagnostic knob, so it is not a breaking change.

continuation-wrapper frames by method/type name and expects them
to be consistently filtered from managed stack traces. Nothing
in the runtime guarded that implicit contract, so a rename,
an added/removed continuation wrapper, or a lost [StackTraceHidden]
marker could silently break async callstack stitching for both
StateMachineAsync (V1) and RuntimeAsync (V2).

Runtime (System.Private.CoreLib):
- Mark the V1 state-machine dispatch frames [StackTraceHidden]
  (InstrumentedMoveNext, MoveNextAsDispatcher, AsyncStateMachineDispatcher.MoveNext)
  to match the V2 RuntimeAsync dispatch frames, so they are consistently hidden
  from managed stack traces while remaining resolvable by name from stack-trace
  metadata.
- Add diagnostic-tooling name-contract comments (unified below the attribute) on
  the dispatcher/wrapper methods the stitcher recognizes by name.
- Rename the (unshipped) env var DOTNET_AsyncProfilerEventSource_EventBufferSize
  to DOTNET_AsyncProfiler_EventBufferSize for naming consistency; drop a now-unused
  using.

Tests (System.Threading.Tasks.Tests):
- Name-contract tests pinning the exact names/count the stitcher hardcodes: V1/V2
  dispatch methods and the 32 V2 continuation-wrapper methods (asserting all 32
  exist and none beyond).
- Frame-capture tests that capture the UNFILTERED physical managed stack from
  inside a resumed continuation and assert the boundary frames appear in the
  expected leaf->root order: V2 single-yield, V1 single-yield, V1 pooling, and V1
  inline-completion climb. Frame identity is resolved via DiagnosticMethodInfo so
  the tests work on CoreCLR, Mono, and NativeAOT (where reflection metadata is
  trimmed but stack-trace metadata is not).
Copilot AI review requested due to automatic review settings August 6, 2026 19:31
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Note

This error may be related to your runner configuration. You can now configure runners for Copilot code review separately from Copilot cloud agent by creating a copilot-code-review.yml file with your setup steps. Read the docs for details.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@noahfalk noahfalk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍

@lateralusX

Copy link
Copy Markdown
Member Author

/ba-g known issue #131956

@lateralusX
lateralusX merged commit 45fb46d into dotnet:main Aug 7, 2026
146 of 148 checks passed
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-rc1 milestone Aug 7, 2026
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.

3 participants