Skip to content

Add reporting-only PR performance comparisons - #564

Merged
dadhi merged 3 commits into
dadhi:masterfrom
jogibear9988:ci/pr-performance-reports
Oct 25, 2026
Merged

dadhi merged 3 commits into
dadhi:masterfrom
jogibear9988:ci/pr-performance-reports

Conversation

@jogibear9988

@jogibear9988 jogibear9988 commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

PR authors currently have to repeat the manual before/after process described in #64. This adds automated performance reports for PRs targeting master, initially in reporting-only mode.

Measurements

  • A dedicated BenchmarkDotNet 0.15.8 suite measures construction, compilation, compilation plus first invocation, warmed delegate execution, and managed allocations for Standard and LightExpression.
  • Four deterministic workloads cover scalar arithmetic, balanced arithmetic, calls/properties/conditions, and nested-lambda captures: 32 benchmark cases. Strict CompileFast and result/checksum checks reject fallback or incorrect behavior.
  • Build the exact PR base and head using SDK 10.0.301. Use one frozen base-branch harness for both revisions, with isolated outputs and opposite process orders: base/PR, then PR/base.
  • Compare complete benchmark/configuration identities and confidence intervals across both rounds. Missing, invalid or mismatched results are inconclusive. Hosted-runner timing differences do not fail PRs; explicit local blocking is available for later calibration.
  • Default PR runs target .NET 10; manual runs support .NET 8, .NET 10, or both. Raw reports, environment information and source/library hashes are retained as artifacts for 14 days.

PR comments and permissions

Benchmark jobs run with read-only repository permissions on disposable GitHub-hosted runners. A separate workflow_run publisher executes only default-branch code and treats the small report artifact as untrusted data: bounded ZIP reads without extraction, strict schema/numeric validation, and no artifact-provided scripts or prose.

The publisher resolves the PR through GitHub's API, handles empty fork-run PR associations, checks the current head/workflow/attempt, and rejects stale results. New head commits receive a new report; older bot comments are marked Outdated and collapsed with a link to the new report. Same-head reruns update their report instead of creating duplicates.

Validation

  • 13 Python policy/artifact tests pass, including reporting versus blocking exit codes, both-round confirmation, configuration mismatches and invalid archives.
  • 7 mocked Node publisher tests pass, including fork resolution, stale-head/attempt rejection, supersession and rerun ordering.
  • Both workflows pass actionlint.
  • The four-run dry integration exercised all 32 cases against both staged libraries and is correctly classified as inconclusive rather than a performance pass.
  • Full local normal .NET 10 integration completed: all 32 cases in all four counterbalanced runs; complete comparison, reporting-only exit 0. Both base and candidate also pass .NET 8 builds and all eight driver/behavior checks.
  • The new GitHub-hosted performance workflow passed, as did the existing Linux and Windows build/test jobs.
  • Downloaded the real GitHub report artifact and validated it through the trusted publisher: all 32 identities, correct PR/head binding, and a correctly rendered 32-row Markdown table.
  • The first hosted run retained one +3.1% time/noise warning and a +1 B/op allocation warning, with no confirmed time or new-zero-path allocation regressions. Compiler sources are identical; these are useful calibration controls for the reporting-only rollout.

Rollout

Based directly on dadhi/master at 0f37356. For the installation PR, master has no harness yet, so a clearly labelled bootstrap uses the same candidate harness for both revisions. Later PRs use the base-branch harness. The publisher becomes active after its workflow is merged into the default branch; before then this PR can expose benchmark summaries/artifacts but cannot activate that trusted publisher.

This addresses #64's repeatable regression-comparison workflow. It does not enable required performance gates or implement the separate minimal-IL experiment discussed there. The regression README describes confidence/noise limits, the first-invocation JIT boundary, local replay, and the path to calibrated enforcement.

Generated comment preview from the first successful run

net10.0: Comparison complete (reporting only)

Base 0f37356fc9ca → PR ff47206815b2; SDK 10.0.301; harness ff47206815b2 (bootstrap).

Bootstrap: the base does not contain this harness yet. One candidate harness was used for both revisions; later PRs use the base-branch harness.

Backend / phase / workload Base ns PR ns Time change B/op: base → PR Assessment
Light / Compile / Arithmetic 5606.10 5583.30 -0.4% 928.00 → 928.00 Within variation
Light / Compile / CallConditional 3277.59 3370.33 +2.9% 1380.50 → 1380.00 Within variation
Light / Compile / Closure 6189.67 6373.72 +3.1% 3033.00 → 3034.00 Warning / noise
Light / Compile / Scalar 2259.97 2279.25 +1.0% 892.50 → 892.00 Within variation
Light / CompileAndFirstInvoke / Arithmetic 44154.59 44562.84 +0.9% 928.00 → 928.00 Within variation
Light / CompileAndFirstInvoke / CallConditional 98180.77 97954.28 -0.2% 1360.00 → 1360.00 Within variation
Light / CompileAndFirstInvoke / Closure 264538.97 265196.27 +0.2% 3185.00 → 3185.00 Within variation
Light / CompileAndFirstInvoke / Scalar 10808.85 10695.95 -1.0% 872.00 → 872.00 Within variation
Light / Construct / Arithmetic 856.69 866.32 +1.1% 1296.00 → 1296.00 Within variation
Light / Construct / CallConditional 164.36 166.19 +1.1% 360.00 → 360.00 Within variation
Light / Construct / Closure 120.89 110.73 -8.1% 144.00 → 144.00 Within variation
Light / Construct / Scalar 74.31 75.60 +1.7% 120.00 → 120.00 Within variation
Light / Invoke / Arithmetic 1.92 1.92 +0.0% 0.00 → 0.00 Within variation
Light / Invoke / CallConditional 1.91 1.91 -0.0% 0.00 → 0.00 Within variation
Light / Invoke / Closure 35.66 35.10 -1.6% 184.00 → 184.00 Within variation
Light / Invoke / Scalar 1.64 1.64 +0.1% 0.00 → 0.00 Within variation
Standard / Compile / Arithmetic 6199.58 5895.11 -4.9% 945.50 → 931.00 Within variation
Standard / Compile / CallConditional 3433.97 3429.11 -0.1% 1380.50 → 1380.50 Within variation
Standard / Compile / Closure 6623.70 6660.85 +0.6% 3034.50 → 3035.50 Allocation increase
Standard / Compile / Scalar 2478.58 2478.54 +0.0% 888.50 → 888.50 Within variation
Standard / CompileAndFirstInvoke / Arithmetic 44495.31 44667.07 +0.4% 928.00 → 928.00 Within variation
Standard / CompileAndFirstInvoke / CallConditional 99627.55 99756.15 +0.1% 1360.00 → 1360.00 Within variation
Standard / CompileAndFirstInvoke / Closure 264921.79 265842.96 +0.3% 3184.00 → 3184.00 Within variation
Standard / CompileAndFirstInvoke / Scalar 10922.82 10995.30 +0.7% 872.00 → 872.00 Within variation
Standard / Construct / Arithmetic 1321.85 1320.44 -0.1% 1808.00 → 1808.00 Within variation
Standard / Construct / CallConditional 619.67 603.20 -2.6% 680.00 → 680.00 Within variation
Standard / Construct / Closure 346.21 346.00 -0.0% 440.00 → 440.00 Within variation
Standard / Construct / Scalar 263.63 266.20 +1.0% 416.00 → 416.00 Within variation
Standard / Invoke / Arithmetic 1.92 1.92 +0.1% 0.00 → 0.00 Within variation
Standard / Invoke / CallConditional 1.91 1.92 +0.1% 0.00 → 0.00 Within variation
Standard / Invoke / Closure 35.46 35.20 -0.7% 184.00 → 184.00 Within variation
Standard / Invoke / Scalar 1.64 1.64 +0.0% 0.00 → 0.00 Within variation

Two opposite-order process rounds on one GitHub-hosted runner; BDN confidence intervals must be separated in both rounds to classify a >5% time regression. A ≥3% change without that evidence is a warning, not proof. Five measurement iterations/round; hosted-runner noise remains.

Compile excludes delegate invocation; CompileAndFirstInvoke includes the first call/JIT of a new delegate. Invoke is warmed; closure invocation includes creating and calling the returned delegate. MemoryDiagnoser reports managed B/op. Loop/checksum overhead is shared by both revisions.

Workflow run and complete raw artifacts

Build the exact base and candidate libraries with SDK 10.0.301, then compile one shared workload definition against each. Cover Standard and Light construction, compilation, warmed invocation and compilation plus first invocation, with MemoryDiagnoser and full BDN JSON exports. Verify deterministic behavior with strict CompileFast and execute baseline/candidate then candidate/baseline on one machine. Keep the exploratory benchmark entry point unchanged.
Add read-only PR measurements on disposable runners, a default-branch-only artifact publisher, and reporting-only policy. Validate complete BDN identities/statistics across both process rounds. Resolve fork PRs through the API, bind reports to the current head, update same-head reruns, and collapse superseded comments for new commits. Never execute or extract privileged artifacts.

Include policy and mocked publisher tests for missing/nonfinite measurements, two-round confidence/allocation confirmation, reporting/enforcement exit codes, malformed/foreign archives, stale runs and comment supersession. Document bootstrap, fork approvals, hosted-runner noise and the staged rollout for dadhi#64.
Keep backend dispatch and delegate casts outside the warmed batch so adapter overhead does not obscure small emitted-code regressions. Exercise both conditional branches and validate first-invocation and batched-driver checksums for every workload/backend.
@dadhi

dadhi commented Oct 25, 2026

Copy link
Copy Markdown
Owner

Let merge, thank you!

@dadhi
dadhi marked this pull request as ready for review October 25, 2026 11:47
@dadhi
dadhi merged commit 280cbaf into dadhi:master Oct 25, 2026
5 checks passed
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.

2 participants