FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

JIT: Use disjoint-set-union for ClassLayout::AreCompatible by ump45nose · Pull Request #134636 · dotnet/runtime · GitHub

Repository navigation

JIT: Use disjoint-set-union for ClassLayout::AreCompatible - #134636

Open
ump45nose wants to merge 2 commits into
dotnet:mainfrom
ump45nose:jit-are-compatible-dsu
Open

ump45nose wants to merge 2 commits into
dotnet:mainfrom
ump45nose:jit-are-compatible-dsu

Conversation

Copy link
Copy Markdown

Fixes #42801

Description

ClassLayout::AreCompatible compared the GC slots of the two layouts one by one on every call, i.e. O(slot count) per call. With many distinct but layout-compatible struct types and many copies between them, JIT compilation time was quadratic in (slots × copies).

This change groups class-based layouts with GC pointers into equivalence classes of compatible layouts using a disjoint-set-union structure:

  • ClassLayout gets a m_dsuParent pointer: null for layouts that do not participate in the DSU (custom, block and non-GC layouts), a self-pointer for class representatives, or a pointer to the representative of the class the layout belongs to.
  • When ClassLayoutTable::AddObjLayout adds a class-based layout with GC pointers, it is compared with the class representatives of the same size and type using the previous slot-by-slot algorithm (kept as ClassLayout::AreCompatibleSlow) and joined with the first compatible one. Since compatibility is equality of the GC slot pattern, a new layout can match at most one class, so the DSU trees stay one level deep and AreCompatible becomes a representative comparison (O(1)).
  • In DEBUG builds AreCompatible verifies its result against AreCompatibleSlow.

Custom and block layouts keep the existing pointer-equality path, and non-GC layouts keep the existing early-out path.

Note on the approach vs the issue: the issue proposed building the DSU lazily on the first AreCompatible call (InitDSU + a static initialized flag). This implementation instead maintains the structure incrementally at layout creation time, which keeps AreCompatible parameterless and bounds the extra creation-time cost to one slot-by-slot comparison per same-size representative per created layout (zero for custom, block and non-GC layouts).

Customer Impact

None known today — the issue notes there are currently no known scenarios where this affects JitCompilationTime. This removes the quadratic JIT compilation-time behavior for methods with many copies between distinct but layout-compatible structs, in anticipation of more AreCompatible usages.

Regression?

  • Yes
  • No

Testing

  • Added src/tests/JIT/opt/Structs/StructCopyCompatibleLayouts.cs: two structs with 1000 fields each (1 GC reference + 999 longs, identical layout) and 2000 straight-line copies between them via Unsafe.As, asserting value and GC-reference preservation.
  • Local A/B on macOS arm64 (Release, DOTNET_TieredCompilation=0, DOTNET_JitTimeLogCsv), with larger generated variants of the same test (GC slots × copies, JIT time of the copy method):
    • 8000 × 20000: Importation 148.5 ms → 19.1 ms (7.8×), total for the method 300.5 ms → 170.6 ms
    • 16000 × 40000: Importation 550.6 ms → 36.2 ms (15.2×), total for the method 964.9 ms → 445.4 ms
    • After the change, Importation scales linearly with IL size (19.1 ms → 36.2 ms when both N and M double), while before it scaled quadratically (148.5 ms → 550.6 ms).
  • Both larger variants and the committed test pass under a Checked build, where the new INDEBUG verification compares every AreCompatible result against AreCompatibleSlow.
  • Not addressed here (remaining from the issue): SuperPMI/JitCompilationTime measurements on System.Private.CoreLib and other real workloads to decide whether the optimization should be used by default.

Risk

Low: the equivalence classes are validated against the previous algorithm on every AreCompatible call in DEBUG/Checked builds; custom, block and non-GC layouts are unaffected.

Group class-based layouts with GC pointers into equivalence classes of
compatible layouts maintained via a DSU parent pointer, so that
ClassLayout::AreCompatible compares class representatives instead of
walking all GC slots on every call. The previous slot-by-slot
comparison is kept as ClassLayout::AreCompatibleSlow; it is used to
join a newly created layout with the representative of its class and
to verify the DSU-based result in DEBUG builds.

Copies between distinct but layout-compatible structs used to make JIT
compilation time quadratic in the number of GC slots times the number
of copies; the compatibility check is now O(1).

Add src/tests/JIT/opt/Structs/StructCopyCompatibleLayouts.cs with two
1000-field structs of identical layout and 2000 straight-line copies
between them, asserting value and GC-reference preservation.

Fixes dotnet#42801
github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Sep 25, 2026
dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Sep 25, 2026

Copy link
Copy Markdown
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.

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Use the existing slow comparison for mixed custom and class-based
layouts. Custom layouts have no DSU parent and cannot use the
representative comparison.

Validated extracted compatibility methods in checked, release and
sanitized harnesses over 104,976 pairs. Full JIT build and execution
were not run in this environment.

AI assistance was used to prepare and validate this change.

Copy link
Copy Markdown
Author

@dotnet-policy-service agree

Copy link
Copy Markdown
Author

For head d45ebc7, the failing SuperPMI tpdiff run has two concrete tooling errors: the windows-x64-2 Helix log reports Intel Pin PrepareToAttach(): Current thread holds VM lock, followed by a missing *_details.csv; the summary step fails in superpmi.py with ValueError: too many values to unpack (expected 5).

Could a maintainer advise whether these match a known build error and what the appropriate next step is? These logs alone do not establish whether the PR caused the failure.

AI-generated diagnostic, posted on behalf of the PR author.

This branch has not been deployed

No deployments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use disjoint-set-union for ClassLayout::AreCompatible.

1 participant


Back | FazBrowse Home | New Git URL