Repository navigation
Conversation
Share a walk budget across recursive branches while retaining the depth limit and direct proofs. Add regression coverage for the repeated PHI walk and nullable control flow. Fix dotnet#134462
|
Azure Pipelines: Successfully started running 5 pipeline(s). 11 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
I haven't run BenchmarkDotNet comparisons for this change yet. The measurements in the description cover JIT compilation time, process RSS and SuperPMI compiler CPU time. I'll compare application execution time using BenchmarkDotNet with the baseline and patched Release CoreRun builds on ARM64, including cases where the walk budget could leave additional null checks. I'll post the results here, including any regressions.
|
|
We should rather avoid doing the repeated work than limit it via a budget. |
Replace the shared walk cutoff with query-local results keyed by VN and remaining depth. Keep direct assertion checks and the original depth limit. Restore the regression test to priority 1.
|
@jakobbotsch I replaced the shared walk budget with memoization of completed PHI walks. The cache is local to each non-null query and keyed by VN and remaining depth. Incoming assertions are checked before the cache, and the original depth limit of 10 is unchanged. For the N10 reproduction on macOS ARM64, the Release results were:
Checked SuperPMI passed all 96,632 contexts with no codegen differences. The extra null checks from the earlier budget version are also gone. I added all 26 BDN conditions to the PR description.
The slowdown did not reproduce in the follow-up, and the helper and wrapper instructions matched. That is not enough to rule out a regression, so I kept both sets of results in the description. |
Fixes #134462.
Repeated non-null PHI queries can revisit the same subgraph many times. This change caches completed PHI-walk results within each top-level non-null query. The cache is keyed by value number and exact remaining depth; the original depth limit of 10 is unchanged.
Direct proofs from the incoming assertion set are still checked on every call. Only the subsequent PHI walk is cached: it obtains assertions from the PHI's own predecessor edges, independently of the caller's incoming assertion set. Both successful and unsuccessful completed walks are stored. Recursive calls share the cache, and entries are read again after recursion so results recorded at other depths are preserved. The shared reaching-assertion visitor and subtype queries are unchanged.
The regression test covers the issue reproduction, nullable merges, loops, exceptions and independent queries. It remains a priority-1 test.
JIT compilation time and peak process RSS
Apple M4 Pro, macOS 26.5.1, ARM64. Baseline:
0fc86e67b3ed75a19c0bb34afdf76712d6b36c18. Matching runtime hosts were used, with only the JIT replaced for the candidate. Values below are medians from six fresh-process pairs for the N10 reproduction. Time measuresRuntimeHelpers.PrepareMethod; RSS is whole-process peak resident memory, not managed allocation.Small N2 compile times were essentially unchanged. The evidence also includes N6 and all individual measurements.
Validation
realworldandbenchmarkscollections with no failures, missing contexts or codegen differences.realworld(approximate paired 95% interval 0.9666 to 1.0112) and 0.9906 forbenchmarks(0.9809 to 1.0005), eight pairs each. These do not establish a general compiler throughput improvement.A separate Checked diagnostic build compared every non-null query with the original recursive implementation, including additional depth 0/1/9 checks, across both SuperPMI collections and the regression test. The comparisons passed, with no codegen differences. Counters confirmed cyclic VN paths and depths 0 through 10. Seeded-cache tests checked that direct proofs override stored false results; additional tests covered false/true entries at each cached depth and small, negative and large offsets. Natural false cache hits were not observed and are not claimed as coverage. This instrumentation is excluded from the proposed change and timing runs.
The uninstrumented SuperPMI compiler-allocation totals increased by 0.0265% (
realworld) and 0.0144% (benchmarks). The largest per-context increases were 16,944 and 16,128 bytes, respectively; the largest relative increases were 0.82% and 1.25%. These are compiler arena allocation totals per compilation, not process RSS. The new maps use the compilation arena and remain allocated until that compilation ends.BenchmarkDotNet execution time
BDN compares fully optimized steady-state execution, separately from the JIT-time table above. All 13 helper instruction listings and code sizes match the baseline after normalizing only
NullExitcall-target relocations. The additional null checks left by the earlier walk-budget implementation are gone.The primary series measured 26 conditions in host order
ABBABAAB, with 5 warmups and 15 measured iterations per launch, targeting 200 ms per iteration. Tiering, tiered PGO and ReadyToRun were disabled. Existing services stayed running on the shared Mac.B/A below 1 means faster. The table uses geometric means of four independent launch pairs; intervals are exploratory and not adjusted for multiple comparisons.
ChainN2, Pattern 1 was 7.93% slower in the primary series. A selected ABBA follow-up measured -0.41% for that condition. It also includedChainN8,DirectGuardandOriginalN10Length, both input patterns, and captured the actual worker's helper and benchmark-wrapper assembly. Those instructions matched across all four follow-up passes. The original slowdown was not reproduced, but this does not prove it was noise or establish execution-time equivalence. Both series and their intervals are retained; no execution-time speedup is claimed.Source, full raw BDN results, follow-up results, disassembly and reproduction commands.
The tested native patch was subsequently formatted with whitespace-only changes. Validation is local to macOS ARM64; it does not replace upstream cross-platform CI.