gallium: hook up reference count debugging code

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
This commit is contained in:
Luca Barbieri
2010-08-18 00:41:10 +02:00
parent 2ff13fe89e
commit c806a40277
+13 -6
View 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;
}