tracer: harmonize the query hooks
[platform/upstream/gstreamer.git] / plugins / tracers / gststats.c
1 /* GStreamer
2  * Copyright (C) 2013 Stefan Sauer <ensonic@users.sf.net>
3  *
4  * gststats.c: tracing module that logs events
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 /**
22  * SECTION:gststats
23  * @short_description: log event stats
24  *
25  * A tracing module that builds usage statistic for elements and pads. 
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #  include "config.h"
30 #endif
31
32 #include "gststats.h"
33
34 #include <stdio.h>
35
36 GST_DEBUG_CATEGORY_STATIC (gst_stats_debug);
37 #define GST_CAT_DEFAULT gst_stats_debug
38
39 static GQuark data_quark;
40 G_LOCK_DEFINE (_elem_stats);
41 G_LOCK_DEFINE (_pad_stats);
42
43 #define _do_init \
44     GST_DEBUG_CATEGORY_INIT (gst_stats_debug, "stats", 0, "stats tracer"); \
45     data_quark = g_quark_from_static_string ("gststats:data");
46 #define gst_stats_tracer_parent_class parent_class
47 G_DEFINE_TYPE_WITH_CODE (GstStatsTracer, gst_stats_tracer, GST_TYPE_TRACER,
48     _do_init);
49
50 typedef struct
51 {
52   /* we can't rely on the address to be unique over time */
53   guint index;
54   /* for pre + post */
55   GstClockTime last_ts;
56   /* hierarchy */
57   guint parent_ix;
58 } GstPadStats;
59
60 typedef struct
61 {
62   /* we can't rely on the address to be unique over time */
63   guint index;
64   /* for pre + post */
65   GstClockTime last_ts;
66   /* time spend in this element */
67   GstClockTime treal;
68   /* hierarchy */
69   guint parent_ix;
70 } GstElementStats;
71
72 /* data helper */
73
74 static GstElementStats no_elem_stats = { 0, };
75
76 static GstElementStats *
77 fill_element_stats (GstStatsTracer * self, GstElement * element)
78 {
79   GstElementStats *stats = g_slice_new0 (GstElementStats);
80
81   stats->index = self->num_elements++;
82   stats->parent_ix = G_MAXUINT;
83   return stats;
84 }
85
86 static void
87 log_new_element_stats (GstElementStats * stats, GstElement * element,
88     GstClockTime elapsed)
89 {
90   gst_tracer_log_trace (gst_structure_new ("new-element",
91           "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()),
92           "ts", G_TYPE_UINT64, elapsed,
93           "ix", G_TYPE_UINT, stats->index,
94           "parent-ix", G_TYPE_UINT, stats->parent_ix,
95           "name", G_TYPE_STRING, GST_OBJECT_NAME (element),
96           "type", G_TYPE_STRING, G_OBJECT_TYPE_NAME (element),
97           "is-bin", G_TYPE_BOOLEAN, GST_IS_BIN (element), NULL));
98 }
99
100 static void
101 free_element_stats (gpointer data)
102 {
103   g_slice_free (GstElementStats, data);
104 }
105
106 static GstElementStats *
107 create_element_stats (GstStatsTracer * self, GstElement * element)
108 {
109   GstElementStats *stats;
110
111   stats = fill_element_stats (self, element);
112   g_object_set_qdata_full ((GObject *) element, data_quark, stats,
113       free_element_stats);
114
115   return stats;
116 }
117
118 static inline GstElementStats *
119 get_element_stats (GstStatsTracer * self, GstElement * element)
120 {
121   GstElementStats *stats;
122   gboolean is_new = FALSE;
123
124   if (!element) {
125     no_elem_stats.index = G_MAXUINT;
126     return &no_elem_stats;
127   }
128
129   G_LOCK (_elem_stats);
130   if (!(stats = g_object_get_qdata ((GObject *) element, data_quark))) {
131     stats = create_element_stats (self, element);
132     is_new = TRUE;
133   }
134   G_UNLOCK (_elem_stats);
135   if (G_UNLIKELY (stats->parent_ix == G_MAXUINT)) {
136     GstElement *parent = GST_ELEMENT_PARENT (element);
137     if (parent) {
138       GstElementStats *parent_stats = get_element_stats (self, parent);
139       stats->parent_ix = parent_stats->index;
140     }
141   }
142   if (G_UNLIKELY (is_new)) {
143     log_new_element_stats (stats, element, GST_CLOCK_TIME_NONE);
144   }
145   return stats;
146 }
147
148 /*
149  * Get the element/bin owning the pad. 
150  *
151  * in: a normal pad
152  * out: the element
153  *
154  * in: a proxy pad
155  * out: the element that contains the peer of the proxy
156  *
157  * in: a ghost pad
158  * out: the bin owning the ghostpad
159  */
160 /* TODO(ensonic): gst_pad_get_parent_element() would not work here, should we
161  * add this as new api, e.g. gst_pad_find_parent_element();
162  */
163 static GstElement *
164 get_real_pad_parent (GstPad * pad)
165 {
166   GstObject *parent;
167
168   if (!pad)
169     return NULL;
170
171   parent = GST_OBJECT_PARENT (pad);
172
173   /* if parent of pad is a ghost-pad, then pad is a proxy_pad */
174   if (parent && GST_IS_GHOST_PAD (parent)) {
175     pad = GST_PAD_CAST (parent);
176     parent = GST_OBJECT_PARENT (pad);
177   }
178   return GST_ELEMENT_CAST (parent);
179 }
180
181 static GstPadStats no_pad_stats = { 0, };
182
183 static GstPadStats *
184 fill_pad_stats (GstStatsTracer * self, GstPad * pad)
185 {
186   GstPadStats *stats = g_slice_new0 (GstPadStats);
187
188   stats->index = self->num_pads++;
189   stats->parent_ix = G_MAXUINT;
190
191   return stats;
192 }
193
194 static void
195 log_new_pad_stats (GstPadStats * stats, GstPad * pad)
196 {
197   gst_tracer_log_trace (gst_structure_new ("new-pad",
198           "ix", G_TYPE_UINT, stats->index,
199           "parent-ix", G_TYPE_UINT, stats->parent_ix,
200           "name", G_TYPE_STRING, GST_OBJECT_NAME (pad),
201           "type", G_TYPE_STRING, G_OBJECT_TYPE_NAME (pad),
202           "is-ghostpad", G_TYPE_BOOLEAN, GST_IS_GHOST_PAD (pad),
203           "pad-direction", GST_TYPE_PAD_DIRECTION, GST_PAD_DIRECTION (pad),
204           "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()), NULL));
205 }
206
207 static void
208 free_pad_stats (gpointer data)
209 {
210   g_slice_free (GstPadStats, data);
211 }
212
213 static GstPadStats *
214 get_pad_stats (GstStatsTracer * self, GstPad * pad)
215 {
216   GstPadStats *stats;
217   gboolean is_new = FALSE;
218
219   if (!pad) {
220     no_pad_stats.index = G_MAXUINT;
221     return &no_pad_stats;
222   }
223
224   G_LOCK (_pad_stats);
225   if (!(stats = g_object_get_qdata ((GObject *) pad, data_quark))) {
226     stats = fill_pad_stats (self, pad);
227     g_object_set_qdata_full ((GObject *) pad, data_quark, stats,
228         free_pad_stats);
229     is_new = TRUE;
230   }
231   G_UNLOCK (_pad_stats);
232   if (G_UNLIKELY (stats->parent_ix == G_MAXUINT)) {
233     GstElement *elem = get_real_pad_parent (pad);
234     if (elem) {
235       GstElementStats *elem_stats = get_element_stats (self, elem);
236
237       stats->parent_ix = elem_stats->index;
238     }
239   }
240   if (G_UNLIKELY (is_new)) {
241     log_new_pad_stats (stats, pad);
242   }
243   return stats;
244 }
245
246 static void
247 do_buffer_stats (GstStatsTracer * self, GstPad * this_pad,
248     GstPadStats * this_pad_stats, GstPad * that_pad,
249     GstPadStats * that_pad_stats, GstBuffer * buf, GstClockTime elapsed)
250 {
251   GstElement *this_elem = get_real_pad_parent (this_pad);
252   GstElementStats *this_elem_stats = get_element_stats (self, this_elem);
253   GstElement *that_elem = get_real_pad_parent (that_pad);
254   GstElementStats *that_elem_stats = get_element_stats (self, that_elem);
255
256   /* TODO(ensonic): need a quark-table (shared with the tracer-front-ends?) */
257   gst_tracer_log_trace (gst_structure_new ("buffer",
258           "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()),
259           "ts", G_TYPE_UINT64, elapsed,
260           "pad-ix", G_TYPE_UINT, this_pad_stats->index,
261           "elem-ix", G_TYPE_UINT, this_elem_stats->index,
262           "peer-pad-ix", G_TYPE_UINT, that_pad_stats->index,
263           "peer-elem-ix", G_TYPE_UINT, that_elem_stats->index,
264           "buffer-size", G_TYPE_UINT, gst_buffer_get_size (buf),
265           "buffer-pts", G_TYPE_UINT64, GST_BUFFER_PTS (buf),
266           "buffer-dts", G_TYPE_UINT64, GST_BUFFER_DTS (buf),
267           "buffer-duration", G_TYPE_UINT64, GST_BUFFER_DURATION (buf),
268           "buffer-flags", GST_TYPE_BUFFER_FLAGS, GST_BUFFER_FLAGS (buf),
269           /*
270              scheduling-jitter: for this we need the last_ts on the pad
271            */
272           NULL));
273 }
274
275 static void
276 do_query_stats (GstStatsTracer * self, GstPad * this_pad,
277     GstPadStats * this_pad_stats, GstPad * that_pad,
278     GstPadStats * that_pad_stats, GstQuery * qry, GstClockTime elapsed,
279     gboolean res, gboolean pre)
280 {
281   GstElement *this_elem = get_real_pad_parent (this_pad);
282   GstElementStats *this_elem_stats = get_element_stats (self, this_elem);
283   GstElement *that_elem = get_real_pad_parent (that_pad);
284   GstElementStats *that_elem_stats = get_element_stats (self, that_elem);
285   GstStructure *s;
286
287   s = gst_structure_new ("query",
288       "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()),
289       "ts", G_TYPE_UINT64, elapsed,
290       "pad-ix", G_TYPE_UINT, this_pad_stats->index,
291       "elem-ix", G_TYPE_UINT, this_elem_stats->index,
292       "peer-pad-ix", G_TYPE_UINT, that_pad_stats->index,
293       "peer-elem-ix", G_TYPE_UINT, that_elem_stats->index,
294       "name", G_TYPE_STRING, GST_QUERY_TYPE_NAME (qry),
295       "structure", GST_TYPE_STRUCTURE, gst_query_get_structure (qry), NULL);
296   if (!pre) {
297     gst_structure_set (s, "res", G_TYPE_BOOLEAN, res, NULL);
298   }
299   gst_tracer_log_trace (s);
300 }
301
302 static void
303 do_element_stats (GstStatsTracer * self, GstPad * pad, GstClockTime elapsed1,
304     GstClockTime elapsed2)
305 {
306   GstClockTimeDiff elapsed = GST_CLOCK_DIFF (elapsed1, elapsed2);
307   GstObject *parent = GST_OBJECT_PARENT (pad);
308   GstElement *this =
309       GST_ELEMENT_CAST (GST_IS_PAD (parent) ? GST_OBJECT_PARENT (parent) :
310       parent);
311   GstElementStats *this_stats = get_element_stats (self, this);
312   GstPad *peer_pad = GST_PAD_PEER (pad);
313   GstElementStats *peer_stats;
314
315   if (!peer_pad)
316     return;
317
318   /* walk the ghost pad chain downstream to get the real pad */
319   /* if parent of peer_pad is a ghost-pad, then peer_pad is a proxy_pad */
320   parent = GST_OBJECT_PARENT (peer_pad);
321   if (parent && GST_IS_GHOST_PAD (parent)) {
322     peer_pad = GST_PAD_CAST (parent);
323     /* if this is now the ghost pad, get the peer of this */
324     get_pad_stats (self, peer_pad);
325     if ((parent = GST_OBJECT_PARENT (peer_pad))) {
326       get_element_stats (self, GST_ELEMENT_CAST (parent));
327     }
328     peer_pad = GST_PAD_PEER (GST_GHOST_PAD_CAST (peer_pad));
329     parent = peer_pad ? GST_OBJECT_PARENT (peer_pad) : NULL;
330   }
331   /* walk the ghost pad chain upstream to get the real pad */
332   /* if peer_pad is a ghost-pad, then parent is a bin and it is the parent of
333    * a proxy_pad */
334   while (peer_pad && GST_IS_GHOST_PAD (peer_pad)) {
335     get_pad_stats (self, peer_pad);
336     get_element_stats (self, GST_ELEMENT_CAST (parent));
337     peer_pad = gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (peer_pad));
338     parent = peer_pad ? GST_OBJECT_PARENT (peer_pad) : NULL;
339   }
340
341   if (!parent) {
342     printf ("%" GST_TIME_FORMAT
343         " transmission on unparented target pad %s_%s -> %s_%s\n",
344         GST_TIME_ARGS (elapsed), GST_DEBUG_PAD_NAME (pad),
345         GST_DEBUG_PAD_NAME (peer_pad));
346     return;
347   }
348   peer_stats = get_element_stats (self, GST_ELEMENT_CAST (parent));
349
350   /* we'd like to gather time spend in each element, but this does not make too
351    * much sense yet
352    * pure push/pull-based:
353    *   - the time spend in the push/pull_range is accounted for the peer and
354    *     removed from the current element
355    *   - this works for chains
356    *   - drawback is sink elements that block to sync have a high time usage
357    *     - we could rerun the ests with sync=false
358    * both:
359    *   - a.g. demuxers both push and pull. thus we subtract time for the pull
360    *     and the push operations, but never add anything.
361    *   - can we start a counter after push/pull in such elements and add then
362    *     time to the element upon next pad activity?
363    */
364 #if 1
365   /* this does not make sense for demuxers */
366   this_stats->treal -= elapsed;
367   peer_stats->treal += elapsed;
368 #else
369   /* this creates several >100% figures */
370   this_stats->treal += GST_CLOCK_DIFF (this_stats->last_ts, elapsed2) - elapsed;
371   peer_stats->treal += elapsed;
372   this_stats->last_ts = elapsed2;
373   peer_stats->last_ts = elapsed2;
374 #endif
375 }
376
377 /* hooks */
378
379 static void
380 do_push_buffer_pre (GstStatsTracer * self, guint64 ts, GstPad * this_pad,
381     GstBuffer * buffer)
382 {
383   GstPadStats *this_pad_stats = get_pad_stats (self, this_pad);
384   GstPad *that_pad = GST_PAD_PEER (this_pad);
385   GstPadStats *that_pad_stats = get_pad_stats (self, that_pad);
386
387   do_buffer_stats (self, this_pad, this_pad_stats, that_pad, that_pad_stats,
388       buffer, ts);
389 }
390
391 static void
392 do_push_buffer_post (GstStatsTracer * self, guint64 ts, GstPad * pad,
393     GstFlowReturn res)
394 {
395   GstPadStats *stats = get_pad_stats (self, pad);
396
397   do_element_stats (self, pad, stats->last_ts, ts);
398 }
399
400 typedef struct
401 {
402   GstStatsTracer *self;
403   GstPad *this_pad;
404   GstPadStats *this_pad_stats;
405   GstPad *that_pad;
406   GstPadStats *that_pad_stats;
407   guint64 ts;
408 } DoPushBufferListArgs;
409
410 static gboolean
411 do_push_buffer_list_item (GstBuffer ** buffer, guint idx, gpointer user_data)
412 {
413   DoPushBufferListArgs *args = (DoPushBufferListArgs *) user_data;
414
415   do_buffer_stats (args->self, args->this_pad, args->this_pad_stats,
416       args->that_pad, args->that_pad_stats, *buffer, args->ts);
417   return TRUE;
418 }
419
420 static void
421 do_push_buffer_list_pre (GstStatsTracer * self, guint64 ts, GstPad * this_pad,
422     GstBufferList * list)
423 {
424   GstPadStats *this_pad_stats = get_pad_stats (self, this_pad);
425   GstPad *that_pad = GST_PAD_PEER (this_pad);
426   GstPadStats *that_pad_stats = get_pad_stats (self, that_pad);
427   DoPushBufferListArgs args = { self, this_pad, this_pad_stats, that_pad,
428     that_pad_stats, ts
429   };
430
431   gst_buffer_list_foreach (list, do_push_buffer_list_item, &args);
432 }
433
434 static void
435 do_push_buffer_list_post (GstStatsTracer * self, guint64 ts, GstPad * pad,
436     GstFlowReturn res)
437 {
438   GstPadStats *stats = get_pad_stats (self, pad);
439
440   do_element_stats (self, pad, stats->last_ts, ts);
441 }
442
443 static void
444 do_pull_range_pre (GstStatsTracer * self, guint64 ts, GstPad * pad)
445 {
446   GstPadStats *stats = get_pad_stats (self, pad);
447   stats->last_ts = ts;
448 }
449
450 static void
451 do_pull_range_post (GstStatsTracer * self, guint64 ts, GstPad * this_pad,
452     GstBuffer * buffer)
453 {
454   GstPadStats *this_pad_stats = get_pad_stats (self, this_pad);
455   guint64 last_ts = this_pad_stats->last_ts;
456   GstPad *that_pad = GST_PAD_PEER (this_pad);
457   GstPadStats *that_pad_stats = get_pad_stats (self, that_pad);
458
459   if (buffer != NULL) {
460     do_buffer_stats (self, this_pad, this_pad_stats, that_pad, that_pad_stats,
461         buffer, ts);
462   }
463   do_element_stats (self, this_pad, last_ts, ts);
464 }
465
466 static void
467 do_push_event_pre (GstStatsTracer * self, guint64 ts, GstPad * pad,
468     GstEvent * ev)
469 {
470   GstElement *elem = get_real_pad_parent (pad);
471   GstElementStats *elem_stats = get_element_stats (self, elem);
472   GstPadStats *pad_stats = get_pad_stats (self, pad);
473
474   elem_stats->last_ts = ts;
475   gst_tracer_log_trace (gst_structure_new ("event",
476           "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()),
477           "ts", G_TYPE_UINT64, ts,
478           "pad-ix", G_TYPE_UINT, pad_stats->index,
479           "elem-ix", G_TYPE_UINT, elem_stats->index,
480           "name", G_TYPE_STRING, GST_EVENT_TYPE_NAME (ev), NULL));
481 }
482
483 static void
484 do_post_message_pre (GstStatsTracer * self, guint64 ts, GstElement * elem,
485     GstMessage * msg)
486 {
487   GstElementStats *stats = get_element_stats (self, elem);
488   const GstStructure *msg_s;
489   GstStructure *structure = gst_structure_new ("message",
490       "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()),
491       "ts", G_TYPE_UINT64, ts,
492       "elem-ix", G_TYPE_UINT, stats->index,
493       "name", G_TYPE_STRING, GST_MESSAGE_TYPE_NAME (msg),
494       NULL);
495
496   stats->last_ts = ts;
497
498   if ((msg_s = gst_message_get_structure (msg))) {
499     gst_structure_set (structure, "structure", GST_TYPE_STRUCTURE, msg_s, NULL);
500   }
501
502   gst_tracer_log_trace (structure);
503 }
504
505 static void
506 do_element_new (GstStatsTracer * self, guint64 ts, GstElement * elem)
507 {
508   GstElementStats *stats;
509
510   stats = create_element_stats (self, elem);
511   log_new_element_stats (stats, elem, ts);
512 }
513
514 static void
515 do_element_query_pre (GstStatsTracer * self, guint64 ts, GstElement * elem,
516     GstQuery * qry)
517 {
518   GstElementStats *stats = get_element_stats (self, elem);
519
520   stats->last_ts = ts;
521   gst_tracer_log_trace (gst_structure_new ("element-query",
522           "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()),
523           "ts", G_TYPE_UINT64, ts,
524           "elem-ix", G_TYPE_UINT, stats->index,
525           "name", G_TYPE_STRING, GST_QUERY_TYPE_NAME (qry), NULL));
526 }
527
528 static void
529 do_query_pre (GstStatsTracer * self, guint64 ts, GstPad * this_pad,
530     GstQuery * qry)
531 {
532   GstPadStats *this_pad_stats = get_pad_stats (self, this_pad);
533   GstPad *that_pad = GST_PAD_PEER (this_pad);
534   GstPadStats *that_pad_stats = get_pad_stats (self, that_pad);
535
536   do_query_stats (self, this_pad, this_pad_stats, that_pad, that_pad_stats,
537       qry, ts, FALSE, TRUE);
538 }
539
540 static void
541 do_query_post (GstStatsTracer * self, guint64 ts, GstPad * this_pad,
542     GstQuery * qry, gboolean res)
543 {
544   GstPadStats *this_pad_stats = get_pad_stats (self, this_pad);
545   GstPad *that_pad = GST_PAD_PEER (this_pad);
546   GstPadStats *that_pad_stats = get_pad_stats (self, that_pad);
547
548   do_query_stats (self, this_pad, this_pad_stats, that_pad, that_pad_stats,
549       qry, ts, res, FALSE);
550 }
551
552 /* tracer class */
553
554 static void
555 gst_stats_tracer_class_init (GstStatsTracerClass * klass)
556 {
557   /* announce trace formats */
558   /* *INDENT-OFF* */
559   gst_tracer_log_trace (gst_structure_new ("buffer.class",
560       "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
561           "related-to", G_TYPE_STRING, "thread", /* TODO use genum */
562           NULL),
563       "pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
564           "related-to", G_TYPE_STRING, "pad",  /* TODO: use genum */
565           NULL),
566       "element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
567           "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
568           NULL),
569       "peer-pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
570           "related-to", G_TYPE_STRING, "pad",  /* TODO: use genum */
571           NULL),
572       "peer-element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
573           "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
574           NULL),
575       "buffer-size", GST_TYPE_STRUCTURE, gst_structure_new ("value",
576           "type", G_TYPE_GTYPE, G_TYPE_UINT,
577           "description", G_TYPE_STRING, "size of buffer in bytes",
578           "flags", G_TYPE_STRING, "",  /* TODO: use gflags */ 
579           "min", G_TYPE_UINT, 0, 
580           "max", G_TYPE_UINT, G_MAXUINT,
581           NULL),
582       "buffer-ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
583           "type", G_TYPE_GTYPE, G_TYPE_UINT64,
584           "description", G_TYPE_STRING, "timestamp of the buffer in ns",
585           "flags", G_TYPE_STRING, "",  /* TODO: use gflags */ 
586           "min", G_TYPE_UINT64, G_GUINT64_CONSTANT (0),
587           "max", G_TYPE_UINT64, G_MAXUINT64,
588           NULL),
589       "buffer-duration", GST_TYPE_STRUCTURE, gst_structure_new ("value",
590           "type", G_TYPE_GTYPE, G_TYPE_UINT64,
591           "description", G_TYPE_STRING, "duration of the buffer in ns",
592           "flags", G_TYPE_STRING, "",  /* TODO: use gflags */ 
593           "min", G_TYPE_UINT64, G_GUINT64_CONSTANT (0),
594           "max", G_TYPE_UINT64, G_MAXUINT64,
595           NULL),
596       /* TODO(ensonic): "buffer-flags" */
597       NULL));
598   gst_tracer_log_trace (gst_structure_new ("event.class",
599       "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
600           "related-to", G_TYPE_STRING, "thread", /* TODO use genum */
601           NULL),
602       "pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
603           "related-to", G_TYPE_STRING, "pad",  /* TODO: use genum */
604           NULL),
605       "element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
606           "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
607           NULL),
608       "name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
609           "type", G_TYPE_GTYPE, G_TYPE_STRING,
610           "description", G_TYPE_STRING, "name of the event",
611           "flags", G_TYPE_STRING, "",  /* TODO: use gflags */ 
612           NULL),
613       NULL));
614   gst_tracer_log_trace (gst_structure_new ("message.class",
615       "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
616           "related-to", G_TYPE_STRING, "thread", /* TODO use genum */
617           NULL),
618       "element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
619           "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
620           NULL),
621       "name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
622           "type", G_TYPE_GTYPE, G_TYPE_STRING,
623           "description", G_TYPE_STRING, "name of the message",
624           "flags", G_TYPE_STRING, "",  /* TODO: use gflags */ 
625           NULL),
626       "structure", GST_TYPE_STRUCTURE, gst_structure_new ("structure",
627           "type", G_TYPE_GTYPE, GST_TYPE_STRUCTURE,
628           "description", G_TYPE_STRING, "message structure",
629           NULL),
630       NULL));
631   gst_tracer_log_trace (gst_structure_new ("elementquery.class",
632       "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
633           "related-to", G_TYPE_STRING, "thread", /* TODO use genum */
634           NULL),
635       "element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
636           "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
637           NULL),
638       "name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
639           "type", G_TYPE_GTYPE, G_TYPE_STRING,
640           "description", G_TYPE_STRING, "name of the query",
641           "flags", G_TYPE_STRING, "",  /* TODO: use gflags */ 
642           NULL),
643       NULL));
644   gst_tracer_log_trace (gst_structure_new ("query.class",
645       "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
646           "related-to", G_TYPE_STRING, "thread", /* TODO use genum */
647           NULL),
648       "pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
649           "related-to", G_TYPE_STRING, "pad",  /* TODO: use genum */
650           NULL),
651       "element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
652           "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
653           NULL),
654       "peer-pad-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
655           "related-to", G_TYPE_STRING, "pad",  /* TODO: use genum */
656           NULL),
657       "peer-element-ix", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
658           "related-to", G_TYPE_STRING, "element",  /* TODO: use genum */
659           NULL),
660       "name", GST_TYPE_STRUCTURE, gst_structure_new ("value",
661           "type", G_TYPE_GTYPE, G_TYPE_STRING,
662           "description", G_TYPE_STRING, "name of the query",
663           "flags", G_TYPE_STRING, "",  /* TODO: use gflags */ 
664           NULL),
665       "structure", GST_TYPE_STRUCTURE, gst_structure_new ("value",
666           "type", G_TYPE_GTYPE, GST_TYPE_STRUCTURE,
667           "description", G_TYPE_STRING, "query structure",
668           "flags", G_TYPE_STRING, "",  /* TODO: use gflags */ 
669           NULL),
670       /* TODO(ensonic): "buffer-flags" */
671       NULL));
672   /* *INDENT-ON* */
673 }
674
675 static void
676 gst_stats_tracer_init (GstStatsTracer * self)
677 {
678   GstTracer *tracer = GST_TRACER (self);
679
680   gst_tracing_register_hook (tracer, "pad-push-pre",
681       G_CALLBACK (do_push_buffer_pre));
682   gst_tracing_register_hook (tracer, "pad-push-post",
683       G_CALLBACK (do_push_buffer_post));
684   gst_tracing_register_hook (tracer, "pad-push-list-pre",
685       G_CALLBACK (do_push_buffer_list_pre));
686   gst_tracing_register_hook (tracer, "pad-push-list-post",
687       G_CALLBACK (do_push_buffer_list_post));
688   gst_tracing_register_hook (tracer, "pad-pull-range-pre",
689       G_CALLBACK (do_pull_range_pre));
690   gst_tracing_register_hook (tracer, "pad-pull-range-post",
691       G_CALLBACK (do_pull_range_post));
692   gst_tracing_register_hook (tracer, "pad-push-event-pre",
693       G_CALLBACK (do_push_event_pre));
694   gst_tracing_register_hook (tracer, "element-new",
695       G_CALLBACK (do_element_new));
696   gst_tracing_register_hook (tracer, "element-post-message-pre",
697       G_CALLBACK (do_post_message_pre));
698   gst_tracing_register_hook (tracer, "element-query-pre",
699       G_CALLBACK (do_element_query_pre));
700   gst_tracing_register_hook (tracer, "pad-query-pre",
701       G_CALLBACK (do_query_pre));
702   gst_tracing_register_hook (tracer, "pad-query-post",
703       G_CALLBACK (do_query_post));
704 }