mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-26 18:20:44 +00:00
e4cba8a0bf
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.
816 lines
29 KiB
C
816 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", ¶ms, 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));
|
|
}
|