mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 06:46:38 +00:00
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
2 changed files with 190 additions and 95 deletions
|
@ -44,15 +44,9 @@
|
|||
* `GST_TRACERS=leaks;latency`, and multiple instances of the same tracer can be
|
||||
* active at the same time.
|
||||
*
|
||||
* Parameters can also be passed to each tracer. The leaks tracer currently
|
||||
* accepts five params:
|
||||
* 1. filters: (string) to filter which objects to record
|
||||
* 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
|
||||
* The tracer properties can also be set to each tracer by passing the object
|
||||
* properties in the list of parameters to the tracer. This uses the same
|
||||
* serialization format as #GstStructure (without a name).
|
||||
*
|
||||
* Examples:
|
||||
* ```
|
||||
|
@ -90,7 +84,40 @@ enum
|
|||
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 \
|
||||
GST_DEBUG_CATEGORY_INIT (gst_leaks_debug, "leaks", 0, "leaks tracer");
|
||||
|
@ -158,39 +185,6 @@ object_refing_infos_free (ObjectRefingInfos * 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
|
||||
set_filters (GstLeaksTracer * self, const gchar * filters)
|
||||
{
|
||||
|
@ -226,51 +220,6 @@ set_filters (GstLeaksTracer * self, const gchar * filters)
|
|||
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
|
||||
_expand_unhandled_filters (gchar * typename, gpointer unused_value,
|
||||
GstLeaksTracer * self)
|
||||
|
@ -415,8 +364,9 @@ handle_object_created (GstLeaksTracer * self, gpointer object, GType type,
|
|||
}
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
if ((gint) self->trace_flags != -1)
|
||||
infos->creation_trace = gst_debug_get_stack_trace (self->trace_flags);
|
||||
if ((gint) self->trace_flags != GST_LEAKS_STACK_TRACE_DISABLED)
|
||||
infos->creation_trace =
|
||||
gst_debug_get_stack_trace ((GstStackTraceFlags) self->trace_flags);
|
||||
|
||||
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->new_refcount = new_refcount;
|
||||
refinfo->reffed = reffed;
|
||||
if ((gint) self->trace_flags != -1)
|
||||
refinfo->trace = gst_debug_get_stack_trace (self->trace_flags);
|
||||
if ((gint) self->trace_flags != GST_LEAKS_STACK_TRACE_DISABLED)
|
||||
refinfo->trace =
|
||||
gst_debug_get_stack_trace ((GstStackTraceFlags) self->trace_flags);
|
||||
|
||||
infos->refing_infos = g_list_prepend (infos->refing_infos, refinfo);
|
||||
|
||||
|
@ -523,6 +474,8 @@ static void
|
|||
gst_leaks_tracer_init (GstLeaksTracer * self)
|
||||
{
|
||||
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,
|
||||
(GDestroyNotify) object_refing_infos_free);
|
||||
|
||||
|
@ -545,8 +498,6 @@ gst_leaks_tracer_constructed (GObject * object)
|
|||
GstLeaksTracer *self = GST_LEAKS_TRACER (object);
|
||||
GstTracer *tracer = GST_TRACER (object);
|
||||
|
||||
set_params (self);
|
||||
|
||||
gst_tracing_register_hook (tracer, "mini-object-created",
|
||||
G_CALLBACK (mini_object_created_cb));
|
||||
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);
|
||||
|
||||
GST_TRACE_OBJECT (self, "start listing currently alive objects");
|
||||
GST_OBJECT_LOCK (self);
|
||||
process_leaks (self, &live_objects);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
@ -1138,13 +1090,150 @@ gst_leaks_tracer_activity_stop_tracking (GstLeaksTracer * 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
|
||||
gst_leaks_tracer_class_init (GstLeaksTracerClass * 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->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",
|
||||
RECORD_FIELD_TYPE_NAME, RECORD_FIELD_ADDRESS, RECORD_FIELD_DESC,
|
||||
|
|
|
@ -42,6 +42,12 @@ G_BEGIN_DECLS
|
|||
typedef struct _GstLeaksTracer GstLeaksTracer;
|
||||
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:
|
||||
*
|
||||
|
@ -71,7 +77,7 @@ struct _GstLeaksTracer {
|
|||
gboolean check_refs;
|
||||
gboolean log_leaks;
|
||||
|
||||
GstStackTraceFlags trace_flags;
|
||||
GstLeaksStackTraceFlags trace_flags;
|
||||
};
|
||||
|
||||
struct _GstLeaksTracerClass {
|
||||
|
|
Loading…
Reference in a new issue