Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/GStreamer/gstreamer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/plugins/gst_plugins_cache.json1
-rw-r--r--plugins/tracers/gstfactories.c187
-rw-r--r--plugins/tracers/gstfactories.h46
-rw-r--r--plugins/tracers/gsttracers.c4
-rw-r--r--plugins/tracers/meson.build1
-rw-r--r--tools/gst-stats.c151
6 files changed, 390 insertions, 0 deletions
diff --git a/docs/plugins/gst_plugins_cache.json b/docs/plugins/gst_plugins_cache.json
index 66f5bd1f6c..67927f5652 100644
--- a/docs/plugins/gst_plugins_cache.json
+++ b/docs/plugins/gst_plugins_cache.json
@@ -2868,6 +2868,7 @@
"package": "GStreamer",
"source": "gstreamer",
"tracers": {
+ "factories": {},
"latency": {},
"leaks": {},
"log": {},
diff --git a/plugins/tracers/gstfactories.c b/plugins/tracers/gstfactories.c
new file mode 100644
index 0000000000..fbb2505e20
--- /dev/null
+++ b/plugins/tracers/gstfactories.c
@@ -0,0 +1,187 @@
+/* GStreamer
+ * Copyright (C) 2021 Collabora Ltd.
+ * @author: Olivier Crete <olivier.crete@collabora.com>
+ *
+ * gstfactories.c: A trace to log which plugin & factories are being used
+ *
+ * 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:tracer-factories
+ * @short_description: log plugin and factories
+ *
+ * A tracing module that logs which plugins and factories are being used.
+ *
+ * This tracing module is particularly useful in conjuction with the `gst-stats`
+ * program to generate a list of plugins and elements that are loaded by a
+ * particular application to generate a minimal custom build of GStreamer.
+ *
+ * As a very simple example, you can run your application like this:
+ * ```
+ * $ GST_TRACERS=factories GST_DEBUG=GST_TRACER:7 gst-launch-1.0 audiotestsrc num-buffers=10 ! fakesink 2> log.txt
+ * ...
+ * $ gst-stats-1.0 log.txt
+ * Plugins used: audiotestsrc;coreelements
+ * Elements: audiotestsrc:audiotestsrc;coreelements:fakesink
+ * Device-providers:
+ * Typefinds:
+ * Dynamic-types:
+ * ```
+ *
+ * Based on this information, one can build a minimal, yet sufficient
+ * build of GStreamer using gst-build with a configuration like this one:
+ * ```
+ * meson setup builddir -Dgst-full-elements="audiotestsrc:audiotestsrc;coreelements:fakesink"
+ * ```
+ *
+ * Since: 1.20
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstfactories.h"
+
+G_DEFINE_TYPE (GstFactoriesTracer, gst_factories_tracer, GST_TYPE_TRACER);
+
+static GstTracerRecord *tr_factory_used;
+
+static void
+do_element_new (GstFactoriesTracer * self, GstClockTime ts,
+ GstElement * element)
+{
+ const gchar *plugin_name;
+ const gchar *factory_name;
+ GstPluginFeature *feature;
+ GstElementFactory *factory = gst_element_get_factory (element);
+ const gchar *source_module_name = "Unknown";
+ GstPlugin *plugin;
+
+ if (factory == NULL)
+ return;
+
+ feature = GST_PLUGIN_FEATURE (factory);
+
+ factory_name = gst_plugin_feature_get_name (feature);
+ plugin_name = gst_plugin_feature_get_plugin_name (feature);
+
+ if (factory_name == NULL)
+ factory_name = "";
+ if (plugin_name == NULL)
+ plugin_name = "";
+
+ plugin = gst_plugin_feature_get_plugin (feature);
+ if (plugin)
+ source_module_name = gst_plugin_get_source (plugin);
+
+ gst_tracer_record_log (tr_factory_used,
+ (guint64) (guintptr) g_thread_self (), ts, "element", factory_name,
+ plugin_name, source_module_name);
+
+ g_clear_object (&plugin);
+}
+
+static void
+do_plugin_feature_loaded (GstFactoriesTracer * self, GstClockTime ts,
+ GstPluginFeature * feature)
+{
+ const gchar *plugin_name;
+ const gchar *factory_name;
+ const gchar *factory_type;
+ const gchar *source_module_name = "Unknown";
+ GstPlugin *plugin;
+
+ /* Only care about elements when one is created */
+ if (GST_IS_ELEMENT_FACTORY (feature))
+ return;
+
+ if (GST_IS_TYPE_FIND_FACTORY (feature))
+ factory_type = "typefind";
+ else if (GST_IS_DEVICE_PROVIDER_FACTORY (feature))
+ factory_type = "device-provider";
+ else if (GST_IS_DYNAMIC_TYPE_FACTORY (feature))
+ factory_type = "dynamic-type";
+ else
+ g_assert_not_reached ();
+
+ factory_name = gst_plugin_feature_get_name (feature);
+ plugin_name = gst_plugin_feature_get_plugin_name (feature);
+
+ if (factory_name == NULL)
+ factory_name = "";
+ if (plugin_name == NULL)
+ plugin_name = "";
+
+ plugin = gst_plugin_feature_get_plugin (feature);
+ if (plugin)
+ source_module_name = gst_plugin_get_source (plugin);
+ if (source_module_name == NULL)
+ source_module_name = "";
+
+ gst_tracer_record_log (tr_factory_used,
+ (guint64) (guintptr) g_thread_self (), ts, factory_type, factory_name,
+ plugin_name, source_module_name);
+
+ g_clear_object (&plugin);
+}
+
+static void
+gst_factories_tracer_class_init (GstFactoriesTracerClass * klass)
+{
+ /* announce trace formats */
+ /* *INDENT-OFF* */
+ tr_factory_used = gst_tracer_record_new ("factory-used.class",
+ "thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
+ "type", G_TYPE_GTYPE, G_TYPE_UINT64,
+ "related-to", GST_TYPE_TRACER_VALUE_SCOPE, GST_TRACER_VALUE_SCOPE_THREAD,
+ NULL),
+ "ts", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+ "type", G_TYPE_GTYPE, G_TYPE_UINT64,
+ "description", G_TYPE_STRING, "event ts",
+ NULL),
+ "factory-type", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+ "type", G_TYPE_GTYPE, G_TYPE_STRING,
+ "description", G_TYPE_STRING, "type name of the factory",
+ NULL),
+ "factory", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+ "type", G_TYPE_GTYPE, G_TYPE_STRING,
+ "description", G_TYPE_STRING, "name of the object factory",
+ NULL),
+ "plugin", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+ "type", G_TYPE_GTYPE, G_TYPE_STRING,
+ "description", G_TYPE_STRING, "name of the plugin",
+ NULL),
+ "source-module", GST_TYPE_STRUCTURE, gst_structure_new ("value",
+ "type", G_TYPE_GTYPE, G_TYPE_STRING,
+ "description", G_TYPE_STRING, "name of the source module this feature is from",
+ NULL),
+ NULL);
+ /* *INDENT-ON* */
+
+ GST_OBJECT_FLAG_SET (tr_factory_used, GST_OBJECT_FLAG_MAY_BE_LEAKED);
+}
+
+static void
+gst_factories_tracer_init (GstFactoriesTracer * self)
+{
+ GstTracer *tracer = GST_TRACER (self);
+
+ gst_tracing_register_hook (tracer, "element-new",
+ G_CALLBACK (do_element_new));
+ gst_tracing_register_hook (tracer, "plugin-feature-loaded",
+ G_CALLBACK (do_plugin_feature_loaded));
+}
diff --git a/plugins/tracers/gstfactories.h b/plugins/tracers/gstfactories.h
new file mode 100644
index 0000000000..950551538a
--- /dev/null
+++ b/plugins/tracers/gstfactories.h
@@ -0,0 +1,46 @@
+/* GStreamer
+ * Copyright (C) 2021 Collabora Ltd.
+ * @author: Olivier Crete <olivier.crete@collabora.com>
+ *
+ * gstfactories.h: A trace to log which plugin & factories are being used
+ *
+ * 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_FACTORIES_TRACER_H__
+#define __GST_FACTORIES_TRACER_H__
+
+#include <gst/gst.h>
+#include <gst/gsttracer.h>
+
+G_BEGIN_DECLS
+
+G_DECLARE_FINAL_TYPE(GstFactoriesTracer, gst_factories_tracer, GST,
+ FACTORIES_TRACER, GstTracer)
+/**
+ * GstFactoriesTracer:
+ *
+ * Opaque #GstFactoriesTracer data structure
+ */
+struct _GstFactoriesTracer {
+ GstTracer parent;
+
+ /*< private >*/
+};
+
+G_END_DECLS
+
+#endif /* __GST_FACTORIES_TRACER_H__ */
diff --git a/plugins/tracers/gsttracers.c b/plugins/tracers/gsttracers.c
index b03e25aeec..e5fe5d0581 100644
--- a/plugins/tracers/gsttracers.c
+++ b/plugins/tracers/gsttracers.c
@@ -29,6 +29,7 @@
#include "gstrusage.h"
#include "gststats.h"
#include "gstleaks.h"
+#include "gstfactories.h"
static gboolean
plugin_init (GstPlugin * plugin)
@@ -47,6 +48,9 @@ plugin_init (GstPlugin * plugin)
return FALSE;
if (!gst_tracer_register (plugin, "leaks", gst_leaks_tracer_get_type ()))
return FALSE;
+ if (!gst_tracer_register (plugin, "factories",
+ gst_factories_tracer_get_type ()))
+ return FALSE;
return TRUE;
}
diff --git a/plugins/tracers/meson.build b/plugins/tracers/meson.build
index 879cd9394f..8039c9be85 100644
--- a/plugins/tracers/meson.build
+++ b/plugins/tracers/meson.build
@@ -10,6 +10,7 @@ gst_tracers_sources = [
'gstleaks.c',
'gststats.c',
'gsttracers.c',
+ 'gstfactories.c'
]
if gst_debug
diff --git a/tools/gst-stats.c b/tools/gst-stats.c
index 8b490905c0..597c1ba1b7 100644
--- a/tools/gst-stats.c
+++ b/tools/gst-stats.c
@@ -47,6 +47,8 @@ static GstClockTime last_ts = G_GUINT64_CONSTANT (0);
static guint total_cpuload = 0;
static gboolean have_cpuload = FALSE;
+static GPtrArray *plugin_stats = NULL;
+
static gboolean have_latency = FALSE;
static gboolean have_element_latency = FALSE;
static gboolean have_element_reported_latency = FALSE;
@@ -122,6 +124,22 @@ typedef struct
guint cpuload;
} GstThreadStats;
+static const gchar *FACTORY_TYPES[] = {
+ "element",
+ "device-provider",
+ "typefind",
+ "dynamic-type",
+};
+
+#define N_FACTORY_TYPES G_N_ELEMENTS(FACTORY_TYPES)
+
+typedef struct
+{
+ gchar *name;
+
+ GPtrArray *factories[N_FACTORY_TYPES];
+} GstPluginStats;
+
/* stats helper */
static gint
@@ -283,6 +301,36 @@ free_thread_stats (gpointer data)
g_slice_free (GstThreadStats, data);
}
+static GstPluginStats *
+new_plugin_stats (const gchar * plugin_name)
+{
+ GstPluginStats *plugin = g_slice_new (GstPluginStats);
+ guint i;
+
+ plugin->name = g_strdup (plugin_name);
+
+ for (i = 0; i < N_FACTORY_TYPES; i++)
+ plugin->factories[i] = g_ptr_array_new_with_free_func (g_free);
+
+ g_ptr_array_add (plugin_stats, plugin);
+
+ return plugin;
+}
+
+static void
+free_plugin_stats (gpointer data)
+{
+ GstPluginStats *plugin = data;
+ guint i;
+
+ g_free (plugin->name);
+
+ for (i = 0; i < N_FACTORY_TYPES; i++)
+ g_ptr_array_unref (plugin->factories[i]);
+
+ g_slice_free (GstPluginStats, data);
+}
+
static void
do_pad_stats (GstPadStats * stats, guint elem_ix, guint size, guint64 ts,
guint64 buffer_ts, guint64 buffer_dur, GstBufferFlags buffer_flags)
@@ -608,6 +656,48 @@ do_element_reported_latency (GstStructure * s)
have_element_reported_latency = TRUE;
}
+static void
+do_factory_used (GstStructure * s)
+{
+ const gchar *factory = NULL;
+ const gchar *factory_type = NULL;
+ const gchar *plugin_name = NULL;
+ GstPluginStats *plugin = NULL;
+ guint i, f;
+
+ factory = gst_structure_get_string (s, "factory");
+ factory_type = gst_structure_get_string (s, "factory-type");
+ plugin_name = gst_structure_get_string (s, "plugin");
+
+ if (!g_strcmp0 (plugin_name, "staticelements"))
+ return;
+
+ if (plugin_name == NULL || plugin_name[0] == 0)
+ plugin_name = "built-in";
+
+ for (f = 0; f < N_FACTORY_TYPES; f++)
+ if (!g_strcmp0 (factory_type, FACTORY_TYPES[f]))
+ break;
+ if (f == N_FACTORY_TYPES)
+ return;
+
+ for (i = 0; i < plugin_stats->len; i++) {
+ GstPluginStats *tmp_plugin = g_ptr_array_index (plugin_stats, i);
+ if (!strcmp (tmp_plugin->name, plugin_name)) {
+ plugin = tmp_plugin;
+ break;
+ }
+ }
+
+ if (plugin == NULL)
+ plugin = new_plugin_stats (plugin_name);
+
+ if (factory && factory[0] &&
+ !g_ptr_array_find_with_equal_func (plugin->factories[f], factory,
+ g_str_equal, NULL))
+ g_ptr_array_add (plugin->factories[f], g_strdup (factory));
+}
+
/* reporting */
static gint
@@ -874,6 +964,8 @@ init (void)
free_latency_stats);
element_reported_latencies = g_queue_new ();
+ plugin_stats = g_ptr_array_new_with_free_func (free_plugin_stats);
+
return TRUE;
}
@@ -902,12 +994,32 @@ done (void)
element_reported_latencies = NULL;
}
+ g_clear_pointer (&plugin_stats, g_ptr_array_unref);
+
if (raw_log)
g_regex_unref (raw_log);
if (ansi_log)
g_regex_unref (ansi_log);
}
+static gint
+compare_plugin_stats (gconstpointer a, gconstpointer b)
+{
+ const GstPluginStats *plugin_a = *(GstPluginStats **) a;
+ const GstPluginStats *plugin_b = *(GstPluginStats **) b;
+
+ return strcmp (plugin_a->name, plugin_b->name);
+}
+
+static gint
+compare_string (gconstpointer a, gconstpointer b)
+{
+ const char *str_a = *(const char **) a;
+ const char *str_b = *(const char **) b;
+
+ return strcmp (str_a, str_b);
+}
+
static void
print_stats (void)
{
@@ -1012,6 +1124,43 @@ print_stats (void)
(GFunc) reported_latencies_foreach_print_stats, NULL);
puts ("");
}
+
+ if (plugin_stats->len > 0) {
+ guint i, j, f;
+
+ g_ptr_array_sort (plugin_stats, compare_plugin_stats);
+
+ printf ("Plugins used: ");
+ for (i = 0; i < plugin_stats->len; i++) {
+ GstPluginStats *ps = g_ptr_array_index (plugin_stats, i);
+ printf ("%s%s", i == 0 ? "" : ";", ps->name);
+ }
+ printf ("\n");
+
+ for (f = 0; f < N_FACTORY_TYPES; f++) {
+ gboolean first = TRUE;
+
+ printf ("%c%ss: ", g_ascii_toupper (FACTORY_TYPES[f][0]),
+ FACTORY_TYPES[f] + 1);
+ for (i = 0; i < plugin_stats->len; i++) {
+ GstPluginStats *ps = g_ptr_array_index (plugin_stats, i);
+
+ if (ps->factories[f]->len > 0) {
+ printf ("%s%s:", first ? "" : ";", ps->name);
+ first = FALSE;
+
+ g_ptr_array_sort (ps->factories[f], compare_string);
+
+ for (j = 0; j < ps->factories[f]->len; j++) {
+ const gchar *factory = g_ptr_array_index (ps->factories[f], j);
+
+ printf ("%s%s", j == 0 ? "" : ",", factory);
+ }
+ }
+ }
+ printf ("\n");
+ }
+ }
}
static void
@@ -1072,6 +1221,8 @@ collect_stats (const gchar * filename)
do_element_latency_stats (s);
} else if (!strcmp (name, "element-reported-latency")) {
do_element_reported_latency (s);
+ } else if (!strcmp (name, "factory-used")) {
+ do_factory_used (s);
} else {
// TODO(ensonic): parse the xxx.class log lines
if (!g_str_has_suffix (data, ".class")) {