Skip to content

[browser][coreCLR] R2R: Interpreter live hotness trigger for on-demand R2R shard download #130516

Description

@pavelsavara

Interpreter live hotness trigger for on-demand R2R shard download

Part of #130524.

Status: draft / issue candidate · Area: CoreCLR interpreter, runtime lazy-load · Related: #130517 (counters), #130523 (R2R-only boot asset), #130515 (IL shard consumer), #130522 (entry-point patch). Rides the upstream webcil-in-wasm async loader (#129634). Required for the R1 demo.

Goal

Give the interpreter a live, in-process mechanism that detects when a method (or loop) has become hot and triggers a request to fetch and activate its precompiled (R2R) shard — the runtime half of R1's "stream what's hot" behavior. This must operate during ordinary execution, with no diagnostics/EventPipe session open.

Why

The interpreter counters (#130517) feed the offline profile export used at build time to select the startup composite (carried out over EventPipe via #130518). They do not, by themselves, drive anything at runtime. R1's defining behavior — the interpreter observing hot code and pulling in its R2R shard in the background — needs a live threshold-and-trigger loop that runs in normal app runs. Without it, lazy tier-up never happens, so even the prototype demo (composite plus lazy shard tier-up) cannot exercise the runtime streaming path. This is a normal-execution feature, not a diagnostics one.

Direction

  • Reuse the interpreter's hotness counters (the same per-method and loop counters introduced by [browser][coreCLR] R2R: Interpreter PGO instrumentation (block counts) #130517) but add a runtime threshold check: when a method crosses the hot threshold, fire a trigger.
  • Own the async R2R-shard fetch and install. On the trigger, ensure the method's IL shard is resident (via the shard consumer), then asynchronously fetch the method's R2R shard and install it in the async continuation — reusing the browser host's webcil-in-wasm instantiate path (grow the table, instantiate the module) — and finally patch the entry point (via the entry-point work). The interpreter keeps running the method meanwhile.
  • Consume the R2R-only boot-config asset. Use the R2R-only asset entry the splitter emits into the boot configuration to locate and size the shard, and to map the hot method to it.
  • Independent of EventPipe. It must work with no profiling session open and add negligible overhead when disabled.
  • Async-tolerant. The interpreter keeps running the method interpreted while the shard is fetched and instantiated in the background; the entry point is upgraded when ready and picked up on the method's next call (no on-stack replacement).
  • De-duplicate and back off. Avoid repeated requests for the same method/shard; handle in-flight and already-satisfied requests gracefully.

Scope

In: the interpreter-side hotness threshold and trigger; owning the async R2R-shard fetch and install (reusing the browser host's async webcil-in-wasm instantiate) with the IL shard ensured resident first; consuming the R2R-only boot-config asset to locate the shard; de-duplication and back-pressure; the enable/disable switch and low idle overhead.

Out: the counters themselves as a profile producer (#130517); the entry-point patch itself (#130522); IL-shard loading (#130515); the offline profile export (#130518); build-time R2R production.

Relationship to other items

This work is the trigger and owns the async R2R-shard fetch/install; it relies on the shard consumer (#130515) for the IL shard, the entry-point work (#130522) for the final patch, and the splitter (#130523) for the R2R-only boot-config asset. The interpreter counters are shared with the offline producer (#130517) and this live trigger — one counter, two consumers, as intended.

Success criteria

  • In a normal run with no EventPipe, a method that becomes hot triggers its R2R shard to load and its entry point to upgrade, and subsequent calls run native — demonstrable in the prototype.
  • Negligible overhead when the feature is off.

Open questions

  • Threshold policy: call count, loop back-edge count, or both; fixed versus adaptive; where loop back-edge counting fits.
  • The trigger contract shared with the shard consumer and R2R lazy loader, so a hot method and its shard arrive coherently (shared with the shard consumer's open question, [browser][coreCLR] R2R: Runtime shard consumer — lazy IL shard load #130515).
  • Behavior when a method's shard is unavailable or fails to load (stay interpreted).
  • Whether to persist the hot set for earlier tier-up on subsequent runs (relates to the local-storage idea) — likely a later extension.

Note

This issue was drafted with GitHub Copilot assistance.

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions