Android OpenGL ES Tracer

by groleo

It’s an Eclipse plugin and a shared library that let you trace the GLES calls performed by an application. Texture data and framebuffer can also be extracted, but as expected, they add a noticeable overhead.

The code producing the traces is found in frameworks/native/opengl/libs/GLES_trace/
which is compiled into libGLES_trace.so
You then control and gather data using the Eclipse plugin :
sdk/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/
Now that you have an rough idea where to find the source code, I’ll detail the way it’s working.
ImageIt all starts in Android’s EGL library, the display initialization code (the top level of the blue call-stack) calls initEglTraceLevel to check if the EGL library is supposed to do any tracing
and if yes, what type of tracing.
All this information comes thru the Android Properties system

Tracing options

The type of tracing is controlled by the debug.egl.trace property, which can
take three values:
  1. systrace
  2. error
  3. number 1

1. When debug.egl.trace is systrace, then the GLES calls are redirected to the Systrace subsystem

2. If debug.egl.trace is error, the tracer will log (logcat log) the errors in the GLES functions plus a callstack.

3. Setting debug.egl.trace to 1 will redirect the tracing to Android log (logcat again).
Here though, if you also set debug.egl.debug_proc to a valid process name, then
only that application will be traced, and the collected data will be sent to your developing machine.

Interface with the host machine

You can see that initEglDebugLevel calls GLTrace_start that spawns a thread. This thread services requests coming from the eclipse plugin, namely from the green highlights below. The communication port is specified in debug.egl.debug_portname.ImageThis connection is then reused for sending the collected traces back to the host machine.

How is tracing done

In Fig.1 you can see that the type of tracing has the same color-coding with some structures: gHooksTrace, gHooksSystrace and gHooksErrorTrace. These structures looks something like this

#define GL_ENTRY(_r, _api, ...) GLTrace_ ## _api,
 EGLAPI gl_hooks_t gHooksDebug = {
    {
      #include "entries.in"
    },
    {
       {0}
    }
 };
#undef GL_ENTRY

entries.in contains the list of GL functions together with their signatures (see glActiveShaderProgramEXT in Fig.1). How is entries.in expanded, depends on how GL_ENTRY is defined. This definition is basically the trick used to generate three types of data structures(for each type of tracing) starting from the same list of functions.

The same entries.in is reused by GLES_trace/src/genapi.py to generate wrapping functions such as the one below(glFlush). You can see how the timing is done and later on sent to the host with  glContext->traceGLMessage(&glmsg). The communication between device and host is marshalled/serialized using Google’s protobuf.

 void GLTrace_glFlush(void) {
     GLMessage glmsg;
     GLTraceContext *glContext = getGLTraceContext();

     glmsg.set_function(GLMessage::glFlush);

     // call function
     nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
     nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFlush();
     nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
     nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);

     void *pointerArgs[] = {
     };

     fixupGLMessage(glContext, wallStartTime, wallEndTime,
                               threadStartTime, threadEndTime,
                               &glmsg, pointerArgs);
     glContext->traceGLMessage(&glmsg);
 }
Advertisements