Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Profiling an application with Visual Studio – CPU Sampling

DZone's Guide to

Profiling an application with Visual Studio – CPU Sampling

· Performance Zone
Free Resource

Evolve your approach to Application Performance Monitoring by adopting five best practices that are outlined and explored in this e-book, brought to you in partnership with BMC.

This is a series of articles I am writing that cover four various methods of application profiling with Visual Studio. These methods are:

Application performance is a key element that should be analyzed and optimized before the actual public release. Microsoft Visual Studio 2010 comes with built-in profiling tools that offer developers the possibility to analyze their application performance based on a multitude of factors. Dynamic code analysis (profiling) allows finding the parts of the application that need to be optimized to achieve better performance.

NOTE: Profiling tools are not available in Visual Studio 2010 Express and Professional editions. Details here.

Setting up a sample application

Before performing the actual analysis, I set up a sample threaded application that will perform a set of data operations (I/O,data retrieval via a web service). It is a simple console application with a Main method and a complementary Get method, that gets the actual data from the web.

The Get method I am talking about looks like this:
static void Get(object state)
{
List<string> cities = new List<string>();
XmlDocument doc = new XmlDocument();
doc.Load(string.Format("http://www.webservicex.net/uszip.asmx/GetInfoByState?USState={0}", state.ToString()));

foreach (XmlNode node in doc.SelectSingleNode("NewDataSet"))
{
XmlNode childNode = node.SelectSingleNode("CITY");
string city = childNode.InnerText;
if (!cities.Contains(city))
{
cities.Add(city);
}
}

foreach (string city in cities)
Trace.WriteLine(city + ", " + state);
}
It is the same method I used for testing purposes in this article and I like to use it as an example of a resource-consuming process. In my application, I am going to start several threads that will call this method and display (and record to a file) the retrieved data.

So for the Main method in my console application, I’ve use the code below:
static void Main(string[] args)
{
TextWriterTraceListener tl = new TextWriterTraceListener("D:\\Temporary\\string.txt");
ConsoleTraceListener cl = new ConsoleTraceListener(false);
Trace.Listeners.Add(tl);
Trace.Listeners.Add(cl);

ThreadPool.QueueUserWorkItem(Get, "TX");
ThreadPool.QueueUserWorkItem(Get, "KS");
ThreadPool.QueueUserWorkItem(Get, "CA");
ThreadPool.QueueUserWorkItem(Get, "VA");
ThreadPool.QueueUserWorkItem(Get, "WA");

Console.Read();
}
If I run the application, I can see a long list of cities being returned and displayed on the screen in a chaotic way, since threads run in no particular order and some of them are finished before others.

All set for the performance analysis, so let’s go to the next step

Tracing the performance indicators

To begin the analysis, you need to launch the Performance Wizard (from the Analyze Menu):

You will be prompted to choose an analysis method out of four possible choices:

I will cover each of the possible profiling methods in my next articles, but here I am specifically covering CPU sampling.

Performing the operation

CPU sampling collects information on how the application impacts the CPU performance, both as a single unit and as a set of separate function calls. It allows the developer to see what parts of the code are the most expensive, CPU-wise.

The next step in the Performance Wizard is choosing the project or application that needs to be profiled.

Since we are working with the current console application project, it is selected as the default item. If the solution that is currently open contains more than one project, each of them will be listed there and you will be able to select more than one project to track performance for.

In case you do not want to work with the existing project, you can bind the wizard to an executable or to a ASP.NET or JavaScript application.

NOTE: If you point to a unmanaged executable, you will only see the end result as a set of calls to system libraries and the performance indicators for the whole process, rather than functions. If you are binding to an obfuscated executable, you won't be able to look at the source code as well.

Now to the last step, and here you are able to launch the profiling session.

Chances are that you aren’t launching Visual Studio as an administrator (with elevated permissions). In this case, once you decide to start the profiling session, you could encounter a message like this:

Click Yes and the profiling session will be started. The application will run just like any other time:

However, Visual Studio will be in process of profiling the current application:

Analyzing the results

Once completed, the final report should look similar to this:

And here is the place where you can take a look at what parts of your code impact the CPU performance most.

First of all, the Hot Path is showing you the function call path that is the most “expensive” – the one that has the biggest impact on the CPU load for your specific application:
 
In my case, this would be Trace.WriteLine inside the Get method, since it is called very often - for every city that is inside the list the string is printed out on the screen and in a text file. If you click on Trace.WriteLine in this list, you will open up a more detailed report on the function call:

The detailed report can give you information on CPU loads based on various calls inside the researched function. Also, you can clearly see the code part that is the most consuming:

You are able to switch between the sample percentage and the actual number of samples by changing the view from Inclusive Samples % to Inclusive Samples. Now you might be asking what Inclusive might mean here.

When a sample is taken, basically it grabs a snapshot of the call stack. When the analyzed function was on top of the stack, it counts towards the inclusive sample. If it was anywhere else in the stack, it counts towards the inclusive sample.

In the main report window, you are also able to see the functions doing the most individual work (called most often). Here, only the exclusive sample is called, therefore when the function was on top of the call stack.

NOTE: The data presented in the profiling report relates to the CPU as a whole. Via the default CPU sampling report you are not able to see the performance based on specific cores, for a multicore system.

Related reading

Understanding Sampling Data Values in Profiling Tools

Profiling Tools Performance Session Overview

Learn tips and best practices for optimizing your capacity management strategy with the Market Guide for Capacity Management, brought to you in partnership with BMC.

Topics:

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}