Profiling your application using PIXBy Rim van Wersch, January 7 2006 |
Profiling allows you to analyze the performance of your application on a call-to-call, per frame basis. This is great for finding performance bottlenecks and getting a good overview of the actual calls made to DirectX from your application. The DirectX SDK comes with a rather decent profiler, called PIX, which we'll use in this tutorial.
How does it work?
The PIX profiler can be set up to log a number of statistics, but one useful setup is to log all calls to DirectX for a given number of frames. This will give you an insight of what's happening 'under the hood' of your application. For further details about how to set this up and more information on PIX, please refer to the 'further reading' section at the bottom of this page.
Using PIX
So if we're not gonna explain in detail how to work with PIX, then what good is this tutorial? Well, as you can see from the screenshot above, PIX collects massive amounts of data which makes it difficult to find out the information you're interested in. In addition, PIX does not track the duration of single calls to the DirectX API, so we can't really find any bottlenecks. Luckily for us, DirectX provides some utility functions to make this a whole lot easier and to get the most out of PIX.
Unfortunately, Managed DirectX does not support these methods, so we've had to create a little wrapper around these functions to get it to work for MDX. At the bottom of this page you'll find the link to our Profiler utility class, which you can use to help profiling your MDX applications. By calling the BeginEvent/EndEvent methods you can specify custom 'blocks' in the code, which are used to group the DirectX calls shown in the PIX profiler. This way you can organize the calls into the various sections used in your rendering code, making it much easier to find out how long each section takes and what is done exactly in a specific section.
Below is some sample code on how the Profiler class (and ProfilerEvent helper class) can be used to break up some fictional rendering code into various sections. The functions in the Profiler class map directly to the DirectX API calls, so if you want to know more details about them, check out the link to the C++ profiling topic below.
public void OnFrameRender(Device device, double appTime, float elapsedTime) { ? ? ? ? ? ?// using the IDisposable ProfilerEvent, so we don't have to call Profiler.EndEvent() ? ?using( new ProfilerEvent( "OnFrameRender" )) ? ?{ ? ? ? ?// You can also call BeginEvent and EndEvent manually ? ? ? ?Profiler.BeginEvent( "Prepare scene" ); ? ? ? ?scene.Prepare(device); ? ? ? ?Profiler.EndEvent(); ? ? ? ?bool beginSceneCalled = false; ? ? ? ?// Clear the render target and the zbuffer ? ? ? ? ? ? ? ? ? ?device.Clear(ClearFlags.ZBuffer | ClearFlags.Target, 0x002D32AA, 1.0f, 0); ? ? ? ?// An example of setting a general purpose marker in the profiler ? ? ? ?Profiler.SetMarker( "Device cleared" ); ? ? ? ?try ? ? ? ?{ ? ? ? ? ? ? ? ? ? ? ? ?device.BeginScene(); ? ? ? ? ? ? ? ? ? ?beginSceneCalled = true; ? ? ? ? ? ?using( new ProfilerEvent( "Render scene" ) ) ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?scene.Render(device); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ?if (showUI) ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?using( new ProfilerEvent( "Render render GUI and texts" ) ) ? ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ?// Show frame rate ? ? ? ? ? ? ? ? ? ?RenderText(); ? ? ? ? ? ? ? ? ? ?// Show UI ? ? ? ? ? ? ? ? ? ?hud.OnRender(elapsedTime); ? ? ? ? ? ? ? ? ? ?sampleUi.OnRender(elapsedTime); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ?} ? ? ? ?} ? ? ? ?finally ? ? ? ?{ ? ? ? ? ? ?if (beginSceneCalled) ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?device.EndScene(); ? ? ? ? ? ?} ? ? ? ?} ? ? ? ? ? ? ? ? ? ? ? ?} }
Files for this tutorial
Filename | Size |
? Source for the Profiler utility class | 1.5 KB |
Further reading