Commit 4b67aabe authored by Philip Withnall's avatar Philip Withnall Committed by Philip Withnall

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's avatarPhilip Withnall <withnall@endlessm.com>
parent 92c30f1d
Pipeline #193516 passed with stage
in 3 minutes and 6 seconds
...@@ -13,6 +13,10 @@ ...@@ -13,6 +13,10 @@
#include <appstream-glib.h> #include <appstream-glib.h>
#include <math.h> #include <math.h>
#ifdef HAVE_SYSPROF
#include <sysprof-capture.h>
#endif
#include "gs-app-collation.h" #include "gs-app-collation.h"
#include "gs-app-private.h" #include "gs-app-private.h"
#include "gs-app-list-private.h" #include "gs-app-list-private.h"
...@@ -61,6 +65,10 @@ typedef struct ...@@ -61,6 +65,10 @@ typedef struct
gulong network_changed_handler; gulong network_changed_handler;
gulong network_available_notify_handler; gulong network_available_notify_handler;
gulong network_metered_notify_handler; gulong network_metered_notify_handler;
#ifdef HAVE_SYSPROF
SysprofCaptureWriter *sysprof_writer; /* (owned) (nullable) */
#endif
} GsPluginLoaderPrivate; } GsPluginLoaderPrivate;
static void gs_plugin_loader_monitor_network (GsPluginLoader *plugin_loader); static void gs_plugin_loader_monitor_network (GsPluginLoader *plugin_loader);
...@@ -498,11 +506,17 @@ gs_plugin_loader_call_vfunc (GsPluginLoaderHelper *helper, ...@@ -498,11 +506,17 @@ gs_plugin_loader_call_vfunc (GsPluginLoaderHelper *helper,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) 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); GsPluginAction action = gs_plugin_job_get_action (helper->plugin_job);
gboolean ret = TRUE; gboolean ret = TRUE;
gpointer func = NULL; gpointer func = NULL;
g_autoptr(GError) error_local = NULL; g_autoptr(GError) error_local = NULL;
g_autoptr(GTimer) timer = g_timer_new (); g_autoptr(GTimer) timer = g_timer_new ();
#ifdef HAVE_SYSPROF
gint64 begin_time_nsec = SYSPROF_CAPTURE_CURRENT_TIME;
#endif
/* load the possible symbol */ /* load the possible symbol */
func = gs_plugin_get_symbol (plugin, helper->function_name); func = gs_plugin_get_symbol (plugin, helper->function_name);
...@@ -737,6 +751,24 @@ gs_plugin_loader_call_vfunc (GsPluginLoaderHelper *helper, ...@@ -737,6 +751,24 @@ gs_plugin_loader_call_vfunc (GsPluginLoaderHelper *helper,
add_app_to_install_queue (helper->plugin_loader, app); 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 */ /* check the plugin didn't take too long */
switch (action) { switch (action) {
case GS_PLUGIN_ACTION_INITIALIZE: case GS_PLUGIN_ACTION_INITIALIZE:
...@@ -1069,6 +1101,9 @@ gs_plugin_loader_run_results (GsPluginLoaderHelper *helper, ...@@ -1069,6 +1101,9 @@ gs_plugin_loader_run_results (GsPluginLoaderHelper *helper,
GError **error) GError **error)
{ {
GsPluginLoaderPrivate *priv = gs_plugin_loader_get_instance_private (helper->plugin_loader); 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 */ /* run each plugin */
for (guint i = 0; i < priv->plugins->len; i++) { for (guint i = 0; i < priv->plugins->len; i++) {
...@@ -1084,6 +1119,27 @@ gs_plugin_loader_run_results (GsPluginLoaderHelper *helper, ...@@ -1084,6 +1119,27 @@ gs_plugin_loader_run_results (GsPluginLoaderHelper *helper,
} }
gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED); 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; return TRUE;
} }
...@@ -1511,6 +1567,10 @@ gs_plugin_loader_job_get_categories_thread_cb (GTask *task, ...@@ -1511,6 +1567,10 @@ gs_plugin_loader_job_get_categories_thread_cb (GTask *task,
{ {
GError *error = NULL; GError *error = NULL;
GsPluginLoaderHelper *helper = (GsPluginLoaderHelper *) task_data; 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 */ /* run each plugin */
if (!gs_plugin_loader_run_results (helper, cancellable, &error)) { if (!gs_plugin_loader_run_results (helper, cancellable, &error)) {
...@@ -1531,19 +1591,30 @@ gs_plugin_loader_job_get_categories_thread_cb (GTask *task, ...@@ -1531,19 +1591,30 @@ gs_plugin_loader_job_get_categories_thread_cb (GTask *task,
gs_category_sort_children (cat); gs_category_sort_children (cat);
} }
/* success */ #ifdef HAVE_SYSPROF
if (helper->catlist->len == 0) { if (priv->sysprof_writer != NULL) {
g_task_return_new_error (task, g_autofree gchar *sysprof_message = gs_plugin_job_to_string (helper->plugin_job);
GS_PLUGIN_ERROR, sysprof_capture_writer_add_mark (priv->sysprof_writer,
GS_PLUGIN_ERROR_NOT_SUPPORTED, begin_time_nsec,
"no categories to show"); sched_getcpu (),
return; getpid (),
SYSPROF_CAPTURE_CURRENT_TIME - begin_time_nsec,
"gnome-software",
"get-categories",
sysprof_message);
} }
#endif /* HAVE_SYSPROF */
/* show elapsed time */ /* show elapsed time */
gs_plugin_loader_job_debug (helper); gs_plugin_loader_job_debug (helper);
/* success */ /* success */
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); 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) ...@@ -2244,6 +2315,9 @@ gs_plugin_loader_setup_again (GsPluginLoader *plugin_loader)
GS_PLUGIN_ACTION_INITIALIZE, GS_PLUGIN_ACTION_INITIALIZE,
GS_PLUGIN_ACTION_SETUP, GS_PLUGIN_ACTION_SETUP,
GS_PLUGIN_ACTION_UNKNOWN }; GS_PLUGIN_ACTION_UNKNOWN };
#ifdef HAVE_SYSPROF
gint64 begin_time_nsec G_GNUC_UNUSED = SYSPROF_CAPTURE_CURRENT_TIME;
#endif
/* clear global cache */ /* clear global cache */
gs_plugin_loader_clear_caches (plugin_loader); gs_plugin_loader_clear_caches (plugin_loader);
...@@ -2275,6 +2349,19 @@ gs_plugin_loader_setup_again (GsPluginLoader *plugin_loader) ...@@ -2275,6 +2349,19 @@ gs_plugin_loader_setup_again (GsPluginLoader *plugin_loader)
gs_plugin_clear_data (plugin); 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 static gint
...@@ -2332,6 +2419,9 @@ gs_plugin_loader_setup (GsPluginLoader *plugin_loader, ...@@ -2332,6 +2419,9 @@ gs_plugin_loader_setup (GsPluginLoader *plugin_loader,
guint j; guint j;
g_autoptr(GsPluginLoaderHelper) helper = NULL; g_autoptr(GsPluginLoaderHelper) helper = NULL;
g_autoptr(GsPluginJob) plugin_job = 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' */ /* use the default, but this requires a 'make install' */
if (priv->locations->len == 0) { if (priv->locations->len == 0) {
...@@ -2546,6 +2636,20 @@ gs_plugin_loader_setup (GsPluginLoader *plugin_loader, ...@@ -2546,6 +2636,20 @@ gs_plugin_loader_setup (GsPluginLoader *plugin_loader,
/* now we can load the install-queue */ /* now we can load the install-queue */
if (!load_install_queue (plugin_loader, error)) if (!load_install_queue (plugin_loader, error))
return FALSE; 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; return TRUE;
} }
...@@ -2654,6 +2758,9 @@ gs_plugin_loader_dispose (GObject *object) ...@@ -2654,6 +2758,9 @@ gs_plugin_loader_dispose (GObject *object)
g_clear_object (&priv->soup_session); g_clear_object (&priv->soup_session);
g_clear_object (&priv->settings); g_clear_object (&priv->settings);
g_clear_pointer (&priv->pending_apps, g_ptr_array_unref); 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); G_OBJECT_CLASS (gs_plugin_loader_parent_class)->dispose (object);
} }
...@@ -2782,6 +2889,10 @@ gs_plugin_loader_init (GsPluginLoader *plugin_loader) ...@@ -2782,6 +2889,10 @@ gs_plugin_loader_init (GsPluginLoader *plugin_loader)
gchar **projects; gchar **projects;
guint i; guint i;
#ifdef HAVE_SYSPROF
priv->sysprof_writer = sysprof_capture_writer_new_from_env (0);
#endif /* HAVE_SYSPROF */
priv->scale = 1; priv->scale = 1;
priv->plugins = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); 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); 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, ...@@ -3094,6 +3205,9 @@ gs_plugin_loader_process_thread_cb (GTask *task,
gboolean add_to_pending_array = FALSE; gboolean add_to_pending_array = FALSE;
guint max_results; guint max_results;
GsAppListSortFunc sort_func; 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 */ /* these change the pending count on the installed panel */
switch (action) { switch (action) {
...@@ -3389,6 +3503,21 @@ gs_plugin_loader_process_thread_cb (GTask *task, ...@@ -3389,6 +3503,21 @@ gs_plugin_loader_process_thread_cb (GTask *task,
if (priv->updates_changed_cnt > 0) if (priv->updates_changed_cnt > 0)
gs_plugin_loader_updates_changed (plugin_loader); 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 */ /* show elapsed time */
gs_plugin_loader_job_debug (helper); gs_plugin_loader_job_debug (helper);
......
...@@ -33,6 +33,7 @@ librarydeps = [ ...@@ -33,6 +33,7 @@ librarydeps = [
json_glib, json_glib,
libm, libm,
libsoup, libsoup,
sysprof,
valgrind, valgrind,
] ]
......
...@@ -110,6 +110,9 @@ json_glib = dependency('json-glib-1.0', version : '>= 1.2.0') ...@@ -110,6 +110,9 @@ json_glib = dependency('json-glib-1.0', version : '>= 1.2.0')
libm = cc.find_library('m', required: false) libm = cc.find_library('m', required: false)
libsoup = dependency('libsoup-2.4', version : '>= 2.52.0') 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') if get_option('mogwai')
mogwai_schedule_client = dependency('mogwai-schedule-client-0', version : '>= 0.2.0') mogwai_schedule_client = dependency('mogwai-schedule-client-0', version : '>= 0.2.0')
conf.set('HAVE_MOGWAI', 1) conf.set('HAVE_MOGWAI', 1)
......
...@@ -19,3 +19,4 @@ option('gtk_doc', type : 'boolean', value : true, description : 'enable API refe ...@@ -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('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('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('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')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment