-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Description
I've been looking at how we implement "Goto Source (Def)" in PerfView for JIT-compiled frames when using ETW (i.e. not EventPipe)
The mapping from stack frame to source goes via a number of steps. One important piece is mapping from { module, RVA } to { Assembly, Namespace, Type, Method, IL offset }
That's achieved by tracking three tables emitted by the CLR's rundown provider: Loader/ModuleDCStart, Method/DCStartVerbose and Method/ILToNativeMapDCStart.
The first two gets us the Assembly, Namespace, Type, Method part. The final table gives us a way to find the IL offset (which, along with the PDB, allows us to identify the line number in source).
If the method in question has been re-JIT-ted -- perhaps due to tiered compilation -- we get two entries in the DCStartVerbose and ILToNativeMapDCStart tables, as you'd expect. In the DCStartVerbose table, the ReJITID can be used to distinguish them. Typically, I see 0 for "QuickJitted" and 1 for "OptimizedTier1". However, in the ILToNativeMapDCStart table the ReJITID always appears to be 0. That makes it difficult to correlate reliably (you have to rely on heuristics).
It looks like a bug that the ReJITID is always 0 in the ILToNativeMapDCStart event.
Reproduction Steps
I can share a .diagsession, if necessary.
- Capture a trace with PerfView of a reasonably complex .NET 6 application (something that exercises tiered compilation)
- Open the trace, view the CPU stacks and try to "Goto Source" for some of the JITted methods. Assuming it works at all, you're likely to end up at the wrong line number. The difference may be very subtle.
More directly (which is how I found it), take a look at the raw events in the trace using PerfView's Events view. Filter to "Method/DCStartVerbose" and "Method/ILToNativeMapDCStart" events. Find an interesting method in the DCStartVerbose table -- one that has been JITted twice for tiered compilation (has a ReJITID of 1). Then search for that MethodID in the ILToNativeMap table. You'll find that it has two entries, each with ReJITID of 0. They likely have completely different IL offsets (view the raw event data) even though they claim to be the same.
Expected behavior
ReJITID is set correctly in the ILToNativeMapDCStart event
Actual behavior
ReJITID is always zero
Regression?
I suspect it's been that way forever -- it's just that tiered compilation only recently became widely available.
Known Workarounds
None
Configuration
.NET 6, Windows, x64
Other information
No response