-
Notifications
You must be signed in to change notification settings - Fork 126
Quick Instructions
Before you try tracing anything first make sure you have libturbojpeg installed:
sudo apt-get install libturbojpeg:i386 libturbojpeg
Then make sure you have the right build of vogl. If your app is 32-bit, you need to build the 32-bit version of vogl, etc. You won't get a good error if you mess this up, so use something like objdump, nm, etc. if you're not sure. See README.md for build instructions.
- Tracing using steamlauncher.sh
vogl/bin/steamlauncher.sh --gameid vogl/vogl_build/bin/glxspheres32
vogl/bin/steamlauncher.sh --gameid vogl/vogl_build/bin/glxspheres64 --amd64
You should now have something like the following in your temp directory:
/tmp/vogltrace.glxspheres64.2014_01_20-16_19_34.bin
- Tracing by directly using libvogltrace32/64.so:
This method will be familiar to you if you've used apitrace's tracer (glxtrace.so) before. The major difference is libvogltrace.so doesn't default to always writing a trace file. In order to get a full-stream trace you must specify the "--vogl_tracefile X.bin" option in the VOGL_CMD_LINE
environment variable. Alternately, the tracer will try to read its command line options from the vogl_cmd_line.txt
file in the current directory. (Unlike apitrace, our tracer can write single/multi-frame snapshots too. See "Single/multi frame capturing mode during tracing", below.)
Here's a example bash script that'll create a full-stream trace of the executable specified on the command line:
# trace.sh
#!/bin/bash
export VOGL_CMD_LINE="--vogl_debug --vogl_dump_stats --vogl_tracefile trace.bin --vogl_pause"
export LD_PRELOAD=/home/richg/dev/vogl_build/bin/libvogltrace32.so
$*
Example usage:
trace.sh ~/dev/vogl_build/bin/glxspheres32
If this works libvogltrace will wait for a keypress very early during initialization and then start full-stream tracing to "trace.bin". While the tracer is waiting you can attach gdb to the process if you want to debug the traced app or the tracer. If you fail to get a "waiting for keypress" message then something went wrong. The LD_DEBUG
environment variable can be useful when debugging LD_PRELOAD problems.
If for some reason LD_PRELOAD isn't your thing then go ahead and manually load libvogltrace32/64.so into your app and use dlsym() on the gliGetProcAddressRAD
exported function. (Or you can just call glXGetProcAddress()
, but I don't think that will work on Optimus. BTW, we don't officially support Optimus.)
- Basic replay of a trace:
/home/richg/dev/vogl_build/bin/voglreplay32 trace
- To convert a apitrace .trace file to our trace format:
You basically just trace apitrace's glretrace app in --benchmark mode (so apitrace doesn't do tons of glGetErrors):
trace.sh glretrace blah.trace --benchmark
libvogltrace32/64.so will sit in between glretrace and the driver and capture all its calls to a vogl .bin trace file. We test apitrace capturing in our regression suite so we make sure it's very reliable. Note apitrace can't currently trace some more obscure things that we do, like the glXUseXFont() call that is used by glxspheres.
You can do single/multi-frame snapshots of glretrace's output too -- it's just another GL/GLX app to us. Note we don't support trace compression right now, so our traces are going to be larger vs. apitrace's. Storage and bandwidth is super cheap these days so it hasn't been a priority.
- To play back a trace with verbose debug output:
voglreplay32 --debug --verbose trace
- Force debug contexts during replaying:
voglreplay32 trace --force_debug_context
- Highest performance playback speed (no glGetErrors(), no divergence checks):
voglreplay32 trace --benchmark
- To losslessly dump the trace to JSON and directly play it back:
mkdir dump
voglreplay32 trace --dump dump/jdump
voglreplay32 dump/jdump
- Read a JSON trace and compile it back to a single file binary trace file:
voglreplay32 --parse dump/jdump newtrace.bin
- To trim any type of trace (full-stream or a already trimmed trace) to a new trace file:
voglreplay32 newtrace.bin --trim_file trimmed.bin --trim_len 2 --trim_frame 10
- To play back a trace endlessly (useful for very short trimmed traces):
voglreplay32 trimmed.bin --endless
Feel free to edit JSON traces (and the loose files they refer to) as they are played back endlessly and see the results in semi-real time. Right now, if you introduce an error (like a compile or program link failure) the replayer will stop (we would like to flesh this feature out eventually).
- To play back a trace in basic "interactive" mode:
voglreplay32 trace -interactive
There will be no keyframes so seeking will be slow. (We'll add a wiki on this soon.)
Hit space to pause, s for slow mode, left/right arrows while paused to seek (ctrl, shift, alt + left/right seek further) - see the voglreplay help text for more keys. The J and T keys will trim at the current trace position.
Note: The replay will flicker while paused on a single frame at the moment because we now restore the frontbuffer's contents during a snapshot restore. After the snapshot restore we play the frame back, then swap (which changes the frontbuffer again) and rewind. We'll be adding a low-level flag to disable restoring the front buffer very soon (because it's of questionable value).
- Single/multi frame capturing mode during tracing
# single_frame_tracing.sh
#!/bin/bash
export VOGL_CMD_LINE="--vogl_debug --vogl_dump_stats --vogl_tracepath ./ --vogl_pause"
export LD_PRELOAD=/home/richg/dev/vogl_build/bin/libvogltrace32.so
$*
Now launch your app using this script, which uses "--vogl_tracepath X"
vs. "--vogl_tracefile X"
. The tracer will monitor the current and trace directories for a file named "__trigger_capture__"
. Once it sees this file it'll capture the next frame to a trace file (i.e. immediately after the next glXSwapBuffers).
Optionally, the first line of this file can specify the # of frames to capture ("all" = all remaining frames, or until the file named "__stop_capture__"
is detected). The optional 2nd line can contain the base filename of the resulting trace file.
- To search a trace for all glXCreateContext
calls:
voglreplay32 --find trace -find_func glXCreateContext
- To search a trace for all instances of GL_DIFFUSE in any parameter or parameter array:
voglreplay32 --find trace -find_param GL_DIFFUSE
- To search a trace for all uses of texture handle 42 in a parameter or parameter array:
voglreplay32 --find q3_trace.bin --find_param 42 --find_namespace GLtexture
- To find all calls to functions beginning with the prefix "glX" using POSIX regex:
voglreplay32 --find --find_func "glX.*" q3_trace.bin
- To limit the find to the specified frame interval:
voglreplay32 --find --find_func "glX.*" --find_frame_low 8 --find_frame_high 10 q3_trace.bin
- To limit the find to the specified call interval:
voglreplay32 --find --find_func "glX.*" --find_call_low 10000 --find_call_high 12000 q3_trace.bin
There are many more --find options, see the help text for info. You can also just dump to JSON and grep the results but that can be a huge pain (due to aliasing and lack of context).
- To dump trace statistics (GL func and extension histogram, etc.):
voglreplay32 --info trace.bin
- To dump a PNG screenshot after every draw or blit:
mkdir dump
voglreplay32 steam_trimmed2 -dump_framebuffer_on_draw -dump_framebuffer_on_draw_prefix dump/cap
You'll wind up with a potentially large number of PNG files beginning with the "cap" prefix in the "dump" directory, like this:
cap_GLCTR01263550_glEnd_FR000000_DCTR00000_W0286_H0050_FBO0162_GL_COLOR_ATTACHMENT0_GL_RGBA8_TEX0224.png
The following info is encoded in each filename:
- GLCTR: GL call counter
- FR: Frame #
- DCTR: Frame draw counter
- W, H: Width/height of FBO (or the default framebuffer)
- FBO: Framebuffer object handle #
- FBO attachment
- Texture's internal format
- Texture handle #
- How to detect if libvogltrace is tracing your app:
See if you can successfully dlsym() gliGetProcAddressRAD
.
Another, more sneaky way is to map a buffer for write-only access. Then call glGetBufferParameteriv
with GL_BUFFER_ACCESS
and make sure the buffer was really mapped as writable only. If it was mapped as read/write then somebody is tracing your calls. (Behind the scenes, libvogltrace will always force your buffer maps to be readable so it's able to safely trace the actual contents of buffers right before they are unmapped. Of course, somebody could just spoof the return value of glGetBufferParameteriv but we don't do that.)