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
plugins/Makefile
plugins/elements/Makefile
plugins/tracers/Makefile
po/Makefile.in
tests/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
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.
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

View 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 \

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_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 ()));

View file

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

View 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;

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

View 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:

View 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;

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