The CLR Profiler
1.0 Where can I get it?
2.0 Should I use it?
When running performance tests, if the CPU is maximized and % Time in GC is greater than 5%, you can improve throughput by reducing allocations.
Excessive garbage collection is often the culprit for low throughput. The “.NET CLR Memory(w3wp)\% Time in GC” performance counter tells you how much time is spent doing collections. The diagram below depicts how this is calculated:
| gc1_begin | gc1_end | gc2_begin
Time à -------------------------------------------------------------------------------------
| | |
% Time in GC = 100 * (gc1_end – gc1_begin) / (gc2_begin – gc1_begin)
For ASP.NET applications, it is interesting to know what is allocated on a per request basis. You can calculate allocated bytes per request by dividing ".NET CLR Memory(w3wp)\Allocated Bytes/Sec" by "ASP.NET Applications(__Total__)\Requests/sec".
3.0 How do I create a profile?
- Change the worker process identity to System.
- Launch ClrProfiler.exe.
- Uncheck “Profiling active”.
- From the File menu, select Profile ASP.NET.
- Wait for a dialog to appear that says, “Waiting for ASP.NET to start common language runtime – this is the time to load your test page”.
- Issue the first request to your page.
- Check “Profiling active”.
- Issue the second request to your page.
- Uncheck “Profiling active”.
- Click the “Kill ASP.NET” button
- From the file menu, select “Save Profile as” if you would like to use the profile for comparisons later on.
4.0 How do I interpret the profile?
There are many interesting ways to use the ClrProfiler. I will discuss the two that I find most useful.
1. The “Histogram Allocated Types” view displays a histogram by size. In the left panel, you can select objects with the mouse, right click, and select “Show Who Allocated”. More importantly, in the right panel is listed the total number of objects allocated and their total size. If you right click in this region, you can select “Export Data to File” to save a CSV file that lists the min size, max size, # instances, and total size for each type. You can write a Perl script to quickly create a diff to assist you when comparing profiles.
2. The “Allocation Graph” view is a graph depicting function calls and the total amount of memory and types of objects allocated by each call. At the far left you see the total amount of memory allocated by your test. As you move to the right, the function calls branch out and you see how much is allocated by each call. At the far right is a list of the objects that are allocated, and the total size of those allocations. You can right click anywhere in the graph and use various options, such as “Prune to Callers and Callees”, “Find Routine”, “Find interesting nodes”, etc.
The ClrProfiler sets a custom environment block for both IISADMIN and W3SVC. Normally this is removed when you click the “Kill ASP.NET” button, but if the profiler crashes you might have to remove it manually. To do this, delete the REG_SZ named Environment beneath HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\IISADMIN and HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W3SVC.
A couple points worth noting:
- You only need to profile a single request. You can profile multiple requests, but the profile will grow quickly in size.
- You do not want to include AppDomain load or AppDomain unload in the profile. Uncheck “Profiling active” to avoid profiling during these times.
The author of the ClrProfiler wrote a document that I hear is quite good. It is available with version 1.0 of the tool at http://download.microsoft.com/download/4/4/2/442d67c7-a1c1-4884-9715-803a7b485b82/clr%20profiler.exe.