Skip to content

Commit 5d24f95

Browse files
authored
Merge pull request #11523 from Mikejo5000/mikejo-br21
Clarify interpretation of collected data in the Optimizing code article
2 parents 011575d + 1345585 commit 5d24f95

File tree

2 files changed

+13
-7
lines changed

2 files changed

+13
-7
lines changed
Loading

docs/profiling/optimize-code-using-profiling-tools.md

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "Reduce compute costs using profiling tools"
33
description: "Learn how to optimize code using Visual Studio profiling tools such as the CPU Usage tool, Database tool, and the .NET Object Allocation tool."
4-
ms.date: 07/21/2023
4+
ms.date: 08/07/2023
55
ms.topic: conceptual
66
dev_langs:
77
- "CSharp"
@@ -20,12 +20,12 @@ ms.workload:
2020

2121
[!INCLUDE [Visual Studio](~/includes/applies-to-version/vs-windows-only.md)]
2222

23-
Reducing your compute time means reducing costs, so optimizing your code can save money. In this article, we also show how you can use various profiling tools, including CPU Usage, NET Object Allocation, and the Database tool, to help you accomplish this task.The CPU Usage tool can help you capture and visualize where compute resources are used in your application. The CPU Usage views such as the call tree and flame chart provide a nice graphical visualization of where time is spent in your app. In addition, auto insights may show precise optimizations that can have a large impact. Other tools can help you isolate issues.
23+
Reducing your compute time means reducing costs, so optimizing your code can save money. In this article, we show how you can use various profiling tools, including CPU Usage, NET Object Allocation, and the Database tool, to help you accomplish this task. Rather than providing step-by-step instructions, the intent here is to show you how to use the profiling tools effectively and how to interpret the data. The CPU Usage tool can help you capture and visualize where compute resources are used in your application. The CPU Usage views such as the call tree and flame chart provide a nice graphical visualization of where time is spent in your app. In addition, auto insights may show precise optimizations that can have a large impact. Other tools can help you isolate issues.
2424

2525
## Start an investigation
2626

2727
- To reduce compute costs, start your investigation by taking a CPU usage trace. The CPU Usage tool is often helpful to begin performance investigations and to optimize code to reduce cost.
28-
- If you would like additional insights to help isolate issues or improve the performance, considering collecting a trace using one of the other profiling tools. For example:
28+
- Next, if you would like additional insights to help isolate issues or improve the performance, considering collecting a trace using one of the other profiling tools. For example:
2929
- Take a look at the memory usage. For .NET, try the .NET Object Allocation tool first. For either .NET or C++, you can look at the Memory Usage tool.
3030
- If your app is using File I/O, use the File I/O tool.
3131
- If you're using ADO.NET or Entity Framework, you can try the Database tool to examine SQL queries, precise query time, et al.
@@ -47,29 +47,35 @@ Start by collecting a trace with the CPU Usage tool. When the diagnostic data lo
4747

4848
You can also view the hot path in the **Call Tree** view. To open this view, use the **Open details** link in the report and then select **Call Tree**.
4949

50-
In this view, you see the hot path again, which shows high CPU usage for the `GetBlogTitleX` method in the app, using about a 60% share of the app's CPU usage. Two external calls to LINQ DLLs are using most of the CPU time. This is the first clue that you may want to look for a LINQ query as an area to optimize.
50+
In this view, you see the hot path again, which shows high CPU usage for the `GetBlogTitleX` method in the app, using about a 60% share of the app's CPU usage. However, the **Self CPU** value for `GetBlogTitleX` is low, only about .10%. Unlike **Total CPU**, the **Self CPU** value excludes time spent in other functions, so we know to look farther down the Call Tree view for the real bottleneck.
5151

5252
:::image type="content" source="./media/optimize-code-cpu-usage-call-tree.png" alt-text="Screenshot of Call Tree view in the CPU Usage tool.":::
5353

54+
`GetBlogTitleX` makes external calls to two LINQ DLLs, which are using most of the CPU time, as evidenced by the very high **Self CPU** values. This is the first clue that you may want to look for a LINQ query as an area to optimize.
55+
56+
:::image type="content" source="./media/optimize-code-cpu-usage-call-tree-self-cpu.png" alt-text="Screenshot of Call Tree view in the CPU Usage tool with Self CPU highlighted." lightbox="./media/optimize-code-cpu-usage-call-tree-self-cpu.png":::
57+
5458
To get a visualized call tree and a different view of the data, switch to the **Flame Graph** view (select from the same list as the **Call Tree**). Here again, it looks like the `GetBlogTitleX` method is responsible for a lot of the app's CPU usage (shown in yellow). External calls to the LINQ DLLs show up beneath the `GetBlogTitleX` box, and they are using all of the CPU time for the method.
5559

5660
:::image type="content" source="./media/optimize-code-cpu-usage-flame-graph.png" alt-text="Screenshot of Flame Graph view in the CPU Usage tool.":::
5761

5862
## Gather additional data
5963

60-
If the CPU Usage tool does not provide enough information to isolate the problem, or you would like additional insights to help improve the performance, you may decide to use one of the other profiling tools. For example, since we identified the LINQ DLLs, we'll first try the Database tool. You can multi-select this tool along with CPU Usage. When you've collected a trace, select the **Queries** tab in the diagnostics page.
64+
Often, other tools can provide additional information to help the analysis and isolate the problem. For example, since we identified the LINQ DLLs, we'll first try the Database tool. You can multi-select this tool along with CPU Usage. When you've collected a trace, select the **Queries** tab in the diagnostics page.
6165

6266
In the Queries tab for the Database trace, you can see the first row shows the longest query, 2446 ms. The **Records** column shows how many records the query reads. We can use this information for later comparison.
6367

6468
:::image type="content" source="./media/optimize-code-database.png" alt-text="Screenshot of Database queries in the Database tool.":::
6569

66-
By examining the SELECT statement generated by LINQ in the Query column, you identify the first row as the query associated with the `GetBlogTitleX` method. The full query string in the Query column is:
70+
By examining the SELECT statement generated by LINQ in the Query column, you identify the first row as the query associated with the `GetBlogTitleX` method. To view the full query string, expand the column width if you need to. The full query string is:
6771

6872
```sql
6973
SELECT "b"."Url", "b"."BlogId", "p"."PostId", "p"."Author", "p"."BlogId", "p"."Content", "p"."Date", "p"."MetaData", "p"."Title"
7074
FROM "Blogs" AS "b" LEFT JOIN "Posts" AS "p" ON "b"."BlogId" = "p"."BlogId" ORDER BY "b"."BlogId"
7175
```
7276

77+
Notice that you are retrieving a lot of column values here, perhaps more than you need.
78+
7379
To see what's going on with the app in terms of memory usage, collect a trace using the .NET Object Allocation tool (For C++, use the Memory Usage tool instead). The **Call Tree** view in the memory trace shows the hot path and helps you identify an area of high memory usage. No surprise at this point, the `GetBlogTitleX` method appears to be generating a lot of objects! Over 900,000 object allocations, in fact.
7480

7581
:::image type="content" source="./media/optimize-code-dotnet-object-allocations.png" alt-text="Screenshot of Call Tree view in the .NET Object Allocation tool.":::
@@ -107,7 +113,7 @@ foreach (var x in db.Posts.Where(p => p.Author.Contains("Fred Smith")).Select(b
107113
In this code, you made several changes to help optimize the query:
108114

109115
- Add the `Where` clause and eliminate one of the `foreach` loops.
110-
- Project only the Title property, which is all you need in this example.
116+
- Project only the Title property in the `Select` statement, which is all you need in this example.
111117

112118
Next, retest using the profiling tools.
113119

0 commit comments

Comments
 (0)