[gnome-software] Add profiling functionality that can show a boot-chart log of startup
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Add profiling functionality that can show a boot-chart log of startup
- Date: Wed, 2 Oct 2013 08:54:41 +0000 (UTC)
commit cc985e2bca398dee92a01f0efd54320144497a89
Author: Richard Hughes <richard hughsie com>
Date: Wed Oct 2 08:28:56 2013 +0100
Add profiling functionality that can show a boot-chart log of startup
src/Makefile.am | 2 +
src/gs-main.c | 7 +
src/gs-plugin-loader.c | 131 +++++++------
src/gs-plugin.h | 3 +-
src/gs-profile.c | 312 +++++++++++++++++++++++++++++
src/gs-profile.h | 66 ++++++
src/plugins/gs-plugin-packagekit-refine.c | 6 +
7 files changed, 466 insertions(+), 61 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index c15890e..81e4a2e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -57,6 +57,8 @@ gnome_software_SOURCES = \
gs-box.c \
gs-plugin.c \
gs-plugin.h \
+ gs-profile.c \
+ gs-profile.h \
gs-shell.c \
gs-shell.h \
gs-shell-details.c \
diff --git a/src/gs-main.c b/src/gs-main.c
index 03e72cb..c690b74 100644
--- a/src/gs-main.c
+++ b/src/gs-main.c
@@ -27,12 +27,14 @@
#include <locale.h>
#include "gs-application.h"
+#include "gs-profile.h"
int
main (int argc, char **argv)
{
int status = 0;
GsApplication *application;
+ GsProfile *profile;
setlocale (LC_ALL, "");
@@ -40,9 +42,14 @@ main (int argc, char **argv)
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
+ profile = gs_profile_new ();
+ gs_profile_start (profile, "GsMain");
application = gs_application_new ();
status = g_application_run (G_APPLICATION (application), argc, argv);
g_object_unref (application);
+ gs_profile_stop (profile, "GsMain");
+ gs_profile_dump (profile);
+ g_object_unref (profile);
return status;
}
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index 53472cd..c3fb460 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -25,6 +25,7 @@
#include "gs-plugin-loader.h"
#include "gs-plugin.h"
+#include "gs-profile.h"
static void gs_plugin_loader_finalize (GObject *object);
@@ -35,6 +36,7 @@ struct GsPluginLoaderPrivate
GPtrArray *plugins;
gchar *location;
GsPluginStatus status_last;
+ GsProfile *profile;
GMutex pending_apps_mutex;
GPtrArray *pending_apps;
@@ -198,16 +200,17 @@ gs_plugin_loader_list_dedupe (GsPluginLoader *plugin_loader, GList *list)
**/
static gboolean
gs_plugin_loader_run_refine (GsPluginLoader *plugin_loader,
+ const gchar *function_name_parent,
GList *list,
GCancellable *cancellable,
GError **error)
{
gboolean ret = TRUE;
+ gchar *profile_id;
GsPlugin *plugin;
const gchar *function_name = "gs_plugin_refine";
GsPluginRefineFunc plugin_func = NULL;
guint i;
- gdouble elapsed_ms;
/* run each plugin */
for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
@@ -219,18 +222,17 @@ gs_plugin_loader_run_refine (GsPluginLoader *plugin_loader,
(gpointer *) &plugin_func);
if (!ret)
continue;
- g_debug ("run %s on %s", function_name,
- g_module_name (plugin->module));
- g_timer_start (plugin->timer);
+ profile_id = g_strdup_printf ("GsPlugin::%s(%s;%s)",
+ plugin->name,
+ function_name_parent,
+ function_name);
+ gs_profile_start (plugin_loader->priv->profile, profile_id);
ret = plugin_func (plugin, list, cancellable, error);
if (!ret)
goto out;
gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
- elapsed_ms = g_timer_elapsed (plugin->timer, NULL) * 1000;
- if (elapsed_ms > 1) {
- g_debug ("%s(%s) took %.0fms",
- plugin->name, function_name, elapsed_ms);
- }
+ gs_profile_stop (plugin_loader->priv->profile, profile_id);
+ g_free (profile_id);
}
/* success */
@@ -249,17 +251,23 @@ gs_plugin_loader_run_results (GsPluginLoader *plugin_loader,
GError **error)
{
gboolean ret = TRUE;
+ gchar *profile_id_parent;
+ gchar *profile_id;
GList *list = NULL;
GsPlugin *plugin;
GsPluginResultsFunc plugin_func = NULL;
guint i;
- gdouble elapsed_ms;
g_return_val_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader), NULL);
g_return_val_if_fail (function_name != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+ /* profile */
+ profile_id_parent = g_strdup_printf ("GsPlugin::*(%s)",
+ function_name);
+ gs_profile_start (plugin_loader->priv->profile, profile_id_parent);
+
/* run each plugin */
for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
plugin = g_ptr_array_index (plugin_loader->priv->plugins, i);
@@ -275,21 +283,16 @@ gs_plugin_loader_run_results (GsPluginLoader *plugin_loader,
(gpointer *) &plugin_func);
if (!ret)
continue;
- g_debug ("run %s on %s", function_name,
- g_module_name (plugin->module));
- g_timer_start (plugin->timer);
-
+ profile_id = g_strdup_printf ("GsPlugin::%s(%s)",
+ plugin->name, function_name);
+ gs_profile_start (plugin_loader->priv->profile, profile_id);
g_assert (error == NULL || *error == NULL);
ret = plugin_func (plugin, &list, cancellable, error);
if (!ret)
goto out;
-
gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
- elapsed_ms = g_timer_elapsed (plugin->timer, NULL) * 1000;
- if (elapsed_ms > 1) {
- g_debug ("%s(%s) took %.0fms",
- plugin->name, function_name, elapsed_ms);
- }
+ gs_profile_stop (plugin_loader->priv->profile, profile_id);
+ g_free (profile_id);
}
/* dedupe applications we already know about */
@@ -297,6 +300,7 @@ gs_plugin_loader_run_results (GsPluginLoader *plugin_loader,
/* run refine() on each one */
ret = gs_plugin_loader_run_refine (plugin_loader,
+ function_name,
list,
cancellable,
error);
@@ -306,6 +310,9 @@ gs_plugin_loader_run_results (GsPluginLoader *plugin_loader,
/* remove duplicates */
list = gs_plugin_loader_list_uniq (plugin_loader, list);
+ /* profile */
+ gs_profile_stop (plugin_loader->priv->profile, profile_id_parent);
+
/* no results */
if (list == NULL) {
g_set_error (error,
@@ -315,6 +322,7 @@ gs_plugin_loader_run_results (GsPluginLoader *plugin_loader,
goto out;
}
out:
+ g_free (profile_id_parent);
if (!ret) {
gs_plugin_list_free (list);
list = NULL;
@@ -1086,13 +1094,13 @@ gs_plugin_loader_search_thread_cb (GSimpleAsyncResult *res,
{
const gchar *function_name = "gs_plugin_add_search";
gboolean ret = TRUE;
+ gchar *profile_id;
GError *error = NULL;
GsPluginLoaderAsyncState *state = (GsPluginLoaderAsyncState *) g_object_get_data (G_OBJECT
(cancellable), "state");
GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
GsPlugin *plugin;
GsPluginSearchFunc plugin_func = NULL;
guint i;
- gdouble elapsed_ms;
/* run each plugin */
for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
@@ -1110,9 +1118,9 @@ gs_plugin_loader_search_thread_cb (GSimpleAsyncResult *res,
(gpointer *) &plugin_func);
if (!ret)
continue;
- g_debug ("run %s on %s", function_name,
- g_module_name (plugin->module));
- g_timer_start (plugin->timer);
+ profile_id = g_strdup_printf ("GsPlugin::%s(%s)",
+ plugin->name, function_name);
+ gs_profile_start (plugin_loader->priv->profile, profile_id);
ret = plugin_func (plugin, state->value, &state->list, cancellable, &error);
if (!ret) {
gs_plugin_loader_get_all_state_finish (state, error);
@@ -1120,11 +1128,8 @@ gs_plugin_loader_search_thread_cb (GSimpleAsyncResult *res,
goto out;
}
gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
- elapsed_ms = g_timer_elapsed (plugin->timer, NULL) * 1000;
- if (elapsed_ms > 1) {
- g_debug ("%s(%s) took %.0fms",
- plugin->name, function_name, elapsed_ms);
- }
+ gs_profile_stop (plugin_loader->priv->profile, profile_id);
+ g_free (profile_id);
}
/* dedupe applications we already know about */
@@ -1132,6 +1137,7 @@ gs_plugin_loader_search_thread_cb (GSimpleAsyncResult *res,
/* run refine() on each one */
ret = gs_plugin_loader_run_refine (plugin_loader,
+ function_name,
state->list,
cancellable,
&error);
@@ -1270,6 +1276,7 @@ gs_plugin_loader_get_categories_thread_cb (GSimpleAsyncResult *res,
{
const gchar *function_name = "gs_plugin_add_categories";
gboolean ret = TRUE;
+ gchar *profile_id;
GError *error = NULL;
GsPluginLoaderAsyncState *state = (GsPluginLoaderAsyncState *) g_object_get_data (G_OBJECT
(cancellable), "state");
GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
@@ -1277,7 +1284,6 @@ gs_plugin_loader_get_categories_thread_cb (GSimpleAsyncResult *res,
GsPluginResultsFunc plugin_func = NULL;
GList *l;
guint i;
- gdouble elapsed_ms;
/* run each plugin */
for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
@@ -1295,9 +1301,9 @@ gs_plugin_loader_get_categories_thread_cb (GSimpleAsyncResult *res,
(gpointer *) &plugin_func);
if (!ret)
continue;
- g_debug ("run %s on %s", function_name,
- g_module_name (plugin->module));
- g_timer_start (plugin->timer);
+ profile_id = g_strdup_printf ("GsPlugin::%s(%s)",
+ plugin->name, function_name);
+ gs_profile_start (plugin_loader->priv->profile, profile_id);
ret = plugin_func (plugin, &state->list, cancellable, &error);
if (!ret) {
gs_plugin_loader_get_all_state_finish (state, error);
@@ -1305,11 +1311,8 @@ gs_plugin_loader_get_categories_thread_cb (GSimpleAsyncResult *res,
goto out;
}
gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
- elapsed_ms = g_timer_elapsed (plugin->timer, NULL) * 1000;
- if (elapsed_ms > 1) {
- g_debug ("%s(%s) took %.0fms",
- plugin->name, function_name, elapsed_ms);
- }
+ gs_profile_stop (plugin_loader->priv->profile, profile_id);
+ g_free (profile_id);
}
/* sort by name */
@@ -1412,13 +1415,13 @@ gs_plugin_loader_get_category_apps_thread_cb (GSimpleAsyncResult *res,
{
const gchar *function_name = "gs_plugin_add_category_apps";
gboolean ret = TRUE;
+ gchar *profile_id;
GError *error = NULL;
GsPluginLoaderAsyncState *state = (GsPluginLoaderAsyncState *) g_object_get_data (G_OBJECT
(cancellable), "state");
GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
GsPlugin *plugin;
GsPluginCategoryFunc plugin_func = NULL;
guint i;
- gdouble elapsed_ms;
/* run each plugin */
for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
@@ -1436,9 +1439,9 @@ gs_plugin_loader_get_category_apps_thread_cb (GSimpleAsyncResult *res,
(gpointer *) &plugin_func);
if (!ret)
continue;
- g_debug ("run %s on %s", function_name,
- g_module_name (plugin->module));
- g_timer_start (plugin->timer);
+ profile_id = g_strdup_printf ("GsPlugin::%s(%s)",
+ plugin->name, function_name);
+ gs_profile_start (plugin_loader->priv->profile, profile_id);
ret = plugin_func (plugin, state->category, &state->list, cancellable, &error);
if (!ret) {
gs_plugin_loader_get_all_state_finish (state, error);
@@ -1446,11 +1449,8 @@ gs_plugin_loader_get_category_apps_thread_cb (GSimpleAsyncResult *res,
goto out;
}
gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
- elapsed_ms = g_timer_elapsed (plugin->timer, NULL) * 1000;
- if (elapsed_ms > 1) {
- g_debug ("%s(%s) took %.0fms",
- plugin->name, function_name, elapsed_ms);
- }
+ gs_profile_stop (plugin_loader->priv->profile, profile_id);
+ g_free (profile_id);
}
/* dedupe applications we already know about */
@@ -1458,6 +1458,7 @@ gs_plugin_loader_get_category_apps_thread_cb (GSimpleAsyncResult *res,
/* run refine() on each one */
ret = gs_plugin_loader_run_refine (plugin_loader,
+ function_name,
state->list,
cancellable,
&error);
@@ -1594,11 +1595,11 @@ gs_plugin_loader_run_action (GsPluginLoader *plugin_loader,
gboolean exists;
gboolean ret = FALSE;
gboolean anything_ran = FALSE;
+ gchar *profile_id;
GError *error_local = NULL;
GsPluginActionFunc plugin_func = NULL;
GsPlugin *plugin;
guint i;
- gdouble elapsed_ms;
/* run each plugin */
for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
@@ -1615,9 +1616,9 @@ gs_plugin_loader_run_action (GsPluginLoader *plugin_loader,
(gpointer *) &plugin_func);
if (!exists)
continue;
- g_debug ("run %s on %s", function_name,
- g_module_name (plugin->module));
- g_timer_start (plugin->timer);
+ profile_id = g_strdup_printf ("GsPlugin::%s(%s)",
+ plugin->name, function_name);
+ gs_profile_start (plugin_loader->priv->profile, profile_id);
ret = plugin_func (plugin, app, cancellable, &error_local);
if (!ret) {
if (g_error_matches (error_local,
@@ -1633,11 +1634,8 @@ gs_plugin_loader_run_action (GsPluginLoader *plugin_loader,
}
}
gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
- elapsed_ms = g_timer_elapsed (plugin->timer, NULL) * 1000;
- if (elapsed_ms > 1) {
- g_debug ("%s(%s) took %.0fms",
- plugin->name, function_name, elapsed_ms);
- }
+ gs_profile_stop (plugin_loader->priv->profile, profile_id);
+ g_free (profile_id);
anything_ran = TRUE;
}
@@ -1852,6 +1850,7 @@ gs_plugin_loader_app_refine (GsPluginLoader *plugin_loader,
gs_plugin_add_app (&list, app);
ret = gs_plugin_loader_run_refine (plugin_loader,
+ NULL,
list,
cancellable,
error);
@@ -1869,6 +1868,7 @@ static void
gs_plugin_loader_run (GsPluginLoader *plugin_loader, const gchar *function_name)
{
gboolean ret;
+ gchar *profile_id;
GsPluginFunc plugin_func = NULL;
GsPlugin *plugin;
guint i;
@@ -1882,9 +1882,12 @@ gs_plugin_loader_run (GsPluginLoader *plugin_loader, const gchar *function_name)
if (!ret)
continue;
gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
- g_debug ("run %s on %s", function_name,
- g_module_name (plugin->module));
+ profile_id = g_strdup_printf ("GsPlugin::%s(%s)",
+ plugin->name, function_name);
+ gs_profile_start (plugin_loader->priv->profile, profile_id);
plugin_func (plugin);
+ gs_profile_stop (plugin_loader->priv->profile, profile_id);
+ g_free (profile_id);
}
}
@@ -1983,9 +1986,9 @@ gs_plugin_loader_open_plugin (GsPluginLoader *plugin_loader,
plugin->pixbuf_size = 64;
plugin->priority = plugin_prio (plugin);
plugin->name = g_strdup (plugin_name ());
- plugin->timer = g_timer_new ();
plugin->status_update_fn = gs_plugin_loader_status_update_cb;
plugin->status_update_user_data = plugin_loader;
+ plugin->profile = g_object_ref (plugin_loader->priv->profile);
g_debug ("opened plugin %s: %s", filename, plugin->name);
/* add to array */
@@ -2101,8 +2104,8 @@ gs_plugin_loader_plugin_free (GsPlugin *plugin)
{
g_free (plugin->priv);
g_free (plugin->name);
+ g_object_unref (plugin->profile);
g_module_close (plugin->module);
- g_timer_destroy (plugin->timer);
g_slice_free (GsPlugin, plugin);
}
@@ -2145,6 +2148,7 @@ gs_plugin_loader_init (GsPluginLoader *plugin_loader)
plugin_loader->priv->plugins = g_ptr_array_new_with_free_func ((GDestroyNotify)
gs_plugin_loader_plugin_free);
plugin_loader->priv->status_last = GS_PLUGIN_STATUS_LAST;
plugin_loader->priv->pending_apps = g_ptr_array_new_with_free_func ((GFreeFunc) g_object_unref);
+ plugin_loader->priv->profile = gs_profile_new ();
plugin_loader->priv->app_cache = g_hash_table_new_full (g_str_hash,
g_str_equal,
NULL,
@@ -2153,6 +2157,9 @@ gs_plugin_loader_init (GsPluginLoader *plugin_loader)
g_mutex_init (&plugin_loader->priv->pending_apps_mutex);
g_mutex_init (&plugin_loader->priv->app_cache_mutex);
+ /* application start */
+ gs_profile_start (plugin_loader->priv->profile, "GsPluginLoader");
+
/* by default we only show project-less apps or compatible projects */
tmp = g_getenv ("GNOME_SOFTWARE_COMPATIBLE_PROJECTS");
if (tmp == NULL)
@@ -2176,9 +2183,13 @@ gs_plugin_loader_finalize (GObject *object)
g_return_if_fail (plugin_loader->priv != NULL);
+ /* application stop */
+ gs_profile_stop (plugin_loader->priv->profile, "GsPluginLoader");
+
/* run the plugins */
gs_plugin_loader_run (plugin_loader, "gs_plugin_destroy");
+ g_object_unref (plugin_loader->priv->profile);
g_strfreev (plugin_loader->priv->compatible_projects);
g_hash_table_unref (plugin_loader->priv->app_cache);
g_ptr_array_unref (plugin_loader->priv->pending_apps);
diff --git a/src/gs-plugin.h b/src/gs-plugin.h
index beac05e..208c1dc 100644
--- a/src/gs-plugin.h
+++ b/src/gs-plugin.h
@@ -29,6 +29,7 @@
#include "gs-app.h"
#include "gs-category.h"
+#include "gs-profile.h"
G_BEGIN_DECLS
@@ -57,9 +58,9 @@ struct GsPlugin {
gchar *name;
GsPluginPrivate *priv;
guint pixbuf_size;
- GTimer *timer;
GsPluginStatusUpdate status_update_fn;
gpointer status_update_user_data;
+ GsProfile *profile;
};
typedef enum {
diff --git a/src/gs-profile.c b/src/gs-profile.c
new file mode 100644
index 0000000..9b1d0b4
--- /dev/null
+++ b/src/gs-profile.c
@@ -0,0 +1,312 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "gs-profile.h"
+
+static void gs_profile_finalize (GObject *object);
+
+#define GS_PROFILE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_PROFILE, GsProfilePrivate))
+
+struct GsProfilePrivate
+{
+ GPtrArray *current;
+ GPtrArray *archived;
+ GMutex mutex;
+};
+
+typedef struct {
+ gchar *id;
+ gint64 time_start;
+ gint64 time_stop;
+} GsProfileItem;
+
+G_DEFINE_TYPE (GsProfile, gs_profile, G_TYPE_OBJECT)
+
+static gpointer gs_profile_object = NULL;
+
+/**
+ * gs_profile_item_free:
+ **/
+static void
+gs_profile_item_free (GsProfileItem *item)
+{
+ g_free (item->id);
+ g_free (item);
+}
+
+/**
+ * gs_profile_item_find:
+ **/
+static GsProfileItem *
+gs_profile_item_find (GPtrArray *array, const gchar *id)
+{
+ GsProfileItem *tmp;
+ guint i;
+
+ g_return_val_if_fail (id != NULL, NULL);
+
+ for (i = 0; i < array->len; i++) {
+ tmp = g_ptr_array_index (array, i);
+ if (g_strcmp0 (tmp->id, id) == 0)
+ return tmp;
+ }
+ return NULL;
+}
+
+/**
+ * gs_profile_start:
+ **/
+void
+gs_profile_start (GsProfile *profile, const gchar *id)
+{
+ GsProfileItem *item;
+
+ g_return_if_fail (GS_IS_PROFILE (profile));
+ g_return_if_fail (id != NULL);
+
+ /* lock */
+ g_mutex_lock (&profile->priv->mutex);
+
+ /* already started */
+ item = gs_profile_item_find (profile->priv->current, id);
+ if (item != NULL) {
+ g_warning ("Already a started task for %s", id);
+ goto out;
+ }
+
+ /* add new item */
+ item = g_new0 (GsProfileItem, 1);
+ item->id = g_strdup (id);
+ item->time_start = g_get_real_time ();
+ g_ptr_array_add (profile->priv->current, item);
+ g_debug ("run %s", id);
+out:
+ /* unlock */
+ g_mutex_unlock (&profile->priv->mutex);
+}
+
+/**
+ * gs_profile_start_full:
+ **/
+void
+gs_profile_start_full (GsProfile *profile, const gchar *id)
+{
+ gchar *id_thr;
+ id_thr = g_strdup_printf ("%p~%s", g_thread_self (), id);
+ gs_profile_start (profile, id_thr);
+ g_free (id_thr);
+}
+
+/**
+ * gs_profile_stop:
+ **/
+void
+gs_profile_stop (GsProfile *profile, const gchar *id)
+{
+ GsProfileItem *item;
+ gdouble elapsed_ms;
+
+ g_return_if_fail (GS_IS_PROFILE (profile));
+ g_return_if_fail (id != NULL);
+
+ /* lock */
+ g_mutex_lock (&profile->priv->mutex);
+
+ /* already started */
+ item = gs_profile_item_find (profile->priv->current, id);
+ if (item == NULL) {
+ g_warning ("Not already a started task for %s", id);
+ goto out;
+ }
+
+ /* debug */
+ elapsed_ms = (item->time_stop - item->time_start) / 1000;
+ if (elapsed_ms > 1)
+ g_debug ("%s took %.0fms", id, elapsed_ms);
+
+ /* update */
+ item->time_stop = g_get_real_time ();
+
+ /* move to archive */
+ g_ptr_array_remove (profile->priv->current, item);
+ g_ptr_array_add (profile->priv->archived, item);
+out:
+ /* unlock */
+ g_mutex_unlock (&profile->priv->mutex);
+}
+
+/**
+ * gs_profile_stop_full:
+ **/
+void
+gs_profile_stop_full (GsProfile *profile, const gchar *id)
+{
+ gchar *id_thr;
+ id_thr = g_strdup_printf ("%p~%s", g_thread_self (), id);
+ gs_profile_stop (profile, id_thr);
+ g_free (id_thr);
+}
+
+/**
+ * gs_profile_sort_cb:
+ **/
+static gint
+gs_profile_sort_cb (gconstpointer a, gconstpointer b)
+{
+ GsProfileItem *item_a = *((GsProfileItem **) a);
+ GsProfileItem *item_b = *((GsProfileItem **) b);
+ if (item_a->time_start < item_b->time_start)
+ return -1;
+ if (item_a->time_start > item_b->time_start)
+ return 1;
+ return 0;
+}
+
+/**
+ * gs_profile_dump:
+ **/
+void
+gs_profile_dump (GsProfile *profile)
+{
+ GsProfileItem *item;
+ gint64 time_start = G_MAXINT64;
+ gint64 time_stop = 0;
+ gint64 time_ms;
+ guint console_width = 86;
+ guint i;
+ guint j;
+ gdouble scale;
+ guint bar_offset;
+ guint bar_length;
+
+ g_return_if_fail (GS_IS_PROFILE (profile));
+
+ /* nothing to show */
+ if (profile->priv->archived->len == 0)
+ return;
+
+ /* get the start and end times */
+ for (i = 0; i < profile->priv->archived->len; i++) {
+ item = g_ptr_array_index (profile->priv->archived, i);
+ if (item->time_start < time_start)
+ time_start = item->time_start;
+ if (item->time_stop > time_stop)
+ time_stop = item->time_stop;
+ }
+ scale = (gdouble) console_width / (gdouble) ((time_stop - time_start) / 1000);
+
+ /* sort the list */
+ g_ptr_array_sort (profile->priv->archived, gs_profile_sort_cb);
+
+ /* dump a list of what happened when */
+ for (i = 0; i < profile->priv->archived->len; i++) {
+ item = g_ptr_array_index (profile->priv->archived, i);
+ time_ms = (item->time_stop - item->time_start) / 1000;
+ if (time_ms < 2)
+ continue;
+
+ /* print a timechart of what we've done */
+ bar_offset = scale * (item->time_start - time_start) / 1000;
+ for (j = 0; j < bar_offset; j++)
+ g_print (" ");
+ bar_length = scale * time_ms;
+ if (bar_length == 0)
+ bar_length = 1;
+ for (j = 0; j < bar_length; j++)
+ g_print ("#");
+ for (j = bar_offset + bar_length; j < console_width + 1; j++)
+ g_print (" ");
+ g_print ("@%04lims ", (item->time_stop - time_start) / 1000);
+ g_print ("%s %lims\n", item->id, time_ms);
+ }
+
+ /* not all complete */
+ if (profile->priv->current->len > 0) {
+ for (i = 0; i < profile->priv->current->len; i++) {
+ item = g_ptr_array_index (profile->priv->current, i);
+ item->time_stop = g_get_real_time ();
+ for (j = 0; j < console_width; j++)
+ g_print ("$");
+ time_ms = (item->time_stop - item->time_start) / 1000;
+ g_print (" @????ms %s %lims\n", item->id, time_ms);
+ }
+ }
+}
+
+/**
+ * gs_profile_class_init:
+ **/
+static void
+gs_profile_class_init (GsProfileClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = gs_profile_finalize;
+ g_type_class_add_private (klass, sizeof (GsProfilePrivate));
+}
+
+/**
+ * gs_profile_init:
+ **/
+static void
+gs_profile_init (GsProfile *profile)
+{
+ profile->priv = GS_PROFILE_GET_PRIVATE (profile);
+ profile->priv->current = g_ptr_array_new ();
+ profile->priv->archived = g_ptr_array_new_with_free_func ((GDestroyNotify) gs_profile_item_free);
+ g_mutex_init (&profile->priv->mutex);
+}
+
+/**
+ * gs_profile_finalize:
+ **/
+static void
+gs_profile_finalize (GObject *object)
+{
+ GsProfile *profile = GS_PROFILE (object);
+ GsProfilePrivate *priv = profile->priv;
+
+ g_ptr_array_foreach (priv->current, (GFunc) gs_profile_item_free, NULL);
+ g_ptr_array_unref (priv->current);
+ g_ptr_array_unref (priv->archived);
+
+ G_OBJECT_CLASS (gs_profile_parent_class)->finalize (object);
+}
+
+/**
+ * gs_profile_new:
+ **/
+GsProfile *
+gs_profile_new (void)
+{
+ if (gs_profile_object != NULL) {
+ g_object_ref (gs_profile_object);
+ } else {
+ gs_profile_object = g_object_new (GS_TYPE_PROFILE, NULL);
+ g_object_add_weak_pointer (gs_profile_object, &gs_profile_object);
+ }
+ return GS_PROFILE (gs_profile_object);
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-profile.h b/src/gs-profile.h
new file mode 100644
index 0000000..ff106be
--- /dev/null
+++ b/src/gs-profile.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GS_PROFILE_H
+#define __GS_PROFILE_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_PROFILE (gs_profile_get_type ())
+#define GS_PROFILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_PROFILE, GsProfile))
+#define GS_PROFILE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GS_TYPE_PROFILE, GsProfileClass))
+#define GS_IS_PROFILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_PROFILE))
+#define GS_IS_PROFILE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GS_TYPE_PROFILE))
+#define GS_PROFILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GS_TYPE_PROFILE, GsProfileClass))
+
+typedef struct GsProfilePrivate GsProfilePrivate;
+
+typedef struct
+{
+ GObject parent;
+ GsProfilePrivate *priv;
+} GsProfile;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GsProfileClass;
+
+GType gs_profile_get_type (void);
+
+GsProfile *gs_profile_new (void);
+void gs_profile_start (GsProfile *profile,
+ const gchar *id);
+void gs_profile_stop (GsProfile *profile,
+ const gchar *id);
+void gs_profile_start_full (GsProfile *profile,
+ const gchar *id);
+void gs_profile_stop_full (GsProfile *profile,
+ const gchar *id);
+void gs_profile_dump (GsProfile *profile);
+
+G_END_DECLS
+
+#endif /* __GS_PROFILE_H */
+
+/* vim: set noexpandtab: */
diff --git a/src/plugins/gs-plugin-packagekit-refine.c b/src/plugins/gs-plugin-packagekit-refine.c
index aeaf685..30a7439 100644
--- a/src/plugins/gs-plugin-packagekit-refine.c
+++ b/src/plugins/gs-plugin-packagekit-refine.c
@@ -353,6 +353,7 @@ gs_plugin_refine (GsPlugin *plugin,
GList *updatedetails_all = NULL;
/* can we resolve in one go? */
+ gs_profile_start_full (plugin->profile, "packagekit-refine[name->id]");
for (l = list; l != NULL; l = l->next) {
app = GS_APP (l->data);
if (gs_app_get_metadata_item (app, "PackageKit::package-id") != NULL)
@@ -367,8 +368,10 @@ gs_plugin_refine (GsPlugin *plugin,
cancellable,
error);
}
+ gs_profile_stop_full (plugin->profile, "packagekit-refine[name->id]");
/* add any missing ratings data */
+ gs_profile_start_full (plugin->profile, "packagekit-refine[desktop-filename->id]");
for (l = list; l != NULL; l = l->next) {
app = GS_APP (l->data);
if (gs_app_get_metadata_item (app, "PackageKit::package-id") != NULL)
@@ -384,8 +387,10 @@ gs_plugin_refine (GsPlugin *plugin,
if (!ret)
goto out;
}
+ gs_profile_stop_full (plugin->profile, "packagekit-refine[desktop-filename->id]");
/* any update details missing? */
+ gs_profile_start_full (plugin->profile, "packagekit-refine[id->update-details]");
for (l = list; l != NULL; l = l->next) {
app = GS_APP (l->data);
if (gs_app_get_state (app) != GS_APP_STATE_UPDATABLE)
@@ -402,6 +407,7 @@ gs_plugin_refine (GsPlugin *plugin,
cancellable,
error);
}
+ gs_profile_stop_full (plugin->profile, "packagekit-refine[id->update-details]");
out:
g_list_free (resolve_all);
g_list_free (updatedetails_all);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]