Search Unity

Performance issues. How fast is C# in Unity compared to say, native C++ on a device?

Discussion in 'Scripting' started by Raccoonteur, Oct 25, 2017.

  1. Raccoonteur

    Raccoonteur

    Joined:
    Jun 4, 2017
    Posts:
    23
    I'm trying to do a Life simulation in Unity and I've run into some severe performance issues, among other problems.

    Here are the relevant portions of my code, called in FixedUpdate:

    Code (CSharp):
    1. // Compute the next life step:
    2. void UpdateCellMatrix()
    3. {
    4.     int n; // Number of adjacent cells alive.
    5.     int state;
    6.  
    7.     for (int j = 0; j < height; j++)
    8.     {
    9.         for (int i = 0; i < width; i++)
    10.         {
    11.  
    12.             // Count living neighbors. Matrix wraps at borders to avoid a bunch of conditional jumps.
    13.  
    14.             n = cellMatrix[i, (j + 1) % height]; // top
    15.             n += cellMatrix[(i + 1) % width, (j + 1) % height]; // top right
    16.             n += cellMatrix[(i + 1) % width, j % height]; // right
    17.             n += cellMatrix[(i + 1) % width, (height + j - 1) % height]; // bottom right
    18.             n += cellMatrix[i % width, (height + j - 1) % height]; // bottom
    19.             n += cellMatrix[(width + i - 1) % width, (height + j - 1) % height]; // bottom left
    20.             n += cellMatrix[(width + i - 1) % width, j % height]; // left
    21.             n += cellMatrix[(width + i - 1) % width, (j + 1) % height]; // top left
    22.  
    23.             state = cellMatrix[i, j]; // Get state of cell.
    24.  
    25.             if (state == 1) // If cell is alive...
    26.             {
    27.                 if ((n < 2) || (n > 3)) { state = 0; } // If cell is alive and has less than 2 or more than 3 alive neighbors, kill it.
    28.             }
    29.             else // If cell is dead...
    30.             {
    31.                 if (n == 3) { state = 1; } // If cell is dead and has exactly 3 living neighbors, kill it.
    32.             }
    33.  
    34.             newMatrix[i, j] = state; // Record new cell state.
    35.  
    36.         }
    37.     }
    38.  
    39.     swapMatrix = cellMatrix;
    40.     cellMatrix = newMatrix; // Swap array pointers.
    41.     newMatrix = swapMatrix;
    42.  
    43. }
    44.  
    45. // Draws the cell matrix to the texture.
    46. void DrawCellMatrix()
    47. {
    48.     int index = 0; // ints in Unity are 32 bit.
    49.  
    50.     for (int j = 0; j < height; j++)
    51.     {
    52.         for (int i = 0; i < width; i++)
    53.         {
    54.             if (cellMatrix[i, j] == 0) { newColors[index] = Color.black; } else { newColors[index] = Color.white; }
    55.             index++;
    56.         }
    57.     }
    58.  
    59.     tex.SetPixels32(newColors); // Second parameter is mip level?
    60.     tex.Apply(); // Update texture on sprite.
    61.  
    62. }
    I have already run the profiler and confirmed that 95% of the time the code is in the UpdateCellMatrix() function. I assume the texture update code is almost as fast as it can be made. I mean I can probably reduce those two loops to one, but I'm guessing the bottleneck there is updating the texture on the card not the speed of that loop.

    I should mention that I am running this within the editor. I do not know if running within the editor the code will execute slower.

    I also do not know if there is some sort of debug mode being enabled somewhere causing code execution to slow down. I am new to Unity.

    I am however not new to programming, just C#, and I know using 2D arrays is bad for performance and having a bunch of modulos in there is also bad. I was just trying to get this up and running as a proof of concept that is easy to understand and could be easily modified before I went crazy with optimizations.

    Still, even without optimizations this should not run this slow. It looks like its running at like 4fps. And a friend has run the same simulation on a a crappy old linux box in matlab of all things, and he's getting 200fps.

    So what's going on here? Is C# interpreted in Unity? Is there some debugger enabled that's slowing things down and which enables that profiler to work? (It's slow whether or not I have the profiler window open.) If so, how do I disable that? Or is the code always slow within the editor? I'm going to build the project and check its speed next, but I have my doubts that is going to help.

    What I really want to know is:

    Is there any way I can speed this up beyond simply optimizing my code? Is something other than my crappy algorithm slowing this way down?

    ADDENDUM:

    I asked about this on Reddit and I got a bunch of irrelevant responses which missed the point so I want to clarify some things:

    1. I am not looking to improve the frame rate. I am looking to increase the speed of the simulation.

    Slowing down the simulation to boost the frame rate misses the point. And co-routines will not help here.

    (Well I mean, maybe if they run on a separate core they might? The code's still super slow though. I don't know much about how co-routines work.)

    2. I am aware the code is unoptimized. I am not looking for suggestions on how to move some of the calculations out of my loop.

    I am looking for an explanation for why similar unoptimized code runs 50x faster in Matlab on a 10-15 year old Linux box.

    The questions I need answered are:

    1. Is C# in Unity in the general vicinity of being as fast as compiled C++? Or is it interpreted at runtime like Javascript in a browser?

    2. Is there some debugger in Unity that slows things down that I can disable?

    3. Will my code run much slower when I am running it in the editor versus building it as a final project?
     
    XCO likes this.
  2. Raccoonteur

    Raccoonteur

    Joined:
    Jun 4, 2017
    Posts:
    23
    So I just found out that if you build a release version the code runs way faster... They should really warn you about that!
     
  3. MaxGuernseyIII

    MaxGuernseyIII

    Joined:
    Aug 23, 2015
    Posts:
    315
    At least you're starting with a real performance problem. A lot of people want help with their imagined performance problems. :)

    You present 1 as a dichotomy, which it may be for you. Generally speaking, C# compiles to .NET or .NET-like output. On Unity, I think it's Mono...maybe a custom flavor of that? Those intermediate languages are, as I'm sure you already know, compiled just in time.

    So, for long-running algorithms (which I would expect a simulation of the game of life to be), the instructions end up being about as fast.

    One thing that differs between a managed language and an un-managed language like C++, however, is all the stuff you don't see. With C++, everything is traceable, if not explicit. Want something on the heap? Make it and, if you want it ever to leave the heap, you've got to make it go away, too.

    That's not the case with managed languages. .NET, specifically, does a bunch of weird stuff with memory. The address of an object in memory can (at least theoretically) move during its lifetime. I find this to be a mind-bending concept and don't understand their reasons (mostly because I haven't looked into them) but there it is. I don't know if it's that way with mono.

    I can't fathom what about your algorithm is taking so long. I'm skeptical that we're actually looking at the true source of the problem. I don't much trust the Unity profiler, which compounds my skepticism.

    It looks fine to me. Have you tried something like running a couple hundred generations in a single frame? I don't mean that as a suggested solution, just as a diagnostic step. If running a hundred generations (without rendering) in a single frame drops the frame rate by an approximate factor of 100, you can narrow down the problem...make absolutely certain that it's in UpdateCellMatrix. If not, then you can try re-rendering 100 times in a frame and see if that's really the problem.

    You could also try moving this to Update instead of FixedUpdate...again, as a diagnostic step, rather than as a solution. If the problem is that FixedUpdate is running a lower number of frames per second than is possible, we can come up with a solution.
     
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    No C# is not as fast as C++. And this is regardless of Unity (technically unity speeds up C# in some instances, I'll get to that).

    C# is a JIT compiled language, like Java. C# is compiled into CIL (sort of like java bytecode). There is a runtime, .net runtime, or in the case of Unity the mono runtime... where at runtime the CIL is compiled into machine code on the fly.

    Optimizations to the runtimes have made them slightly comparable to C++ compiled code, BUT it's still technically slower and Unity uses a much older runtime that lacks many optimizations.

    With that said, when you build and target a platform using IL2CPP, this converts the C# to C++ and then builds natively to that device and will run faster.

    Yes, there is a debugger in the editor.

    Yes

    ...


    As for why your code may be running at such a low framerate... no idea as of yet. I have not reviewed the code.

    If you could supply the example project in full so that I could easily run it, I would take a look. But I'm not going to rebuild it as is from your code snippet as I am on my laptop out of state and don't want to.
     
  5. McDev02

    McDev02

    Joined:
    Nov 22, 2010
    Posts:
    664
    Is this the exact same code? There must be something else, maybe matlab has some special system for these kind of simulations?

    Also I wonder what is the number of width and height? do we talk about hundreds or millions of cells?

    Well I am curious, maybe I give UpdateCellMatrix() a try on my own later at home :)
     
  6. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    Two things:

    1) Uploading a new, modified texture from the CPU to the GPU (texture.Apply()) is painfully slow, especially on mobile devices. You need to come up with a different way of drawing the game board for peak performance.

    2) If your frame rate drops, FixedUpdate will run more often with less visible results, which is exponentially compounding your issue. You could be drawing and updating the game board 10 times without visually seeing any of the results.
     
    Stef_Morojna likes this.
  7. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Right, if you're interested only in the speed of your simulation, you should disable the texture update, at least as a test to see how much difference that makes. It could be quite a bit.

    How much faster? Did this completely solve your concern?
     
  8. Raccoonteur

    Raccoonteur

    Joined:
    Jun 4, 2017
    Posts:
    23
    It's not super fast, but its fast enough to do a 256x256 grid at what looks to be around 30fps and I'm now confident that the remaining slowness is most likely a result of my unoptimized code, the fact that I'm writing to a texture, and that I'm running the code in fixedupdate().

    So I'd say it's solved my concern. I know with some optimization I can get this to be at least 10x as fast and I should eventually be able to a 1024x1024 grid at a reasonable frame rate. On a PC at least. I'm concerned about what the performance will be like on a cellphone, but I'll cross that bridge when I get to it.
     
  9. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    It's a fun problem. I'm sure the community can think of lots of optimization ideas... in fact you might even consider trying the PixelSurface asset in my sig, which can neatly avoid updating parts of the texture that aren't changing (which tends to happen a lot in Life simulations once they settle down).

    So, please keep us posted as it evolves, and if you feel like it, don't be shy about asking for input!
     
  10. dadude123

    dadude123

    Joined:
    Feb 26, 2014
    Posts:
    789
    When you get around to doing a few modifications, try this:


    Code (CSharp):
    1. n = cellMatrix[i, (j + 1) % height]; // top
    2.             n += cellMatrix[(i + 1) % width, (j + 1) % height]; // top right
    3.             n += cellMatrix[(i + 1) % width, j % height]; // right
    4.             n += cellMatrix[(i + 1) % width, (height + j - 1) % height]; // bottom right
    5.             n += cellMatrix[i % width, (height + j - 1) % height]; // bottom
    6.             n += cellMatrix[(width + i - 1) % width, (height + j - 1) % height]; // bottom left
    7.             n += cellMatrix[(width + i - 1) % width, j % height]; // left
    8.             n += cellMatrix[(width + i - 1) % width, (j + 1) % height]; // top left

    First of all you should definitely save ((j+1) % height) into a local variable instead of calculating it again and again.
    Same with all other expressions. (i+1)%width ...
    Then you should use "jagged" arrays instead of "square", in case you don't know what that means: Its simply using int[][] instead of int[,]. There is a performance difference between the two.

    Maybe that also helps.
    And as you have discovered already, there is a large difference between debug and release builds.
    Most of that comes from the jit compiler though, not from the compiler flag. And how the jit compiler produces code is determined by the presence of a debugger.
     
    JoeStrout likes this.
  11. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I don't think we're actually supposed to be brainstorming yet. ;) But when we do, what the really high-end CA simulators do is divide the grid into regions, and keep track of which regions have any activity going on at all. Then you can entirely skip the regions where you know nothing is going to change.

    The bookkeeping gets a lot more complicated, but it's worth it for the massive speed-up you get in typical cases (though obviously it's slightly worse in the worst case).
     
  12. Raccoonteur

    Raccoonteur

    Joined:
    Jun 4, 2017
    Posts:
    23
    I'm not shy about asking for input, but I am a game programmer with over 20 years of experience on slow crappy PCs coding down to the metal, so I already knew a lot of the optimizations people were going to suggest and I was pretty sure the problem was something else but I'd just gotten it working before I went to bed and I asked in the morning before I finished exploring every avenue because I thought it might take a while to get answers. :)

    I'm glad to see the community is so helpful though!

    Still even with my experience there's a lot I don't know about Unity and its a big API so I'm sure I will miss some optimization opportunities as I learn it, and I do have one question I can think of off the top of my head...

    I was trying to use the raycasting functions to get the mouse cursor position within my texture on my sprite, but as of a few days ago they weren't working and I haven't had a chance to go back and look at it. I wanted to be able to click to change cells in my simulation.

    Do you know if raycasting even works with sprites? I know they're special in some ways in Unity, so for all I know it doesn't work and it's not telling me I'm doing something bad trying to make it work.

    Here's my code for that. Sorry about the mess, I was commenting everything out trying to get the texture drawing stuff to work.

    Code (CSharp):
    1. //FixedUpdate is called at a fixed interval and is independent of frame rate. Put physics code here.
    2.     void FixedUpdate()
    3.     {
    4.  
    5.         Vector3 pos = Input.mousePosition; // Get mouse position
    6.         //Debug.Log(pos);
    7.  
    8.         /*
    9.         RaycastHit hit; // Create a RaycastHit struct called hit.
    10.         //Camera _cam = Camera.mainCamera; // Get camera to use for raycasting
    11.         Camera _cam = Camera.main; // Get camera to use for raycasting
    12.         Ray ray = _cam.ScreenPointToRay(pos); // Define a ray to cast using mouse position on screen.
    13.         Physics.Raycast(_cam.transform.position, ray.direction, out hit, 10000.0f); // Cast a ray from the camera's position in the direction defined by the ray, and return the result in the hit struct.
    14.         Debug.DrawRay(ray.origin, ray.direction * 10, Color.yellow); // Draws a line on the screen that matches the ray cast for debugging.
    15.         */
    16.  
    17.         //Color c;
    18.  
    19.         /*
    20.         if (hit.collider) // If our ray hit something...
    21.         {
    22.             Debug.Log("hit!");
    23.  
    24.             Texture2D tex = (Texture2D)hit.collider.gameObject.GetComponent<Renderer>().material.mainTexture; // Get the texture of the object we hit.
    25.      
    26.             Vector2 pixelUV = hit.textureCoord; // Get texture coordinates of raycast hit.
    27.  
    28.             pixelUV.x *= tex.width; // Calculate XY texture coordinates from the UV coordinates returned by the raycast hit.
    29.             pixelUV.y *= tex.height;
    30.  
    31.             tex.SetPixel((int)pixelUV.x, (int)pixelUV.y, Color.black); // Faster to use SetPixel32. Better yet use SetPixels32.
    32.  
    33.             tex.Apply(); // This applies the changes we made to the texture in RAM by copying them to texture memory.
    34.  
    35.             //c = tex.GetPixelBilinear(hit.textureCoord2.x, hit.textureCoord2.y); // Get interpolated color from texture using U,V coordinates.
    36.  
    37.         }
    38.         */
    39.  
    40.         // *** OLD ***
    41.         //Texture2D tex = (Texture2D)GetComponent<Renderer>().material.mainTexture;
    42.         //Texture2D tex = GetComponent<SpriteRenderer>().sprite.texture;
    43.         //Debug.Log(Random.Range(0, tex.width - 1));
    44.         //tex.SetPixel(Random.Range(0, tex.width-1), Random.Range(0, tex.height - 1), Color.black);
    45.         //tex.Apply();
    46.  
    47.         UpdateCellMatrix(); // Very slow, but could be optimized.
    48.         DrawCellMatrix(); // Reasonably fast on its own.
    49.  
    50.         // Code to get texture coordinates where mouse clicked on sprite:
    51.  
    52.         /*
    53.         SpriteRenderer renderer = hit.collider.GetComponentInChildren<SpriteRenderer>();
    54.         Texture2D tex = renderer.sprite.texture;
    55.  
    56.         //Get hit position (placeholder)
    57.         Vector2 pixelUV = hit.textureCoord;
    58.         pixelUV.x *= tex.width;
    59.         pixelUV.y *= tex.height;
    60.         */
    61.  
    62.         // Instantiate a copy of the texture so when we write to it we don't modify the texture on disk.
    63.         // This may not be necessary if we just create the texture from scratch.
    64.  
    65.         //Texture2D newTex = new Texture2D (tex.width, tex.height, TextureFormat.ARGB32, false);
    66.         //newTex.SetPixels32(tex.GetPixels32());
    67.  
    68.         // Texture2D newTex = (Texture2D)GameObject.Instantiate(tex); // Faster
    69.  
    70.         // Should I be doing this every update? I don't think so. It will overwrite my last change.
    71.  
    72.         //newTex.SetPixel((int) pixelUV.x, (int) pixelUV.y, Color.black); // Use SetPixel32. Better yet use SetPixels32.
    73.  
    74.         //newTex.Apply(); // This applies the changes we made to the texture in RAM by copying them to texture memory.
    75.  
    76.  
    77.         // renderer.sprite = Sprite.Create(newTex, renderer.sprite.rect, new Vector2(0.5f, 0.5f)); // Not sure what this is for aside from displaying the new texture.
    78.  
    79.  
    80.  
    81.     }
    82.  
    83. }
    Oh and one more thing... Even though I believe I have set my camera size correctly to scale the texture to fit the screen, and the texture is not scaled down, and I have looked at it with magnification in the editor to be sure... my pixels aren't coming out as black and white. They're shades of gray. Almost as if the texture is displaying the wrong mip level. It could just be my crappy graphics card though. I really need to upgrade it. It's like from 2010.

    The reason I suspect it is because when I did the ball roll demo, the shadowed areas of the ball were splotchy. Like, reddish and bluish splotches. I have to assume it's some incompatibility with my graphics driver or the shaders Unity is using. I don't want to upgrade my graphics card just yet either because I plan to get a VR setup eventually so I don't want to waste money on a high end card when a better one is probably going to come out before I buy the headset.
     
    XCO likes this.
  13. dadude123

    dadude123

    Joined:
    Feb 26, 2014
    Posts:
    789
    That's a good idea. Many simulators (I mean even the ones that aren't closely related to cell-based things) do this in one way or another.

    The PhysX engine puts objects to "sleep". Which isn't quite the same as skipping a region, but its a similar approach.
     
    Stef_Morojna likes this.
  14. dadude123

    dadude123

    Joined:
    Feb 26, 2014
    Posts:
    789
    Maybe you removed the colliders on accident?
    I think you need those unless you're working with a Canvas/UI (as that does thing differently)
     
  15. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    As long as C# relies on an interpreter while C++ compiles to native code, C# will never be as fast as C++. Unless you use IL2CPP, in which case, we're not really talking about C# anymore.

    Having said that, you pretty much need to do complex operations for the performance difference between C# and C++ to really matter these days. You can get pretty fast in C# using unsafe code (just be sure you know what you're doing).

    I've been able to write bitmap analyzers in C# to scan the pixels for blown highlights and still keep the app running in triple-digit FPS. Native code was still needed for complex image operations such as hough line detection, converting images to 3D meshes, etc.

    Also keep in mind that there may be a slight overhead in going from managed to native, and back again. You need to be sure that whatever performance gains you make using native code won't be cancelled out by that overhead.
     
    Last edited: Oct 25, 2017
  16. MaxGuernseyIII

    MaxGuernseyIII

    Joined:
    Aug 23, 2015
    Posts:
    315
    Are you saying that Unity doesn't do the basic just-in-time compilation that .NET and vanilla Mono both do?
     
  17. dadude123

    dadude123

    Joined:
    Feb 26, 2014
    Posts:
    789

    There's no interpreter, that's complete nonsense.

    C# gets compiled to CIL, which gets jit-ed at runtime, in the end both C# and C++ create native code.
    And "never be as fast as c++" is debatable. Sure there are some more optimizations that could be done in the .NET jit compiler, but the performance is definitely comparable.

    I'm not questioning the usage of C++ there, but note that C# also has unsafe pointers etc...
    If you really wanted to, you could do the same low-level things in C#.
     
  18. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    Actually, that's a question I'm not entirely sure about. I would think (hope!) it does JIT the same way, but since it's an old (and hacked) version of Mono, I don't think I could give a solid answer to that without digging into it further.

    However, there was a time when Apple forbade interpreters (which included JIT interpreters) for iOS platforms, so code had to be AOT compiled for that platform. I'm not sure if that's still the case today, though. (And before anyone asks, no this does not mean it's the fastest because it's AOT compiled, as that has its own set of issues and must target the lowest common denominator in the iOS ecosystem).

    Technically speaking, with the JIT compiler, there is overhead to do a cache lookup vs compiling never-before-executed methods (or it might just re-compile if it thinks it's faster), but it's so laughably minimal it's not really worth thinking about, much less making you decide to turn your whole project into C++. Don't even try to beat the JIT compiler. You won't be able to.
     
  19. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    See previous post. There's technically speaking, and there's realistically speaking. I was speaking in terms of technically speaking.

    But realistically speaking? It's not worth it.

    EDIT: It also seems you took issue with my usage of the word "interpreter", which is fair enough. I was thinking of the JIT compiler logic that determines whether code needs to be compiled, re-compiled, or retrieved from the cache. I started thinking of that as an interpreter, which is where I'm coming from.

    I also addressed that:

     
    Last edited: Oct 25, 2017
    dadude123 likes this.
  20. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    As @dadude123 points out, raycasting works with colliders. So you'd need to have a collider on your sprite.

    An alternative, when doing neat 2D stuff like this, is to just take the mouse position and do the math to calculate what cell it would be over. As long as you're using an orthographic camera, and you've been precise about how you position the sprite on screen, this will work fine. (And if you haven't, well, that's probably something you'll want to fix sooner or later anyway.)

    Possible. You shouldn't have any mips defined on this texture, though.

    More likely it's a shader effect. Make sure you're using the Sprite shader, and that the sprite color is set to pure white. Most other shaders apply lighting, which you don't want here. (In fact, take all lights out of your scene — that's a pretty sure way to make sure you're not using a shader affected by lighting.)
     
  21. Raccoonteur

    Raccoonteur

    Joined:
    Jun 4, 2017
    Posts:
    23
    I don't have a collider. Which sort of collider should I use? Sprites are 2D but the ray is in 3D space. A 3D mesh collider perhaps?

    Well, the end game plan is to allow the user to zoom in on this thing and the pixels will be replaced with sprites. So I can't just assume the thing is being rendered at a particular size. I may not even end up using a sprite for this. I haven't worked out all the details.

    But I would like to learn how to do raycasting properly in Unity. I won't learn as much just doing it with math. :)

    I'm not creating it with mipmaps:

    Code (CSharp):
    1.     // Initialize:
    2.     void Start()
    3.     {
    4.  
    5.         // Create a new texture for our sprite.
    6.         tex = new Texture2D(width, height, TextureFormat.RGBA32, false); // Create new texture in default format with mipmaps.
    7.  
    8.         //GetComponent<Renderer>().material.mainTexture = tex; // Assign new texture to the object.
    9.         //GetComponent<SpriteRenderer>().sprite.texture = tex;  // Assign new texture to the object.
    10.         //Neither of the above work. The first seems to doe nothing, and the second complains texture is read only.
    11.  
    12.         // Create a new sprite with our texture.
    13.         SpriteRenderer sr = GetComponent<SpriteRenderer>(); // Get the sprite renderer attached to this object.
    14.         sr.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f)); // Replace the sprite with a new sprite with our new texture. Use default 100 pixels per unit.
    15.  
    16.         // ???
    17.         tex = GetComponent<SpriteRenderer>().sprite.texture;
    18.  
    19.         cellMatrix = new int[width, height];
    20.         newMatrix = new int[width, height];
    21.         newColors = new Color32[width * height]; // Can't use a 2D array for this.
    22.  
    23.         RandomizeCellMatrix();
    24.  
    25.     }
    There are no lights in the scene. The shader and material are "Sprites-Default". The sprite color is pure white.

    This is what I am seeing with a 256x256 grid and texture, with 5x zoom:




    If I instead change the camera size from 5.12 to 1.0 so I can turn off zoom, I instead see a blurry life simulation, as if bi-linear filtering is on, which it probably is, but I haven't figured out yet how to turn it off on a texture I create at runtime.
     
  22. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    Unity does indeed use C# JIT compilation on platforms that support it. I'm pretty sure, as I've run into bugs where Unity were trying to JIT-compile code on non-JIT platforms!

    @scswift
    Did you remember to turn off the profiler?

    I'm asking because if I run your code on a 256x256 game in the editor, I'm getting ~100 fps. If I turn on deep profiling, it hits ~7 fps. So be sure to close the profiler window. If you have an old version of Unity, there used to be a bug where profiling kept running after you closed the window, so if that's the case, manually toggle off the Record checkbox in the profiler.
    It might also be beacuse I had to guess my way to what your texture was. I used a RawImage to show the image in a UI. You seem to be using a SpriteRenderer. There might be some overhead there, I have no idea.


    On how to do this faster:
    Running at 512x512, I'm getting ~25fps with your code, so a frame time of about 35ms. In that calculation, UpdateCellMatrix takes 15ms and DrawCellMatrix takes 20ms.

    So the big cost is definitely setting/applying the pixels on the texture. You might get around that by setting up things differently - either by doing this in a shader somehow, or by using the Graphics or GL APIs.

    I tried to implement your thing with Graphics.DrawMeshInstanced, and a 512x512 game jumped from ~25fps to... ~28fps. I'd love to get hold of a better profiler than Unity's to figure out what's being slow - if it's the pure game of life code, or if the code starts running into tons of cache misses. Here's the code if you're interested:

    Code (csharp):
    1.  
    2. using System;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.Profiling;
    6. using Random = UnityEngine.Random;
    7. #if UNITY_EDITOR
    8. using UnityEditor;
    9. #endif
    10.  
    11. public class GameOfLife2 : MonoBehaviour
    12. {
    13.     public const int size = 512;
    14.     private int[] cellMatrix = new int[size * size];
    15.     private int[] newMatrix = new int[size * size];
    16.  
    17.     private BatchArray liveMatrices;
    18.     private BatchArray deadMatrices;
    19.  
    20.     public Material liveMaterial, deadMaterial;
    21.     public Mesh meshToDraw;
    22.     private int liveCount;
    23.     private int deadCount;
    24.  
    25.     private void Start()
    26.     {
    27.         var maxCellCount = size * size;
    28.         liveMatrices = new BatchArray(maxCellCount);
    29.         deadMatrices = new BatchArray(maxCellCount);
    30.  
    31.         for (int x = 0; x < size; x++)
    32.         {
    33.             for (int y = 0; y < size; y++)
    34.             {
    35.                 if (Random.value < .3f)
    36.                     cellMatrix[x * y] = 1;
    37.             }
    38.         }
    39.         DrawCellMatrix();
    40.     }
    41.  
    42.     void Update()
    43.     {
    44.         Profiler.BeginSample("Update matrix");
    45.         UpdateCellMatrix();
    46.         Profiler.EndSample();
    47.  
    48.         Profiler.BeginSample("Draw matrix");
    49.         DrawCellMatrix();
    50.         Profiler.EndSample();
    51.     }
    52.  
    53.     private const string gameOfLifeCaluclation = "Game Of Life Caluclation";
    54.     private const string matrixFun = "Matrix Fun!";
    55.  
    56.     // Compute the next life step:
    57.     void UpdateCellMatrix()
    58.     {
    59.  
    60.         int liveIndex = 0;
    61.         int deadIndex = 0;
    62.         int center = size / 2;
    63.  
    64.         for (int x = 0; x < size; x++)
    65.         {
    66.             for (int y = 0; y < size; y++)
    67.             {
    68. //                Profiler.BeginSample(gameOfLifeCaluclation);
    69.                 // Count living neighbors. Matrix wraps at borders to avoid a bunch of conditional jumps.
    70.                 var jIndex = (y + 1) % size;
    71.                 var jIndex2 = (size + y - 1) % size;
    72.                 var iIndex = (x + 1) % size;
    73.                 var iIndex2 = (size + x - 1) % size;
    74.  
    75.                 var n = cellMatrix[x + jIndex * size]; // Number of adjacent cells alive.
    76.                 n += cellMatrix[iIndex + jIndex * size]; // top right
    77.                 n += cellMatrix[iIndex + y % size * size]; // right
    78.                 n += cellMatrix[iIndex + jIndex2 * size]; // bottom right
    79.                 n += cellMatrix[x % size + jIndex2 * size]; // bottom
    80.                 n += cellMatrix[iIndex2 + jIndex2 * size]; // bottom left
    81.                 n += cellMatrix[iIndex2 + y % size * size]; // left
    82.                 n += cellMatrix[iIndex2 + jIndex * size]; // top left
    83.  
    84.                 var state = cellMatrix[x + y * size];
    85.  
    86.                 if (state == 1) // If cell is alive...
    87.                 {
    88.                     if ((n < 2) || (n > 3)) { state = 0; } // If cell is alive and has less than 2 or more than 3 alive neighbors, kill it.
    89.                 }
    90.                 else // If cell is dead...
    91.                 {
    92.                     if (n == 3) { state = 1; } // If cell is dead and has exactly 3 living neighbors, kill it.
    93.                 }
    94.  
    95.                 newMatrix[x + y * size] = state; // Record new cell state.
    96.  
    97. //                Profiler.EndSample();
    98. //                Profiler.BeginSample(matrixFun);
    99.  
    100.                 if (state == 1)
    101.                 {
    102.                     liveIndex++;
    103.                     var current = liveMatrices[liveIndex];
    104.                     current.m03 = x - center;
    105.                     current.m13 = y - center;
    106.                     liveMatrices[liveIndex] = current;
    107.                 }
    108.                 else
    109.                 {
    110.                     deadIndex++;
    111.                     var current = liveMatrices[liveIndex];
    112.                     current.m03 = x - center;
    113.                     current.m13 = y - center;
    114.                     deadMatrices[deadIndex] = current;
    115.                 }
    116.  
    117. //                Profiler.EndSample();
    118.             }
    119.         }
    120.  
    121.         liveCount = liveIndex;
    122.         deadCount = deadIndex;
    123.  
    124.         var swapMatrix = cellMatrix;
    125.         cellMatrix = newMatrix; // Swap array pointers.
    126.         newMatrix = swapMatrix;
    127.  
    128.     }
    129.  
    130.     // Draws the cell matrix to the texture.
    131.     void DrawCellMatrix()
    132.     {
    133.         liveMatrices.Draw(meshToDraw, liveMaterial, liveCount);
    134.         deadMatrices.Draw(meshToDraw, deadMaterial, deadCount);
    135.     }
    136.  
    137.     public class BatchArray
    138.     {
    139.         private Matrix4x4[][] batches;
    140.         private int maxIndex;
    141.  
    142.         public BatchArray(int size)
    143.         {
    144.             var requiredBatches = size / 1023;
    145.             batches = new Matrix4x4[requiredBatches][];
    146.  
    147.             maxIndex = size - 1;
    148.             for (int i = 0; i < requiredBatches; i++)
    149.             {
    150.                 batches[i] = new Matrix4x4[1023];
    151.                 for (int j = 0; j < 1023; j++)
    152.                 {
    153.                     batches[i][j] = Matrix4x4.identity;
    154.                 }
    155.             }
    156.         }
    157.  
    158.         public Matrix4x4 this[int index]
    159.         {
    160.             get
    161.             {
    162.                 if (index < 0 || index > maxIndex)
    163.                     throw new ArgumentOutOfRangeException();
    164.                 int batch = 0;
    165.                 while (index >= 1023)
    166.                 {
    167.                     batch++;
    168.                     index -= 1023;
    169.                 }
    170.                 return batches[batch][index];
    171.             }
    172.             set
    173.             {
    174.                 if (index < 0 || index > maxIndex)
    175.                     throw new ArgumentOutOfRangeException();
    176.                 int batch = 0;
    177.                 while (index >= 1023)
    178.                 {
    179.                     batch++;
    180.                     index -= 1023;
    181.                 }
    182.                 batches[batch][index] = value;
    183.             }
    184.         }
    185.  
    186.         public void Draw(Mesh mesh, Material material, int countToDraw)
    187.         {
    188.             int currentBatch = 0;
    189.             int numLeft = countToDraw;
    190.             while (numLeft > 1023)
    191.             {
    192.                 var batch = batches[currentBatch++];
    193.                 numLeft -= 1023;
    194.  
    195.                 Graphics.DrawMeshInstanced(mesh, 0, material, batch);
    196.             }
    197.  
    198.             Graphics.DrawMeshInstanced(mesh, 0, material, batches[currentBatch], numLeft);
    199.         }
    200.     }
    201. }
     
  23. Raccoonteur

    Raccoonteur

    Joined:
    Jun 4, 2017
    Posts:
    23
    Well I never had the profiler on in the first place. At least not until I went looking for the problem.

    But I just tried turning it off now and I noticed something... but not something related to the profiler. I noticed that my simulation seemed to speed up the longer it ran in the editor.

    Tell me... did you run the code with UpdateCellMatrix() and DrawCellMatrix() in Update() or FixedUpdate()?

    Because if you put them in FixedUpdate, you should be seeing what I'm seeing, which is the simulation appearing to run really slowly.

    But there's a new twist now, because after I noticed the simulation speeding up I decided to try what someone had suggested above which is putting the code to update the simulation in Update() which doesn't make a whole lot of sense to me, but maybe FixedUpdate is just being called too often. I don't know how often it's called. Is it 60fps?

    Anyway as soon as I made that change, the simulation is now running very fast in the editor. It seems like whoever said that if I ran it in FixedUpdate and it was running too slow it would compound the problem may have been right.

    I think I understand how FixedUpdate works, being called at fixed time intervals with Update rendering the frames as fast as it can and generating in-between frames if needed... So I thought putting my code in FixedUpdate would be best because of course I want my simulation to run at fixed time steps... But what if my code is just slow enough that it's taking slightly longer than each FixedUpdate is supposed to take? Then all hell breaks loose, right?

    And the fact that I noticed the simulation speeding up after a bit when I had the code in FixedUpdate could be chalked up to maybe some memory being allocated or something that causes those first few updates to be even slower... Which then makes the simulation slow to start up. OR, it is hard to tell, but maybe it is running dozens of simulation cycles at the start that I never even get to see, until things settle down and it catches up again, but it's still slow, so it still looks choppy even after it speeds up.

    Whatever is happening, putting those update functions in Update() I find that I can build my application or run it in the editor with a 1024x1024 grid and it runs slow to be sure... But it runs only as slow as the 256x256 grid was running when I had the code in FixedUpdate(). So that's a huge performance improvement.

    I wonder then, if I did optimize the life code and got it to the point where it was just fast enough, if updating in FixedUpdate() would then run at full speed as it should? I suppose I could also change the speed at which FixedUpdate() runs, I saw that option somewhere today, but I would rather not mess with that if I don't have to.

    I wasn't aware there was another way. But yes, I am using a SpriteRenderer and texture. I don't know what a RawImage is but I guess I'll have to research that.


    And that's what I would have expected if things were running normally, but they clearly weren't which is why I haven't been focusing on improving the rendering speed for the texture. Not that I knew of any way to significantly speed that up aside from someone's suggestion to avoid missed branches by using an array to store the colors and index into that.

    DrawMeshInstanced? I guess that's another thing I need to research. :)
     
  24. Raccoonteur

    Raccoonteur

    Joined:
    Jun 4, 2017
    Posts:
    23
    And looking at your hidden code I see that you did indeed you the update functions in Update() instead of FixedUpdate() which probably explains why you are getting a good framerate!

    Try putting them in FixedUpdate() and see if it slows way down!
     
  25. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Mesh colliders are always the last resort. Use a BoxCollider instead.

    :eek: Whatever for?

    A sprite is a reasonable way to do it. A quad would be another. There is no avoiding pushing the texture data to the video card on each frame (except by breaking it into chunks and pushing only the changed data, as discussed before).

    True enough.

    Then, unless there's something else going on that I'm not thinking of, you ought to get the exact colors that are in your texture.

    I'm not sure I trust Unity's game view zoom feature to not do some sort of filtering as it zooms. Better to take a screen shot and zoom in with a trusted image editor (or use a screen-magnification utility, or similar).

    I don't think it's the texture; I think it's just that you haven't arranged everything to get pixel-perfect rendering. This is a somewhat deep topic, but mostly it amounts to doing the math and very carefully making sure your orthographic camera size and sprite scale all work together so that 1 texel in the texture works out to exactly 1 (or some integer multiple thereof) pixel on the screen.
     
  26. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    But that's what FixedUpdate is supposed to do. It's supposed to run exactly (by default) 50 frames per second.

    If that's not what you want, then Don't Do That. :)
     
  27. Raccoonteur

    Raccoonteur

    Joined:
    Jun 4, 2017
    Posts:
    23
    Yes, it's supposed to... But if you try it, you're not going to see a life simulation running at 50fps. You will see one that appears to be animating at like 4fps.
     
  28. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Ah, well FixedUpdate will do interesting things if you tie it up so much that it can't achieve the fps you've told it to maintain. It'll starve the regular Update loop, for example. If that's still not enough, I'm not sure what it does... but I imagine it involves panicking, running around in circles, and finally hiding in a corner and whimpering.

    All that said, it sounds like the reason it was tying things up so badly was because you were running it under the debugger, so 'nuff said about that, I guess.
     
  29. Raccoonteur

    Raccoonteur

    Joined:
    Jun 4, 2017
    Posts:
    23
    Do you mean the profiler? I wasn't running under the profiler. I was just running it in the editor. And it still runs terribly if I have the functions in FixedUpdate() while running it in the editor.

    Doing a build, it runs less terribly with the functions in FixedUpdate().

    But with the functions in Update() it runs well, in the editor, or in a build.

    So the next thing to test is if I optimize the code some, or tweak the fixed update rate, will it run properly with the functions in FixedUpdate().
     
  30. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    Why do you want to put it in FixedUpdate? FixedUpdate is for things you want to run in sync with the physics engine. There isn't really any reason to put anything else in there.
     
  31. Raccoonteur

    Raccoonteur

    Joined:
    Jun 4, 2017
    Posts:
    23
    Well, FixedUpdate is called at a fixed timestep. Update is not. If I update in FixedUpdate then I know my simulation will run at a specific rate regardless of the framerate. If I update the simulation in Update, then the simulation will run faster or slower depending on the framerate, which could vary wildly. Speaking of which, is the framerate in Unity capped?
     
  32. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Well, no, you know Unity will try to run at the specified rate. It may not be able to, though.

    That's true, though you can always throttle it yourself just by checking the time.

    Generally not, on desktop anyway, but you can fiddle with Application.targetFrameRate.
     
  33. Raccoonteur

    Raccoonteur

    Joined:
    Jun 4, 2017
    Posts:
    23
    Sure, but I can't throttle it if I want my simulation to run at 60fps but the app is running at 30fps because it's on a cellphone. Also throttling the simulation in Update() and doing so in a manner that keeps the update rate consistent just feels like re-creating FixedUpdate() and what it's there for.

    Plus it seems like it would be a whole lot easier to split the calculations up across two FixedUpdates() or make use of one of those coroutines if it came to it than to try to make it work within Update() at framerates that may be lower than the desired simulation speed.
     
  34. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    But that's my point -- FixedUpdate can't give you more cycles than the machine has, either.

    Well, kinda. Except that, as we've seen, FixedUpdate rather freaks out when it can't achieve the rate you've requested. Your own code could handle this in whatever way you see fit.

    As you wish. (But note that coroutines run at the same rate as Update.)
     
  35. nat42

    nat42

    Joined:
    Jun 10, 2017
    Posts:
    353
    So with FixedUpdate()... I take it if you overshoot frame 1's time budget by 10% then next update you have to 2 updates instead of one to make up for it, only if the cost is fixed you now take twice as long overshooting that frame's time budget by 120%, so then the next update you have to do 3 times the work and you overshoot the frame budget by...

    Is that how it works?
     
    JoeStrout likes this.
  36. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    you cant compare C# with c++, Unity compiles your C# in to c++ runtime, compearing Unity games to a pure c++ game, you see no difference in framerate. Using FixedUpdate for this is bad practice, its only used with physics.

    Another thing you need to do is to turn off vsync so you can see higher framerate

    Example:
    Code (CSharp):
    1.     QualitySettings.vSyncCount = 0;
    2.         Application.targetFrameRate = 300;
     
    Last edited: Oct 26, 2017
  37. Raccoonteur

    Raccoonteur

    Joined:
    Jun 4, 2017
    Posts:
    23
    Yes, I understand that. So I need to optimize my code, or divide up the task to fix the problem, if I want to continue to run in FixedUpdate.

    Hm... I thought they were like a timer based thing that ran at specified intervals.

    http://devblog.aliasinggames.com/first-encounter-with-coroutines/

    I guess not. I'd only read about them the night before and I thought the WaitForSeconds(time) one was something that was executed every X seconds. But it just suspends its execution for X seconds? I mean I guess you could make it call itself again?

    I also found this:
    https://docs.unity3d.com/ScriptReference/MonoBehaviour.InvokeRepeating.html

    That would automatically run the function every X seconds. Though I have no idea how you stop it.

    And with that you still have the same basic issue as with FixedUpdate... If the stuff you're doing takes longer than the time between updates, all hell will break loose. But that's to be expected.

    Of course, the problem is, even if I optimize my code so it runs fast enough on a PC so all hell doesn't break loose, what about a cellphone?

    The right thing to do may be to allow the life simulation to run at whatever speed it likes, within some limiting factor. Throttling it, like you said, to prevent it from running too fast. But I didn't want it to kill the framerate either if it was running too slow, which is why I didn't want to put it in Update().

    So perhaps co-routines are the way to go here?

    Found some more useful info on coroutines here:
    https://stackoverflow.com/questions...ine-yield-return-pattern-really-work-in-unity

    Kinda sounds like you have to specify in the coroutine where it yields to the rest of the system... So it will take up as much time as it likes unless you give it yield points. And if you give it yield points... Then maybe it doesn't return to execute more until the next frame? That could be problematic. I guess I was hoping for something more like multi-threading where I don't have to worry about trying to divide the problem up into manageable chunks.
     
    Last edited: Oct 26, 2017
  38. katoun

    katoun

    Joined:
    Dec 26, 2012
    Posts:
    91
  39. Raccoonteur

    Raccoonteur

    Joined:
    Jun 4, 2017
    Posts:
    23
    Just wanted to revisit this after reading up on coroutines and how they work...

    So the thing I didn't understand is what Unity is doing behind the scenes. The last link I provided above talks about that. I still don't have a complete understanding of it, but it seems there's one main thread in Unity, and Update() and FixedUpdate() get called in it... I don't know how it manages them when things start to slow down, but it would seem that sometimes Update() has to run faster than FixedUpdate() and sometimes it has to run slower, because FixedUpdate() always has to run at 50fps if at all possible?

    Meanwhile coroutines are simply stuck in this same loop, and everything stops for them. So a coroutine and update() will run the same number of times per second, if you let them run as fast as possible.

    I'm still trying to wrap my head around how this works though when say, the framerate dips below 50fps, but FixedUpdate still needs to run at 50fps. Does FixedUpdate get called twice some frames sometimes? So it's not being updated every 1/50th of a second, but just 50 times a second, potentially stuttering on occasion? And when the framerate is faster than 50fps, sometimes FixedUpdate() doesn't execute in some frames, so two or three frames might happen between FixedUpdates()?

    I guess my confusion was I thought it was running every 1/50th of a second, possibly in a thread, but this makes more sense. I've seen this done before when I was working in Blitz3D. Though I tended to avoid the additional complexity and use DeltaTime to do my physics. Which admittedly were much less sophisticated than Unity's because I had to code them all myself. :)
     
  40. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    IL2CPP is only available for some platforms, e.g. for Standalone it's not.

    I wouldn't second that, especially not when no IL2CPP is available.
    When compiled to C++ using IL2CPP, there may not be much of noticeable difference. Once on a Unite event someone from UT said it's their aim to generate C++ code that's most-likely outperforming most of the code you'd ever write yourself in C++.


    They all run on the main thread in a specific order. Check out the flow chart which describes the order of Unity's event functions and coroutines.

    Yes, they are.
    They will run the same number of times per second if you return anything but a specialized YieldInstruction, most of the time it's 'null' - which is basically saying 'continue on the next frame'.

    The other YieldInstructions are just different in that they're being polled every frame in order to determine whether to continue execution or not.

    To be more exact, FixedUpdate does not run every 1/FixedUpdates seconds (default 1/50 = 0.02 seconds) but it simulates that by running x cycles using a fixedDeltaTime in order to catch up to the current frame time.
    A small yet important difference.

    So it can run 0 times between 2 frames, it could run once, or multiple times.
    That's also the reason why you might end up slowing down your application / messing up your performnce if you put expensive Update logic into FixedUpdate.
     
    Last edited: Oct 27, 2017
    Ryiah and JoeStrout like this.
  41. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    I'd like to mention that with the upcoming Entity/Component system and C# Job system coming to Unity 2018.1, you will be able to write extremely efficient multi-threaded code within Unity's framework, arguably in a better way than you could accomplish in C++.

    It was announced and demonstrated at Unite 2017 in Europe and Austin, and would be perfect for any kind of simulation logic. So perhaps look to the future for your ideal implementation.
     
    Suddoha, Ryiah and JoeStrout like this.
  42. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    Unity engine is mostly c++ so yea no real performance difference on most platforms compered to other engine. C# is js just logic scripting not code to render things or deal with the memory management. If your C# is impacting performance, then you must be doing something wrong.
     
  43. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Of course it's written in C++. I wasn't talking about the engine parts.

    However, the bold part is semi-nonsense.

    Logic can also be expensive, even if you optimize the hell out of it and do everything correctly.
    It's no secret one is somewhat limited to optmize in C# compared to C++, not to mention the cross-language calls. There's also the garbage collector, various runtime checks in most commonly-used types and much more stuff.

    Sure, basic operations and controls can be as fast as C++ - and that's what comparisons often rely on. Once it gets more complex, you'd simply take advantage of techniques available in C++, which speed up everything. But barely anyone's going to do that for yet another quick post.

    If you were to write the game completely in C++, it would definitely run faster - given that you know C++ well enough.
    And that's also why IL2CPP exists and is more and more improved.

    I'm not saying C# is slow, I do love C#. It's a fantastic language and it does perform surprisingly well if you put effort into it.
     
    Last edited: Oct 27, 2017
    nat42 likes this.
  44. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    Its the engine that produces the speed of the graphics not the C# scripts. None of my C# script interfere with the game speed. GC is pretty much a no issue.. Even c++ games can lagg due to poor data structure. I seen allot of c++ games performance laggy compared to a well design Unity game. So yes doing logic in c++ is no advantage. Its actuality a disadvantage. Again you cant directly compear c++ @ C# because C# is taken from c++ and developed as a framework for a managed system. You dont deal with the low level machine stuff. You can do allot of things wrong with c++ that can impact performance. When it comes to speed its more about how the render engine is optimized.
     
    Last edited: Oct 27, 2017
  45. nat42

    nat42

    Joined:
    Jun 10, 2017
    Posts:
    353
    That assumes that the "scripts" do trival computation, and you add the "of the graphics" clause which I feel misses the mark as the thread isn't much talking rendering but computation.

    The conclusion here seems wrong. We aren't comparing the potential to write inefficient c++ (sure you can write really bad c++ code that will preform poorly) or debating the merits of c# (it's a wonderful language)

    Huh? You just tried to compare them yourself and c# is it's own language.

    Anyway this thread urgh.
     
    Suddoha likes this.
  46. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    You don't need to tell me what's doing the actual rendering. I'm well aware of that.
    But MonoBehaviours naturally contribute to the frame-time, and they're written in C#. If you use complex logic and algorithms or even AI, it's most-likely slower as if it was written in well-optimized C++.

    Oh really...That statement though.

    First of all, C# sort of combines different languages and initially had more in common with Java than C++.

    Also, I said 'given that you know C++ well enough'. Of course you can write bad code in C++, just like you can write extremely inefficient code in C#.
    The rendering is an important part, but you obviously miss the fact that - even though it's important and needs to be as efficient as possible - it's still just one of many pieces of a huge and complex puzzle.
     
  47. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    OK its good that we are on the same page then Suddoha :) with c++ you can put out wrong pointers to memory blocks, in C# you can allocate wrongly and get gc overheads. Both things is bad for performance. What i am trying to say, since this thread is about fps/performance, is that all the FPS you get form the engine comes from pure c++ core (well done if i might say so) . Logic is another thing. Seeing all the great Unity games that comes out lalty i think pure c++ games have some real competition. C++ games can get real messy, take allot of memory and have a general low fps output.
     
  48. nat42

    nat42

    Joined:
    Jun 10, 2017
    Posts:
    353
    I am going to bite the bullet and try this myself, because I really am surprised that Conway's Game of Life CA would preform so poorly under Unity, and feel I must be missing something I would like to better understand
     
    Suddoha likes this.
  49. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    I have games with inventory, items, gear, weapons, monster AI, path system, data structure all made in c#. I have zero lagg or GC issue. I get a stable 100FPS all over the place, (100 cap) . Game might lagg abit on load of a slow harddrive, but other than that codes in memory is doing just fine where its at. Nettwork code is alot a thing that can impact performance, but all of this things is under the category of "lagg" and not game performance FPS. There is no C# scritps that produce graphics by them self or show a pixel on your screen.
     
    Last edited: Oct 27, 2017
  50. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    If you stress the engine by using bad allocation pratice then yes, even bad shader code than do that.