Measure performance of Asp.Net web applications with Microsoft Performance Monitor


This article gives a short introduction in performance measurement of Asp.Net web applications with the Microsoft Performance Monitor (perfmon.exe). The goal is to visualize and measure incoming traffic and to find performance bottlenecks using Microsoft tools.

This post shows how to use the Microsoft Performance Monitor, also known as perfmon. A small Asp.Net web application and a client application will be created. With both applications on board, perfmon is used to measure the traffic between the client and the web application.

Create the Asp.Net Web Application

As a starting point, we’ll create an Asp.Net web application with Visual Studio 2013. Simply click new project and type in a name for the project. I choose “AspNetTest”. Confirm the following dialog. We only need Asp.Net MVC here, no need for Web API or something else. Here you can see the steps:

Create the Client Application

After creating the Asp.Net web application project, we need to simulate some concurrent user visits of the new web application. Therefore, we create a second project. A console application will be enough for this scenario:

To simulate concurrent user visits, we start a random number of threads that will request the Asp.Net web application to the same time in several intervals. To do this, we insert the following code in the main method of the console application:

This code uses the TPL (Task Parallel Library) of the .Net framework to ease the use of threads. The code shows, that a random number of tasks is created. Tasks are created by a task factory available as a static member of the Task class. Each task simply runs the code that is given within the lambda expression.

Here we use the WebClient class to send a request to the web application in each thread. The WebClient class provides an easy way to request a web resource. The result of the request is downloaded synchronously. At the end, the result is written to the console. This is just to check that some web content has been downloaded.

Threads are initialized in the inner for-loop in the code. The for-statement does not start the tasks explicitly. This is done by the call of Task.WaitAll(). This method takes an array of tasks, starts all tasks in that array and waits until each task has completed. So we ensure, that all our tasks are executed to the same time. The outer for-loop runs this thread logic several times.

A delay of 1000 ms between the intervals is used to start a random number of requests every second. This should simulate some real user scenario.

To test our code, simply start the AspNetTest web application by hitting F5. The browser opens and shows you the web application. Then, starting the AspNetTestClient application. The console shows you the result of each web request.

IIS vs. IIS Express

Now we can start measure the requests that are handled by the web application. For this, we’ll use the perfmon.exe tool and the performance counters, which are registered with the Asp.Net features for the IIS. You can use performance counters with IIS or IIS Express.

Using the performance counters with IIS Express requires to start the Visual Studio for the Asp.Net web application as an administrator.

Using the performance counters with IIS, go to the project settings of the Asp.Net web application project. Switch the host to “Local IIS” as shown in the image below. Visual Studio will create a virtual directory for you and configure the application to run in IIS. Ensure, that you have appropriate rights for the IIS in order to create a virtual directory. Otherwise Visual Studio shows an error. Alternatively, you can start Visual Studio as an administrator.

Notice: the URL used for the web application (Project URL) has changed. Maybe you have to choose another port. That depends on your local configuration (e.g. IIS and IIS Express cannot use the same port simultaneously). In the client application, you have to adapt the URL in the WebClient.DownloadString() call. Change it to the new URL of the web application.

Rebuild and start the Asp.Net web application again and run the client application. The console output should be the same as show above. Now we can use perfmon.exe to visualize and measure the request that are handled by the web application.

Use the Performance Monitor (perfmon.exe)

The Microsoft Performance Monitor (perfmon.exe) is a system tool that can be found in the \Windows\System32-folder. The performance monitor can show graphs of different performance counters. A performance counter measures a specific system resource (e.g. used RAM, CPU utilization). It is possible to add different performance counters to the diagram. The image below shows the GUI of the performance monitor. The toolbar above the diagram provides some functionality, e.g. for adding performance counters. The list below the diagram shows the selected performance counters rendered in the diagram.

There are several performance counters you can use to measure system utilization. To add performance counters, the add button (with the green + in the toolbar) has to be clicked. Alternatively this function can be found in the countext menu of the performance counter list below the diagram. The following image shows the dialog to add new counters. The list on the left side of the dialog shows all available performance counters. From here, we will select some counters to measure the Asp.Net web application.

The Windows performance counters are extensible. So there are bunches of counters registered in the system. They are grouped, so we’ll need those ones for Asp.Net. Performance counters for Asp.Net are grouped by those ones which measure the performance of all Asp.Net web applications running on the system (named ASP.NET), and those which measure the performance of specific Asp.Net applications (named ASP.NET Apps). Those target applications can be selected per counter when adding it.

Performance counters for specific Asp.Net application will be used here. So expand the ASP.NET Apps group. You can see several counters (image below). For each of those counters, the specific target application can be selected in the instances of selected object list below the counters. The counter measures explicitely the selected target application. While our Asp.Net web application is running, it is listed there. Using the add button adds the selected performance counter for the selected target application to the list on the right side.

In this example, the performance counters Requests Failed, Request Succeeded, Requests Total and Requests/Sec are used. Select these counters and for each the Asp.Net web application and add them to the added counters list. The result will look like in the image below.

Confirm the dialog with ok. The new counters will be shown in the list below the diagram in the performance monitor GUI. The diagram needs to be customized for this example. To change properties of the diagram and counters, double click a counter or use the context menu. The following image shows the dialog that comes up. We change the sample interval and the duration of measurement for this example. Change the sample period to 1 means that the performance monitor will measure the appropriate counter every 1 second. The duration of 120 seconds changes the range of the x-axis in the diagram. The settings below cause the diagram to show 2 minutes of data and so 120 data points.

The data tab shows up all selected performance counters. Some properties of the counters can be changed here. For better recognition, we change the color of the Request/Sec counter to blue. Confirm the dialog with ok.

Due to different value types and ranges of the performance counters (e.g. CPU utilization in percent, Request Total as total number), some measured values can be outside the value range of the performance monitor diagram or they can be too small to see them. To fit the graph into the diagram, each counter can be scaled by a factor that can be set in the data tab of the performance monitor properties dialog (image above). You can also scale the counter’s graphs automatically via the context menu (image below).

Measure the Asp.Net web application performance

After setting up the counters and the diagram, our concrete test can start. Reset the diagram by the clear command in the context menu. Ensure that the Asp.Net web application is running. Start the client console application. The performance monitor measures all selected counters now. Results are shown in the diagram. After the console application finished, stop the performance monitor from measuring with the freeze command in the toolbar (pause icon). Results can be investigated now.

For better explanation, we will change the web application a little bit and run the test again. Failed request should be simulated. For this, keep the performance monitor as it is and go back to the Asp.Net web application solution in Visual Studio. Add some code that throws an exception in the Index-action method of the HomeController. Each request to that action will fail now. Rebuild the application and start it. Then go to the performance monitor and continue measuring by the unfreeze command in the toolbar. Execute the client console application again. After the console application has finished, freeze the diagram again. The image below shows the complete graphs for both tests on my system.

Let’s have a closer look at the results in the diagram. The light blue line shows the requests per second. The diagram shows that there were two periods of requests. This corresponds to our two test runs. The green line shows the number of those requests which could be handled successfully. During the first test run this number increases as expected and goes down after all request have been processed. The increase of succeeded requests is not linear because of the random request generation in the test application.

The red line shows the number of failed requests. The graph looks a little bit similar to that one of succeeded requests, except that it is growing during the second test run. Because of the exceptions which where thrown in the Index-action of the HomeController during the second test run, all requests in this run failed. That is what the graph shows. There was no successful request in the second run as well as there was no failed request in the first test run.


The example above is a very basic one used to demonstrate performance counters and the performance monitor. There are bunches of other performance counters which help you analyzing your Asp.Net web application. E.g. you can measure all rejected requests, used cache sizes, sessions and so on. Just explore the list of counters in the add counter dialog to see what is possible. That gives you the possibility to build more complex test scenarios to find performance bottlenecks and other problems with your web application.

With the Performance Monitor you can measure your application on live servers as well. You can define a job collecting specific counters and schedule the job to start to a given time running for a given period. After that you can analyze the data offline. But this is not part of this post.

If you have any problems or questions please do not hesitate to context me via email at


2 thoughts on “Measure performance of Asp.Net web applications with Microsoft Performance Monitor

Leave a Reply