gallium: hook up reference count debugging code
authorLuca Barbieri <luca@luca-barbieri.com>
Tue, 17 Aug 2010 22:41:10 +0000 (00:41 +0200)
committerLuca Barbieri <luca@luca-barbieri.com>
Fri, 20 Aug 2010 16:18:28 +0000 (18:18 +0200)
This commit adds the ability to produce a log file containing all
reference count changes, and object creation/destruction, on Gallium
objects.

The data allows to answer these crucial questions:
1. This app is exhausting all my memory due to a resource leak: where
   is the bug?
2. Which resources is this app using at a given moment? Which parts of
   the code created them?
3. What kinds of resources does this app use?
4. How fast does this app create and destroy resources? Which parts of
   the code create resources fast?

The output is compatible with the one produced by the similar facility
in Mozilla Firefox, allowing to use Mozilla's tools to analyze the data.

To get the log file:
export GALLIUM_REFCNT_LOG=<file>

To get function names and source lines in the log file:
tools/addr2line.sh <file>

To process the log file, see:
http://www.mozilla.org/performance/refcnt-balancer.html

src/gallium/auxiliary/util/u_inlines.h

index 540305c1465765a90c3fd141ca484520e5a0a285..90b0903e3f0d43cfdab924275253b2bfad51f72c 100644 (file)
@@ -33,6 +33,8 @@
 #include "pipe/p_state.h"
 #include "pipe/p_screen.h"
 #include "util/u_debug.h"
+#include "util/u_debug_describe.h"
+#include "util/u_debug_refcnt.h"
 #include "util/u_atomic.h"
 #include "util/u_box.h"
 #include "util/u_math.h"
@@ -67,7 +69,7 @@ pipe_is_referenced(struct pipe_reference *reference)
  * \return TRUE if the object's refcount hits zero and should be destroyed.
  */
 static INLINE boolean
-pipe_reference(struct pipe_reference *ptr, struct pipe_reference *reference)
+pipe_reference_described(struct pipe_reference *ptr, struct pipe_reference *reference, void* get_desc)
 {
    boolean destroy = FALSE;
 
@@ -76,6 +78,7 @@ pipe_reference(struct pipe_reference *ptr, struct pipe_reference *reference)
       if (reference) {
          assert(pipe_is_referenced(reference));
          p_atomic_inc(&reference->count);
+         debug_reference(reference, get_desc, 1);
       }
 
       if (ptr) {
@@ -83,41 +86,45 @@ pipe_reference(struct pipe_reference *ptr, struct pipe_reference *reference)
          if (p_atomic_dec_zero(&ptr->count)) {
             destroy = TRUE;
          }
+         debug_reference(ptr, get_desc, -1);
       }
    }
 
    return destroy;
 }
 
+static INLINE boolean
+pipe_reference(struct pipe_reference *ptr, struct pipe_reference *reference)
+{
+   return pipe_reference_described(ptr, reference, debug_describe_reference);
+}
 
 static INLINE void
 pipe_surface_reference(struct pipe_surface **ptr, struct pipe_surface *surf)
 {
    struct pipe_surface *old_surf = *ptr;
 
-   if (pipe_reference(&(*ptr)->reference, &surf->reference))
+   if (pipe_reference_described(&(*ptr)->reference, &surf->reference, debug_describe_surface))
       old_surf->texture->screen->tex_surface_destroy(old_surf);
    *ptr = surf;
 }
 
-
 static INLINE void
 pipe_resource_reference(struct pipe_resource **ptr, struct pipe_resource *tex)
 {
    struct pipe_resource *old_tex = *ptr;
 
-   if (pipe_reference(&(*ptr)->reference, &tex->reference))
+   if (pipe_reference_described(&(*ptr)->reference, &tex->reference, debug_describe_resource))
       old_tex->screen->resource_destroy(old_tex->screen, old_tex);
    *ptr = tex;
 }
 
-
 static INLINE void
 pipe_sampler_view_reference(struct pipe_sampler_view **ptr, struct pipe_sampler_view *view)
 {
    struct pipe_sampler_view *old_view = *ptr;
 
-   if (pipe_reference(&(*ptr)->reference, &view->reference))
+   if (pipe_reference_described(&(*ptr)->reference, &view->reference, debug_describe_sampler_view))
       old_view->context->sampler_view_destroy(old_view->context, old_view);
    *ptr = view;
 }