[browser][coreCLR] R2R: Interpreter PGO instrumentation (block counts)
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
# Interpreter PGO instrumentation (block counts) for CoreCLR-on-WASM
Part of #130524.
Status: **draft / issue candidate** · Area: CoreCLR interpreter, PGO · Related: #130521 (WASM RyuJIT PGO enablement)
## Goal
Make the CoreCLR interpreter a first-class **profile producer** so that hotness data collected while an app runs interpreted can drive precompilation (R2R) selection. This is the profile source the R2R-on-WASM ("R1") work needs: run the app on the interpreter, observe what is hot, and emit a standard profile that the existing precompilation toolchain consumes unchanged.
## Why
Today the WASM app starts and runs on the interpreter. To decide *what* to precompile (the startup hot path, JSON, and later lazily-streamed code), we need a real profile of the interpreted run. The runtime already has a mature, well-understood profile format and downstream tooling; the missing piece is a producer on the interpreter side.
## Direction
- **Count basic-block execution keyed by IL offset.** The interpreter increments a counter at block heads (method entry and loop/branch targets), tagging each count with its IL offset. IL offsets are engine-independent, so the profile is portable and matches what the precompiler re-derives from the same IL.
- **Emit block counts, not edge counts.** Deliberately avoid reproducing the JIT's edge/spanning-tree instrumentation scheme (which is shaped by the JIT's own flow-graph and internal blocks). Block counts are simpler, engine-independent, and the precompiler already derives branch likelihoods from block weights — so we get branching hints without coupling to JIT internals.
- **Reuse the shared profile representation.** Populate the same profile schema/records the JIT already produces, so the collected data is format-identical and needs no special-casing in the profile tools or the precompiler.
- **Cheap and gated.** A single-increment counter per instrumented point, stored in interpreter method metadata, enabled by the standard profiling switch and (optionally) scoped to a method filter to bound overhead during bring-up.
- **Export via existing profile paths.** Once counts live in the shared representation, the runtime's existing profile-export mechanisms carry them out to the precompiler with no new format.
## Scope
**In:** interpreter block-count instrumentation keyed by IL offset; storing counts in the shared profile representation; enabling collection during an interpreted run; producing a profile the precompiler accepts.
**Out:** edge-count profiles; JIT-side instrumentation and the broader feature enablement (that is #130521); consuming profiles / loading precompiled code.
## Success criteria
- An interpreter-only run yields a profile that the precompilation toolchain accepts without modification.
- That profile selects essentially the same hot methods a JIT-collected profile would, for the same workload.
- Measurable overhead of instrumentation is small and only paid when profiling is enabled.
## Dependencies & relationship to #130521
- Requires the shared profile subsystem to be **available in the WASM build**. It is currently compiled out for WASM; this work therefore depends on either that subsystem being enabled (#130521) or a minimal interpreter-scoped counter store as an interim.
- This interpreter-only producer plus #130521 together answer the "how do we get PGO on WASM" decision: **the interpreter producer lands now** (enough to unblock R1 profiling), **#130521 brings up the full producer/consumer feature** for the WASM JIT as a follow-up.
## Open questions
- Which profile record kinds to emit (method-entry plus loop-head block counts) for good precompiler results.
- Whether the profile tools and precompiler accept interpreter-produced, IL-offset-keyed counts with zero changes.
- Divergence risk where the interpreter's block boundaries differ from the precompiler's at non-branch-target points; validate that loop heads and branch targets line up and that unmatched blocks degrade gracefully.
> [!NOTE]
> This issue was drafted with GitHub Copilot assistance.
Contributor guide
Assessment
This issue has not been assessed yet.