Intro to Profiling | Game Engine series

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up guys my name is Jonah welcome back to my game engine series so last time we took a look at a little bit of an optimization of how we could basically make our render A to D out of urine bura a lot simpler in the in the sense that we had a kind of one shed if everything make sure you guys check out that video if you haven't already because it's a cool little optimization and it's a different kind of way of thinking I think that video is quite good now today we're gonna be talking about what we said we would last time which was basically taking a little bit of a look at performance and timing and benchmarking and profiling there's a lot of it a lot of these kind of buzzwords floating around here what we're gonna do today is I'm kind of probably gonna introduce this like as an introduction today because this is gonna end up being like a 2 or 3 pot miniseries within I guess this game engine series well we're just basically going to talk about you know how we can both change our card I guess modify our code in a way that allows us to record some metrics such as CPU usage CPU time basically and then also how to kind of I guess look at and analyze that data in a meaningful way because you know in this kind of topic there's there's two sides the right there's two sides of the coin there's the actual collecting data right so you need to figure out what data you want what numbers are gonna be useful to you you know for example we might want to know how long one frame takes how long the kind of updating of the camera takes how long clearing the render attacks even maybe you wanna if you want to kind of drill down into it specific grande recommends you want to kind of like like lay this out and be like yeah when I hit the mouse button when I render I am going well everything that happens in my game engine in my game I would like to know how long everything takes so that way if you know if everything's kind of taking one millisecond and there's this one function that every frame is taking five milliseconds I know that maybe I should optimize that specific area of code if you're kind of flying blind in a way where you just you just don't know like what is slow what is fast you kind of look at your frame and your frame rates just like 20 or something and just not performing well it can be difficult to drill down and actually figure out what's wrong so that's kind of the the sense that okay well I want to know how long every function text for example right I want to know this on update is sandbox 2d on update function that we have here how many milliseconds every frame am i spending inside that function doing that function right how much time is my renderer spending actually rendering these quads you know do I need to speed that up and of course that's gonna be important because when we do move on to optimizing our end virtuti because it is a very simple kind of one quad per draw style 2d renderer at this point when we do optimize it it's gonna be really nice to see that massive performance benefit that we do get and that's why that's why I want to get all this always kind of timing profiling stuff done now the other side of that coin that the other side of this profiling problem that I think people don't realize as often is once I have that data what what am I gonna do with it okay cool it at three milliseconds here right do I really want like a list of numbers that just tells me that okay this took five months that consists of three milliseconds this to 0.5 this took point three okay cool how does this work that's probably not a very good way of doing it I want to actually visualize this data somehow apart from just maybe seeing it visually to begin with I also want to maybe record specific trends in the data or whatever you know for example what happens if 10 frames are fine but then every 10th frame or something or every 50th frame there's a bit of a hitch why does that why does that happen I want to kind of draw attention to that weed that out because that might be information that's useful to me and then of course yeah visualizing the data would be incredible as well so all these things are things that were gonna cover in this little miniseries we're gonna basically just I don't want to spend too long on this and I and I am actually planning to make us to learn videos specifically about like profiling and benchmarking in fact I do have video on benchmarking in C++ definitely check that out because I'm actually going to be using some of the code from that video here today but basically I don't wanna spend too long on this so today we're just gonna like see if we can get some numbers out and then next week next episode we're gonna see if we can visualize those numbers somehow I do want to point out as well that this is going to be completely independent of any kind of tooling right I don't want to tie this to Visual Studio for example now this is another little discussion there are profiling tools available every IDE probably has a profiler built in a partner and aside from that there's obviously standalone profilers which will basically can look at your code and be like okay well this is how long every function takes that's something the visual studio does offer and I might cover that in a different video probably part of the C++ series or something like that just a standalone video it's good I won't lie the profiling tools in Visual Studio I'm not bad at all but it's better to ultimately it's better to not necessarily better but you know yeah like for example I would still use visual studios profiling tools even if I had man but in a lot of cases it makes a lot of sense to write your own profiling tools the reason is that it's gonna be something that is inside your code base and because of that you know presumably you kind of distance yourself if it's not kind of part of the development environment you choose to work in right it's part of your actual code libraries part of your actual engine that's really useful because suddenly that doesn't that means that I don't need to be using Visual Studio I don't need to have Visual Studio hooked into my code to see how fast things take right that's not good what if I'm deploying on Mac well all I can use Xcode and that has some like instrumentation tools great what about Linux you know I'll have to use a different profile now what about Android what about iOS what about consoles you know you start ending up with all of this this kind of situation here where it's like you know I have I'm using a different tool for every platform and not only that but I have have like a debugger connector or I have to have like this profiling tool connected to my app to actually see how fast everything is what if just randomly on a special build will say of my code when I'm running on some users machine for example right there downloaded my gambler my friend play my game it's running really slowly on his computer I understand why because he's got a great graphics card or whatever right I want to see what's going on well wouldn't it be nice to just flip on a switch get all that data out analyze it be able to look at it and see what's wrong without having to be like a cable first you're gonna have to download Visual Studio and am I gonna have to we don't want that right that this might have been a long-winded explanation but my point is it's really nice to have your own tools and by doing that you know we can easily kind of take a look at every function in our code it's called instrumentation when we actually go through our code and we add additional code basically that will track all of these things this is definitely something that you want to shut off for distribution bills it's usually just used for debug builds or broglie's builds it usually has its own flag as well because you don't want it to be running all the time or being compiled into your code all the time so that anyway there's a lot of things we can talk about I don't want to again I don't want to make this huge malicious dive in we're gonna take a time on class from the benchmarking and say false false code sorry benchmarking in C++ video that I have linked up there then I made a while ago we're gonna take that time a class we're gonna change that around a little bit and then we're gonna see if we can record some basic metrics from within sandbox 2d to begin with and you know what else I want to give a huge thank you to all the patrons that made this series possible petrichor full slash the Cherno series will not be here without you guys I've done some pretty exciting things lately I've had an exclusive video about talking about how I'm getting Vulcan into hazel and also of course there is a hazel development branch it's becoming it what I want to do with with patreon what I want to do with that with those exclusive videos is kind of treat them as like a weekly devlog right not one that not not like the one that went up on youtubers or like fancy it's all like these cinnamon cinematic like shots and everything and it's like to tip it took me like a week to edit I don't want anything like that just a quick and dirty video pretty much live just like a live stream almost about me just kind of being like okay well this is what I did with hazel this week well this is what I did with you know my channel this week or whatever look a little dev vlog because me working by myself is a full-time youtuber it's a little bit difficult to stay accountable to all these things that I'm working on so I think that if I was to make a weekly video of of course myself every Monday morning or every Friday because it's like the end of the week to just kind of make a video but I'm like this is what I did all week and show off a bunch of things I think that would probably be very healthy for me and it'd be cool for you guys to see as well so that's kind of the plan I guess I should probably do the first of these videos like tomorrow cuz tomorrow's Friday we'll see anyway um so that's what's going on and of course thank you so much for helping to support my channel let's get into this profiling stuff okay so this is what we had at the moment again you know this is week two this last episode is not really worth talking to much about it yeah I want to see how long everything text that's kind of the goal for today I'm just gonna scroll up to the very top of this file this is the sandbox to D del CBP file we're gonna be like real quick and dirty yeah because I just want to show you guys how this works I'm gonna paste in a basic timer clause this is basically the same thing that was in the the benchmarking supersoul video I changed a little bit we're taking in a con strong point as the name here and we're doing some other loose stuff but basically it's really simple right what we do is it's kind of scope based it's ra íí- which basically just means that when we constructed it starts up and when we destroy it it stops right and in fact this is annoying me slightly I'm just gonna move the destructor over here so basically all it's doing again is it's starting the timer when we actually construct the object and when we destroy the object if it however if it hasn't already been stopped it will record the endtime point and then calculate the distance between the two to get our duration in milliseconds which we should probably also write okay cool so you might have a few questions about this again is just an example piece of card one of the questions might be what might be why are we using comps child pointers this is not C as C++ yes it is but I don't want to store an entire like heap-allocated string or anything like that because this is meant to be a static string and you know we can talk about strings in a future episode but basically if you have a static string static meaning that is literally typed in like this it's not like a variable it's not mutable at all it's something that's literally written in the code as a static string then you do not want to use STD string because by doing so you know you're basically apart from the potential heap allocation and all that there's so much there's so much unnecessary overhead because it really you know what is a string it's just a bunch of characters it's a memory address that we have with a buffer that has a bunch of characters that's all I need it for because it's going to be a static string okay cool so that's out of the way let's talk about how we can use this well at the moment all it does is it outputs this to the console now that's great let's see it in action quickly I'm just gonna grab this timer we probably need to include burner as well if we go over here to all on update that's a good candidate for this I'll type in time and time I will have to give it a name I'll give it the name of this function so sandbox 3d on update this is what I mean by a static string right this is never gonna be something that we like take in from from a file or gets generated in any way through our program code just a static string and that should be it like if I just run this program now theoretically we should know how long this on update function takes because what are we doing we're printing it to the console now we get a value that's between 0 and 1 well I mean sometimes a 0 sometimes is one most the time is 0 the reason that this is happening of course is because you know we're we're treating this is milliseconds we've told our timer we want milliseconds so it's giving us to the closest millisecond we'll change this to microseconds to make this a little bit more clear and then I'm probably just through order you know duration equals so we had n minus dot I'm actually gonna make this exploit and - stop and then I'll multiply it by point zero zero one just to get that from microseconds in two milliseconds so now that we have this we can replace that with that and we should get something a little bit more precise here alright and here we go to three decimal places we seem to be getting a pretty accurate timing here of how long our update cycle actually takes so specifically the user based update cycle meaning the actual client code on update function okay brilliant so we've got that that's fantastic now having that data in the console is a little bit well not very useful because we have to look at the console also if we have numerous ones of these for example we have sandbox Treaty on update and which probably actually look like the name or something like that instead of just um you know a function and instead of just duration as a static string but anyway if I want to see for example this is code based remember right so if I want to see for example you know camera on/off date and instead of actually putting it into the camera control function we're gonna put it here if I want to see something like this and I probably don't even have to rename this I can just you know will do camera controller on update you know it's not bad like I want to see all the data here but I'm just kind of trying to demonstrate to you guys why it's not great this is clearly a mess right I'd much rather see it like you know I'm gooey and eventually maybe in some kind of visual way so how do we do that well I'm gonna kind of quickly add something to this that's gonna actually make it so that we can visualize this not really visualizes but see this an IM GUI I'm acting inside like an actual control I make a little struct called profile result this is gonna basically contain a Const name and then we'll also have the actual time so this kind of profile result I'll just make a vector of these so that we can have basically unlimited amounts of these kind of profile results we'll say and then what I want to do is I want actually kind of I gets pushed back into that vector when I actually get a profile result and maybe over here I'll have some kind of section where I just go through all of the profile results so a result in purple results and then what we'll do in some form or another will just present this in time ability so I'll just use I'm Joey text which is like a formatted text option and then maybe I can do something like the name of the result and then eventually like there's also in fact if we were to do this we need to concatenate two strings so it may be let's just make like a I'll call this label little buffer here so that we can use so we have to use a function we don't have to use safe functions again you could convert this into it send a string and do everything there but I'm trying to be a little bit more mindful of performance I guess and we can just do this all on the stack really easily by just doing this so label is our destination source I guess we'll put the name of the the name of the profile result and then into labor wall so concatenate the so what is this label have to be okay for formatted labels so in other words we'll have the name right which is already in there and then we'll have two spaces and then percentage point to F and then m/s for milliseconds so this should give us the time I guess I'll do point three for more precision that will give us the time in milliseconds so now we can do label and then resolved all time okay so we're just basically this is just the same as printf we're formatting were basically formatting our label here so that it not only contains the name but then followed by the name it following the name it has our time two to three decimal places okay cool so we've got that pretty simple now we have to have some way of actually I guess putting this back into here now we could do some crazy things here I mean I'll probably have to modify the time because I'll make it a little bit better I think I'll make it a little bit more you vessel what I'll do instead of this is they'll actually pass in a lambda which will return a profile result and then this profile result so I can just probably Sasori um this profile result I'll then be able to do something like profile results I'll push back and then profile the result okay so but I'll basically just have something like something like this and we'll take us by reference of course so we have profile results push back profile result so that'll actually get it in there and then obviously as soon as I ran to them I want to clear them so we'll just be clear here okay sounds good to me obviously we need to extend the API to include this and then yeah should be it should be good so what I'll do is I'll add now I could I'm taking an STD function here that will probably cause my cause that heap allocation it's slightly better in this case and it's gonna be throw away time anyway so it's it's quite nice and display in this case to actually use this lambda without having to construct an STD function object and because a lambda will actually generate a type that is basically unique to this lambda there's no way for us to capture that really so we have to use something like templates or order to actually handle it so what I'll do is I'll just use our template here so this will be like our function I'll call it funk I'm just taking it in as a double reference here and then I'm going to well we'll copy it into this class we'll just have em funk like that and I'll just be FN here which is like the this is essentially going to be the type of lambda the DeBeers right and it can be any wonder that's why we're making this a template and then what we'll do is we'll set up and font what will set the vary the member variable here I'll put a direct bound a name and then instead of us doing this all I'm gonna do is call back that pull back right it's just gonna be lambda that we're calling and we're gonna call it with name so and name and then duration okay so that's it really so what this will do is when the timer stops we're gonna call this callback function which is our lambda right and that's gonna well we're giving it we're constructing a profile result with name and duration and then what that's gonna do is just go into M profile results and push back that profile result so now we now we should have that list there and that's it and realistically like you'd need to copy this everywhere that's gonna get annoying so I'm just gonna make a macro define you know profile scope I guess this is a scope profile will do timer timer will probably make it unique with the line number just in case you want to do two and two in a row whatever cuz otherwise you know that won't work for example because they're called the same thing whereas by using line working cabanne working catenae ting the line number which is just gonna give us like the line number so you'll give us the unique name of the whole point of this thing and then we need to take in the name which I guess yeah we just taking the name and then we'll construct this lambda which just basically put us back our profile result that's it I think right cool okay so now we can just use profile scarp with the name which is this pretty cool so profile scarf sandbox 2d on update and then purple scope camera controller on update we might as well change this around a little bit and make it so that we'll just add stuff basically so we have like this bottom our Renda I'll just say renderer renderer prep just like the preparation for rendering I guess and then if we wanted to you know also do the actual arounder at raw I guess right which kind of doesn't begin scene and all about draw quads and we put these into scope so the time it should stop automatically everything looks pretty good and I don't know if this will work let's just see if I can get this to our first try well we got some errands so that's great so yeah I did I did see a suspicious amount of Kelly brackets here also rather not Kelly brackets but parentheses so yeah I guess we don't know we don't need that extra one at the end yeah let's hit f5 more errors okay could not reduce template so this is probably because we used order here and it just it just can't reduce it so whenever you get like T it's basically just a continuous order error message so this is a tough call result let's tell it that f5 once again okay and we're running pretty cool so if we where's our window here it is if we look at this window check this out so we have all four of our timings here and they look pretty good if we just click somewhere on the title bar to freeze this you can see how long everything takes so on update is point zero to nine milliseconds very fast then we have point zero one three point zero nine eight and then the actual I guess the whole function so the drawing takes about you know 0.1 millisecond which is pretty quick and then sandbox 2d on update text which is the entire function all together takes 0.14 five milliseconds which is very fast okay cool sir one more thing I want to do I'm regretting my decision here to have it in that order I'm basically just gonna flip this and then this will be a string copy and then it's ranked at this is basically just gonna make it so that our time is first followed by the name that way it will just be nicely aligned unlike that mess that we saw before okay that is better and there's some we should probably get rid of this di am GUI demo window in fact that's annoying me so much is that inside I'm doing layer or somewhere probably is yeah sure demo window and I'm doing around that we don't need that online do you render out oh I think let's get rid of that entire function because that I'm Google a shouldn't be doing any I'm goo rendering most likely you know even core stuff should probably be coming from the render or some way okay that's better there we go so that's that's that right we can see oh look I made a big I made a full spoon and took a bit more time it's still very faster anyway this now shows us everything that we want to know about our profiles it's pretty cool you can stick this anywhere right obviously this is not like the most ideal thing in the world for example if you have something that isn't that frame like on event it'd be pretty much impossible to track that and then also you know this isn't like saving out everything it's really kind of hard to inspect it's a good rough way to just be like okay cool you know my sandbox drawing stuff is taking point to one five milliseconds I'm cool that's great and obviously if you add this profile if you were to expand this and add the profile scope macros all around your code like in every function for example so we added it into like render HP begin same then drop quad and saner everywhere then we would actually see everything but having a long list of everything over here is not ideal either so that's why that's why the kind of visualization of data comes in and ultimately what we'll talk about in the next episode if you guys you enjoyed this video you can do it please hit that like button as always you can help support the series but go to patreon.com/scishow now as i mentioned earlier in this video next time we're going to talk about what we can do with this dot and now that we're actually collecting milliseconds and we've got this kind of timing code that's actually collecting data what are we going to do with it how we're gonna visualize it we're gonna talk about that in the next video I will see you guys later good bye [Music]
Info
Channel: The Cherno
Views: 17,290
Rating: undefined out of 5
Keywords: thecherno, thechernoproject, cherno, c++, programming, gamedev, game development, learn c++, c++ tutorial, game engine, how to make a game engine, game engine series
Id: YbYV8rRo9_A
Channel Id: undefined
Length: 24min 53sec (1493 seconds)
Published: Thu Nov 14 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.