[Music] hello everyone my name is Philip I'm a developer advocate on the floor team and today I'm talking about performance and you know it's funny how like every speaker at a conference like this thinks that their topic is the most important and it's funny because obviously performance is the most important topic today right so but I'm joking about not really because you know even if you have like them the greatest app with best features and great animations if the performance isn't good then that's gonna slash the value of the code the of the of the
top I'm sorry of the app a lot so let's talk about performance today today we'll be talking about some basic terminology and I should profess this this is an advanced all right so we'll I'll start with some of the basics so that we can have the same foundation but if you're new to flutter you should know that flutter is fine it's fast by default if you're not doing something crazy if you're not pushing the boundaries of whether your app should be performant enough but if you do have like a very complex app or if you
do want to go really in depth or if you are pushing further to the limits then this might be interesting especially in the later stage of this talk so yeah so we'll start with terminology then we'll talk about some of the basic tools and basic ideas of performance and lastly and probably more most importantly we'll be looking at a single app and we'll be going through it and troubleshooting some of the performance issues that are there and I will show you like how you might approach different ones and how how you might fix those so
yeah let's start with terminology in keeping with the spirit of this talk all the animations and the presentations are super slow so enjoy alright so Jiang Jiang is something that I didn't know that such a word exists like three years ago and now it's everywhere so suggest that we have the same vocabulary Jiang is like visual stutter it's when you have something that is fluid or should be fluid like an animation and then it kinda stutters or like it skips a frame or two and that just not is it's not very visually nice there is
like it is theoretically possible that your app is slow in its entirety like every frame takes a long time but in practice this most likely is not going to happen and most likely if you have a performance issue it will be jank meaning again something that should have been smooth is not so that's what I mean by jank UI thread at some of you know every application in flutter uses at least three threads UI thread the main one which is where you're building your widgets and which words where you have your main dodge dart and
stuff like this then there's a GPU thread and then there's IO thread and you're not touching those but you can also create your own threads for your own computation the the reason I'm talking about UI thread here is because if you take too much time in the UI thread then your app will jank because that's what flutter uses the that's where the flutter framework is running right so you're a thread tracing is the idea of kinda recording what your app does at what time and seeing like for example how each computation how much time it
takes so on the level of code it looks something like this you can do timeline timeline is a class that comes from dart : developer and it's so it's visible from everywhere and you can say my mind don't start saying and say this computation starts here and it starts or finishes there right you will not be using this too much because flutter actually does this for you in the most important areas so you're fine but but this is how it looks like in in flora code as well and then on the side of that consuming
the tracing the events you will have some kind of timeline and the timeline will say at this point you started my computation and at this point you ended the computation and so therefore you can be like oh so it took like 0.8 milliseconds to do this computation and now I'm I can optimize it or maybe I don't need to because it's fine you know so this this is what tracing s for and we'll be doing basically everything that we'll be doing today is tracing flame chart is basically taking this timeline of events of tracing events
and as you can see if you have a timeline like this it pretty quickly gets very gnarly and it's like oh so what starts where even though there's just two events really in this timeline it's already pretty busy right so flame chart is someone clever some long time ago came up with this charting which is basically just if there's some event that takes some time you will just be like have a little bar that goes from the start to the end and then if there's another thing you'll again have a bar and so just by
looking at this this is like the simplest flames are possible as well this you see that built the execution of built took this much time and during build we were in foo and that took this much time it basically is most of the execution time of build will spend in foo right so that's a flame job this is this is how the easiest one looks like a more normal flame chart that we'll be seeing today looks like this I think it's called flame chart because if you look at it like bottom-up it kind of looks
like a flame but I don't know so flame chart ok and last thing trade off especially in performance that's very important trade off is basically compromise when you have two things that you need to kind of all trade off between so in performance it's often Oh like on one hand I warned my app to have a thousand particle effects every time I do something on the other hand I don't want people to have bad performance or for the app to consume too much battery and resources right so and there's a trade off and you have
to choose and there's never like this they almost never an easy solution you you have to compromise another classic trade-off is CPU versus memory so if you aggressively cache then your CPU will probably save some CPU cycles but on the other hand you will need more memory so that's a trade-off ok so we're at tools and basics and I will skip that all right so if I come to you and I say let's profile this app and you see this you should be like screaming and and there should be riot here because of two things
one debug mode never profile in debug mode debug mode is by default is much slower than proof and production mode it does not have any relation almost to the actual performance of your app so never do that second this is a simulator or emulator again emulator is not indicative of how your app will actually look like when you run it in on a real device so if you do profiling do it in profile mode and do it on a real device another basic thing it's just it's kind of obvious but avoid work in the UI
thread you can completely avoid work in the UI thread because then you don't have an app but but like if you can make stuff either go to a different isolate meaning a different thread or if you can just I will show you some ways to you know don't rebuild widgets that you don't need to and stuff like that also minimize use of expensive widgets I will again I will tell you later what these are these are things like backdrop filter and stuff like this that doesn't mean that you should not use them at all but
it might mean that you will be more you know intentional in in using those some tools so there's performance overlay some of you probably know this this is where you ask for r2 on top of showing the app itself also show how long each frame took to build and there's at the top there's the GPU time and at the bottom is the you item then there's the track widget builds which is something that is currently I think only in Android studio I will show you how this works later but it's a really good way to
kind of get an idea of how much you're rebuilding everything there's dart dev tools which is kind of this up-and-coming suite of tools that help you optimize your app it's it's some things aren't not yet ready there but it's it's definitely getting they're very fast there's also observatory which we'll be using today which is this like older tool for not only performance optimization but yeah it has a bunch of stuff and the last tool I want to say is sometimes instead of looking at just metrics it's nice to look at your app in slow motion
and for that because like you know our eyes aren't perfect and so sometimes we miss some of these skipped frames so it's nice to have a recording of your app in slow motion the good news is that if you have a mobile phone that was built in the last few years you know days you have a high-speed camera it's like on Android you just go like to video and you have some something called a slow motion motor I think and then that creates this kind of stuff and this is eight times slower than real life
and so if you have a chanc there you will definitely see it here there's some checking this works okay so that's today and now let's go live profiling but before we go there I have to give you some introduction so I made this app which is like really terrible basically everything about is terrible and you might be thinking but Philip all your apps are terrible huh that's what's you and and I say this is intentionally terrible because I want you to to see all all the things that can go wrong right which brings me to
this and this talk if an performance issue is the proverbial needle in a haystack this talk is like this like Oh where's the needle you know it's not worry the haystack in the real life it's like this and it's like oh you have up to ten thousand needles in the haystack go you know so don't think you know don't think this is what you'll see today is indicated of actual you know work with with performance on the other hand if I didn't do it this way if if I had a more real app this wouldn't
take like 45 minutes to take 8 hours and we would be kind of going through a lot of code that has nothing to do with performance so so this is I think better another caveat like if you like me after this talk you will go to your app and try to optimize everything and that's not a good idea please don't prematurely optimize only optimize things when you actually know they are a performance issue which you know it's just a good thing and that also means measure if you have an optimization problem that you like a
first you have to look at something like the timeline view or something like this to see oh that is actually optimization I'm sorry performance issue and also if you do some do some optimization measure before and after to see what you actually achieved so maybe you will make it a little bit faster but you will also make your code a lot less maintainable and if you made something 1% faster for you know and it's just again trade-offs so measure I actually if you want something like continuous measurement then I wrote this article last year that's
exploring this so if you're interested in that you can definitely read that all right so finally we get to the actual part where we go and run the app so I will flutter you can you see this yeah I should probably look at this so what do you see here is this real device it is just going through here and so it will probably not be 60 frames per second but whatever so you can do further around - - profile which will run it in profile mode and for again this is an advanced talk normally
you wouldn't do that but you can do also - - trace yeah which gives you a lot more information about what's happening in the GPU threat we'll use that later so I do this and then we wait that's the bad part about performance optimization you don't have hot reload because you're in profile mode so stuff takes time okay so we have this app and basically how it works is it is always like - it's like every third page in this page view has some performance issue not this one this is just the Welcome page and
so we'll do some stuff so we're we we ran further on profile and it's as you can see here it tells us Oh Observatory debugger and profiler is on this dress so we'll open this address and that's the observatory that gives you a lot of information but today will be only looking at this the timeline okay so this is the timeline that's a pretty small resolution that's going to be fun and then we I just tapped the fluttered developer profile which is just you know doing some presets for me and now if I do some
things with the app I can refresh the timeline and then I can just go around and look at what's what's happening here right so I can I can zoom in on all the things and we'll will see later how you know how this all works so that's the timeline and that's how it works then you can also see here for detailed help message press H so that's what I'll do and it will give me among other things tip - I can show the performance overlay by hitting shift P which I'll do now so you can
see here now I have a performance overlay okay so this is as you can see if if if it's down that's fine because then we have we didn't skip any frames which is cool and the next one I want to see by the way you can do all of these things without using the command line right like you can if from an Android studio you can run your further flutter app in profile mode that's that's cool but what you can do as far as I know is do this enabled timeline events for all widget build
methods and that's pressing a so that's what I'll do now you can't see any difference but later in the timeline we'll see a lot more detail so if you I can again advanced like you probably don't need this normally but if you really want to go inside and just do this okay so let's go and explore the app so we have these two kind of dummy page views just so that you can see how it should look like and then if I go to the next one you will see a little bit of Jack hopefully
I don't know if you saw that but you definitely see this this right here right this took way too long for one single frame I'll do it again and this one this time I will clear my timeline so that I don't have don't have a lot of stuff there and now I do Dean and it's still a lot of time so I refresh and I see a bunch of stuff here and the gpus isn't really interesting for us now but you can see there's so this is a timeline right so this is time these are
the frames and that that's a lot of things happening here this was one of the script frames and as you can see okay so blue page took a long time and there was a lot of building here and just a bunch of stuff was happening so let's look at the code so we're in blue page yeah we are there okay and so this is just a regular status widget there's some rounded cards which is this thing and then there's a list view that has 10,000 items in it which we built immediately and it's not just
that we're building 10,000 widgets we're actually calling this method 10,000 times and this method creates one two three four five six seven eight nine widgets so it's 90,000 widgets in this one frame that were created right that which is not great and again haystack you know that kind of thing like that you would normally not see something like this but this is something where a you should probably use ListView builder here instead of creating the whole Long's you know list of widgets in one go and also even if not if you have something this complex
nine widgets inside of padding and stuff like this maybe you want to create your own stateless widget like you know I'm not going to actually do this but you could just say you know what this all goes here right and then here I just in this place I just do like you know my widget and suddenly it's still not great because we're used we are creating 10,000 widgets here but it's just 10,000 widgets and not 90,000 widgets all right so let me do that let's go to different failure here so let me again clear this
so that we don't have too much happening there and go here okay Wow another big spike here so what's happening here again we can refresh and we can see what's what's going on and again we see this huge thing happening here and we see okay so a bunch of really long built methods where we're done and this is a little different so what's happening it's yellow and we see this is not the same case like we're only doing a little bit there is not actually ten thousands more like a few and where we're doing a
little bit of these and if you look at the item line it's not really it looks at least in first for first time it looks pretty okay right like just a container with a row and expanded why is it taking so much time to to belt and so we could look at the code but let's do it through here one cool thing that you can do in the time line is just selecting the whole thing if I can do that damn it Wow what's going on I'm a goat I may need to go to like
a full-screen view I normally don't have it in this small whoa Wow did it ask for em yeah let's let's try again so BAM and refresh oh yeah that's okay so if you select a bunch of stuff in the timeline you will get these things at the bottom and one of these is samples which is basically like where did at different times at what well did we spend our time during this this time Terry terrible English Wow anyway so we have with see things like draw frame which is not really that interesting that's that you'll
see that everywhere truncated is just that that part the that method was truncated the name was truncated but you can see you know again not very interesting but we see we spent a lot of time in something called Fibonacci hmm okay so let me just go back to can i okay so let's see is there a Fibonacci here oh yeah and it's it turns out that there's a number here which is actually a Fibonacci number which is computed in the least efficient way possible which is our problem here right and so we might a we
might first ask why we do like why do we have a Fibonacci number there but we all can also make it a little more efficient we could also as I showed you before we can be like timeline import this from dart developer start saying and something like you know make subtitle and then do timeline finish saying and now if i I don't I'm not going to do it now because that would take too much time but if I read like finish the app and like do further round again now my time when I would have
this makes a title there so so I could actually see and measure how long it took and I could be like okay to make this much much faster but in this case why do we have a fibula here okay so let's go somewhere else and do another one oh this is actually there's another thing so here we have a functionality super important we have a lot of items here that we can scroll through and then we can tap this and it will rotate and you can see that's pretty terrible so what's happening down let's look
at the code so this is green and if you know a little bit about animation builders and animations in general you almost immediately see the problem here but basically it's we have an animation builder we have the rotation animation and then we have the actual builder callback and in that callback for every frame we are creating transform rotate with a current value and then we're creating this ListView with 20,000 padding's and texts inside right not great so and again we could look into the timeline and it would kind of give us that thing there's also
this functionality that I wanted to show you which only works in in what do we have which only works in debug mode and I'm not going to go to the macro now but it's if you if you are in debug mode and you go to flutter performance you at the bottom you have track widget rebuilds and now whatever you do with your app in real time it will show you in the last frame how many times did we did any of the widgets on the page be rebuilt so in this case like I can click
on here and see like Oh last frame so every frame we're building 19 of these text widgets which is probably not what we want we we're only rotating stuff but we don't want to rebuild the whole thing every time right so this is this only works in debug mode so again what we want to do here is we want to use the depend of the child builder pattern here so all of these animated builders and lots of other widgets coming with footer I will have this what they they will give you a context and they
will give you a child the child is a widget that you can kind of give it here so I have a child and I'll put all of this here because we only really want to build it once and then as we rotate that that's just we just want to build this transform rotate widget and now this child will always be this ListView right so we now instead of doing it every frame we're doing it once at the start and then we're just putting the child here you'll see this a lot this is why you always
almost always have in these builders you have a child and this is why it's a really good idea to use it again if we if we compile the app you would see that now it's it's not as terrible as it was before okay oh yeah so now you see it a little different issue and that is mostly in this area oh we do don't you don't see any issue okay so you see a bunch of stuff at the top which is the GPU thing let's look at the timeline if we may up a refresh hopefully
we'll see it yeah and you see a bunch of stuff is happening here you see things like upload raster image this is skia like create texture right pixels a bunch of stuff that is happening here outside the main set thankfully but still you know even the GPU thread can make your app jank so what's happening here we're in I think this is orange yeah so this is just well again a ListView with some small avatars of my face and you can see okay so this is like 70 times 70 pixels and we're using these assets
right so let's look at the assets assets Philip Wong Wow three megabytes lots of pixels and then we use let's let's not do that and then we use it for 70 times 70 not great so just by looking at this if you see graph like that Andy and if you look at the timeline and you see stuff like lots of things happening here like concurrent worker image from compress data that is basically the tracing telling you hey like I'm doing a lot of stuff with images here so you want to in this case the the
easiest solution would be to provide a thumbnail image that is actually you know 70 x 70 and so we don't spend all this time like decompressing the image while reading the image 3 megabytes times 5 then decompressing it from JPEG and then making it small and putting it into a all thumbnail okay so let's go to the next thing oh so this is fine right but now if we compute you see terrible terrible jank there and you know the Chiang is like I can do whatever I but it will just be unresponsive so what's happening
there again we could look in the timeline and I can promise you you would see a huge chunk of something in the UI thread so let's look at pink and so here we see so what's happening when we tap the compute button we are starting some computation and this is this is just for show basically right first we set state the result in now so that will show the little circular progress indicator then we delay for 200 milliseconds so just so that you see that little like start of the progress indicator and then we do
something again and fibonacci and and then we delay again so that you see that the rest of the animation that the reason I do this is because if I if I don't have the this and this then it would just like it would just Jiang it would just not do anything and it would show which which doesn't look like it's checking but as you can see it is actually changing so in this case the D the obvious solution is to not do Fibonacci in the main thread again but this looks like we're actually using it
so what you can do is the probably the easiest way to create a new thread and in the thread do some computation is to use the compute method so that's something that father gives you and that's just a method coming with I think for a foundation and it will take a function and some data and it will you can await this and it will give you back the resolve what would it does on the you know at the big round is it will actually create a threat for you and it will run this in that
threat this will not make the computation faster of course because you like first have to create a threat and then you have to do all this stuff but it will not block on the UI thread which is what we want okay so again if we recompile now this would this would still take some time but the circle progress indicator will just continue running okay oh so expensive widgets here you can see you know a bunch of stuff that is let's see the timeline so refresh and you can see the GPU thread is busy and it's
busy with things like and again this is a lot of stuff but drawbitmap there is probably there is shadow somewhere around here and wow you know and the thing is the reason for this is that we just edit this is brown eye thing which is added shadows everywhere like every text every grille glyph in the text has a little shadow which kind of you know underlined said and stuff like this so this is just like us being a little weird and we should probably think about like maybe not having this many shadows everywhere right it's
still fine it's this doesn't actually jank but you know don't do that oh talking about expensive widgets this is blur so I think it is Antigua yeah oh yes so this is backdrop filter so whenever you have backdrop filter if I rotate this you know terrible and this is because basically what photo needs to do if you do something like this is it will need to like layout and render everything below the backdrop filter and then it will take it and then it will go through some you know filter imaging and stuff like this so
again this is probably better if you either don't do it at all or try to do it in a different way does not mean that you should never do a background backdrop filter but maybe don't do it like on every frame from scratch so that's another one and then I do still have time this is a different kind of issue and this is basically memory so we've been talking about GPU and CPU what about if you have a leak or something like this so in this case we'll don't actually have a leak but we see
that for what is this it's actually you know doing quite a lot of stuff and let's see if I can show you let's see I will need to run dev tools from here and open it here you normally don't need to do this because theft tools is accessible from an IDE but so just ignore this and let's go to memory if I can hey okay and so what's happening here is you can see like we're not actually leaking memory because it's a the top line the capacity line isn't going up but we're doing a lot
of this like oh we're creating a lot of new things then we're clearing that and again and again again if I do a snapshot here it will give me like where are the most you know kilobytes and row what would are we actually but do we have in the memory and we see immediately that hundred and eighty three kilobytes at that exact time was was taken by date format and date format is not something that you should have two thousand off so let's see what what's happening there we can go to line and we see
that there is a timestamp so for every of these little events we were creating a timestamp and for for it to work we need some kind of date format that we will then use to kind of actually show the formatting but the unfortunate thing is that as we create each of these timestamps this is an instance field on the class so every time you create a timestamp you will also create a date three date formats for each of those which is probably not what you wanted so in this case just making these static is final
instead of like two thousand of these you just have three and so we fixed a problem all right and lastly but no please let's talk about how things look like so we without telling me I have a look at this and think about what you think is more performant or faster a or be faster mostly so well I see it's actually pretty janky on the on the screen but not not in my in my app so is it a is a faster or is be faster right so it was a trick question of course because
they both are the same length they both take 300 milliseconds to complete but B definitely seems faster and this is just because of the curve that I'm using so this is a linear curve this is the default this is the I think this is cubic is out and that's all it takes sometimes so there is no performance issue with a but a kind of feels sloppy and slow but B feels fine so experiment with the curves a even just that can make your app look a lot faster or and a lot just more responsive that
I think concludes what I was trying to show today if I can go back to these ok all right so we talked about some terminology we talked about some basic tools and life profiling I want to again say by default for it's fun and it's it's fast enough but if you really want to push it you might want to look at these things that I've shown you and I don't think we have time for questions we have one minute but anyways thank you for listening [Applause] Thanks [Music]