Episode I – The Frozen Screen
Do you want to test your optimization chops with JustTrace
? Does using a guide feel like cheating? Then don’t read this article! Instead, download the JustTraceExamples
project and fix the issues. This article will be here if you are stuck.
Everyone else, press ↑, ↑, ↓, ↓, ←, →, ←, →, b, a, b, a, start.
Each episode in this series is a walkthrough for a particular performance issue. I will describe how to analyze and solve the issue using JustTrace and other tools, such as JustDecompile and Fiddler.
Download JustTraceExamples and open it in Visual Studio. There are currently two projects in this solution. One, named JustTraceExamples, to run through this exercise and another, JustTraceExamples.Optimized, with the optimizations from this article applied.
Enable JustTrace using Main Menu -> Telerik -> JustTrace -> Enable JustTrace.
Start the application from Visual Studio. I recommend starting without debugging to avoid having both a debugger and a profiler attached to the process. JustTrace will display a dialog to start a profiler. Select Tracing Profiler and click Continue.
The application will then load with following screen.
It instructs you to press Load Events, which will load and parse a large XML file. It tabulates all event tags found within the file and presents the count for each id encountered. Press the button.
This operation freezes the application while it runs. There is no indication anything is taking place aside from its unresponsiveness. Here is my screen after it finally returns.
In many cases, user perception is more important than actual performance for software. Although the loading operation took more than 23 seconds to complete, the first step is to eliminate the unresponsiveness.
Click the Kill Profilee button on the newly opened JustTrace panel in Visual Studio.
Click on the Timeline, select a range, and then click Show Snapshot.
JustTrace opens the All Threads view with the hot path (indicated by fiery red expanders) open.
You can immediately identify this problem based on the hot path. The application is inside RadButton.OnClick for nearly 21 seconds, locking up the UI thread. Following the call tree further, the ultimate culprit is EventParser.CountEvents.
You can make your application more responsive by moving long running processes to a separate thread. That’s easy to do with C# 5. Open EventParser.cs and find the CountEvents method. Then create an async version of this method and wrap a call to the original within.
You will need to change MainViewModel.LoadEvents method as well. The LoadEventsCommand wraps this method in delegate, and that command is bound to the RadButton.
There is no need to support two versions for the ViewModel. Add the async modifier to the LoadEvents method then change the CountEvents call to use the asynchronous version.
Note: I decided that the EventParser class should have an asynchronous version of the CountEvents method. An alternative is to change only the LoadEvents method by wrapping the CountEvents call in a Task without modifying the EventParser class.
Run the application to view how the user experience has improved with this one, easy change. Be sure to take another snapshot.
EventParser.CountEvents still consumes a significant amount of time, but it’s now running in a separate thread. This is apparent since it’s an immediate child of the process. This is more obvious by deselecting Merge Threads.
Users are more accepting of poor performance when the UI is responsive during processing. There’s peace of mind in knowing the application isn’t lock up, and the user can still close it if necessary. C# 5 makes asynchronous programming relatively simple, and JustTrace makes it easy to find the most effective places to apply these skills.
In episode 2, I will begin optimizing the CountEvents method. Until then, happy profiling!
Chris lives in the Southern US and is not fond of frozen anything, especially applications.