tracer: initial prototype for the tracing subsystem

This commit is contained in:
Stefan Sauer 2013-10-24 14:47:48 +02:00
parent 456ef2aa1d
commit 4e5d586c7d
19 changed files with 951 additions and 35 deletions

View file

@ -990,6 +990,7 @@ libs/gst/helpers/Makefile
libs/gst/net/Makefile libs/gst/net/Makefile
plugins/Makefile plugins/Makefile
plugins/elements/Makefile plugins/elements/Makefile
plugins/tracers/Makefile
po/Makefile.in po/Makefile.in
tests/Makefile tests/Makefile
tests/benchmarks/Makefile tests/benchmarks/Makefile

View 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 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. 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 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 variable, such as GST_TRACE="meminfo,dbus". One can also pass parameters to
add them to certain hooks. Another env var GST_TRACE_CHANNEL can be used to send plugins: GST_TRACE="log(events;buffers),stats(all)".
the tracing to a file or a socket (Do the same for GST_DEBUG_CHANNEL). The syntax When then plugins are loaded, we'll add them to certain hooks according to that
could be GST_XXX_CHANNEL=file:///path/to/file or GST_XXX_CHANNEL=tcp://<ip>:<port>. 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. 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 TODO(ensonic): we might want to have GST_{DEBUG|TRACE)_FORMAT envars as well.
could be raw, ansi-color, binary, ... These could be raw, ansi-color, binary, suitable for babeltrace (see lttng), ...
Hooks With these we can deprecate GST_DEBUG_FILE and GST_DEBUG_NO_COLOR.
-----
e.g. gst_pad_push() will do add this line:
GST_TRACER_PUSH_BUFFER (pad, buffer)
If tracing is disable at compile time the macro will evaluate to nothing. Otherwise Hook api
it will become something along the lines of: --------
if (__tracer && __tracer_hook_is_used) { e.g. gst_pad_push() would become:
gst_tracer_push_buffer (pad, buffer);
#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 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://lwn.net/Articles/412072/ + http://lwn.net/Articles/435215/
- http://lxr.free-electrons.com/source/kernel/jump_label.c - 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 :/ - it is linux specific :/
In addition to api hooks we should also provide timer hooks. Interval timers are 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 Hooks
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 gst_bin_add
consume (=read) the provided data. Most trace plugins will log data to a trace gst_bin_remove
channel. 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 meminfo
------- -------
@ -68,17 +130,19 @@ dbus
---- ----
- provide a dbus iface to announce applications that are traced - 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 - 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 is getting logged to
application is started with tracing activated, the dbus plugin will announce the - one would start the tracing UI first and when the application is started with
new application, upon which the tracing UI can start reading from the log channels 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 topology
-------- --------
- register to pipeline topology hooks - register to pipeline topology hooks
- tracing UIs can show a live pipeline graph - tracing UIs can show a live pipeline graph
communication stats
------------- -----
- register to buffer, event, message and query flow - register to buffer, event, message and query flow
- tracing apps can do e.g. statistics - 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 is loaded) and read the log streams from the sockets/files that are configured for
the app. the app.
gst-trace-stats gst-tracer
--------------- ----------
Such a tool could read a trace and summarize the content like gst-tracelib did for Counterpart of gst-tracelib-ui
stats in 0.10.
Problems / Open items 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 - 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 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

View file

@ -115,6 +115,8 @@ libgstreamer_@GST_API_VERSION@_la_SOURCES = \
gsttoc.c \ gsttoc.c \
gsttocsetter.c \ gsttocsetter.c \
$(GST_TRACE_SRC) \ $(GST_TRACE_SRC) \
gsttracer.c \
gsttracerfactory.c \
gsttypefind.c \ gsttypefind.c \
gsttypefindfactory.c \ gsttypefindfactory.c \
gsturi.c \ gsturi.c \
@ -218,6 +220,8 @@ gst_headers = \
gsttaskpool.h \ gsttaskpool.h \
gsttoc.h \ gsttoc.h \
gsttocsetter.h \ gsttocsetter.h \
gsttracer.h \
gsttracerfactory.h \
gsttypefind.h \ gsttypefind.h \
gsttypefindfactory.h \ gsttypefindfactory.h \
gsturi.h \ gsturi.h \

View file

@ -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_pad_get_type ());
g_type_class_ref (gst_element_factory_get_type ()); g_type_class_ref (gst_element_factory_get_type ());
g_type_class_ref (gst_element_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_type_find_factory_get_type ());
g_type_class_ref (gst_bin_get_type ()); g_type_class_ref (gst_bin_get_type ());
g_type_class_ref (gst_bus_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); GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
GST_INFO ("initialized GStreamer successfully"); GST_INFO ("initialized GStreamer successfully");
#ifndef GST_DISABLE_GST_DEBUG
_priv_gst_tracer_init ();
#endif
return TRUE; return TRUE;
} }
@ -951,6 +956,9 @@ gst_deinit (void)
GST_DEBUG ("already deinitialized"); GST_DEBUG ("already deinitialized");
return; return;
} }
#ifndef GST_DISABLE_GST_DEBUG
_priv_gst_tracer_deinit ();
#endif
g_thread_pool_set_max_unused_threads (0); g_thread_pool_set_max_unused_threads (0);
bin_class = GST_BIN_CLASS (g_type_class_peek (gst_bin_get_type ())); 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_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_factory_get_type ()));
g_type_class_unref (g_type_class_peek (gst_element_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_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_bin_get_type ()));
g_type_class_unref (g_type_class_peek (gst_bus_get_type ())); g_type_class_unref (g_type_class_peek (gst_bus_get_type ()));

View file

@ -77,6 +77,8 @@
#include <gst/gsttaskpool.h> #include <gst/gsttaskpool.h>
#include <gst/gsttoc.h> #include <gst/gsttoc.h>
#include <gst/gsttocsetter.h> #include <gst/gsttocsetter.h>
#include <gst/gsttracer.h>
#include <gst/gsttracerfactory.h>
#include <gst/gsttypefind.h> #include <gst/gsttypefind.h>
#include <gst/gsttypefindfactory.h> #include <gst/gsttypefindfactory.h>
#include <gst/gsturi.h> #include <gst/gsturi.h>

View file

@ -393,6 +393,27 @@ struct _GstTypeFindFactoryClass {
gpointer _gst_reserved[GST_PADDING]; 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 { struct _GstElementFactory {
GstPluginFeature parent; GstPluginFeature parent;

View file

@ -94,6 +94,7 @@
#include "gstutils.h" #include "gstutils.h"
#include "gstinfo.h" #include "gstinfo.h"
#include "gsterror.h" #include "gsterror.h"
#include "gsttracer.h"
#include "gstvalue.h" #include "gstvalue.h"
#include "glib-compat-private.h" #include "glib-compat-private.h"
@ -4442,8 +4443,28 @@ not_linked:
* *
* MT safe. * MT safe.
*/ */
#ifndef GST_DISABLE_GST_DEBUG
static inline GstFlowReturn __gst_pad_push (GstPad * pad, GstBuffer * buffer);
#endif
GstFlowReturn GstFlowReturn
gst_pad_push (GstPad * pad, GstBuffer * buffer) 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_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_PAD_IS_SRC (pad), GST_FLOW_ERROR);

View file

@ -55,7 +55,7 @@ G_BEGIN_DECLS
* This _must_ be updated whenever the registry format changes, * This _must_ be updated whenever the registry format changes,
* we currently use the core version where this change happened. * 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: * GST_MAGIC_BINARY_VERSION_LEN:

View file

@ -31,6 +31,8 @@
#include <gst/gst_private.h> #include <gst/gst_private.h>
#include <gst/gstconfig.h> #include <gst/gstconfig.h>
#include <gst/gstelement.h> #include <gst/gstelement.h>
#include <gst/gsttracer.h>
#include <gst/gsttracerfactory.h>
#include <gst/gsttypefind.h> #include <gst/gsttypefind.h>
#include <gst/gsttypefindfactory.h> #include <gst/gsttypefindfactory.h>
#include <gst/gstdeviceproviderfactory.h> #include <gst/gstdeviceproviderfactory.h>
@ -350,6 +352,13 @@ gst_registry_chunks_save_feature (GList ** list, GstPluginFeature * feature)
/* pack element metadata strings */ /* pack element metadata strings */
gst_registry_chunks_save_string (list, gst_registry_chunks_save_string (list,
gst_structure_to_string (factory->metadata)); 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 { } else {
GST_WARNING_OBJECT (feature, "unhandled feature type '%s'", type_name); 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 GST_DEBUG
("Reading/casting for GstRegistryChunkPluginFeature at address %p", ("Reading/casting for GstRegistryChunkPluginFeature at address %p",
*in); *in);
unpack_element (*in, dmf, GstRegistryChunkDeviceProviderFactory, end, fail); unpack_element (*in, dmf, GstRegistryChunkDeviceProviderFactory, end, fail);
pf = (GstRegistryChunkPluginFeature *) dmf; pf = (GstRegistryChunkPluginFeature *) dmf;
@ -692,6 +702,12 @@ gst_registry_chunks_load_feature (GstRegistry * registry, gchar ** in,
goto fail; 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 { } else {
GST_WARNING ("unhandled factory type : %s", G_OBJECT_TYPE_NAME (feature)); GST_WARNING ("unhandled factory type : %s", G_OBJECT_TYPE_NAME (feature));
goto fail; goto fail;

313
gst/gsttracer.c Normal file
View file

@ -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 */

115
gst/gsttracer.h Normal file
View file

@ -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__ */

76
gst/gsttracerfactory.c Normal file
View file

@ -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);
}

56
gst/gsttracerfactory.h Normal file
View file

@ -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__ */

View file

@ -1,3 +1,4 @@
SUBDIRS = elements SUBDIRS = elements tracers
DIST_SUBDIRS = elements tracers
DIST_SUBDIRS = elements

12
plugins/tracers/.gitignore vendored Normal file
View file

@ -0,0 +1,12 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs
*.bb
*.bbg
*.da
*.def
*.gcno

View file

@ -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@ \
> $@

60
plugins/tracers/gstlog.c Normal file
View file

@ -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);
}

64
plugins/tracers/gstlog.h Normal file
View file

@ -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__ */

View file

@ -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);