-
Notifications
You must be signed in to change notification settings - Fork 202
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
Early adopters can experiment with native AOT form factor #248
Comments
Be careful to define this properly. A "JIT-less native AOT" is not a good idea. Far too much of the .NET ecosystem depends on the JIT being there for one reason or another. A far better goal is to AOT everything that can be determined statically, and then leave the JIT in there for when it's needed. It doesn't have to be an either/or thing. Just another example of Anders Hejlsberg's principle: static where possible, dynamic when necessary. |
@masonwheeler certain platforms like e.g. iOS don't allow JITs, I believe. Supporting a JITless scenario is the only option there. I believe the "AOT and JIT at once" scenario is already filled by ReadyToRun, no? |
Then we shouldn't support them. Particularly iOS; why legitimize a system that's spent over a decade being actively hostile to you? Like a person in an abusive relationship, attempting to appease them never makes anything better; the only correct choice of action is to walk away.
Not really. It doesn't go anywhere near far enough in AOTing things that can be AOT'd; as soon as a problem starts to look even a little bit difficult it punts it off to the JIT. I say, aggressively AOT everything that can be AOT'd, and leave the JIT only for things that legitimately require it. |
This would cut the option to support game consoles, too. As far as I remember there were quite some interest for native AOT from game developers in the survey. |
Indeed, I believe that none of the game console platforms allow JITs either (though of course detailed info on this kinda stuff will be behind NDAs). There's a reason Mono AOT is necessary, and also Unity's IL2CPP.
Not getting into any of the "abusive relationship" stuff... not supporting iOS is a huge market missed and also means Android is less viable (no ability to share code). That's not practical.
Did you mix up "AOT" and "JIT" in your last sentence? At first you say it AOTs too little but then you say it should JIT as much as possible. |
@RalfKornmannEnvision Which game console forbids JITs on their platform? I've only ever heard of Apple doing that with iOS. (It's quite possible that I haven't heard about it on consoles because of NDAs or whatever, but the fact remains that I haven't heard about it happening anywhere other than iOS. Do they have a problem with JITs in general, or just with runtime generation of executable code in-memory, and if the latter, could the IL interpreter be employed?) |
Oops, you're right. Fixed now.
That's what we call "penny wise and pound foolish." The "abusive relationship stuff" is my entire point: iOS is a system that is actively hostile to both developers and users, and we ought to treat it as a pariah and actively work to delegitimize it and disempower it, rather than appeasing their ever-worsening demands in the hopes of catching a few crumbs from their table. |
Every modern game console doesn't allow to generate any kind of executable code at runtime. It's part of the security system. You can always run an interpreter but on a system like the Nintendo Switch I would honestly prefer to have an option to not depend on it even if it means that I lost some features.Developers who already use one of the C# solutions for these platforms are already aware of such limitations. But using RyuJit instead of Mo0no AOT would mean an significant performances improvement. |
To cover the edge cases. If you have code that's using dynamic code generation (expression trees, serializers, etc,) calling reflection features such as If the AOT can prove that the program doesn't use any of this, it's free to leave the JIT out. And if the execution never uses these features, it will never need to fire up the JIT. But saying "here's this feature that massive amounts of the existing .NET ecosystem touch in one way or another, and we're going to place all of that existing code off-limits if you want good AOT" just leaves a bad taste in my mouth. |
These kinds of edge cases are better solved in ways such as better compile time code generation, which we are getting with C# source generators for example. |
What people expect when they use .NET code is .NET code that works. That should always be the highest priority. |
I fail to see how this is mutually exclusive? |
Oh, I definitely agree. And if source generators were actually any good, that would be amazing. But they aren't. The current implementation of generators really sucks, and the Roslyn team is firmly committed to making sure they never stop being sucky, because good metaprogramming is incompatible with something they hold as a much higher value: ensuring that everything will execute very quickly and never make Intellisense have to wait. (Not exaggerating. This is the result of many exasperating conversations with team members who are completely unwilling to budge on this point. Visual Studio UX trumps language quality any day of the week.) |
I don't think that this would be a big problem. Developers are already using Xamarin on iOS, Unity or Mono AOT today All of these have limitations compared to the full .Net experiences But even if there are already working solutions for AOT I still like to see am offical supported solution that is based on the current .net development. Because based on own experiments I know that the RuyJit based CoreRT solution generates much better results than Mono AOT. |
Rust does it by having actual metaprogramming, of the type the Roslyn folks refuse to consider. Not sure which other languages you're referring to. The only other "high level system language" that's gained any traction in recent years is Go, and Go is basically awful all around in this area. |
The current version of source generators isn't great, that's true. But it'll be improved. And imo it's very important we keep the fast nature of Roslyn. Do we really want another C++ with a build process more complicated then your code, and longer compilation time then Runtime? (exaggeration, of course, but you get the point) Roslyn is very very powerful and it's not at its limits with source generators at all, theres lots of improvements to be made imo, but I don't doubt they'll be made for one second. Also, I believe the only thing the Roslyn team refuses to consider is code removal/rewriting. Not sure what everyone thinks this will do for them, but to my knowledge another core principle of the Roslyn code base is immutability, and this makes sense from a language design perspective too, I've never heard a single compelling case for code rewriting. There are already security concerns with analyzers, and even more of them with source generators... |
And given that rewriting is the single most useful feature of metaprogramming, my complaint stands. |
Thanks for reconsidering the status of AOT support. |
Would be absolutely amazing if Blazor switches to using NativeAOT (assuming it uses CoreRT as its base). CoreRT produced much smaller binaries than Mono’s AOT effort while still producing best in class performance. It would solve the question of “can I use Blazor for a massive public facing website?” as AOT Wasm is extremely fast so there’d be no performance penalty of using Blazor over JavaScript SPA frameworks, and the start-up time would, in theory, only be slightly slower than these aforementioned frameworks. I’m convinced that if Microsoft want Blazor to be the go-to answer for web development then it needs to use the gold mine that is CoreRT. There’s only a few too many uncomfortable trade-offs a person has to make when using today’s Blazor but they can be eliminated entirely with a good NativeAOT/CoreRT story. Begging MS to pursue this. |
I'd also add in that LLILC could pair nicely with a native AOT implementation to target multiple backends and optimizations via LLVM. Auto-vectorization comes to mind. |
The issue with LLILC is that you will lost all the special net optimization's that are done by RyuJit. Because of this there is the idea to to to use a combination of RyuJit and LLVM. First let RyuJit convert and optimize the MSIL code to the CPU independent internal RyuJit intermediate format. Than instead of generating code for the target CPU the RyuJit format can be converted to LLVM. This will allow future optimization's that are beyond the limitations of RyuJit. This way you can get the best of both worlds. But this is even further away than NativeAOT. |
COM interop needs to be added because it's the most impactful thing tracked in this repo, and it would fix a major regression in the ecosystem by replacing netnative. System.Text.Json and EventSource source generators and precompiling regex code are nice-to-have features rather than essentials, while COM interop opens up frameworks where native AOT can immediately get real usage, with large benefit for developers and users. The title of this issue is not ambitious enough because early adopters can already experiment with native AOT form factor, and they have been able to experiment with it and even use it in production for years! It was better before: "Developers can compile .NET apps into native executables (native AOT form factor)". |
My opinion on the matter: I, today, can take a .NET 5 Windows Forms project, run it though NativeAOT, and have the window appear as expected. (When you try to do anything further you get a crash due to missing COM support.) However, these days I use WPF. WPF uses C++/CLI in two of its assemblies: DirectWriteForwarder and ReachFramework. I have never used ReachFramework (hell, I don't even know what it does), but DirectWriteForwarder is an integral WPF component, very near the root of the dependency graph. You can create a lot of crazy MSIL code using C++/CLI. I fully understand that it is impossible to support every possible C++/CLI assembly out there. However, not supporting any C++/CLI immediately rules out usage of WPF with NativeAOT. This would be a dealbreaker for me, as I (and many others) write 100% WPF applications because WPF is the only actually usable C# GUI toolkit available. (Windows Forms looks extremely dated, and WinUI 3 is nowhere near usable yet.) |
@hez2010 I actually have already extensively experimented with that technology, but thanks for the pointer! |
Seems like it's only setup for Mac OSX Native right now? (looking at the source) |
I would like to back Ethan's comment as a MonoGame contributor and in regard to my position at Flying Oak Games (we make, and port games to consoles). NativeAOT, as it is now, has been an extremely valuable project and several relevant projects have been shipped with it to wide audiences. This includes Streets of Rage 4, Carrion, ScourgeBringer, River City Ransom: Underground, Dust... which all shipped to Windows, macOS, and Linux, and to more than 100k players each. I would also very much back the counterproductivity of AOT+JIT in that context. C# game developers are very used to work without a JIT (they want to avoid it at all cost because it is visible during gameplay, and a forced AOT is an excellent benchmark to proof a code to work without JIT) and without reflection because most console runtimes don't support it in favor of aggressive AOT. As mentioned by Ethan, game developers are more into pre-generating serializers (e.g. with protobuf) than relying on runtime IL emition (this is a trend that I can clearly confirm). In regard to reflection, BRUTE (the AOT compiler used for FNA and MonoGame on consoles) is using a very straightforward xml description file to let the compiler know which types should be included if they were to be trimmed by spidering. It works great as it is. TL;DR; NativeAOT is a very relevant, appreciated and battle-tested project as it is for game development, and I would very much support its integration as an official .NET form-factor. |
I'm also making a mmorpg game that have both client and server written with dotnet 6 and built with NativeAOT. NativeAOT provides more efficient code, and most importantly for me, it protects my source code almost as c++ would do. |
We've hit our targets here for 6.0 -- new architecture support (ARM64 on Linux and Windows) and many bugs fixed. Huge amounts of netcoreapp libraries have been annotated for trimming (dotnet/runtime#43543) which is the most important indicator of NativeAOT compatibility. Many libraries have even been made safe for trimming, like the source generators for System.Text.Json (dotnet/runtime#1568). We've also started adding more CoreCLR feature support to NativeAOT, like default interface implementations and covariant returns. This is just the start of NativeAOT work, but .NET 6 has tons of improvements. We'll soon start planning for .NET 7 and we'll see what else we can do for NativeAOT and how the improvements can fit into the broader .NET 7 release. |
Have any experiments been done that just compile (C# => LLVM => ASM) OR (C# => ASM) directly? Another thought: If a new C++ feature comes out, older compilers can't parse the headers & thats fine. Same concept should apply to .NET binaries. Seems like its far to often newer C# features take forever to be considered because of older runtime compatibility nonsense. This really needs to be mitigated more and newer runtimes designed to handle newer lang features in performant manors should be the focus. Thats a hard Pro over any minor Cons IMO. This would allow features like fixed multi-dimensional arrays & fixed non-primitive arrays to be added very quickly I would imagine. AOT has valuable lessons that seem to be getting missed in the .NET / JIT world IMO. |
.net 6 has been release,but seems both (AOT or Native) not included. |
If anyone has the time, a brief summary of the state of AOT in .Net 6 including how early adopters can begin experimenting with it would be greatly appreciated. 🙂 |
While these experiments can be interesting research projects, they would lead towards a complete reset and fork of .NET ecosystem. We do not believe that it would be a viable strategy. See ingredients of successful native AOT support in https://github.com/dotnet/designs/blob/main/accepted/2020/form-factors.md#native-aot-form-factors
It used to to be the case with .NET Framework. We are well pass that. We have been adding new core runtime features in every .NET Core release that are not present in older runtimes. |
.NET had different forms of AOT since forever. https://docs.microsoft.com/en-us/dotnet/core/deploying/ready-to-run is form of AOT for server and desktop included in .NET 6. There is also AOT for wasm and mobile form factors.
NativeAOT packages are published on experimental feed. It is enough for early adopters that we have been in contact with to experiment with it. See https://github.com/dotnet/runtimelab/blob/feature/NativeAOT/docs/using-nativeaot/compiling.md for how to use it. |
-- This is only partially true. Which is why I specifically brought up "fixed multi-dimensional arrays & fixed non-primitive arrays" which are being blocked by MSIL & legacy runtime compatibility issues with said IL (which is what needs to be mitigated). And thats just the one I know of because I've wished this part of the lang was feature complete for years. I'm sure their are others in this category. |
fixed arrays are a type system concern. IL is just one of the many places where the .NET type system is materialized. Other places include language compilers, AOT compilers, runtime, reflection APIs, debuggers, and all sort of other tools. Adding new core concept requires touching most of these. The problem is updating all these places, not in updating the IL alone. |
|
I respectfully disagree. Maintaining C# compiler compatibility so it can target older .NETFW 4.x runtimes adds less than 0.1% overhead to everything we do today.
That's true for .NET today. You cannot run modern .NET 6 C# with old .NET Framework. The opposite works though: you can compile and run old C# code with latest .NET 6. Just like it is with C++. |
But not always in the most optimal/performant way. Anyway don't mean to drag this on forever... |
Unity's Burst is basically an alternative optimized compiler as far as I know, and I think it still just takes in IL. (IIRC) In a blog post they mentioned that re-using the (relatively) high level IL emitted by the C# compiler was much easier than making a completely alternative C# compiler (or language altogether). Of course it's still a specialized case, but it's something to consider.
I don't know about non-primitive arrays ,but my understanding is that the runtime barely even knows what |
Multi-dimensional arrays already exist. According to the CLI spec:
This is supported in the C# language through multidimensional array syntax. |
I believe @zezba9000 is referring to struct Foo
{
public fixed byte Bar[32];
} |
Yes, for fixed arrays of primitive types only. If you would like to have fixed arrays of non-primitive types, allow fixed array to show up in signatures, or access them via reflection, there is some level of runtime support required. See dotnet/runtime#61135 and related issues. This topic is best discussed there. |
@PJB3005 I was referring to these incomplete lang features. (None of which compile atm) [StructLayout(LayoutKind.Sequential)]
struct MyStruct
{
// some fields
}
[StructLayout(LayoutKind.Sequential)]
unsafe struct Foo
{
public fixed MyStruct Items[123];// single-dimensional fixed-array with custom-struct
public fixed MyStruct Items[123][28];// multi-dimensional fixed-array with custom-struct
public fixed float Items[123][28];// multi-dimensional fixed-array with primitives
} |
for (custom struct) fixed-sized-buffers .net 6 -C#10 ,no processing yet . |
This is a draft/proposed User Story and not committed for .NET 6.0 yet.
We have seen a surge of interest in statically linked binaries with minimal dependencies in recent years. This is a reversal of a multi-decade trend to deliver dependencies as shared libraries. The benefits to deployment and the ability to optimize a single app outweigh the benefits of sharing for certain types of workloads. The gain is most significant for workloads with a high number of deployed instances: cloud infrastructure, hyper-scale services, popular apps or games. The number of apps of this type is relatively small, but they are highly visible, impactful, and often cost a lot of money to operate (savings can be meaningful).
Emerging programming environments (e.g. Go, Rust) tend to be designed for this form factor. Established programming environments are catching up on this trend to be relevant for this highly visible segment, for example Java Graal, Dart, Kotlin/Native.
Various implementations of .NET (Xamarin, Unity, .NET Native) have demonstrated that .NET is well suited to native AOT in terms of fundamentals, however, there are tools experience and ecosystem challenges that currently prevent .NET from being a great general purpose solution. We intend to start addressing these issues with this project. It is very likely that the first set of improvements will have rough edges that may prevent adoption for some developers. We will use feedback to determine which experience issues to prioritize. We are also not comitting to any particular end point for this project, at this time.
This high level section sets our intention to invest in native AOT scenarios and more definition from the teams will be needed to define our phased approach over the next few .NET releases.
Work Items / User stories
The text was updated successfully, but these errors were encountered: