From 17c5436f6ef6b6a1238816c08a12097e58c48979 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Fri, 10 Aug 2018 17:42:12 -0300 Subject: [PATCH] profile: Add a Sysprof-based profiler This exposes the /org/gnome/Sysprof3/Profiler object inside Mutter to allow initiating a Sysprof capture. https://gitlab.gnome.org/GNOME/mutter/merge_requests/197 --- src/backends/meta-backend.c | 5 + src/backends/meta-profiler.c | 193 +++++++++++++++++++++++++++++++++++ src/backends/meta-profiler.h | 41 ++++++++ src/meson.build | 17 +++ 4 files changed, 256 insertions(+) create mode 100644 src/backends/meta-profiler.c create mode 100644 src/backends/meta-profiler.h diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c index 23ab2faec..e6db720f2 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); } @@ -841,6 +844,8 @@ meta_backend_initable_init (GInitable *initable, system_bus_gotten_cb, backend); + priv->profiler = meta_profiler_new (); + return TRUE; } diff --git a/src/backends/meta-profiler.c b/src/backends/meta-profiler.c new file mode 100644 index 000000000..112a62519 --- /dev/null +++ b/src/backends/meta-profiler.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2019 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 "config.h" + +#include "src/backends/meta-profiler.h" + +#include +#include + +#include "cogl/cogl-trace.h" + +#define META_SYSPROF_PROFILER_DBUS_PATH "/org/gnome/Sysprof3/Profiler" + +struct _MetaProfiler +{ + MetaDBusSysprof3ProfilerSkeleton parent_instance; + + GDBusConnection *connection; + GCancellable *cancellable; + + gboolean running; +}; + +static void +meta_sysprof_capturer_init_iface (MetaDBusSysprof3ProfilerIface *iface); + +G_DEFINE_TYPE_WITH_CODE (MetaProfiler, + meta_profiler, + META_DBUS_TYPE_SYSPROF3_PROFILER_SKELETON, + G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_SYSPROF3_PROFILER, + meta_sysprof_capturer_init_iface)) + +static gboolean +handle_start (MetaDBusSysprof3Profiler *dbus_profiler, + GDBusMethodInvocation *invocation, + GVariant *options, + GVariant *fd_variant) +{ + MetaProfiler *profiler = META_PROFILER (dbus_profiler); + GMainContext *main_context = g_main_context_default (); + GDBusMessage *message; + GUnixFDList *fd_list; + int position; + int fd = -1; + + if (profiler->running) + { + g_dbus_method_invocation_return_error (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_FAILED, + "Profiler already running"); + return TRUE; + } + + g_variant_get (fd_variant, "h", &position); + + message = g_dbus_method_invocation_get_message (invocation); + fd_list = g_dbus_message_get_unix_fd_list (message); + if (fd_list) + fd = g_unix_fd_list_get (fd_list, position, NULL); + + if (fd != -1) + cogl_set_tracing_enabled_on_thread_with_fd (main_context, fd); + else + cogl_set_tracing_enabled_on_thread (main_context, "mutter-profile.syscap"); + + profiler->running = TRUE; + + g_debug ("Profiler running"); + + meta_dbus_sysprof3_profiler_complete_start (dbus_profiler, invocation); + return TRUE; +} + +static gboolean +handle_stop (MetaDBusSysprof3Profiler *dbus_profiler, + GDBusMethodInvocation *invocation) +{ + MetaProfiler *profiler = META_PROFILER (dbus_profiler); + + if (!profiler->running) + { + g_dbus_method_invocation_return_error (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_FAILED, + "Profiler not running"); + return TRUE; + } + + cogl_set_tracing_disabled_on_thread (g_main_context_default ()); + profiler->running = FALSE; + + g_debug ("Stopping profiler"); + + meta_dbus_sysprof3_profiler_complete_stop (dbus_profiler, invocation); + return TRUE; +} + +static void +meta_sysprof_capturer_init_iface (MetaDBusSysprof3ProfilerIface *iface) +{ + iface->handle_start = handle_start; + iface->handle_stop = handle_stop; +} + +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 *profiler; + + 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; + } + + profiler = META_PROFILER (user_data); + interface_skeleton = G_DBUS_INTERFACE_SKELETON (profiler); + + 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; + } + + profiler->connection = g_steal_pointer (&connection); +} + +static void +meta_profiler_finalize (GObject *object) +{ + MetaProfiler *self = (MetaProfiler *)object; + + g_cancellable_cancel (self->cancellable); + + 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..aa0d72640 --- /dev/null +++ b/src/backends/meta-profiler.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 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 + +#include "meta-dbus-sysprof3-profiler.h" + +G_BEGIN_DECLS + +#define META_TYPE_PROFILER (meta_profiler_get_type()) + +G_DECLARE_FINAL_TYPE (MetaProfiler, + meta_profiler, + META, + PROFILER, + MetaDBusSysprof3ProfilerSkeleton) + +MetaProfiler * meta_profiler_new (void); + +G_END_DECLS + +#endif /* META_PROFILER_H */ diff --git a/src/meson.build b/src/meson.build index 5007b5cab..53db81e85 100644 --- a/src/meson.build +++ b/src/meson.build @@ -625,6 +625,23 @@ dbus_idle_monitor_built_sources = gnome.gdbus_codegen('meta-dbus-idle-monitor', ) mutter_built_sources += dbus_idle_monitor_built_sources +if have_profiler + mutter_sources += [ + 'backends/meta-profiler.c', + 'backends/meta-profiler.h', + ] + + dbus_interfaces_dir = join_paths(datadir, 'dbus-1', 'interfaces') + sysprof3_dbus_file = join_paths(dbus_interfaces_dir, 'org.gnome.Sysprof3.Profiler.xml') + + dbus_sysprof3_profiler_built_sources = gnome.gdbus_codegen('meta-dbus-sysprof3-profiler', + sysprof3_dbus_file, + interface_prefix: 'org.gnome.', + namespace: 'MetaDBus', + ) + mutter_built_sources += dbus_sysprof3_profiler_built_sources +endif + if have_native_backend cvt = find_program('cvt')