-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ObjWriter in C# #95876
ObjWriter in C# #95876
Conversation
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas Issue DetailsThis is reimplementation of NativeAOT ObjWriter in pure C# instead of depending on LLVM. It implements Mach-O, ELF, COFF object file emitter with DWARF and CodeView debugging information. Only x64 and arm64 targets are implemented to cover officially supported platforms (win-x86 code is present and lightly tested; linux-x86 code is present and incomplete, only serves as a test bed for emitting 32-bit ELF files if we ever need that). Fixes #77178
|
What is this, it is ilc.exe ?? |
Yes. It replaces the object file format writing of the ILC backend. |
On that topic, dunno if ilc is already today using NativeAOT, but I assume that this PR should make it a lot more lightweight for this scenario, correct? |
ILC itself is published as NativeAOT executable. It's not compiled with the in-tree compiler though so it takes a little while till the bits propagate through the dependency pipeline into the SDK and back, but it's self-hosted. It makes it slightly more lightweight in some ways. I expect the memory usage to reduce, although it's not trivial to compare with both the GC and native heap contributing to it. Performance measurements on smoke tests were favorable. It also simplifies the build process and dependency handling, especially for the full .NET source builds. |
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/Dwarf/DwarfHelper.cs
Outdated
Show resolved
Hide resolved
Yup, ilc is published as a NativeAOT app. |
Is there any code/method left from the prototype that used existing NuGets? (Asking whether we need to add entry to |
The algorithm for The only other thing that indirectly came from 3rd party sources were the constants in ElfNative.cs, MachNative.cs, and DwarfNative.cs. They were mostly taken from the specs where possible but few of them mirror the system headers. |
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/CoffObjectWriter.cs
Outdated
Show resolved
Hide resolved
So what about compilation time, is it faster? |
You can see more information in the linked issue #77178. Yes it's faster. |
Should the outputs of this and the LLVM object writer be identical byte for byte? I'm seeing different sizes on the same commit using each object writer for linux-x64. |
TL;DR: No. There are differences in the order of sections, string table order, temporary local symbols in symbol table, DWARF relocations (.debug_info -> .debug_info relocations were not correctly generated in the original ObjWriter), and DWARF compile unit headers. Throughout the development I used a mode where I matched up the output more closely but it’s not an efficient thing to do and it was only useful for the initial debugging. I switched later on to comparing the object files semantically through Aside from debugging information the linked output should be byte for byte identical. |
This is wonderful @filipnavara |
Melanzana is commit ef829f2a7ec22999bab8e07c04bf65ec1474d381 from https://github.com/filipnavara/CodeSign LibObjectFile is commit c483288f58ed7776ad0700314f62545053513086 from https://github.com/filipnavara/LibObjectFile/tree/loclist-wip
…ersioning), reference the projects
…bolTable was moved past EmitDebugSections
This is available in latest daily build of installer: @filipnavara, just noticed that on win-x64, the object size is smaller with managed implementation, but final executable size regresses. > Set-Alias -Name dotnet9 -Value ~/.dotnet9/dotnet
> dotnet9 --version
9.0.100-alpha.1.24059.1
> dotnet9 new webapiaot -n web1
> cd web1
# managed
> dotnet9 publish -c Release -o dist
> wsl du -b dist/web1.exe obj/Release/net9.0/win-x64/native/web1.obj
9504768 dist/web1.exe
51874490 obj/Release/net9.0/win-x64/native/web1.obj
# native
> rm -r -fo obj
> $env:DOTNET_USE_LLVM_OBJWRITER="1"
> dotnet9 publish -c Release -o dist2
> wsl du -b dist2/web1.exe obj/Release/net9.0/win-x64/native/web1.obj
9241088 dist2/web1.exe
55142434 obj/Release/net9.0/win-x64/native/web1.obj worth tracking? |
What advantages does it have over llvm? |
Definitely. Can you file an issue please? I'll look into it. |
Faster compilation speeds at lower memory usage. |
i saw newest version of ilc.exe is 9.0.0-alpha.1.24058.11 and it had objwriter.dll |
There's still a |
We are seeing this in ASP.NET NativeAOT benchmarks. Not only win-x64 (~2%), but for both linux-x64 and for linux-arm64 (~4-6%). (Percent size regressions are for app size + symbols.)
|
Are the win-x64 numbers with #96686? That solved the regression in winapiaot that was reported by @am11 and I believe it should solve the reported regressions in the ASP.NET on win-x64 too. Do you have any hints on what to build to repro the size regression on linux-x64/arm64? I can take a look this week. |
Note that on Linux specifically there's a regression in symbol size in DWARF format inside the .o file because correct relocations are emitted for the |
It looks like the win-x64 did go back down after a few builds, but not all the way back:
|
Isn't the |
It is. I specifically mentioned that because of the "+ symbols". I am not sure how the benchmarks are setup to deal with the symbols so depending on the configuration it may have some effect. |
We explicitly pass |
This comment was marked as outdated.
This comment was marked as outdated.
win-x64 / .NET SDK 9.0.100-alpha.1.24060.16 With With In conclusion, I don't see a size regression on win-x64 with the latest SDK build downloaded from dotnet/installer. The executable size and .pdb size is entirely identical. This is with just flipping the ObjWriter code path and no other unrelated changes. The size is 9.00 MiB which is consistent with the dashboard size. Perhaps the additional regression from 8.81 MiB to 9.00 MiB is caused by some other change? |
linux-x64 / .NET SDK 9.0.100-alpha.1.24060.24 With With Again, there's not regression in executable size by just switching the ObjWriter code. I manually verified the sections of the .o files to make sure the correct ObjWriter was used (a quirk makes the name of the |
For posterity, the data above for both of the platforms were produced with this Benchmarks commit. |
I can get the mstat files between the 2 benchmark runs, if that helps anything? Are there other files that would help identify the regression? |
You may be onto something here. I am testing on Ubuntu 22.04. The binlog file shows The relevant versions on the system are:
I'll try the LLVM linker and specifically check the .eh_frame section and its padding. |
linux-x64, same as above, just with
There's difference to the size from the BFD linker but the difference between the old/new ObjWriter is only 8 bytes. |
One thing I forgot to mention is that the app as checked in is targeting net8.0. You need to change the TFM to net9.0. crank does that for us automatically. |
Yeah, I figured that out after the first set of bogus numbers in #95876 (comment).
Seems like the specification say to align to address size, which in our case would be 4-bytes, and we always align to 8-bytes. I'll need to check this thoroughly. I'd expect to see this difference between the local builds with |
Getting the mstat files helped here. Looks like there was some changes in LINQ that might be causing the regression, and I just saw this "ObjWriter" change with comments saying there was a size regression. Here are the mstat files for anyone who is curious: Sorry for the false alarm here, @filipnavara. UPDATE: I believe the regression is from #96570 (comment). |
No worries... I am happy for the extra scrutiny of this PR. It actually helped bring a light to the |
Installer build is out for this SDK as well. Just replaced ~/.dotnet9 with new bits and it fixed the win-x64 regression (smaller .obj and .pdb, identical .exe). Thanks for the quick fix! :)
nit: prefer using |
This is reimplementation of NativeAOT ObjWriter in pure C# instead of depending on LLVM. It implements Mach-O, ELF, COFF object file emitter with DWARF and CodeView debugging information. Only x64 and arm64 targets are implemented to cover officially supported platforms (win-x86 code is present and lightly tested; linux-x86 code is present and incomplete, only serves as a test bed for emitting 32-bit ELF files if we ever need that).
Original object writer code is still present and can be used by setting the
DOTNET_USE_LLVM_OBJWRITER=1
environment variable.Thanks to @am11 for helping with testing and debugging this, @xoofx for making LibObjectFile which helped kickstart this project, @PaulusParssinen for tips about branchless U/SLEB128 size calculation, and all the people on the .NET team who helped push this forward!
Fixes #77178