diff options
author | Thibault Saunier <tsaunier@gnome.org> | 2016-12-01 17:35:45 -0300 |
---|---|---|
committer | Thibault Saunier <thibault.saunier@osg.samsung.com> | 2016-12-20 15:29:10 -0300 |
commit | 30133909cefab53447556a4f82d4ccb63f0027a6 (patch) | |
tree | 8791bf49d7bac012d290afb6713442d170b98a5e /plugins | |
parent | 32b17a8f3db33a01f2ddeaab8f044d3919704295 (diff) |
leaks: Allow tracing Gst(Mini)Object reffing operations
It makes it much simpler to later debug refcount issues.
https://bugzilla.gnome.org/show_bug.cgi?id=775541
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/tracers/gstleaks.c | 159 | ||||
-rw-r--r-- | plugins/tracers/gstleaks.h | 2 |
2 files changed, 147 insertions, 14 deletions
diff --git a/plugins/tracers/gstleaks.c b/plugins/tracers/gstleaks.c index 08cb3f58b..950d92069 100644 --- a/plugins/tracers/gstleaks.c +++ b/plugins/tracers/gstleaks.c @@ -48,12 +48,45 @@ G_DEFINE_TYPE_WITH_CODE (GstLeaksTracer, gst_leaks_tracer, GST_TYPE_TRACER, _do_init); static GstTracerRecord *tr_alive; +static GstTracerRecord *tr_refings; #ifdef G_OS_UNIX static GstTracerRecord *tr_added = NULL; static GstTracerRecord *tr_removed = NULL; #endif /* G_OS_UNIX */ static GQueue instances = G_QUEUE_INIT; +typedef struct +{ + gboolean reffed; + gchar *trace; + gint new_refcount; + GstClockTime ts; +} ObjectRefingInfo; + +typedef struct +{ + gchar *creation_trace; + + GList *refing_infos; +} ObjectRefingInfos; + +static void +object_refing_info_free (ObjectRefingInfo * refinfo) +{ + g_free (refinfo->trace); + g_free (refinfo); +} + +static void +object_refing_infos_free (ObjectRefingInfos * infos) +{ + g_list_free_full (infos->refing_infos, + (GDestroyNotify) object_refing_info_free); + + g_free (infos->creation_trace); + g_free (infos); +} + static void set_print_stack_trace (GstLeaksTracer * self, GstStructure * params) { @@ -120,6 +153,7 @@ set_params_from_structure (GstLeaksTracer * self, GstStructure * params) if (filters) set_filters (self, filters); + gst_structure_get_boolean (params, "check-refs", &self->check_refs); } static void @@ -261,11 +295,13 @@ static void handle_object_created (GstLeaksTracer * self, gpointer object, GType type, gboolean gobject) { - gchar *trace = NULL; + ObjectRefingInfos *infos; + if (!should_handle_object_type (self, type)) return; + infos = g_malloc0 (sizeof (ObjectRefingInfos)); if (gobject) g_object_weak_ref ((GObject *) object, object_weak_cb, self); else @@ -273,11 +309,10 @@ handle_object_created (GstLeaksTracer * self, gpointer object, GType type, mini_object_weak_cb, self); GST_OBJECT_LOCK (self); - if (self->log_stack_trace) { - trace = gst_debug_get_stack_trace (0); - } + if (self->log_stack_trace) + infos->creation_trace = gst_debug_get_stack_trace (0); - g_hash_table_insert (self->objects, object, trace); + g_hash_table_insert (self->objects, object, infos); #ifdef G_OS_UNIX if (self->added) @@ -309,9 +344,74 @@ object_created_cb (GstTracer * tracer, GstClockTime ts, GstObject * object) } static void +handle_object_reffed (GstLeaksTracer * self, gpointer object, gint new_refcount, + gboolean reffed, GstClockTime ts) +{ + ObjectRefingInfos *infos; + ObjectRefingInfo *refinfo; + + if (!self->check_refs) + return; + + GST_OBJECT_LOCK (self); + infos = g_hash_table_lookup (self->objects, object); + if (!infos) + goto out; + + refinfo = g_malloc0 (sizeof (ObjectRefingInfo)); + refinfo->ts = ts; + refinfo->new_refcount = new_refcount; + refinfo->reffed = reffed; + if (self->log_stack_trace) + refinfo->trace = gst_debug_get_stack_trace (0); + + infos->refing_infos = g_list_prepend (infos->refing_infos, refinfo); + +out: + GST_OBJECT_UNLOCK (self); +} + +static void +object_reffed_cb (GstTracer * tracer, GstClockTime ts, GstObject * object, + gint new_refcount) +{ + GstLeaksTracer *self = GST_LEAKS_TRACER_CAST (tracer); + + handle_object_reffed (self, object, new_refcount, TRUE, ts); +} + +static void +object_unreffed_cb (GstTracer * tracer, GstClockTime ts, GstObject * object, + gint new_refcount) +{ + GstLeaksTracer *self = GST_LEAKS_TRACER_CAST (tracer); + + handle_object_reffed (self, object, new_refcount, FALSE, ts); +} + +static void +mini_object_reffed_cb (GstTracer * tracer, GstClockTime ts, + GstMiniObject * object, gint new_refcount) +{ + GstLeaksTracer *self = GST_LEAKS_TRACER_CAST (tracer); + + handle_object_reffed (self, object, new_refcount, TRUE, ts); +} + +static void +mini_object_unreffed_cb (GstTracer * tracer, GstClockTime ts, + GstMiniObject * object, gint new_refcount) +{ + GstLeaksTracer *self = GST_LEAKS_TRACER_CAST (tracer); + + handle_object_reffed (self, object, new_refcount, FALSE, ts); +} + +static void gst_leaks_tracer_init (GstLeaksTracer * self) { - self->objects = g_hash_table_new_full (NULL, NULL, NULL, g_free); + self->objects = g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) object_refing_infos_free); g_queue_push_tail (&instances, self); } @@ -329,6 +429,17 @@ gst_leaks_tracer_constructed (GObject * object) gst_tracing_register_hook (tracer, "object-created", G_CALLBACK (object_created_cb)); + if (self->check_refs) { + gst_tracing_register_hook (tracer, "object-reffed", + G_CALLBACK (object_reffed_cb)); + gst_tracing_register_hook (tracer, "mini-object-reffed", + G_CALLBACK (mini_object_reffed_cb)); + gst_tracing_register_hook (tracer, "mini-object-unreffed", + G_CALLBACK (mini_object_unreffed_cb)); + gst_tracing_register_hook (tracer, "object-unreffed", + G_CALLBACK (object_unreffed_cb)); + } + /* We rely on weak pointers rather than (mini-)object-destroyed hooks so we * are notified of objects being destroyed even during the shuting down of * the tracing system. */ @@ -342,13 +453,13 @@ typedef struct const gchar *type_name; guint ref_count; gchar *desc; - const gchar *trace; + ObjectRefingInfos *infos; } Leak; /* The content of the returned Leak struct is valid until the self->objects * hash table has been modified. */ static Leak * -leak_new (gpointer obj, GType type, guint ref_count, const gchar * trace) +leak_new (gpointer obj, GType type, guint ref_count, ObjectRefingInfos * infos) { Leak *leak = g_slice_new (Leak); @@ -356,7 +467,7 @@ leak_new (gpointer obj, GType type, guint ref_count, const gchar * trace) leak->type_name = g_type_name (type); leak->ref_count = ref_count; leak->desc = gst_info_strdup_printf ("%" GST_PTR_FORMAT, obj); - leak->trace = trace; + leak->infos = infos; return leak; } @@ -381,10 +492,10 @@ create_leaks_list (GstLeaksTracer * self) { GList *l = NULL; GHashTableIter iter; - gpointer obj, trace; + gpointer obj, infos; g_hash_table_iter_init (&iter, self->objects); - while (g_hash_table_iter_next (&iter, &obj, &trace)) { + while (g_hash_table_iter_next (&iter, &obj, &infos)) { GType type; guint ref_count; @@ -402,7 +513,7 @@ create_leaks_list (GstLeaksTracer * self) ref_count = ((GstMiniObject *) obj)->refcount; } - l = g_list_prepend (l, leak_new (obj, type, ref_count, trace)); + l = g_list_prepend (l, leak_new (obj, type, ref_count, infos)); } /* Sort leaks by type name so they are grouped together making the output @@ -416,7 +527,7 @@ create_leaks_list (GstLeaksTracer * self) static gboolean log_leaked (GstLeaksTracer * self) { - GList *leaks, *l; + GList *ref, *leaks, *l; leaks = create_leaks_list (self); if (!leaks) @@ -426,7 +537,17 @@ log_leaked (GstLeaksTracer * self) Leak *leak = l->data; gst_tracer_record_log (tr_alive, leak->type_name, leak->obj, leak->desc, - leak->ref_count, leak->trace ? leak->trace : ""); + leak->ref_count, + leak->infos->creation_trace ? leak->infos->creation_trace : ""); + + leak->infos->refing_infos = g_list_reverse (leak->infos->refing_infos); + for (ref = leak->infos->refing_infos; ref; ref = ref->next) { + ObjectRefingInfo *refinfo = (ObjectRefingInfo *) ref->data; + + gst_tracer_record_log (tr_refings, refinfo->ts, leak->type_name, + leak->obj, refinfo->reffed ? "reffed" : "unreffed", + refinfo->new_refcount, refinfo->trace ? refinfo->trace : ""); + } } g_list_free_full (leaks, (GDestroyNotify) leak_free); @@ -473,6 +594,11 @@ gst_leaks_tracer_finalize (GObject * object) ((GObjectClass *) gst_leaks_tracer_parent_class)->finalize (object); } +#define RECORD_FIELD_TYPE_TS \ + "ts", GST_TYPE_STRUCTURE, gst_structure_new ("value", \ + "type", G_TYPE_GTYPE, GST_TYPE_CLOCK_TIME, \ + "related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_PROCESS, \ + NULL) #define RECORD_FIELD_TYPE_NAME \ "type-name", GST_TYPE_STRUCTURE, gst_structure_new ("value", \ "type", G_TYPE_GTYPE, G_TYPE_STRING, \ @@ -601,6 +727,11 @@ gst_leaks_tracer_class_init (GstLeaksTracerClass * klass) RECORD_FIELD_REF_COUNT, RECORD_FIELD_TRACE, NULL); GST_OBJECT_FLAG_SET (tr_alive, GST_OBJECT_FLAG_MAY_BE_LEAKED); + tr_refings = gst_tracer_record_new ("object-refings.class", + RECORD_FIELD_TYPE_TS, RECORD_FIELD_TYPE_NAME, RECORD_FIELD_ADDRESS, + RECORD_FIELD_DESC, RECORD_FIELD_REF_COUNT, RECORD_FIELD_TRACE, NULL); + GST_OBJECT_FLAG_SET (tr_alive, GST_OBJECT_FLAG_MAY_BE_LEAKED); + if (g_getenv ("GST_LEAKS_TRACER_SIG")) { #ifdef G_OS_UNIX setup_signals (); diff --git a/plugins/tracers/gstleaks.h b/plugins/tracers/gstleaks.h index 6dd3def93..7539b26b4 100644 --- a/plugins/tracers/gstleaks.h +++ b/plugins/tracers/gstleaks.h @@ -68,6 +68,8 @@ struct _GstLeaksTracer { gint unhandled_filter_count; gboolean done; + gboolean check_refs; + gboolean log_stack_trace; }; |