Skip to content

Add CoreCLR WASM composite R2R microbenchmark lane - #5324

Open
lewing wants to merge 4 commits into
mainfrom
lewing-wasm-coreclr-composite-r2r-lane
Open

lewing wants to merge 4 commits into
mainfrom
lewing-wasm-coreclr-composite-r2r-lane

Conversation

@lewing

@lewing lewing commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

Adds a CoreCLR browser-WASM composite ReadyToRun microbenchmark lane next to the per-assembly R2R lane from #5297.

Dependencies

Changes

  • CLI (micro_benchmarks.py): new --wasm-ready-to-run-composite option that implies R2R. --wasm-ready-to-run still means per-assembly. Both options require --wasm --wasm-runtime-flavor CoreCLR. configure_wasm_ready_to_run always writes both PERFLAB_WASM_READY_TO_RUN and PERFLAB_WASM_READY_TO_RUN_COMPOSITE, so a stale parent value can't select the wrong mode. benchmarks_ci.py accepts --wasm-workload-source with either mode.
  • Job script (run_performance_job.py): r2r_run_type == "r2r_composite" maps to R2RType=r2r_composite and passes --wasm-ready-to-run-composite to the Helix work item. The workload-source SDK cohort applies to both R2R modes. r2r_composite is rejected for any runtime type other than wasm_coreclr.
  • MSBuild (MicroBenchmarks.Wasm.targets):
    • PublishReadyToRunComposite now comes from the selected mode. PublishTrimmed, WebCIL and ContainerFormat=wasm are the same as before, so per-assembly mode is unchanged.
    • ValidateWasmReadyToRunConfiguration checks that the applied composite value matches the selected mode, and that composite mode is only used together with R2R.
    • ValidateWasmReadyToRunOutputs (after _CreateR2RImages), composite mode: requires exactly one _ReadyToRunCompileList item with CreateCompositeImage=true. Its OutputR2RImage must end in .r2r.wasm and exist on disk, and there must be at least one _ReadyToRunCompositeBuildInput or _ReadyToRunCompositeUnrootedBuildInput.
    • ValidateWasmReadyToRunOutputs, per-assembly mode: now also fails if a composite image was planned.
    • New ValidateWasmReadyToRunCompositePublishAssets (after ProcessPublishFilesForWasm): requires exactly one _WasmCompositePublishStaticWebAsset with AssetTraitValue=readyToRunComposite. GenerateWasmBootJson routes exactly that asset to resources.coreAssembly (with isCompositeImage). This catches a composite that was compiled but never shipped or loaded.
    • I ran every guard branch locally in a stub MSBuild harness: each failure path reported its error, and the valid composite and per-assembly paths passed.
  • Crossgen2Tasks shim (temporary): build_wasm_coreclr_payload copies staging/Crossgen2Tasks/ into the Helix payload as crossgen2-tasks/ when the artifact has it (and fails on an incomplete copy). For the r2r_composite lane only, run_performance_job.py exports PERFLAB_WASM_CROSSGEN2_TASKS_DIR in the Helix pre-commands, and micro_benchmarks.py turns that into Crossgen2SdkOverridePropsPath/Crossgen2SdkOverrideTargetsPath environment properties in composite mode. They must be environment properties, not set in MicroBenchmarks.Wasm.targets, because the WebAssembly SDK reads them during props evaluation, before BenchmarkDotNet imports that file. Per-assembly R2R keeps the SDK's own tasks. If the artifact has no shim, the job logs a warning and the composite build uses the SDK's tasks.
  • Pipeline: new coreclr_r2r_composite_v8 job in runtime-wasm-perf-jobs.yml. It is identical to coreclr_r2r_v8 except r2rRunType: 'r2r_composite': same release-branch exclusion, payload, machine and engine. The run-performance-job.yml workload-source condition now covers both R2R types.
  • Tests and docs: test_wasm_coreclr_r2r.py covers mode parsing and validation, env configuration (including stale values), work item forwarding, run configuration, the MSBuild property and guard structure, and a check that the new pipeline lane matches the per-assembly lane apart from its identity. They also cover shim staging in the payload, the pre-command export, and that the override applies to composite mode only. The docs describe the new option and the shim variable.

Validation

Results identity

Composite runs report R2RType=r2r_composite, so PerfLab keeps them in a separate history from per-assembly R2RType=r2r and from the interpreted coreclr_v8 lane. Existing histories don't change.

Risks to watch in the first validation run

  • Crossgen2 time/memory vs. --buildTimeout 1200: one composite covers the whole trimmed benchmark closure, including Roslyn (Microsoft.CodeAnalysis*). It is one large, serial compile rather than many small ones, and could exceed the BDN build timeout or the machine's memory.
  • BDN's WASM launcher and coreAssembly: the composite owner is loaded from the boot config's resources.coreAssembly before CoreCLR initializes, with component stubs staying in the TPA. BDN's generated WASM host must use the SDK's boot config and loader unchanged. If it doesn't, stubs will fail-fast because they can't find the owner.
  • ColdStart/instantiation cost: instantiating one large .wasm image may noticeably move first-iteration and startup-sensitive numbers compared with per-assembly R2R.
  • Shim compatibility: Crossgen2Tasks.dll is built against the same runtime global.json SDK that the artifact ships as dotnet-none, so it should load into that SDK's MSBuild. A mismatch would show up as a task-load error at the start of the composite compile.

Notes (no changes made)

  • PublishReadyToRunExclude: none remain in MicroBenchmarks.csproj; Enable Jil for CoreCLR WASM R2R #5317, which removed the Jil exclusion, is already in main. Any future exclusion would keep that assembly out of the composite (it would stay IL/interpreted), which is the expected composite behavior.
  • _AOT_InternalForceInterpretAssemblies (Roslyn): this is a Mono AOT item and has no effect on CoreCLR Crossgen2. In composite mode, Roslyn is compiled into the composite, the main contributor to the compile-time risk above. If that turns out too slow, a follow-up could exclude Microsoft.CodeAnalysis* from the composite.

Note

This PR description was generated with GitHub Copilot assistance.

Copilot AI lite review requested due to automatic review settings September 28, 2026 15:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The WASM targets file is not imported, so the composite configuration and validation do not run.

Review effort: Lite
Findings: 1 High severity

Open (1)
What changed in this PR

Adds an opt-in CoreCLR browser-WASM composite ReadyToRun microbenchmark lane with distinct result tracking.

Changes:

  • Adds composite R2R CLI, validation, environment propagation, and job forwarding.
  • Adds MSBuild output and publish-asset checks.
  • Adds pipeline wiring, tests, and documentation.
File Summary
src/​benchmarks/​micro/​MicroBenchmarks.Wasm.targets Composite R2R configuration and validation; currently not imported by the project, so these changes are inactive.
scripts/​tests/​test_wasm_coreclr_r2r.py Tests mode parsing, forwarding, configuration, and pipeline behavior.
scripts/​run_performance_job.py Propagates composite mode and result identity.
scripts/​micro_benchmarks.py Adds composite R2R CLI support.
scripts/​benchmarks_ci.py Accepts composite workload-source runs.
eng/​pipelines/​templates/​run-performance-job.yml Enables workload-source forwarding.
eng/​pipelines/​runtime-wasm-perf-jobs.yml Defines the composite benchmark lane.
docs/​benchmarking-workflow-dotnet-runtime.md Documents composite R2R usage and dependencies.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/benchmarks/micro/MicroBenchmarks.Wasm.targets
LoopedBard3
LoopedBard3 previously approved these changes Sep 28, 2026

@LoopedBard3 LoopedBard3 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems good to me, let's merge once we have the dependencies merged.

DrewScoggins
DrewScoggins previously approved these changes Sep 28, 2026

@DrewScoggins DrewScoggins left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Add a coreclr_r2r_composite_v8 job (r2rRunType r2r_composite) alongside
the per-assembly coreclr_r2r_v8 lane. The mode flows through
run_performance_job.py (R2RType=r2r_composite, a separate PerfLab
history) to a new --wasm-ready-to-run-composite micro_benchmarks option,
which sets PERFLAB_WASM_READY_TO_RUN_COMPOSITE for MSBuild.

MicroBenchmarks.Wasm.targets now sets PublishReadyToRunComposite from
the selected mode, validates it, and in composite mode verifies that
exactly one <entry>.r2r.wasm composite image was produced with
component inputs and that it was defined as the readyToRunComposite
publish asset that GenerateWasmBootJson routes to coreAssembly.

Depends on dotnet/runtime#134618.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Composite CoreCLR WASM R2R needs ReadyToRun SDK tasks that name the
owner image <entry>.r2r.wasm (dotnet/sdk#56395), which the SDK shipped
in the BrowserWasmCoreCLR perf artifact does not have yet.
dotnet/runtime#135204 stages runtime's wasm-aware Crossgen2Tasks shim
into that artifact as staging/Crossgen2Tasks.

Copy the shim into the Helix payload when present, export its location
as PERFLAB_WASM_CROSSGEN2_TASKS_DIR for the r2r_composite lane only, and
in composite mode pass it to the WebAssembly SDK through
Crossgen2SdkOverridePropsPath/Crossgen2SdkOverrideTargetsPath. These must
be environment properties because the SDK reads them during props
evaluation. Per-assembly R2R keeps the SDK's own ReadyToRun tasks.

TODO: remove once the SDK carries dotnet/sdk#56395
(dotnet/runtime#135023).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings October 5, 2026 11:19
@lewing
lewing dismissed stale reviews from DrewScoggins and LoopedBard3 via 3312c0c October 5, 2026 11:19
@lewing
lewing force-pushed the lewing-wasm-coreclr-composite-r2r-lane branch from c61ba13 to 3312c0c Compare October 5, 2026 11:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Clear inherited Crossgen2 override paths before configuring R2R modes.

Review effort: Lite
Findings: 1 Medium severity

Open (1)
Resolved since last review (1)

Comment thread scripts/micro_benchmarks.py
configure_wasm_crossgen2_sdk_override now removes inherited
Crossgen2SdkOverridePropsPath/Crossgen2SdkOverrideTargetsPath before
deciding whether to apply the shim, so per-assembly R2R always keeps
the SDK's ReadyToRun tasks and a composite run without a staged shim
cannot pick up a stale path. PERFLAB_WASM_CROSSGEN2_TASKS_DIR remains
the only way to select a shim.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings October 5, 2026 13:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved critical MSBuild validation and moderate shim-handling findings remain.

Review effort: Lite
Findings: 1 High severity

Open (1)
Resolved since last review (1)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Raise an error for incomplete Crossgen2Tasks shims

scripts/​build_runtime_payload.py:361

When the artifact is supplied as a directory and staging/Crossgen2Tasks exists but contains none of the required files (or only unrelated files), this branch treats the malformed shim as an old artifact and silently falls back to the SDK tasks. That contradicts the intended fail-fast behavior for an incomplete copy and makes the composite lane proceed with tasks that will fail the runtime's owner-name validation; distinguish an absent shim directory from a present-but-incomplete one and raise ValueError for the latter.

Comment thread src/benchmarks/micro/MicroBenchmarks.Wasm.targets
maraf
maraf previously approved these changes Oct 5, 2026
lewing added a commit to dotnet/runtime that referenced this pull request Oct 5, 2026
…ifact (#135204)

The new composite R2R microbenchmark lane in dotnet/performance#5324
(`coreclr_r2r_composite_v8`) publishes CoreCLR browser-wasm with
`PublishReadyToRunComposite`. #134618's
`_WasmCoreClrValidateCompositeTasks` rejects that publish unless the SDK
ReadyToRun tasks name the owner `<entry>.r2r.wasm`. The SDK tasks only
learn to do that in dotnet/sdk#56395, which hasn't reached runtime's
global.json SDK yet (11.0.100-rc.1.26420.103).

This PR copies the in-tree wasm-aware task shim, the same one
Wasm.Build.Tests use via
`Crossgen2SdkOverridePropsPath`/`Crossgen2SdkOverrideTargetsPath`, into
the `BrowserWasmCoreCLR` perf artifact. The shim comes from
`artifacts/bin/Crossgen2Tasks/<config>/`, which `Build.proj` already
produces.

Staged layout (flat, no config subfolder; this is the path
dotnet/performance consumes):

```
staging/Crossgen2Tasks/Crossgen2Tasks.dll
staging/Crossgen2Tasks/Microsoft.NET.CrossGen.props
staging/Crossgen2Tasks/Microsoft.NET.CrossGen.targets
```

The step fails if the source directory or any of these three files is
missing. Only the CoreCLR leg (`includeCoreClrToolchainPacks: true`)
changes; the Mono artifact is untouched.

This is temporary: remove it once dotnet/sdk#56395 reaches global.json.
Tracked by #135023.

Validation: YAML parses (`python3 yaml.safe_load`) and `git diff
--check` is clean. The pipeline itself hasn't run yet.

> [!NOTE]
> This PR was generated with the help of GitHub Copilot.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a287cfc0-a881-4272-9024-bdaf9d9db4ef
A BrowserWasmCoreCLR directory artifact with a staging/Crossgen2Tasks
folder that lacks the required files was treated like an artifact
without the shim, silently falling back to the SDK ReadyToRun tasks.
Only a missing folder (directory artifacts) or no extracted entries
(archives) now means "no shim"; anything else must contain
Crossgen2Tasks.dll and Microsoft.NET.CrossGen.props/.targets or
build_wasm_coreclr_payload raises ValueError. Add archive coverage.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings October 5, 2026 15:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Composite R2R workload-source cohorts can skip required Crossgen2 task shim staging.

Review effort: Lite
Findings: 1 High severity

Open (1)
Resolved since last review (1)

Comment thread scripts/run_performance_job.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants