Solving WPF Performance Problems: Step 1

This is the first in a series of upcoming blogs about solving WPF performance problems.  I’m going to start with a basic overview of the tools, approaches, and thinking needed to tackle these challenges.  If you’re skills are already beyond that point stay tuned for my upcoming posts – I have some neat approaches and insights into the WPF stack that I’ll be getting to shortly.  But for now, I’ll be starting out with the basics to ensure everyone is up to speed.

 

First, let me point out that perf problems aren’t scary or intractable.  Sometimes they seem totally abstract initially, but that’s normal.  Performance optimization is all about deciding whether or not you’re paying the right price for a given set of functionality.  Yah there’s tweaking and tuning, but your most important goal is understanding every piece of your app that isn’t meeting expectations.  To gain that understanding, you need data.

 

Over the next few weeks I’m going to help you gather data by first walking you through the tools, and then shedding light on the bits of the WPF callstack you need to make good performance decisions.

 

From a high level, solving most perf problems can be broken down into 3 steps:

 

  • Step 1.  Finding out where resources are going (e.g., CPU Time, working set).  Smart people have spent months, if not years, writing lots of great tools to gather this data for you.  Learn to use them and your half-way there.
  • Step 2.  After the grunt work of collecting data, you get to the fun stuff: determining why time and/or memory are being spent where it is.
  • Step 3.  Finally, the last part comes naturally: deciding whether the costs are worth the benefits.  You’ll find yourself asking questions like ‘Do I really need to time that much doing X’, or ‘Is there another way I could do Y’?

 

Step 1. Using the Tools to Collect CPU Time

 

Overview of the Tools

 

You need a profiler.  To know anything about the performance of your app, you need a profiler.  There are a handful of these on the market and I’m not going to debate which is best.  Since I work at MS, I’m using Visual Studio 2005 Performance Analyzer included in Visual Studio 2005 Team Edition for Developers, and Visual Studio 2005 Team Suite.  It also happens to be available free for us Microsoft-ies, but you can use it free too (for 180 days).  Get the 180-day free trial of Team Suite here.

 

Sample-based or Instrumentation-based

 

When trying to measure any system, the principle Heisenberg observed always has a way of coming up. This is especially true about performance analysis.  To mitigate it there are 2 ways to profile that you should know about.  Sample-based profiling introduces low-overhead by not tracking every single function call.  This gives you inaccurate results for the smaller/shorter functions in your app – if you’re familiar with sampling theory it’s the classic aliasing problem.

 

The other option is instrumentation-based profiling, which introduces much higher overhead by tracking every single function call.  This higher overhead means your app behaves even more differently than it would without it, but the time spent in all function calls is known (well actually, that’s just an estimate too). 

 

For simple problems (e.g., root-causing large bottlenecks) you can get away with using only one method, but by using both you’ll get a decent picture of what your app is doing. 

 

Quick Walk-Thru

 

Open up your project in Visual Studio 2005.  For this experiment I’m just going to create a default WinFX application using the Orcas add-in.  Once inside, the Performance Analyzer can be found from the Tools menu | Performance Tools | New Performance Session.  Notice the combo-box in the Performance-Explorer pane currently set to ‘Sampling’.  You should leave it for now, but that’s where you switch between the instrumentation & sample - based profiling options I mentioned earlier.

 

Always profile optimized Release bits, and not Debug.  Double-check that Release is selected in Build menu | Configuration Manager.

 

Next, make sure you have full symbol information.  You can get symbol information for a bunch of unmanaged Microsoft binaries by hooking into the public Microsoft symbols server: Tools menu | Options … | Debugging | Symbols.  Click the new icon, and add https://msdl.microsoft.com/download/symbols to the list.  Then click Ok.  Make sure symbols for any other unmanaged binaries in your application are also available, otherwise the performance data will only include the module for each function, not the actual function names.  You can double-check this by viewing the ‘Modules’ window when debugging (when debugging, Debug menu | Windows | Modules). 

 

In the Performance Explorer pane, select Targets | Add Target Project.  This let’s the tool know what binaries you’ll be profiling (and specifically, all the binaries associates with your project).

 

 

Finally, begin your profile by clicking the Launch button on the Performance Explorer pane.  Then hit the Stop button when the actions you want to profile have finished.  After a minute or so your new profile will be available.  Browse thru the various views and become comfortable with them, especially the Call Tree view, where you can see exactly where time is being spent in your application.

 

Four Profiling Tips

  • Learn to use the command-line profiler.  Using this removes overhead introduced into your system by the VS IDE.
  • If you’re not trying to optimize startup-time, don’t profile it.  Start profiling after your app is running.  In fact, in general, make sure your profile only includes the set of actions you’re trying to optimize (e.g., resizing, scrolling, animating, etc.).
  • Short profiles (< 1 second) can miss important call sequences when started from the command line or the IDE, due to the latency involved in starting/stopping profiling.  Use longer profiles to account for this.
  • Whatever you’re profiling, try to do a lot of it when profiling is on (e.g., profile 20 controls instead of 1 control, profile animation sequences for seconds instead of milliseconds, etc). 

Final Thoughts

 

Becoming proficient at using a profiling tool is the first step toward solving all of your performance problems.  Spend a few days gathering some data and next week we’ll work on interpreting the results, including understanding why & where time is being spent in WPF.  If you have any specific questions about your profiles before then make sure and let me know, and I’ll answer them in my next post.  Also, if there’s enough interest, I’ll post walk-through’s on how to get instrumentation-based CPU profiles & working-set data in the future.

 

More information on the Visual Studio Performance Analyzer is available at: https://msdn2.microsoft.com/en-us/library/z9z62c29(VS.80).aspx