Repository navigation
Closed
Labels
arch-x64area-GC-coreclros-linuxLinux OS (any supported distro)Linux OS (any supported distro)runtime-coreclrspecific to the CoreCLR runtimespecific to the CoreCLR runtimetenet-performancePerformance related issuePerformance related issuetenet-performance-benchmarksIssue from performance benchmarkIssue from performance benchmark
Milestone
Description
Run Information
| Name | Value |
|---|---|
| Architecture | x64 |
| OS | ubuntu 22.04 |
| Queue | ViperUbuntu |
| Baseline | 58dfec78ed8de81f527f428f44d095e37fecb401 |
| Compare | ff279bafa8ca2fbf920b605868e9b0a2c0497034 |
| Diff | Diff |
| Configs | CompilationMode:tiered, RunKind:micro |
Regressions in System.Memory.Memory<Char>
| Benchmark | Baseline | Test | Test/Base | Test Quality | Edge Detector | Baseline IR | Compare IR | IR Ratio |
|---|---|---|---|---|---|---|---|---|
| 20.90 ns | 22.83 ns | 1.09 | 0.11 | False |
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
python3 .\performance\scripts\benchmarks_ci.py -f net8.0 --filter 'System.Memory.Memory<Char>*'Details
System.Memory.Memory<Char>.Pin(Size: 512)
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 | ubuntu 22.04 |
| Queue | ViperUbuntu |
| Baseline | 58dfec78ed8de81f527f428f44d095e37fecb401 |
| Compare | ff279bafa8ca2fbf920b605868e9b0a2c0497034 |
| Diff | Diff |
| Configs | CompilationMode:tiered, RunKind:micro |
Regressions in System.Memory.Memory<Byte>
| Benchmark | Baseline | Test | Test/Base | Test Quality | Edge Detector | Baseline IR | Compare IR | IR Ratio |
|---|---|---|---|---|---|---|---|---|
| 20.65 ns | 21.91 ns | 1.06 | 0.15 | False |
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
python3 .\performance\scripts\benchmarks_ci.py -f net8.0 --filter 'System.Memory.Memory<Byte>*'Details
System.Memory.Memory<Byte>.Pin(Size: 512)
ETL Files
Histogram
JIT Disasms
Docs
Profiling workflow for dotnet/runtime repository
Benchmarking workflow for dotnet/runtime repository
Metadata
Metadata
Assignees
Labels
arch-x64area-GC-coreclros-linuxLinux OS (any supported distro)Linux OS (any supported distro)runtime-coreclrspecific to the CoreCLR runtimespecific to the CoreCLR runtimetenet-performancePerformance related issuePerformance related issuetenet-performance-benchmarksIssue from performance benchmarkIssue from performance benchmark
Type
Projects
- StatusShow more project fieldsNo status


Activity
LoopedBard3 commentedon Jul 14, 2026
🔍 Automated Triage Analysis
Summary: Verified regression in Pin(Size: 512) — caused by commit 8f365c9 ("Publish GCHandle assignments with release semantics (#130213)"). 2 tests bisected to related culprit commits.
Finding Confidence: 5/5 (analysis accuracy)
Regression Confidence: 5/5 (likelihood of true regression)
Likely Cause: 8f365c934088b8ae21a4dfce8073da0d3eb22a54
🤖 Proposed Next Actions: Known-cause regression — transfer & notify — 0 done, 3 dry-run (rule⚠️ disputes (overconfident-aggregate)
R4_known_regression_new— see Full Analysis for the table). · 🦆 Re-analysis:📊 Full Analysis (click to expand)
Summary: Two Memory.Pin regressions detected (+9.2% Char, +6.1% Byte) attributed to commit 8f365c9 which added VolatileStore release semantics to GCHandle assignment. Finding confidence 4/5 (excellent historical data, 299 runs, clear step change), regression confidence 4/5 (direct code path hit, z=3.16, precise temporal alignment with 4-commit range).
Issue Overview
Test Analysis
Legend: μ=mean, σ=stddev, n=runs, z=z-score, Thresh%=adaptive threshold
Finding Confidence: 4/5 - Excellent historical data (297–299 runs), low CV (3.4%), clear step-change pattern sustained across 45 post-change runs. Minor downgrade from 5 due to a few outliers (26.4 ns spikes) slightly inflating σ.
Candidate Stack Relevance
Runtime stack: Desktop + CoreCLR (implicit)
src/coreclr/gc/handletable.inlsrc/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs,String.Manipulation.cssrc/coreclr/tools/aot/,src/tests/Interop/eng/build.sh,docs/Confirmed Regressions
System.Memory.Memory<Char>.Pin(Size: 512) (+9.22%)
VolatileStore(release semantics) inHndAssignHandleandHndAssignHandleGCinsrc/coreclr/gc/handletable.inl. TheMemory<T>.Pin()benchmark creates a pinned GCHandle on each iteration. While x64 has strong store ordering (no hardware fence needed),VolatileStoreprevents compiler reordering/optimization of the store, which can add measurable overhead in tight microbenchmark loops. The commit timestamp (2026-07-05T16:58:39) exactly matches the regression date. Both Char and Byte variants show the same pattern, confirming a shared code path (GC handle assignment).System.Memory.Memory<Byte>.Pin(Size: 512) (+6.07%) — Borderline
Memory<T>.Pin()which allocates/assigns a pinned GCHandle. The slightly smaller delta for Byte vs Char is likely measurement variance rather than a different code path (both use the same GCHandle infrastructure).Benchmark Source
Memory.cs#L27-L34:
The benchmark pins a
Memory<T>of size 512 on each invocation, which internally creates aGCHandleof typePinned. TheVolatileStorechange inHndAssignHandleis hit on every iteration.Open Questions
Recommended Actions
#ifdefor platform-specific volatile can reduce x64 impact while preserving ARM64 correctness.Memory<Byte>.Pinclassification after 10+ additional runs to confirm sustained elevation.Bisection Results
Total bisection time: 7563s
Success rate: 2/2 tests
System.Memory.Memory.Pin(Size: 512)
HndAssignHandleinhandletable.inlto useVolatileStoreinstead of a plain store when assigning GC handle slots.Memory<Char>.Pin()creates a GCHandle internally, so this change directly affects the hot path of the benchmark. The VolatileStore adds a compiler barrier that prevents reordering optimizations, plausibly adding ~0.8ns overhead per Pin operation.Helix jobs
736dc4cc-8e32-4f29-a42e-60afe8300723f2348508-cc17-4ad2-8605-63a06d675b24Per-commit measurements
58dfec78ed8de9914e44b4408f365c934088ff279bafa8caBisection details
…[earlier output omitted]
● Parse confirmation results (shell)
│ cat /tmp/1784020884292-copilot-tool-output-hwd1i8.txt | python3 -c "
│ import json, sys
│ data = json.load(sys.stdin)
│ report = json.loads(data['report'])
│ benchmarks = report.get('Benchmarks', [])…
└ 14 lines…
Confirmation run is consistent:
Both runs consistently show the step change at commit 8f365c9. The culprit is clear.
System.Memory.Memory.Pin(Size: 512)
HndAssignHandleinsrc/coreclr/gc/handletable.inlto useVolatileStoreinstead of a plain pointer store.Memory<T>.Pin()allocates a pinned GCHandle viaGCHandle.Alloc, which callsHndAssignHandleon the hot path. The VolatileStore adds a compiler barrier on x64 that prevents instruction reordering optimizations, directly impacting the benchmark's measured operation.Helix jobs
adeaa63d-0ba4-43c5-bf6b-2c98f92fa303ab9d46f3-4222-4210-9c5e-13293380c46d7cc7114c-4a05-46e3-b7e0-07571e721e74Per-commit measurements
58dfec78ed8d8f365c934088e9914e44b440ff279bafa8caBisection details
…[earlier output omitted]
Consistent ~0.6 ns regression at commit
8f365c934088. Now let me get the commit details for the final report.● get_single_commit_summary (MCP: PerfTriageMcp) · owner: "dotnet", repo: "runtime", sha: "8f365c93…
└ {"index":null,"sha":"8f365c934088b8ae21a4dfce8073da0d3eb22a54","abbrevSha":"8...
I have all the data needed. Here's the bisection result:
🤖 Proposed Next Actions
Rule:
R4_known_regression_new— Known-cause regression — transfer & notify.Verified regression attributed to commit 8f365c9 (finding 5/5, regression 5/5, bisection RELATED). No prior linked autofile issue found.
8f365c934088🦆 Pre-bisection Re-analysis (advisory)
✅ Agrees with the pre-bisection plan — advisory only, not applied
Rationale: Both findings share the same likely commit (8f365c9), have relevant stack traces, and reasonably high change confidence (4/5 and 3/5). The candidate set is tight—two closely related Pin benchmarks differing only in type parameter—making bisection efficient and unlikely to waste slots on noise.
This critique is advisory in the current configuration and did not change which tests were bisected.
🦆 Re-analysis (advisory)
Flags:
overconfident-aggregateRationale: Bisection converged on the same commit for both findings with no alignment warnings, which strongly supports the culprit choice. However, the aggregate confidence scores (5/5 for both) exceed the per-finding scores (finding: 4/4, change: 4/3). The aggregate should not exceed its constituents — adjusting both to 4/5 to match the strongest individual signal.
Suggested confidence: Finding Confidence → 4/5; Change Confidence → 4/5 (advisory — not applied)
This critique is advisory in the current configuration and did not change the confidences, culprit, or proposed actions above.
Generated by PerfTriageAgent on 2026-07-14 11:15 UTC
LoopedBard3 commentedon Jul 14, 2026
Seems like this may be due to #130213. This is clearer on the Byte pin test.
dotnet-policy-service commentedon Jul 14, 2026
Tagging subscribers to this area: @dotnet/area-system-memory
See info in area-owners.md if you want to be subscribed.
adamsitnik commentedon Jul 15, 2026
This particular PR is a bug fix, so I would say it's by design.
Leaving it up to @jkotas who reviewed the PR to make the call, as I don't know whether this arm64 fix could regress x64.
jkotas commentedon Jul 15, 2026
The change regressed code produced by clang on x64:
Before the change:
After the change:
We should be able to tweak the sources to workaround this clang issue.
dotnet-policy-service commentedon Jul 15, 2026
Tagging subscribers to this area: @anicka-net, @dotnet/gc
See info in area-owners.md if you want to be subscribed.
BradBarnich commentedon Jul 27, 2026
@jkotas what do you think about
#define VOLATILE_MEMORY_BARRIER() __atomic_signal_fence(__ATOMIC_SEQ_CST)for x64 and clang?From what I understand, the current value
asm volatile ("" : : : "memory")creates an optimization block under clang that emits this extra jmp. Using__atomic_storelike arm64 does (instead full barrier macro) also emitted extra instructions.some robot notes: https://gist.github.com/BradBarnich/e9b14acca0719a1d063e289da5a1f605#file-x64-volatile-md
janvorli commentedon Jul 27, 2026
I've spent some time today on it and came up with the same conclusion as @BradBarnich. I've enabled llvm output using "-emit-llvm -S " options and then analyzed the output using copilot.
Change VOLATILE_MEMORY_BARRIER for x64 Unix (#131807)