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 res, gboolean is_post) { 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); GstStructure *s; s = gst_structure_new ("query", "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()), "ts", G_TYPE_UINT64, elapsed, "pad-ix", G_TYPE_UINT, this_pad_stats->index, "elem-ix", G_TYPE_UINT, this_elem_stats->index, "peer-pad-ix", G_TYPE_UINT, that_pad_stats->index, "peer-elem-ix", G_TYPE_UINT, that_elem_stats->index, "name", G_TYPE_STRING, GST_QUERY_TYPE_NAME (qry), "structure", GST_TYPE_STRUCTURE, gst_query_get_structure (qry), NULL); if (is_post) { gst_structure_set (s, "res", G_TYPE_BOOLEAN, res, NULL); } gst_tracer_log_trace (s); }
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); /* TODO(ensonic): need a quark-table (shared with the tracer-front-ends?) */ gst_tracer_log_trace (gst_structure_new ("buffer", "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()), "ts", G_TYPE_UINT64, elapsed, "pad-ix", G_TYPE_UINT, this_pad_stats->index, "elem-ix", G_TYPE_UINT, this_elem_stats->index, "peer-pad-ix", G_TYPE_UINT, that_pad_stats->index, "peer-elem-ix", G_TYPE_UINT, that_elem_stats->index, "buffer-size", G_TYPE_UINT, gst_buffer_get_size (buf), "buffer-pts", G_TYPE_UINT64, GST_BUFFER_PTS (buf), "buffer-dts", G_TYPE_UINT64, GST_BUFFER_DTS (buf), "buffer-duration", G_TYPE_UINT64, GST_BUFFER_DURATION (buf), "buffer-flags", GST_TYPE_BUFFER_FLAGS, GST_BUFFER_FLAGS (buf), /* scheduling-jitter: for this we need the last_ts on the pad */ NULL)); }
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 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 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; }
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_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_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_element_query_pre (GstStatsTracer * self, guint64 ts, GstElement * elem, GstQuery * qry) { GstElementStats *stats = get_element_stats (self, elem); stats->last_ts = ts; gst_tracer_log_trace (gst_structure_new ("element-query", "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()), "ts", G_TYPE_UINT64, ts, "elem-ix", G_TYPE_UINT, stats->index, "name", G_TYPE_STRING, GST_QUERY_TYPE_NAME (qry), NULL)); }
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_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_log_trace (gst_structure_new ("event", "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()), "ts", G_TYPE_UINT64, ts, "pad-ix", G_TYPE_UINT, pad_stats->index, "elem-ix", G_TYPE_UINT, elem_stats->index, "name", G_TYPE_STRING, GST_EVENT_TYPE_NAME (ev), NULL)); }
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; stats->last_ts = ts; s = gst_structure_new ("message", "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()), "ts", G_TYPE_UINT64, ts, "elem-ix", G_TYPE_UINT, stats->index, "name", G_TYPE_STRING, GST_MESSAGE_TYPE_NAME (msg), NULL); if (msg_s) { gst_structure_set (s, "structure", GST_TYPE_STRUCTURE, msg_s, NULL); } gst_tracer_log_trace (s); }
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 }