Skip to content

Reduce COFF relocation allocation overhead - #132933

Open
awakecoding wants to merge 4 commits into
dotnet:mainfrom
awakecoding:nativeaot-compact-coff-relocations
Open

Reduce COFF relocation allocation overhead#132933
awakecoding wants to merge 4 commits into
dotnet:mainfrom
awakecoding:nativeaot-compact-coff-relocations

Conversation

@awakecoding

@awakecoding awakecoding commented Aug 29, 2026

Copy link
Copy Markdown

Summary

  • Store each COFF relocation as a 12-byte readonly value instead of a separate heap object referenced by the section's relocation list.
  • Enumerate the values by readonly reference while preserving the existing 10-byte COFF wire encoding.

Motivation

NativeAOT can retain tens of millions of COFF relocations while constructing large Windows object files. The previous representation required one managed object and one list reference per relocation, increasing allocation volume, object count, and GC pressure for data that consists of two uint values and a relocation type.

The retained .NET 10.0.11 RDM experiment contained 41,018,549 COFF relocation records. Replacing the heap records with 12-byte values repeatedly reduced managed allocation by 0.51-0.67 GiB and produced a byte-identical 3,744,339,247-byte object.

Implementation

CoffRelocation is now an immutable struct with the same VirtualAddress, SymbolTableIndex, and Type values. Its natural managed layout is 12 bytes; Write continues to emit the specified 10-byte little-endian COFF record.

Relocations remain in the same List<CoffRelocation> and are appended in the same order. The overflow marker remains the first record with the real count in VirtualAddress and zero symbol/type fields. Emission uses CollectionsMarshal.AsSpan with ref readonly iteration to avoid defensive copies.

This change does not add capacity planning, alternate storage, experiment gates, compact symbols or symbolic relocations, lazy section state, or changes to symbol-table construction.

Validation

  • .\build.cmd clr.aot+libs -rc Release -lc Release on the unmodified base and changed tree: succeeded with 0 warnings and 0 errors.
  • .\build.cmd clr.aot+libs -rc Checked -lc Release: succeeded with 0 warnings and 0 errors.
  • .\build.cmd clr+libs+host -rc Release -lc Release -hc Release: succeeded with 0 warnings and 0 errors.
  • ILCompiler.Compiler.Tests, Release: 22 passed.
  • ILCompiler.Compiler.Tests, Checked: 22 passed.
  • ILCompiler.ReadyToRun.Tests, Release: 87 passed, 5 platform-specific tests skipped.
  • NativeAOT smoke tree: built successfully; 28 tests passed, including SmokeTests\Determinism.
  • A preserved base compiler and the changed compiler produced identical output for the current-main ILC repro: 2,631,448 bytes, SHA-256 6E5DDFA7041B951AAC835F804D275D11EF1CFCF0E7D05AE73DF268A70BE8D09E.

Current-main A/B stress benchmark

A standalone harness outside the production diff reproduces the old class/list-reference representation and the new readonly-struct representation directly from current main (c210d82dbc1ab432b9369604a1caef9a0ab763d2). It creates and writes 5,000,000 relocations per process in interleaved order baseline, compact, compact, baseline, baseline, compact, compact, baseline.

The table reports medians across four processes per representation.

Metric Baseline Compact Change
Heap relocation objects 5,000,000 0 -5,000,000
List element 8-byte reference 12-byte value Inline value
Managed allocation 294,218,508 B 201,327,264 B -92,891,244 B (-31.57%)
Gen 0 collections 13 2 -11
Gen 1 collections 13 2 -11
Gen 2 collections 5 2 -3
Peak private bytes 287,408,128 B 194,394,112 B -93,014,016 B
Peak working set 296,382,464 B 168,476,672 B -127,905,792 B
Conversion wall time 487.66 ms 80.60 ms -83.47%
Conversion CPU time 515.63 ms 171.88 ms -66.67%
Write wall time 439.44 ms 401.87 ms -8.55%
Write CPU time 656.25 ms 781.25 ms +19.05%

Every run wrote the same 50,000,000-byte relocation stream with SHA-256 EDF812AAC09B2D81E39089A2E491C1B2A7F578F77E6E1FEC0E1BBBB5C699A571.

The benchmark establishes the allocation and object-density improvement. The short conversion/write timings are not an end-to-end compilation result and are not used to claim a wall-time improvement.

Retained RDM evidence

The .NET 10.0.11 RDM runs are separate supporting evidence; their response file is not reused for current .NET 11.

Run Wall Object emission Relocation conversion Managed allocation Peak private
Control B 666.90 s 217.35 s 15.15 s 115.53 GiB 35.64 GiB
Compact COFF relocations 638.62 s 203.01 s 8.35 s 115.02 GiB 35.50 GiB
Control C 619.11 s 195.60 s 8.23 s 115.69 GiB 36.25 GiB

All three runs contained 41,018,549 relocation records and produced the same 3,744,339,247-byte object with SHA-256 A267FA3F2402258BAFC93EFDE72DAE04AB1050959788D6CCDB8B64BC477DFFD9.

Allocation improved repeatedly, but relocation conversion matched the warm control floor and end-to-end wall time did not establish a repeatable improvement. This is therefore an allocation/object-density change, with wall time classified as neutral.

Limitations

  • The change affects COFF object emission only.
  • It intentionally makes no end-to-end wall-time claim.
  • It does not include any other profiling experiment or infrastructure.

Note

This pull request description was generated with GitHub Copilot.

Copilot AI lite review requested due to automatic review settings August 29, 2026 22:52
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Aug 29, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

Pull request overview

This PR reduces allocation and GC overhead during COFF object emission by changing CoffRelocation from a per-relocation heap object to an immutable value type, and updates emission to iterate relocations by ref readonly. It also adds targeted unit tests that validate the relocation record encoding and key COFF relocation behaviors across x86/x64/ARM64.

Changes:

  • Replace CoffRelocation with an internal readonly struct and update relocation construction sites accordingly.
  • Emit relocations using CollectionsMarshal.AsSpan(... ) with ref readonly iteration to avoid struct copies during writing.
  • Add ILCompiler.Compiler.Tests coverage for relocation encoding/count/overflow behavior and architecture-specific relocation type mapping, and expose required internals to the test assembly.
File summaries
File Description
src/coreclr/tools/Common/Compiler/ObjectWriter/CoffObjectWriter.cs Converts relocation representation to a compact readonly struct and updates relocation emission to iterate by ref readonly.
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj Adds InternalsVisibleTo to allow tests to access internal COFF writer details/types.
src/coreclr/tools/aot/ILCompiler.Compiler.Tests/ILCompiler.Compiler.Tests.csproj Includes the new COFF object writer test file in compilation.
src/coreclr/tools/aot/ILCompiler.Compiler.Tests/CoffObjectWriterTests.cs Adds focused unit tests for COFF relocation encoding, overflow record behavior, ordering/field stability, addends, and per-architecture relocation type mapping.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 0
  • Review effort level: Lite

Comment thread src/coreclr/tools/aot/ILCompiler.Compiler.Tests/CoffObjectWriterTests.cs Outdated
Copilot AI review requested due to automatic review settings August 30, 2026 00:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread src/coreclr/tools/Common/Compiler/ObjectWriter/CoffObjectWriter.cs
Copilot AI review requested due to automatic review settings August 30, 2026 00:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Comment thread src/coreclr/tools/Common/Compiler/ObjectWriter/CoffObjectWriter.cs Outdated
Copilot AI review requested due to automatic review settings August 30, 2026 01:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

src/coreclr/tools/Common/Compiler/ObjectWriter/CoffObjectWriter.cs:714

  • CoffRelocation is now used via ref readonly iteration (CollectionsMarshal.AsSpan(section.Relocations)), but its Write method is not marked readonly, which can force a defensive copy when invoked on a ref readonly value. Mark Write as readonly to ensure the iteration is actually copy-free.
            public uint VirtualAddress { get; }
            public uint SymbolTableIndex { get; }
            public CoffRelocationType Type { get; }

            public const int Size =
                sizeof(uint) +  // VirtualAddress
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread src/coreclr/tools/Common/Compiler/ObjectWriter/CoffObjectWriter.cs
@jkotas

jkotas commented Aug 30, 2026

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@jkotas jkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

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

Labels

area-NativeAOT-coreclr 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.

3 participants