ASP.NET Performance Improvements and VS2015 Profiler

By Sudha Polapragada

Introduction

Large scale application design indispensably considers some factors like scalability, maintainability of the code, and performance. Performance of an application is simply how fast a user’s request executes; this is especially important when the application is hit by thousands of users concurrently. The time taken for a high volume of concurrent requests with huge volume of database interaction would obviously be different in most cases compared to the time taken for the same request to run on a developer’s local machine. How well an application supports large numbers of concurrent requests while still having the system respond in a reasonable amount of time is called scalability. This article focuses on some performance improvement tips for ASP.NET Web applications you can utilize with Visual Studio 2015 Profiler while in the code development phase.

Poor server resources can be a reason for performance some times; however, there can be other reasons, such as server switching among different kinds of tasks accessing various static resources from the server, handling thousands of connections, disk I/O waiting for some tasks, running task intensive chunk of application, and eventually running out of memory. Generally, in large scale ASP.NET applications, parts of the code and logic will be separated into various tiers. Due to this separation of code and the boundaries between tiers, service calls will decrease performance by some percentage as well.

Performance and Diagnostic Tools VS2015

There have been profiling tools in Visual Studio for quite some time. Focusing on using those tools during development would be helpful to avoid performance issues. This article focuses on enhanced debugging features and diagnostics tools for profiling in VS2015 and how to use them when coding to analyze performance issues and a few general optimization techniques that developers can follow when coding the programs. Some features and tools are described below.

PerfTips

The most common practice during debugging sessions is that the developer keeps the cursor on a variable to know its value in Visual Studio. If a piece of code is observed running slower in general, the developer uses the System.Diagnostics.Stopwatch class to get the timing information, as shown in the following code snippet:

Stopwatch sw = Stopwatch.StartNew();
ApplyRules();
sw.Stop();
Console.WriteLine("Time elapsed: {0}ms",
   sw.Elapsed.TotalMilliseconds);

Output
Time elapsed: 00:00:30.0001277

Now, with new PerfTips feature, which is part of Visual Studio 2015, there is no need to insert Stopwatch code and developers can measure the time that passes between the debugger breaks automatically. During debug, even if developer uses Step Into, Step Over, or Run to Cursor, the measured timespan is displayed in the PerfTip, as well as recorded as a list in the Diagnostic Tools window.

Let us say you have the following code:

static void Main()
   {
      var myEmployee = new MyEmployee();
      var allEmployees = myEmployee.GetEmployeeList();
      foreach (var Emp in allEmployees)
      {
         Console.WriteLine(Emp.Name);
      }
   }

Place the break point at the beginning of the for loop as shown below, and it shows the length of time elapsed by the time the debugger reaches it.

Profile01
Figure 1: Indicating the break point

Lambda Expression Evaluation in the Watch and Immediate Window

In versions of Visual Studio prior to Visual Studio 2015, if a developer had to evaluate the value of a lambda expression in the watch window or immediate window, a message would show, such as “LINQ and lambda expressions are not allowed in immediate or watch windows.” Now, while debugging the code using Visual Studio 2015, a developer can write LINQ queries in the immediate windows at run time to select or filter the lists or objects.

For example, in the following code sample:

static void Main()
   {
      var myEmployee = new MyEmployee();
      var allEmployees = myEmployee.GetEmployeeList();
      Console.ReadLine();

   }

The developer can evaluate a LINQ expression like as the one below in the immediate window.

(from emp in allEmployees select emp.Name).ToList();

allEmployees.Where(x => x.Name == cUserName).FirstOrDefault();

64-bit Edit and Continue: In Visual Studio 2015, ‘edit & continue’ is available for both 32- and 64-bit processes. However, 64bit edit & continue requires .NET framework 4.5.1 or above. In earlier versions, it was available only for 32-bit processes.

Diagnostic Tools

Diagnostic Tools are the tools that allow a developer to see historical information rather than values that can be observed at breakpoint. There are three main tools:

  • The Output window: Developers can see program output and debugger events.
  • IntelliTrace:Historical data in the Call Stack and Locals windows. The developer can see the list of every method call, and its parameters as well.
  • The Performance and Diagnostics hub: When a developer runs an application without a debugger, this tool is used to perform a comprehensive performance analysis of the application, such as the CPU Usage tool and the Memory Usage tool, depending on the nature of the performance issue.

Diagnostic Tools Window

The Diagnostic Tools Window allows the application of profiling tools to the debugging work. Select Show Diagnostic Tools or click Ctrl+Alt+F2, as shown in Figure 2, to launch diagnostic tools in VS2015.

Profile02
Figure 2: Launching VS2015 diagnostic tools

And that launches a Diagnostic tools window, as shown in Figure 3.

Profile03
Figure 3: The Diagnostic tools window

The diagnostic tools window shows the timeline in the upper half of the window, and detailed information in the bottom half of the window. VS2015 shows Events, Memory Usage tool, and the CPU Usage tool in the Diagnostics Tools window. In the earlier versions of Visual Studio, this data could be recorded only by using a profiling session. The Diagnostic Tools Window in VS2015 now will display the data always while the debugging session is active and thus any spikes in either CPU, memory, or garbage collections can be observed during debugging and the developer can easily track the code that is causing the spikes during the development phase itself.

CPU and Memory tools by van be enabled or disabled, as shown in Figure 4.

Profile04
Figure 4: You can toggle CPU tools and Memory tools off or on

The XAML UI Responsiveness tool is replaced with this; the developer can view a detailed breakdown of the UI thread performance for WPF and Universal Windows Projects and Windows Store apps. You also can observe network usage and network performance of Universal Windows Projects that make use of the WinRT HttpClient APIs.

IntelliTrace

IntelliTrace helps a developer to record specific events and debug errors by tracking related code, data during debugger events, and function call information. It records debugger events, handled and unhandled exceptions, .NET framework events, and share point events.

For example, if there is any unintended event left over on any UI control and that fires server side code to cause undesired results or any repetitive code causing delays, by using the historical call stack, the developer can check the code and find the bug easily. IntelliTrace allows users to record both live debugging as well as when application runs out side of Visual Studio environment.

A developer can control the events IntelliTrace considers “interesting” through Tools | Options | IntelliTrace | IntelliTrace Events.

Profile05
Figure 5: Controlling the events IntelliTrace considers “interesting”

If you select the second radio button, as shown in Figure 5, that is IntelliTrace events and calls information. IntelliTrace will intercept every method call and record it; this affects the app’s performance but it is a powerful debugging feature.

If you click an event in the list to expand it, you then can select Activate Historical Debugging and set the debugger to the point where IntelliTrace recorded the selected event, as shown in Figure 6.

Profile06
Figure 6: Selecting Activate Historical Debugging

You can double-click the event and it takes you to the specific code that relates to it for troubleshooting. You can filter the events from the filter dropdown, as shown in Figure 7.

Profile07
Figure 7: Filtering the events

    • Category Filter Control: By using this filtering control, you can hide or show event categories while they’re still being collected to focus on specific events. The current list of categories includes: ADO.NET, ASP.NET, Console, Data Binding, Debugger, Environment Variables, Exception, File, Gesture, Lazy Initialization, Output, Registry, Service Model, Threading, Tracing, User Prompt, and XAML, as demonstrated in Figure 8.

Profile08
Figure 8: Checking the IntelliTrace events

      • Thread Filter Control: Hiding or showing of events can be by the thread from which they were generated.
      • Show Events from External Code Button:You can bypass the debugger’s setting and show events from external code by using this option.

        Two kinds of event that can be tracked are Break events and IntelliTrace events. The events timeline is split into two tracks:

        Profile09
        Figure 9: Viewing the IntelliTrace events

      • Break events: The break events track shows events when break points are hit or at any debugger break statements. When you hover over a break event, a red color hat is shown for a break point, a yellow one for step, and blue for Break All.
      • IntelliTrace Events track: These are the events collected by IntelliTrace, such as Web requests, SQL queries, program output, file access, and many others. The red color denotes Exception, purple denotes Custom event, and grey is for everything else

The Diagnostic Tools Hub

VS2015 and 2013 both have the Diagnostics Tools Hub; you can launch that by selecting ‘debug ‘ -> ‘ Start Diagnostic Tools without Debugging’. This hub has many small tools that record and display CPU Utilization. You can run the application, record data, calculate results, and display the timeline visualization and details for recorded measurement in a Visual Studio diagnostic tools window.

In Visual Studio 2015, the hub contains the following set of tools:

      • Application Timeline: Examine where time is spent in the application.
      • CPU Usage: The developer can see where the CPU is spending time.
      • GPU Usage: For DirectX applications, it shows if GPU is bottlenecked.
      • Memory Usage: Memory leaks can be identified by investigating the application memory.
      • Performance Wizard: The Visual Studio Profiler used for CPU sampling, instrumentation, and .NET memory allocation.
      • Energy Consumption: Energy consumption can be examined.
      • HTML UI Responsiveness: UI thread activity for HTML-based apps.
      • JavaScript Memory: The JavaScript heap can be examined for memory leaks.
      • Network: Network operations, such as http request headers, play loads, cookies, time data, and more can be investigated.

Figure 10 shows sample CPU sampling while running an application.

Profile10
Figure 10: CPU sampling

Conclusion

As you’ve seen in this article, Visual Studio 2015 has many great debugging features that can help developers to write quality code by keeping performance in view.

About the Author

Sudha Polapragada works as a Lead Developer with a Government Agency. She spent lots of her programming years working as an ASP.NET programmer and with Microsoft Technologies. She also specializes in Oracle and the Microsoft BI suite. In her free time, she explores features on various development platforms, including various database, front-end technologies, Big Data, and cloud technologies.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read