[gnome-software] gs-plugin-loader: Add sysprof support for profiling jobs



commit 4b67aabebaebaf226bbcc41bf8c3b13a6c8b5323
Author: Philip Withnall <withnall endlessm com>
Date:   Fri Jun 19 14:58:27 2020 +0100

    gs-plugin-loader: Add sysprof support for profiling jobs
    
    This can be used with a command like:
    ```
    sysprof-cli --gtk --use-trace-fd -- gnome-software
    ```
    or from within GNOME Builder, to profile gnome-software. The changes
    in this commit use the `sysprof-capture-3` library to write additional
    timing data to the capture, showing the details of every plugin job and
    vfunc call which happen in gnome-software.
    
    This should make it easier to visualise what plugin jobs are happening,
    and which ones are taking a long time.
    
    This commit adds an optional dependency on `sysprof-capture-3`.
    
    Signed-off-by: Philip Withnall <withnall endlessm com>

 lib/gs-plugin-loader.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++---
 lib/meson.build        |   1 +
 meson.build            |   3 +
 meson_options.txt      |   1 +
 4 files changed, 142 insertions(+), 8 deletions(-)
---
diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c
index fd355a1e..a7bd53f7 100644
--- a/lib/gs-plugin-loader.c
+++ b/lib/gs-plugin-loader.c
@@ -13,6 +13,10 @@
 #include <appstream-glib.h>
 #include <math.h>
 
+#ifdef HAVE_SYSPROF
+#include <sysprof-capture.h>
+#endif
+
 #include "gs-app-collation.h"
 #include "gs-app-private.h"
 #include "gs-app-list-private.h"
@@ -61,6 +65,10 @@ typedef struct
        gulong                   network_changed_handler;
        gulong                   network_available_notify_handler;
        gulong                   network_metered_notify_handler;
+
+#ifdef HAVE_SYSPROF
+       SysprofCaptureWriter    *sysprof_writer;  /* (owned) (nullable) */
+#endif
 } GsPluginLoaderPrivate;
 
 static void gs_plugin_loader_monitor_network (GsPluginLoader *plugin_loader);
@@ -498,11 +506,17 @@ gs_plugin_loader_call_vfunc (GsPluginLoaderHelper *helper,
                             GCancellable *cancellable,
                             GError **error)
 {
+#ifdef HAVE_SYSPROF
+       GsPluginLoaderPrivate *priv = gs_plugin_loader_get_instance_private (helper->plugin_loader);
+#endif
        GsPluginAction action = gs_plugin_job_get_action (helper->plugin_job);
        gboolean ret = TRUE;
        gpointer func = NULL;
        g_autoptr(GError) error_local = NULL;
        g_autoptr(GTimer) timer = g_timer_new ();
+#ifdef HAVE_SYSPROF
+       gint64 begin_time_nsec = SYSPROF_CAPTURE_CURRENT_TIME;
+#endif
 
        /* load the possible symbol */
        func = gs_plugin_get_symbol (plugin, helper->function_name);
@@ -737,6 +751,24 @@ gs_plugin_loader_call_vfunc (GsPluginLoaderHelper *helper,
                add_app_to_install_queue (helper->plugin_loader, app);
        }
 
+#ifdef HAVE_SYSPROF
+       if (priv->sysprof_writer != NULL) {
+               g_autofree gchar *sysprof_name = NULL;
+               g_autofree gchar *sysprof_message = NULL;
+
+               sysprof_name = g_strconcat ("vfunc:", gs_plugin_action_to_string (action), NULL);
+               sysprof_message = gs_plugin_job_to_string (helper->plugin_job);
+               sysprof_capture_writer_add_mark (priv->sysprof_writer,
+                                                begin_time_nsec,
+                                                sched_getcpu (),
+                                                getpid (),
+                                                SYSPROF_CAPTURE_CURRENT_TIME - begin_time_nsec,
+                                                "gnome-software",
+                                                sysprof_name,
+                                                sysprof_message);
+       }
+#endif  /* HAVE_SYSPROF */
+
        /* check the plugin didn't take too long */
        switch (action) {
        case GS_PLUGIN_ACTION_INITIALIZE:
@@ -1069,6 +1101,9 @@ gs_plugin_loader_run_results (GsPluginLoaderHelper *helper,
                              GError **error)
 {
        GsPluginLoaderPrivate *priv = gs_plugin_loader_get_instance_private (helper->plugin_loader);
+#ifdef HAVE_SYSPROF
+       gint64 begin_time_nsec G_GNUC_UNUSED = SYSPROF_CAPTURE_CURRENT_TIME;
+#endif
 
        /* run each plugin */
        for (guint i = 0; i < priv->plugins->len; i++) {
@@ -1084,6 +1119,27 @@ gs_plugin_loader_run_results (GsPluginLoaderHelper *helper,
                }
                gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
        }
+
+#ifdef HAVE_SYSPROF
+       if (priv->sysprof_writer != NULL) {
+               g_autofree gchar *sysprof_name = NULL;
+               g_autofree gchar *sysprof_message = NULL;
+
+               sysprof_name = g_strconcat ("run-results:",
+                                           gs_plugin_action_to_string (gs_plugin_job_get_action 
(helper->plugin_job)),
+                                           NULL);
+               sysprof_message = gs_plugin_job_to_string (helper->plugin_job);
+               sysprof_capture_writer_add_mark (priv->sysprof_writer,
+                                                begin_time_nsec,
+                                                sched_getcpu (),
+                                                getpid (),
+                                                SYSPROF_CAPTURE_CURRENT_TIME - begin_time_nsec,
+                                                "gnome-software",
+                                                sysprof_name,
+                                                sysprof_message);
+       }
+#endif  /* HAVE_SYSPROF */
+
        return TRUE;
 }
 
@@ -1511,6 +1567,10 @@ gs_plugin_loader_job_get_categories_thread_cb (GTask *task,
 {
        GError *error = NULL;
        GsPluginLoaderHelper *helper = (GsPluginLoaderHelper *) task_data;
+#ifdef HAVE_SYSPROF
+       GsPluginLoaderPrivate *priv = gs_plugin_loader_get_instance_private (helper->plugin_loader);
+       gint64 begin_time_nsec G_GNUC_UNUSED = SYSPROF_CAPTURE_CURRENT_TIME;
+#endif
 
        /* run each plugin */
        if (!gs_plugin_loader_run_results (helper, cancellable, &error)) {
@@ -1531,20 +1591,31 @@ gs_plugin_loader_job_get_categories_thread_cb (GTask *task,
                gs_category_sort_children (cat);
        }
 
-       /* success */
-       if (helper->catlist->len == 0) {
-               g_task_return_new_error (task,
-                                        GS_PLUGIN_ERROR,
-                                        GS_PLUGIN_ERROR_NOT_SUPPORTED,
-                                        "no categories to show");
-               return;
+#ifdef HAVE_SYSPROF
+       if (priv->sysprof_writer != NULL) {
+               g_autofree gchar *sysprof_message = gs_plugin_job_to_string (helper->plugin_job);
+               sysprof_capture_writer_add_mark (priv->sysprof_writer,
+                                                begin_time_nsec,
+                                                sched_getcpu (),
+                                                getpid (),
+                                                SYSPROF_CAPTURE_CURRENT_TIME - begin_time_nsec,
+                                                "gnome-software",
+                                                "get-categories",
+                                                sysprof_message);
        }
+#endif  /* HAVE_SYSPROF */
 
        /* show elapsed time */
        gs_plugin_loader_job_debug (helper);
 
        /* success */
-       g_task_return_pointer (task, g_ptr_array_ref (helper->catlist), (GDestroyNotify) g_ptr_array_unref);
+       if (helper->catlist->len == 0)
+               g_task_return_new_error (task,
+                                        GS_PLUGIN_ERROR,
+                                        GS_PLUGIN_ERROR_NOT_SUPPORTED,
+                                        "no categories to show");
+       else
+               g_task_return_pointer (task, g_ptr_array_ref (helper->catlist), (GDestroyNotify) 
g_ptr_array_unref);
 }
 
 /**
@@ -2244,6 +2315,9 @@ gs_plugin_loader_setup_again (GsPluginLoader *plugin_loader)
                GS_PLUGIN_ACTION_INITIALIZE,
                GS_PLUGIN_ACTION_SETUP,
                GS_PLUGIN_ACTION_UNKNOWN };
+#ifdef HAVE_SYSPROF
+       gint64 begin_time_nsec G_GNUC_UNUSED = SYSPROF_CAPTURE_CURRENT_TIME;
+#endif
 
        /* clear global cache */
        gs_plugin_loader_clear_caches (plugin_loader);
@@ -2275,6 +2349,19 @@ gs_plugin_loader_setup_again (GsPluginLoader *plugin_loader)
                                gs_plugin_clear_data (plugin);
                }
        }
+
+#ifdef HAVE_SYSPROF
+       if (priv->sysprof_writer != NULL) {
+               sysprof_capture_writer_add_mark (priv->sysprof_writer,
+                                                begin_time_nsec,
+                                                sched_getcpu (),
+                                                getpid (),
+                                                SYSPROF_CAPTURE_CURRENT_TIME - begin_time_nsec,
+                                                "gnome-software",
+                                                "setup-again",
+                                                NULL);
+       }
+#endif  /* HAVE_SYSPROF */
 }
 
 static gint
@@ -2332,6 +2419,9 @@ gs_plugin_loader_setup (GsPluginLoader *plugin_loader,
        guint j;
        g_autoptr(GsPluginLoaderHelper) helper = NULL;
        g_autoptr(GsPluginJob) plugin_job = NULL;
+#ifdef HAVE_SYSPROF
+       gint64 begin_time_nsec G_GNUC_UNUSED = SYSPROF_CAPTURE_CURRENT_TIME;
+#endif
 
        /* use the default, but this requires a 'make install' */
        if (priv->locations->len == 0) {
@@ -2546,6 +2636,20 @@ gs_plugin_loader_setup (GsPluginLoader *plugin_loader,
        /* now we can load the install-queue */
        if (!load_install_queue (plugin_loader, error))
                return FALSE;
+
+#ifdef HAVE_SYSPROF
+       if (priv->sysprof_writer != NULL) {
+               sysprof_capture_writer_add_mark (priv->sysprof_writer,
+                                                begin_time_nsec,
+                                                sched_getcpu (),
+                                                getpid (),
+                                                SYSPROF_CAPTURE_CURRENT_TIME - begin_time_nsec,
+                                                "gnome-software",
+                                                "setup",
+                                                NULL);
+       }
+#endif  /* HAVE_SYSPROF */
+
        return TRUE;
 }
 
@@ -2654,6 +2758,9 @@ gs_plugin_loader_dispose (GObject *object)
        g_clear_object (&priv->soup_session);
        g_clear_object (&priv->settings);
        g_clear_pointer (&priv->pending_apps, g_ptr_array_unref);
+#ifdef HAVE_SYSPROF
+       g_clear_pointer (&priv->sysprof_writer, sysprof_capture_writer_unref);
+#endif
 
        G_OBJECT_CLASS (gs_plugin_loader_parent_class)->dispose (object);
 }
@@ -2782,6 +2889,10 @@ gs_plugin_loader_init (GsPluginLoader *plugin_loader)
        gchar **projects;
        guint i;
 
+#ifdef HAVE_SYSPROF
+       priv->sysprof_writer = sysprof_capture_writer_new_from_env (0);
+#endif  /* HAVE_SYSPROF */
+
        priv->scale = 1;
        priv->plugins = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
        priv->pending_apps = g_ptr_array_new_with_free_func ((GFreeFunc) g_object_unref);
@@ -3094,6 +3205,9 @@ gs_plugin_loader_process_thread_cb (GTask *task,
        gboolean add_to_pending_array = FALSE;
        guint max_results;
        GsAppListSortFunc sort_func;
+#ifdef HAVE_SYSPROF
+       gint64 begin_time_nsec G_GNUC_UNUSED = SYSPROF_CAPTURE_CURRENT_TIME;
+#endif
 
        /* these change the pending count on the installed panel */
        switch (action) {
@@ -3389,6 +3503,21 @@ gs_plugin_loader_process_thread_cb (GTask *task,
        if (priv->updates_changed_cnt > 0)
                gs_plugin_loader_updates_changed (plugin_loader);
 
+#ifdef HAVE_SYSPROF
+       if (priv->sysprof_writer != NULL) {
+               g_autofree gchar *sysprof_name = g_strconcat ("process-thread:", gs_plugin_action_to_string 
(action), NULL);
+               g_autofree gchar *sysprof_message = gs_plugin_job_to_string (helper->plugin_job);
+               sysprof_capture_writer_add_mark (priv->sysprof_writer,
+                                                begin_time_nsec,
+                                                sched_getcpu (),
+                                                getpid (),
+                                                SYSPROF_CAPTURE_CURRENT_TIME - begin_time_nsec,
+                                                "gnome-software",
+                                                sysprof_name,
+                                                sysprof_message);
+       }
+#endif  /* HAVE_SYSPROF */
+
        /* show elapsed time */
        gs_plugin_loader_job_debug (helper);
 
diff --git a/lib/meson.build b/lib/meson.build
index e792c2ab..8e896163 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -33,6 +33,7 @@ librarydeps = [
   json_glib,
   libm,
   libsoup,
+  sysprof,
   valgrind,
 ]
 
diff --git a/meson.build b/meson.build
index 8eb9ae20..a44a2351 100644
--- a/meson.build
+++ b/meson.build
@@ -110,6 +110,9 @@ json_glib = dependency('json-glib-1.0', version : '>= 1.2.0')
 libm = cc.find_library('m', required: false)
 libsoup = dependency('libsoup-2.4', version : '>= 2.52.0')
 
+sysprof = dependency('sysprof-capture-3', required: get_option('sysprof'))
+conf.set('HAVE_SYSPROF', sysprof.found())
+
 if get_option('mogwai')
   mogwai_schedule_client = dependency('mogwai-schedule-client-0', version : '>= 0.2.0')
   conf.set('HAVE_MOGWAI', 1)
diff --git a/meson_options.txt b/meson_options.txt
index f6068ba5..8d4ad0d1 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -19,3 +19,4 @@ option('gtk_doc', type : 'boolean', value : true, description : 'enable API refe
 option('hardcoded_popular', type : 'boolean', value : true, description : 'enable hardcoded-popular apps 
plugin')
 option('default_featured_apps', type : 'boolean', value : true, description : 'enable installation of 
default featured apps list')
 option('mogwai', type : 'boolean', value : false, description : 'enable metered data support using Mogwai')
+option('sysprof', type : 'feature', value : 'auto', description : 'enable sysprof-capture support for 
profiling')


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