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 @@
#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,19 +1591,30 @@ 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 */
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);
......
......@@ -33,6 +33,7 @@ librarydeps = [
json_glib,
libm,
libsoup,
sysprof,
valgrind,
]
......
......@@ -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)
......
......@@ -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')
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