 Okay, so hello, I'm Stephen and this is Stevie W and the quest for 60 FPS And there's going to be daring feats of bravery and there's going to be thrills And there's going to be a whole lot of Chrome developer tools So let's meet our adventure here. He is it's Stevie W. And if you couldn't already tell it's it's me Steven Stevie. Yeah, right So it's a true story a true story of feats of bravery and daring and cunning and he was prepared to give a talk at any tech Quick plug Steven Waterman YouTube. Yep. And for that he needed a minesweeper game one that let the audience Participate and let them choose what to do So he started a new react Redux app and progress was good. It was all going well and Stevie was happy He was happy But unfortunately something terrible happened while he was working on the game He was playing around with it and he enabled the auto solver He waited it for he waited for it to start solving and then he kept waiting and he kept waiting and he kept the app It froze him. Nothing was happening and then the browser crashed and Stevie thought to himself Well, that's embarrassing. I should Optimize it And he ignored those thoughts It was just gonna be too much effort and he really didn't have time He was he had a talk in this tomorrow and he had to add a few more features So he just did that a little bit of time passed and Stevie gave his talk He wrote a few blog posts worked on some side projects and just generally tried to evolve it tried to avoid Actually optimizing this thing But eventually he ran out of things to procrastinate with and he was forced to start optimizing But there was one issue He had no idea how to optimize a web app Alas, there was no time for depression. He was shortly interrupted by a goggly vision It was Matt Stobbs And he said thanks for coming to my tech talk about Svelte Stevie thought, huh, that was helpful But suddenly he had another vision and it was robust and he said thanks for coming to my tech talk about web optimization And Stevie thought, huh, that was helpful So, uh, thanks guys. That was So you're actually in the audience Armed with that newfound knowledge, Stevie knew one thing for sure. It was optimization time So the plan it was brilliant and incredibly detailed Step one Reimplement the app in Svelte Because Matt had told me about how amazing Svelte was Step two, ellipsis Step three, profit It was it was in detail, but Stevie had faith. He knew that Svelte was amazing and people really liked it It's actually quite similar to uh, Swift UI kind of two-way data bindings and reactivity. It's all very exciting Um, so yeah, if we think about Svelte, there's four places in the kind of web pipeline where something could optimize for You could optimize for writing in a way that kind of lets you Write bigger and more complex projects without getting bogged down in the details and both Svelte and React helped with that Now they could help improve compiling speed and Svelte is actually bad at that It slows you down in the compilation stage because it adds an extra compilation step The same way that Babel or TypeScript do to add more features to JavaScript Meanwhile, React is purely runtime, so it has no effect But when it gets to the bits that are actually running on the client machines, whether that's their phones or their rubbish computers from 2004 It's fast, which is what we want because their machines are going to be the ones that are struggling So Svelte has no runtime libraries, which means nothing to download and no overhead for running that code compared to React, which Is really slow and makes you cry So steve you thought that sounded perfect He jumped on his computer and loaded up a new Svelte project and wrote a mind sweeper solver pretty much the same as the one he did for any tech So let's have a look at that now so There might be quite a lot of refreshing here because it is pretty much just random chance when it's actually going to be able to solve it And then we can demo it I would have made this work a bit better. Here we go. It doesn't look like it's doing much, but that's because it's not very fast Just around here. You can see it kind of slowly work its way out and solve this mind sweeper Solve the mind sweeper bored We'll just ignore that one Cool So he'd done it. He'd written it in Svelte and he knew it was going to be great, but it wasn't He thought well, that's embarrassing He'd rewritten it from scratch in a performance first web framework and it reached an astonishing 1.9 fps Admittedly it didn't crash the browser didn't crash the tab it didn't freeze So that was a good improvement and that was 100 by 100. It's quite big The any tech one crashed if you had about 15 by 15 But where are those fps? Looking at developer tools, he was horrified at what he saw in the performance tab It was this weird box shape with lots of small boxes and then there were multiple colors But he googled it and then he started to understand he was a bit less scared So it's like a timeline for left to right So the app starts on the left and all of this yellow and blue is JavaScript code running as we go further down It's kind of deeper into that call stack At the very end here after six seconds of computation it it produces one frame Yeah, so for 60 fps we want 16 milliseconds per frame and we were running about 6,000 milliseconds per frame But to understand what went wrong here, we need to talk about how spelt stores global state It uses objects known as stores similar to redux Which are basically just data containers that you can attach a listener to If you're familiar with like java beans, it's about like an observable Some some are writeable some are readable there's a whole kind of ecosystem there But for our purposes It's felt component subscribes to a store whenever the value in the store changes the component gets re-rendered And stores can also subscribe to stores So this is known as this is known as a derived store the one on the left is derived from the one on the right For example, if this store stored the amount of stock that we had for a certain type of A certain type of Chocolate bar in our shop then we could derive from that whether or not we're out of stock So if it's zero, it's out of stock and whenever this value changes We have to recompute the store on the left based on that function And it's also possible to derive one store from multiple For example, if each of these stored the stock of one chocolate bar and their price This one could calculate the total worth of all of our chocolate bar inventory So what had steve you done when writing this global state management? Well, he had one main store down here Which stored the entire board every single cell and from there he derived one store per cell So this one would select cell one from the main store and then the component for cell one would subscribe to that derived store Whenever a cell got revealed We sent an update to the main store He said hey the cell one's been revealed and obviously it changed its value Because that one had changed its value. We needed to look at everything that was derived from that store So all of these and these 10,000 more for the remaining 10,000 cells That was 10,000 function invocations and each one of those was accessing an index of a 10,000 element array It wasn't fast and then of course after all that one cell actually updates That's what I call deriving top down and you can tell it's back. So I'll put it in like a bad font Deriving top down is when you've got lots of small stores derived from one big one And as we've seen that can be really inefficient But a better alternative is deriving bottom up written in a nice font I'm wasted as a developer Deriving bottom up is when you've got one big store derived from lots of little stores So the difference is when the arrows are going this way And we're deriving small stores from big the big store is the source of truth The other way these small stores are the source of truth Um, and you're probably looking at this thing. That doesn't look like bottom up. That looks like right to left Yeah, well they go I think of it like a pyramid because you've got lots of small ones Anyway, that's exactly what Steve he did. He changed it so that instead of deriving top down he derived bottom up Which meant that they looked like this which is basically the same this arrow points the opposite direction But now whenever we update a cell we send that update to the cell one store because that's the source of truth for information about cell one That triggers an update in cell one which then propagates through just the bits that actually get affected All of these 9999 remaining stores haven't had to do anything because we've kind of Statically told the app that this is the way that the dependencies work So what was different when deriving top down an update to one cell triggered 10,001 store updates But when driving bottom up it only triggered two and they both have the same net effect So steve it's slain this felt store optimization dragon. But what was the result? Let's have a look so here is a reworked version which actually derives bottom up and again, we will continue to refresh I would have compiled you a version that was like actually gonna work, but the six versions and i'm kind of out of time We'll get there eventually there we go So you can see it's it's quite a lot faster to be honest saving each of those 10,000 store checks The 20 times a second 60 times a second makes it a lot faster So what was it in fps? Well, it's a 1100 increase in speed 23.3 fps It's a big improvement, but still a long way from that 60 fps goal What's slowing us down now? So in the development tools we can see a lot of interesting things First of all the javascript doesn't take nearly as long Um, but now we've got these two steps the layout and the paint which are both parts of the html rendering pipeline And just as a note it looks like these have got bigger But actually if just the javascript is now so small that we've zoomed in and these were invisible before because it's that much faster Um, so he dreaded it, but steve knew it was time to take on his biggest challenge yet The cave of html rendering optimization And he jumped right in Showing no fear steve came across the first fearsome beast the unnecessary html layout So the layout has taken quite a long time Um, and actually it looks like there's probably a way to get rid of it But before we talk about that we need to talk about what html layout is And i'm giving you this amazing analogy imagine there's a line of people to the shops and someone just pushes in the middle We have to lay out everyone so that they can make space Basically, that's what html layout is If we had a node in the middle of a grid Everything else might have to shift along and the browser isn't sure whether or not that has to happen So it has to do a layout and check That happens in steve's app whenever a cell goes from being unknown to being known either clear or flagged Because we're adding text into that node adding the text means we've added an html node and the browser thinks Oh, this might have caused everything to move around We know that it hasn't because it's actually being overlaid on top, but the browser doesn't know that Armed with this trusty friend google steve discovered that actually You can trigger pain if you change non geometric properties like backgrounds text color shadows, but these don't cause a layout So we can change the color of text or the color of backgrounds and that doesn't cause a layout adding the nodes does but When we statically generate that board at the start of the mind sheet brigade We know what text is going to be in every cell. We just don't display it Because the the minds are the minds are organized on the board and we know where they all are Therefore we know what every number is going to be so instead of adding the text We could just display it in a transparent color and then when the cell gets revealed rather than adding the text Display it in an opaque color so that it becomes visible The beast was slain steve. He had solved the unnecessary html layout and let's have a look at how fast it is now So that's actually quite a big improvement. You kind of can't tell because it's so fast, but We'll get the numbers so 36.5 fps That's a 57 speed up and all that happened was instead of adding text Always display text just transparently Absolutely can and you can just highlight it as well and it'll show up Um, I think you might be able to change like opacity or something like that Or you can do css tricks to make it not selectable But also if we get to the very end the final solution Doesn't use that And Yeah, but we'll get there So in the developer tools that unnecessary layout step which was shown in purple has completely gone And now this paint step is taking so much longer Well, it's not it's taking the same amount of time again to zoom in but look at it It's taking like so much more time than everything else just to paint So barely given a chance to recover after slaying that beast steve encountered the even more fearsome unnecessary paint complexity But what is html painting? Is it when crony's is a paintbrush? No, not really Painting is the final step in that pipeline So the browser has decided where everything is going to be on the screen So it's a science position and it knows what size it's all going to be how it's all laid out And all it needs to do is convert that kind of html DOM into some paint instructions and rasterize it into an image Um, so why is that taking so long in steve's app? Well, each frame we have to pay 800 by 800 pixel area We have to do that 60 times per second eventually And each one contains 30 000 paint steps But what's a paint step is it that no The browser has to break down The painting into multiple small steps for each step is something like paint a square paint a rectangle paint a circle or paint some text And each cell in steve's app has to paint three things a square for the background There's a kind of hollow square for the border and then some text for the middle and then that creates one cell It's 10 000 cells so 30 000 paint steps and each one of those takes a little bit of time But how could we reduce that? Well, yeah, I guess we could just get rid of the borders and use a kind of checkerboard pattern instead The dragon wasn't wasn't dead, but it was certainly wounded and let's have like a how dead it is Wounded it is not dead Okay Yep, so after removing the borders you can see this kind of checkerboard pattern And there we go. So there it goes again solving it And again, it's a kind of fairly minor improvement, but we're getting so close to 60 fps now that it's going to get harder to tell And it gets 50.1 fps we're only 9.9 off if we round down that's zero That's a 37 percent improvement um But you can see the paint is still taking a really long time. It's still the most thing in that rendering pipeline It wasn't enough to just reduce the paint complexity at each cell We somehow had to reduce the amount of stuff being painted the amount of cells being painted Because whenever one cell got cleared we had to repaint this entire board even even the bits that stayed the same And furious with rage steve sliced the board into many small pieces and suddenly we had html layers So each of these small squares is one html layer containing 10 by 10 things Cells therefore one percent of the board What that means is that if a cell gets changed inside one of these layers We only have to repaint that layer anything that hasn't changed can just be reduced that same painting that we'd used before So you've defeated the unnecessary paint complexity monster and I'm excited for this one So let's see the results of that after adding these html layers I'm going to really regret this never do anything that involves random chat. Look at how fast that is Super speedy, so we've massively sped up that paint step and let's have a look exactly how 60 fps I mean you could probably tell it's like butter, but let's have a look at just how fast it was And you'll probably notice first of all the javascript looks like it's taking a really long time again Which shows you just how much we've zoomed in each of these paint steps is about One percent as big as the original one and there are two of them because we've had to paint two layers So instead of having this massive one that had all 100 layers We've got these two for the two that actually needed repainting Stevie was finally happy. He'd achieved his goal He yoked himself out of that cave of html rendering optimization and he married a princess and they they all lived happily ever after Oh What what's happened? 30 fps he gets in five blocks and it turns out that adding those layers actually made it slower Um, no it doesn't work in five months. Does it have to? Yes, please That'd be great This is what's known as a writing convenience But nonetheless, Stevie yoked himself back into the cave and inside there was a terrifying beast It was chris price And he said You could always just use html canvas and then you'd get full control of that rendering pipeline You could choose exactly what gets painted and it would work across browsers And then it disappeared revealing the even more terrifying beast the evil unicorn of having to use html Five canvas the cross browser compatibility Not very catchy Completely fed up at this point Prince cfw just accepted his fate and he got on with it. Thankfully the app wasn't very complicated It was just a grid every cell was the same size nothing moved around there was no interactivity And when it comes to html five canvas, it doesn't really get any simpler than that So he just did it he graded his teeth and he pulled out his gun and he just shot the unicorn and it was done He'd implemented it in html five canvas He'd oh so whenever a cell changed only that bit of the canvas gets overwritten and suddenly It works in firefox, which I can't show you because firefox isn't on this laptop But you can try it for yourself with the last slide um, so here it is in html five canvas and That did work. It just it got to a point where it couldn't solve anymore. Um We'll hopefully go on where it actually solves a lot so you can see it going And wait at this point you actually can't select the text so Oh, look it's nothing because it is just an image is actually getting progressively painted So there it is running an html five canvas and finally we get 60 fps in both chrome and firefox DevTools shows no paint step up here because it's all being done on the gpu directly So not only is it crossbar as a compatible, but I've made gpu accelerates in mine sweeper Sorry stevie has nothing Does it work in firefox? Hell yeah, it does Thank you for watching and thank you for listening And I wrote a blog post on this and came out on monday It's a little bit more technical if you are interested in that kind of stuff You can try it out for yourself with optimization dot stevenboardman.uk I've got my own name there Um, and do look up the hero's journey because I put a lot of effort into that into making that exactly the same narrative arc as like the Elias Thank you. Does anyone have any questions if you don't I'd be concerned Yes, um, so when you did the step to add the html like the you grouped the 10 by 10 I don't know Yes html layers Was there a reason for choosing 10 like it does it get too complicated if you do like tiny ones? Or is it more is it just inefficient? So I've actually skipped out a couple of steps in html rendering pipeline After painting where we paint each layer is a step called layer compositing So each layer you imagine it's like a 10 by 10 image. We have to combine them all at the one 800 by 800 image So if you have too many of those that steps becomes incredibly slow And I just kind of by trial and error tried different sizes and found that that 10 by 10 worked quite nicely It's also worth mentioning that you're they don't have to be squares as long as they're rectangles I could have had long rows But because our cell generally affects the ones around it in all directions the square made sense to reduce the kind of The number of times that one cell would affect across a layer because obviously that's twice as expensive Yeah Does it work on mobile? It does work on mobile it basically anything that last one anything that runs html 5 canvas will work And I think pretty much everything supports html 5 canvas might not work on the weed browser Yeah, and spelled just works on everything because it compiles down to plain java scripts. Um, I think it's just kind of common script as well It's not like It's not like a more recent one such a book basically on anything Any other questions? Did you try it on GPU heavy hardware as a IPC with No, I think by the time I got to 60 fps I was happy At home I've got a 165 fps monitor and I just flat out refused because at this point I was fed up with mine sweeper But a GPU heavy it probably wouldn't make that much of a difference. You could improve the performance a lot more by So I was using spelled components for each cell Even though I was using canvas. They weren't actually displaying anything They were just sending requests to that canvas just having one controller Which fired the requests and how to solve an old build in would have been a lot faster But I started this project to learn spelled and learn about optimization and it would have been a bit pointless to kind of Strip all that out for the purpose of making it go faster when I was already fast enough The last solution that Worked in Firefox and gave you 50 fps. What does it give you in chrome? The the html5 canvas one that gives you 60 fps in ebbling It doesn't like go up to 120 It probably will but chrome won't render it any higher frame rate than your monitor has So at home I could have tried them a monitor, but I don't want to open that kind of world because I think 60 fps will target 99 percent of people Not going to give myself a word. So it's the bottleneck now that jabs broke? Yes, yeah, I think Yes You totally could And yeah, actually so the While it's running at 60 fps I think that the amount of time that the rendering pipeline takes changes the amount of Steps of solving that it does in each frame So I'm a little bit. I think actually the layers one comes a little bit faster than the html5 canvas one Because it it's a the rendering is faster Therefore it solves it faster because it can do more javascript steps if you don't mind the assembly I'll probably just do it in one step. I wonder if I was just doing it. It's not a very complex algorithm It's not as powerful as a lot of the solvers that exists It just kind of does the basic stuff because the main thing I was worried about was ace felton b rendering Thank you very much