[NativeAOT] Prototype guarded incremental compilation - #132962
[NativeAOT] Prototype guarded incremental compilation#132962awakecoding wants to merge 2 commits into
Conversation
|
Azure Pipelines: Successfully started running 4 pipeline(s). 12 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 |
|
What are you trying to achieve with this? It would be better to start with an issue discussing the experience you would like to see. |
|
I feel like the existing "multifile" mode that we haven't productized is a better approach here (one object file per assembly, would allow incremental ILC execution at the assembly boundary). |
I am trying to improve incremental build performance for NativeAOT on very large projects like Remote Desktop Manager. It currently takes a good 15 minutes to make a change and rebuild, and memory peaks over 32GB in ILC. I've been told you're supposed to just make managed builds with the warnings for NativeAOT to figure out what to fix for NativeAOT and then just wait on the NativeAOT build, trusting that it works, but this prevents actually trying out the NativeAOT build and repeatedly iterate on it. I know my project (RDM) is huge, but that doesn't mean we can't optimize the build tooling to introduce incremental builds |
Where is this documented? |
|
You can set the IlcMultiModule property to true to try it out. Once again, no guarantees, this is unsupported, etc. I also don't know if we actually have the MSBuild targets set up correctly to make this run in an incremental manner so this may need more work for that front. |
|
@jkotas @jkoritzinsky I have created an issue here for NativeAOT incremental compilation support: #132977 |
Summary
Adds a disabled-by-default, internal NativeAOT incremental-compilation prototype for Windows x64 COFF. A single ILC process retains its completed dependency graph, recompiles a prevalidated finite set of changed method bodies, and creates each updated object by patching a copy of the immutable baseline object.
The prototype adds no public API. Incremental rejection is explicit: ILC prints
ILC_INCREMENTAL_REJECTED, exits with code 85, removes outputs it created, and requires the caller to start a fresh clean compilation. Ordinary compiler failures are not classified as clean-fallback requests.Tracking issue: #132977
Implementation
MethodCodeNodecode, GC, EH, debug, local, and dependency state required for recompilation.Supported envelope
Incremental compilation is accepted only for:
OptimizationMode.Nonewith exactly one compiler thread.MethodCodeNode, no conditional dependencies or EH, and overlayable ECMA IL.All other cases request a clean compilation.
RDM build-performance impact
Measured on one eligible edit to reachable
Program.BuildModuleViewIndexin the RDMRdmNativeAotFast=trueworkload:The 3,744,339,247-byte incremental object exactly matched the clean object with SHA-256
B3140045782498DC4A06F712C2DAA329B732D6340DFCD3D80AD4181E17844206. The update reused 13,455,307 of 13,455,308 object nodes, patched one byte, and allocated 1,568,736 managed bytes.These are measured component timings. A separate clean RDM publish measured 951.9 s (15m 51.9s), but a comparable complete incremental
dotnet publishwas not timed. The defensible practical result is the ~36.8-second edit-and-link loop instead of ~10–11 minutes, not a 36.8-second full build.The first request still pays for the clean compilation and retains roughly 34–36 GiB. The result applies only to edits that pass the narrow safety gate.
Validation
build.cmd clr+libs+hostbaseline: succeeded with 0 warnings/errors.build.cmd clr.aot+libs -rc Release -lc Release: succeeded with 0 warnings/errors.ILCompiler.Compiler.TestsRelease: 80 passed, 0 failed, 0 skipped.IncrementalCompilationTests: 58 passed, 0 failed, 0 skipped.BuildNativeAotand succeeded with 0 warnings/errors.0BE481A1B058F826D4FCD0E013DEFC544BF4382E16CE8C5549EF94AE1F73666F.0CB70EB6CAA77ABC4C6F120AE64C1AF3F6370A37AEC4FD54FBF8A96179E44497.Limitations
Normal compiler-driven source edits commonly change the MVID and therefore request a clean compilation. Productization would require a supported command/API contract, complete cross-process content keys for references/resources/toolchain/JIT/environment, request isolation, eviction and crash recovery, broader invalidation for optimized/inlined/preinitialized/reflection/generic/global facts, discovery of newly dirty nodes, validation or regeneration of linker-affecting side outputs, and compile-time-checked internal seams across the compiler assemblies.
Note
This pull request description was generated with GitHub Copilot.