Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

conversion of C# Script to C++ dll results in speed up factor ~10

Discussion in 'Scripting' started by BlueBudgie1, Jul 26, 2016.

Thread Status:
Not open for further replies.
  1. BlueBudgie1

    BlueBudgie1

    Joined:
    Apr 14, 2016
    Posts:
    47
    I did a scene for a C++_dll vs C#_script benchmark test where I have a for-loop in the update function of a C# script to bottleneck the cpu. The forloop could be anything which is cpu heavy. It represents a typical high-cpu bottleneck here.
    Then I did the identical for-loop in C++, compiled it to a DLL using VS2013 Community and use that one with the Unity dll import. I can switch between C++ dll for loop and C# script for loop in the simple Rotator script by commenting out.

    There is a speed difference of around 10.

    I attached the project.
    https://drive.google.com/file/d/0B_g3hVIuNxkUejE1RTNxN1VaZ2s/view?usp=sharing
    The scene is very basic and boiled down to the dll test. I am new to unity, but have experience in coding etc, and hope I did it right.
    With such a speed difference, it seems worth to outsource as many functions as possible to dlls instead of using them in C# scripts. Also coding your game in a way that it uses dll speed up functions as much as possible seems like a good idea. Not sure what functions display such a speed up apart from for-loops, but since whileloops etc are as basic as forloops chances are good.

    I also understand that dll support was only for the subscription fee Pro version before Unity 5 which seems to make sense since it is a performance feature. In Unity 5 it can be used in the free version as well.

    I am new to Unity and would appreciate any comments about dll pitfalls and so on. Or just to tell me what dumb thing I did wrong and that there actually is no speed difference.


    ----------------------------------------------------------------------------------------------------------------
    Plugin C++ Code

    #if _MSC_VER // this is defined when compiling with Visual Studio
    #define EXPORT_API __declspec(dllexport) // Visual Studio needs annotating exported functions with this
    #else
    #define EXPORT_API // XCode does not need annotating exported functions, so define is empty
    #endif
    // ------------------------------------------------------------------------
    // Plugin itself
    // Link following functions C-style (required for plugins)
    extern "C"
    {
    // The functions we will call from Unity.
    //
    int EXPORT_API PrintANumber(){
    return 5;
    }
    int EXPORT_API LongForLoopDLL()
    {
    for (int i = 1; i <= 50000000; i++)
    {}
    return -50;
    }
    } // end of export C block



    Unity Script Code

    using UnityEngine;
    using System.Collections;
    using System;
    using System.Runtime.InteropServices;


    public class Rotator : MonoBehaviour {
    void LongForLoop(){for (int i = 1; i <= 50000000; i++){ }}
    //Lets make our calls from the Plugin
    [DllImport("ASimplePlugin")]
    private static extern int PrintANumber(); // returns the number 5
    [DllImport("ASimplePlugin")]
    public static extern int LongForLoopDLL(); // returns the number -50 and does the for loop from void LongForLoop()

    void Update ()
    {
    //transform.Rotate (new Vector3 (50, 0, 0) * Time.deltaTime);
    //LongForLoop();

    //LongForLoopDLL();
    transform.Rotate(new Vector3(LongForLoopDLL(), 0, 0) * Time.deltaTime);
    Debug.Log(PrintANumber());
    }

    }
     
  2. Dave-Carlile

    Dave-Carlile

    Joined:
    Sep 16, 2012
    Posts:
    967
    Write your code in C#, profile if there is a performance issue, optimize only when and where needed.
     
    aer0ace and mathiasj like this.
  3. BlueBudgie1

    BlueBudgie1

    Joined:
    Apr 14, 2016
    Posts:
    47
    Sorry for the misunderstanding, there is no performance issue here.
    This is about the general speed difference between C# script and C++ dll and the why/wheather/when a C++ dll should be used.
    If you can be faster, more content can be added too the game.
     
  4. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    It's certainly worth it for some things. Cities Skylines uses C++ for their traffic simulations I believe. The thing to keep in mind is that marshalling objects back and forth between unmanaged and managed memory is not a free operation.
     
  5. Dave-Carlile

    Dave-Carlile

    Joined:
    Sep 16, 2012
    Posts:
    967
    But you shouldn't worry about that until you need to. There are thousands of games that work just fine with C#. Your game is most likely going to work just fine with C#. Why spend time optimizing something before it's needed? It's generally wasted time, especially something as architecturally significant as what you're proposing.
     
  6. mathiasj

    mathiasj

    Joined:
    Nov 3, 2015
    Posts:
    64
    It might be that C++ is faster, but
    • The performance difference often is negligible in real code
    • Game logic often is not the bottleneck of performance
    There are of course cases where it makes sense to write code in C++ rather than in C# but I'd also write it first in C# and if the code performance turns out to be the problem, then you can optimize it in C++.

    Or, to quote Donald Knuth:

    "Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%."
     
  7. BlueBudgie1

    BlueBudgie1

    Joined:
    Apr 14, 2016
    Posts:
    47
    Thanks for the replies.

    The game we are planning will use lots of ocean and buoyancy calculations, that's why we are onto the topic of cpu stress relief. It is true, if the game does not use much cpu, it is not worth it.

    On the other hand, outsourcing for-loops and such to C++ plug-ins is only a matter of minutes, so there is not much optimisation in the classic sense going on here.
     
  8. jimroberts

    jimroberts

    Joined:
    Sep 4, 2014
    Posts:
    560
    You should just use C#. The benefit of creating C++ functions for simple loops and calculations will usually be lost by the marshaling overhead. However, extremely long and complex calculations that return simple results can gain you a significant boost in speed.
     
  9. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    I wouldn't be too optimistic about it.

    You don't know what happens during the C++ compiler's optimization.
    It might actually optimize the empty loop away, if you post such stuff you should also include something which proves that the code is being executed as expected.

    Also, if you're already going for really optimized code, use the pre-increment (++i) instead of post-increment (i++).
     
    jimroberts likes this.
  10. jimroberts

    jimroberts

    Joined:
    Sep 4, 2014
    Posts:
    560
    Both loops should technically be optimized out assuming hes building in release mode.

    @BlueBudgie1 please post the compiled IL for the C# script and the assembly for the C++ script.
     
  11. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Perhaps he has tested it in the editor or something... That would be an optimized dll vs that poor heavy loop. :D
     
  12. BlueBudgie1

    BlueBudgie1

    Joined:
    Apr 14, 2016
    Posts:
    47
    @jimroberts an @Suddoha

    That was it! Thanks for actually replying to the very last sentence of my first post.
    In a release build the C# runs as fast as the C++ dll in the Editor.
    Downside for the C++ dll is that is does not run at all in the release built (cube does not rotate). If you find a free minute, maybe you can look into the file from the first post to check the reason.

    I have not done much in Unity before and do not know the specifics of the engine. So it seems I have to build a release mode everytime to check the true performance because Editor and Release mode differ quite some bit. This might be very time consuming when the project gets large. :(

    Suddoha, the C++ forloop was executed. I checked with some Input and operations in it.
     
  13. BlueBudgie1

    BlueBudgie1

    Joined:
    Apr 14, 2016
    Posts:
    47
    dll was 64bit, release 32...now both working.
    will check later with fps on screen if there is any Speed up at all and if, then how much
     
  14. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,294
    If you have some input and operations in it, it won't get optimized away. An empty for-loop probably will be.

    Comparing the performance of these kinds of things are remarkably hard, exactly because C/C++ murders a lot of performance-testing code through optimization. In general, everything that's really a no-op could be removed, and everything that can be replaced by a constant could be.


    You should really look into using compute shaders for that! That's a built-in way for pushing tasks to the GPU, and those kinds of operations should be ideal for moving over there.
     
  15. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,766
    Yeah because by simply combining two materials to a single material, it can probably result in a better optimization result that converting all your C# code to C++. I would rather spend the time creating a simple texture atlas for optimization rather that trying to optimize the game by messing around with the existing C# code that works fine and risk breaking the code, which is almost guaranteed to happen at some point.
     
  16. BlueBudgie1

    BlueBudgie1

    Joined:
    Apr 14, 2016
    Posts:
    47
    I updated the test for testing in release mode:
    (found a nice script on wiki to show fps on Screen)

    + expanded for.loop to bring the C# script down to below 60fps
    + identically expanded the C++ Loop plus gave it some Input to make sure it is executed.

    -> C# executes at 34ms/Frame, C++ dll at cap 16.67ms/Frame. Just brute doubling the c++ dll for Loop length gives 23ms.

    Here is the updated file + VS2013 Project. You can just comment C#/C++dll in and out and build. Maybe it helps someone.
    https://drive.google.com/file/d/0B_g3hVIuNxkUckVhOU9HeV9EaDQ/view?usp=sharing

    I will stop here. C++ seems a bit faster in the test, but as mentioned above, putting exact numbers on it is hard. If we ever run in CPU bottlenecks, this is a card up the sleeve to pull. I am also just starting in Unity, so no guarantee that everything is bulletproof.


    @Baste Thanks for the advice. We did this here in UE4, but have to switch to Unity for its transparent materials advantage with forward rendering and z-buffer for transp. mats..



    (http://www.bluebudgiestudios.com)
     
  17. BlueBudgie1

    BlueBudgie1

    Joined:
    Apr 14, 2016
    Posts:
    47
Thread Status:
Not open for further replies.