 On today's Visual Studio Toolbox, we continue looking at the profiling tools in Visual Studio, and Sagar is going to show us how you profile asynchronous code. Hi, welcome to Visual Studio Toolbox. I'm your host, Robert Green. I'm guest hosting today, filling in for Leslie. I'll be doing this from time to time. It's great to see you all again. Today, my guest is Sagar Shetty. Hey, Sagar, how are you? I'm doing great, Robert. How are you doing? Excellent, excellent. We are continuing our deep dive into the profiling tools, and today, you're going to tell us all about the .NET Async tool, which gives us the ability to profile asynchronous code. Very exciting, which I think that's interesting because async code works a little bit differently than sync code or regular code or however you want to call it. Yeah, absolutely. Robert, I thought it would be a good idea to start with establishing a foundation for what even is asynchronous programming. It's a buzzword you hear a lot of the time, and I think a good way to think about it is to use an analogy. But first, at a high level, what asynchronous programming is, the basic idea is you can run multiple tasks simultaneously, and there's a few caveats here, so long as the tasks don't depend on each other and so long as the tasks don't share the same resources. So let's use an analogy that helps simplify this a bit. I think cooking and baking and being in the kitchen in general is a very popular analogy for asynchronous work because let's just say we wanted to make some breakfast and we wanted to say, fry some eggs, toast some bread, make some toast, and pour some orange juice. If we go through a quote-unquote synchronous workflow, essentially what that would look like is maybe we take out a frying pan, we fry our eggs, we do nothing but just stare at the eggs while they're frying, and then once that's done, we move on to the next task. So maybe we throw some bread in the toaster and make some toast, and then we do nothing while that's toasting and then once that's done, we pour a glass of orange juice. Obviously we know if you have any experience cooking that you don't necessarily need to wait on one task to finish before you start another one. So asynchronously what that might look like is, okay, you take out the frying pan, you put the eggs in, and then while that's frying, you go ahead and put the bread in the toaster and then while that's toasting, you just pour the glass of orange juice. And so instead of taking 10 minutes, maybe it takes three minutes. So the reason why you can do these things asynchronously in the our analogy is one, tasks don't depend on each other again, that's point number one. So you don't need fried eggs to make toast. And two, you're not sharing the same resources. So in the cooking analogy, that would be like, you don't need a frying pan to toast bread, you need a toaster. So they're using different tools. So at a high level, basically the point is you don't want to be sitting around waiting for tasks to finish if you don't need to wait on them, right? And computers kind of work the same way. Computers are composed of threads, which are kind of the cooks in the kitchen if you will. And the computers that, you know, even modern computers have, you know, hundreds of thousands of operations that they need to execute even a second. So these are complex mathematical computations, all sorts of database calls, reading and writing text files, setting of clients, et cetera. And if we were sitting around doing everything synchronously, waiting for one task to finish before starting another one, things would just never get done, right? And so kind of the big takeaway here is that this asynchronous framework and programming is very much ingrained in ASB done at core in a lot of modern frameworks. And it's for good reason, right? It's because essentially what you're trying to do is increase the throughput of your application and increase the bandwidth of what you're capable of. And so yeah, that's kind of asynchronous programming in a nutshell and the async tool, which is kind of one of our many tools in the profiling suite is a tool targeted towards kind of getting a better understanding of asynchronous tasks in your code. Is this a new tool? Has it been around a while? So at this point it's been around for a few months, probably close to a year now. I mean, time flies in today's day and age, but it is a relatively newer tool. And one thing I'll stress is that it's still very much a work in progress and I'll allude to some things that we're doing to kind of develop and refine it. So yeah. There's always many people's understanding of asynchronous code in the first place. So I guess that works, that matches. Yeah, exactly. So asynchronous call a web API, but there's more you can do with it. Yeah. Absolutely. And C-Sharp and .NET definitely has quite a lot of support for asynchronous. I mean, like I said, it's very much baked into the .NET framework. We have the async and await keywords, but like you suggested, Robert, it is more than that. It's not just using a few keywords here and there. And hopefully our profiling tool, the async tool will help you kind of detect and optimize issues with your asynchronous code. Let's see it work. Yeah. So let's just jump straight into VS. So I have a web application here. Shout out to our colleague, Mark Downey on the production diagnostics team. Hopefully we'll be seeing him in a future episode. But yeah, so we have a basic ASP.NET Core web application. And so essentially what's happening here is I'll go ahead and launch the profiler summary page. So that as everyone is probably memorized by now, it's kind of the alt F2 shortcut. And we have our summary page. I have the async tool selected. I also have the CPU usage tool selected. So we've mentioned this in the past, but one concept within the profiler is this idea that you can use multiple tools simultaneously. And hopefully by the end of the demo, I can at least allude to or at least showcase a reason why you'd want these two tools in particular paired together. So we're going to go ahead and start this. And so this is going to start. This is going to launch the web application. And so I'm going to go ahead and record a CPU profile. So this is also collecting the CPU data that Esteban had kind of talked about in an earlier episode. If we go back to, in fact, let me grab a URL real quick. So this is essentially how I'm going to generate a payload within this application. So this app is not necessarily meant to be this kind of crazy end to end experience. It's more just to kind of operate with a few interesting asynchronous functions that you'll see in a second here and just give us some data to kind of highlight some of the insights that the async tool provides. So I'm just going to spam this. I'll show you what this is doing in a second, but essentially it's just triggering reading from a text file. And then we're going to stop collection here. So this is going to load. I've actually prepared a data set ahead of time, but that was kind of the workflow of what you do to start this up. So now let's kind of dig into the async tool in particular. So we're looking at the support, Robert. We've got a couple of columns here and I want to start the far left with the name column. So we kind of talked about at the heart of asynchronous work are kind of different tasks operating simultaneously. And in a lot of other profiling tools, we have this idea of kind of a call stack or kind of a function calling another function calling another function. In the async tool, we have this name column each of these nodes corresponds to a particular task. And these are, you can think of these as task chains, if you will. So task calling other tasks, calling other tasks. And tasks are generally generated using the async and await keywords in C sharp and dot net. So we've got different task chains here, different tasks that are happening. In addition, some tasks happen multiple times. So we have an account that's kind of keeping track of how many times we saw that task occurring and executing. In addition to that, we have some timestamps. So we have the start time. So this start time corresponds to the first time we see the very first instance of this particular task occurring. The end time corresponds to when we see the end of the last instance. So there are four versions of this particular task. So this is the end of when the last one ended. And then this total time is not necessarily always the total time elapsed over the course of all four but just the average time for each given one. So we've got a few high level metrics here. And in general, what's I think interesting with the async tool and the kind of metrics you wanna hone in on our count and then total time. Because we wanna see essentially tasks that are really holding up our thread pool and not allowing us to progress further. So either tasks that are happening a lot or tasks that are taking a long time. So if we start to kind of dig into some of these task chains here, this one looks interesting because it happens 22 times. And in general, it seems to be taking a bit longer. So let's look into this. And this was also the same payload I was generating using the sync over async result task. And so this is the top level node. And now I wanna dig into this a little bit more. So first of all, I saw that that task, this top level node was in general, taking more than a lot of other tasks. But when I go into it and see the task it's calling, we see some more interesting information. So for example, this task that delays taking way, way, way longer than all these other tasks. And so this is something that we would look at and I'm gonna go to the code in a second so we can see exactly where this is in the code. But this is something we could look to potentially optimize because this is taking way longer than other tasks and odds are, and in this case it is, it's kind of holding up the thread pool of it. And so this task is getting away. This is the average over the 20 or so times it ran or the total over the 20. This is the average. Can you tell the individual ones maybe one of the 20 took way longer but all the other ones worked well? Perfect segue Robert, I really appreciate that. So as we kind of, we did, we did it. So as you dig into the nodes, you can go into more and more details views. So in this case, we'll keep going to task.delay and just as you suggest Robert, we can go into individual instances. Two things I'll call out here. One is we have a bucket, so there's 22 of them, 17 of them are classified as within normal variance. So they were kind of close to the average. And then we have some outliers. So these outliers might be really interesting, right? If there was one particular example that really stood out, we want to look into this a bit more. Of course, we can also see just the normal variances as well. And for each of these individual instances, we can also get all the start time, the end time, and then it's total time. So you get all that great. One of them was horrible and the other 21 were fine. It's just an anomaly, something to look out for, but you know. Yeah, absolutely. And another thing I'll say, and this is, I kind of want to emphasize, going back to something I said earlier, this tool is still very much a work in progress. And something that you're going to see in the next couple of versions 16.9 specifically is what we're kind of aiming for for a few updates is the idea. So in previous episodes, we've kind of talked about the swim lane up here and you can kind of time filter. And as Esteban mentioned in a previous episode, if you're running multiple tools, so we do have the CPU usage tool up here. If you time filter on that swim lane, it will filter down the time across all the tools you ran. So in particular, Robert, like let's say you were interested in this particular task delay because it took a lot of time. Right now, you'd have to manually kind of find these timestamps and filter that down. In the future in 16.9, when you right click, this button's not shown here yet, but we will have like a time filter by this specific range. So for this specific task. So then you can be able to then go to say, the CPU usage tool and do a deeper dive of, hey, okay, so this one task instance was a bit off. What was going on in the call stack here? Like what functions are being called? What hot paths were being triggered here? So then you can do that deeper dive because the async tool is a little bit more surface level, but the CPU usage tool is more of that heavy hitter. So that's kind of how our tools are kind of playing together a bit. All right, so kind of last thing I wanna talk about here is ultimately going back to code. So we talk a lot about with a lot of different profiling tools that at the end of the day we wanna optimize performance and we want to bring you the user back to your own source code that you can actually manipulate and change to help optimize performance. So just wanted to show that here. So with the async tool, we've kind of been going through this view. We've kind of seen that this task that deleted task is a bit problematic. It's kind of taking a lot longer than other tasks. Symbols are not being my best friend today. So normally you'd be able to go to source file. I have the code up. So I'll just navigate to the function manually, kind of going through some of the code here. This was the URL that kind of generated that payload from before and essentially we kind of come into this particular method sync over async result and essentially what's happening every time this is hit is we're reading from a text file. And there is a read text async method here and I wanna go into that because that will be particularly interesting. And now once we go into this particular asynchronous task we see that there here is the task delay within that asynchronous task. And to be honest, Robert, like this task that delays sort of a placeholder you could imagine, I mean this just as easily could have been some sort of call to a REST API or database. It's very realistic that some other call could have been here that would take three seconds, whatever, however long. And it's important to note that in this case, this task that delays kind of holding up everything else. So this is kind of written in a synchronous nature. So what you would want here is another await even if you had your REST API call or whatever. So it's not kind of holding up everything. So in this case we could delete it or if it was some sort of call you actually did need make sure it's written in asynchronous way. But yeah, that's kind of how you go back to source and can kind of play around the async tool, not necessarily for the deep dives per se but much more about giving you the high level insights to kind of further investigate into your code and kind of point out problematic asynchronous tasks. Awesome, awesome. Yeah. So where do you see this tool going in the future? Yeah, I mean, we definitely have a lot of plans for it. A lot of designs kind of in the works. Like I said, there's some usability things coming into play with being able to filter down by specific task time ranges. So you're not having to manually just like guess in the sim lane where a specific millisecond is. Additionally, I don't know if it fully showed up in VS today but a lot of the task names kind of end with like DLLs and things that are not particularly readable. And a lot of that kind of comes from a lack of symbol support we're working on that. So ready to run symbols and other symbols are going to be more and more supported. That also is kind of in the 16 nine time range I alluded to earlier. So some increased readability in terms of tasks. And then big picture, we really just want to help visualize these tasks, right? It's tricky because a lot of these tasks are kind of overlapping and running simultaneously. So right now we kind of have this tree grid view which is pretty popular in the profiler but we really have, and I don't have any finalized designs to share today, but let's just say we're really interested in kind of making that visual experience a lot more intuitive and accessible. So that's kind of where we see the async tool going at least in the short term. But also, like Esteban said with like the database tool for example, we'd love to hear feedback because this is a tool that we still very much want to polish and really all of our tools we'd love to hear feedback because we're very much in a polish mode and want to really refine it. And yeah, if you want to learn more about any of these tools we'll make sure the docs are linked. Link you should be seeing now is kind of the main homepage, but yeah at that homepage you'll see individual tool docs async tool be among them. So yeah, feel free to give us feedback on the docs dude, would love to hear. Very cool, very cool. Thanks for showing this to us, it was awesome stuff. It's a very handy tool to have as are all of these profiling tools. So thank you. Yeah, thanks for having me Robert, fun as always. All right, we'll see you next time on Visual Studio Toolbox and happy profiling. Happy profiling.