Interesting results! Whenever I teach optimization, I always begin with "Measure, don't guess". Measure for your platform. Measure in real world situations. Start with readable code, measure and then fix to meet a frame budget. Everything else is premature optimisation because you can't guess what optimisations the compiler will do.
@Tarodev2 жыл бұрын
I like this and fully agree.
@danebramage4522 жыл бұрын
There's a saying... you get what you measure.
@saniel27482 жыл бұрын
You can pretty much always guess that arrays iteration is faster than linked list. And pretty much guess that GetComponent in Update is kinda bad
@BDCPT-NguyenThanho2 жыл бұрын
at the example between Vector3.Distance vs SqrMagnitude have u try ((Random.insideUnitSphere - Random.insideUnitSphere) * MULTIPLIER).sqrMagnitude || i think it is a bit faster || 1 multiplier and 1 subdivisor faster than 2 multiplier and 1 subdivisor right ? (this is my opinion)
@beanieteamie7435 Жыл бұрын
In my case I'm working with a compiler that literally doesn't optimize anything, this creates code that runs several orders of magnitude slower than a regular monobehavior.
@r6scrubs1262 жыл бұрын
Love to see actual tests instead of people just repeating the same things they heard elsewhere. Good job
@alexey6343-x0 Жыл бұрын
"Actual" means on different devices with different CPU architectures and different compiler options?
@ЛеняБорисов10 ай бұрын
your clients (means gamers) are playing in unity editor? If they so, you could apply on that "tests". Anybody actually developed at least one game says that you must check optimization in release build on device only
@bonehelm2 жыл бұрын
Regarding the Vector3.Distance function, you're also making 2 calls to Random.insideUnitSphere, which definitely makes 1 call to sin and 2 to cos, which are also both expensive operations. But then you're calling it twice. The 6 calls to sin/cos probably dwarf the time it takes to make 1 sqrt call. That's probably why sqrt and sqrtSquared about the same time, cause the 6 trigonometric computations are taking over.
@Tarodev2 жыл бұрын
You're right. The simplified code I posted on screen shows more predictable results, but even then... not enough for me to use the less readable option. (900k iterations, 6ms and 4ms)
@television10882 жыл бұрын
Also you should be comparing it to MIN_DIST*MIN_DIST
@davibergamin59432 жыл бұрын
@@television1088 if we cache MIN_DIST*MIN_DIST it will be the same thing
@television10882 жыл бұрын
@@davibergamin5943 That's not something that would ever be cached except for artificially improving benchmarking.
@vizepi692 жыл бұрын
@@Tarodev Your simplified code is still hiding the call to operator- which *may* have an impact on performances, even if Vector3 is stack-allocated, it can trigger a call instruction to operator- and constructor. By manually writing a Vector3.SqrDistance( Vector3 a, Vector3 b ) you can have a ~40% gain in performances
@avgchoobafan2 жыл бұрын
Really nice insight on code performace! I would recommend having an "average" result for each test in miliseconds, so the more you test you get a stable number to compare.
@Tarodev2 жыл бұрын
Damn! Why didn't I think of that. Great suggestion
@CheeseChuckie2 жыл бұрын
I love a good caesh! Speaking of - I've heard the idea of a "Runtime Set" in a few talks regarding scriptable objects. I think it's a very nice alternative to finding objects by/of
@sdhority2 жыл бұрын
The order of operations bit is really handy, it's really impressive to see the difference that just reorganizing your math can make on computing time. Thanks!
@lastsipahi Жыл бұрын
Last one completely caught me off-guard. It'll be hard to erase a 10 year old habit! Great video btw, thx.
@yerngames2 жыл бұрын
Great video! Just remember everyone, optimization is the last thing to do! Do not try to optimize everything that you make at the start. I always suggest to make a sloppy prototype and re-write an optimized version of whole code later on.
@Tarodev2 жыл бұрын
I cannot heart this comment enough. I was planning on adding a prefix to this video regarding pre-optimization but I guess it slipped my mind.
@yerngames2 жыл бұрын
@@Tarodev Thanks for the heart :P
@umapessoa60512 жыл бұрын
I disagree, its the same as doing multiplayer games, its something that is easier/faster/better to do since the beginning.
@RobLang2 жыл бұрын
@@umapessoa6051 I disagree. It's not the same. Multiplayer sets architectural constraints on your code, so you should do at start. Optimization should be as a result of measurement. You cannot guess what the compiler will do.
@umapessoa60512 жыл бұрын
@@RobLang when your game grow big enough its pretty hard to change the base of your code to optimize it, you'll probably lose a lot of time doing it, you can't predict what the compiler will do but you can know for sure that some functions/ways of doing things shouldn't be used at all as there's more optimized options.
@ronygankin41582 жыл бұрын
Hey Tarodex, avid fan here. I've been studying game dev in a local college here (its unlike US colleges) and while we learned alot of game oriented programming, your more "classic" programming stuff is just enormously helpful because you stay so relevant to video game programming. Really wanted to thank you for that, it's super enriching and I learn alot from your videos. If you ever make a series that's more in depth programming then getting components while still staying relevant to video game programming. You have a fan waiting. Thx alot for sharing all that knowledge my friend!
@FaDe5872 жыл бұрын
Regarding the Vector Distance thing: It is important to note that Vector3.Distance and sqrMagnitude do NOT produce the same result. The result of Vector3.Distance produces the magnitude of the direction vector between the supplied vectors whereas sqrMagnitude is that same magnitude squared. This can be useful if you want to compare distances, e.g. to see which of two positions is further away, because you don't really care about the actual distance but rather which of the two is greater. If you however need to get the actual distance, you have to use either Vector3.Distance or magnitude, sqrMagnitude will be incorrect.
@odo4322 жыл бұрын
In regards to the NonAlloc, I've done some testing with this and it can yield significant performance improvements depending on how you use it. For example, if you perform a OverlapSphere and there is 100 colliders then it will process 100 colliders. However, if you use OverlapSphereNonAlloc and set it to 10 then it will only process 10 colliders and disregard the rest. This can be handy, for example, if you want to improve performance at the cost of accuracy. EDIT 1: Just had a go at your WEBGL build. Using Vector.Distance is almost twice as slow for me with 900k loops (12ms for Distance vs 7ms for Square Root). EDIT 2: Just had a go with the order of operation. Even with 900k loops I would almost always get 6ms for each one. But every now and then FxFxV would jump to 9ms whilst the other two would stay on 6ms or jump to 7ms. For the most part, I don't think order of operation has a significant impact.
@Tarodev2 жыл бұрын
The NonAlloc collider limit is great. I use it for grounding and use an array of size 1. As for the results... It seems WebGL is just insanely varied from pc to pc and browser to browser. My webgl distance comes out to 6ms and 4ms, so sqrMagnitude wins, but not by enough to not use the far more readable Vector3.Distance. Order of operation comes out identical for me on both webgl and il2cpp.
@FaDe5872 жыл бұрын
@@Tarodev I would guess that Order Of Operation might be one of those things the compiler can detect and optimize away.
@Tarodev2 жыл бұрын
@@unitydev457 that's actually a test I'd like to run... If there's 1000 colliders and you limit it to 10, how much faster is that
@treppas2 жыл бұрын
Super interesting! Thanks for taking the time to put this together and share it 😊.
@FyresGames2 жыл бұрын
The Linq vs For was one I was looking for. I was annoyed by a friend refactoring my for loops into Linq behind me because "Cleaner". It made my day to see that concrete proof I was right.
@Iboshido2 жыл бұрын
Love this type of videos. Code optimization in Unity isnt covered enough on KZbin
@hasankarakoc15762 жыл бұрын
I was just researching for it and you made it just in time! Thanks!
@eduardo-silva-792 жыл бұрын
Certainly didn't know a lot of these and they are really useful! The time complexity test also helps to understand your point quite a bit more, rather than simply trusting your word.
@DevDunkStudio2 жыл бұрын
This one is great to know for performance and not many use this properly: Caching WaitForSeconds and other yield return calls (like WaitForEndFrame etc) in a coroutine! You can cache the variable as private WaitForSeconds = new WaitForSeconds (1f); Without doing this you'll add stuff to the garbage collector every so often which can add up! Bonus nitpick: you can change both transform.rotation and .position by calling setPositionAndRotation, then the calls are merged into 1?
@Tarodev2 жыл бұрын
I remember years ago when I first decompiled WaitForSeconds to discover it being a class and not a struct. I was shocked and began caching them ever since. Nice tip! Also yup, just decompiled setPositionAndRotation and it is indeed just one extern call.
@AJ213Probably Жыл бұрын
Be very careful with this. You may be tempted to make central area with different cached wait for seconds. Or maybe you would make a dictionary for caching this too. The problem with that is if multiple coroutines are using the same wait for seconds, the timing will be completly wrong due to the internal timer being reset when the routines exit. I find this often at my job.
@szyslay2 жыл бұрын
SUCH a gem of a video! Currently makiny my game on Early Access and this helps. Glad to use all recommended functions already ^_^ Thank you for sharing!
@overrideFunction2 жыл бұрын
Being new to Unity this was fantastic. It also provided some context to how expensive calls actually were. Needless to say I will avoid the game object and type find calls like crazy!
@danleg12 жыл бұрын
Super helpful tests, would love to see more this
@XinvaderGaming2 жыл бұрын
The comnt section is very positive and downright encouraging! Love it!
@MalbersAnimations2 жыл бұрын
You my friend, have earned the bell notification button... well done 👏👏👏👏
@Tarodev2 жыл бұрын
Oh wow. Thank you ❤️
@okee2 жыл бұрын
Code optimization is one of the things I planned to improve this month. VERY BIG THANKS!!
@divainsyoutube42542 жыл бұрын
Great video! Haven't known them all so thanks for the knowledge! About the cached for-loop, I'll add and say that it is faster because the non-cached version, List.Count invokes the get method on the Count property each iteration
@VEOdev2 жыл бұрын
This channel faster became my favorite game dev channel with many useful information that no other dev talking about and things I didn't really know they exist or how to use them .. I would like to see a Playfab tutorial on multiplayer game and matchmaking and stuff it will really help since there isn't any one talking about it and who talks about it only shows the basics but no one goes deep in it and there is non useful documentations
@Tarodev2 жыл бұрын
I did a recent one on LootLocker, but it's not a step by step tutorial, more of an overview.
@SlyzDev2 жыл бұрын
Bro. Im actually watching all your videos and they all are just too good for someone like me. Like seriously. I never comment under videos but like litteraly what you show is so damn useful lmao thanks for everything
@shreyanshanchlia2 жыл бұрын
Would like to see interpolated string performance added in the string builder list.
@zoks2 жыл бұрын
Release builds will have vastly different perf than what you see in the editor (debug). Great vid.
@simoncodrington9 ай бұрын
Fascinating, never knew transform wasn't a direct property and that behind the scenes it was going off and doing stuff, another quick win for caching
@zenmasters_games2 жыл бұрын
Bro, you deserve way more subs! Cheers 🍻
@Tarodev2 жыл бұрын
Thanks brother
@CrazyMan-lt6ky2 жыл бұрын
Man, you're rocks! Thank You for your course !!! I've learned so much!!!
@daniel_keen8 ай бұрын
I did not know about the order of operations. Very interesting!
@nodaichi60802 жыл бұрын
i have no idea why, but hearing your voice just makes feel soothed.
@Tarodev2 жыл бұрын
Awwww ❤️
@YasserSedrati2 жыл бұрын
You did all what we was wondering about. Thanks for this video! -good UI scene btw.
@Tarodev2 жыл бұрын
Better than looking at some boring numbers in a console :)
@TheIcyGoose2 жыл бұрын
Thank you for an excellent video! I would be interested to see you run these tests in a build and not in the editor. I find the performance is usually different once you build and run.
2 ай бұрын
I couldn't overcome all the thread performance bottleneck and issues and started coding in ECS and everything is now so smooth and performant. Still some cases are really harder to code than MonoBheaviour, but it worths when I see the performance difference. Using Burst compiler with JobSystem and run everything parallel when possible gets a lot of performance advantage. This is similar coding with C++ but you still use C#. Interesting approach but it works pretty smooth
@GorasGamesStudio2 ай бұрын
I started DOTS programming too in Unity and yes the performances are wayyyyyyy better (far away) but have to learn everything again, not easy !
@dathus64372 жыл бұрын
If foreach is faster in your tests, that's actually because it is implemented on a different assembly which has been compiled to release mode, whereas your for loop is in build mode which is generally way slower. This is why when compiled in webgl the for loop is actually faster!
@lanepemberton84662 жыл бұрын
I was wondering how a for loop could be slower than a foreach as well
@nikoart15612 жыл бұрын
And actually foreach generate more garbage Collection
@Devorkan4 ай бұрын
Even a single wasted millisecond per frame is a lot though since we only get a "budget" of 16.67 milliseconds per frame in order to hit 60 FPS (and even less with VR)
@bxbvxbv2 жыл бұрын
finally I can focus on just writing simple working code rather than constantly stressing by thinking about ways to make it performance efficient. the amount of emphasize regarding using some functions in docs & web is too much, that if you do this then it's slower. thanks for making this awesome test 🔥
@kingreinhold99052 жыл бұрын
This unity scene is so good for teaching these optimisations... Great quality content as always! Keep going, thanks for your work!
@jacques-dev2 жыл бұрын
(cries in cache) Thanks for the great video dude, I'd love to see more videos like this with more unity specific things, like nesting GameObjects vs. having them live free and wild in the hierarchy, nesting canvases, and other best practices for performance
@synchaoz2 жыл бұрын
Dude, yes, love vids like these and you're like the only one on the planet doing them. Much love.
@yudanaim68492 жыл бұрын
Awesome video. Im waiting for ECS comparison
@cgh3532 жыл бұрын
this is useful. thanks. I would like to see you test optimization on more code.
@TheOriginalDarkGlitch2 жыл бұрын
You are doing the Lord's work. Thank you for being awesome, I always wanted to do tests like this, but I don't have time right now.
@francoismentec42602 жыл бұрын
I LOVED this video, I just started Unity and you are my favorite channel so far. Quality content focused on Unity (not generic programming stuff) and Game Dev. I did not even knew about Unity making external call to C++ I would be interested in a follow up video focusing on differences across platforms. Maybe look at Browser vs Windows vs Mobile.
@pstudioDOTtk2 жыл бұрын
Interestingly when I try the WebGL build FxFxV is the slowest in the order of operation test. For max iterations the most frequent result was 4,3,3. Distance was also slower than squared magnitude. It just shows how difficult optimisation can be and that you should probably test on multiple machines and not just your own.
@Tarodev2 жыл бұрын
So many people reporting skewed results in WebGL. We're at the mercy of the browser!
@rickloyd8208Ай бұрын
Very interesting, thanks for your work and sharing results with us!
@sinisterdesign2 жыл бұрын
Great video! It's especially good to see the StringBuilder hype confirmed. I'd love to see the performance of the string Contains() method compared to alternatives like IndexOf(), RegExp, and Linq.
@t33h33studio3 ай бұрын
I always knew FindObjectOfType was on the slower side, but that is still surprisingly slow from what I was thinking. Good stuff!
@jonathansaindon7882 жыл бұрын
Nice video! For order of operations, you can achieve the same result by grouping the same types in parentheses like : Vector3 stillFast = x * (a * b).
@Nova045502 жыл бұрын
Good idea
@lee1davis12 жыл бұрын
Order of operation is the only one I did not know about. Glad you added it too.
@gamesplusjames2 жыл бұрын
This is really interesting to see! I've been talking about a few of these recently so it's good to have a clear example to point to!
@zerohidz2 жыл бұрын
I havent watched the video yet but I'm sure it will enhance my knowledge and benefit me. Thanks, please keep this quality content.
@qwertyram45982 жыл бұрын
About the distance, Godot has a separate function, squareDistance, which gives you the square of the distance(as the name implies, it doesn't root the distance). The documentation says use this if you're comparing two distances, as it's faster.
@Tarodev2 жыл бұрын
Godot has some lovely little helper functions it seems
@bonehelm2 жыл бұрын
@@Tarodev the reason you're not seeing a difference between distance and distanceSquared is because you're also calling Random.insideUnitSphere twice. That function calls triginometric functions 3 times, so you're doing 6 trig computations. So 6 trig computations are going to dwarf the call to 1 sqrt.
@iDerp692 жыл бұрын
This is great! Hope you make more of these optimization tests in the future.
@Spleegness12 жыл бұрын
God DAMN this is exactly my kinda video. You're incredible!! Thanks for the hard work
@AndersonReis42 Жыл бұрын
"send message is not a good practice" and here I was sitting and thinking i was doing a neat job using send message to optimize my code. thanks for the tip!
@r1pfake5212 жыл бұрын
I read somewhere that they store objects with tags in a extra lookup, so they only have to iterate over that one instead of iterating over overy object, so it makes sense that it is much faster
@halivudestevez22 жыл бұрын
thank you for mythbusting! :) I am happy you've made these clear! (SqrRoot -Distance)
@Fewnity2 жыл бұрын
Great video! Thanks, I was surprised with the results!
@KojiKazama2 жыл бұрын
Thank you sir. I will need to make a quick reference for these. The last one was unexpected as I didn't think the order actually mattered.
@longroadgames6592 Жыл бұрын
I just found your channel and I love it. Thank you!
@PvPNetwork2 жыл бұрын
Thanks for sharing. Even if you have an idea of what is potentially better its nice to see some testing results. The small things like VxFxFx make sense if I think about it - but I doubt I would have even thought about it until you mentioned it. Remember using strings in my item tooltip , and switched over to stringbuilder - never looked back!
@jean-michel.houbre2 жыл бұрын
Bravo and thank you for this great video, very interesting and well done. I was quite surprised by some results (distance versus magnitude for example), but I prefer surprise to the strict application of unproven rules... Here are the results for 1000 "Linq vs Loop" on your WebGL: Chrome 99.0.4844.74: --> Linq 1907 For 289 Cached for 252 Foreach 898 Firefox 98.0.1: --> Linq 1128 For 138 Cached for 128 Foreach 428
@svendpai2 жыл бұрын
been looking for a video like this, taro you champ
@NicTda2 жыл бұрын
Very interesting, mainly confirming what I was finding online to optimize our games. Regarding the last point, the Order of operations, it seems to have 0 impact on WebGL build when running your benchmark, probably because it's optimized at compile time (3ms for 900k on all tests). Good stuff!
@jahoopyjaheepu4972 жыл бұрын
This is a great video, and some of your results make me feel better about optimizing some of my code; it can actually make a difference! In regard to NonAlloc methods, I believe the Unity 2022 documentation states that they will be deprecated. Instead, something like Physics2D.Boxcast has two overload methods - one that takes an array as a parameter, like in your example, and another that takes a List - that actually grab all colliders, not just the first one. I would be curious how these perform, and especially if the List version is notably slower and/or produces any garbage.
@Tarodev2 жыл бұрын
That's interesting... I do prefer how the NonAlloc version works as it returns a count also. Good change IMO.
@KrzysztofGnutek Жыл бұрын
For the Linq vs Loop you mention that "foreach" is faster than regular "for" when you access the array you are looping through more than once - but what if you cache the array element so you access the array only once and then access the data on the cached object and not directly on the array? :)
@Tarodev Жыл бұрын
Very good question. I suspect you'll find it improves performance! You should benchmark it and reply here. I'm currently in Japan so it's a little tricky
@badscotsman2 жыл бұрын
Great video! You hit on all my potential talking points concerning usage. 😊 Another one you see a lot is using CompareTag() vs using the == operator. Speaking of, how Unity overrides the == operator is another subject worthy of a video. 😅
@Tarodev2 жыл бұрын
Whenever I can please you, I know I've done alright 😊 And dammit! Compare tag would have been a great one to showcase
@freddyspageticode2 жыл бұрын
Wait so which is faster?
@BenVanTreese2 жыл бұрын
@@freddyspageticodeCompareTag is much faster. As well as you should avoid object.name where you can, as it crosses C++ boundary AND allocates. (i.e. if(obj1.name == obj2.name))
@Handlessuck12 жыл бұрын
@@BenVanTreese Why would c++ be slower if its going to become assembly?
@BenVanTreese2 жыл бұрын
@@Handlessuck1 It depends on what you mean, generally C++ is faster. Both C# (when using IL2CPP), and C++ are compiled to native instructions, but due to the general nature of C#, when it "talks to" the C++ portion of the engine itself, it needs to do some marshalling and etc. (C++ doesn't really become assembly, it is compiled to native instructions, which we write as ASM so people can read it, but ASM is just another language that is converted to actual bin instructions, which are defined by the specific arch of the CPU/target) This causes it to do extra work + allocate memory that needs to be GC later. CompareTag is optimized where it does the work in the "native" part of the engine without requiring the marshalling and etc.
@doismilho2 жыл бұрын
Best dev channel currently on youtube
@Nullref_Arcana2 жыл бұрын
Regarding FindObjctOfType, I actually made a component that I use regularily called Fetchable, which has a string id/name field and a static dictionary. Then you can do Fetchable.Fetch(idName) to find the specific object. This of course makes it a one-to-one name to object, but I find it as a really useful alternative to any Find method (assuming it's a 1-to-1, which is often the case)
@MarkRiverbank2 жыл бұрын
I’ve never used “SendMessage,” but I think the intent is more of a poor-man’s publisher-subscriber pattern, in which case “GetComponent” isn’t the analog. But, C# events, UnityEvents, or a custom observer pattern would probably always be a better choice. “SendMessage” is a bit unique, in that the publisher and subscriber are completely decoupled-the publisher doesn’t know if anyone received the message and the receivers don’t know who sent it. Sounds sloppy and unnecessary, but there’s a possibility the problem is our lack of imagination for when that would be useful.
@RamonAlonsoLopezMartinez2 жыл бұрын
You are correct! Send message is definitely an Observer pattern not Get Component. But still crappy and slow! And unsafe!
@milanstevic84246 ай бұрын
It was just a makeshift solution that sounded good back in the early days of Unity. Nobody sane uses it, it's a dinosaur.
@user-uk9er5vw4c11 ай бұрын
this is awesome, I love this kind of low level things to improve code. thanks and you're welcome to do more videos like this
@testitestmann88192 жыл бұрын
The sqrMagnitude really surprised me. I made sure to always avoid the sqrt calls. Thank for checking!
@KDSBestGameDev2 жыл бұрын
I hope it is fine for me to explain something on the Vector3.Distance thing. Vector3.Distance doesn't instantiate a new Vector3, but your calculus for (b - a).sqrtMagnitude does. So this is not a fair comparison. If you compare (b - a).sqrMagnitude with (b - a).magnitude then there is a 2x performance difference. If you remove the memory allocation completly and compare it with Vector3.Distance it is even slower. My example Code: Vector3 z = Vector3.zero; float MULTIPLIER = 500000; int c = 100000; var sw = new System.Diagnostics.Stopwatch(); sw.Reset(); sw.Start(); for(int i = 0; i < c; i++) { var value = (UnityEngine.Random.insideUnitCircle * MULTIPLIER - UnityEngine.Random.insideUnitCircle * MULTIPLIER).sqrMagnitude < 250; } sw.Stop(); UnityEngine.Debug.Log($"sqrMagnitude {sw.Elapsed.TotalMilliseconds}"); sw.Start(); for (int i = 0; i < c; i++) { var value = (UnityEngine.Random.insideUnitCircle * MULTIPLIER - UnityEngine.Random.insideUnitCircle * MULTIPLIER).magnitude < 250; } sw.Stop(); UnityEngine.Debug.Log($"magnitude {sw.Elapsed.TotalMilliseconds}"); sw.Start(); for (int i = 0; i < c; i++) { var value = Vector3.Distance((UnityEngine.Random.insideUnitCircle * MULTIPLIER - UnityEngine.Random.insideUnitCircle * MULTIPLIER), z) < 250; } sw.Stop(); UnityEngine.Debug.Log($"distance {sw.Elapsed.TotalMilliseconds}"); My times: sqrMagnitude 20,3163 magnitude 41,8683 distance 66,1406 Also these are debug performance measures, which are totally off. I highly suggest you do a RELEASE build and compare performance with that next time. Some functions do more DEBUG bogus than others and also some things get highly optimized by the compiler, while others don't. Please don't spread the rumor that Math.Sqrt is not a computational heavy thing for the computer. Also funny to note is that Math.Sqrt strangle for the same value is always faster than for other values. Also not significant but surely measureable. Don't know why honestly. FindObjectWithTag is searching the metadata of a gameobject and the FindObjectOfType need to search all components of all game objects and also do reflection on them since IIRC it works with interfaces. Using Linq is fine in Unity as long as you doing it right. With everything if you use it badly, it will do bad things. I love Linq in Unity and overall. Linq sometimes (depends what you are doing) will generate garbage. And the reason not to use Linq is for not generating unexpected garbage on mobile platforms, since GC is bad on there. I honestly use Linq all the time, but I do mainly PC Games. I'm really curious if caching the for loop makes a differernce on a optimized RELEASE build. The for loop should be faster on an array instead of a List. Because then the indexed data and accessing the index data[i] is way faster. Especially in your case. Try the for loop vs foreach with an array instead of a list and you should see the for loop be way superior. Reason behind this is that array data is cached on CPU cache and accessing it indexed is a single point read on memory. While a List is accessing a reference (the references are acutally cached in CPU) but the actual values behind the reference are not. So data[i] gets reference from CPU cache but has to resolve the reference which often will be a cache miss. And if you do that multiple times, it will be worse. This should get optimized by a RELEASE build. The foreach gets the reference value one time and will cache ich for you in your variable. That's why the for is slower when accessed multiple times without compiler optimization and with a List instead of an T[]. This being said the foreach is usually slower than a for (with an array and caching in mind), because it will instantiate an Enumerator. The JIT does alot behind the scene, but honestly test it with an array and you will see magic.
@INeatFreak2 жыл бұрын
Distance check has actually made difference for me. Vector3.Distance : 7 ms Srq Magnitude : 4 ms Order Of Operation has no effect. They all the same 4 ms.
@JuniorDjjrMixMods2 жыл бұрын
He used 2 Random in the sqrMagnitude call, but 1 Random on .Distance, this caused problem in the benchmark.
@kilroyyyyy902 жыл бұрын
That last one is HUGE for my game, literally just what I needed haha There's quite a hefty load in FixedUpdate just because of the nature of the game, but I've been doing essentially V*F*F for everything just because it makes more sense to do that in my head. But I shall change my ways :D
@AntonioNoack2 жыл бұрын
and even better, don't write it like v*f*f but instead with brackets, v*(f*f), so your future self will understand what you have done 😄
@Mecheka2 жыл бұрын
Hi! Very interesting video! But I've got a note/doubt: In the LinqvsLoop part, you mentioned that FOREACH is better than FOR if you access the de "[i]" twice or more in the loop. Did you try benchmarking a FOR loop caching the object at the beginning of each loop? (so you access the list/array once), but then using it several times? Because I think that is (roughly) what FOREACH do in the background. Also, you could test this and a versión where you also cache de COUNT before the loop.
@Tarodev2 жыл бұрын
I did not test that and yes that should come out to be equal! This has actually triggered something in me... I don't cache the item nearly enough, but end up using the index multiple times. Thanks for mentioning it!
@hackbeam2 жыл бұрын
This topic should be pinned or mentioned in the description
@TheHaatchoum2 жыл бұрын
I remember quite a few months ago, coming across a general "Unity C# code and garbage optimization tricks" blog somewhere. And I specificaly remember it saying that FOREACH loop was slower and somewhat generating more garbage. It also told to always cache objects that needs multiple access. (seems like the most generic thing to say) But I'm nowhere near the level to even figure out what's true about this. So seeing this video here is a real blessing. Although, he didn't say anything about For/Foreach on the garbage side.
@Mecheka2 жыл бұрын
@@TheHaatchoum for and foreach loops have been suffering optimizations all these years. I heard the same thing you say really long ago (like 3+ years). I might be wrong, but I think that with the new .net the for and foreach loops are now much more efficient, specially when iterating List. On the old times I remember avoiding Lists much more than now. Which remembers me, @Tarodev: There's another performance axis on the for/foreach loops that is much more important. And that is: what you loop through? - Looping arrays is better than Lists (as said, on newer unity, not by much more) - Looping value types is *MUCH* better than reference types (classes) So looping int[] would be the fastests and looping List would be slowest In my testing, this axis (value types and arrays) is much more important than caching (avoiding multiple access), or using for loop instead of foreach. I've created loop heavy algorithms that generate Gameplays (wordsearch) iterating NativeArrays of structs really quickly (few milliseconds) on low end mobile devices. Yes foreach is technically slower, but the difference in the new .net is not that much and iterating arrays and value types is much more important.
@Norbingel2 жыл бұрын
I learned more than a thing or two. Thanks!
@torcheyegames2 жыл бұрын
Great video. Actually the newest Rider has the last bullet point covered in their editor - it will give you a hint of "expensive computation" or something like that and you can one-click to change the order of multiplication, like from V*F*F to F*F*V.
@Tarodev2 жыл бұрын
I've quite enjoyed that new feature
@Warwipf2 жыл бұрын
3:53 that is super surprising to me. thanks.
@XxBobTheGlitcherxX2 жыл бұрын
For the distance you use Random.insideUnitSphere twice in each test. I have not seen the code Unity uses to calculate that, but to me it would seem obvious that its a lot more costly than calculating the distance. Making your square root comparaison completly irrelevant in the test. You could precompute the list of random vectors before the test and then only compare the square root to get a hopefully more acurate result. Edit: I did the test and if I compare the magnitude with sqrt magnitude I get for 100 000 000 iterations Distance => 1700ms Sqrt => 900ms However if I use the Distance function, forcing me to use two vectors and subtracting them in the sqrt test I get for half the number of iterations : Distance => 1700 Sqrt => 1700 so according to my computer even subtracting two vectors is enough to remove the optimization gained by avoiding the square root.
@Tarodev2 жыл бұрын
Did you see the overlay code I put on the screen at 3:24 ? Regardless, the random is being perform an equal amount of times for both tests so it shouldn't skew it too much. I did want to include that simple version on the screen just for this reason though :)
@XxBobTheGlitcherxX2 жыл бұрын
@@Tarodev The random would not skew the results, it would technically take the same time in both tests for the distance part. What would happen is the ms you show would practicly only represent the random vector generation instead of showing the time for the distance functions. For the popup you put it would seem you reuse the same 2 vectors over and over which is, I would think, prone to compiler optimizations. Since its not talked about verbally in the video I think its worth mentioning in the comments and hopefully people will know that doing tests like these have an insane amount of pitfalls and shouldn't be relied on too much.
@Tarodev2 жыл бұрын
@@XxBobTheGlitcherxX You're totally right. The benchmark I did for distance sucks, it's really just a benchmark for the 'Random.insideUnitSphere' function. But yeah even with the simplified code over 900k iterations, it comes out to 6ms and 4ms, so not enough for me to stray from the more readable Vector3.Distance.
@dzj3zterminator6612 жыл бұрын
eventually it all snapped into place and I started learning how to add all the effects, titles, motion text. It was pretty cool to see my
@nirangasithara2 жыл бұрын
Damn !!! it's like the first day learning programming for me. Hope in few years I can understand and utilize these !!
@Foxyzier2 жыл бұрын
Really liked this format for the video
@LiveWireDX2 жыл бұрын
For some other tests: I've been told to avoid large numbers of null checks for gameobjects in the update loop. Might also be interesting to see how GetComponentsInChildren compares in the find object test. I don't know how it functions under the hood so maybe running it on all root objects in the scene is effectively the same as FindObjectsOfType.
@devforfun56182 жыл бұрын
how do you avoid null comparisons ? by never losing destroying anything ?
@DeathxStrike182 жыл бұрын
Not sure if you read this but I found places where you need comparisons and the editor states they are intensive for example if ( a == null ) if you instead use if ( a is null) or if (a is not null) will provide a slight performance boost though not sure why.
@TheKr0ckeR2 жыл бұрын
wow, great video! always stressed about optimizations
@erinzaharris21622 жыл бұрын
I would be interested in exploring 1 update loop controlling multiple entities vs an update loop on each of the entities. I was implementing a swarming type enemy in my game and I tried to put the logic of them into a singular script that would handle the movement of them. I tried a single for loop through a manager with each of the entities as children and I tried coroutines. Both of those methods were slower than just having the logic of each of them on their own individual update methods. But everyone keeps telling me that having a singular update for multiple entities is faster.
@Tarodev2 жыл бұрын
Great benchmark idea. I'll make a part 2 with this included
@saniel27482 жыл бұрын
Because objects that share parent can not be multithreaded when unity updates them. You generally don't want moving objects to have a parent
@erinzaharris21622 жыл бұрын
@@saniel2748 that doesn't make physical sense. Especially since my code was a singular script on the parent object. The multithreading happening was in my script logic then being applied to the individual rigidbody children. All my movement is done with the physics engine. I suppose I could try and throw them in a list for reference instead just to test this theory. But I doubt this has anything to do with it.
@saniel27482 жыл бұрын
@@erinzaharris2162 Idk this not my idea. There was a talk from unity guy that said that when you have stuff that moves you want them to be unparented
@GameDevCoffeeBreak2 жыл бұрын
Nice work, thank you a lot for this video!
@WagnerGFX2 жыл бұрын
Whenever i think some code could have a performance impact I do this type of test, but a lot simpler. The whole setup for benchmarking is great and I will use it in the future to test logic faster. 👍 I just wished there was an easy way to track GC allocations too.
@YoutubePremiumMem Жыл бұрын
The profiler is decent at telling you when gc is collected and how much but it’s a bit crap at actually helping track down the culprit and so it needs a lot of drilling down to find the offender.
@Xeit2 жыл бұрын
Find Objects - Holy hell! Entire length of this segment I was like "Why, why would any1 use this. For the love of God please don't. So many possible problems." and then came your conclusion and I was like "Yeeeees". But I started in OpenGL (pain) so I guess I have other principles than others.
@rockersfilmstudio2 жыл бұрын
Just started using Rider and it suggests converting a lot of my List foreachloops into Linq by default - interesting that it is less performant. Maybe it's just to do with making the code more efficiently written?
@Tarodev2 жыл бұрын
Linq is all about code writing efficiency and readability. I use it everywhere in non-critical areas. Take this expression: list.where(predicate).Select(predicate).OrderBy(predicate).Take(3); Imagine the alternate code... Much longer, not even close in terms of readability, slower to write, etc.
@rockersfilmstudio2 жыл бұрын
@@Tarodev Thanks for the awesome video btw, just went through and removed a bunch of gross FindObjectOfTypes... True that - I had only used Linq for some ordering and comparing of lists - it was only when using Rider that the Linq alteranatives came to light. Much love from across the Tasman
@Nova045502 жыл бұрын
Super helpful!! You put so much thought into this. You are killing it.
2 жыл бұрын
Very nicely put video ! Good job.
@Betruet2 жыл бұрын
Phat info dump, thanks for putting in the effort.
@marcoseliasmep Жыл бұрын
Awesome! Another tip that could make a huge impact is avoiding Update, FixedUpdate and LateUpdate in scripts that have many instances loaded. If you do a foreach… myscript.CustomUpdate in thousands objects it will be faster than having Update() in all thousand instances. I just avoid using it in my project because we must have a list of all objects. With dynamic worlds and spawners based on distance that array would be constantly resized, so generating garbage. But with a fixed amount of enabled objects the change could save a lot of milliseconds.
@animal96332 жыл бұрын
Thanks for that last one, I've never seen that anywhere before.