All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: qemu-devel@nongnu.org
Cc: Pavel.Dovgaluk@ispras.ru, vilanova@ac.upc.edu, cota@braap.org,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"Stefan Hajnoczi" <stefanha@redhat.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>
Subject: [Qemu-devel] [RFC PATCH 14/21] trace: add support for plugin infrastructure
Date: Fri,  5 Oct 2018 16:49:03 +0100	[thread overview]
Message-ID: <20181005154910.3099-15-alex.bennee@linaro.org> (raw)
In-Reply-To: <20181005154910.3099-1-alex.bennee@linaro.org>

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch adds support for dynamically loaded plugins. Every plugin
is a dynamic library with a set of optional exported functions that
will be called from QEMU.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
[AJB: moved to using trace point API]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
ajb
  - moved to tracepoint interface (bind_to_tracepoints)
  - now in trace/ and include/plugins/
---
 include/plugins/plugins.h |  14 ++++
 include/qemu/plugins.h    |  18 +++++
 qemu-options.hx           |  10 +++
 trace/Makefile.objs       |   1 +
 trace/plugins.c           | 139 ++++++++++++++++++++++++++++++++++++++
 vl.c                      |   8 +++
 6 files changed, 190 insertions(+)
 create mode 100644 include/plugins/plugins.h
 create mode 100644 include/qemu/plugins.h
 create mode 100644 trace/plugins.c

diff --git a/include/plugins/plugins.h b/include/plugins/plugins.h
new file mode 100644
index 0000000000..54ac53cb32
--- /dev/null
+++ b/include/plugins/plugins.h
@@ -0,0 +1,14 @@
+#ifndef PLUGINS_INTERFACE_H
+#define PLUGINS_INTERFACE_H
+
+#include <stdbool.h>
+#include <stdio.h>
+
+/* Mandatory Plugin interfaces */
+
+bool plugin_init(const char *args);
+char *plugin_status(void);
+
+/* Other optional hooks are defined by available trace-points */
+
+#endif /* PLUGINS_INTERFACE_H */
diff --git a/include/qemu/plugins.h b/include/qemu/plugins.h
new file mode 100644
index 0000000000..c86bb7ae67
--- /dev/null
+++ b/include/qemu/plugins.h
@@ -0,0 +1,18 @@
+#ifndef PLUGINS_H
+#define PLUGINS_H
+
+#ifdef CONFIG_TRACE_PLUGIN
+
+void qemu_plugin_parse_cmd_args(const char *optarg);
+void qemu_plugin_load(const char *filename, const char *args);
+void qemu_plugins_init(void);
+
+#else
+
+static inline void qemu_plugin_parse_cmd_args(const char *optarg) { }
+static inline void qemu_plugin_load(const char *filename, const char *args) { }
+static inline void qemu_plugins_init(void) { }
+
+#endif
+
+#endif /* PLUGINS_H */
diff --git a/qemu-options.hx b/qemu-options.hx
index f139459e80..87206dd79f 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3892,6 +3892,16 @@ STEXI
 Enable synchronization profiling.
 ETEXI
 
+#ifdef CONFIG_TRACE_PLUGIN
+DEF("plugin", HAS_ARG, QEMU_OPTION_plugin, \
+           "-plugin file=<file>[,args=<args>] load <dso> plugin with <args>\n", QEMU_ARCH_ALL)
+STEXI
+@item -plugin file=@var{file}[,args=@var{args}]
+@findex -plugin
+Load @var{file} plugin passing @var{args} arguments.
+ETEXI
+#endif
+
 STEXI
 @end table
 ETEXI
diff --git a/trace/Makefile.objs b/trace/Makefile.objs
index afd571c3ec..4977f654a5 100644
--- a/trace/Makefile.objs
+++ b/trace/Makefile.objs
@@ -54,6 +54,7 @@ $(obj)/generated-tcg-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/
 
 util-obj-$(CONFIG_TRACE_SIMPLE) += simple.o
 util-obj-$(CONFIG_TRACE_FTRACE) += ftrace.o
+util-obj-$(CONFIG_TRACE_PLUGIN) += plugins.o
 util-obj-y += control.o
 target-obj-y += control-target.o
 util-obj-y += qmp.o
diff --git a/trace/plugins.c b/trace/plugins.c
new file mode 100644
index 0000000000..25aec2ff70
--- /dev/null
+++ b/trace/plugins.c
@@ -0,0 +1,139 @@
+/*
+ * Plugin Support
+ *
+ *
+ * Copyright (c) 2018 Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
+ * Copyright (c) 2018 Alex Bennée <alex.bennee@linaro.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include <gmodule.h>
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "qemu/plugins.h"
+#include "qemu/queue.h"
+#include "qemu/option.h"
+#include "trace/control.h"
+
+typedef bool (*PluginInitFunc)(const char *);
+typedef char * (*PluginStatusFunc)(void);
+
+typedef struct QemuPluginInfo {
+    const char *filename;
+    const char *args;
+    GModule *g_module;
+
+    PluginInitFunc init;
+    PluginStatusFunc status;
+
+    GPtrArray *events;
+
+    QLIST_ENTRY(QemuPluginInfo) next;
+} QemuPluginInfo;
+
+static QLIST_HEAD(, QemuPluginInfo) qemu_plugins
+                                = QLIST_HEAD_INITIALIZER(qemu_plugins);
+
+static QemuOptsList qemu_plugin_opts = {
+    .name = "plugin",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_plugin_opts.head),
+    .desc = {
+        {
+            .name = "file",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "args",
+            .type = QEMU_OPT_STRING,
+        },
+        { /* end of list */ }
+    },
+};
+
+void qemu_plugin_parse_cmd_args(const char *optarg)
+{
+    QemuOpts *opts = qemu_opts_parse_noisily(&qemu_plugin_opts, optarg, false);
+    qemu_plugin_load(qemu_opt_get(opts, "file"),
+                     qemu_opt_get(opts, "args"));
+}
+
+static int bind_to_tracepoints(GModule *g_module, GPtrArray *events)
+{
+    int count = 0;
+    TraceEventIter iter;
+    TraceEvent *ev;
+
+    trace_event_iter_init(&iter, "*");
+    while ((ev = trace_event_iter_next(&iter)) != NULL) {
+        const char *name = trace_event_get_name(ev);
+        gpointer fn;
+
+        if (g_module_symbol(g_module, name, &fn)) {
+            ev->plugin = (uintptr_t) fn;
+            trace_event_set_state_dynamic(ev, true);
+            count++;
+        }
+    }
+
+    return count;
+}
+
+void qemu_plugin_load(const char *filename, const char *args)
+{
+    GModule *g_module;
+    QemuPluginInfo *info = NULL;
+    if (!filename) {
+        error_report("plugin name was not specified");
+        return;
+    }
+    g_module = g_module_open(filename,
+        G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+    if (!g_module) {
+        error_report("can't load plugin '%s'", filename);
+        return;
+    }
+    info = g_new0(QemuPluginInfo, 1);
+    info->filename = g_strdup(filename);
+    info->g_module = g_module;
+
+    if (!g_module_symbol(g_module, "plugin_init",
+                         (gpointer *) &info->init)) {
+        error_report("all plugins must provide a plugin_init hook");
+        return;
+    }
+
+    if (!g_module_symbol(g_module, "plugin_status",
+                         (gpointer *) &info->status)) {
+        error_report("all plugins must provide a plugin_status hook");
+        return;
+    }
+
+    /* OK we can now see how many events might have bindings */
+    info->events = g_ptr_array_new();
+
+    if (bind_to_tracepoints(g_module, info->events) < 0) {
+        error_report("failed to bind any events");
+        return;
+    }
+
+    /* Save the args, we will initialise later on once everything is
+       set up */
+    if (args) {
+        info->args = g_strdup(args);
+    }
+
+    QLIST_INSERT_HEAD(&qemu_plugins, info, next);
+
+    return;
+}
+
+void qemu_plugins_init(void)
+{
+    QemuPluginInfo *info;
+    QLIST_FOREACH(info, &qemu_plugins, next) {
+        if (info->init) {
+            info->init(info->args);
+        }
+    }
+}
diff --git a/vl.c b/vl.c
index 795e025445..b46ef5032f 100644
--- a/vl.c
+++ b/vl.c
@@ -130,6 +130,7 @@ int main(int argc, char **argv)
 #include "qapi/qapi-commands-run-state.h"
 #include "qapi/qmp/qerror.h"
 #include "sysemu/iothread.h"
+#include "qemu/plugins.h"
 
 #define MAX_VIRTIO_CONSOLES 1
 
@@ -3884,6 +3885,11 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_enable_sync_profile:
                 qsp_enable();
                 break;
+#ifdef CONFIG_TRACE_PLUGIN
+            case QEMU_OPTION_plugin:
+                qemu_plugin_parse_cmd_args(optarg);
+                break;
+#endif
             case QEMU_OPTION_nouserconfig:
                 /* Nothing to be parsed here. Especially, do not error out below. */
                 break;
@@ -4449,6 +4455,8 @@ int main(int argc, char **argv, char **envp)
     }
     parse_numa_opts(current_machine);
 
+    qemu_plugins_init();
+
     /* do monitor/qmp handling at preconfig state if requested */
     main_loop();
 
-- 
2.17.1

  parent reply	other threads:[~2018-10-05 15:49 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-05 15:48 [Qemu-devel] [RFC PATCH 00/21] Trace updates and plugin RFC Alex Bennée
2018-10-05 15:48 ` [Qemu-devel] [RFC PATCH 01/21] util/log: allow -dfilter to stack Alex Bennée
2018-10-06 16:57   ` Richard Henderson
2018-10-05 15:48 ` [Qemu-devel] [RFC PATCH 02/21] util/log: add qemu_dfilter_append_range() Alex Bennée
2018-10-06 17:00   ` Richard Henderson
2018-10-05 15:48 ` [Qemu-devel] [RFC PATCH 03/21] linux-user: add -dfilter progtext shortcut Alex Bennée
2018-10-06 17:12   ` Richard Henderson
2018-10-05 15:48 ` [Qemu-devel] [RFC PATCH 04/21] trace: enable the exec_tb trace events Alex Bennée
2018-10-06 17:15   ` Richard Henderson
2018-10-07  1:42   ` Emilio G. Cota
2018-10-08  9:41     ` Alex Bennée
2018-10-05 15:48 ` [Qemu-devel] [RFC PATCH 05/21] trace: keep a count of trace-point hits Alex Bennée
2018-10-06 18:26   ` Richard Henderson
2018-10-05 15:48 ` [Qemu-devel] [RFC PATCH 06/21] trace: show trace point counts in the monitor Alex Bennée
2018-10-06 18:27   ` Richard Henderson
2018-10-08 12:51   ` Markus Armbruster
2018-10-17 11:52   ` Dr. David Alan Gilbert
2018-10-05 15:48 ` [Qemu-devel] [RFC PATCH 07/21] accel/tcg/cputlb: convert tlb_flush debugging into trace events Alex Bennée
2018-10-15 16:33   ` Richard Henderson
2018-10-15 18:23     ` Alex Bennée
2018-10-15 18:37       ` Richard Henderson
2018-10-05 15:48 ` [Qemu-devel] [RFC PATCH 08/21] accel/tcg/cputlb: convert remaining tlb_debug() to " Alex Bennée
2018-10-15 16:38   ` Richard Henderson
2018-10-15 18:17     ` Alex Bennée
2018-10-15 18:35       ` Richard Henderson
2018-10-05 15:48 ` [Qemu-devel] [RFC PATCH 09/21] trace: suppress log output of trace points Alex Bennée
2018-10-15 16:47   ` Richard Henderson
2018-10-05 15:48 ` [Qemu-devel] [RFC PATCH 10/21] qom/cpu: add a cpu_exit trace event Alex Bennée
2018-10-06 18:51   ` Richard Henderson
2018-10-05 15:49 ` [Qemu-devel] [RFC PATCH 11/21] trace: expose a plugin fn pointer in TraceEvent Alex Bennée
2018-10-15 16:52   ` Richard Henderson
2018-10-05 15:49 ` [Qemu-devel] [RFC PATCH 12/21] configure: expose a plugin to the trace-backends Alex Bennée
2018-10-15 17:14   ` Richard Henderson
2018-10-05 15:49 ` [Qemu-devel] [RFC PATCH 13/21] tracetool: generate plugin snippets Alex Bennée
2018-10-15 17:02   ` Richard Henderson
2018-10-05 15:49 ` Alex Bennée [this message]
2018-10-07  1:29   ` [Qemu-devel] [RFC PATCH 14/21] trace: add support for plugin infrastructure Emilio G. Cota
2018-10-15 17:11   ` Richard Henderson
2018-10-05 15:49 ` [Qemu-devel] [RFC PATCH 15/21] trace: add linux-user plugin support Alex Bennée
2018-10-15 17:13   ` Richard Henderson
2018-10-05 15:49 ` [Qemu-devel] [RFC PATCH 16/21] trace: add infrastructure for building plugins Alex Bennée
2018-10-15 17:24   ` Richard Henderson
2018-10-15 18:16     ` Alex Bennée
2018-10-05 15:49 ` [Qemu-devel] [RFC PATCH 17/21] hmp: expose status of plugins to the monitor Alex Bennée
2018-10-15 17:27   ` Richard Henderson
2018-10-17 12:04   ` Dr. David Alan Gilbert
2018-10-17 17:36     ` Markus Armbruster
2018-10-05 15:49 ` [Qemu-devel] [RFC PATCH 18/21] linux-user: allow dumping of plugin status at end of run Alex Bennée
2018-10-15 17:28   ` Richard Henderson
2018-10-05 15:49 ` [Qemu-devel] [RFC PATCH 19/21] plugins: add an example hotblocks plugin Alex Bennée
2018-10-08 12:59   ` Pavel Dovgalyuk
2018-10-08 14:05     ` Alex Bennée
2018-10-15 17:33   ` Richard Henderson
2018-10-15 18:15     ` Alex Bennée
2018-10-05 15:49 ` [Qemu-devel] [RFC PATCH 20/21] plugins: add hotness summary to hotblocks Alex Bennée
2018-10-15 17:34   ` Richard Henderson
2018-10-05 15:49 ` [Qemu-devel] [RFC PATCH 21/21] plugin: add tlbflush stats plugin Alex Bennée
2018-10-07  1:23 ` [Qemu-devel] [RFC PATCH 00/21] Trace updates and plugin RFC Emilio G. Cota
2018-10-08 10:28   ` Alex Bennée
2018-10-08 12:51     ` Philippe Mathieu-Daudé
2018-10-08 13:59     ` Emilio G. Cota
2018-10-08 14:15       ` Alex Bennée
2018-10-09  6:28 ` Pavel Dovgalyuk
2018-10-09  8:31   ` Alex Bennée
2018-10-09  8:38     ` Pavel Dovgalyuk
2018-10-09  9:26       ` Alex Bennée
2018-10-29  7:46         ` Pavel Dovgalyuk
2018-10-29 11:30           ` Alex Bennée
2018-10-29 12:24             ` Pavel Dovgalyuk
2018-10-29 15:03               ` Alex Bennée

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181005154910.3099-15-alex.bennee@linaro.org \
    --to=alex.bennee@linaro.org \
    --cc=Pavel.Dovgaluk@ispras.ru \
    --cc=cota@braap.org \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    --cc=vilanova@ac.upc.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.