Skip to content

ReJITID is always zero in ILToNativeMapDCStart event #70187

@pharring

Description

@pharring

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.

  1. Capture a trace with PerfView of a reasonably complex .NET 6 application (something that exercises tiered compilation)
  2. 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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions