cogl-debug: add instrumentation to track the number of objects

This allows to track the number of objects allocated by Cogl. The
results are displayed on the standard output by calling :

cogl_debug_print_instances ();

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@linux.intel.com>
Signed-off-by: Neil Roberts <neil@linux.intel.com>
This commit is contained in:
Lionel Landwerlin 2011-06-10 18:44:09 +01:00 committed by Neil Roberts
parent c603dc67ca
commit 5dc42284a5
5 changed files with 185 additions and 45 deletions

View File

@ -84,6 +84,7 @@ static const int n_cogl_behavioural_debug_keys =
G_N_ELEMENTS (cogl_behavioural_debug_keys); G_N_ELEMENTS (cogl_behavioural_debug_keys);
unsigned int _cogl_debug_flags[COGL_DEBUG_N_INTS]; unsigned int _cogl_debug_flags[COGL_DEBUG_N_INTS];
GHashTable *_cogl_debug_instances;
static void static void
_cogl_parse_debug_string_for_keys (const char *value, _cogl_parse_debug_string_for_keys (const char *value,

View File

@ -75,6 +75,7 @@ typedef enum {
#define COGL_DEBUG_N_INTS COGL_FLAGS_N_INTS_FOR_SIZE (COGL_DEBUG_N_FLAGS) #define COGL_DEBUG_N_INTS COGL_FLAGS_N_INTS_FOR_SIZE (COGL_DEBUG_N_FLAGS)
extern unsigned int _cogl_debug_flags[COGL_DEBUG_N_INTS]; extern unsigned int _cogl_debug_flags[COGL_DEBUG_N_INTS];
extern GHashTable *_cogl_debug_instances;
#define COGL_DEBUG_ENABLED(flag) \ #define COGL_DEBUG_ENABLED(flag) \
COGL_FLAGS_GET (_cogl_debug_flags, flag) COGL_FLAGS_GET (_cogl_debug_flags, flag)

View File

@ -123,51 +123,84 @@ struct _CoglObject
#define _COGL_HANDLE_DEBUG_UNREF _COGL_OBJECT_DEBUG_UNREF #define _COGL_HANDLE_DEBUG_UNREF _COGL_OBJECT_DEBUG_UNREF
#define COGL_HANDLE_DEBUG_FREE COGL_OBJECT_DEBUG_FREE #define COGL_HANDLE_DEBUG_FREE COGL_OBJECT_DEBUG_FREE
#define COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, type_name, code) \ #define COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, type_name, code) \
\ \
static CoglObjectClass _cogl_##type_name##_class; \ static CoglObjectClass _cogl_##type_name##_class; \
\ static unsigned long _cogl_object_##type_name##_count; \
GQuark \ \
_cogl_object_##type_name##_get_type (void) \ static inline void \
{ \ _cogl_object_##type_name##_inc (void) \
static GQuark type = 0; \ { \
if (!type) \ _cogl_object_##type_name##_count++; \
{ \ } \
type = g_quark_from_static_string ("Cogl"#TypeName); \ \
{ code; } \ static inline void \
} \ _cogl_object_##type_name##_dec (void) \
return type; \ { \
} \ _cogl_object_##type_name##_count--; \
\ } \
GQuark \ \
_cogl_handle_##type_name##_get_type (void) \ static void \
{ \ _cogl_object_##type_name##_indirect_free (CoglObject *obj) \
return _cogl_object_##type_name##_get_type (); \ { \
} \ _cogl_##type_name##_free ((Cogl##TypeName *) obj); \
\ _cogl_object_##type_name##_dec (); \
static Cogl##TypeName * \ } \
_cogl_##type_name##_object_new (Cogl##TypeName *new_obj) \ \
{ \ GQuark \
CoglObject *obj = (CoglObject *)&new_obj->_parent; \ _cogl_object_##type_name##_get_type (void) \
obj->ref_count = 1; \ { \
obj->n_user_data_entries = 0; \ static GQuark type = 0; \
obj->user_data_array = NULL; \ if (!type) \
\ { \
obj->klass = &_cogl_##type_name##_class; \ type = g_quark_from_static_string ("Cogl"#TypeName); \
if (!obj->klass->type) \ _cogl_object_##type_name##_count = 0; \
{ \ \
obj->klass->type = _cogl_object_##type_name##_get_type ();\ if (_cogl_debug_instances == NULL) \
obj->klass->virt_free = _cogl_##type_name##_free; \ _cogl_debug_instances = \
} \ g_hash_table_new (g_str_hash, g_str_equal); \
\ \
_COGL_OBJECT_DEBUG_NEW (TypeName, obj); \ g_hash_table_insert (_cogl_debug_instances, \
return new_obj; \ "Cogl"#TypeName, \
} \ &_cogl_object_##type_name##_count); \
\ \
Cogl##TypeName * \ { code; } \
_cogl_##type_name##_pointer_from_handle (CoglHandle handle) \ } \
{ \ return type; \
return handle; \ } \
\
GQuark \
_cogl_handle_##type_name##_get_type (void) \
{ \
return _cogl_object_##type_name##_get_type (); \
} \
\
static Cogl##TypeName * \
_cogl_##type_name##_object_new (Cogl##TypeName *new_obj) \
{ \
CoglObject *obj = (CoglObject *)&new_obj->_parent; \
obj->ref_count = 0; \
cogl_object_ref (obj); \
obj->n_user_data_entries = 0; \
obj->user_data_array = NULL; \
\
obj->klass = &_cogl_##type_name##_class; \
if (!obj->klass->type) \
{ \
obj->klass->type = _cogl_object_##type_name##_get_type (); \
obj->klass->virt_free = \
_cogl_object_##type_name##_indirect_free; \
} \
\
_cogl_object_##type_name##_inc (); \
_COGL_OBJECT_DEBUG_NEW (TypeName, obj); \
return new_obj; \
} \
\
Cogl##TypeName * \
_cogl_##type_name##_pointer_from_handle (CoglHandle handle) \
{ \
return handle; \
} }
#define COGL_OBJECT_DEFINE_WITH_CODE(TypeName, type_name, code) \ #define COGL_OBJECT_DEFINE_WITH_CODE(TypeName, type_name, code) \

View File

@ -247,3 +247,35 @@ cogl_object_get_user_data (CoglObject *object, CoglUserDataKey *key)
return NULL; return NULL;
} }
void
cogl_debug_object_foreach_type (CoglDebugObjectForeachTypeCallback func,
void *user_data)
{
GHashTableIter iter;
unsigned long *instance_count;
CoglDebugObjectTypeInfo info;
g_hash_table_iter_init (&iter, _cogl_debug_instances);
while (g_hash_table_iter_next (&iter,
(void *) &info.name,
(void *) &instance_count))
{
info.instance_count = *instance_count;
func (&info, user_data);
}
}
static void
print_instances_cb (const CoglDebugObjectTypeInfo *info,
void *user_data)
{
g_print ("\t%s: %lu\n", info->name, info->instance_count);
}
void
cogl_debug_object_print_instances (void)
{
g_print ("Cogl instances:\n");
cogl_debug_object_foreach_type (print_instances_cb, NULL);
}

View File

@ -81,6 +81,37 @@ typedef struct
*/ */
typedef void (*CoglUserDataDestroyCallback) (void *user_data); typedef void (*CoglUserDataDestroyCallback) (void *user_data);
/**
* CoglDebugObjectTypeInfo:
* @name: A human readable name for the type.
* @instance_count: The number of objects of this type that are
* currently in use
*
* This struct is used to pass information to the callback when
* cogl_debug_object_foreach_type() is called.
*
* Since: 1.8
* Stability: unstable
*/
typedef struct
{
const char *name;
unsigned long instance_count;
} CoglDebugObjectTypeInfo;
/**
* CoglDebugObjectForeachTypeCallback:
* @info: A pointer to a struct containing information about the type.
*
* A callback function to use for cogl_debug_object_foreach_type().
*
* Since: 1.8
* Stability: unstable
*/
typedef void
(* CoglDebugObjectForeachTypeCallback) (const CoglDebugObjectTypeInfo *info,
void *user_data);
/** /**
* cogl_object_set_user_data: (skip) * cogl_object_set_user_data: (skip)
* @object: The object to associate private data with * @object: The object to associate private data with
@ -123,5 +154,47 @@ cogl_object_set_user_data (CoglObject *object,
void * void *
cogl_object_get_user_data (CoglObject *object, cogl_object_get_user_data (CoglObject *object,
CoglUserDataKey *key); CoglUserDataKey *key);
#ifdef COGL_ENABLE_EXPERIMENTAL_API
#define cogl_debug_object_foreach_type \
cogl_debug_object_foreach_type_EXP
/**
* cogl_debug_object_foreach_type:
* func: A callback function for each type
* user_data: A pointer to pass to @func
*
* Invokes @func once for each type of object that Cogl uses and
* passes a count of the number of objects for that type. This is
* intended to be used solely for debugging purposes to track down
* issues with objects leaking.
*
* Since: 1.8
* Stability: unstable
*/
void
cogl_debug_object_foreach_type (CoglDebugObjectForeachTypeCallback func,
void *user_data);
#define cogl_debug_object_print_instances \
cogl_debug_object_print_instances_EXP
/**
* cogl_debug_object_print_instances:
*
* Prints a list of all the object types that Cogl uses along with the
* number of objects of that type that are currently in use. This is
* intended to be used solely for debugging purposes to track down
* issues with objects leaking.
*
* Since: 1.8
* Stability: unstable
*/
void
cogl_debug_object_print_instances (void);
#endif /* COGL_ENABLE_EXPERIMENTAL_API */
#endif /* __COGL_OBJECT_H */ #endif /* __COGL_OBJECT_H */