diff --git a/configure.ac b/configure.ac index 0c6e603919..30c6740568 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/docs/design/draft-tracing.txt b/docs/design/draft-tracing.txt index 6867d4fa9a..605ef346a3 100644 --- a/docs/design/draft-tracing.txt +++ b/docs/design/draft-tracing.txt @@ -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://:. +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://:. 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. -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); +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); + + 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. +useful to get e.g. resource usage snapshots. Also absolute timers might make +sense. All this could be implemented with a clock thread. -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. +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 -TODO(ensonic): use GSignal for the hooks? +Plugin api +---------- -Plugins -======= +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 + diff --git a/gst/Makefile.am b/gst/Makefile.am index 213e3fda59..f45e413b03 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -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 \ diff --git a/gst/gst.c b/gst/gst.c index e28dd92d01..7f1404fae7 100644 --- 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 ())); diff --git a/gst/gst.h b/gst/gst.h index 8ebd76ce60..c9ffed55b8 100644 --- a/gst/gst.h +++ b/gst/gst.h @@ -77,6 +77,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/gst/gst_private.h b/gst/gst_private.h index 6de9013ec7..39e2245875 100644 --- a/gst/gst_private.h +++ b/gst/gst_private.h @@ -393,6 +393,27 @@ struct _GstTypeFindFactoryClass { gpointer _gst_reserved[GST_PADDING]; }; +struct _GstTracerFactory { + GstPluginFeature feature; + /* */ + + GType type; + + /* + gpointer user_data; + GDestroyNotify user_data_notify; + */ + + gpointer _gst_reserved[GST_PADDING]; +}; + +struct _GstTracerFactoryClass { + GstPluginFeatureClass parent; + /* */ + + gpointer _gst_reserved[GST_PADDING]; +}; + struct _GstElementFactory { GstPluginFeature parent; diff --git a/gst/gstpad.c b/gst/gstpad.c index 86ef566d80..e1a68fd51d 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -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); diff --git a/gst/gstregistrybinary.h b/gst/gstregistrybinary.h index f1102c7591..22e56d1961 100644 --- a/gst/gstregistrybinary.h +++ b/gst/gstregistrybinary.h @@ -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: diff --git a/gst/gstregistrychunks.c b/gst/gstregistrychunks.c index f8548654c7..c88152d12a 100644 --- a/gst/gstregistrychunks.c +++ b/gst/gstregistrychunks.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include #include @@ -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 index 0000000000..45bedcc2c6 --- /dev/null +++ b/gst/gsttracer.c @@ -0,0 +1,313 @@ +/* GStreamer + * Copyright (C) 2013 Stefan Sauer + * + * 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 index 0000000000..f99e326066 --- /dev/null +++ b/gst/gsttracer.h @@ -0,0 +1,115 @@ +/* GStreamer + * Copyright (C) 2013 Stefan Sauer + * + * 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 +#include +#include +#include + +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 index 0000000000..77d4925234 --- /dev/null +++ b/gst/gsttracerfactory.c @@ -0,0 +1,76 @@ +/* GStreamer + * Copyright (C) 2013 Stefan Sauer + * + * 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 index 0000000000..2bfe481b16 --- /dev/null +++ b/gst/gsttracerfactory.h @@ -0,0 +1,56 @@ +/* GStreamer + * Copyright (C) 2013 Stefan Sauer + * + * 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 +#include +#include +#include + +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__ */ diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 4e46e718bd..cee04aa2bc 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -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 index 0000000000..dc1483ec66 --- /dev/null +++ b/plugins/tracers/.gitignore @@ -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 index 0000000000..ede77f6c25 --- /dev/null +++ b/plugins/tracers/Makefile.am @@ -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 index 0000000000..a4c7c0ca37 --- /dev/null +++ b/plugins/tracers/gstlog.c @@ -0,0 +1,60 @@ +/* GStreamer + * Copyright (C) 2013 Stefan Sauer + * + * 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 index 0000000000..e95857b0f7 --- /dev/null +++ b/plugins/tracers/gstlog.h @@ -0,0 +1,64 @@ +/* GStreamer + * Copyright (C) 2013 Stefan Sauer + * + * 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 + +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 index 0000000000..1a0ed9dcbb --- /dev/null +++ b/plugins/tracers/gsttracers.c @@ -0,0 +1,39 @@ +/* GStreamer + * Copyright (C) 2013 Stefan Sauer + * + * 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 +#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);