Application Profiling in Visual Studio 2010
Today we will measure the performance of our application using the Visual Studio Profiling Tool .
Visual Studio Profiling Tool allows developers to measure and evaluate application and code performance. These tools are fully integrated into the IDE to give the developer uninterrupted control.
In this guide, we will step by step profile the PeopleTrax application using Sampling and Instrumentation profiling methods to identify problems in application performance.
A lot of pictures.
To work with this guide, you will need:
Let's step back a little from the main topic of the article and consider possible profiling methods. You can skip this chapter, the profiling methods used will be briefly described before use.
Sampling - collects statistics on the operation of the application (during profiling). This method is lightweight and therefore, as a result of its work, there is a very small error in the data obtained.
Each specific time interval collects information about the call stack (call stack). Based on this data, performance is calculated. Used for initial profiling and for identifying problems associated with CPU usage.
Instrumentation - collects detailed information about the operating time of each function called. Used to measure the performance of I / O operations.
The method embeds its code in a binary file, which records information about the synchronization (time) for each function in the file, and for each function that are called in this one.
The report contains 4 values to represent the time spent:
Concurrency - Gathers information about multi-threaded applications (for how to debug multi-threaded applications, see the "Guide to debugging multi-threaded applications in Visual Studio 2010" ). The method collects detailed information about the call stack, each time competing threads are forced to wait for access to the resource.
.NET Memory - the profiler collects information about the type, size, and also the number of objects that were created in the distribution or were destroyed by the garbage collector. Memory profiling has almost no effect on overall application performance.
Tier Interaction - Adds information to a file for profiling synchronous ADO.NET calls between an ASP.NET page or other applications and the SQL server. The data includes the number and time of calls, as well as the maximum and minimum time.
We’ll finish this discussion of profiling methods and continue to learn how to profile applications.
Sampling is a profiling method that periodically polls the process in question to determine the active function. The result shows the number of times the function was at the beginning of the call stack during testing.
We open the test project PeopleTrax . We set the configuration in Release (additional information is built into the Debug version for debugging the application, and it will adversely affect the accuracy of the profiling results).
In the Analyze menu, click on the Launch Performance Wizard .
At this step, you need to select a profiling method. Select CPU Sampling (recommended) and click Next.
We choose which application we will profile, this is PeopleTrax and the Next button. In the next click Finish and the profiler and our application will automatically start. On the screen we see the PeopleTrax program. We press the Get People button , we wait for completion of work andExport Data . We close the notebook and the program and the profiler will generate a report.
Profiler generated report (* .vsp)
The Summary displays the graph of CPU utilization during the time profiling. The Hot Path list shows the call branches that are most active. And in the list of the Functions the Doing the Work Most Individual (whose name speaks for itself) - the function that occupied used to proc eed the process in the body of these functions.
Looking at the Hot Path list, we see that the PeopleNS.People.GetNames method takes almost the last place in the call branch. It can then be studied more closely for improving performance. We click on PeopleNS.People.GetNames and Function Details opens before us .
This window contains two parts. The expense window provides a graphical representation of the operation of the functions, and the contribution of the function and its callers to the number of instances that were selected. You can change the function in question by clicking on it with the mouse.
Function Code View shows the code of the method when it is available and highlights the most “expensive” lines in the selected method. When the GetNames method is selected , it can be seen that it reads lines from application resources using StringReader , adding each line to an ArrayList . There are no obvious ways to improve this part.
Since PeopleNS.People.GetPeople is the only one who calls GetNames - click GetPeople. This method returns an ArrayList of PersonInformationNS.PersonInformation objects with the names of people and companies returned by the GetNames method . However, GetNames is called twice each time PersonInformation is created . (This is shown by yellow and red highlighting). Obviously, you can easily optimize a method by creating lists only once at the beginning of the method.
An alternative version of GetPeople is also in the code and we will enable it now. To do this, define OPTIMIZED_GETPEOPLE as a Conditional compilation symbol in the project properties window of People and PeopleTrax .And yes, if you want to repeat my experiments, then you need to fix the error in the project. The name of the resources is not spelled correctly in the optimized constructor of the class: you need PeopleNS.Resources together with PeopleNS.Resource. If this is not changed, everything will fail with terrible mistakes.
The optimized method will replace the old one at the next build.
We restart profiling in the current session by clicking Launch with Profiling in the Performance Explorer window . Click on Get People and Export Data . Close the notebook and the program and the profiler will generate a new report.
To compare two reports - select both and RMB Compare Performance Reports . Delta Column Shows Version Performance DifferenceBaseline with later Comparison . Select Inclusive Samples% and Apply.
As you can see, the performance gain is noticeable to the naked eye.
This method is useful for profiling input / output operations, writing to disk, and exchanging data over a network. This method provides more information than the previous one, but it carries with it more overhead. The binaries obtained after inserting additional code are more than usual, and are not intended for deployment.
This time we will focus our analysis on data export, in which a list of people is written to a notebook file.
In Performance Explorer, select Instrumentation and click Start Profiling. Click Get People. After loading people, we wait 10 seconds and click Export Data. Close the notebook and the program. The profiler will generate a report.
The profiler will show this picture:
We did not receive the information that we wanted. We filter the data. We specifically waited 10 seconds to simply filter out the profiling data that is no longer needed. We mark from the 13th to the end and click Filter by selection . Another result:
Hot Path shows that the Concat method takes a lot of time (it is also the first in the list of Functions With Most Individual Work). Click on Concat to view the details of the method.
It can be seen that PeopleTrax.Form1.ExportData is the only method that calls Concat . Click PeopleTrax.Form1.ExportData in the calling methods (Function calling this function ).
We analyze the method in the code window. Please note that there is no direct call to Concat. Together, there is the use of the operand + = , which the compiler replaces with the methods System.String.Concat . As almost everyone already knows that any changes to strings in .NET will destroy the old version of the string and create the modified string. Fortunately, in .NET there is a StringBuilder class which is designed for such work.
The project already has an optimized method using StringBuilder . In the PeopleTrax project, we add the compilation variable OPTIMIZED_EXPORTDATA. We save and run the profiler again and compare the reports. It’s immediately obvious (and logically clear) that we optimized Concat calls (from 6000 to 0 times).
After launching the application, a noticeable performance improvement is seen by eye. It is very important to run profiling again, there are even visible improvements. Viewing new data after fixing the problem may reveal other problems in application performance.
Thanks for attention. Quick as lightning you code.
Visual Studio Profiling Tool allows developers to measure and evaluate application and code performance. These tools are fully integrated into the IDE to give the developer uninterrupted control.
In this guide, we will step by step profile the PeopleTrax application using Sampling and Instrumentation profiling methods to identify problems in application performance.
A lot of pictures.
Training
To work with this guide, you will need:
- Microsoft Visual Studio 2010
- Average knowledge of C #
- A copy of the PeopleTrax test application can be downloaded from the MSDN Code Gallery
Profiling Methods
Let's step back a little from the main topic of the article and consider possible profiling methods. You can skip this chapter, the profiling methods used will be briefly described before use.
Sampling
Sampling - collects statistics on the operation of the application (during profiling). This method is lightweight and therefore, as a result of its work, there is a very small error in the data obtained.
Each specific time interval collects information about the call stack (call stack). Based on this data, performance is calculated. Used for initial profiling and for identifying problems associated with CPU usage.
Instrumentation
Instrumentation - collects detailed information about the operating time of each function called. Used to measure the performance of I / O operations.
The method embeds its code in a binary file, which records information about the synchronization (time) for each function in the file, and for each function that are called in this one.
The report contains 4 values to represent the time spent:
- Elapsed Inclusive - total time spent executing a function
- Application Inclusive - the time taken to execute the function, with the exception of the time it takes to access the operating system.
- Elapsed Exclusive - time spent executing code in the body. The time that the functions called by the target function spend.
- Application Exclusive - the time taken to execute the code in the body. It excludes the time spent on making calls to the operating system and the time spent on performing functions caused by the target function.
Concurrency
Concurrency - Gathers information about multi-threaded applications (for how to debug multi-threaded applications, see the "Guide to debugging multi-threaded applications in Visual Studio 2010" ). The method collects detailed information about the call stack, each time competing threads are forced to wait for access to the resource.
.NET memory
.NET Memory - the profiler collects information about the type, size, and also the number of objects that were created in the distribution or were destroyed by the garbage collector. Memory profiling has almost no effect on overall application performance.
Tier interaction
Tier Interaction - Adds information to a file for profiling synchronous ADO.NET calls between an ASP.NET page or other applications and the SQL server. The data includes the number and time of calls, as well as the maximum and minimum time.
We’ll finish this discussion of profiling methods and continue to learn how to profile applications.
Profiling Sampling Method
Sampling is a profiling method that periodically polls the process in question to determine the active function. The result shows the number of times the function was at the beginning of the call stack during testing.
Profiling
We open the test project PeopleTrax . We set the configuration in Release (additional information is built into the Debug version for debugging the application, and it will adversely affect the accuracy of the profiling results).
In the Analyze menu, click on the Launch Performance Wizard .
At this step, you need to select a profiling method. Select CPU Sampling (recommended) and click Next.
We choose which application we will profile, this is PeopleTrax and the Next button. In the next click Finish and the profiler and our application will automatically start. On the screen we see the PeopleTrax program. We press the Get People button , we wait for completion of work andExport Data . We close the notebook and the program and the profiler will generate a report.
Profiler generated report (* .vsp)
Sampling Method Report Analysis
The Summary displays the graph of CPU utilization during the time profiling. The Hot Path list shows the call branches that are most active. And in the list of the Functions the Doing the Work Most Individual (whose name speaks for itself) - the function that occupied used to proc eed the process in the body of these functions.
Looking at the Hot Path list, we see that the PeopleNS.People.GetNames method takes almost the last place in the call branch. It can then be studied more closely for improving performance. We click on PeopleNS.People.GetNames and Function Details opens before us .
This window contains two parts. The expense window provides a graphical representation of the operation of the functions, and the contribution of the function and its callers to the number of instances that were selected. You can change the function in question by clicking on it with the mouse.
Function Code View shows the code of the method when it is available and highlights the most “expensive” lines in the selected method. When the GetNames method is selected , it can be seen that it reads lines from application resources using StringReader , adding each line to an ArrayList . There are no obvious ways to improve this part.
Since PeopleNS.People.GetPeople is the only one who calls GetNames - click GetPeople. This method returns an ArrayList of PersonInformationNS.PersonInformation objects with the names of people and companies returned by the GetNames method . However, GetNames is called twice each time PersonInformation is created . (This is shown by yellow and red highlighting). Obviously, you can easily optimize a method by creating lists only once at the beginning of the method.
An alternative version of GetPeople is also in the code and we will enable it now. To do this, define OPTIMIZED_GETPEOPLE as a Conditional compilation symbol in the project properties window of People and PeopleTrax .And yes, if you want to repeat my experiments, then you need to fix the error in the project. The name of the resources is not spelled correctly in the optimized constructor of the class: you need PeopleNS.Resources together with PeopleNS.Resource. If this is not changed, everything will fail with terrible mistakes.
The optimized method will replace the old one at the next build.
We restart profiling in the current session by clicking Launch with Profiling in the Performance Explorer window . Click on Get People and Export Data . Close the notebook and the program and the profiler will generate a new report.
To compare two reports - select both and RMB Compare Performance Reports . Delta Column Shows Version Performance DifferenceBaseline with later Comparison . Select Inclusive Samples% and Apply.
As you can see, the performance gain is noticeable to the naked eye.
Instrumentation Profiling
This method is useful for profiling input / output operations, writing to disk, and exchanging data over a network. This method provides more information than the previous one, but it carries with it more overhead. The binaries obtained after inserting additional code are more than usual, and are not intended for deployment.
This time we will focus our analysis on data export, in which a list of people is written to a notebook file.
Profiling
In Performance Explorer, select Instrumentation and click Start Profiling. Click Get People. After loading people, we wait 10 seconds and click Export Data. Close the notebook and the program. The profiler will generate a report.
Analysis
The profiler will show this picture:
We did not receive the information that we wanted. We filter the data. We specifically waited 10 seconds to simply filter out the profiling data that is no longer needed. We mark from the 13th to the end and click Filter by selection . Another result:
Hot Path shows that the Concat method takes a lot of time (it is also the first in the list of Functions With Most Individual Work). Click on Concat to view the details of the method.
It can be seen that PeopleTrax.Form1.ExportData is the only method that calls Concat . Click PeopleTrax.Form1.ExportData in the calling methods (Function calling this function ).
We analyze the method in the code window. Please note that there is no direct call to Concat. Together, there is the use of the operand + = , which the compiler replaces with the methods System.String.Concat . As almost everyone already knows that any changes to strings in .NET will destroy the old version of the string and create the modified string. Fortunately, in .NET there is a StringBuilder class which is designed for such work.
The project already has an optimized method using StringBuilder . In the PeopleTrax project, we add the compilation variable OPTIMIZED_EXPORTDATA. We save and run the profiler again and compare the reports. It’s immediately obvious (and logically clear) that we optimized Concat calls (from 6000 to 0 times).
After launching the application, a noticeable performance improvement is seen by eye. It is very important to run profiling again, there are even visible improvements. Viewing new data after fixing the problem may reveal other problems in application performance.
Literature
- Getting Started with Profiling Tools
- Walkthrough: Profiling Applications
- PeopleTrax Sample (project)
- Visual Studio Profiler Team Blog
- Debugging Guide for Multithreaded Applications in Visual Studio 2010
Thanks for attention. Quick as lightning you code.