Daniel Hahn

The Profiler

This week I had a first encounter with the new Visual Studio's profiler. Fortunately, my colleague Markus had already researched it's pecularities ;-)

I didn't really try the GUI setup, though. I'm sure it works fine for regular projects, but for something large and complex you're bound to get your hands dirty.

The profiling comes in two flavours: "Sampling" and "Instrumentation". Basically, the sampling mode gives you an overview of the performance, while the instrumentation mode will really profile each function call and allows you to get into the details. I'll only talk about the instrumentation mode from now on.

If you just turn the instrumentation profiler loose, it will generate huge amounts of data; you will really want to limit the profiling to the parts of your application which are actually interesting.

Fortunately, you can control the profiler programatically. In native C++ applications, you'll have to link against VSPerf.lib, which comes with Visual Studio. Then you can do something like:

#include <VSPerf.h>
...

StartProfile(PROFILE_GLOBAL, PROFILE_CURRENTID);

DoSomethingNasty();

StopProfile(PROFILE_GLOBAL, PROFILE_CURRENTID);

There are a bunch of other commands and options, which you can look up in the documentation.

For C++ applications (native and managed) you'll also tell the linker to emit profiling information. The setting is under Linker -> Advanced -> Profile in the project preferences.
Managed applications need to reference the Microsoft.VisualStudio.Profiler.dll and do something like:

#using Microsoft.VisualStudio.Profiler

...

DataCollection.StartProfile(ProfileLevel.Global, DataCollection.CurrentId);

DoSomethingNasty();

DataCollection.StopProfile(ProfileLevel.Global, DataCollection.CurrentId);

(I had a strange problem with mixed mode: I tried to controller from a managed C# assembly, which was called from managed C++ code, which was in turn called from the native C++ application. This resulted in the C# calls just being skipped over, without error. Even so, controlling the profiler in the native code worked fine. If you have a solution to this, let me know.)

Now it's time to fire up the command prompt and set up your profiling session. Unfortunately the cygwin shell seems to be problematic, since windows scripts seem to have problems to set new variables in the bash.

Before you get to the actual profiling, you'll need to instrument your files:

VSInstr <MyExeOrDll>

If you instrument managed assemblies with a strong name, this will whack the file's signature. You'll have to re-sign the assembly:

sn -R <MyManagedExeOrDll> MySillyKey.snk

And, if you ever want to see the symbols (method names) from managed code, you'll have to set up some environment variables. Fortunately, there's a script coming with the profiler which allows you to do that. There are many options to it, but it will probably look like this:

VSPerfCLREnv /traceon

You can get a list of the possible settings by using the /? switch.

Now that you're all set to go, it is time to start the profiler session:

VSPerfCmd /start:trace /output:MyResults.vsp

VSPerfCmd /globaloff

The first command start the profiler, and the second command disables the profiling. This means that the profiler won't collect any data until it hits the StartProfile() command in your code.

Now you can start up your application, do the things that you want to profile, and shut it down again.

After that, you have to shut down the profiler:

VSPerfCmd /shutdown

While you can use the command-line analysis tools, it will probably be easiest to just click on the new .vsp file to open it. This will bring up a new instance of Visual Studio with the profiling results; depending on the amount of data collected, you'll have to wait for a few minutes until the analysis is completed.

And that's it! Here are some more links with information on how to use the profiler:

This project is maintained by averell23