Skip to content

[Perf] Windows/x64: 6 Improvements on 6/2/2026 10:24:00 PM +00:00 #74238

Closed

Description

@performanceautofiler

Run Information

Name Value
Architecture x64
OS Windows 10.0.22631
Queue ViperWindows
Baseline c7d89359fb2afdb3cf045f26c61350885a714811
Compare ac695692911547e710e43fa7f6e38546a13504a5
Diff Diff
Configs CompilationMode:tiered, RunKind:micro

Improvements in System.Linq.Tests.Perf_Enumerable

Benchmark Baseline Test Test/Base Test Quality Edge Detector Baseline IR Compare IR IR Ratio
97.06 ns 31.35 ns 0.32 0.01 False
98.19 ns 35.27 ns 0.36 0.04 False
93.08 ns 55.75 ns 0.60 0.03 False
72.38 ns 44.74 ns 0.62 0.07 False

graph
graph
graph
graph
Test Report

Repro

General Docs link: https://github.com/dotnet/performance/blob/main/docs/benchmarking-workflow-dotnet-runtime.md

git clone https://github.com/dotnet/performance.git
py .\performance\scripts\benchmarks_ci.py -f net8.0 --filter 'System.Linq.Tests.Perf_Enumerable*'
Details

System.Linq.Tests.Perf_Enumerable.Aggregate(input: IEnumerable)

ETL Files

Histogram

JIT Disasms

System.Linq.Tests.Perf_Enumerable.SingleWithPredicate_FirstElementMatches(input: IEnumerable)

ETL Files

Histogram

JIT Disasms

System.Linq.Tests.Perf_Enumerable.LastWithPredicate_FirstElementMatches(input: IEnumerable)

ETL Files

Histogram

JIT Disasms

System.Linq.Tests.Perf_Enumerable.Min(input: IEnumerable)

ETL Files

Histogram

JIT Disasms

Docs

Profiling workflow for dotnet/runtime repository
Benchmarking workflow for dotnet/runtime repository


Run Information

Name Value
Architecture x64
OS Windows 10.0.22631
Queue ViperWindows
Baseline c7d89359fb2afdb3cf045f26c61350885a714811
Compare ac695692911547e710e43fa7f6e38546a13504a5
Diff Diff
Configs CompilationMode:tiered, RunKind:micro

Improvements in System.IO.Tests.MemoryStreamChunkedTests

Benchmark Baseline Test Test/Base Test Quality Edge Detector Baseline IR Compare IR IR Ratio
248.74 μs 230.58 μs 0.93 0.16 False

graph
Test Report

Repro

General Docs link: https://github.com/dotnet/performance/blob/main/docs/benchmarking-workflow-dotnet-runtime.md

git clone https://github.com/dotnet/performance.git
py .\performance\scripts\benchmarks_ci.py -f net8.0 --filter 'System.IO.Tests.MemoryStreamChunkedTests*'
Details

System.IO.Tests.MemoryStreamChunkedTests.WriteSpan(ChunkSize: 1)

ETL Files

Histogram

JIT Disasms

Docs

Profiling workflow for dotnet/runtime repository
Benchmarking workflow for dotnet/runtime repository


Run Information

Name Value
Architecture x64
OS Windows 10.0.22631
Queue ViperWindows
Baseline c7d89359fb2afdb3cf045f26c61350885a714811
Compare ac695692911547e710e43fa7f6e38546a13504a5
Diff Diff
Configs CompilationMode:tiered, RunKind:micro

Improvements in System.Collections.Perf_Frozen<Int16>

Benchmark Baseline Test Test/Base Test Quality Edge Detector Baseline IR Compare IR IR Ratio
16.32 μs 14.77 μs 0.90 0.36 False

graph
Test Report

Repro

General Docs link: https://github.com/dotnet/performance/blob/main/docs/benchmarking-workflow-dotnet-runtime.md

git clone https://github.com/dotnet/performance.git
py .\performance\scripts\benchmarks_ci.py -f net8.0 --filter 'System.Collections.Perf_Frozen<Int16>*'
Details

System.Collections.Perf_Frozen<Int16>.ToFrozenSet(Count: 512)

ETL Files

Histogram

JIT Disasms

Docs

Profiling workflow for dotnet/runtime repository
Benchmarking workflow for dotnet/runtime repository

Activity

  1. LoopedBard3 commented on Jun 9, 2026

    @LoopedBard3
    Member

    🔍 Automated Triage Analysis

    Summary: Verified improvement in Aggregate(input: IEnumerable) — caused by commit 92296631121c ("JIT: add post-inline cleanup for no-return calls (#128513)"). 5 tests bisected to related culprit commits. 1 other test(s) found unrelated commits (possible alignment artifacts). ⚠️ Note: Historical data shows bimodal behavior — bisection result may be unreliable.

    Finding Confidence: 3/5 (analysis accuracy)
    Improvement Confidence: 3/5 (likelihood of true improvement)

    Likely Cause: 92296631121c2eb917f58dfca70864821cba250a

    🤖 Proposed Next Actions: Uncertain — flag for re-triage — 2 proposed (rule R5_look_again — see Full Analysis for the table).

    📊 Full Analysis (click to expand)

    Summary: 5 confirmed improvements and 1 borderline across LINQ, MemoryStream, and FrozenSet benchmarks (-7% to -68%). The 4 LINQ IEnumerable tests improved dramatically (-38% to -68%) likely attributed to commit a2ec76b0691e (JIT loop cloning profitability heuristic), which changed code generation for enumeration patterns. Finding confidence 4/5, improvement confidence 4/5.

    Issue Overview

    • Issue: [Perf] Windows/x64: 6 Improvements on 6/2/2026 10:24:00 PM +00:00 #74238 - [Perf] Windows/x64: 6 Improvements on 6/2/2026 10:24:00 PM +00:00
    • Type: Performance Improvement
    • Date: 2026-06-02 | Queue: Windows.11.Amd64.Viper.Perf | OS/Arch: Windows/x64
    • Commits: c7d89359fb2a → ac695692911 (28 commits)
    • Labels: untriaged, os-windows, perf-improvement, arch-x64, branch-refs/heads/main, runtime-coreclr, kind-micro, compilationmode-tiered, runkind-micro
    • Runtime Stack: Desktop + CoreCLR (implicit)
    • Historical Data: Available (296-300 runs per test) — very high data confidence

    Test Analysis

    Test Name Baseline Compare Δ% μ σ n z Thresh% Noise? Assessment
    Perf_Enumerable.Aggregate 97.06 ns 31.35 ns -67.7% 95.69 0.35 300 -183.3 5% N Step change, ultra-stable
    Perf_Enumerable.SingleWithPredicate_FirstElementMatches 98.19 ns 35.27 ns -64.1% 100.38 0.87 300 -75.3 5% N Drift + massive step
    Perf_Enumerable.LastWithPredicate_FirstElementMatches 93.08 ns 55.75 ns -40.1% 92.91 0.54 300 -68.9 5% N Step change, bimodal after
    Perf_Enumerable.Min 72.38 ns 44.74 ns -38.2% 73.34 1.23 300 -23.3 5% N Step change, bimodal after
    MemoryStreamChunkedTests.WriteSpan(ChunkSize: 1) 248.74 μs 230.58 μs -7.3% 258.85 μs 9.14 μs 296 -3.1 7.07% N Step change (second step down)
    Perf_Frozen<Int16>.ToFrozenSet(Count: 512) 16.32 μs 14.77 μs -9.5% 15.78 μs 0.60 μs 300 -1.7 7.56% Borderline Conflicting signals

    Legend: μ=mean, σ=stddev, n=runs, z=z-score, Thresh%=adaptive threshold

    Finding Confidence: 4/5 - Excellent historical data (300 runs per test), low variance for LINQ tests (CV 0.4-1.7%), clear step changes visible in all confirmed improvements. Not verified via RunWithBuildAtHash.

    Candidate Stack Relevance

    Commit Touched Paths (summary) Relevance Notes
    a2ec76b0691e src/coreclr/jit/loopcloning.cpp, compiler.h, jitconfigvalues.h Relevant JIT loop cloning profitability heuristic — directly affects codegen for enumeration loops
    b3db78f44230 src/coreclr/jit/objectalloc.cpp Relevant CEA fix for enumerator locals — correctness fix that also changes cloning eligibility
    33b43115a73e src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs Shared Reverts MemoryStream breaking change, removes Array.MaxLength property lookups
    92296631121c src/coreclr/jit/fginline.cpp, compiler.cpp Relevant Post-inline cleanup for no-return calls
    db8761084874 src/coreclr/jit/targetamd64.h Relevant Don't kill FP/SIMD/mask regs across x64 write barriers

    Confirmed Improvements

    System.Linq.Tests.Perf_Enumerable.Aggregate (-67.7%)

    • Delta: 97.06 ns → 31.35 ns (-67.7%)
    • Historical Context: μ=95.69 (σ=0.35, n=300); z-score=-183.3; adaptive threshold=5%
    • Assessment: Clean step change on an ultra-stable test (CV=0.37%). After values tightly clustered at ~31.4 ns.
    • Finding Confidence: 4/5 - Excellent historical data, extremely low variance, unmistakable step change
    • Improvement Confidence: 4/5 - Massive delta with extreme z-score, clear JIT candidates, but multiple possible JIT commits
    • Likely Cause: a2ec76b0691e - "JIT: add profitability heuristic for loop cloning"
      • Affected Areas: JIT / Loop Cloning / Enumeration
      • Stack Relevance: Relevant
      • Rationale: The new loop cloning profitability heuristic rejects unprofitable clones for large loop bodies. For IEnumerable LINQ operations that iterate via virtual GetEnumerator/MoveNext, this changes the JIT's code generation strategy. By not cloning loops with insufficient benefit ratio, the simpler control flow graph enables better downstream optimizations (potentially allowing CEA to stack-allocate enumerators). The consistent 38-68% speedup across 4 different IEnumerable LINQ operators strongly suggests a shared codepath change. Commit b3db78f44230 (CEA fix) may also contribute by making escape analysis more robust for enumerator locals.
      • Candidates Considered:
        • a2ec76b0691e - Loop cloning profitability gate, changes codegen for loops with GDV tests
        • b3db78f44230 - CEA fix for enumerator locals, correctness fix that may enable better stack allocation
        • 92296631121c - Post-inline cleanup, could improve inlining decisions
    • Verification Status: Not verified

    System.Linq.Tests.Perf_Enumerable.SingleWithPredicate_FirstElementMatches (-64.1%)

    • Delta: 98.19 ns → 35.27 ns (-64.1%)
    • Historical Context: μ=100.38 (σ=0.87, n=300); z-score=-75.3; adaptive threshold=5%
    • Assessment: Massive step improvement. Before series showed minor pre-existing drift (earlyMean=100.55 → recentMean=98.19), but improvement far exceeds that drift.
    • Finding Confidence: 4/5 - Strong historical data, clear step change despite pre-existing minor drift
    • Improvement Confidence: 4/5 - Extreme z-score, same causal mechanism as Aggregate, corroborated by 4 tests
    • Likely Cause: a2ec76b0691e - "JIT: add profitability heuristic for loop cloning"
      • Affected Areas: JIT / Loop Cloning / Enumeration
      • Stack Relevance: Relevant
      • Rationale: Same mechanism as Aggregate — the profitability heuristic changes loop code generation for IEnumerable iteration. After values have higher variance (~32-38 ns) than Aggregate, possibly due to different predicate evaluation paths.
      • Candidates Considered: Same as Aggregate
    • Verification Status: Not verified

    System.Linq.Tests.Perf_Enumerable.LastWithPredicate_FirstElementMatches (-40.1%)

    • Delta: 93.08 ns → 55.75 ns (-40.1%)
    • Historical Context: μ=92.91 (σ=0.54, n=300); z-score=-68.9; adaptive threshold=5%
    • Assessment: Clear step improvement. After values are bimodal (~45-48 and ~55-57 ns clusters), suggesting two execution paths both substantially faster than baseline.
    • Finding Confidence: 4/5 - Excellent data, bimodal after distribution noted but both clusters well below baseline
    • Improvement Confidence: 4/5 - Strong signal, same root cause as other LINQ tests, bimodal distribution suggests tiered compilation or branch prediction effects
    • Likely Cause: a2ec76b0691e - "JIT: add profitability heuristic for loop cloning"
      • Affected Areas: JIT / Loop Cloning / Enumeration
      • Stack Relevance: Relevant
      • Rationale: Same shared mechanism. The bimodal after-values may indicate non-deterministic codepath selection (tiered JIT promotion timing or branch prediction), but both paths are dramatically faster than baseline.
      • Candidates Considered: Same as Aggregate
    • Verification Status: Not verified

    System.Linq.Tests.Perf_Enumerable.Min (-38.2%)

    • Delta: 72.38 ns → 44.74 ns (-38.2%)
    • Historical Context: μ=73.34 (σ=1.23, n=300); z-score=-23.3; adaptive threshold=5%
    • Assessment: Clear step improvement. Moderate historical variance (CV=1.67%) with bimodal after-values (~44-46 and ~56-59 ns clusters), both well below historical baseline.
    • Finding Confidence: 4/5 - Good data quality, clear improvement above threshold despite moderate variance
    • Improvement Confidence: 4/5 - Strong z-score, consistent with other LINQ test improvements, corroborated pattern
    • Likely Cause: a2ec76b0691e - "JIT: add profitability heuristic for loop cloning"
      • Affected Areas: JIT / Loop Cloning / Enumeration
      • Stack Relevance: Relevant
      • Rationale: Same shared mechanism as other LINQ tests. Min has a simpler body than Aggregate but iterates the full collection, consistent with loop-level optimization.
      • Candidates Considered: Same as Aggregate
    • Verification Status: Not verified

    System.IO.Tests.MemoryStreamChunkedTests.WriteSpan (-7.3%)

    • Delta: 248.74 μs → 230.58 μs (-7.3%)
    • Historical Context: μ=258.85 μs (σ=9.14 μs, n=296); z-score=-3.1; adaptive threshold=7.07%
    • Assessment: Step change confirmed. Before series was bimodal (~266k and ~248k ns clusters indicating a prior step change); compare values form a new lower cluster ~230-235k ns.
    • Finding Confidence: 3/5 - Good data but bimodal before-series complicates baseline interpretation
    • Improvement Confidence: 3/5 - Direct code path match but the change is a revert (removes bounds checks), and prior bimodality suggests other factors at play
    • Likely Cause: 33b43115a73e - "Revert MemoryStream breaking change"
      • Affected Areas: BCL / System.IO / MemoryStream
      • Stack Relevance: Shared
      • Rationale: This commit directly modifies MemoryStream.cs, reverting capacity validation that used Array.MaxLength (a property requiring a static field access) back to int.MaxValue (a JIT constant). The removal of MemStreamMaxLength property and ArgumentOutOfRangeException.ThrowIfGreaterThan from the constructor path eliminates overhead in the WriteSpan hot loop which creates MemoryStream instances. The 7.3% improvement aligns with removing a few branch+property-access instructions from a tight write loop.
      • Candidates Considered:
        • 33b43115a73e - Direct MemoryStream.cs modification, removes validation overhead
        • b836f4b9a125 - ThreadPool semaphore changes, could affect async patterns (less likely for sync WriteSpan)
    • Verification Status: Not verified

    System.Collections.Perf_Frozen<Int16>.ToFrozenSet (Borderline, -9.5%)

    • Delta: 16.32 μs → 14.77 μs (-9.5%)
    • Historical Context: μ=15.78 μs (σ=0.60 μs, n=300); z-score=-1.7; adaptive threshold=7.56%
    • Assessment: Borderline. Delta exceeds threshold (9.5% > 7.56%) but z-score is below significance (1.7 < 2.0). Historical series is bimodal (~16.2k and ~15.0k ns clusters), which inflates variance and suppresses z-score. After values (~14.7-15.4k ns) are at/below the lower historical cluster.
    • Finding Confidence: 3/5 - Good data quantity but bimodal distribution complicates interpretation
    • Improvement Confidence: 2/5 - Conflicting signals (delta passes threshold, z-score fails), no direct commit attribution, may be settling into lower cluster of pre-existing bimodal distribution
    • Likely Cause: No clear single attribution. Possible indirect effect of JIT loop cloning profitability heuristic or coincidental alignment with lower bimodal cluster.
      • Affected Areas: Collections / FrozenSet construction
      • Stack Relevance: Unknown
      • Rationale: No commit in the range directly touches System.Collections.Frozen. The bimodal historical pattern suggests this test naturally oscillates between two performance states. The "improvement" may simply be a measurement coinciding with the lower cluster.
      • Candidates Considered:
        • a2ec76b0691e - Loop cloning heuristic could affect FrozenSet construction loops (indirect)
        • db8761084874 - FP/SIMD register preservation could marginally help (unlikely for integer set)
    • Verification Status: Not verified

    Open Questions

    • Bimodal After-Values: LastWithPredicate and Min show bimodal after-value distributions (two distinct performance clusters). This may indicate non-deterministic tiered JIT promotion timing or branch prediction effects. Both clusters are faster than baseline so the improvement is real, but the variability should be monitored.
    • Root Cause Mechanism: The exact mechanism by which the loop cloning profitability heuristic produces 38-68% improvement in LINQ IEnumerable operations needs confirmation. Hypothesis: rejecting unprofitable clones simplifies CFG enough for CEA to stack-allocate enumerators.
    • FrozenSet Borderline: The bimodal history makes it unclear if this is a true improvement or normal oscillation.
    • Confidence Limitations: Multiple JIT commits (a2ec76b0691e, b3db78f44230, 92296631121c) could contribute; bisection would isolate the primary cause.

    Recommended Actions

    1. Verification: Verify LINQ improvement with RunWithBuildAtHash on a2ec76b0691e vs its parent 4832002fd287 to confirm the profitability heuristic is the primary cause
    2. Bisection: If verification is inconclusive, bisect the 3 JIT commits (a2ec76b0691e, b3db78f44230, 92296631121c) to isolate which produces the LINQ speedup
    3. Monitor: Track bimodal behavior in LastWithPredicate and Min to determine if after-values stabilize to one cluster over time
    4. FrozenSet: No action needed for borderline result — continue monitoring for persistent trend

    Bisection Results

    Test Status Culprit Commit Relevance Reported Diff (issue) Bisected Diff (at culprit) Duration
    Aggregate(input: IEnumerable) ✅ Success 92296631121c ✅ RELATED 97.1→31.3 ns (-68%) 95.6→31.3 ns (-67%) 1111s
    SingleWithPredicate_FirstElementMatch... ✅ Success 92296631121c ✅ RELATED 98.2→35.3 ns (-64%) 98.0→34.5 ns (-65%) 5158s
    LastWithPredicate_FirstElementMatches... ✅ Success 92296631121c ✅ RELATED 93.1→55.7 ns (-40%) 93.8→46.0 ns (-51%) 1431s
    Min(input: IEnumerable) ✅ Success 92296631121c ✅ RELATED 72.4→44.7 ns (-38%) 74.2→44.6 ns (-40%) 1140s
    WriteSpan(ChunkSize: 1) ✅ Success 92296631121c ✅ RELATED 248.7→230.6 μs (-7%) 248.3→230.9 μs (-7%) 1281s
    ToFrozenSet(Count: 512) ✅ Success 4a662a97471e ⚠️ UNRELATED 16.3→14.8 μs (-10%) 16.3→15.3 μs (-6%) 2809s

    Total bisection time: 12931s
    Success rate: 6/6 tests

    ⚠️ Alignment Warning

    Bisection found commits that are unrelated to the regressed tests. This strongly suggests the performance changes are caused by code alignment, binary layout, or other non-functional factors rather than actual regressions. Consider marking as noise.

    System.Linq.Tests.Perf_Enumerable.Aggregate(input: IEnumerable)

    • Culprit: 92296631121c
    • Commit Message: JIT: add post-inline cleanup for no-return calls (#128513)
    • Relevance: RELATED
    • Explanation: This commit adds a JIT compiler phase that trims dead code following no-return calls after inlining and converts blocks to BBJ_THROW. This produces a cleaner flow graph that enables better optimization in subsequent JIT phases, directly improving codegen for methods like LINQ's Aggregate which rely heavily on inlining.

    Helix jobs

    Job ID Submitted by bisection Last status
    d4f5734a-e04f-44ad-a028-4350ef05a2a4 ✅ submitted
    3ba8c48e-14cd-40ab-9dbc-7b7a43ad17fd ✅ submitted

    Per-commit measurements

    Commit Position Measurements
    4a662a97471e q2-threequarter 95.560 ns
    81a16039509f q2-mid 96.010 ns
    a4461ef220fe q2-quarter 95.500 ns
    5e837f7300b5 threequarter 31.380 ns
    92296631121c mid 31.330 ns
    f90673945503 quarter 95.580 ns
    Bisection details

    …[earlier output omitted]

    Let me verify and examine the culprit commit:

    ● get_single_commit_summary (MCP: PerfTriageMcp) · owner: "dotnet", repo: "runtime", sha: "92296631…
    └ {"index":null,"sha":"92296631121c2eb917f58dfca70864821cba250a","abbrevSh...

    I have all the information needed. The culprit commit is 92296631121c2eb917f58dfca70864821cba250a — a JIT optimization by Andy Ayers that adds a post-inline cleanup phase for no-return calls. This is directly related to LINQ's Aggregate benchmark because the JIT now produces a cleaner flow graph after inlining, which likely enables better optimization of the Aggregate method's hot path.

    BISECTION RESULT:
    - Culprit Commit: 92296631121c2eb917f58dfca70864821cba250a
    - Commit Message: JIT: add post-inline cleanup for no-return calls (#128513)
    - Commits Tested: 6
    - Confidence: 5
    - Commit Relevance: RELATED
    - Relevance Explanation: This commit adds a JIT compiler phase that trims dead code following no-return calls after inlining and converts blocks to BBJ_THROW. This produces a cleaner flow graph that enables better optimization in subsequent JIT phases, directly improving codegen for methods like LINQ's Aggregate which rely heavily on inlining.
    - Baseline Value: 95.56 ns
    - Culprit Value: 31.33 ns
    - Summary: Double bisection narrowed the improvement to commit 92296631 (adjacent to 4a662a97 which showed baseline performance). The JIT optimization clearly caused the ~67% improvement by enabling better flow graph optimization after inlining.
    
    HELIX JOBS:
    - d4f5734a-e04f-44ad-a028-4350ef05a2a4
    - 3ba8c48e-14cd-40ab-9dbc-7b7a43ad17fd
    
    MEASUREMENTS:
    - f90673945503 (quarter): 95.58 ns
    - a4461ef220fe (Q2-quarter): 95.50 ns
    - 81a16039509f (Q2-mid): 96.01 ns
    - 4a662a97471e (Q2-threeQuarter): 95.56 ns
    - 92296631121c (mid): 31.33 ns
    - 5e837f7300b5 (threeQuarter): 31.38 ns
    

    System.Linq.Tests.Perf_Enumerable.SingleWithPredicate_FirstElementMatches(input: IEnumerable)

    • Culprit: 92296631121c
    • Commit Message: JIT: add post-inline cleanup for no-return calls (#128513)
    • Relevance: RELATED
    • Explanation: This JIT commit adds a post-inline phase that trims dead code following no-return (throw) calls and converts blocks to BBJ_THROW. LINQ's Single method has throw paths for "no match" and "multiple matches" scenarios; cleaning these up after inlining produces a tighter flow graph and enables better optimization of the hot path, directly explaining the ~64% improvement.

    Helix jobs

    Job ID Submitted by bisection Last status
    616658b9-2a8e-4c54-b3d9-96c9b58782da ✅ submitted
    39d44fcc-fef3-4fb9-bd83-3fa1b2c1135e ✅ submitted

    Per-commit measurements

    Commit Position Measurements
    4a662a97471e q2-threequarter 98.040 ns
    81a16039509f q2-mid 98.220 ns
    a4461ef220fe q2-quarter 98.410 ns
    5e837f7300b5 threequarter 35.290 ns
    92296631121c mid 34.550 ns
    f90673945503 quarter 98.240 ns
    Bisection details

    …[earlier output omitted]

    Now let me examine the culprit commit.

    ● get_single_commit_summary (MCP: PerfTriageMcp) · owner: "dotnet", repo: "runtime", sha: "92296631…
    └ {"index":null,"sha":"92296631121c2eb917f58dfca70864821cba250a","abbrevSh...

    Excellent! The culprit commit is identified. Let me compile the final results.

    The commit 92296631 is a JIT optimization by Andy Ayers that adds a post-inline cleanup phase for no-return calls. The LINQ Single method has throw paths (for "no match" and "multiple matches") that would benefit from this dead-code trimming, resulting in better-optimized hot paths.

    BISECTION RESULT:
    - Culprit Commit: 92296631121c2eb917f58dfca70864821cba250a
    - Commit Message: JIT: add post-inline cleanup for no-return calls (#128513)
    - Commits Tested: 6
    - Confidence: 5
    - Commit Relevance: RELATED
    - Relevance Explanation: This JIT commit adds a post-inline phase that trims dead code following no-return (throw) calls and converts blocks to BBJ_THROW. LINQ's Single method has throw paths for "no match" and "multiple matches" scenarios; cleaning these up after inlining produces a tighter flow graph and enables better optimization of the hot path, directly explaining the ~64% improvement.
    - Baseline Value: 98.04 ns
    - Culprit Value: 34.55 ns
    - Summary: Double-bisection narrowed a 28-commit range to the single culprit in two Helix jobs. The improvement boundary is sharp (98→35 ns) and falls exactly at this JIT optimization commit.
    
    HELIX JOBS:
    - 616658b9-2a8e-4c54-b3d9-96c9b58782da
    - 39d44fcc-fef3-4fb9-bd83-3fa1b2c1135e
    
    MEASUREMENTS:
    - f90673945503 (quarter): 98.24 ns
    - a4461ef220fe (Q2-quarter): 98.41 ns
    - 81a16039509f (Q2-mid): 98.22 ns
    - 4a662a97471e (Q2-threeQuarter): 98.04 ns
    - 92296631121c (mid): 34.55 ns
    - 5e837f7300b5 (threeQuarter): 35.29 ns
    

    System.Linq.Tests.Perf_Enumerable.LastWithPredicate_FirstElementMatches(input: IEnumerable)

    • Culprit: 92296631121c
    • Commit Message: JIT: add post-inline cleanup for no-return calls (#128513)
    • Relevance: RELATED
    • Explanation: This commit adds a new JIT phase that trims dead code following no-return calls introduced by inlining, enabling cleaner flow graphs for subsequent optimizations like GDV resolution. The LINQ LastWithPredicate test heavily exercises inlined code paths, and removing dead code after no-return calls allows the JIT to generate significantly better code for the hot loop.

    Helix jobs

    Job ID Submitted by bisection Last status
    cc940995-e537-46a3-b4fb-3836bd0161bf ✅ submitted
    4e8faf3c-ba94-425e-bda8-198527736ed2 ✅ submitted
    295bee95-0b52-44b8-9c05-cb37883943be ✅ submitted

    Per-commit measurements

    Commit Position Measurements
    4a662a97471e confirmation-baseline 93.850, 93.800 ns
    f90673945503 q1-quarter 93.270 ns
    81a16039509f q2-mid 92.880 ns
    92296631121c q2-mid 46.450, 45.980 ns
    a4461ef220fe q2-quarter 92.830 ns
    5e837f7300b5 q3-threequarter 55.790 ns
    Bisection details

    …[earlier output omitted]

    Id: "295bee95-0b52-44b8-9c05-cb37883943be"
    └ Output too large to read at once (34.3 KB). Saved to: /tmp/1781003754407...

    ● Parse confirmation job results (shell)
    │ cat /tmp/1781003754407-copilot-tool-output-2f5wzh.txt | python3 -c "
    │ import json, sys, re
    │ data = json.load(sys.stdin)
    │ report = json.loads(data['report'])
    │ benchmarks = report.get('Benchmarks', [])…
    └ 11 lines...

    The confirmation run validates the bisection:

    • 4a662a97471e (parent): 93.85 ns (baseline)
    • 92296631121c (culprit): 45.98 ns (improved)

    This is a clear ~51% improvement at the exact boundary. The bisection is conclusive.

    BISECTION RESULT:
    - Culprit Commit: 92296631121c2eb917f58dfca70864821cba250a
    - Commit Message: JIT: add post-inline cleanup for no-return calls (#128513)
    - Commits Tested: 8
    - Confidence: 5
    - Commit Relevance: RELATED
    - Relevance Explanation: This commit adds a new JIT phase that trims dead code following no-return calls introduced by inlining, enabling cleaner flow graphs for subsequent optimizations like GDV resolution. The LINQ `LastWithPredicate` test heavily exercises inlined code paths, and removing dead code after no-return calls allows the JIT to generate significantly better code for the hot loop.
    - Baseline Value: 93.85 ns
    - Culprit Value: 45.98 ns
    - Summary: Bisected 28 commits using double-bisection strategy across 3 Helix jobs. The improvement was cleanly isolated to a single commit boundary with a ~51% speedup, consistent with the reported -40.1% improvement.
    
    HELIX JOBS:
    - cc940995-e537-46a3-b4fb-3836bd0161bf
    - 4e8faf3c-ba94-425e-bda8-198527736ed2
    - 295bee95-0b52-44b8-9c05-cb37883943be
    
    MEASUREMENTS:
    - f90673945503 (Q1-quarter): 93.27 ns
    - 92296631121c (Q2-mid): 46.45 ns
    - 5e837f7300b5 (Q3-threeQuarter): 55.79 ns
    - a4461ef220fe (Q2-quarter): 92.83 ns
    - 81a16039509f (Q2-mid): 92.88 ns
    - 4a662a97471e (Q2-threeQuarter): 93.80 ns
    - 4a662a97471e (confirmation-baseline): 93.85 ns
    - 92296631121c (confirmation-culprit): 45.98 ns
    

    System.Linq.Tests.Perf_Enumerable.Min(input: IEnumerable)

    • Culprit: 92296631121c
    • Commit Message: JIT: add post-inline cleanup for no-return calls (#128513)
    • Relevance: RELATED
    • Explanation: This commit adds a JIT phase that trims dead code following no-return calls after inlining, producing a cleaner flow graph for subsequent optimizations. The System.Linq.Min benchmark benefits because the JIT can now eliminate unreachable paths and optimize the hot loop more effectively, resulting in a ~38% speedup.

    Helix jobs

    Job ID Submitted by bisection Last status
    6663e6e2-41db-4dd3-af75-6938e51de559 ✅ submitted
    16fa9754-3118-4b1b-bbc2-e9bd8ee9c0b8 ✅ submitted

    Per-commit measurements

    Commit Position Measurements
    4a662a97471e q2-three-quarter 74.230 ns
    81a16039509f q2-mid 73.570 ns
    a4461ef220fe q2-quarter 74.210 ns
    5e837f7300b5 three-quarter 44.750 ns
    92296631121c mid 44.590 ns
    f90673945503 quarter 72.260 ns
    Bisection details

    …[earlier output omitted]

    /1781004893439-copilot-tool-output-6szntd.txt | python3 -c "
    │ import json, sys
    │ data = json.load(sys.stdin)
    │ report = json.loads(data['report'])
    │ benchmarks = report.get('Benchmarks', [])…
    └ 14 lines...

    All three commits show ~74 ns (baseline level). Combined with the first job showing 92296631 at 44.59 ns, the improvement happened between 4a662a97 and 92296631 — they're adjacent commits. So 92296631121c2eb917f58dfca70864821cba250a is the culprit.

    Let me examine this commit:

    ● get_single_commit_summary (MCP: PerfTriageMcp) · owner: "dotnet", repo: "runtime", sha: "92296631…
    └ {"index":null,"sha":"92296631121c2eb917f58dfca70864821cba250a","abbrevSh...

    Excellent! This is a JIT optimization commit. Now I have all the information needed to provide the bisection result.

    BISECTION RESULT:
    - Culprit Commit: 92296631121c2eb917f58dfca70864821cba250a
    - Commit Message: JIT: add post-inline cleanup for no-return calls (#128513)
    - Commits Tested: 6
    - Confidence: 5
    - Commit Relevance: RELATED
    - Relevance Explanation: This commit adds a JIT phase that trims dead code following no-return calls after inlining, producing a cleaner flow graph for subsequent optimizations. The System.Linq.Min benchmark benefits because the JIT can now eliminate unreachable paths and optimize the hot loop more effectively, resulting in a ~38% speedup.
    - Baseline Value: 74.23 ns
    - Culprit Value: 44.59 ns
    - Summary: Double-bisection narrowed 28 commits to adjacent pair in two Helix jobs. The improvement appeared between 4a662a97 (74.23 ns) and 92296631 (44.59 ns), pinpointing the JIT no-return cleanup commit as the source of the ~38% improvement.
    
    HELIX JOBS:
    - 6663e6e2-41db-4dd3-af75-6938e51de559
    - 16fa9754-3118-4b1b-bbc2-e9bd8ee9c0b8
    
    MEASUREMENTS:
    - f90673945503 (quarter): 72.26 ns
    - 92296631121c (mid): 44.59 ns
    - 5e837f7300b5 (three-quarter): 44.75 ns
    - a4461ef220fe (Q2-quarter): 74.21 ns
    - 81a16039509f (Q2-mid): 73.57 ns
    - 4a662a97471e (Q2-three-quarter): 74.23 ns
    

    System.IO.Tests.MemoryStreamChunkedTests.WriteSpan(ChunkSize: 1)

    • Culprit: 92296631121c
    • Commit Message: JIT: add post-inline cleanup for no-return calls (#128513)
    • Relevance: RELATED
    • Explanation: This commit adds a JIT compiler phase that trims dead code following no-return calls after inlining, producing a cleaner flow graph for subsequent optimization phases. JIT improvements affect all managed code including System.IO.MemoryStream.WriteSpan; the cleaner CFG likely enables better optimization of the write path, explaining the ~7% improvement.

    Helix jobs

    Job ID Submitted by bisection Last status
    60a38e2f-ec43-4c90-9b0b-6a1312b0740a ✅ submitted
    fe9aef51-2a2c-4922-9757-0326701af7c3 ✅ submitted

    Per-commit measurements

    Commit Position Measurements
    4a662a97471e q2 three-quarter 248.334 μs
    81a16039509f q2 mid 248.327 μs
    a4461ef220fe q2 quarter 248.672 μs
    5e837f7300b5 three-quarter 230.967 μs
    92296631121c mid 230.875 μs
    f90673945503 quarter 248.184 μs
    Bisection details

    …[earlier output omitted]

    6631(index 14, improved). The culprit is commit92296631121c2eb917f58dfca70864821cba250a`.

    Let me examine this commit.

    ● get_single_commit_summary (MCP: PerfTriageMcp) · owner: "dotnet", repo: "runtime", sha: "92296631…
    └ {"index":null,"sha":"92296631121c2eb917f58dfca70864821cba250a","abbrevSh...

    I have all the information needed. Let me compile the final result.

    The culprit commit 92296631121c2eb917f58dfca70864821cba250a is a JIT optimization by Andy Ayers that adds a post-inline cleanup phase for no-return calls. This is a JIT change that could plausibly improve any benchmark by producing a cleaner flow graph after inlining, potentially enabling better code generation for the MemoryStream.WriteSpan hot path.

    BISECTION RESULT:
    - Culprit Commit: 92296631121c2eb917f58dfca70864821cba250a
    - Commit Message: JIT: add post-inline cleanup for no-return calls (#128513)
    - Commits Tested: 6
    - Confidence: 4
    - Commit Relevance: RELATED
    - Relevance Explanation: This commit adds a JIT compiler phase that trims dead code following no-return calls after inlining, producing a cleaner flow graph for subsequent optimization phases. JIT improvements affect all managed code including System.IO.MemoryStream.WriteSpan; the cleaner CFG likely enables better optimization of the write path, explaining the ~7% improvement.
    - Baseline Value: 248334.42 ns
    - Culprit Value: 230875.37 ns
    - Summary: Bisected 28 commits across two rounds of Helix jobs. The improvement was introduced at commit 92296631 (JIT post-inline no-return cleanup), with a clear step change from ~248k ns to ~231k ns matching the reported improvement magnitude.
    
    HELIX JOBS:
    - 60a38e2f-ec43-4c90-9b0b-6a1312b0740a
    - fe9aef51-2a2c-4922-9757-0326701af7c3
    
    MEASUREMENTS:
    - f90673945503 (quarter): 248184.23 ns
    - 92296631121c (mid): 230875.37 ns
    - 5e837f7300b5 (three-quarter): 230967.37 ns
    - a4461ef220fe (Q2 quarter): 248671.63 ns
    - 81a16039509f (Q2 mid): 248327.48 ns
    - 4a662a97471e (Q2 three-quarter): 248334.42 ns
    

    System.Collections.Perf_Frozen.ToFrozenSet(Count: 512)

    • Culprit: 4a662a97471e
    • Commit Message: [cDAC] Remove GetObjectContents from DAC/DBI (#128615)
    • Relevance: UNRELATED
    • Explanation: This commit removes a debugger (DAC/DBI) interface method GetObjectContents from coreclr's diagnostic infrastructure. It modifies only debugger-related files (dacdbiimpl.cpp, divalue.cpp, dacdbi.idl) and has no functional connection to System.Collections or FrozenSet construction. The performance improvement is almost certainly due to binary layout/code alignment changes rather than a real optimization of the tested code path.
    • ⚠️ This commit is UNRELATED to the test — likely a code alignment artifact

    Helix jobs

    Job ID Submitted by bisection Last status
    c251e41f-9f11-4931-83e8-b5e5e248ee62 ✅ submitted
    6b5357d3-27dd-48c9-8058-5522bf836431 ✅ submitted
    d25effe6-a910-4099-a12b-e2493049f05d ✅ submitted

    Per-commit measurements

    Commit Position Measurements
    0701fbf3ec5b baseline region 16.405 μs
    772147228c6b last baseline 16.255 μs
    81a16039509f baseline region 16.401 μs
    b3db78f44230 baseline region 16.302 μs
    f90673945503 baseline region 16.267 μs
    4a662a97471e culprit 15.297 μs
    5e837f7300b5 improved 14.835 μs
    92296631121c improved 15.020 μs
    a4461ef220fe noise outlier 15.148 μs
    Bisection details

    …[earlier output omitted]

    Let me compile the final result:

    BISECTION RESULT:
    - Culprit Commit: 4a662a97471e79279529cac640854e2478c98079
    - Commit Message: [cDAC] Remove GetObjectContents from DAC/DBI (#128615)
    - Commits Tested: 9
    - Confidence: 2
    - Commit Relevance: UNRELATED
    - Relevance Explanation: This commit removes a debugger (DAC/DBI) interface method `GetObjectContents` from coreclr's diagnostic infrastructure. It modifies only debugger-related files (dacdbiimpl.cpp, divalue.cpp, dacdbi.idl) and has no functional connection to System.Collections or FrozenSet construction. The performance improvement is almost certainly due to binary layout/code alignment changes rather than a real optimization of the tested code path.
    - Baseline Value: 16254.90 ns
    - Culprit Value: 15296.91 ns
    - Summary: Bisected 28 commits between c7d89359fb2a and ac6956929115. Six consecutive commits at indices 7-12 measured baseline (~16255-16405 ns), while commits from index 13 onward measured improved (~14835-15297 ns). The transition occurs at 4a662a97 but the improvement delta (~958 ns) is within the historical 2σ noise floor (1194 ns), and the commit is unrelated to the test area, suggesting a code alignment artifact.
    
    HELIX JOBS:
    - c251e41f-9f11-4931-83e8-b5e5e248ee62
    - 6b5357d3-27dd-48c9-8058-5522bf836431
    - d25effe6-a910-4099-a12b-e2493049f05d
    
    MEASUREMENTS:
    - f90673945503 (baseline region): 16266.71 ns
    - 0701fbf3ec5b (baseline region): 16405.39 ns
    - a4461ef220fe (noise outlier): 15147.57 ns
    - b3db78f44230 (baseline region): 16301.63 ns
    - 81a16039509f (baseline region): 16400.52 ns
    - 772147228c6b (last baseline): 16254.90 ns
    - 4a662a97471e (culprit): 15296.91 ns
    - 92296631121c (improved): 15020.19 ns
    - 5e837f7300b5 (improved): 14835.44 ns
    
    ALIGNMENT WARNING:
    This bisection found a commit that does not appear related to the improvement test.
    This suggests the performance change may be due to code alignment, binary layout,
    or other non-functional factors rather than a real change in the tested code path.
    

    🤖 Proposed Next Actions

    Rule: R5_look_again — Uncertain — flag for re-triage.

    Bimodal benchmark history — bisection results would be unreliable, so the cause is not auto-classified as known. Revisit once more historical data is available.

    # Action Status Details
    1 Add label 🕒 Planned Look Again
    2 Remove label 🕒 Planned untriaged

    Generated by PerfTriageAgent on 2026-06-09 12:43 UTC

  2. AndyAyersMS commented on Jun 9, 2026

    @AndyAyersMS
    Member
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions