[mutter/gbsneto/tracing: 3/7] profile: Add a Sysprof-based profiler (WIP)



commit 1cd73bf391cbfd36a998829012dc73ea7d7f8613
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Fri Aug 10 17:42:12 2018 -0300

    profile: Add a Sysprof-based profiler (WIP)
    
    This exposes the /org/gnome/Sysprof/Capturer object
    inside Mutter to allow initiating a Sysprof capture.
    
    The D-Bus interface is still WIP, and needs to be
    evaluated by the Sysprof team before this branch can
    be accepted.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/197

 src/backends/meta-backend.c        |   5 +
 src/backends/meta-profiler.c       | 223 +++++++++++++++++++++++++++++++++++++
 src/backends/meta-profiler.h       |  43 +++++++
 src/meson.build                    |   9 ++
 src/org.gnome.Sysprof.Capturer.xml |  15 +++
 5 files changed, 295 insertions(+)
---
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
index 23ab2faec..41df968e6 100644
--- a/src/backends/meta-backend.c
+++ b/src/backends/meta-backend.c
@@ -64,6 +64,7 @@
 #include "clutter/clutter-mutter.h"
 #include "meta/main.h"
 #include "meta/meta-backend.h"
+#include "backends/meta-profiler.h"
 #include "meta/util.h"
 
 #ifdef HAVE_REMOTE_DESKTOP
@@ -126,6 +127,7 @@ struct _MetaBackendPrivate
   MetaScreenCast *screen_cast;
   MetaRemoteDesktop *remote_desktop;
 #endif
+  MetaProfiler *profiler;
 
   ClutterBackend *clutter_backend;
   ClutterActor *stage;
@@ -192,6 +194,7 @@ meta_backend_finalize (GObject *object)
   g_hash_table_destroy (priv->device_monitors);
 
   g_clear_object (&priv->settings);
+  g_clear_object (&priv->profiler);
 
   G_OBJECT_CLASS (meta_backend_parent_class)->finalize (object);
 }
@@ -514,6 +517,8 @@ meta_backend_real_post_init (MetaBackend *backend)
       reset_pointer_position (backend);
       priv->is_pointer_position_initialized = TRUE;
     }
+
+  priv->profiler = meta_profiler_new ();
 }
 
 static MetaCursorRenderer *
diff --git a/src/backends/meta-profiler.c b/src/backends/meta-profiler.c
new file mode 100644
index 000000000..73f23449e
--- /dev/null
+++ b/src/backends/meta-profiler.c
@@ -0,0 +1,223 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2018 Endless, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <glib-unix.h>
+#include <gio/gunixfdlist.h>
+
+#include "meta-profiler.h"
+
+#include "cogl/cogl-trace.h"
+
+#define META_SYSPROF_PROFILER_DBUS_PATH "/org/gnome/Sysprof/Profiler"
+
+struct _MetaProfiler
+{
+  MetaDBusSysprofCapturerSkeleton parent_instance;
+
+  GCancellable *cancellable;
+  GDBusConnection *connection;
+
+  guint capture_timeout_id;
+};
+
+static void
+meta_sysprof_capturer_init_iface (MetaDBusSysprofCapturerIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (MetaProfiler,
+                         meta_profiler,
+                         META_DBUS_TYPE_SYSPROF_CAPTURER_SKELETON,
+                         G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_SYSPROF_CAPTURER,
+                                                meta_sysprof_capturer_init_iface))
+
+static gboolean
+on_capture_timeout_cb (gpointer user_data)
+{
+  MetaProfiler *self = META_PROFILER (user_data);
+
+  g_debug ("Stopping profiler");
+
+  cogl_set_tracing_disabled_on_thread (g_main_context_default ());
+
+  self->capture_timeout_id = 0;
+  return G_SOURCE_REMOVE;
+}
+
+static gboolean
+handle_get_capabilities (MetaDBusSysprofCapturer *capturer,
+                         GDBusMethodInvocation   *invocation)
+{
+  GVariantBuilder builder;
+  GVariant *capabilities;
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+  g_variant_builder_add (&builder, "{sv}", "Name",
+                         g_variant_new_string ("Mutter"));
+  g_variant_builder_add (&builder, "{sv}", "Interface-Version",
+                         g_variant_new_uint32 (1));
+
+  capabilities = g_variant_builder_end (&builder);
+
+  meta_dbus_sysprof_capturer_complete_get_capabilities (capturer,
+                                                        invocation,
+                                                        capabilities);
+  return TRUE;
+}
+
+static gboolean
+handle_capture (MetaDBusSysprofCapturer *capturer,
+                GDBusMethodInvocation   *invocation,
+                GVariant                *parameters)
+{
+  MetaProfiler *self = META_PROFILER (capturer);
+  guint timeout = 0;
+
+  g_debug ("Starting profiler");
+
+  g_variant_lookup (parameters, "timeout", "u", &timeout);
+
+  if (timeout == 0)
+    {
+      g_autoptr (GUnixFDList) fd_list = NULL;
+      g_autoptr (GVariant) fd_variant = NULL;
+      g_autoptr (GError) error = NULL;
+      int capture_pipe[2];
+      int fd_index;
+
+      if (!g_unix_open_pipe (capture_pipe, FD_CLOEXEC, &error))
+        {
+          g_critical ("Error opening pipe: %s", error->message);
+
+          g_dbus_method_invocation_return_error (invocation,
+                                                 G_IO_ERROR,
+                                                 G_IO_ERROR_FAILED,
+                                                 "Error opening pipe");
+          return TRUE;
+        }
+
+      cogl_set_tracing_enabled_on_thread (g_main_context_default (),
+                                          capture_pipe[1]);
+
+      fd_list = g_unix_fd_list_new ();
+      fd_index = g_unix_fd_list_append (fd_list, capture_pipe[0], &error);
+      fd_variant = g_variant_new_handle (fd_index);
+
+      close (capture_pipe[0]);
+
+      g_dbus_method_invocation_return_value_with_unix_fd_list (invocation,
+                                                               fd_variant,
+                                                               fd_list);
+      return TRUE;
+    }
+  else if (self->capture_timeout_id == 0)
+    {
+      cogl_set_tracing_enabled_on_thread (g_main_context_default (), -1);
+
+      self->capture_timeout_id =
+        g_timeout_add_seconds (timeout, on_capture_timeout_cb, self);
+
+      g_debug ("Capturing profiling data for %u seconds", timeout);
+    }
+
+  meta_dbus_sysprof_capturer_complete_capture (capturer, invocation,
+                                               g_variant_new_handle (-1));
+  return TRUE;
+}
+
+static void
+meta_sysprof_capturer_init_iface (MetaDBusSysprofCapturerIface *iface)
+{
+  iface->handle_get_capabilities = handle_get_capabilities;
+  iface->handle_capture = handle_capture;
+}
+
+static void
+on_bus_acquired_cb (GObject      *source,
+                    GAsyncResult *result,
+                    gpointer      user_data)
+{
+  g_autoptr (GDBusConnection) connection = NULL;
+  GDBusInterfaceSkeleton *interface_skeleton;
+  g_autoptr (GError) error = NULL;
+  MetaProfiler *self;
+
+  connection = g_bus_get_finish (result, &error);
+
+  if (error)
+    {
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        g_warning ("Failed to get session bus: %s\n", error->message);
+      return;
+    }
+
+  self = META_PROFILER (user_data);
+  interface_skeleton = G_DBUS_INTERFACE_SKELETON (self);
+
+  if (!g_dbus_interface_skeleton_export (interface_skeleton,
+                                         connection,
+                                         META_SYSPROF_PROFILER_DBUS_PATH,
+                                         &error))
+    {
+      g_warning ("Failed to export profiler object: %s\n", error->message);
+      return;
+    }
+
+  self->connection = g_steal_pointer (&connection);
+}
+
+static void
+meta_profiler_finalize (GObject *object)
+{
+  MetaProfiler *self = (MetaProfiler *)object;
+
+  g_cancellable_cancel (self->cancellable);
+
+  g_clear_handle_id (&self->capture_timeout_id, g_source_remove);
+  g_clear_object (&self->cancellable);
+  g_clear_object (&self->connection);
+
+  G_OBJECT_CLASS (meta_profiler_parent_class)->finalize (object);
+}
+
+static void
+meta_profiler_class_init (MetaProfilerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = meta_profiler_finalize;
+}
+
+static void
+meta_profiler_init (MetaProfiler *self)
+{
+  self->cancellable = g_cancellable_new ();
+
+  g_bus_get (G_BUS_TYPE_SESSION,
+             self->cancellable,
+             on_bus_acquired_cb,
+             self);
+}
+
+MetaProfiler *
+meta_profiler_new (void)
+{
+  return g_object_new (META_TYPE_PROFILER, NULL);
+}
+
diff --git a/src/backends/meta-profiler.h b/src/backends/meta-profiler.h
new file mode 100644
index 000000000..a94b75826
--- /dev/null
+++ b/src/backends/meta-profiler.h
@@ -0,0 +1,43 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2018 Endless, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef META_PROFILER_H
+#define META_PROFILER_H
+
+#include <glib-object.h>
+
+#include "meta-dbus-sysprof-capturer.h"
+
+G_BEGIN_DECLS
+
+#define META_TYPE_PROFILER (meta_profiler_get_type())
+
+G_DECLARE_FINAL_TYPE (MetaProfiler,
+                      meta_profiler,
+                      META,
+                      PROFILER,
+                      MetaDBusSysprofCapturerSkeleton)
+
+MetaProfiler * meta_profiler_new (void);
+
+G_END_DECLS
+
+#endif /* META_PROFILER_H */
diff --git a/src/meson.build b/src/meson.build
index 9919b5cfb..da93d409e 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -212,6 +212,8 @@ mutter_sources = [
   'backends/meta-output.h',
   'backends/meta-pointer-constraint.c',
   'backends/meta-pointer-constraint.h',
+  'backends/meta-profiler.c',
+  'backends/meta-profiler.h',
   'backends/meta-remote-access-controller-private.h',
   'backends/meta-remote-access-controller.c',
   'backends/meta-renderer.c',
@@ -604,6 +606,13 @@ dbus_idle_monitor_built_sources = gnome.gdbus_codegen('meta-dbus-idle-monitor',
   )
 mutter_built_sources += dbus_idle_monitor_built_sources
 
+dbus_sysprof_capturer_built_sources = gnome.gdbus_codegen('meta-dbus-sysprof-capturer',
+    'org.gnome.Sysprof.Capturer.xml',
+    interface_prefix: 'org.gnome.',
+    namespace: 'MetaDBus',
+  )
+mutter_built_sources += dbus_sysprof_capturer_built_sources
+
 if have_native_backend
   cvt = find_program('cvt')
 
diff --git a/src/org.gnome.Sysprof.Capturer.xml b/src/org.gnome.Sysprof.Capturer.xml
new file mode 100644
index 000000000..1754d7dba
--- /dev/null
+++ b/src/org.gnome.Sysprof.Capturer.xml
@@ -0,0 +1,15 @@
+<!DOCTYPE node PUBLIC
+'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
+'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
+
+<node>
+  <interface name='org.gnome.Sysprof.Capturer'>
+    <method name="GetCapabilities">
+      <arg type='a{sv}' name='parameters' direction='out'/>
+    </method>
+    <method name="Capture">
+      <arg type='a{sv}' name='parameters' direction='in'/>
+      <arg type='h' name='fd' direction='out'/>
+    </method>
+  </interface>
+</node>


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