Reduce COFF relocation allocation overhead - #132933
Conversation
|
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. |
|
Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib |
There was a problem hiding this comment.
🟢 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
CoffRelocationwith aninternal readonly structand update relocation construction sites accordingly. - Emit relocations using
CollectionsMarshal.AsSpan(... )withref readonlyiteration to avoid struct copies during writing. - Add
ILCompiler.Compiler.Testscoverage 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
There was a problem hiding this comment.
🟡 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
CoffRelocationis now used viaref readonlyiteration (CollectionsMarshal.AsSpan(section.Relocations)), but itsWritemethod is not markedreadonly, which can force a defensive copy when invoked on aref readonlyvalue. MarkWriteasreadonlyto 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
|
/azp run runtime-nativeaot-outerloop |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
Summary
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
uintvalues 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
CoffRelocationis now an immutable struct with the sameVirtualAddress,SymbolTableIndex, andTypevalues. Its natural managed layout is 12 bytes;Writecontinues 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 inVirtualAddressand zero symbol/type fields. Emission usesCollectionsMarshal.AsSpanwithref readonlyiteration 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 Releaseon 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.SmokeTests\Determinism.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 orderbaseline, compact, compact, baseline, baseline, compact, compact, baseline.The table reports medians across four processes per representation.
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.
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
Note
This pull request description was generated with GitHub Copilot.