[sysprof] helpers: add fallbacks for perf_event_open



commit 1a576aa779672361e17736fae29fdbf1285372e5
Author: Christian Hergert <chergert redhat com>
Date:   Thu May 9 14:44:16 2019 -0700

    helpers: add fallbacks for perf_event_open
    
    First try the proxy to the service, then fallback to trying in-process.

 src/helpers.h                    |  16 ++---
 src/libsysprof/sysprof-helpers.c | 135 ++++++++++++++++++++++++++++++++++-----
 src/libsysprof/sysprof-helpers.h |   2 +-
 3 files changed, 129 insertions(+), 24 deletions(-)
---
diff --git a/src/helpers.h b/src/helpers.h
index c0f6555..4c5fe9a 100644
--- a/src/helpers.h
+++ b/src/helpers.h
@@ -27,14 +27,14 @@
 
 G_BEGIN_DECLS
 
-gboolean helpers_list_processes  (gint32   **processes,
-                                  gsize     *n_processes);
-gboolean helpers_perf_event_open (GVariant  *options,
-                                  gint32     pid,
-                                  gint32     cpu,
-                                  gint       group_fd,
-                                  guint64    flags,
-                                  gint      *out_fd);
+gboolean helpers_list_processes  (gint32      **processes,
+                                  gsize        *n_processes);
+gboolean helpers_perf_event_open (GVariant     *options,
+                                  gint32        pid,
+                                  gint32        cpu,
+                                  gint          group_fd,
+                                  guint64       flags,
+                                  gint         *out_fd);
 gboolean helpers_get_proc_file   (const gchar  *path,
                                   gchar       **contents,
                                   gsize        *len);
diff --git a/src/libsysprof/sysprof-helpers.c b/src/libsysprof/sysprof-helpers.c
index 2966f08..0825095 100644
--- a/src/libsysprof/sysprof-helpers.c
+++ b/src/libsysprof/sysprof-helpers.c
@@ -35,8 +35,27 @@ struct _SysprofHelpers
   IpcService *proxy;
 };
 
+typedef struct
+{
+  GVariant *options;
+  gint32 pid;
+  gint32 cpu;
+  gint group_fd;
+  guint64 flags;
+} PerfEventOpen;
+
 G_DEFINE_TYPE (SysprofHelpers, sysprof_helpers, G_TYPE_OBJECT)
 
+static void
+perf_event_open_free (gpointer data)
+{
+  PerfEventOpen *state = data;
+  g_clear_pointer (&state->options, g_variant_unref);
+  if (state->group_fd)
+    close (state->group_fd);
+  g_slice_free (PerfEventOpen, state);
+}
+
 static void
 sysprof_helpers_finalize (GObject *object)
 {
@@ -191,7 +210,6 @@ sysprof_helpers_list_processes_finish (SysprofHelpers  *self,
   return FALSE;
 }
 
-#ifdef __linux__
 static void
 sysprof_helpers_get_proc_file_cb (IpcService   *service,
                                   GAsyncResult *result,
@@ -255,6 +273,7 @@ sysprof_helpers_get_proc_file_finish (SysprofHelpers  *self,
   return FALSE;
 }
 
+#ifdef __linux__
 static void
 sysprof_helpers_perf_event_open_cb (IpcService   *service,
                                     GAsyncResult *result,
@@ -263,20 +282,84 @@ sysprof_helpers_perf_event_open_cb (IpcService   *service,
   g_autoptr(GTask) task = user_data;
   g_autoptr(GUnixFDList) fd_list = NULL;
   g_autoptr(GError) error = NULL;
+  PerfEventOpen *state;
 
   g_assert (IPC_IS_SERVICE (service));
   g_assert (G_IS_ASYNC_RESULT (result));
   g_assert (G_IS_TASK (task));
 
+  state = g_task_get_task_data (task);
+
+  g_assert (state != NULL);
+  g_assert (state->options != NULL);
+
   if (!g_dbus_proxy_call_with_unix_fd_list_finish (G_DBUS_PROXY (service),
                                                    &fd_list,
                                                    result,
                                                    &error))
+    {
+      gint out_fd = -1;
+
+      if (helpers_perf_event_open (state->options,
+                                   state->pid,
+                                   state->cpu,
+                                   state->group_fd,
+                                   state->flags,
+                                   &out_fd))
+        {
+          fd_list = g_unix_fd_list_new ();
+          if (-1 == g_unix_fd_list_append (fd_list, out_fd, NULL))
+            g_clear_object (&fd_list);
+          close (out_fd);
+        }
+    }
+
+  g_assert (error || fd_list);
+
+  if (error != NULL)
     g_task_return_error (task, g_steal_pointer (&error));
   else
     g_task_return_pointer (task, g_steal_pointer (&fd_list), g_object_unref);
 }
 
+static GVariant *
+build_options_dict (struct perf_event_attr *attr)
+{
+  return g_variant_take_ref (
+    g_variant_new_parsed ("["
+                            "{'comm', <%b>},"
+#ifdef HAVE_PERF_CLOCKID
+                            "{'clockid', <%i>},"
+                            "{'use_clockid', <%b>},"
+#endif
+                            "{'config', <%t>},"
+                            "{'disabled', <%b>},"
+                            "{'exclude_idle', <%b>},"
+                            "{'mmap', <%b>},"
+                            "{'wakeup_events', <%u>},"
+                            "{'sample_id_all', <%b>},"
+                            "{'sample_period', <%t>},"
+                            "{'sample_type', <%t>},"
+                            "{'task', <%b>},"
+                            "{'type', <%u>}"
+                          "]",
+                          (gboolean)!!attr->comm,
+#ifdef HAVE_PERF_CLOCKID
+                          (gint32)attr->clockid,
+                          (gboolean)!!attr->use_clockid,
+#endif
+                          (guint64)attr->config,
+                          (gboolean)!!attr->disabled,
+                          (gboolean)!!attr->exclude_idle,
+                          (gboolean)!!attr->mmap,
+                          (guint32)attr->wakeup_events,
+                          (gboolean)!!attr->sample_id_all,
+                          (guint64)attr->sample_period,
+                          (guint64)attr->sample_type,
+                          (gboolean)!!attr->task,
+                          (guint32)attr->type));
+}
+
 void
 sysprof_helpers_perf_event_open_async (SysprofHelpers         *self,
                                        struct perf_event_attr *attr,
@@ -289,28 +372,50 @@ sysprof_helpers_perf_event_open_async (SysprofHelpers         *self,
                                        gpointer                user_data)
 {
   g_autoptr(GTask) task = NULL;
-  g_autoptr(GVariant) options = NULL;
 
   g_return_if_fail (SYSPROF_IS_HELPERS (self));
   g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+  g_return_if_fail (group_fd >= -1);
 
   task = g_task_new (self, cancellable, callback, user_data);
   g_task_set_source_tag (task, sysprof_helpers_list_processes_async);
 
   if (!fail_if_no_proxy (self, task))
-    g_dbus_proxy_call_with_unix_fd_list (G_DBUS_PROXY (self->proxy),
-                                         "PerfEventOpen",
-                                         g_variant_new ("(@a{sv}iit)",
-                                                        options,
-                                                        pid,
-                                                        cpu,
-                                                        flags),
-                                         G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
-                                         -1,
-                                         NULL,
-                                         cancellable,
-                                         (GAsyncReadyCallback) sysprof_helpers_perf_event_open_cb,
-                                         g_steal_pointer (&task));
+    {
+      g_autoptr(GUnixFDList) fd_list = NULL;
+      g_autoptr(GVariant) params = NULL;
+      PerfEventOpen *state;
+      gint handle = -1;
+
+      if (group_fd != -1)
+        {
+          fd_list = g_unix_fd_list_new ();
+          handle = g_unix_fd_list_append (fd_list, group_fd, NULL);
+        }
+
+      state = g_slice_new0 (PerfEventOpen);
+      state->options = g_variant_take_ref (build_options_dict (attr));
+      state->pid = pid;
+      state->cpu = cpu;
+      state->group_fd = dup (group_fd);
+      state->flags = flags;
+      g_task_set_task_data (task, state, perf_event_open_free);
+
+      g_dbus_proxy_call_with_unix_fd_list (G_DBUS_PROXY (self->proxy),
+                                           "PerfEventOpen",
+                                           g_variant_new ("(@a{sv}iiht)",
+                                                          state->options,
+                                                          state->pid,
+                                                          state->cpu,
+                                                          handle,
+                                                          state->flags),
+                                           G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
+                                           -1,
+                                           fd_list,
+                                           cancellable,
+                                           (GAsyncReadyCallback) sysprof_helpers_perf_event_open_cb,
+                                           g_steal_pointer (&task));
+    }
 }
 
 gboolean
diff --git a/src/libsysprof/sysprof-helpers.h b/src/libsysprof/sysprof-helpers.h
index 962549f..85da604 100644
--- a/src/libsysprof/sysprof-helpers.h
+++ b/src/libsysprof/sysprof-helpers.h
@@ -42,7 +42,6 @@ gboolean        sysprof_helpers_list_processes_finish  (SysprofHelpers
                                                         gint32                 **processes,
                                                         gsize                   *n_processes,
                                                         GError                 **error);
-#ifdef __linux__
 void            sysprof_helpers_get_proc_file_async    (SysprofHelpers          *self,
                                                         const gchar             *path,
                                                         GCancellable            *cancellable,
@@ -52,6 +51,7 @@ gboolean        sysprof_helpers_get_proc_file_finish   (SysprofHelpers
                                                         GAsyncResult            *result,
                                                         gchar                  **contents,
                                                         GError                 **error);
+#ifdef __linux__
 void            sysprof_helpers_perf_event_open_async  (SysprofHelpers          *self,
                                                         struct perf_event_attr  *attr,
                                                         gint32                   pid,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]