leaks: Port to using object property based parameters
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8086>
This commit is contained in:
parent
5e18499372
commit
d929df61dd
@ -44,15 +44,9 @@
|
|||||||
* `GST_TRACERS=leaks;latency`, and multiple instances of the same tracer can be
|
* `GST_TRACERS=leaks;latency`, and multiple instances of the same tracer can be
|
||||||
* active at the same time.
|
* active at the same time.
|
||||||
*
|
*
|
||||||
* Parameters can also be passed to each tracer. The leaks tracer currently
|
* The tracer properties can also be set to each tracer by passing the object
|
||||||
* accepts five params:
|
* properties in the list of parameters to the tracer. This uses the same
|
||||||
* 1. filters: (string) to filter which objects to record
|
* serialization format as #GstStructure (without a name).
|
||||||
* 2. check-refs: (boolean) whether to record every location where a leaked
|
|
||||||
* object was reffed and unreffed
|
|
||||||
* 3. stack-traces-flags: (string) full or none; see: #GstStackTraceFlags
|
|
||||||
* 4. name: (string) set a name for the tracer object itself
|
|
||||||
* 5. log-leaks-on-deinit: (boolean) whether to report all leaks on
|
|
||||||
* gst_deinit() by printing them in the debug log; "true" by default
|
|
||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
* ```
|
* ```
|
||||||
@ -90,7 +84,40 @@ enum
|
|||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFAULT_LOG_LEAKS TRUE /* for backwards-compat */
|
#define DEFAULT_LOG_LEAKS TRUE
|
||||||
|
#define DEFAULT_CHECK_REFS FALSE
|
||||||
|
|
||||||
|
#define GST_TYPE_LEAKS_STACK_TRACE_FLAGS (gst_leaks_stack_trace_flags_get_type())
|
||||||
|
static GType
|
||||||
|
gst_leaks_stack_trace_flags_get_type (void)
|
||||||
|
{
|
||||||
|
static GType type = 0;
|
||||||
|
static const GFlagsValue values[] = {
|
||||||
|
{GST_LEAKS_STACK_TRACE_DISABLED, "Disabled", "disabled"},
|
||||||
|
{GST_LEAKS_STACK_TRACE_NONE, "None", "none"},
|
||||||
|
{GST_LEAKS_STACK_TRACE_FULL, "Full", "full"},
|
||||||
|
{0, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
type = g_flags_register_static ("GstLeaksStackTraceFlags", values);
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEFAULT_STACK_TRACE_FLAGS GST_LEAKS_STACK_TRACE_DISABLED
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0,
|
||||||
|
PROP_FILTERS,
|
||||||
|
PROP_CHECK_REFS,
|
||||||
|
PROP_STACK_TRACES_FLAGS,
|
||||||
|
PROP_LOG_LEAKS_ON_DEINIT,
|
||||||
|
N_PROPERTIES
|
||||||
|
};
|
||||||
|
|
||||||
|
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
|
||||||
|
|
||||||
#define _do_init \
|
#define _do_init \
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_leaks_debug, "leaks", 0, "leaks tracer");
|
GST_DEBUG_CATEGORY_INIT (gst_leaks_debug, "leaks", 0, "leaks tracer");
|
||||||
@ -158,39 +185,6 @@ object_refing_infos_free (ObjectRefingInfos * infos)
|
|||||||
g_free (infos);
|
g_free (infos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
set_print_stack_trace_from_string (GstLeaksTracer * self, const gchar * str)
|
|
||||||
{
|
|
||||||
gchar *trace;
|
|
||||||
|
|
||||||
/* Test if we can retrieve backtrace */
|
|
||||||
trace = gst_debug_get_stack_trace (FALSE);
|
|
||||||
if (!trace)
|
|
||||||
return;
|
|
||||||
|
|
||||||
g_free (trace);
|
|
||||||
|
|
||||||
if (g_strcmp0 (str, "full") == 0)
|
|
||||||
self->trace_flags = GST_STACK_TRACE_SHOW_FULL;
|
|
||||||
else
|
|
||||||
self->trace_flags = GST_STACK_TRACE_SHOW_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_print_stack_trace (GstLeaksTracer * self, GstStructure * params)
|
|
||||||
{
|
|
||||||
const gchar *trace_flags = g_getenv ("GST_LEAKS_TRACER_STACK_TRACE");
|
|
||||||
|
|
||||||
self->trace_flags = -1;
|
|
||||||
if (!trace_flags && params)
|
|
||||||
trace_flags = gst_structure_get_string (params, "stack-traces-flags");
|
|
||||||
|
|
||||||
if (!trace_flags)
|
|
||||||
return;
|
|
||||||
|
|
||||||
set_print_stack_trace_from_string (self, trace_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_filters (GstLeaksTracer * self, const gchar * filters)
|
set_filters (GstLeaksTracer * self, const gchar * filters)
|
||||||
{
|
{
|
||||||
@ -226,51 +220,6 @@ set_filters (GstLeaksTracer * self, const gchar * filters)
|
|||||||
g_strfreev (tmp);
|
g_strfreev (tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
set_params_from_structure (GstLeaksTracer * self, GstStructure * params)
|
|
||||||
{
|
|
||||||
const gchar *filters, *name;
|
|
||||||
|
|
||||||
filters = gst_structure_get_string (params, "filters");
|
|
||||||
if (filters)
|
|
||||||
set_filters (self, filters);
|
|
||||||
|
|
||||||
name = gst_structure_get_string (params, "name");
|
|
||||||
if (name)
|
|
||||||
gst_object_set_name (GST_OBJECT (self), name);
|
|
||||||
|
|
||||||
gst_structure_get_boolean (params, "check-refs", &self->check_refs);
|
|
||||||
gst_structure_get_boolean (params, "log-leaks-on-deinit", &self->log_leaks);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_params (GstLeaksTracer * self)
|
|
||||||
{
|
|
||||||
gchar *params, *tmp;
|
|
||||||
GstStructure *params_struct = NULL;
|
|
||||||
|
|
||||||
g_object_get (self, "params", ¶ms, NULL);
|
|
||||||
if (!params)
|
|
||||||
goto set_stacktrace;
|
|
||||||
|
|
||||||
tmp = g_strdup_printf ("leaks,%s", params);
|
|
||||||
params_struct = gst_structure_from_string (tmp, NULL);
|
|
||||||
g_free (tmp);
|
|
||||||
|
|
||||||
if (params_struct)
|
|
||||||
set_params_from_structure (self, params_struct);
|
|
||||||
else
|
|
||||||
set_filters (self, params);
|
|
||||||
|
|
||||||
g_free (params);
|
|
||||||
|
|
||||||
set_stacktrace:
|
|
||||||
set_print_stack_trace (self, params_struct);
|
|
||||||
|
|
||||||
if (params_struct)
|
|
||||||
gst_structure_free (params_struct);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_expand_unhandled_filters (gchar * typename, gpointer unused_value,
|
_expand_unhandled_filters (gchar * typename, gpointer unused_value,
|
||||||
GstLeaksTracer * self)
|
GstLeaksTracer * self)
|
||||||
@ -415,8 +364,9 @@ handle_object_created (GstLeaksTracer * self, gpointer object, GType type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
GST_OBJECT_LOCK (self);
|
GST_OBJECT_LOCK (self);
|
||||||
if ((gint) self->trace_flags != -1)
|
if ((gint) self->trace_flags != GST_LEAKS_STACK_TRACE_DISABLED)
|
||||||
infos->creation_trace = gst_debug_get_stack_trace (self->trace_flags);
|
infos->creation_trace =
|
||||||
|
gst_debug_get_stack_trace ((GstStackTraceFlags) self->trace_flags);
|
||||||
|
|
||||||
g_hash_table_insert (self->objects, object, infos);
|
g_hash_table_insert (self->objects, object, infos);
|
||||||
|
|
||||||
@ -470,8 +420,9 @@ handle_object_reffed (GstLeaksTracer * self, gpointer object, GType type,
|
|||||||
refinfo->ts = ts;
|
refinfo->ts = ts;
|
||||||
refinfo->new_refcount = new_refcount;
|
refinfo->new_refcount = new_refcount;
|
||||||
refinfo->reffed = reffed;
|
refinfo->reffed = reffed;
|
||||||
if ((gint) self->trace_flags != -1)
|
if ((gint) self->trace_flags != GST_LEAKS_STACK_TRACE_DISABLED)
|
||||||
refinfo->trace = gst_debug_get_stack_trace (self->trace_flags);
|
refinfo->trace =
|
||||||
|
gst_debug_get_stack_trace ((GstStackTraceFlags) self->trace_flags);
|
||||||
|
|
||||||
infos->refing_infos = g_list_prepend (infos->refing_infos, refinfo);
|
infos->refing_infos = g_list_prepend (infos->refing_infos, refinfo);
|
||||||
|
|
||||||
@ -523,6 +474,8 @@ static void
|
|||||||
gst_leaks_tracer_init (GstLeaksTracer * self)
|
gst_leaks_tracer_init (GstLeaksTracer * self)
|
||||||
{
|
{
|
||||||
self->log_leaks = DEFAULT_LOG_LEAKS;
|
self->log_leaks = DEFAULT_LOG_LEAKS;
|
||||||
|
self->check_refs = DEFAULT_CHECK_REFS;
|
||||||
|
self->trace_flags = DEFAULT_STACK_TRACE_FLAGS;
|
||||||
self->objects = g_hash_table_new_full (NULL, NULL, NULL,
|
self->objects = g_hash_table_new_full (NULL, NULL, NULL,
|
||||||
(GDestroyNotify) object_refing_infos_free);
|
(GDestroyNotify) object_refing_infos_free);
|
||||||
|
|
||||||
@ -545,8 +498,6 @@ gst_leaks_tracer_constructed (GObject * object)
|
|||||||
GstLeaksTracer *self = GST_LEAKS_TRACER (object);
|
GstLeaksTracer *self = GST_LEAKS_TRACER (object);
|
||||||
GstTracer *tracer = GST_TRACER (object);
|
GstTracer *tracer = GST_TRACER (object);
|
||||||
|
|
||||||
set_params (self);
|
|
||||||
|
|
||||||
gst_tracing_register_hook (tracer, "mini-object-created",
|
gst_tracing_register_hook (tracer, "mini-object-created",
|
||||||
G_CALLBACK (mini_object_created_cb));
|
G_CALLBACK (mini_object_created_cb));
|
||||||
gst_tracing_register_hook (tracer, "object-created",
|
gst_tracing_register_hook (tracer, "object-created",
|
||||||
@ -1021,6 +972,7 @@ gst_leaks_tracer_get_live_objects (GstLeaksTracer * self)
|
|||||||
|
|
||||||
g_value_init (&live_objects, GST_TYPE_LIST);
|
g_value_init (&live_objects, GST_TYPE_LIST);
|
||||||
|
|
||||||
|
GST_TRACE_OBJECT (self, "start listing currently alive objects");
|
||||||
GST_OBJECT_LOCK (self);
|
GST_OBJECT_LOCK (self);
|
||||||
process_leaks (self, &live_objects);
|
process_leaks (self, &live_objects);
|
||||||
GST_OBJECT_UNLOCK (self);
|
GST_OBJECT_UNLOCK (self);
|
||||||
@ -1138,13 +1090,150 @@ gst_leaks_tracer_activity_stop_tracking (GstLeaksTracer * self)
|
|||||||
GST_OBJECT_UNLOCK (self);
|
GST_OBJECT_UNLOCK (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_leaks_tracer_get_property (GObject * object, guint prop_id,
|
||||||
|
GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
GstLeaksTracer *self = GST_LEAKS_TRACER (object);
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (self);
|
||||||
|
switch (prop_id) {
|
||||||
|
case PROP_CHECK_REFS:
|
||||||
|
g_value_set_boolean (value, self->check_refs);
|
||||||
|
break;
|
||||||
|
case PROP_STACK_TRACES_FLAGS:
|
||||||
|
g_value_set_flags (value, self->trace_flags);
|
||||||
|
break;
|
||||||
|
case PROP_LOG_LEAKS_ON_DEINIT:
|
||||||
|
g_value_set_boolean (value, self->log_leaks);
|
||||||
|
break;
|
||||||
|
case PROP_FILTERS:
|
||||||
|
{
|
||||||
|
GString *str = g_string_new ("");
|
||||||
|
if (self->filter) {
|
||||||
|
guint i;
|
||||||
|
for (i = 0; i < self->filter->len; i++) {
|
||||||
|
GType type = g_array_index (self->filter, GType, i);
|
||||||
|
if (i > 0)
|
||||||
|
g_string_append_c (str, ',');
|
||||||
|
g_string_append (str, g_type_name (type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_value_take_string (value, g_string_free (str, FALSE));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
GST_OBJECT_UNLOCK (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_leaks_tracer_set_property (GObject * object, guint prop_id,
|
||||||
|
const GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
GstLeaksTracer *self = GST_LEAKS_TRACER (object);
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (self);
|
||||||
|
switch (prop_id) {
|
||||||
|
case PROP_CHECK_REFS:
|
||||||
|
self->check_refs = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
|
case PROP_STACK_TRACES_FLAGS:
|
||||||
|
self->trace_flags = g_value_get_flags (value);
|
||||||
|
break;
|
||||||
|
case PROP_LOG_LEAKS_ON_DEINIT:
|
||||||
|
self->log_leaks = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
|
case PROP_FILTERS:
|
||||||
|
if (self->filter) {
|
||||||
|
g_array_free (self->filter, TRUE);
|
||||||
|
self->filter = NULL;
|
||||||
|
}
|
||||||
|
const gchar *filters = g_value_get_string (value);
|
||||||
|
if (filters) {
|
||||||
|
set_filters (self, g_value_get_string (value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
GST_OBJECT_UNLOCK (self);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_leaks_tracer_class_init (GstLeaksTracerClass * klass)
|
gst_leaks_tracer_class_init (GstLeaksTracerClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
gst_tracer_class_set_use_structure_params (GST_TRACER_CLASS (klass), TRUE);
|
||||||
|
|
||||||
gobject_class->constructed = gst_leaks_tracer_constructed;
|
gobject_class->constructed = gst_leaks_tracer_constructed;
|
||||||
gobject_class->finalize = gst_leaks_tracer_finalize;
|
gobject_class->finalize = gst_leaks_tracer_finalize;
|
||||||
|
gobject_class->get_property = gst_leaks_tracer_get_property;
|
||||||
|
gobject_class->set_property = gst_leaks_tracer_set_property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstLeaksTracer:filters:
|
||||||
|
*
|
||||||
|
* Comma-separated list of GObject types to track. Only objects of these types
|
||||||
|
* or their subtypes will be monitored for leaks.
|
||||||
|
*
|
||||||
|
* Example: "GstEvent,GstMessage" to only track GstEvent and GstMessage objects.
|
||||||
|
*
|
||||||
|
* Since: 1.26
|
||||||
|
*/
|
||||||
|
properties[PROP_FILTERS] = g_param_spec_string ("filters",
|
||||||
|
"Type Filters",
|
||||||
|
"Comma-separated list of GObject types to track", NULL,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstLeaksTracer:check-refs:
|
||||||
|
*
|
||||||
|
* Whether to record every location where a leaked object was reffed and unreffed.
|
||||||
|
* When enabled, the tracer will collect stack traces for every ref/unref operation
|
||||||
|
* on tracked objects.
|
||||||
|
*
|
||||||
|
* Since: 1.26
|
||||||
|
*/
|
||||||
|
properties[PROP_CHECK_REFS] = g_param_spec_boolean ("check-refs",
|
||||||
|
"Check References",
|
||||||
|
"Whether to track ref/unref operations", DEFAULT_CHECK_REFS,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstLeaksTracer:stack-traces-flags:
|
||||||
|
*
|
||||||
|
* Stack trace collection mode. Controls whether and how stack traces are collected
|
||||||
|
* for object allocations and ref/unref operations.
|
||||||
|
*
|
||||||
|
* Since: 1.26
|
||||||
|
*/
|
||||||
|
properties[PROP_STACK_TRACES_FLAGS] =
|
||||||
|
g_param_spec_flags ("stack-traces-flags", "Stack Trace Flags",
|
||||||
|
"Stack trace collection mode", GST_TYPE_LEAKS_STACK_TRACE_FLAGS,
|
||||||
|
DEFAULT_STACK_TRACE_FLAGS,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstLeaksTracer:log-leaks-on-deinit:
|
||||||
|
*
|
||||||
|
* Whether to report all leaks on gst_deinit() by printing them in the debug log.
|
||||||
|
* When enabled, any detected leaks will be logged under GST_TRACER:7 when the
|
||||||
|
* GStreamer is being shut down.
|
||||||
|
*
|
||||||
|
* Since: 1.26
|
||||||
|
*/
|
||||||
|
properties[PROP_LOG_LEAKS_ON_DEINIT] =
|
||||||
|
g_param_spec_boolean ("log-leaks-on-deinit", "Log Leaks",
|
||||||
|
"Whether to log leaks on shutdown", DEFAULT_LOG_LEAKS,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
|
||||||
|
|
||||||
|
|
||||||
|
g_object_class_install_properties (gobject_class, N_PROPERTIES, properties);
|
||||||
|
|
||||||
tr_alive = gst_tracer_record_new ("object-alive.class",
|
tr_alive = gst_tracer_record_new ("object-alive.class",
|
||||||
RECORD_FIELD_TYPE_NAME, RECORD_FIELD_ADDRESS, RECORD_FIELD_DESC,
|
RECORD_FIELD_TYPE_NAME, RECORD_FIELD_ADDRESS, RECORD_FIELD_DESC,
|
||||||
|
@ -42,6 +42,12 @@ G_BEGIN_DECLS
|
|||||||
typedef struct _GstLeaksTracer GstLeaksTracer;
|
typedef struct _GstLeaksTracer GstLeaksTracer;
|
||||||
typedef struct _GstLeaksTracerClass GstLeaksTracerClass;
|
typedef struct _GstLeaksTracerClass GstLeaksTracerClass;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GST_LEAKS_STACK_TRACE_DISABLED = -1,
|
||||||
|
GST_LEAKS_STACK_TRACE_NONE = GST_STACK_TRACE_SHOW_NONE,
|
||||||
|
GST_LEAKS_STACK_TRACE_FULL = GST_STACK_TRACE_SHOW_FULL
|
||||||
|
} GstLeaksStackTraceFlags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstLeaksTracer:
|
* GstLeaksTracer:
|
||||||
*
|
*
|
||||||
@ -71,7 +77,7 @@ struct _GstLeaksTracer {
|
|||||||
gboolean check_refs;
|
gboolean check_refs;
|
||||||
gboolean log_leaks;
|
gboolean log_leaks;
|
||||||
|
|
||||||
GstStackTraceFlags trace_flags;
|
GstLeaksStackTraceFlags trace_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstLeaksTracerClass {
|
struct _GstLeaksTracerClass {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user