hi my name is John peppers and I'm an engineer on net for Android and net Maui and what I want to share today is this is just kind of a example of how I do performance investigations um so that could mean something slow that could be a memory leak um so I'm going to show how I I do that and just some general tips for for performance um this was a talk that I gave internally it just on teams at Microsoft so I felt like this is something that you know I I could record myself again and hopefully it all works in one uh one shot I just press record so we'll see how it goes yeah so let's say you have the problem of my app is slow or I have a memory leak or you know so forth um there's a couple things you could check first um we'll go through those um I'll show examples of how to profile an app I I'll do it from scratch with a project template and I'll do it on Android because that's the more complicated one and I'll show all the commands to run and so forth um and then I'll give some examples of uh some zaml that might not be the fastest option so so before you do anything um the first thing you might check um if you feel like your app is slow is it slow in release mode right uh debug mode has a lot of settings that are enabled for productivity like hot reload but they actually can make General code in your app slower than it would be in real life when you go to uh distribute your app uh so for example um the setting use interpreter true it's it's on by default for debug and that enables C hot reload so you could change like a body of a method and you click that little fire button in Visual Studio or and now VSS code has it too um and that will reload your code live uh but that enables the mono interpreter that is actually a bit slower in running code generally um same with uh zaml hot reload it actually parses the zaml um when in debug mode when you when you have this uh zaml hot reload enabled um and while in release mode it will like precompile all the zaml so there's no parsing happening um so that's another reason things can be slow so also check you know if you haven't tested your app on a physical device and you've only been testing on a simulator or emulator um physical devices tend to be a bit faster because you know a they're not emulated but they also uh have Hardware acceleration for you know what's happening on the screen while many times uh the simulator emulator are not Hardware accelerated um and then if if you you know there's a link to check here if you've not seen akms profile hyphen Maui that has a lot of details about this stuff at the top um and it has links to how to profile and other things um and if you do find that you know hey this thing is slow and it you know you're using a particular feature of Maui and it's slow and you don't think it should be you know file an issue like make a sample you know that will help us you know improve the product in general so let's talk about the different tools you might use uh here's here's an example of some of the problems you might encounter so let's say your app launches slow and and you want to speed that up you know that's more likely to happen on Android I think um and so you could record startup with net Trace uh in suspend mode um and you know another idea or another problem might be there's a particular screen that's slow and so in that case you you don't need to record startup you need to record just that screen so you might use no suspend mode and I'll talk about what that means uh but suspend in general when the app launches it will block and pause until net Trace attaches and and I'll show an example uh same thing with scrolling you would want to just attach doet Trace like while you're scrolling and then stop it and then look what happened um and for a memory leak you'd use a completely different tool you'd use net GC dump and I'll give a Dio of all of these in a minute now if you're fortunate enough to have the problem on Windows it's actually much easier to uh get this information you can basically just open Visual Studio and just clicking a few buttons do do everything you need to do right you can go to the uh diagnostic tools menu and there's a section called CPU CPU usage which kind of is the same information is net trace and then the memory usage tab has kind of the same information that net GC will give you um and so if uh try this menu first it's pretty simp easy to use you can just click and do what you need um and then you can even save the files out if you need to attach those to an issue or get you need someone else to look at what's going on that that's what I I would do um but the problem like why mobile is more complicated is just generally like we don't have uh the ability to push a button in the IDE and do all the stuff for mobile yet that's something that we would like to happen in the future hopefully someday we can so let's talk about how you set up on mobile uh there's three tools uh GC dump donet Trace we've already talked about and then this third tool is is DS router um in general what it does is um it will talk to a remote process on a mobile device or emulator or whatever and it will kind of forward the profiling or tracing information uh from that device to net Trace running on your desktop um and generally it takes a couple terminals to set all this up and I'll show how to do that um and and while tracing the types of files that you'll get there's a couple different types let's just kind of go through them um a net Trace file is is what net trce creates by default and you can open this in Visual Studio or per few on Windows if you're on a Mac or Linux desktop you might want to use speed scope instead uh and then there's just a website speeds scope. apppp that you can open uh the apps or sorry the traces in and it I also think the speed scope is is generally pretty good at showing profile information so I I use it um probably the most out of some of these tools but um and then a GC dump file um you can record these on macro Linux but as of right now the only way to view them is to open them in Visual Studio or perie on Windows um I Heard a Community member was working on some kind of Mac viewer thing uh or or some way to convert it to something that you could open on a Mac but that we don't have that quite yet maybe someday so let's do a demo um so I'm going to do everything in vs code just um just to make it easier so I've got the terminal the code everything right here but um you could do this in any terminal you like any IDE you like I'm not going to do anything particularly special here um but let's just start out with creating a project I'm just going to do net new Maui um and then let's configure a couple settings so I'm going to open the project and and a lot of these are for convenience so you might do this temporarily to help trace and then undo everything I'm about to show here but uh I'm I'm just going to mainly change these settings to make my command line commands easier so I'm going to do a single Target framework and what that lets me do is uh not have to pass dasf net 80- Android on every command um so of course you know that's optional and then the first thing I need to do um is actually enable the profiler android enable profiler oh and what that will do is it uh when I build the project it'll actually add the mono diagnostic component to the app if you if you miss this step um basically none other tracing will work because there's no the tracing infrastructure isn't in the app um so this is pretty important um and I'll have some links in case like you get lost or you want to read to follow along I I'll pull up the doc in in just a second but the other thing I'm going to set is I'm going to set a runtime identifier to actually Android arm 64 and that'll just prevent uh the build from uh building for four architectures and this is just for me waiting on the build just in a minute this so this is kind of optional but um that way it only run the at compiler once um and then another setting this is also optional um but I'm going to set the Android package format to APK just because it will do app bundle by default and that's a bit slower um app bundles generally are a bit slower to build all right so that that's all the settings we need so let's also do one thing in the app to make it slow so I'm going to open the main page and then I'm just going to go uh I'm just going to go here and let's sleep for one second yeah um just trying to put something that that'll take time in that did I spell it right I spelled the thread twice that looks right uh I don't know if I have if my C dev kit working yeah let's restart it I don't hey it colored well anyway hey that looks good is it is it working uh yeah wa oh it's it's loading but anyway we can we can move on we don't have to wait for it um so now at this point uh I've got a device attached and this is actually a device is plugged in and I'm showing it on my screen with a program called visor um you could use an emulator but I just wanted to show the real deal and um it's also a little more complicated to do set this up for a device um so let's just build the app in release mode and I'm actually going to do run the target run and while that's running we can actually set up DS router um so I can doet DS route oh well you know what let's let's actually pull up a Doc before I do that hold on so akms profile Maui will take you here um and one of The Links at the top is the Android profiling documentation I recommend following along there if you in case you miss a step or whatever it it also explains like how to install the tooling so like before you do anything you've got to install these three Net Global tools you know Trace router GC dump and then you want to make sure you have at least an 8. 0 version of these tools um this also you know everything I'm talking about here is on this doc if you miss something or you know Miss a step or something like that um so I've I've already got the three tools um so I can just run netds router and then the subcommand I want to run uh you could run Android D emu for emulator um but if this is an Android device so I'm just going to run Android and it'll kind of print out a lot of information um but one thing to note when you do this for a device is that um it's going to listen uh the app is going to listen on Port 9000 butet router is listening on [Music] 90001 um and so we got to run a command to kind of connect those two ports together or or none of this is going to work um so let's open another terminal uh and it's in my history but ADB reverse is going to to hook these ports together basically um so the the the local Port I think 9,000 the Android app will talk to 9,000 and then um your desktop will talk to 90001 and this is kind of puts them together uh and it if you're on a if you're doing this for an emulator uh you can skip this step because it it it's all on the same machine um okay so that's hooked up um um and the app I saw it launched yeah it launched over here um so the next thing that we need to do um it tells you about this setting net diagnostic ports right and so this is an environment variable and you could set an Android environment variable um but it requires you to rebuild the app and you know so forth so we actually have um an Android system property that you could use instead um so I'm going to copy this value uh it's called debug.
mon. profile and I'm just going to paste this value in so ADB shell set problem debug model profile and so now when the app launches it will see this setting and act as if it was profiling um so I'm actually let's do no suspend instead of suspend and I'm going to close the app and we'll relaunch it so we can kind of see that suspend working um did not work oh dear okay so um what I forgot to do before is actually put it in suspend mode and what that will do is the app pause on it splash screen waiting for net Trace to connect um so we're going to set it suspend mode and then we're going to tap the app icon to launch it uh and it's going to block there um and then we're going to copy this net Trace collect command that was printed out and then we're going to say- format speed scope that's the only change um and so it recorded the app and the app launched so we can made here and then we can just kind of press enter to let net Trace write out its files um uh and I've got a couple extra files here these these two look like they're old didn't work um but I'm going to open Speed scope. apppp um I use the website it it's not uploading anything anywhere it just kind of opens the file locally in a viewer so you can get a speed scope command line tool I think it's an npm package or something but um if you'd rather type speed scope and then the path to the file you could um and then I'm just going to drag and drop the speed scope file um and so this is the default like timeline view and you can kind of zoom in um you kind of get this nice Jagged graph of what happens over time um and then the other thing that you can do is press this left heavy button and so because we're interested in like basically just startup time and that's all be recorded the left heavy button is pretty useful in that uh it's going of kind of add everything together and show us what the slowest thing is and unmanaged code time that's the biggest bar here because there was just several seconds where I didn't hit enter fast enough um so you may want to zoom in just like that um so we should be able to scroll down here and we can see that the slowest thing is this thread.
sleep call that is inside the main Pages Constructor uh which is the thing that we put in here to be slow on purpose um and let me actually Zoom this so that we can see it yeah yeah yeah there we go that looks good so 1. 01 seconds uh 15% of the total Trace time so that sometimes the percent uh isn't important in this case if I waited longer than that percent number would change so it's kind of like the walk one second time is more important here um so yeah uh another thing another way to search is you can do the sandwich View and this is a list of every method that was called um and this is a sampling profiler so what that means is uh the way it works is every so so many times a second it records what method is in the middle of being executed right now um and so these numbers here aren't exact times it's just uh how many times was this method actually in the middle of running while we record it uh and it and you know the numbers here will be a bit slower than real life because the act of measuring performance slows it down a little bit um but once you're in here we could sort by the total um and then pretty easily we kind of get down to the main Pages Constructor and on this side we can let me zoom in again you can see that thread. sleep is the actual culprit um so one thing to notice is when the bars are are like almost extremely wide that means that this is the thing that still took the most time so um so let's say we wanted to do something else um so that was an example of startup um but what if we wanted to measure something like a something is slow right so let's put this thread sleep in the button click event and then let's deploy the app again and actually let's change uh change it to no suspense now um and let's build the app again um so this is app's deploying again and so what we're going to do is uh we're going to run the app uh we're going to attach doet Trace after that has launched we're going to click the button a bunch and then we're going to stop the trace and then see how that Trace compares to the other one we just like look down uh so it'll take a bit to build I'm building a release build so it's running the aot compiler on apparently 76.
net assemblies but yeah it's already done um so the app is running uh we should be able to just kind of hit up hold on let me get on the right uh and then collect a fresh speed scope so I'm going to do that it's attached I'm going to quickly I'm going to tap the button over here I can tell it's slow um and then let's stop the trace all right we got a new Trace um so let's open a new speed scope and it's this one is that right yeah okay yeah so if we look at the timeline view in both of these um you can kind of see that like the startup one has these irregular Jagged Peaks um that's kind of what it things are going to look like as you're um loading screens but in this case we're tapping a button over and over and it's so the same thing is happening over and over and over so if you look at a a trace of like scrolling it may look like this but maybe the bars are really tight really small um but this one you can do left left heavy is even more useful in this type of Trace where you've only recorded it for a few seconds and you made the slow thing happen by tapping um you can see pretty easily left heavy oh well immediately thread.