-
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
Advanced Embedding API in .NET5 like Mono #39798
Comments
Very good ideas 👍 |
@BeastLe9enD Thanks for filing this issue. This feature is something we have been mulling over for quite some time. We have actually started exploring this path by providing some basic building blocks. One of the most important is At this point in the release there isn't enough time to design and provide an official API but this is definitely something we are discussing in the .NET 6 release. These decisions are based on user feedback so please keep it coming. |
This statement is interesting to me. Some "marshalling" of a The registration of P/Invokes can possibly be handled in a different way by manually using the None of the above diminishes the value of a similar API to mono's Embedding or the JVM's JNI, I just want to make sure I am understanding all the suggestions/pain points in the issue. |
There are performance trade-offs that come with exposing raw object allocation APIs like this one to 3rd party code. Exposing APIs like this typically requires conservative stack scanning that comes with non-trivial performance hit (~20% for real world workloads when we have measured it last time). CoreCLR offers significantly more performance in part by not having raw embedding APIs like Mono.
System.Reflection has equivalent managed APIs. You can get the same functionality by calling the managed reflection APIs, and sending back the answers to your engine via regular interop. If the reflection APIs do not have the right performance for your scenario or do not offer right features, I believe that we would be more interested in improving managed reflection APIs. Better reflection API would provide more value accross the board. |
@AaronRobinsonMSFT The thing with the managed reflection APIs is very interesting and sounds understandable to me. For my engine I'm working on at the moment I am forced to use the managed refleciton API's and then pass the results back to C++. I do not perceive this as cumbersome because, for example, instead of giving long names to the types, I can use keywords such as typeof, which is easier. As internal call replacement, I'm currently using(for theese who are interested) an own internal call attribute with an external method like the [MethodImpl(MethodImplOptions.InternalCall)] is working: [XInternalCall]
private static extern void MyCustomInternalCall(); Obviously this would normally crash with a TypeLoadException because the method has no implementation! To work around this problem, I load the assembly with its own assembly, which searches all types for the attribute XInternalCall via Mono.Cecil and then fills the method body with the Calli instructions. |
@BeastLe9enD Thanks for the clarification here. It seems that @jkotas understood this point better than I did. This is an useful scenario but as mentioned does come with some drawbacks. Either conservative garbage collection or expensive object pinning must be done. The mono solution is conservative garbage collection but that comes with the performance impact which appears to be why some would like to use coreclr instead. This means we would need to require pinning and then we have a different performance impact. The trade-off is difficult to determine in a general way and allowing user configuration makes the feature even more complicated. The idea behind the /cc @elinor-fung |
like mono, wish mono support alc unload assembly soon. |
@AaronRobinsonMSFT that Interop blog post you mentioned get posted anywhere ? |
@xgalaxy I just got back to work. The blog is close to complete - still updating/clarifying some technical details that have been in flux. The survey has been published and can be found at #40484. The blog will be published in the normal manner so currently following .NET blogs should be sufficient when it is finally published. Thanks for keeping it in mind. |
Yes, I get get your point, the NET5 embedding API is a strength and a weakness at the same time. The runtime performance has really improved, but in situations like you described, its way more complicated and you have to expose parts of the managed reflection api to c++ on your own. Thats what for example UnrealCLR (a plugin that natively integrates NET5 into UnrealEngine) is doing: But there could be more advanced functionality in that direction already integrated into NET6+, we will see |
Thanks for taking note, I will check back when NET6 is released. |
Please compare apples to apples. Here is one example of where MonoVM is compared to CoreCLR https://twitter.com/ben_a_adams/status/1314401170652377088. As you can see the gap is in single percentage point range specifically for this complex benchmark. |
We have no plans to recreate the current shape of Mono embedding APIs in CoreCLR. |
Good to know! So I don't invest any significant efforts into .NET then. |
Very bad, because systems like Unity3D are very much tied to outdated Mono CLR and don't want to update .NET to CoreCLR versions due to porting difficulties and embedding APIs would make it easier to update and maintain CLR in GameEngines In fact, it would be great to archive mono and finally transfer all features from Mono to CoreCLR :\ |
Sorry, I missclicked my mouse (thats the reason why I closed it). In fact, not exposing an real embedding API is really unpractical for using C# as a scripting language, however engines like Unity could write an abstraction from Mono to CoreCLR which should be possible (as far as I think) |
|
Why not? C# has a huge ecosystem that allows you to use the language in all sorts of scenarios. (top-level, csx, etc) |
@BrUnOXaVIeRLeiTE and those disappointed by the statement of no planned support. An explicit embedding API isn't planned, but that doesn't mean scripting and other scenarios leveraging mono's Embedding API aren't important to us nor something we don't want to enable - for example see our Objective-C plan. What would be very helpful to understand is not so much a request for an existing API (i.e. mono's embedding API) that satisfies these needs but rather a description of what functionality is needed. There was mention of the Reflection API above. This could be exposed through a series of static P/Invokes using DNNE. As mentioned the static P/Invoke method is burdensome and clunky, so if DNNE instead permitted exposing a managed class with blittable function signatures to a C++ environment, would that be helpful? What other pieces of functionality are needed? We should also avoid conflating lack of functionality with owning and writing boilerplate code. Much, not all, of mono's Embedding API functionality can be exposed to unmanaged code from CoreCLR manually or using something like DNNE to generate the boilerplate. The real issue for much of the API then is it isn't as direct or simple as mono's Embedding API. This means we should break down the request(s) into groups:
|
Hi, @BrUnOXaVIeRLeiTE it's look so interesting, how you made it? can you share the full code? |
Background and Motivation
In recent years, .NET has established itself in the gaming world. Many game engines like Unity or CryEngine use .NET for scripting entity components and other gameplay related stuff.
This was made possible using the mono runtime, which Unity and CryEngine use. It offers a diversified embedding API with detailed methods that provide precise access to the CLR and all required components.
Unfortunately, CoreCLR only offers a very superficial interface, so for me as a game engine developer it is unfortunately difficult to use CoreCLR instead of mono, although it offers significantly more performance in some places.
Proposed API
One really important function in Mono is the concept of internal calls. You can register internal calls with mono_add_internal_call and they act as native functions you can call from the CLR universe. Because .NET Core has no internal calls that can be controlled by the runtime host, you have to use PInvoke, which has some downsides for example that garbage collected objects must be marshalled (for example System.String -> const char*)
Usage Examples
To store managed objects in the native universe, mono_object_new/mono_string_new are really useful to create managed objects from the native universe, and to ensure that the object is not garbage collected, mono_gchandle_new is unavoidable.
To enumerate properties of components, its required to enumerate/access field and method properties of managed types, so methods like mono_class_get_methods/mono_class_get_field really help!
These few examples are just a small insight of what the Mono Embedding API offers for game developers, and I'm sure that all game developers willing to use .NET will be really excited to see a comparable API in .NET 5 runtime!
The text was updated successfully, but these errors were encountered: