Skip to content

Commit f6ba8d1

Browse files
committed
edits
1 parent 1035890 commit f6ba8d1

File tree

1 file changed

+15
-15
lines changed

1 file changed

+15
-15
lines changed

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

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ monikerRange: '>= vs-2022'
1616
---
1717
# Beginner's guide to optimizing code and reducing compute costs (C#, Visual Basic, C++, F#)
1818

19-
In this guide, we aim to provide a comprehensive understanding of how to optimize code to reduce compute costs effectively and save money. By leveraging Visual Studio's profiling tools, developers can gain insights into their application's performance, identify bottlenecks, and implement optimizations to improve efficiency. The case study focuses on a .NET application that performs numerous queries against a database, highlighting common performance issues and demonstrating how to use tools like the CPU Usage tool, the .NET Object Allocation tool, and the Database tool to diagnose and resolve these issues.
19+
In this guide, we aim to provide a comprehensive understanding of how to optimize code to reduce compute costs effectively and save money. By leveraging Visual Studio's profiling tools, developers can gain insights into their application's performance, identify bottlenecks, and implement optimizations to improve efficiency.
2020

2121
Our goal is to equip developers with the knowledge to:
2222

@@ -29,23 +29,23 @@ By the end of this guide, readers should be able to apply these techniques to th
2929

3030
## Summary
3131

32-
The sample application discussed in this case study is a .NET application designed to run queries against a database of blogs and associated blog posts. It utilizes the Entity Framework, a popular ORM (Object-Relational Mapping) for .NET, to interact with a SQLite local database. The application is structured to execute a large number of queries, simulating a real-world scenario where a .NET application might be required to handle extensive data retrieval tasks. The sample application is based on the [Entity Framework sample](/ef/core/querying/), but modified to run a large number of queries against a SQLite local database.
32+
The sample application discussed in this case study is a .NET application designed to run queries against a database of blogs and associated blog posts. It utilizes the Entity Framework, a popular ORM (Object-Relational Mapping) for .NET, to interact with a SQLite local database. The application is structured to execute a large number of queries, simulating a real-world scenario where a .NET application might be required to handle extensive data retrieval tasks. The sample application is based on the [Entity Framework sample](/ef/core/querying/), but modified to run a large number of queries.
3333

3434
The primary performance issue with the sample application lies in how it manages compute resources and interacts with the database. The application suffers from several common performance bottlenecks that can significantly impact its efficiency and, consequently, the compute costs associated with running it. These problems include:
3535

3636
1. **High CPU Usage**: The application may be performing inefficient computations or processing tasks in a way that unnecessarily consumes a large amount of CPU resources. This can lead to slow response times and increased operational costs.
3737

38-
2. **Inefficient Memory Allocation**: .NET applications, especially those that make extensive use of the Entity Framework, can sometimes face issues related to memory usage and allocation. Inefficient memory management can lead to increased garbage collection, which in turn can affect application performance.
38+
2. **Inefficient Memory Allocation**: Applications can sometimes face issues related to memory usage and allocation. Inefficient memory management can lead to increased garbage collection, which in turn can affect application performance.
3939

4040
3. **Database Interaction Overheads**: Given that the application executes a large number of queries against a database, it is prone to experiencing bottlenecks related to database interactions. This includes inefficient queries, excessive database calls, and poor use of Entity Framework capabilities, all of which can degrade performance.
4141

4242
The case study aims to address these issues by employing Visual Studio's profiling tools to analyze the application's performance. By understanding where and how the application's performance can be improved, developers can implement optimizations to reduce CPU usage, improve memory allocation efficiency, streamline database interactions, and optimize resource utilization. The ultimate goal is to enhance the application's overall performance, making it more efficient and cost-effective to run.
4343

4444
## Challenge
4545

46-
Addressing the performance issues in the sample .NET application presents several challenges. These challenges stem from the complexity of diagnosing performance bottlenecks, the intricacies of optimizing code without compromising functionality, and the need to balance improvements across different aspects of the application. The key challenges in fixing the problems described are as follows:
46+
Addressing the performance issues in the sample .NET application presents several challenges. These challenges stem from the complexity of diagnosing performance bottlenecks. The key challenges in fixing the problems described are as follows:
4747

48-
1. **Diagnosing Performance Bottlenecks**: One of the primary challenges is accurately identifying the root causes of the performance issues. High CPU usage, inefficient memory allocation, and database interaction overheads can have multiple contributing factors. Developers must use profiling tools effectively to diagnose these issues, which requires a deep understanding of how these tools work and how to interpret their output.
48+
1. **Diagnosing Performance Bottlenecks**: One of the primary challenges is accurately identifying the root causes of the performance issues. High CPU usage, inefficient memory allocation, and database interaction overheads can have multiple contributing factors. Developers must use profiling tools effectively to diagnose these issues, which requires a good understanding of how these tools work and how to interpret their output.
4949

5050
2. **Optimizing Database Interactions**: The application's heavy reliance on database queries means that optimizing these interactions is crucial. However, doing so without a thorough understanding of the Entity Framework's inner workings and best practices can be challenging. Developers must identify inefficient queries and excessive database calls, then refactor them without affecting the application's functionality or data integrity.
5151

@@ -83,20 +83,20 @@ In this view, we see the hot path again, which shows high CPU usage for the `Get
8383

8484
:::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":::
8585

86-
To get a visualized call tree and a different view of the data, right-click `GetBlogTitleX` and choose **View in Flame Graph**. 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.
86+
To get a visualized call tree and a different view of the data, we right-click `GetBlogTitleX` and choose **View in Flame Graph**. 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.
8787

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

9090
### Gather additional data
9191

92-
Often, other tools can provide additional information to help the analysis and isolate the problem. For this example, take the following approach:
92+
Often, other tools can provide additional information to help the analysis and isolate the problem. For this example, we take the following approach:
9393

94-
- First, take a look at memory usage. There might be a correlation between high CPU usage and high memory usage, so it can be helpful to look at both to isolate the issue.
94+
- First, we take a look at memory usage. There might be a correlation between high CPU usage and high memory usage, so it can be helpful to look at both to isolate the issue.
9595
- Because we identified the LINQ DLLs, we'll also look at the Database tool.
9696

9797
#### Check the memory usage
9898

99-
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 us 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.
99+
To see what's going on with the app in terms of memory usage, we collect a trace using the .NET Object Allocation tool (For C++, you can use the Memory Usage tool instead). The **Call Tree** view in the memory trace shows the hot path and helps us 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.
100100

101101
:::image type="content" source="./media/optimize-code-dotnet-object-allocations.png" alt-text="Screenshot of Call Tree view in the .NET Object Allocation tool.":::
102102

@@ -119,7 +119,7 @@ Notice that we are retrieving a lot of column values here, perhaps more than we
119119

120120
### Optimize code
121121

122-
It's time to take a look at the `GetBlogTitleX` source code. In the Database tool, right-click the query and choose **Go to Source File**. In the source code for `GetBlogTitleX`, we find the following code that uses LINQ to read the database.
122+
It's time to take a look at the `GetBlogTitleX` source code. In the Database tool, we right-click the query and choose **Go to Source File**. In the source code for `GetBlogTitleX`, we find the following code that uses LINQ to read the database.
123123

124124
```csharp
125125
foreach (var blog in db.Blogs.Select(b => new { b.Url, b.Posts }).ToList())
@@ -150,23 +150,23 @@ In this code, we made several changes to help optimize the query:
150150
- Added the `Where` clause and eliminate one of the `foreach` loops.
151151
- Projected only the Title property in the `Select` statement, which is all we need in this example.
152152

153-
Next, retest using the profiling tools.
153+
Next, we retest using the profiling tools.
154154

155155
## Results
156156

157-
After updating the code, re-run the CPU Usage tool to collect a trace. The **Call Tree** view shows that `GetBlogTitleX` is running only 1754 ms, using 37% of the app's CPU total, a significant improvement from 59%.
157+
After updating the code, we re-run the CPU Usage tool to collect a trace. The **Call Tree** view shows that `GetBlogTitleX` is running only 1754 ms, using 37% of the app's CPU total, a significant improvement from 59%.
158158

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

161-
Switch to the **Flame Graph** view to see another visualization of the improvement. In this view, `GetBlogTitleX` also uses a smaller portion of the CPU.
161+
We switch to the **Flame Graph** view to see another visualization of the improvement. In this view, `GetBlogTitleX` also uses a smaller portion of the CPU.
162162

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

165-
Check the results in the Database tool trace, and only two records are read using this query, instead of 100,000! Also, the query is much simplified and eliminates the unnecessary LEFT JOIN that was generated previously.
165+
We check the results in the Database tool trace, and only two records are read using this query, instead of 100,000! Also, the query is much simplified and eliminates the unnecessary LEFT JOIN that was generated previously.
166166

167167
:::image type="content" source="./media/optimize-code-database-fixed.png" alt-text="Screenshot of faster query time in the Database tool.":::
168168

169-
Next, recheck the results in the .NET Object Allocation tool, and see that `GetBlogTitleX` is only responsible for 56,000 object allocations, nearly a 95% reduction from 900,000!
169+
Next, we recheck the results in the .NET Object Allocation tool, and see that `GetBlogTitleX` is only responsible for 56,000 object allocations, nearly a 95% reduction from 900,000!
170170

171171
:::image type="content" source="./media/optimize-code-dotnet-object-allocations-fixed.png" alt-text="Screenshot of reduced memory allocations in the .NET Object Allocation tool.":::
172172

0 commit comments

Comments
 (0)