Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Unity Code Performance Questions

Discussion in 'General Discussion' started by happy1, Apr 25, 2015.

  1. happy1

    happy1

    Joined:
    Mar 11, 2015
    Posts:
    15
    I have a few random questions about Unity code performance.
    • I'm noticing that Unity 4.6 -> 5.0 script upgrades replace certain properties with GetComponent<>() calls. Is there still performance degradation when using GetComponent in Update loops?
    • Should I still avoid manipulating and creating strings in Update loops? Do string and StringBuilder objects still generate lots of garbage?
    • I also read that foreach loops and co-routines generate garbage. Should I avoid these in the Update loop, too?
    • I have methods that work with a lot of vectors. Are vectors allocated in the heap or call-stack?
    • I read that the core of Unity 3d is written in unmanaged C++. Isn't there performance degradation with all the PInvoke calls made from C#?
    Cheers!
     
  2. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Unity 4 used to use getcomponent equivalent behind the scenes. Those shortcuts you used like .renderer or whatever were never free. They were getcomponent too. You should cache them.

    As for your other questions, yes it's still best practise to do the common sense stuff. Nothing's changed except unity is constantly optimising. It doesn't mean we can be lazy just yet.
     
    happy1 and Ryiah like this.
  3. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    On the other hand preppy imitation is the root of all evil.

    Don't be dumb. But don't spend hours optimising code that doesn't make a difference to the player experience.

    Edit: pre optimisation is the root of all evil. I'd fix it, but the auto correct fail is pretty hilarious.
     
    Last edited: Apr 26, 2015
    angrypenguin likes this.
  4. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    The best thing is always use the profiler.

    --Eric
     
    happy1, Ryiah and Kiwasi like this.
  5. cl9-2

    cl9-2

    Joined:
    May 31, 2013
    Posts:
    417
    Yes. As someone mentioned, storing the result of GetComponent in a private variable is still a good practice.
    In my opinion, yes, if you're working with display timers, scores, etc that use high frame rates.
    In my opinion, yes for some genres like racing games. I prefer for-loops and timers where possible.
    Vectors are allocated in the method's call stack.
    According to MSDN:
     
    happy1 likes this.
  6. darkhog

    darkhog

    Joined:
    Dec 4, 2012
    Posts:
    2,218
    Only optimize if your performance really suffers. And I mean really. Like "only 12 fps on GTX 960" really.
     
    happy1 likes this.
  7. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    8,984
    "Premature Optimization", (or more accurately, becoming obsessed with) it can be a huge time suck.

    Optimization (and sometimes pre-optimization) is a do-as-you-go sort of thing. Best practices and such. It is much easier to write optimal code than to optimize after the fact. For example, if you learn a better way to write something that is more efficient, it may not be worth a refactor, but next time you do the better way from the start.
     
  8. happy1

    happy1

    Joined:
    Mar 11, 2015
    Posts:
    15
    Oh wow. So simply adding two vectors or even just retrieving a vector's value can have that much overhead?

    I'm doing mobile. I'm aiming for a consistent 60fps on 2D, even for older devices where apps are left with a measly 30-60mb of memory

    Thanks everybody
    Cheers!
     
  9. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    If you are doing a lot of vector addition in hot code, then in lining it can make a huge difference. This is one of the post optimisations that you do at the end of your project. It makes the code messy and horrible to maintain. But there are some projects that wouldn't be possible without it.

    Key point, at the end of your project. Not before.
     
    happy1 likes this.
  10. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,614
    Note that calls into Unity methods from script code does not use P/Invoke.
     
    happy1 likes this.
  11. happy1

    happy1

    Joined:
    Mar 11, 2015
    Posts:
    15
    Great to know!

    Is the Unity 3d core written in managed C++? What is happening behind the scenes when a C# script eventually calls the C++ part of the engine?
     
  12. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    Let's put that in context.. How many x86 instructions does a modern x86 processor do? I think you'll find it's something like 2-100 billion instructions per second.

    10 - 30 instructions? Who would care about that...

    Though, as superpig said P/Invoke is not used for script -> Unity API calls, so it's somewhat moot anyway.
     
    happy1 likes this.
  13. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,614
    There's no Managed C++ involved. We use internal calls.
     
    happy1 likes this.
  14. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,507
    That depends on the platform :). On Windows Store platforms we do use P/Invoke.
     
    happy1 likes this.
  15. cl9-2

    cl9-2

    Joined:
    May 31, 2013
    Posts:
    417
    Is this due to Windows Store platforms using .NET instead of Mono?
     
    happy1 likes this.
  16. cl9-2

    cl9-2

    Joined:
    May 31, 2013
    Posts:
    417
    Content optimization should also help with stringent memory requirements: texture compression, atlases (large enough to allow dynamic batching).
     
    happy1 likes this.
  17. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,507
    Yes. Consumers of .NET framework cannot register their own internal calls. If you look at .NETs source code on github, you'll see that their icalls is a static array of functions that never change at runtime.
     
    happy1 likes this.
  18. TheSniperFan

    TheSniperFan

    Joined:
    Jul 18, 2013
    Posts:
    712
    Here are some general performance tips:

    1. Don't believe, verify!
    What? Instead of blindly believing that your code runs fast, you should put it to the test. The profiler is your best friend when it comes to this.
    Why? Because we're humans and humans make errors. If you just look at the code, isolated from the actual environment it runs in, chances are that you overlook some factors that are important.
    Example? The way I go about it is by stress-testing every module I write. After I've written one - say an item component that makes it so that the player can pick up something - I create an empty test-scene, think about how many items there can exist in a level of my game and add considerably more (because better safe than sorry). Before I run the scene with the profiler attached, it is absolutely crucial that I think about my expectations first. How many CPU cycles should 800 items that are not being interacted with use? Then I test it.
    Believe me when I tell you that you're in for some surprises if you do it that way.

    2. Don't measure your performance in FPS:
    What? When game-developers measure performance, they don't look at the framerate, but the frametime. You never target 60 fps, you target 16 ms. You never target 30 fps, you target 33 ms.
    Why? Because the framerate averages the actual performance over the course of one second which makes it completely useless. One second is a very long time for your computer.
    Example? If your game produces 60 frames within 500 ms and then completely stops for the other 500 ms, it will be completely unplayable despite running at 60 fps.

    3. Consistent performance is absolutely crucial:
    What? It's better to have slightly worse, but consistent performance, than having your performance jump all over the place.
    Why? Think about the players who are close to the minimal system requirements. When their performance varies greatly, it varies between playable and unplayable, which easily renders the game unenjoyable.
    Example? There's few things more frustrating than enjoying a game for hours, before having to put it down due to a performance hit in a late chapter that makes it impossible to play any further. That stuff shouldn't happen. If the player can start, he should be able to finish.

    4. Optimize for the most common case, not the most generic one:
    What? The title says it all.
    Why? Because being fast in a case that barely even happens often doesn't matter.
    Example? A ladder script that you can attach to anything that you want the player to be able to climb up. What's the most common case of a ladder? I'll tell you what it isn't and that's the player actually climbing. So before making sure that your climbing code is efficient, you should make sure that the component is disabled when there's nobody climbing it in the first place. (Point 2 at the second list - the overhead involved in calling Update() functions is huge)

    5. Prevent last minute decision making:
    What? Last minute decision making means that you're doing calculations despite already knowing that you don't need them. switch and if/else statements are particularly problematic and so are Update() functions that start contain one huge if/else.
    Why? You're wasting CPU cycles for literally nothing. Use the information you've got to the fullest.
    Example? Calculating some movement vectors and discard them afterwards, instead of checking whether they should be calculated first. Obvious? Sure. There are far more elusive cases out there. Some of which have devastating performance implications.

    6. Don't pretend like your components exist in a vacuum, over-abstract or be afraid of coupling:
    What? When you write components for Unity, it's typically considered to be good practice to write your components in a way that you can drag them onto any object and they Just Work™. This can be a very bad thing to do in not just a few cases.
    Why? Because by virtue of over-abstraction, your model of the world can be completely detached from the reality in which the software actually runs. You're rarely dealing with "an item", "a ladder" or "an enemy". The reality is that you're dealing with "a set of items", "a set of ladders" or "a set of enemies". Write your classes accordingly and couple what belongs together.
    Example? You have written a "selector" that lets you pick up "items". The item's Update() function handles them being picked up and held in front of you among other things. Typically, when regarding "an item" as if it existed in a vacuum, you'd probably use something like a boolean variable that determines whether the item is being held or not. The selector would change it from the outside. This is terrible, terrible code. Instead, look at the actual reality of your game: A set of items where either one or none is held at a time. Suddenly it makes a lot more sense to write good code. Namely, ditching the boolean logic of the item class, making the Update() function hold the object directly, without any further checks and using the selector to enable/disable the desired object. This is a prime example of rules 4, 5 and 6 and creates a tremendous performance increase, because it reduces the runtime complexity of your items from O(n) to O(1).

    Here are some more Unity-specific performance tips I apply when writing my code for Unity:

    1. Zero background noise:
    What? What I refer to as "background noise" are heap-allocations that happen during each update-loop. Of course this also includes FixedUpdate() and LateUpdate().
    Why? Automatic memory management is very dangerous for real-time applications. You cannot control when the garbage collector kicks in and when it does, your application comes to a complete stop for a uncertain period of time. I have an Intel Xeon E3-1231 v3 which plays in a whole other league than what mobile developers have to work with. The GC still takes a few ms to complete.
    Example? You write a player script and run the profiler. If you're standing still, you should allocate exactly nothing. However, this is not enough because standing perfectly still is not the most common case. Usually, the player will move his character. This means that all the common operations (moving, rotating the camera, jumping, leaning, crouching and whatnot) are not allowed to allocate memory during each update-loop. If you need some resources on the heap, allocate them beforehand and reuse them.

    2. Disable unused scripts:
    What? Manage which scripts have their Update(), LateUpdate() and FixedUpdate() functions called at all. If it's not doing anything, it shouldn't use any CPU cycles.
    Why? Scalability in regards to the overhead of calling those functions. If you merely use a boolean variable to skip the actual logic of your update-loop altogether, you're underestimating the overhead involved in calling them. From what I've seen, the overhead of the Update() function being called seems to be orders of magnitude slower than comparing a boolean variable. I found this out during my stress-testing sessions.
    Example? So you wrote a script that you can drag on an GameObject and it makes the GameObject play a sound when falling on the floor. Let's assume that you have placed a lot of them. Do you really need to have the objects in that building on the far side of your level being updated, if the player isn't anywhere close to them? No, because the player wouldn't be able to hear them falling down anyway.

    3. Cache stuff:
    What? The components you use a lot should be cached. Other objects you work with, should be cached (if you already know them). You get the idea.
    Why? GetComponent<T>() and GameObject.Find() are very, very slow calls. Just use them once, instead of every frame.
    Example? You do your GetComponent<T>() calls in Awake() and store the results.


    It's possible that I forgot some, because I'm really tired.
     
    Last edited: Apr 29, 2015
    MPM, gl33mer, ZJP and 10 others like this.
  19. happy1

    happy1

    Joined:
    Mar 11, 2015
    Posts:
    15
    Brilliant!

    You must author a book. I've never seen this level of practical and professional advice on the Unity forums.
     
    gl33mer likes this.
  20. TheSniperFan

    TheSniperFan

    Joined:
    Jul 18, 2013
    Posts:
    712
    @happy1 Well, thanks but no; I am not authoring a book. :oops:
    But I do consider fixing scripting part of the Wiki page about performance which is quite....'lacking' to put it nicely. Share my findings for the benefit of the community.

    I am a CS student who tries to absorb as much knowledge about this as possible. This means that if someone with lots of experience speaks, I listen. HOWEVER, I have a strong distaste for those drones who think that simply repeating smart people makes them smart themselves. This leads to situations where I have 'unpopular opinions', so I try my best to back the stuff I say up to make them shut up before quoting someone, instead of thinking for themselves. :D

    The single best example in this context:
    People quote him as if he said "Screw optimization", but he didn't. He simply said that you shouldn't optimize too early. What is »too early«?
    In my opinion this is something you should decide on a case-by-case basis. If your client tells you that performance is crucial, you don't start your project with the 'write beautiful code, ignore performance' mindset. It's that simple.

    We're in the Unity forums here, so I assume that people program videogames. Videogames are soft real-time applications.
    There's two kinds of people who will have direct influence on your success: Players (obviously) and critics.
    Guess how much these people will care about how many design patterns you've used. (Hint: Not at all)
    Guess how much these people will care about how good your game performs. (Hint: A lot)
    Performance is not an option!
    If your game runs like Crysis, it better looks like Crysis. You cannot tell people to buy a stronger Playstation. It either runs or it doesn't, period.

    So when @darkhog says that one should only optimize after running into performance problems, I have to disagree given that we're talking about videogames here.
    I'd even go as far as to say that he'll waste more time by handling it this way. If your game runs at 12 fps on a reasonably powerful machine, it's unlikely that you're dealing with just one problem. You probably have tons of them, scattered throughout your entire project. Can you imagine how long it could take to fix this? It could involve completely scrapping months old code and redesign it from scratch.

    If you do it the way I do (stress-testing immediately after verifying correct functionality) you have the added bonus of working with the code while everything is still fresh. If you make a decision that leads to poorly readable code? Then so be it, just be sure to add a couple extra-comments.


    On a side-note:
    If you want a good good book, I can wholeheartedly recommend 'The pragmatic programmer'. It's not a book about performance (quite the opposite in fact), but it's still something every programmer should have read (imo).
    Quite a few performance considerations from my list were incorporated into my code after watching this video on 'Data Oriented Design'. It made me rethink a lot of my design decisions for the better. His example of how much the model in your head can differ from the reality (the one using linked lists) completely blew my mind. It just makes so much sense.

    It's long, but totally worth it.
     
    cl9-2 likes this.
  21. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    @TheSniperFan. Some very good well reasoned advice here. Most of it I agree with. I especially like your thoughts around optimising for when things are not in use.

    However I'm going to speak up in defence of late optimisation. And by late optimisation I don't mean being dumb. Obvious things that don't effect code readability should be second nature. Caching GetComponent results, avoiding Update and the like.

    But ultimately you get more bang for you buck optimising after you can see the bottle necks. Optimising entire systems will be the most effective. Then optimising algorithms within systems. Then optimising algorithms within each system. Then finally code level optimisations.

    Only hot code should ever be fully optimised. Very little point optimising a system that only gets used once in a game.

    And perhaps the biggest risk of pre-optimisation is wasting hours or days of time on a system that ultimately gets cut from the final build.
     
    Ryiah likes this.
  22. ShilohGames

    ShilohGames

    Joined:
    Mar 24, 2014
    Posts:
    2,985
    What I like to do is optimize all of the obvious stuff as I code. For example, stuff like caching the GetComponent results. I also like to periodically take several hours (or even a day) during the middle of a project and re-examine optimizations. I don't like to completely hold off on optimizations until the end, because sometimes I find useful performance gains as the result of refactoring code mid-project. Sometimes this is because the scope of the project changed, and the data layout is no longer optimal. By fixing that type of thing mid-project, it usually takes less time than if I waited until the end of the project to refactor. Then toward the end of a project, I will run more detailed performance testing.
     
  23. TheSniperFan

    TheSniperFan

    Joined:
    Jul 18, 2013
    Posts:
    712
    @BoredMormon :
    I am strongly against this way of handling things, because it often does not work. Not only when it comes to performance optimization; You can also see it when it comes to documentation and comments.
    Procrastination is the keyword here. If you keep pushing important things back, you eventually won't do them at all.

    Furthermore there is another huge flaw when basing your decision when and what to optimize on late performance bottlenecks: It's completely arbitrary.
    How do you determine what is and isn't acceptable performance? By examining how well it runs on your computer? That's not reliable in the slightest unless it runs really bad. If you're 50% done with your project and your current build runs at 60 fps on the target device. Does it run good? Or is it a performance nightmare waiting to blow up in your face during the next 50%?

    I don't think there is any game-developer in the world, who can really reason about a game's performance by looking at it as a whole. You have hundreds of thousands of variables that you would need to factor in. How are you supposed to do that? On a module-level this is so easy. You only have a couple of variables and can reason about them.
     
  24. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    All's well as long as you don't over do it with your lighting. I have a few lights in my scene and when I bumped up the light pixels setting in quality, my framerate dropped to 56 from like 200.
     
  25. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,516
    Or the optimisations can become prohibitively harder, more expensive, or less effective. An optimisation that's moderately difficult early on may be near impossible when a bunch of other stuff is built "on top" of it.

    It shouldn't be arbitrary. (To be clear, I'm agreeing with you here.) You should have performance targets and target test platforms. You should then use those things extensively during development to maintain performance as both a feature and a requirement of your software. If your team is large you should also have budgets so that different parts of the team aren't stepping on each other's toes - you can't all use all of the VRAM or system RAM and you can't all use 16ms of main thread time if the game is to run at 60fps.

    On the other hand you also don't want to be optimising stuff that doesn't matter. Spend that time elsewhere. That's another reason that budgets are helpful - even if you know you could make something better, they help you decide if you should.

    Also, don't just think about performance in terms of code alone. Think of what art and audio is present, what it's doing. Also think about the development pipeline - the more efficient that is the better you'll be able to make your game.
     
    zombiegorilla likes this.
  26. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,516
    Forward rendering, I assume?
     
  27. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    Nah, I just set the light pixel thing from 4 up to 32. I have no idea what I'm doing obviously, but I didn't touch any other settings. I just wanted my lights to stop turning off when I stopped looking at them :p

    Also when the killer robots entered the room, their eye lights were making other lights turn off. It was looking quite awkward. I also had to turn shadows on so light would stop bleeding through the walls. I *hate shadows and find them unnecessary in games, but it seems to be the quick fix for this :c

    I'll probably lower that setting until things look 'good enough', but wow, lighting is a monster.
     
  28. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,614
    This is good advice but the reasoning is wrong. It's entirely possible to consider the FPS over a period less than 1 second - this is why you'll look at FPS counters and see them update multiple times per second. Usually the FPS is just calculated every frame as (1 / frameTimeInSeconds) so it updates just as often as frame time does.

    The reason FPS is bad is because it's a deceptively non-linear reflection of the amount of work being done: a change from 15FPS to 10FPS is a much bigger deal than a change from 100FPS to 95FPS, even though it's a 5FPS drop in each case. If you consider the changes in terms of milliseconds-per-frame instead, it's much more obvious: 15FPS->10FPS is a change from 66.6ms->100ms (+33.3ms), while 100FPS->95FPS is a change from 10ms->10.53ms (+0.53ms). And crucially, the same work will take the same time as your project scales up - i.e. if you added something that takes 0.53ms now, it'll still take 0.53ms when you've added a load more things to your project, so by thinking in terms of frame times and budgets (16.6ms == 60FPS) you can reason much more easily about how your performance is stacking up throughout development.
     
    angrypenguin, Kiwasi and TheSniperFan like this.
  29. TheSniperFan

    TheSniperFan

    Joined:
    Jul 18, 2013
    Posts:
    712
  30. ZJP

    ZJP

    Joined:
    Jan 22, 2010
    Posts:
    2,649
    This. My rule.