Skip to content

Listen to JIT events - #3169

Merged
timcassell merged 12 commits into
masterfrom
jit-stage-determinism
Jul 18, 2026
Merged

timcassell merged 12 commits into
masterfrom
jit-stage-determinism

Conversation

@timcassell

@timcassell timcassell commented Jun 3, 2026 •

Copy link
Copy Markdown
Collaborator

Improves the JIT stage by listening to events instead of waiting 250ms per tier. It's still not 100% deterministic, but it's much better than before.

Master: ~750ms + benchmark time
PR: ~90ms + benchmark time + compilation time

@timcassell
timcassell force-pushed the jit-stage-determinism branch from 610e77d to 02e7826 Compare June 20, 2026 18:48
@timcassell
timcassell marked this pull request as ready for review June 20, 2026 18:48
@timcassell
timcassell force-pushed the jit-stage-determinism branch from 6250266 to ae07d7b Compare June 20, 2026 20:09
timcassell and others added 3 commits June 20, 2026 16:59
Conflict resolved in DeclarationsProvider.cs: keep both master's
GetLoadArguments/GetPassArguments and the branch's
GetWorkloadMethodParameterTypes/GetTypeOfExpression resolver helpers.

Master reintroduced FileCleanupHelper (it now has call sites in
BenchmarkRunnerClean/GeneratorBase), overriding the branch's tangential
deletion of it.

Bumped SyncTaskCoreEmitter's no-arg async-method ordinals +1 to track the
branch's +1 shift of the base map: the generated __ResolveWorkloadMethods
member shifts every Roslyn declaration-order ordinal by one, and master's
sync-task override (added independently) hadn't accounted for it, breaking
InProcessEmitTest's ConsumeTasksSynchronously case.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@timcassell
timcassell force-pushed the jit-stage-determinism branch from 54e01a3 to 80765b9 Compare June 27, 2026 22:54
@timcassell

Copy link
Copy Markdown
Collaborator Author

cc @EgorBo @AndyAyersMS

Identify watched methods exactly instead of by metadata token + name, which
collide both across modules (tokens are only unique within one, and every
module numbers them from 0x06000001) and across generic instantiations:

- Non-canonicalized methods (all non-generic ones, plus value-type generic
  instantiations) match on the event's MethodID, the MethodDesc pointer that
  the public RuntimeMethodHandle.Value exposes. Exact and module-proof, and
  one integer compare instead of the name payloads.
- Canonicalized methods (any reference-type generic argument, at any depth)
  can't use it: CoreCLR compiles one shared body for them and publishes it
  against the __Canon MethodDesc, which reflection cannot hand back. They
  match on ModuleID + token + name + the canonicalized declaring type name,
  which is how the events spell the instantiation. ModuleID is best-effort;
  unresolved simply means "don't compare".
- Generic methods are now rejected. The events name only the declaring type
  and the bare method name, so a canonicalized instantiation cannot be told
  from any other. BDN has never supported them as benchmark methods, so this
  is a contract violation rather than something to half-support.

Dispose the listener when the stage is abandoned. EngineStage is IDisposable
and the engine's stage loop disposes it, so an exception or cancellation mid
jit stage no longer leaks the Jit keyword — an event for every method jitted
process-wide — into the measurement stages.

Don't enable events from OnEventSourceCreated. The base EventListener ctor
calls it before our ctor body runs, so enabling there let the EventPipe
dispatcher thread reach OnEventWritten while watchedMethods was still null.

Fix JitStage_MultipleMethodsUnevenInvocationRates, whose sleep counted
invocations where it meant tier crossings, making its condition unsatisfiable
so it never staggered the two methods it was written to stagger.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AndyAyersMS

Copy link
Copy Markdown
Member

Dismayed that it is so complicated. I don't believe we have any better solution to offer.

@timcassell

Copy link
Copy Markdown
Collaborator Author

Dismayed that it is so complicated. I don't believe we have any better solution to offer.

Right, it's the consequence of having to compensate for racing with the JIT and event dispatcher threads. Dedicated APIs would vastly simplify it (dotnet/runtime#129020).

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