Sign in to follow this  
AlexandreMutel

Unity [.net] Faster game with NetAsm, a JIT Native Code Injection Library

Recommended Posts

Hi,

I would like to share with the .NET community, the NetAsm opensource project available on codeplex.
NetAsm provides a hook to the .NET JIT compiler and enables to inject your own native code in replacement of the default CLR JIT compilation. With this library, it is possible, at runtime, to inject x86 assembler code in CLR methods with the speed of a pure CLR method call and without the cost of Interop/PInvoke calls. With this library, it is possible for example to inject highly optimized code (using SSE, MMX) inside a method, in replacement of the default generated native code by the JIT compiler.
This library could be particularly useful for game using .NET platform (XNA for example), as it provides a way to integrate fast native code for methods that need highly optimized native code. The current features of NetAsm are:

  • Runs on x86 32bit Microsoft .NET platform with 2.0+ CLR runtime (x64 may be supported in the future
  • Provides three different native code injection techniques: Static, DLL, and Dynamic
    • Static code injection: The native code is stored in an attribute of the method.
    • Dll code injection: this method is similar to the DllImport mechanism but CLR methods are directly bind to the DLL function, without going through the interop layers.
    • Dynamic code injection: you can generate native code dynamically with a callback interface that is called by the JIT when compilation of a method is occurring. It means that you can compile a method "on the fly". You have also access to the IL code of the method being compiled.
  • Supports for debugging static and dynamic code injection.
  • Supports for different calling conventions: StdCall, FastCall, ThisCall, Cdecl. Default calling convention is CLRCall
  • NetAsm can be used inside any .NET language (you can run assembler code inside VB!)
  • Very small library <100Ko.

For additional information and documentation, please visit the NetAsm codeplex site.

Alexandre

Share this post


Link to post
Share on other sites
Odd question, but is there any chance that the approach could be modified to work on the Xbox 360, which runs a version of the .net compact framework and omits the emit instruction, or does the approach rely on something x86 specific? I realize its a very different architecture, but the CPU is fairly well understood and if it were possible it would go a long way towards getting the most out of the 360 (such as the VMX128 units).

I'm not sure if there are other protections in place, in fact, there probably are, but it would definitely be something to look into.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ravyne
Odd question, but is there any chance that the approach could be modified to work on the Xbox 360, which runs a version of the .net compact framework and omits the emit instruction, or does the approach rely on something x86 specific? I realize its a very different architecture, but the CPU is fairly well understood and if it were possible it would go a long way towards getting the most out of the 360 (such as the VMX128 units).

I'm not sure if there are other protections in place, in fact, there probably are, but it would definitely be something to look into.
Well, currently, NetAsm is supporting only x86 32bit .NET platform. NetAsm is not able to run on .NET CF on XBox360, as the Xbox CF doesn't allow the use of mixed library or native library. Although, technically, if the .NET CF on XBox360 was more open, NetAsm should be able to run with few minor changes...

Share this post


Link to post
Share on other sites
Very interesting.
Quote:
Original post by AlexandreMutelDll code injection: this method is similar to the DllImport mechanism but CLR methods are directly bind to the DLL function, without going through the interop layers.

Would it be possible also something like this with delegates? Like calling delegate would directly bind to given address of some native function without interop layers. I'm thinking here about usage of OpenGL extensions and wglGetProcAddress returned function pointer.

Share this post


Link to post
Share on other sites
Quote:
Original post by bubu LV
Would it be possible also something like this with delegates? Like calling delegate would directly bind to given address of some native function without interop layers. I'm thinking here about usage of OpenGL extensions and wglGetProcAddress returned function pointer.

If you think about something similar to Marshal.GetDelegateForFunctionPointer this is currently possible in NetAsm through Dynamic code injection (see TestDynamicCodeInjection.cs in NetAsmDemo sample on how to do dynamic code injection). I could add this delegate features if enough people are interested in (add this request to the Issue Tracker on codeplex).
However, NetAsm should not be considered as a replacement for Interop. There are some issues :
  1. The native code injected is considered as CLR code and not as unmanaged, so there are some restrictions when using external functions that could call OS functions (for example, even if NetAsm could call printf from msvcrt.dll, it prints nothing because the CLR is supposed to be in CLR mode and not unmanaged) : Interop has a different behavior as you leave the CLR runtime to the unmanaged runtime (the VM does a couple of things to insure the transition, thread contexts...etc.).
  2. Also, NetAsm doesn't fully support other calling conventions (StdCall, FastCall, ThisCall, Cdecl). The default supported calling convention is ClrCall - which doesn't do any conversion call between the CLR call and the code injected-

Currently, native code injection should be preferred when using CPU intensive calculation (for small routines for example).

Moreover, if you look at some benchmarks on NetAsm, you will see that when a method is CPU intensive and is running for a medium-time, the cost of calling through Interop is negligible to the cost of the method itself (See Matrix Multiplication sample using SSE2 : in this example, NetAsm is only 10% faster than fast interop - without security checking).

Share this post


Link to post
Share on other sites
This is extremely interesting!

A couple of questions:

Is there any chance that this could work on the Mono JIT? What would it take for that to happen?

How easy is it to add support for different platforms (e.g. x86_64)?

"The native code injected is considered as CLR code and not as unmanaged" - would this restrict calling e.g. OpenGL functions?

I am mainly trying to understand how/if this project could be used to speed up wrappers like Tao or OpenTK.

Keep up the good work!

Share this post


Link to post
Share on other sites
Quote:
Original post by Fiddler
Is there any chance that this could work on the Mono JIT? What would it take for that to happen?

We have to wait... i have just asked this to Miguel de Icaza. It would be nice but i'm not sure it's possible or even it would be made possible by Mono team dev...
Quote:
How easy is it to add support for different platforms (e.g. x86_64)?

I don't have currently any way to test such platform, although the port of NetAsm to x64 shouldn't be hard. If anyone is interested in helping me on this, i would appreciate.
Quote:
"The native code injected is considered as CLR code and not as unmanaged" - would this restrict calling e.g. OpenGL functions?

You have to test it. I'm not sure it's going to work.

Share this post


Link to post
Share on other sites
Quote:
Original post by AlexandreMutel
Quote:
Original post by Fiddler
Is there any chance that this could work on the Mono JIT? What would it take for that to happen?

We have to wait... i have just asked this to Miguel de Icaza. It would be nice but i'm not sure it's possible or even it would be made possible by Mono team dev...

Great! Going from posts on the mono-dev mailing for the debugging and profiler APIs, I suspect that it might be possible, but I'm nowhere proficient enough on the Mono internals to say for sure.

I also don't know how Mono plays with C++/CLI. There was some work on this front recently, but I don't think it's really supported at this point. (By supported I mean running C++/CLI assemblies, not compiling).

Going slightly off-topic now, but Mono takes a smaller hit than .Net when calling unmanaged code (about 6ns overhead versus 12ns for a simple function with one parameter and one return value, measured on x64 mode on a Core 2 @2.66GHz). The capability for dynamic injection through NetAsm is still awesome, though!

Quote:

Quote:
How easy is it to add support for different platforms (e.g. x86_64)?

I don't have currently any way to test such platform, although the port of NetAsm to x64 shouldn't be hard. If anyone is interested in helping me on this, i would appreciate.

If you point me to the correct direction, I could help with this. Is this as simple as adding a new calling to the CallingConventionHelper.h? How would the JIT hooks need to change?

Quote:
Quote:
"The native code injected is considered as CLR code and not as unmanaged" - would this restrict calling e.g. OpenGL functions?

You have to test it. I'm not sure it's going to work.
[/quote]
Fair enough :D I'll write a simple test to check this out.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Forum Statistics

    • Total Topics
      628282
    • Total Posts
      2981805
  • Similar Content

    • By ForgedInteractive


      Who We Are
      We are Forged Interactive, a small team of like-minded game developers with the sole purpose of making games we love! We're a team of artists, animators, programmers, level designers, writers, composers, producers, and other creative minds. We want to make games that you, the modern gamer want to play! We hope to build a community that enjoys our games as much as we love creating them. With your feedback and support we will be able to achieve that.

      About the Game
      GAME NAME is a fun, action-packed army builder with unique characters, challenges and engaging levels. Set forth on an adventure to protect friends, family and countrymen from new adversaries. Once defeated your enemies turn coat and join you in your adventures. Players can enjoy a range of troops and abilities based on their gameplay style which become more important as maps introduce more challenging terrain, enemies and bosses. Strong orc knights, dangerous shamans, and even a dragon are out on the prowl. Knowing when to fight and when to run, and how to manage your army is essential. Your actions alone decide the fate of this world.

      Previous Work by Team
      Although we are working towards our first game as a team, our team members themselves have past experience in the industry.
      This includes members who have worked on titles including:
      Final Fantasy Kingsglaive, FIFA, Xcom 2 and Civilization.

      Who are we looking for? 3D Modellers Concept Artists Marketing Specialists Level Designer

      What do we expect? Reference work or portfolio. Examples what have you already done and what projects you have worked on academic or otherwise. The ability to commit to the project on a regular basis. If you are going on a two-week trip, we don't mind, but it would be good if you could commit 10+ hours to the project each week. Willingness to work with a royalty based compensation model, you will be paid when the game launches. Openness to learning new tools and techniques
      What can we offer? Continuous support and availability from our side. You have the ability to give design input, and creative say in the development of the game. Shown in credits on websites, in-game and more. Insight and contacts from within the Industry.
      Contact
      If you are interested in knowing more or joining. Please email or PM us on Skype. Myself or Colin will reply to you within 48 hours.

      E-mail: Recruitment@ForgedInteractive.com
      Skype: ForgedInteractive

      Regards,
      David and Colin

      Follow us on:

      Facebook: https://www.facebook.com/ForgedInteractive/
      Twitter: @ForgedInteract
      Youtube: https://www.youtube.com/channel/UCpK..._as=subscriber
      Reddit: https://www.reddit.com/user/Forged_Interactive/
    • By Eck
      I just saw their courses were knocked down to $10 each and figured I'd share the info here. They have stuff for Unity, Unreal, drawing, business, etc. I haven't used their stuff before, but the previews I looked at seemed pretty good and there is a user review system as well.
      https://www.udemy.com/courses/search/?q=Unity&src=ukw
      - Eck
       
    • By zizulot
      first and only logo , for now
    • By sidbhati32
      I am working on a game in which we control a rectangular box at the bottom of the screen. Three sphere which has alphabets in it fall down. When the game starts, a word is generated from the predefined list of words(which I'll give) and we are supposed to touch the correct sphere having the alphabet based on that word. The question is how to detect if I have touched the correct sphere. 
      secondly, if I have touched a correct sphere before and there is no recurrence of that alphabet in that word then during the second wave the game should not proceed if I touch the same alphabet again.
      Looking forward to your answers, i have to submit this project in a couple of days. please help! (Working on Unity 3D)
      Thanks
    • By NDraskovic
      Hey guys,   As the title says, I'm trying to control a desktop game by using my mobile phone as a controller.  I created two scenes, one that acts as a server, other as a client.    Server has this code: void Start () {         Test = "Nothing yet happened";         NetworkServer.Listen(25000);         NetworkServer.RegisterHandler(888, ServerReceiveMessage);     }         private void ServerReceiveMessage(NetworkMessage message)     {                 StringMessage msg = new StringMessage();         msg.value = message.ReadMessage<StringMessage>().value;         if (!String.IsNullOrEmpty(msg.value))         {             Test = "Message received";             string[] deltas = msg.value.Split('|');             Horizontal = Convert.ToSingle(deltas[0]);             Vertical = Convert.ToSingle(deltas[1]);             TestScript.MoveForward(Vertical);             TestScript.RotateAroundY(Horizontal);         }         else         {             Test = "Nothing received";         }     }  
        And client this:  private void Connect()     {              client.Connect(IPAddress, 25000);           }     void Start () {         client = new NetworkClient();         Connect();            }         void Update () {    #if UNITY_ANDROID         MobileTouches = Input.touches;         if (MobileTouches.Length > 0)         {             for (int i = 0; i < MobileTouches.Length; i++)             {                 if (MobileTouches[i].phase == TouchPhase.Moved)                 {                     Horizontal = MobileTouches[i].deltaPosition.x;                     Vertical = MobileTouches[i].deltaPosition.y;                 }else if(MobileTouches[i].phase == TouchPhase.Stationary)                 {                     Connect();                                  }             }         } #elif UNITY_EDITOR               Horizontal = Input.GetAxis("Horizontal");         Vertical = Input.GetAxis("Vertical"); #endif         thumb.Translate(Vector3.up * Vertical * Time.deltaTime);         thumb.Translate(Vector3.right * Horizontal * Time.deltaTime);         SendControllerInfo();     }     static public void SendControllerInfo()     {         if (client.isConnected)         {             StringMessage msg = new StringMessage();             msg.value = Horizontal + "|" + Vertical;             client.Send(888, msg);         }     }  
        Ip address is hard coded, I just replaced it with the "IpAddress" variable. The code itself builds fine, and when I try to run in on a desktop computer, it works as expected (just a simple movement of an object on the server screen). However when I try to publish the client scene to a mobile device (Android), it doesn't connect to the server. They are both connected to the same network. Can anyone tell me what the problem might be?   Thanks
  • Popular Now