tracer: initial prototype for the tracing subsystem
authorStefan Sauer <ensonic@users.sf.net>
Thu, 24 Oct 2013 12:47:48 +0000 (14:47 +0200)
committerStefan Sauer <ensonic@users.sf.net>
Mon, 5 Oct 2015 18:59:39 +0000 (20:59 +0200)
19 files changed:
configure.ac
docs/design/draft-tracing.txt
gst/Makefile.am
gst/gst.c
gst/gst.h
gst/gst_private.h
gst/gstpad.c
gst/gstregistrybinary.h
gst/gstregistrychunks.c
gst/gsttracer.c [new file with mode: 0644]
gst/gsttracer.h [new file with mode: 0644]
gst/gsttracerfactory.c [new file with mode: 0644]
gst/gsttracerfactory.h [new file with mode: 0644]
plugins/Makefile.am
plugins/tracers/.gitignore [new file with mode: 0644]
plugins/tracers/Makefile.am [new file with mode: 0644]
plugins/tracers/gstlog.c [new file with mode: 0644]
plugins/tracers/gstlog.h [new file with mode: 0644]
plugins/tracers/gsttracers.c [new file with mode: 0644]

index 0c6e603..30c6740 100644 (file)
@@ -990,6 +990,7 @@ libs/gst/helpers/Makefile
 libs/gst/net/Makefile
 plugins/Makefile
 plugins/elements/Makefile
+plugins/tracers/Makefile
 po/Makefile.in
 tests/Makefile
 tests/benchmarks/Makefile
index 6867d4f..605ef34 100644 (file)
@@ -11,26 +11,57 @@ per process or none if tracing is off (not enabled via envvar or compiled out).
 Certain GStreamer core function (such as gst_pad_push or gst_element_add_pad) will
 call into the tracer. The tracer will dispatch into loaded tracing plugins.
 Developers will be able to select a list of plugins by setting an environment
-variable, such as GST_TRACE="meminfo,dbus". When then plugins are loaded, they will
-add them to certain hooks. Another env var GST_TRACE_CHANNEL can be used to send
-the tracing to a file or a socket (Do the same for GST_DEBUG_CHANNEL). The syntax
-could be GST_XXX_CHANNEL=file:///path/to/file or GST_XXX_CHANNEL=tcp://<ip>:<port>.
+variable, such as GST_TRACE="meminfo,dbus". One can also pass parameters to
+plugins:  GST_TRACE="log(events;buffers),stats(all)".
+When then plugins are loaded, we'll add them to certain hooks according to that
+they are interested in.
+
+Another env var GST_TRACE_CHANNEL can be used to send the tracing to a file or
+a socket (Do the same for GST_DEBUG_CHANNEL). The syntax could be
+GST_XXX_CHANNEL=file:///path/to/file or GST_XXX_CHANNEL=tcp://<ip>:<port>.
 If no channel is set, the tracing goes to stderr like the debug logging.
 
-TODO(ensonic): we might want to have GST_{DEBUG|TRACE)_FORMAT envars as well. These
-could be raw, ansi-color, binary, ...
+TODO(ensonic): we might want to have GST_{DEBUG|TRACE)_FORMAT envars as well.
+These could be raw, ansi-color, binary, suitable for babeltrace (see lttng), ...
 
-Hooks
------
-e.g. gst_pad_push() will do add this line:
-GST_TRACER_PUSH_BUFFER (pad, buffer)
+With these we can deprecate GST_DEBUG_FILE and GST_DEBUG_NO_COLOR.
+
+Hook api
+--------
+e.g. gst_pad_push() would become:
+
+#ifndef GST_DISABLE_GST_DEBUG
+static inline GstFlowReturn __gst_pad_push (GstPad * pad, GstBuffer * buffer);
+#endif
+
+GstFlowReturn
+gst_pad_push (GstPad * pad, GstBuffer * buffer)
+#ifndef GST_DISABLE_GST_DEBUG
+{
+  if (__tracer_enabled && __tracer_hook_is_used)
+    gst_tracer_push_buffer_pre (pad, buffer);
+  GstFlowReturn res = __gst_pad_push (GstPad * pad, GstBuffer * buffer);
+  if (__tracer_enabled && __tracer_hook_is_used)
+    gst_tracer_push_buffer_post (pad, res);
+  return res;
+}
+
+static inline GstFlowReturn
+__gst_pad_push (GstPad * pad, GstBuffer * buffer)
+#endif
+{
+  g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
+  g_return_val_if_fail (GST_PAD_IS_SRC (pad), GST_FLOW_ERROR);
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
 
-If tracing is disable at compile time the macro will evaluate to nothing. Otherwise
-it will become something along the lines of:
-if (__tracer && __tracer_hook_is_used) {
-  gst_tracer_push_buffer (pad, buffer);
+  return gst_pad_push_data (pad,
+      GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_PUSH, buffer);
 }
 
+TODO(ensonic): gcc has some magic for wrapping functions
+- http://gcc.gnu.org/onlinedocs/gcc/Constructing-Calls.html
+- http://www.clifford.at/cfun/gccfeat/#gccfeat05.c
+
 TODO(ensonic): we should eval if we can use something like jump_label in the kernel
 - http://lwn.net/Articles/412072/ + http://lwn.net/Articles/435215/
 - http://lxr.free-electrons.com/source/kernel/jump_label.c
@@ -41,18 +72,49 @@ TODO(ensonic): liblttng-ust provides such a mechanism for user-space
 - it is linux specific :/
 
 In addition to api hooks we should also provide timer hooks. Interval timers are
-useful to get e.g. resource usage snapshots. Also absolute timers might make sense. 
-
-Plugins can attach handlers to one or more hooks. When a hook such as
-gst_tracer_push_buffer () is called it will take a timestamp and call all attached
-handlers. Hooks will be called from misc threads. The trace plugins should only
-consume (=read) the provided data. Most trace plugins will log data to a trace
-channel.
+useful to get e.g. resource usage snapshots. Also absolute timers might make
+sense. All this could be implemented with a clock thread.
 
-TODO(ensonic): use GSignal for the hooks?
-
-Plugins
-=======
+Hooks
+-----
+  gst_bin_add
+  gst_bin_remove
+  gst_element_add_pad
+  gst_element_post_message
+  gst_element_query
+  gst_element_remove_pad
+  gst_pad_link
+  gst_pad_pull_range
+  gst_pad_push
+  gst_pad_push_list
+  gst_pad_push_event
+  gst_pad_unlink
+
+Plugin api
+----------
+
+TracerPlugins are plugin features. They have a simple api:
+
+GstTracerHookMask init(gchar *params);
+Plugins can attach handlers to one or more hooks. They use a HookMask to tell
+which events they are interested in. The params are the extra detail from the
+environment var.
+
+void invoke(GstStructure *s);
+Hooks marshall the parameters given to a trace hook into a GstStructure and also
+add some extra into such as a timestamp. The hooks will receive this structure.
+Hooks will be called from misc threads. The trace plugins should only consume 
+(=read) the provided data. Most trace plugins will log data to a trace channel.
+
+void done(void);
+Plugins can output results and release data. This would ideally be done at the
+end of the applications, but gst_deinit() is not mandatory. gst_tracelib was
+using a gcc_destructor
+
+Plugins ideas
+=============
+
+We can have some under gstreamer/plugins/tracers/
 
 meminfo
 -------
@@ -68,17 +130,19 @@ dbus
 ----
 - provide a dbus iface to announce applications that are traced
 - tracing UIs can use the dbus iface to find the channels where logging and tracing
-  is getting logged to, one would start the tracing UI first and when the
-  application is started with tracing activated, the dbus plugin will announce the
-  new application, upon which the tracing UI can start reading from the log channels
+  is getting logged to
+- one would start the tracing UI first and when the application is started with
+  tracing activated, the dbus plugin will announce the new application,
+  upon which the tracing UI can start reading from the log channels, this avoid
+  missing some data
 
 topology
 --------
 - register to pipeline topology hooks
 - tracing UIs can show a live pipeline graph
 
-communication
--------------
+stats
+-----
 - register to buffer, event, message and query flow
 - tracing apps can do e.g. statistics
 
@@ -92,14 +156,21 @@ Alternatively it would show a dialog that shows all local apps (if the dbus plug
 is loaded) and read the log streams from the sockets/files that are configured for
 the app.
 
-gst-trace-stats
----------------
-Such a tool could read a trace and summarize the content like gst-tracelib did for
-stats in 0.10.
+gst-tracer
+----------
+Counterpart of gst-tracelib-ui
 
 
 Problems / Open items
 =====================
+- when hooking into a timer, should we just have some predefined intervals?
+- how to trigger the shutdown processing?
 - when connecting to a running app, we cant easily get the 'current' state if logging
 is using a socket, as past events are not stored
 
+
+Try it
+======
+GST_DEBUG="GST_REG*:4,GST_TRACER:4,log:7" GST_TRACE=log gst-launch-1.0 fakesrc num-buffers=10 ! fakesink
+- traces for buffer flow in TRACE level and default category
+
index 213e3fd..f45e413 100644 (file)
@@ -115,6 +115,8 @@ libgstreamer_@GST_API_VERSION@_la_SOURCES = \
        gsttoc.c                \
        gsttocsetter.c          \
        $(GST_TRACE_SRC)        \
+       gsttracer.c             \
+       gsttracerfactory.c      \
        gsttypefind.c           \
        gsttypefindfactory.c    \
        gsturi.c                \
@@ -218,6 +220,8 @@ gst_headers =                       \
        gsttaskpool.h           \
        gsttoc.h                \
        gsttocsetter.h          \
+       gsttracer.h             \
+       gsttracerfactory.h      \
        gsttypefind.h           \
        gsttypefindfactory.h    \
        gsturi.h                \
index e28dd92..7f1404f 100644 (file)
--- a/gst/gst.c
+++ b/gst/gst.c
@@ -587,6 +587,7 @@ init_post (GOptionContext * context, GOptionGroup * group, gpointer data,
   g_type_class_ref (gst_pad_get_type ());
   g_type_class_ref (gst_element_factory_get_type ());
   g_type_class_ref (gst_element_get_type ());
+  g_type_class_ref (gst_tracer_factory_get_type ());
   g_type_class_ref (gst_type_find_factory_get_type ());
   g_type_class_ref (gst_bin_get_type ());
   g_type_class_ref (gst_bus_get_type ());
@@ -718,6 +719,10 @@ init_post (GOptionContext * context, GOptionGroup * group, gpointer data,
       GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
   GST_INFO ("initialized GStreamer successfully");
 
+#ifndef GST_DISABLE_GST_DEBUG
+  _priv_gst_tracer_init ();
+#endif
+
   return TRUE;
 }
 
@@ -951,6 +956,9 @@ gst_deinit (void)
     GST_DEBUG ("already deinitialized");
     return;
   }
+#ifndef GST_DISABLE_GST_DEBUG
+  _priv_gst_tracer_deinit ();
+#endif
 
   g_thread_pool_set_max_unused_threads (0);
   bin_class = GST_BIN_CLASS (g_type_class_peek (gst_bin_get_type ()));
@@ -984,6 +992,7 @@ gst_deinit (void)
   g_type_class_unref (g_type_class_peek (gst_pad_get_type ()));
   g_type_class_unref (g_type_class_peek (gst_element_factory_get_type ()));
   g_type_class_unref (g_type_class_peek (gst_element_get_type ()));
+  g_type_class_unref (g_type_class_peek (gst_tracer_factory_get_type ()));
   g_type_class_unref (g_type_class_peek (gst_type_find_factory_get_type ()));
   g_type_class_unref (g_type_class_peek (gst_bin_get_type ()));
   g_type_class_unref (g_type_class_peek (gst_bus_get_type ()));
index 8ebd76c..c9ffed5 100644 (file)
--- a/gst/gst.h
+++ b/gst/gst.h
@@ -77,6 +77,8 @@
 #include <gst/gsttaskpool.h>
 #include <gst/gsttoc.h>
 #include <gst/gsttocsetter.h>
+#include <gst/gsttracer.h>
+#include <gst/gsttracerfactory.h>
 #include <gst/gsttypefind.h>
 #include <gst/gsttypefindfactory.h>
 #include <gst/gsturi.h>
index 6de9013..39e2245 100644 (file)
@@ -393,6 +393,27 @@ struct _GstTypeFindFactoryClass {
   gpointer _gst_reserved[GST_PADDING];
 };
 
+struct _GstTracerFactory {
+  GstPluginFeature              feature;
+  /* <private> */
+
+  GType                         type;
+
+  /*
+  gpointer                      user_data;
+  GDestroyNotify                user_data_notify;
+  */
+
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+struct _GstTracerFactoryClass {
+  GstPluginFeatureClass         parent;
+  /* <private> */
+
+  gpointer _gst_reserved[GST_PADDING];
+};
+
 struct _GstElementFactory {
   GstPluginFeature      parent;
 
index 86ef566..e1a68fd 100644 (file)
@@ -94,6 +94,7 @@
 #include "gstutils.h"
 #include "gstinfo.h"
 #include "gsterror.h"
+#include "gsttracer.h"
 #include "gstvalue.h"
 #include "glib-compat-private.h"
 
@@ -4442,8 +4443,28 @@ not_linked:
  *
  * MT safe.
  */
+#ifndef GST_DISABLE_GST_DEBUG
+static inline GstFlowReturn __gst_pad_push (GstPad * pad, GstBuffer * buffer);
+#endif
+
 GstFlowReturn
 gst_pad_push (GstPad * pad, GstBuffer * buffer)
+#ifndef GST_DISABLE_GST_DEBUG
+{
+  const gboolean trace = gst_tracer_is_enabled (GST_TRACER_HOOK_ID_BUFFERS);
+  GstFlowReturn res;
+
+  if (trace)
+    gst_tracer_push_buffer_pre (pad, buffer);
+  res = __gst_pad_push (pad, buffer);
+  if (trace)
+    gst_tracer_push_buffer_post (pad, res);
+  return res;
+}
+
+static inline GstFlowReturn
+__gst_pad_push (GstPad * pad, GstBuffer * buffer)
+#endif
 {
   g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
   g_return_val_if_fail (GST_PAD_IS_SRC (pad), GST_FLOW_ERROR);
index f1102c7..22e56d1 100644 (file)
@@ -55,7 +55,7 @@ G_BEGIN_DECLS
  * This _must_ be updated whenever the registry format changes,
  * we currently use the core version where this change happened.
  */
-#define GST_MAGIC_BINARY_VERSION_STR "1.0.0"
+#define GST_MAGIC_BINARY_VERSION_STR "1.3.0"
 
 /*
  * GST_MAGIC_BINARY_VERSION_LEN:
index f854865..c88152d 100644 (file)
@@ -31,6 +31,8 @@
 #include <gst/gst_private.h>
 #include <gst/gstconfig.h>
 #include <gst/gstelement.h>
+#include <gst/gsttracer.h>
+#include <gst/gsttracerfactory.h>
 #include <gst/gsttypefind.h>
 #include <gst/gsttypefindfactory.h>
 #include <gst/gstdeviceproviderfactory.h>
@@ -350,6 +352,13 @@ gst_registry_chunks_save_feature (GList ** list, GstPluginFeature * feature)
     /* pack element metadata strings */
     gst_registry_chunks_save_string (list,
         gst_structure_to_string (factory->metadata));
+  } else if (GST_IS_TRACER_FACTORY (feature)) {
+    /* Initialize with zeroes because of struct padding and
+     * valgrind complaining about copying unitialized memory
+     */
+    pf = g_slice_new0 (GstRegistryChunkPluginFeature);
+    pf_size = sizeof (GstRegistryChunkPluginFeature);
+    chk = gst_registry_chunks_make_data (pf, pf_size);
   } else {
     GST_WARNING_OBJECT (feature, "unhandled feature type '%s'", type_name);
   }
@@ -677,6 +686,7 @@ gst_registry_chunks_load_feature (GstRegistry * registry, gchar ** in,
     GST_DEBUG
         ("Reading/casting for GstRegistryChunkPluginFeature at address %p",
         *in);
+
     unpack_element (*in, dmf, GstRegistryChunkDeviceProviderFactory, end, fail);
 
     pf = (GstRegistryChunkPluginFeature *) dmf;
@@ -692,6 +702,12 @@ gst_registry_chunks_load_feature (GstRegistry * registry, gchar ** in,
         goto fail;
       }
     }
+  } else if (GST_IS_TRACER_FACTORY (feature)) {
+    align (*in);
+    GST_DEBUG
+        ("Reading/casting for GstRegistryChunkPluginFeature at address %p",
+        *in);
+    unpack_element (*in, pf, GstRegistryChunkPluginFeature, end, fail);
   } else {
     GST_WARNING ("unhandled factory type : %s", G_OBJECT_TYPE_NAME (feature));
     goto fail;
diff --git a/gst/gsttracer.c b/gst/gsttracer.c
new file mode 100644 (file)
index 0000000..45bedcc
--- /dev/null
@@ -0,0 +1,313 @@
+/* GStreamer
+ * Copyright (C) 2013 Stefan Sauer <ensonic@users.sf.net>
+ *
+ * gsttracer.h: tracing subsystem
+ *
+ * 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.
+ */
+
+#include "gst_private.h"
+#include "gstenumtypes.h"
+#include "gstregistry.h"
+#include "gsttracer.h"
+#include "gsttracerfactory.h"
+#include "gstutils.h"
+
+#ifndef GST_DISABLE_GST_DEBUG
+
+GST_DEBUG_CATEGORY_EXTERN (tracer_debug);
+#define GST_CAT_DEFAULT tracer_debug
+
+/* tracing plugins base class */
+
+enum
+{
+  PROP_0,
+  PROP_PARAMS,
+  PROP_MASK,
+  PROP_LAST
+};
+
+static GParamSpec *properties[PROP_LAST];
+
+static void gst_tracer_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_tracer_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+struct _GstTracerPrivate
+{
+  const gchar *params;
+  GstTracerHook mask;
+};
+
+#define gst_tracer_parent_class parent_class
+G_DEFINE_ABSTRACT_TYPE (GstTracer, gst_tracer, GST_TYPE_OBJECT);
+
+static void
+gst_tracer_class_init (GstTracerClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = gst_tracer_set_property;
+  gobject_class->get_property = gst_tracer_get_property;
+
+  properties[PROP_PARAMS] =
+      g_param_spec_string ("params", "Params", "Extra configuration parameters",
+      NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_MASK] =
+      g_param_spec_flags ("mask", "Mask", "Event mask", GST_TYPE_TRACER_HOOK,
+      GST_TRACER_HOOK_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (gobject_class, PROP_LAST, properties);
+  g_type_class_add_private (klass, sizeof (GstTracerPrivate));
+}
+
+static void
+gst_tracer_init (GstTracer * tracer)
+{
+  tracer->priv = G_TYPE_INSTANCE_GET_PRIVATE (tracer, GST_TYPE_TRACER,
+      GstTracerPrivate);
+}
+
+static void
+gst_tracer_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstTracer *self = GST_TRACER_CAST (object);
+
+  switch (prop_id) {
+    case PROP_PARAMS:
+      self->priv->params = g_value_get_string (value);
+      break;
+    case PROP_MASK:
+      self->priv->mask = g_value_get_flags (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_tracer_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstTracer *self = GST_TRACER_CAST (object);
+
+  switch (prop_id) {
+    case PROP_PARAMS:
+      g_value_set_string (value, self->priv->params);
+      break;
+    case PROP_MASK:
+      g_value_set_flags (value, self->priv->mask);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_tracer_invoke (GstTracer * self, GstStructure * s)
+{
+  GstTracerClass *klass = GST_TRACER_GET_CLASS (self);
+
+  g_return_if_fail (klass->invoke);
+
+  klass->invoke (s);
+}
+
+/* tracing modules */
+
+gboolean
+gst_tracer_register (GstPlugin * plugin, const gchar * name, GType type)
+{
+  GstPluginFeature *existing_feature;
+  GstRegistry *registry;
+  GstTracerFactory *factory;
+
+  g_return_val_if_fail (name != NULL, FALSE);
+  g_return_val_if_fail (g_type_is_a (type, GST_TYPE_TRACER), FALSE);
+
+  registry = gst_registry_get ();
+  /* check if feature already exists, if it exists there is no need to update it
+   * when the registry is getting updated, outdated plugins and all their
+   * features are removed and readded.
+   */
+  existing_feature = gst_registry_lookup_feature (registry, name);
+  if (existing_feature) {
+    GST_DEBUG_OBJECT (registry, "update existing feature %p (%s)",
+        existing_feature, name);
+    factory = GST_TRACER_FACTORY_CAST (existing_feature);
+    factory->type = type;
+    existing_feature->loaded = TRUE;
+    //g_type_set_qdata (type, __gst_elementclass_factory, factory);
+    gst_object_unref (existing_feature);
+    return TRUE;
+  }
+
+  factory = g_object_newv (GST_TYPE_TRACER_FACTORY, 0, NULL);
+  GST_DEBUG_OBJECT (factory, "new tracer factory for %s", name);
+
+  gst_plugin_feature_set_name (GST_PLUGIN_FEATURE_CAST (factory), name);
+  gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE_CAST (factory),
+      GST_RANK_NONE);
+
+  factory->type = type;
+  GST_DEBUG_OBJECT (factory, "tracer factory for %u:%s",
+      (guint) type, g_type_name (type));
+
+  if (plugin && plugin->desc.name) {
+    GST_PLUGIN_FEATURE_CAST (factory)->plugin_name = plugin->desc.name; /* interned string */
+    GST_PLUGIN_FEATURE_CAST (factory)->plugin = plugin;
+    g_object_add_weak_pointer ((GObject *) plugin,
+        (gpointer *) & GST_PLUGIN_FEATURE_CAST (factory)->plugin);
+  } else {
+    GST_PLUGIN_FEATURE_CAST (factory)->plugin_name = "NULL";
+    GST_PLUGIN_FEATURE_CAST (factory)->plugin = NULL;
+  }
+  GST_PLUGIN_FEATURE_CAST (factory)->loaded = TRUE;
+
+  gst_registry_add_feature (gst_registry_get (),
+      GST_PLUGIN_FEATURE_CAST (factory));
+
+  return TRUE;
+}
+
+/* tracing helpers */
+
+static gboolean tracer_enabled = FALSE;
+
+static GList *tracers[GST_TRACER_HOOK_ID_LAST] = { NULL, };
+
+/* Initialize the debugging system */
+void
+_priv_gst_tracer_init (void)
+{
+  const gchar *env = g_getenv ("GST_TRACE");
+
+  if (env != NULL && *env != '\0') {
+    GstRegistry *registry = gst_registry_get ();
+    GstPluginFeature *feature;
+    GstTracerFactory *factory;
+    GstTracerHook mask;
+    GstTracer *tracer;
+    gchar **t = g_strsplit_set (env, ",", 0);
+    gint i = 0, j;
+    gchar *params;
+
+    GST_INFO ("enabling tracers: '%s'", env);
+
+    while (t[i]) {
+      // TODO(ensonic): check t[i] for params
+      params = NULL;
+
+      GST_INFO ("checking tracer: '%s'", t[i]);
+
+      if ((feature = gst_registry_lookup_feature (registry, t[i]))) {
+        factory = GST_TRACER_FACTORY (gst_plugin_feature_load (feature));
+        if (factory) {
+          GST_INFO_OBJECT (factory, "creating tracer: type-id=%u",
+              (guint) factory->type);
+
+          tracer = g_object_new (factory->type, "params", params, NULL);
+          g_object_get (tracer, "mask", &mask, NULL);
+
+          if (mask) {
+            /* add to lists according to mask */
+            j = 0;
+            while (mask && (j < GST_TRACER_HOOK_ID_LAST)) {
+              if (mask & 1) {
+                tracers[j] = g_list_prepend (tracers[j],
+                    gst_object_ref (tracer));
+                GST_WARNING_OBJECT (tracer, "added tracer to hook %d", j);
+              }
+              mask >>= 1;
+              j++;
+            }
+
+            tracer_enabled = TRUE;
+          } else {
+            GST_WARNING_OBJECT (tracer,
+                "tracer with zero mask won't have any effect");
+          }
+          gst_object_unref (tracer);
+        } else {
+          GST_WARNING_OBJECT (feature,
+              "loading plugin containing feature %s failed!", t[i]);
+        }
+      } else {
+        GST_WARNING ("no tracer named '%s'", t[i]);
+      }
+      i++;
+    }
+    g_strfreev (t);
+  }
+}
+
+void
+_priv_gst_tracer_deinit (void)
+{
+  gint i;
+  GList *node;
+
+  /* shutdown tracers for final reports */
+  for (i = 0; i < GST_TRACER_HOOK_ID_LAST; i++) {
+    for (node = tracers[i]; node; node = g_list_next (node)) {
+      gst_object_unref (node->data);
+    }
+    g_list_free (tracers[i]);
+    tracers[i] = NULL;
+  }
+}
+
+gboolean
+gst_tracer_is_enabled (GstTracerHookId id)
+{
+  return tracer_enabled && (tracers[id] != NULL);
+}
+
+static void
+dispatch (GstTracerHookId id, GstStructure * s)
+{
+  GList *node;
+  for (node = tracers[id]; node; node = g_list_next (node)) {
+    gst_tracer_invoke (node->data, s);
+  }
+}
+
+/* tracing hooks */
+void
+gst_tracer_push_buffer_pre (GstPad * pad, GstBuffer * buffer)
+{
+  // TODO(ensonic): gst_structure_new_id
+  dispatch (GST_TRACER_HOOK_ID_BUFFERS, gst_structure_new ("push_buffer::pre",
+          ".ts", G_TYPE_UINT64, gst_util_get_timestamp (),
+          "pad", GST_TYPE_PAD, pad, "buffer", GST_TYPE_BUFFER, buffer, NULL));
+}
+
+void
+gst_tracer_push_buffer_post (GstPad * pad, GstFlowReturn res)
+{
+  // TODO(ensonic): gst_structure_new_id
+  dispatch (GST_TRACER_HOOK_ID_BUFFERS, gst_structure_new ("push_buffer::post",
+          ".ts", G_TYPE_UINT64, gst_util_get_timestamp (),
+          "pad", GST_TYPE_PAD, pad, "return", G_TYPE_INT, res, NULL));
+}
+
+#endif /* GST_DISABLE_GST_DEBUG */
diff --git a/gst/gsttracer.h b/gst/gsttracer.h
new file mode 100644 (file)
index 0000000..f99e326
--- /dev/null
@@ -0,0 +1,115 @@
+/* GStreamer
+ * Copyright (C) 2013 Stefan Sauer <ensonic@users.sf.net>
+ *
+ * gsttracer.h: tracing subsystem
+ *
+ * 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.
+ */
+
+#ifndef __GST_TRACER_H__
+#define __GST_TRACER_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gst/gstconfig.h>
+#include <gst/gstbin.h>
+
+G_BEGIN_DECLS
+
+#ifndef GST_DISABLE_GST_DEBUG
+
+/* hook flags and ids */
+
+typedef enum
+{
+  GST_TRACER_HOOK_NONE      = 0,
+  GST_TRACER_HOOK_BUFFERS   = (1 << 0),
+  GST_TRACER_HOOK_EVENTS    = (1 << 1),
+  GST_TRACER_HOOK_MESSAGES  = (1 << 2),
+  GST_TRACER_HOOK_QUERIES   = (1 << 3),
+  GST_TRACER_HOOK_TOPOLOGY  = (1 << 4),
+  /*
+  GST_TRACER_HOOK_TIMER
+  */
+  GST_TRACER_HOOK_ALL       = (1 << 5) - 1
+} GstTracerHook;
+
+typedef enum
+{
+  GST_TRACER_HOOK_ID_BUFFERS = 0,
+  GST_TRACER_HOOK_ID_EVENTS,
+  GST_TRACER_HOOK_ID_MESSAGES,
+  GST_TRACER_HOOK_ID_QUERIES,
+  GST_TRACER_HOOK_ID_TOPLOGY,
+  /*
+  GST_TRACER_HOOK_ID_TIMER
+  */
+  GST_TRACER_HOOK_ID_LAST
+} GstTracerHookId;
+
+/* tracing plugins */
+
+typedef struct _GstTracer GstTracer;
+typedef struct _GstTracerPrivate GstTracerPrivate;
+typedef struct _GstTracerClass GstTracerClass;
+
+#define GST_TYPE_TRACER            (gst_tracer_get_type())
+#define GST_TRACER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TRACER,GstTracer))
+#define GST_TRACER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TRACER,GstTracerClass))
+#define GST_IS_TRACER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TRACER))
+#define GST_IS_TRACER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TRACER))
+#define GST_TRACER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_TRACER,GstTracerClass))
+#define GST_TRACER_CAST(obj)       ((GstTracer *)(obj))
+
+struct _GstTracer {
+  GstObject        parent;
+  /*< private >*/
+  GstTracerPrivate *priv;
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+typedef void                 (*GstTracerInvokeFunction) (GstStructure *s);
+
+struct _GstTracerClass {
+  GstObjectClass parent_class;
+  
+  /* plugin vmethods */
+  GstTracerInvokeFunction invoke;
+  
+  /*< private >*/
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+GType gst_tracer_get_type          (void);
+
+/* tracing hooks */
+
+void _priv_gst_tracer_init (void);
+void _priv_gst_tracer_deinit (void);
+
+gboolean gst_tracer_register (GstPlugin * plugin, const gchar * name, GType type);
+
+gboolean gst_tracer_is_enabled (GstTracerHookId id);
+void gst_tracer_push_buffer_pre (GstPad *pad, GstBuffer *buffer);
+void gst_tracer_push_buffer_post (GstPad *pad, GstFlowReturn res);
+
+
+#endif /* GST_DISABLE_GST_DEBUG */
+
+G_END_DECLS
+
+#endif /* __GST_TRACER_H__ */
+
diff --git a/gst/gsttracerfactory.c b/gst/gsttracerfactory.c
new file mode 100644 (file)
index 0000000..77d4925
--- /dev/null
@@ -0,0 +1,76 @@
+/* GStreamer
+ * Copyright (C) 2013 Stefan Sauer <ensonic@users.sf.net>
+ *
+ * gsttracerfactory.c: tracing subsystem
+ *
+ * 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:gsttracerfactory
+ * @short_description: Information about registered tracer functions
+ *
+ * Last reviewed on 2012-10-24 (1.2.X)
+ */
+
+#include "gst_private.h"
+#include "gstinfo.h"
+#include "gsttracer.h"
+#include "gsttracerfactory.h"
+#include "gstregistry.h"
+
+GST_DEBUG_CATEGORY (tracer_debug);
+#define GST_CAT_DEFAULT tracer_debug
+
+#define _do_init \
+{ \
+  GST_DEBUG_CATEGORY_INIT (tracer_debug, "GST_TRACER", \
+      GST_DEBUG_FG_BLUE, "tracing subsystem"); \
+}
+
+#define gst_tracer_factory_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstTracerFactory, gst_tracer_factory,
+    GST_TYPE_PLUGIN_FEATURE, _do_init);
+
+static void
+gst_tracer_factory_class_init (GstTracerFactoryClass * klass)
+{
+}
+
+static void
+gst_tracer_factory_init (GstTracerFactory * factory)
+{
+}
+
+/**
+ * gst_tracer_factory_get_list:
+ *
+ * Gets the list of all registered tracer factories. You must free the
+ * list using gst_plugin_feature_list_free().
+ *
+ * The returned factories are sorted by factory name.
+ *
+ * Free-function: gst_plugin_feature_list_free
+ *
+ * Returns: (transfer full) (element-type Gst.TracerFactory): the list of all
+ *     registered #GstTracerFactory.
+ */
+GList *
+gst_tracer_factory_get_list (void)
+{
+  return gst_registry_get_feature_list (gst_registry_get (),
+      GST_TYPE_TRACER_FACTORY);
+}
diff --git a/gst/gsttracerfactory.h b/gst/gsttracerfactory.h
new file mode 100644 (file)
index 0000000..2bfe481
--- /dev/null
@@ -0,0 +1,56 @@
+/* GStreamer
+ * Copyright (C) 2013 Stefan Sauer <ensonic@users.sf.net>
+ *
+ * gsttracerfactory.h: tracing subsystem
+ *
+ * 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.
+ */
+
+#ifndef __GST_TRACER_FACTORY_H__
+#define __GST_TRACER_FACTORY_H__
+
+#include <gst/gstcaps.h>
+#include <gst/gstplugin.h>
+#include <gst/gstpluginfeature.h>
+#include <gst/gsttracer.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_TRACER_FACTORY                 (gst_tracer_factory_get_type())
+#define GST_TRACER_FACTORY(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TRACER_FACTORY, GstTracerFactory))
+#define GST_IS_TRACER_FACTORY(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TRACER_FACTORY))
+#define GST_TRACER_FACTORY_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TRACER_FACTORY, GstTracerFactoryClass))
+#define GST_IS_TRACER_FACTORY_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TRACER_FACTORY))
+#define GST_TRACER_FACTORY_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TRACER_FACTORY, GstTracerFactoryClass))
+#define GST_TRACER_FACTORY_CAST(obj)            ((GstTracerFactory *)(obj))
+
+/**
+ * GstTracerFactory:
+ *
+ * Opaque object that stores information about a tracer function.
+ */
+typedef struct _GstTracerFactory GstTracerFactory;
+typedef struct _GstTracerFactoryClass GstTracerFactoryClass;
+
+/* tracering interface */
+
+GType           gst_tracer_factory_get_type          (void);
+GList *         gst_tracer_factory_get_list          (void);
+
+
+G_END_DECLS
+
+#endif /* __GST_TRACER_FACTORY_H__ */
index 4e46e71..cee04aa 100644 (file)
@@ -1,3 +1,4 @@
-SUBDIRS = elements
+SUBDIRS = elements tracers
+
+DIST_SUBDIRS = elements tracers
 
-DIST_SUBDIRS = elements
diff --git a/plugins/tracers/.gitignore b/plugins/tracers/.gitignore
new file mode 100644 (file)
index 0000000..dc1483e
--- /dev/null
@@ -0,0 +1,12 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
+*.bb
+*.bbg
+*.da
+*.def
+*.gcno
diff --git a/plugins/tracers/Makefile.am b/plugins/tracers/Makefile.am
new file mode 100644 (file)
index 0000000..ede77f6
--- /dev/null
@@ -0,0 +1,35 @@
+
+plugin_LTLIBRARIES = libgstcoretracers.la
+
+libgstcoretracers_la_DEPENDENCIES = $(top_builddir)/gst/libgstreamer-@GST_API_VERSION@.la
+libgstcoretracers_la_SOURCES = \
+  gstlog.c \
+       gsttracers.c
+
+libgstcoretracers_la_CFLAGS = $(GST_OBJ_CFLAGS)
+libgstcoretracers_la_LIBADD = \
+       $(top_builddir)/libs/gst/base/libgstbase-@GST_API_VERSION@.la \
+       $(GST_OBJ_LIBS)
+libgstcoretracers_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstcoretracers_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+
+noinst_HEADERS = \
+  gstlog.h
+
+CLEANFILES = *.gcno *.gcda *.gcov *.gcov.out
+
+%.c.gcov: .libs/libgstcoretracers_la-%.gcda %.c
+       $(GCOV) -b -f -o $^ > $@.out
+
+gcov: $(libgstcoretracers_la_SOURCES:=.gcov)
+
+Android.mk: Makefile.am
+       androgenizer -:PROJECT gstreamer -:SHARED libgstcoretracers -:TAGS eng debug \
+        -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+        -:SOURCES $(libgstcoretracers_la_SOURCES) \
+        -:CFLAGS $(DEFS) $(libgstcoretracers_la_CFLAGS) \
+        -:LDFLAGS $(libgstcoretracers_la_LDFLAGS) \
+                   $(libgstcoretracers_la_LIBADD) \
+        -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+                      LOCAL_MODULE_PATH:=$$\(TARGET_OUT\)/lib/gstreamer-@GST_API_VERSION@ \
+       > $@
diff --git a/plugins/tracers/gstlog.c b/plugins/tracers/gstlog.c
new file mode 100644 (file)
index 0000000..a4c7c0c
--- /dev/null
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) 2013 Stefan Sauer <ensonic@users.sf.net>
+ *
+ * gstlog.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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "gstlog.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_log_debug);
+#define GST_CAT_DEFAULT gst_log_debug
+
+#define _do_init \
+    GST_DEBUG_CATEGORY_INIT (gst_log_debug, "log", 0, "log tracer");
+#define gst_log_tracer_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstLogTracer, gst_log_tracer, GST_TYPE_TRACER,
+    _do_init);
+
+static void gst_log_tracer_invoke (GstStructure * s);
+
+static void
+gst_log_tracer_class_init (GstLogTracerClass * klass)
+{
+  GstTracerClass *gst_tracer_class = GST_TRACER_CLASS (klass);
+
+  gst_tracer_class->invoke = gst_log_tracer_invoke;
+}
+
+static void
+gst_log_tracer_init (GstLogTracer * self)
+{
+  g_object_set (self, "mask", GST_TRACER_HOOK_ALL, NULL);
+}
+
+static void
+gst_log_tracer_invoke (GstStructure * s)
+{
+  gchar *str = gst_structure_to_string (s);
+  /* TODO(ensonic): log to different categories depending on GstHookId */
+  GST_TRACE ("%s", str);
+  g_free (str);
+}
diff --git a/plugins/tracers/gstlog.h b/plugins/tracers/gstlog.h
new file mode 100644 (file)
index 0000000..e95857b
--- /dev/null
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) 2013 Stefan Sauer <ensonic@users.sf.net>
+ *
+ * gstlog.h: 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.
+ */
+
+#ifndef __GST_LOG_TRACER_H__
+#define __GST_LOG_TRACER_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_LOG_TRACER \
+  (gst_log_tracer_get_type())
+#define GST_LOG_TRACER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_LOG_TRACER,GstLogTracer))
+#define GST_LOG_TRACER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_LOG_TRACER,GstLogTracerClass))
+#define GST_IS_LOG_TRACER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_LOG_TRACER))
+#define GST_IS_LOG_TRACER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_LOG_TRACER))
+
+typedef struct _GstLogTracer GstLogTracer;
+typedef struct _GstLogTracerClass GstLogTracerClass;
+
+/**
+ * GstLogTracer:
+ *
+ * Opaque #GstLogTracer data structure
+ */
+struct _GstLogTracer {
+  GstTracer     parent;
+
+  /*< private >*/
+};
+
+struct _GstLogTracerClass {
+  GstTracerClass parent_class;
+
+  /* signals */
+};
+
+G_GNUC_INTERNAL GType gst_log_tracer_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_LOG_TRACER_H__ */
diff --git a/plugins/tracers/gsttracers.c b/plugins/tracers/gsttracers.c
new file mode 100644 (file)
index 0000000..1a0ed9d
--- /dev/null
@@ -0,0 +1,39 @@
+/* GStreamer
+ * Copyright (C) 2013 Stefan Sauer <ensonic@users.sf.net>
+ *
+ * gsttracers.c: tracing modules
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include "gstlog.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  if (!gst_tracer_register (plugin, "log", gst_log_tracer_get_type ()))
+    return FALSE;
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, coretracers,
+    "GStreamer core tracers", plugin_init, VERSION, GST_LICENSE,
+    GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);