Skip to content

[wasm] [spmi] Broaden browser/wasm SuperPMI collections - #136717

Open
lewing wants to merge 2 commits into
mainfrom
lewing-wasm-superpmi-coverage
Open

lewing wants to merge 2 commits into
mainfrom
lewing-wasm-superpmi-coverage

Conversation

@lewing

@lewing lewing commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Wasm has no runtime JIT, so crossgen2 is the only way to collect browser/wasm SuperPMI contexts. Today's only wasm collection, libraries.crossgen2 (composite, from #135296), compiles just the browser-wasm runtime pack: 89,081 contexts. The x64 libraries.crossgen2 collection has 284,215, mostly because its input is all of Core_Root (331 assemblies vs 181). The CoreLib partition is about the same size on both (27.2k wasm vs 28.0k x64). The other collection kinds aren't possible for wasm: *.run needs a runtime JIT, PMI would load the wasm32 JIT into the x64 runtime, and there's no wasm NativeAOT target.

Changes

A. Wider libraries input. The wasm collection now also compiles the portable non-framework IL at the top level of Core_Root: Roslyn, TraceEvent, FSharp.Core, Newtonsoft.Json, xunit, and the out-of-band libraries. Windows-only libraries are skipped. These are the inputs the host libraries collections already compile. The runtime pack is now passed to superpmi_collect_setup.py with a new -target_runtime_pack_directory argument instead of InputDirectory.

B. New coreclr_tests.crossgen2 wasm collection. crossgen2 compiles the JIT/ tests from the AnyOS coreclr test build one assembly at a time, against the runtime pack plus one staged copy of TestLibrary/XUnitWrapperLibrary. Tests built with optimizations disabled should also add MinOpts contexts; there are only 20 today. Partitions keep each test directory together, so dependencies copied next to a test resolve through -r:<input dir>/*.dll. This is the closest wasm can get to the coreclr_tests.run collections that other platforms have. The Arm and x86 hardware intrinsics tests are excluded: on wasm they mostly compile software fallbacks, and they were most of the input (934 MB → 288 MB). Each crossgen2 invocation is capped at 900 s (new superpmi.py -crossgen2_timeout); a timed-out invocation is killed, logged, and its method contexts dropped, so one slow test can't take down a work item.

is_managed_assembly and get_assembly_simple_name move from superpmi.py to jitutil.py so the setup script can use them. Host collections are unchanged.

Validation

superpmi-collect-test build 1656419, on the first commit:

  • A: wasm libraries.crossgen2 = 221,445 contexts (was 89,081, 2.5×); 10 partitions, 17 minutes in Helix.
  • B: 36 of 37 partitions passed in under 5 minutes each (1.24M contexts before cross-partition dedup). Partition 31 hit the 2-hour work item timeout. The cause is JIT/Regression_3/DevDiv_255294, a single huge method that already opts out of crossgen and NativeAOT testing. With a release crossgen2 it takes the wasm JIT ~298 s versus ~2 s for x64, mostly in redundant branch optimization (optRedundantBranch → optRelopImpliesRelop). The second commit adds the timeout and the hardware intrinsics exclusion.
  • The other failures in that run also fail on main's collection or are unrelated: run collections ("No files found to merge"), aspire on Windows (clone hits "Filename too long"), and Pri1 Runtime Tests Run osx arm64 (canceled by job timeout).

Local validation of the second commit:

  • Collection with a 20 s timeout over DevDiv_255294 plus quick tests: the slow compile was killed and dropped, and the rest merged into a valid MCH. Collection without a timeout is unchanged.
  • Setup dry run over the real downloaded JIT/ test tree: 14 partitions; only HardwareIntrinsics/General* and *Wasm* remain.

Supersedes the remaining work in #132538, which #135296 continued.

Note

This PR description was generated with GitHub Copilot.

Wasm has no runtime JIT, so crossgen2 is the only way to collect wasm
method contexts. The wasm libraries collection only compiled the
browser-wasm runtime pack (89k contexts vs 284k for x64, whose input is
all of Core_Root).

- libraries (composite): also compile the portable non-framework IL at the
  top level of Core_Root (Roslyn, TraceEvent, FSharp.Core, Newtonsoft.Json,
  xunit, out-of-band libraries), skipping Windows-only libraries. The
  runtime pack now comes in via -target_runtime_pack_directory.
- New coreclr_tests crossgen2 collection over the JIT/ tests of the coreclr
  test build, compiled per assembly against the runtime pack and staged
  test infrastructure. Partitions keep each test directory together so
  sibling dependencies resolve via -r:<input dir>/*.dll.
- Move is_managed_assembly/get_assembly_simple_name into jitutil.py.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@lewing

lewing commented Oct 30, 2026

Copy link
Copy Markdown
Member Author

/azp run runtime-coreclr superpmi-collect-test

Note

Comment posted by GitHub Copilot on behalf of @lewing.

@azure-pipelines

Copy link
Copy Markdown
No pipelines are associated with this pull request.

@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Oct 30, 2026
@azure-pipelines

azure-pipelines Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
10 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

@lewing

lewing commented Oct 30, 2026

Copy link
Copy Markdown
Member Author

/azp run runtime-coreclr superpmi-collect-test

Note

Comment posted by GitHub Copilot on behalf of @lewing.

@azure-pipelines

Copy link
Copy Markdown
No pipelines are associated with this pull request.

@lewing

lewing commented Oct 30, 2026

Copy link
Copy Markdown
Member Author

/azp run runtime-coreclr superpmi-collect-test

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

…ests input

The wasm coreclr_tests collection lost a whole partition to one test:
JIT/Regression_3/DevDiv_255294 (a single huge method; already opted out of
crossgen and NativeAOT testing) takes the wasm JIT ~300s in a release
crossgen2 vs ~2s for x64, mostly in redundant branch optimization, and ran
past the 2-hour Helix work item timeout with the checked JIT + collector.

- superpmi.py: new -crossgen2_timeout. Each invocation gets its own shim
  log directory so a killed invocation's .mc file can be dropped; the
  timed-out assembly is logged.
- superpmi-collect.proj: use a 900s timeout for cross-target per-assembly
  crossgen2 collections.
- superpmi_collect_setup.py: exclude_directories accepts paths relative to
  the input directory; the wasm coreclr_tests collection skips the Arm and
  x86 hardware intrinsics tests (934MB -> 288MB of input), which on wasm
  mostly compile software fallbacks.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@lewing

lewing commented Oct 30, 2026

Copy link
Copy Markdown
Member Author

/azp run runtime-coreclr superpmi-collect-test

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@lewing
lewing marked this pull request as ready for review November 1, 2026 02:53
@lewing
lewing requested a review from AndyAyersMS November 1, 2026 02:53
lewing added a commit that referenced this pull request Nov 2, 2026
…36740)

`optRedundantBranch` walks up the dominator tree from each conditional
branch. Its only bound, `matchLimit = 4`, counts dominating compares
that are *related* to the current one (`rii.canInfer`). With a long
chain of unrelated compares every relop walks all the way to the method
entry, calling `optRelopImpliesRelop` → `GetRelatedRelop` → `VNForFunc`
at each step, so the phase is O(n²) in the chain length.

This caps the total number of dominating compares inspected per relop at
128 (overridable in DEBUG via `DOTNET_JitRboDominatorLimit`).

## Trigger

`src/tests/JIT/Regression_3/DevDiv_255294`: `HugeMethod` is 62,348 `if
(f) i++;` on a static bool. Each `f` load goes through a static-base
helper call that may run a cctor. Since #136106, VN treats those helpers
as heap writes, so each load gets a distinct VN and no dominating
compare is ever related.

- wasm (`CORINFO_HELP_GET_NONGCSTATIC_BASE`) was already slow before
#136106.
- #136106 made x64 R2R (`READYTORUN_NONGCSTATIC_BASE`) slow too. This
attribution comes from the mechanism, JitDumps and before/after
crossgen2 timings. It was not bisected.

Found because the new browser/wasm SuperPMI `coreclr_tests` collection
(#136717) hit the 2-hour Helix timeout on this test.

## Measurements

osx-arm64 host, release JITs, crossgen2 from current main,
`--parallelism:1`, on generated methods with the DevDiv_255294 shape:

| Method | wasm before → after | x64 before → after |
|---|---|---|
| 62,335 branches | 304.5 s → 5.8 s | 219.6 s → 1.5 s |
| 16,000 branches | 11.7 s → 1.4 s | 11.1 s → 0.9 s |

## SuperPMI asmdiffs (checked base vs. diff)

- linux-x64 and linux-arm64 `coreclr_tests.run`, `libraries.crossgen2`,
`libraries.pmi` (~2.5M contexts): **zero diffs** at limit 128. At limit
64 there were 2 regressions per arch
(`JitTest_cond32_NaN_il.Test:RunTests`,
`JitTest_cond64_NaN_il.Test:RunTests`, about +61%), so I picked 128.
- browser/wasm `libraries.crossgen2` (87,061 contexts): no real diffs.
The run reports ~290 same-size binary diffs whose disassembly is
identical. A base-vs-identical-base run shows the same noise (250).
- **Not covered locally:** benchmarks/aspnet collections, osx-arm64
collections, and throughput (no Pin on macOS). CI's superpmi-diffs and
tpdiff on this PR should cover those.

## Possible follow-up (out of scope)

With the cap, wasm still takes ~5.8 s vs. 1.5 s for x64 at 62k branches,
because some wasm-only phases also grow superlinearly ("Wasm control
flow" 4.5 s, "Generate code" 2.9 s, "Set block weights" 0.5 s).

> [!NOTE]
> This PR description was generated with GitHub Copilot.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant