gstreamer/plugins/tracers/gststats.c
Guillaume Desmottes e4cba8a0bf tracers: set MAY_BE_LEAKED on tracer records
The records are static and so appear as false positives when using those
tracers with the leaks tracer as well.
The leaks tracer was already setting this flag on its record so let's
set it on the other ones as well.
2019-08-02 13:07:58 +05:30

817 lines
29 KiB
C

/* GStreamer
* Copyright (C) 2013 Stefan Sauer <ensonic@users.sf.net>
*
* gststats.c: tracing module that logs events
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:tracer-stats
* @short_description: log event stats
*
* A tracing module that builds usage statistic for elements and pads.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gststats.h"
#include <stdio.h>
GST_DEBUG_CATEGORY_STATIC (gst_stats_debug);
#define GST_CAT_DEFAULT gst_stats_debug
static GQuark data_quark;
G_LOCK_DEFINE (_elem_stats);
G_LOCK_DEFINE (_pad_stats);
#define _do_init \
GST_DEBUG_CATEGORY_INIT (gst_stats_debug, "stats", 0, "stats tracer"); \
data_quark = g_quark_from_static_string ("gststats:data");
#define gst_stats_tracer_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstStatsTracer, gst_stats_tracer, GST_TYPE_TRACER,
_do_init);
static GstTracerRecord *tr_new_element;
static GstTracerRecord *tr_new_pad;
static GstTracerRecord *tr_buffer;
static GstTracerRecord *tr_element_query;
static GstTracerRecord *tr_event;
static GstTracerRecord *tr_message;
static GstTracerRecord *tr_query;
typedef struct
{
/* we can't rely on the address to be unique over time */
guint index;
/* for pre + post */
GstClockTime last_ts;
/* hierarchy */
guint parent_ix;
} GstPadStats;
typedef struct
{
/* we can't rely on the address to be unique over time */
guint index;
/* for pre + post */
GstClockTime last_ts;
/* time spend in this element */
GstClockTime treal;
/* hierarchy */
guint parent_ix;
} GstElementStats;
/* data helper */
static GstElementStats no_elem_stats = { 0, };
static GstElementStats *
fill_element_stats (GstStatsTracer * self, GstElement * element)
{
GstElementStats *stats = g_slice_new0 (GstElementStats);
stats->index = self->num_elements++;
stats->parent_ix = G_MAXUINT;
return stats;
}
static void
log_new_element_stats (GstElementStats * stats, GstElement * element,
GstClockTime elapsed)
{
gst_tracer_record_log (tr_new_element, (guint64) (guintptr) g_thread_self (),
elapsed, stats->index, stats->parent_ix, GST_OBJECT_NAME (element),
G_OBJECT_TYPE_NAME (element), GST_IS_BIN (element));
}
static void
free_element_stats (gpointer data)
{
g_slice_free (GstElementStats, data);
}
static GstElementStats *
create_element_stats (GstStatsTracer * self, GstElement * element)
{
GstElementStats *stats;
stats = fill_element_stats (self, element);
g_object_set_qdata_full ((GObject *) element, data_quark, stats,
free_element_stats);
return stats;
}
static inline GstElementStats *
get_element_stats (GstStatsTracer * self, GstElement * element)
{
GstElementStats *stats;
gboolean is_new = FALSE;
if (!element) {
no_elem_stats.index = G_MAXUINT;
return &no_elem_stats;
}
G_LOCK (_elem_stats);
if (!(stats = g_object_get_qdata ((GObject *) element, data_quark))) {
stats = create_element_stats (self, element);
is_new = TRUE;
}
G_UNLOCK (_elem_stats);
if (G_UNLIKELY (stats->parent_ix == G_MAXUINT)) {
GstElement *parent = GST_ELEMENT_PARENT (element);
if (parent) {
GstElementStats *parent_stats = get_element_stats (self, parent);
stats->parent_ix = parent_stats->index;
}
}
if (G_UNLIKELY (is_new)) {
log_new_element_stats (stats, element, GST_CLOCK_TIME_NONE);
}
return stats;
}
/*
* Get the element/bin owning the pad.
*
* in: a normal pad
* out: the element
*
* in: a proxy pad
* out: the element that contains the peer of the proxy
*
* in: a ghost pad
* out: the bin owning the ghostpad
*/
/* TODO(ensonic): gst_pad_get_parent_element() would not work here, should we
* add this as new api, e.g. gst_pad_find_parent_element();
*/
static GstElement *
get_real_pad_parent (GstPad * pad)
{
GstObject *parent;
if (!pad)
return NULL;
parent = GST_OBJECT_PARENT (pad);
/* if parent of pad is a ghost-pad, then pad is a proxy_pad */
if (parent && GST_IS_GHOST_PAD (parent)) {
pad = GST_PAD_CAST (parent);
parent = GST_OBJECT_PARENT (pad);
}
return GST_ELEMENT_CAST (parent);
}
static GstPadStats no_pad_stats = { 0, };
static GstPadStats *
fill_pad_stats (GstStatsTracer * self, GstPad * pad)
{
GstPadStats *stats = g_slice_new0 (GstPadStats);
stats->index = self->num_pads++;
stats->parent_ix = G_MAXUINT;
return stats;
}
static void
log_new_pad_stats (GstPadStats * stats, GstPad * pad)
{
gst_tracer_record_log (tr_new_pad, (guint64) (guintptr) g_thread_self (),
stats->index, stats->parent_ix, GST_OBJECT_NAME (pad),
G_OBJECT_TYPE_NAME (pad), GST_IS_GHOST_PAD (pad),
GST_PAD_DIRECTION (pad));
}
static void
free_pad_stats (gpointer data)
{
g_slice_free (GstPadStats, data);
}
static GstPadStats *
get_pad_stats (GstStatsTracer * self, GstPad * pad)
{
GstPadStats *stats;
gboolean is_new = FALSE;
if (!pad) {
no_pad_stats.index = G_MAXUINT;
return &no_pad_stats;
}
G_LOCK (_pad_stats);
if (!(stats = g_object_get_qdata ((GObject *) pad, data_quark))) {
stats = fill_pad_stats (self, pad);
g_object_set_qdata_full ((GObject *) pad, data_quark, stats,
free_pad_stats);
is_new = TRUE;
}
G_UNLOCK (_pad_stats);
if (G_UNLIKELY (stats->parent_ix == G_MAXUINT)) {
GstElement *elem = get_real_pad_parent (pad);
if (elem) {
GstElementStats *elem_stats = get_element_stats (self, elem);
stats->parent_ix = elem_stats->index;
}
}
if (G_UNLIKELY (is_new)) {
log_new_pad_stats (stats, pad);
}
return stats;
}
static void
do_buffer_stats (GstStatsTracer * self, GstPad * this_pad,
GstPadStats * this_pad_stats, GstPad * that_pad,
GstPadStats * that_pad_stats, GstBuffer * buf, GstClockTime elapsed)
{
GstElement *this_elem = get_real_pad_parent (this_pad);
GstElementStats *this_elem_stats = get_element_stats (self, this_elem);
GstElement *that_elem = get_real_pad_parent (that_pad);
GstElementStats *that_elem_stats = get_element_stats (self, that_elem);
GstClockTime pts = GST_BUFFER_PTS (buf);
GstClockTime dts = GST_BUFFER_DTS (buf);
GstClockTime dur = GST_BUFFER_DURATION (buf);
gst_tracer_record_log (tr_buffer, (guint64) (guintptr) g_thread_self (),
elapsed, this_pad_stats->index, this_elem_stats->index,
that_pad_stats->index, that_elem_stats->index, gst_buffer_get_size (buf),
GST_CLOCK_TIME_IS_VALID (pts), pts, GST_CLOCK_TIME_IS_VALID (dts), dts,
GST_CLOCK_TIME_IS_VALID (dur), dur, GST_BUFFER_FLAGS (buf));
}
static void
do_query_stats (GstStatsTracer * self, GstPad * this_pad,
GstPadStats * this_pad_stats, GstPad * that_pad,
GstPadStats * that_pad_stats, GstQuery * qry, GstClockTime elapsed,
gboolean have_res, gboolean res)
{
GstElement *this_elem = get_real_pad_parent (this_pad);
GstElementStats *this_elem_stats = get_element_stats (self, this_elem);
GstElement *that_elem = get_real_pad_parent (that_pad);
GstElementStats *that_elem_stats = get_element_stats (self, that_elem);
gst_tracer_record_log (tr_query, (guint64) (guintptr) g_thread_self (),
elapsed, this_pad_stats->index, this_elem_stats->index,
that_pad_stats->index, that_elem_stats->index, GST_QUERY_TYPE_NAME (qry),
gst_query_get_structure (qry), have_res, res);
}
static void
do_element_stats (GstStatsTracer * self, GstPad * pad, GstClockTime elapsed1,
GstClockTime elapsed2)
{
GstClockTimeDiff elapsed = GST_CLOCK_DIFF (elapsed1, elapsed2);
GstObject *parent = GST_OBJECT_PARENT (pad);
GstElement *this =
GST_ELEMENT_CAST (GST_IS_PAD (parent) ? GST_OBJECT_PARENT (parent) :
parent);
GstElementStats *this_stats = get_element_stats (self, this);
GstPad *peer_pad = GST_PAD_PEER (pad);
GstElementStats *peer_stats;
if (!peer_pad)
return;
/* walk the ghost pad chain downstream to get the real pad */
/* if parent of peer_pad is a ghost-pad, then peer_pad is a proxy_pad */
parent = GST_OBJECT_PARENT (peer_pad);
if (parent && GST_IS_GHOST_PAD (parent)) {
peer_pad = GST_PAD_CAST (parent);
/* if this is now the ghost pad, get the peer of this */
get_pad_stats (self, peer_pad);
if ((parent = GST_OBJECT_PARENT (peer_pad))) {
get_element_stats (self, GST_ELEMENT_CAST (parent));
}
peer_pad = GST_PAD_PEER (GST_GHOST_PAD_CAST (peer_pad));
parent = peer_pad ? GST_OBJECT_PARENT (peer_pad) : NULL;
}
/* walk the ghost pad chain upstream to get the real pad */
/* if peer_pad is a ghost-pad, then parent is a bin and it is the parent of
* a proxy_pad */
while (peer_pad && GST_IS_GHOST_PAD (peer_pad)) {
get_pad_stats (self, peer_pad);
get_element_stats (self, GST_ELEMENT_CAST (parent));
peer_pad = gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (peer_pad));
parent = peer_pad ? GST_OBJECT_PARENT (peer_pad) : NULL;
}
if (!parent) {
printf ("%" GST_TIME_FORMAT
" transmission on unparented target pad %s_%s -> %s_%s\n",
GST_TIME_ARGS (elapsed), GST_DEBUG_PAD_NAME (pad),
GST_DEBUG_PAD_NAME (peer_pad));
return;
}
peer_stats = get_element_stats (self, GST_ELEMENT_CAST (parent));
/* we'd like to gather time spend in each element, but this does not make too
* much sense yet
* pure push/pull-based:
* - the time spend in the push/pull_range is accounted for the peer and
* removed from the current element
* - this works for chains
* - drawback is sink elements that block to sync have a high time usage
* - we could rerun the ests with sync=false
* both:
* - a.g. demuxers both push and pull. thus we subtract time for the pull
* and the push operations, but never add anything.
* - can we start a counter after push/pull in such elements and add then
* time to the element upon next pad activity?
*/
#if 1
/* this does not make sense for demuxers */
this_stats->treal -= elapsed;
peer_stats->treal += elapsed;
#else
/* this creates several >100% figures */
this_stats->treal += GST_CLOCK_DIFF (this_stats->last_ts, elapsed2) - elapsed;
peer_stats->treal += elapsed;
this_stats->last_ts = elapsed2;
peer_stats->last_ts = elapsed2;
#endif
}
/* hooks */
static void
do_push_buffer_pre (GstStatsTracer * self, guint64 ts, GstPad * this_pad,
GstBuffer * buffer)
{
GstPadStats *this_pad_stats = get_pad_stats (self, this_pad);
GstPad *that_pad = GST_PAD_PEER (this_pad);
GstPadStats *that_pad_stats = get_pad_stats (self, that_pad);
do_buffer_stats (self, this_pad, this_pad_stats, that_pad, that_pad_stats,
buffer, ts);
}
static void
do_push_buffer_post (GstStatsTracer * self, guint64 ts, GstPad * pad,
GstFlowReturn res)
{
GstPadStats *stats = get_pad_stats (self, pad);
do_element_stats (self, pad, stats->last_ts, ts);
}
typedef struct
{
GstStatsTracer *self;
GstPad *this_pad;
GstPadStats *this_pad_stats;
GstPad *that_pad;
GstPadStats *that_pad_stats;
guint64 ts;
} DoPushBufferListArgs;
static gboolean
do_push_buffer_list_item (GstBuffer ** buffer, guint idx, gpointer user_data)
{
DoPushBufferListArgs *args = (DoPushBufferListArgs *) user_data;
do_buffer_stats (args->self, args->this_pad, args->this_pad_stats,
args->that_pad, args->that_pad_stats, *buffer, args->ts);
return TRUE;
}
static void
do_push_buffer_list_pre (GstStatsTracer * self, guint64 ts, GstPad * this_pad,
GstBufferList * list)
{
GstPadStats *this_pad_stats = get_pad_stats (self, this_pad);
GstPad *that_pad = GST_PAD_PEER (this_pad);
GstPadStats *that_pad_stats = get_pad_stats (self, that_pad);
DoPushBufferListArgs args = { self, this_pad, this_pad_stats, that_pad,
that_pad_stats, ts
};
gst_buffer_list_foreach (list, do_push_buffer_list_item, &args);
}
static void
do_push_buffer_list_post (GstStatsTracer * self, guint64 ts, GstPad * pad,
GstFlowReturn res)
{
GstPadStats *stats = get_pad_stats (self, pad);
do_element_stats (self, pad, stats->last_ts, ts);
}
static void
do_pull_range_pre (GstStatsTracer * self, guint64 ts, GstPad * pad)
{
GstPadStats *stats = get_pad_stats (self, pad);
stats->last_ts = ts;
}
static void
do_pull_range_post (GstStatsTracer * self, guint64 ts, GstPad * this_pad,
GstBuffer * buffer)
{
GstPadStats *this_pad_stats = get_pad_stats (self, this_pad);
guint64 last_ts = this_pad_stats->last_ts;
GstPad *that_pad = GST_PAD_PEER (this_pad);
GstPadStats *that_pad_stats = get_pad_stats (self, that_pad);
if (buffer != NULL) {
do_buffer_stats (self, this_pad, this_pad_stats, that_pad, that_pad_stats,
buffer, ts);
}
do_element_stats (self, this_pad, last_ts, ts);
}
static void
do_push_event_pre (GstStatsTracer * self, guint64 ts, GstPad * pad,
GstEvent * ev)
{
GstElement *elem = get_real_pad_parent (pad);
GstElementStats *elem_stats = get_element_stats (self, elem);
GstPadStats *pad_stats = get_pad_stats (self, pad);
elem_stats->last_ts = ts;
gst_tracer_record_log (tr_event, (guint64) (guintptr) g_thread_self (), ts,
pad_stats->index, elem_stats->index, GST_EVENT_TYPE_NAME (ev));
}
static void
do_post_message_pre (GstStatsTracer * self, guint64 ts, GstElement * elem,
GstMessage * msg)
{
GstElementStats *stats = get_element_stats (self, elem);
const GstStructure *msg_s = gst_message_get_structure (msg);
GstStructure *s =
msg_s ? (GstStructure *) msg_s : gst_structure_new_empty ("dummy");
stats->last_ts = ts;
/* FIXME: work out whether using NULL instead of a dummy struct would work */
gst_tracer_record_log (tr_message, (guint64) (guintptr) g_thread_self (), ts,
stats->index, GST_MESSAGE_TYPE_NAME (msg), s);
if (s != msg_s)
gst_structure_free (s);
}
static void
do_element_new (GstStatsTracer * self, guint64 ts, GstElement * elem)
{
GstElementStats *stats;
stats = create_element_stats (self, elem);
log_new_element_stats (stats, elem, ts);
}
static void
do_element_query_pre (GstStatsTracer * self, guint64 ts, GstElement * elem,
GstQuery * qry)
{
GstElementStats *stats = get_element_stats (self, elem);
stats->last_ts = ts;
gst_tracer_record_log (tr_element_query,
(guint64) (guintptr) g_thread_self (), ts, stats->index,
GST_QUERY_TYPE_NAME (qry));
}
static void
do_query_pre (GstStatsTracer * self, guint64 ts, GstPad * this_pad,
GstQuery * qry)
{
GstPadStats *this_pad_stats = get_pad_stats (self, this_pad);
GstPad *that_pad = GST_PAD_PEER (this_pad);
GstPadStats *that_pad_stats = get_pad_stats (self, that_pad);
do_query_stats (self, this_pad, this_pad_stats, that_pad, that_pad_stats,
qry, ts, FALSE, FALSE);
}
static void
do_query_post (GstStatsTracer * self, guint64 ts, GstPad * this_pad,
GstQuery * qry, gboolean res)
{
GstPadStats *this_pad_stats = get_pad_stats (self, this_pad);
GstPad *that_pad = GST_PAD_PEER (this_pad);
GstPadStats *that_pad_stats = get_pad_stats (self, that_pad);
do_query_stats (self, this_pad, this_pad_stats, that_pad, that_pad_stats,
qry, ts, TRUE, res);
}
/* tracer class */
static void
gst_stats_tracer_constructed (GObject * object)
{
GstStatsTracer *self = GST_STATS_TRACER (object);
gchar *params, *tmp;
const gchar *name;
GstStructure *params_struct = NULL;
g_object_get (self, "params", &params, NULL);
if (!params)
return;
tmp = g_strdup_printf ("stats,%s", params);
params_struct = gst_structure_from_string (tmp, NULL);
g_free (tmp);
if (!params_struct)
return;
/* Set the name if assigned */
name = gst_structure_get_string (params_struct, "name");
if (name)
gst_object_set_name (GST_OBJECT (self), name);
gst_structure_free (params_struct);
}
static void
gst_stats_tracer_class_init (GstStatsTracerClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->constructed = gst_stats_tracer_constructed;
/* announce trace formats */
/* *INDENT-OFF* */
tr_buffer = gst_tracer_record_new ("buffer.class",
"thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_THREAD,
NULL),
"ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"description", G_TYPE_STRING, "event ts",
NULL),
"pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_PAD,
NULL),
"element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_ELEMENT,
NULL),
"peer-pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_PAD,
NULL),
"peer-element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_ELEMENT,
NULL),
"buffer-size", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"description", G_TYPE_STRING, "size of buffer in bytes",
"min", G_TYPE_UINT, 0,
"max", G_TYPE_UINT, G_MAXUINT,
NULL),
"buffer-pts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"description", G_TYPE_STRING, "presentation timestamp of the buffer in ns",
"flags", GST_TYPE_TRACER_VALUE_FLAGS, GST_TRACER_VALUE_FLAGS_OPTIONAL,
"min", G_TYPE_UINT64, G_GUINT64_CONSTANT (0),
"max", G_TYPE_UINT64, G_MAXUINT64,
NULL),
"buffer-dts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"description", G_TYPE_STRING, "decoding timestamp of the buffer in ns",
"flags", GST_TYPE_TRACER_VALUE_FLAGS, GST_TRACER_VALUE_FLAGS_OPTIONAL,
"min", G_TYPE_UINT64, G_GUINT64_CONSTANT (0),
"max", G_TYPE_UINT64, G_MAXUINT64,
NULL),
"buffer-duration", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"description", G_TYPE_STRING, "duration of the buffer in ns",
"flags", GST_TYPE_TRACER_VALUE_FLAGS, GST_TRACER_VALUE_FLAGS_OPTIONAL,
"min", G_TYPE_UINT64, G_GUINT64_CONSTANT (0),
"max", G_TYPE_UINT64, G_MAXUINT64,
NULL),
"buffer-flags", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, GST_TYPE_BUFFER_FLAGS,
"description", G_TYPE_STRING, "flags of the buffer",
NULL),
NULL);
tr_event = gst_tracer_record_new ("event.class",
"thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_THREAD,
NULL),
"ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"description", G_TYPE_STRING, "event ts",
NULL),
"pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_PAD,
NULL),
"element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_ELEMENT,
NULL),
"name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_STRING,
"description", G_TYPE_STRING, "name of the event",
NULL),
NULL);
tr_message = gst_tracer_record_new ("message.class",
"thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_THREAD,
NULL),
"ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"description", G_TYPE_STRING, "event ts",
NULL),
"element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_ELEMENT,
NULL),
"name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_STRING,
"description", G_TYPE_STRING, "name of the message",
NULL),
"structure", GST_TYPE_STRUCTURE, gst_structure_new ("structure",
"type", G_TYPE_GTYPE, GST_TYPE_STRUCTURE,
"description", G_TYPE_STRING, "message structure",
NULL),
NULL);
tr_element_query = gst_tracer_record_new ("element-query.class",
"thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_THREAD,
NULL),
"ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"description", G_TYPE_STRING, "event ts",
NULL),
"element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_ELEMENT,
NULL),
"name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_STRING,
"description", G_TYPE_STRING, "name of the query",
NULL),
NULL);
tr_query = gst_tracer_record_new ("query.class",
"thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_THREAD,
NULL),
"ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"description", G_TYPE_STRING, "event ts",
NULL),
"pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_PAD,
NULL),
"element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_ELEMENT,
NULL),
"peer-pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_PAD,
NULL),
"peer-element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_ELEMENT,
NULL),
"name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_STRING,
"description", G_TYPE_STRING, "name of the query",
NULL),
"structure", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, GST_TYPE_STRUCTURE,
"description", G_TYPE_STRING, "query structure",
NULL),
"res", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_BOOLEAN,
"description", G_TYPE_STRING, "query result",
"flags", GST_TYPE_TRACER_VALUE_FLAGS, GST_TRACER_VALUE_FLAGS_OPTIONAL,
NULL),
NULL);
tr_new_element = gst_tracer_record_new ("new-element.class",
"thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_THREAD,
NULL),
"ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"description", G_TYPE_STRING, "event ts",
NULL),
"ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_ELEMENT,
NULL),
"parent-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_ELEMENT,
NULL),
"name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_STRING,
"description", G_TYPE_STRING, "name of the element",
NULL),
"type", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_STRING,
"description", G_TYPE_STRING, "type name of the element",
NULL),
"is-bin", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_BOOLEAN,
"description", G_TYPE_STRING, "is element a bin",
NULL),
NULL);
tr_new_pad = gst_tracer_record_new ("new-pad.class",
"thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT64,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_THREAD,
NULL),
"ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_PAD,
NULL),
"parent-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
"type", G_TYPE_GTYPE, G_TYPE_UINT,
"related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_ELEMENT,
NULL),
"name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_STRING,
"description", G_TYPE_STRING, "name of the pad",
NULL),
"type", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_STRING,
"description", G_TYPE_STRING, "type name of the pad",
NULL),
"is-ghostpad", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, G_TYPE_BOOLEAN,
"description", G_TYPE_STRING, "is pad a ghostpad",
NULL),
"pad-direction", GST_TYPE_STRUCTURE, gst_structure_new ("value",
"type", G_TYPE_GTYPE, GST_TYPE_PAD_DIRECTION,
"description", G_TYPE_STRING, "ipad direction",
NULL),
NULL);
/* *INDENT-ON* */
GST_OBJECT_FLAG_SET (tr_buffer, GST_OBJECT_FLAG_MAY_BE_LEAKED);
GST_OBJECT_FLAG_SET (tr_event, GST_OBJECT_FLAG_MAY_BE_LEAKED);
GST_OBJECT_FLAG_SET (tr_message, GST_OBJECT_FLAG_MAY_BE_LEAKED);
GST_OBJECT_FLAG_SET (tr_element_query, GST_OBJECT_FLAG_MAY_BE_LEAKED);
GST_OBJECT_FLAG_SET (tr_query, GST_OBJECT_FLAG_MAY_BE_LEAKED);
GST_OBJECT_FLAG_SET (tr_new_element, GST_OBJECT_FLAG_MAY_BE_LEAKED);
GST_OBJECT_FLAG_SET (tr_new_pad, GST_OBJECT_FLAG_MAY_BE_LEAKED);
}
static void
gst_stats_tracer_init (GstStatsTracer * self)
{
GstTracer *tracer = GST_TRACER (self);
gst_tracing_register_hook (tracer, "pad-push-pre",
G_CALLBACK (do_push_buffer_pre));
gst_tracing_register_hook (tracer, "pad-push-post",
G_CALLBACK (do_push_buffer_post));
gst_tracing_register_hook (tracer, "pad-push-list-pre",
G_CALLBACK (do_push_buffer_list_pre));
gst_tracing_register_hook (tracer, "pad-push-list-post",
G_CALLBACK (do_push_buffer_list_post));
gst_tracing_register_hook (tracer, "pad-pull-range-pre",
G_CALLBACK (do_pull_range_pre));
gst_tracing_register_hook (tracer, "pad-pull-range-post",
G_CALLBACK (do_pull_range_post));
gst_tracing_register_hook (tracer, "pad-push-event-pre",
G_CALLBACK (do_push_event_pre));
gst_tracing_register_hook (tracer, "element-new",
G_CALLBACK (do_element_new));
gst_tracing_register_hook (tracer, "element-post-message-pre",
G_CALLBACK (do_post_message_pre));
gst_tracing_register_hook (tracer, "element-query-pre",
G_CALLBACK (do_element_query_pre));
gst_tracing_register_hook (tracer, "pad-query-pre",
G_CALLBACK (do_query_pre));
gst_tracing_register_hook (tracer, "pad-query-post",
G_CALLBACK (do_query_post));
}