Real world profiling with the OpenGL Profiler

OpenGL Profiler is a very powerful tool for debugging and optimizing OpenGL in Mac OS X. This technote describes basic usage of OpenGL Profiler as well as some real world techniques for application analysis and more advanced topics for more specific testing and profiling. The content of this document describes OpenGL Profiler v.4 which is included in Mac OS X Leopard but should help you use the previous versions as well.





Getting Started

OpenGL Profiler is located at /Developer/Applications/Graphics Tools.

The first time you open OpenGL Profiler, it will give you a choice to enable attaching to running applications as shown in Figure 1.

If you click enable Profiler will set the GL_ENABLE_DEBUG_ATTACH environment variable, which will take effect in the next login. Go ahead and enable it.

Figure 1: Enabling Profiler Attaching.

Figure 1, Enabling Profiler Attaching.

The Main Window launch or attach

There are 2 ways to analyze an application, by attaching to a running instance or by launching within Profiler.

Launching an application with Profiler

The main window with Launch application selected as shown in Figure 2 is where you can drag and drop your application bundle, or you can press the "+" button to add it in the open panel. Select the application name in the table, and press the Launch button to start the application. Also, you can click on the Launch Arguments field and add any arguments needed for the application prior to launching it.

Once running you can start to see the instant and peak Frame Rate.

The default update time of 5 secs for the frame rate display can be changed in the Preferences as shown in OpenGL Profiler Preferences.

Note: The frame rate field is updated by counting CGLFlushDrawable per unit of time, if your application is not double buffered this field might not display the correct information

Figure 2: Launching an application within Profiler.

Figure 2, Launching an application within Profiler.

Back to Top

Attaching to a running application

There might be times when attaching to a running application is more convenient, and this can be done by selecting Attach to application , choosing the appropriate process and the clicking the Attach button as shown in Figure 3.

Figure 3: Attaching to a running application.

Figure 3, Attaching to a running application.

Note: If an error as shown in Figure 4 is presented at this time, the most likely cause is that the environment variable GL_ENABLE_DEBUG_ATTACH is not set, or you have not logged out and logged back in after enabling the attach feature upon the very first launch of OpenGL Profiler. A similar message will be presented if trying to launch an application that is no longer at the provided path.

Figure 4: Launch or attach error

Figure 4, Launch or attach error

Back to Top

Collecting an OpenGL call trace

Once you have launched or attached to an application, you can collect statistics and trace view of the OpenGL commands submitted by your application.

To collect an OpenGL trace simply select Trace under the Views menu or press Command-Option-T.

The trace view is very useful to analyze the sequence of operations as well as to identify redundant calls or state mishandling.

Figure 5 shows a trace window with Lines #'s, Contexts and Timing information selected.

Figure 5: Trace window.

Figure 5, Trace window.

You can also collect backtraces by selecting Include Backtraces on the Profiler's main window.

This will collect backtraces with function names, so you can see who is calling a particularly slow call by clicking on the function name as shown in Figure 6. You may right click on it and choose to view the original image in a new window or tab.

Figure 6: Trace view with call stack

Figure 6, Trace view with call stack

Saving a Trace to a text file

The call trace can be saved to a text file for post processing by clicking on Save As Text

Traces can be long and might take some time to finish saving a text file which can get really large.

With Line #'s, Context and Timing selected the generated text file looks like:

1: 0x00a2d400     0.18 µs glBegin(GL_QUADS);
2: 0x00a2d400     0.08 µs glTexCoord2f(0.025, 0.025);
3: 0x00a2d400     0.08 µs glNormal3f(0, 0, 1);
4: 0x00a2d400     1.19 µs glVertex3f(0, 0.03, 3.15);
5: 0x00a2d400     0.10 µs glVertex3f(0.03, 0, 3.15);
6: 0x00a2d400     0.10 µs glVertex3f(0, -0.03, 3.15);
7: 0x00a2d400     0.08 µs glVertex3f(-0.03, 0, 3.15);
8: 0x00a2d400     0.07 µs glNormal3f(0, 0, -1);
9: 0x00a2d400     0.10 µs glVertex3f(-0.03, 0, 0);
10: 0x00a2d400     0.08 µs glVertex3f(0, -0.03, 0);
11: 0x00a2d400     0.08 µs glVertex3f(0.03, 0, 0);
12: 0x00a2d400     0.09 µs glVertex3f(0, 0.03, 0);

For information on the Save Using Filter see section Trace Filtering

Note: Collecting traces and backtraces is a very heavy operation and it will slow down your rendering, so this feature is designed to analyze relatively small portions of an application.

Back to Top

Collecting OpenGL call statistics

To collect statistics simply select Statistics under the Views menu or press Command-Option-S.

The window presents a table of information that can be reordered by clicking on the column heading.

The statistics view is great to see the estimated % of time spent in GL as a total, the percentages of time spent in GL per call and the percentage of App time that a particular call is taking as well as how many times a function is being called.

The "% App Time" field shows an estimate of how much time the application spends in a particular function. This is calculated by timing the each GL call and diving the cummulative results by the total application running time. Managing the timing of the GL calls might skew the numbers a few percentage points but the results are still representative. Shark might give you a more accurate number.

The "% GL Time" is an estimate based on the time a particular function takes in relation to the total time spent inside OpenGL.

Also the statistics can be scrolled in different time slices by using the Show slice at the bottom of the window.

Figure 7 shows the statistics window sorted by the largest Total Time spent in a function.

Figure 7: Statistics window

Figure 7, Statistics window

Saving statistics to a text file

In the same way you can save a call trace to a text file, you can do the same for the statistics, and the text file takes the form:

GL Function;# of Calls;Total Time (µsec);Avg Time (µsec);% GL Time;% App Time
...

Back to Top

Checking the Pixel Format

Sometimes it is useful to examine the pixel format of a context and Profiler allows you to do just that in the Pixel Format selection under the Views menu or press Command-Option-P

If there are multiple contexts, the one in black is the current context.

Among other things, this is where you look to see if an OpenGL context is double buffered, antialiased, etc.

Figure 8 shows what the Pixel Format window looks like.

Figure 8: Pixel Format View

Figure 8, Pixel Format View

There is also a way to override the pixel format that an application asks for with a custom temporary pixel format and this is shown in Launching with a custom pixel format

Back to Top

Setting breakpoints

One of the most powerful features of OpenGL Profiler is the ability to set breakpoints at which resources (textures, ...), GL state, scripts can be run, the multithreaded engine can be enabled, or even see if the current setup is going to run in the CPU or GPU,.

Profiler also allows you to control the execution (or bypass) at the OpenGL function level.

You can set breakpoints by selecting the Breakpoints option of Views menu or you can press Command-Option-B .

Figure 9 shows the breakpoints window.

Breakpoints can be set before or after executing a particular call, at a GL error, VAR error, thread conflict, and software fallback.

To set a breakpoint at a particular call, click under before or after on the line of the particular function of interest. To quickly scroll to a particular GL call you can type the first few letters of the particular function your are interested in.

To set a breakpoint in any GL errors simply click on the Break on Error button, similarly for Break on VAR error , Break on thread conflict and Break on SW fallback.

Figure 9: Breakpoint window.

Figure 9, Breakpoint window.

Once the application hits the breakpoint the call stack, context, kCGLCPGPUFragmentProcessing (fragment processing on the GPU), kCGLCPGPUVertexProcessing (vertex processing on the GPU) and kCGLCPCurrentRendererID (see /System/Library/Frameworks/OpenGL.framework/Headers/CGLRenderers.h) are presented.

In the event of a break for GL error, VAR error or thread conflict there is a useful status message at the bottom of the Call Stack view.

The Actions pop up allows you set and reset all breakpoints. It also allows you to attach scripts to execute at a breakpoint. This feature is discussed at Attaching and running scripts at breakpoints.

Figure 10 shows an application stopped at CGLFlushDrawable with everything running on the GPU at that point.

Figure 10: Stopped at CGLFlushDrawable.

Figure 10, Stopped at CGLFlushDrawable.

Back to Top

Controlling execution

Execution of a particular call is done by the selection of Execute on the line of that particular call. By default all OpenGL calls are set to execute. The Actions pop up allows you to set or reset global execution.

If a call is set to not execute, it becomes a noop and the consequences of this vary greatly depending on many factors. This functionality should only be used when the code, traces, etc are understood.

Sometimes is necessary to set breakpoints but ignore them for a period of time, this can be achieved by enabling the Ignore all breakpoints button.

To continue execution click on the Continue button at the lower right hand corner of the Breakpoints window.

Back to Top

Inspecting OpenGL state

The current OpenGL state can be checked at breakpoints by clicking on the State tab of the breakpoints window.

This is very useful when rendering anomalies are encountered, for state sorting ideas, etc.

Figure 11 shows the state right before a CGLFlushDrawable, the blue highlighted state is the state that has changed From default state .

Figure 11: Highlighted changes from default GL state.

Figure 11, Highlighted changes from default GL state.

Although not pictured if Since last breakpoint is selected the GL state changes would be highlighted in red. if both the options are selected GL state highlighted in purple signifies changes from default and since last breakpoint.

Back to Top

Viewing Resources

While stopped at a breakpoint a variety of resources can then be examined.

The resource view can be opened by selecting Resources from the Views menu or you can press Command-Option-R.

Textures

The Textures tab presents a list of textures objects sorted by their texture ID.

The ones highlighted in red are not loaded into Profiler yet, but a simple click on any of them should bring the texture out.

In this view, the textures can be examined, their target, internal format, source format, source type, and dimensions are shown.

The Mipmap Level slider at the bottom will let you select other mipmaps levels if defined, the Zoom Level slider allows to zoom in and out the texture in the view, the Source Blend Mode and Destination Blend Mode can be adjusted if necessary for proper viewing, the Background Color & Opacity picker will let you select the color and opacity of the background and the Flip Texture button will flip the texture vertically.

Figure 12 shows a texture resource view.

Figure 12: Examining the textures in the resource view

Figure 12, Examining the textures in the resource view

Back to Top

ARB Programs

ARB Programs can be examined in the Resources window under the Programs tab. As with any resource make sure the application is at a break point.

Back to Top

GLSL Shaders

OpenGL Profiler is very useful for examining and even editing shaders in your application. To get there make sure to stop at a breakpoint, open the Resources in the View menu if you haven't already and select the Shaders tab. Here Profiler presents a list of shader and program objects to inspect.

For editing or tweaking shaders in your application this way see the section Editing shaders.

Figure 13 shows what a program object might look like.

Figure 13: Program Object.

Figure 13, Program Object.

Figure 14 shows what a shader object with a vertex shader might look like.

Figure 14: Vertex Shader

Figure 14, Vertex Shader

Figure 15 shows what a shader object with a fragment shader might look like.

Figure 15: Fragment Shader.

Figure 15, Fragment Shader.

Back to Top

FBOs

Framebuffer Objects can be examined in the Resources window under the FBOs tab. As with any resource make sure the application is at a break point. Here Profiler presents a list of the FBOs it knows about.

Here you can identify the color, depth, and stencil attachments of an FBO and use the Texture or Renderbuffers tabs to inspect their contents.

Figure 16 shows the structure and attachments of the FBO.

Figure 16: FBO structure in the resource view

Figure 16, FBO structure in the resource view

Back to Top

Renderbuffers

Renderbuffers can be examined in the Resources window under the Renderbuffers tab. As with any resource make sure the application is at a break point.

The functionality here is very similar to the Texture tab as described above. There are adjustments for zoom, source and destination blend, background color and opacity, and the ability to vertically flip the image.

Figure 17 shows the contents of a Renderbuffer.

Figure 17: Renderbuffer in the resource view.

Figure 17, Renderbuffer in the resource view.

Back to Top

VBOs

Vertex Buffer Objects can be examined in the Resources window under the VBOs tab. As with any resource make sure the application is at a break point.

Profiler shows you the properties associated with a VBO.

Figure 18 shows the contents of a Renderbuffer.

Figure 18: Vertex Buffer Object view

Figure 18, Vertex Buffer Object view

Back to Top

VAOs

Vertex Array Objects can be examined in the Resources window under the VAOs tab. As with any resource make sure the application is at a break point.

Back to Top

Buffer Views

Under the view menu, several buffers can be examined when stopped at a breakpoint. Below are some screen captures from a particle shader in the GLSLShowpiece example.

Back bufffer

Figure 19: Current back buffer

Figure 19, Current back buffer

Back to Top

Depth buffer

Figure 20: Initial depth buffer view

Figure 20, Initial depth buffer view

Figure 21: Depth buffer view with max and min range

Figure 21, Depth buffer view with max and min range

Back to Top

Alpha buffer

Figure 22: Alpha buffer

Figure 22, Alpha buffer

Back to Top

Stencil buffer

Figure 23: Stencil buffer

Figure 23, Stencil buffer

Back to Top

Real World Techniques

Checking the Application for Errors

OpenGL Profiler can help to quickly check an application for errors by setting breakpoints of GL errors, thread errors, etc.

  • On the breakpoint window, set the appropriate breakpoint for GL errors

  • Launch or attach to the application if you have not done so

  • Monitor the breakpoint window to see if catches an error

Figure 24 shows Profiler catching an error.

Figure 24: Break on error

Figure 24, Break on error

Back to Top

Checking GPU or CPU execution of current state

The easiest way to check in OpenGL Profiler if the application is indeed executing on the GPU is to let Profiler break on software fallbacks.

  • On the breakpoint window, check the SW fallback option

  • Launch or attach to the application if you have not done so

  • Monitor the breakpoint window to see if catches a software callback

Figure 25 shows Profiler catching a software callback. Note that kCGLCPGPUFragmentProcessing and kCGLCPGPUVertexProcessing are both GL_FALSE at the point, indicating that fragment processing and vertex processing are currently handled by a software recovery mechanism. The value of kCGLCPCurrentRendererID also becomes distinct.

Figure 25: Break on software fallback

Figure 25, Break on software fallback

Back to Top

Collecting Trace and Statistics for a single frame

Collecting the trace and statistics of a single frame can give you a quick (if somewhat narrow) view of what the application is doing.

  • Launch or attach to the application of interest

  • Navigate the application to the suspect area

  • Set a breakpoint in CGLFlushDrawable for double buffered contexts or glFlush for single buffered ones

  • Once stopped, open (or clear) the trace and statistics windows

  • Press Continue once at the bottom of the breakpoints window

Here are a few things to consider in the trace:

Do you see any duplicate or redundant calls?

On this single frame look for state management, can it be improved by state sorting?

Do you see any single call taking significantly more time than the others?

Is the frame not done rendering? Maybe more than one CGLFlushDrawable / glFlush are being sent per frame.

Back to Top

Enabling Multithreaded execution of the OpenGL Framework

Some applications might benefit from enabling multithreaded execution of the OpenGL Framework.

OpenGL Profiler allows you to test this option without any coding.

  • Launch or attach to the application of interest

  • Note the frame rate at somewhat repeatable point

  • Set any breakpoint. CGLFlushDrawable is common for double buffered contexts.

  • Once stopped select Force on in the Multi-thread control

  • Clear the breakpoint and

  • Press Continue once at the bottom of the breakpoints window

  • Note the frame rate under multi-threaded execution

Note: Not all applications will benefit. See Enabling multi-threaded execution of the OpenGL framework

Back to Top

Monitoring VRAM with Driver Monitor

Although a separate application from OpenGL Profiler, OpenGL Driver Monitor is another key tool when debugging and optimizing OpenGL applications.

There is a performance cliff when VRAM becomes full, so knowing how your application uses VRAM is essential.

  • In OpenGL Profiler select Driver Monitor under the View menu to start OpenGL Driver Monitor

  • In OpenGL Driver Monitor select the appropriate driver. Usually this is accomplised by pressing Cmd-1 on machines with a single graphics card or you can select it under Driver Monitors in the Monitors menu

  • On the driver monitor window click Parameters and double click on Current Free Video Memory

Page Offs and Page Ons of textures and surfaces are others you might want to monitor in relation to VRAM.

Back to Top

Editing shaders

With Mac OS X Leopard, OpenGL Profiler provides the ability to modify shaders on the fly.

  • Launch or attach to the application of interest

  • Set a breakpoint and wait for the application to stop

  • Open the Resources View and select the Shaders tab

  • Select the desired shader object on the left. See Figure 14

  • Edit the shader in the Source tab and press Compile

  • If compilation failed you can use the Log tab. You can use the Revert button to return to the original code and then hit Compile again

  • if the compilation was succesful then release the breakpoint and hit Continue on the breakpoints view

Back to Top

Disabling OpenGL Execution

Under some circumstances you might want to disable procession of OpenGL functions. This is possible within Profiler by selecting Execute none under Actions in the Breakpoints view. To restore execution select Execute all

Back to Top

Attaching and running scripts at breakpoints

OpenGL Profiler allows you to insert (at a performance cost) small amounts of GL code or Scripts to be executed while stopped at a breakpoint.

First you must create the script. Open the Scripts view and click on the "+" button. This generates an empty script that you can rename. On right side you can edit the contents of the script as shown in Figure 26 .

Figure 26: The scripts view

Figure 26, The scripts view

Once created this script can be executed manually while stopped in a breakpoint. To automatically execute the script, attach it to a breakpoint by selecting Attach Script... under the Actions in the Breakpoints view. You can choose to execute the script before or after the break, and continue automatically or not after the execution, as shown in Figure 27.

Figure 27: Attaching a script to a breakpoint.

Figure 27, Attaching a script to a breakpoint.

Note: Keep in mind that running scripts automatically in a call that is used repeatedly is not a good way to measure performance differences since the execution and continue is a very expensive operation.

Back to Top

Trace Filtering

OpenGL Profiler allows you to create a custom filter that takes stdin and put something to stdout to save your trace.

A possible example might be finding a the slowest calls. Consider the simple shell script at Listing 1 and the image at Figure 28.

The script will generate a sorted (increasingly slower) output of the trace once you click the Filter button. Then you could use the line number of the output to trace back to the surroundings where the call actually took place. This will help in figuring out what particular frames might be slowing down your scene.

Listing 1: sortedByTime.sh.

#!/bin/tcsh -f 
awk '{ print $3" "$0 }' | sort -n

Figure 28: Using sortedByTime.sh

Figure 28, Using sortedByTime.sh

Back to Top

Launching with a custom pixel format

OpenGL Profiler allows you to Launch an application with a custom pixel format. By selecting the Launch Settings in the main window as shown in Figure 29

Among other things, this allows you to try different antialising settings and quickly seeing the results without modifying the source code of the application.

Figure 29: Custom Pixel format.

Figure 29, Custom Pixel format.

Back to Top

Programatic control of OpenGL Profiler

OpenGL Profiler also provides some programmatic control..

Controlling breakpoints

This is a very powerful feature that allows your application to set and clear breakpoints when attached to OpenGL Profiler.

You can set a breakpoint by making an array with 3 GLints:

  • Parameter 0: function ID (see CGLProfilerFunctionEnum.h)

  • Parameter 1: the logical OR of kCGLProfBreakBefore or kCGLProfBreakAfter, indicating how you want the breakpoint to stop: before entering OpenGL, on return from OpenGL, or both

  • Parameter 2: is used like a boolean which turns the breakpoint on or off

and then passing this array to CGLSetOption().

Listing 2 shows how to programmatically set a breakpoint at CGLFlushDrawable.

Listing 2: Setting a breakpoint at CGLFlushDrawable.

#include "OpenGL/CGLProfiler.h"
#include "OpenGL/CGLProfilerFunctionEnum.h"
...
   GLint myBreakpoint[] = { kCGLFECGLFlushDrawable, kCGLProfBreakBefore, 1;}
   CGLSetOption( kCGLGOEnableBreakpoint, myBreakpoint );
...

Back to Top

Inserting comments in the Trace view

Comments can be printed out in the Trace window using the technique illustrated in Listing 3

Listing 3: Inserting comments in the trace.

#include <OpenGL/CGLProfiler.h>
...
    CGLSetOption(kCGLGOComment, (long) "***** My Comment is here *****");
...

The resulting comment looks like this in the trace:

21561: 0.00 µs /* ***** My Comment is here ***** */

Back to Top

Controlling the trace logging

You application can also control when to start/stop the trace logging as shown in Listing 4

This gives you fine grain control over what traces to collect in a specific section or time for example.

Listing 4: Pass GL_TRUE to start and GL_FALSE to stop tracing.

#include <OpenGL/CGLProfiler.h>
...
    CGLSetOption(kCGLGOEnableFunctionTrace, GL_TRUE);
...

Listing 5: Clearing the trace window.

#include <OpenGL/CGLProfiler.h>
...
    CGLSetOption(kCGLGOResetFunctionTrace, NULL);
...

Back to Top

Controlling the collection of statistics

You application can also control when to start/stop the collection of statistics as shown in Listing 6.

Make sure to open the statistics window first.

Listing 6: Controlling the statistics.

#include <OpenGL/CGLProfiler.h>
...
    // To start
    CGLSetOption(kCGLGOResetFunctionStatistics, NULL); // if you want to reset counters to zero
    CGLSetOption(kCGLGOEnableFunctionStatistics, GL_TRUE);
...
    // To stop the counters
    CGLSetOption(kCGLGOEnableFunctionStatistics, GL_FALSE);
...

Back to Top

OpenGL Profiler Preferences

Figure 30: Preferences window

Figure 30, Preferences window

Document Revision History

Date Notes
2008-09-16 First Version

Posted: 2008-09-16


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.