From 90c6d87a8ca688d59e155d9238f6f82a3254cc6a Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Thu, 20 Jul 2023 17:02:56 -0700 Subject: [PATCH] libsysprof: implement callgraph frame summaries --- src/libsysprof/sysprof-callgraph-frame.c | 19 ++++++++++ src/libsysprof/tests/test-callgraph.c | 47 ++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/libsysprof/sysprof-callgraph-frame.c b/src/libsysprof/sysprof-callgraph-frame.c index 2ec8a918..9e493034 100644 --- a/src/libsysprof/sysprof-callgraph-frame.c +++ b/src/libsysprof/sysprof-callgraph-frame.c @@ -519,6 +519,25 @@ static void summarize_node (const SysprofCallgraphNode *node, Summary *summaries) { + if (node->is_toplevel && + node->category != 0 && + node->category != SYSPROF_CALLGRAPH_CATEGORY_PRESENTATION) + { + gboolean seen[SYSPROF_CALLGRAPH_CATEGORY_LAST] = {0}; + + seen[node->category & 0xFF] = TRUE; + summaries[node->category & 0xFF].count += node->count; + + for (const SysprofCallgraphNode *parent = node->parent; parent; parent = parent->parent) + { + if (!seen[parent->category & 0xFF] && (parent->category & SYSPROF_CALLGRAPH_CATEGORY_INHERIT) != 0) + { + seen[parent->category & 0xFF] = TRUE; + summaries[parent->category & 0xFF].count += node->count; + } + } + } + for (const SysprofCallgraphNode *iter = node->children; iter; iter = iter->next) summarize_node (iter, summaries); } diff --git a/src/libsysprof/tests/test-callgraph.c b/src/libsysprof/tests/test-callgraph.c index b6856853..7a10d694 100644 --- a/src/libsysprof/tests/test-callgraph.c +++ b/src/libsysprof/tests/test-callgraph.c @@ -35,9 +35,11 @@ typedef struct _Augment static char *kallsyms_path; static gboolean include_threads; static GEnumClass *category_class; +static gboolean summary_only; static const GOptionEntry entries[] = { { "kallsyms", 'k', 0, G_OPTION_ARG_FILENAME, &kallsyms_path, "The path to kallsyms to use for decoding", "PATH" }, { "threads", 't', 0, G_OPTION_ARG_NONE, &include_threads, "Include threads in the stack traces" }, + { "summary", 's', 0, G_OPTION_ARG_NONE, &summary_only, "Only show summary" }, { 0 } }; @@ -68,6 +70,42 @@ print_callgraph (GListModel *model, } } +static void +summarize_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + SysprofCallgraphFrame *frame = SYSPROF_CALLGRAPH_FRAME (object); + GMainLoop *main_loop = user_data; + g_autoptr(GError) error = NULL; + g_autoptr(GListModel) model = NULL; + guint n_items; + + model = sysprof_callgraph_frame_summarize_finish (frame, result, &error); + g_assert_no_error (error); + g_assert_nonnull (model); + g_assert_true (G_IS_LIST_MODEL (model)); + + g_print ("\n\nSummary\n"); + + n_items = g_list_model_get_n_items (model); + + for (guint i = 0; i < n_items; i++) + { + g_autoptr(SysprofCategorySummary) summary = g_list_model_get_item (model, i); + + g_assert_nonnull (summary); + g_assert_true (SYSPROF_IS_CATEGORY_SUMMARY (summary)); + + g_print ("%s: %lf\n", + g_enum_to_string (SYSPROF_TYPE_CALLGRAPH_CATEGORY, + sysprof_category_summary_get_category (summary)), + sysprof_category_summary_get_fraction (summary)); + } + + g_main_loop_quit (main_loop); +} + static void callgraph_cb (GObject *object, GAsyncResult *result, @@ -86,10 +124,13 @@ callgraph_cb (GObject *object, root = g_list_model_get_item (G_LIST_MODEL (callgraph), 0); aug = sysprof_callgraph_frame_get_augment (root); - g_print (" Hits Percent\n"); - print_callgraph (G_LIST_MODEL (callgraph), 0, aug->total); + if (!summary_only) + { + g_print (" Hits Percent\n"); + print_callgraph (G_LIST_MODEL (callgraph), 0, aug->total); + } - g_main_loop_quit (main_loop); + sysprof_callgraph_frame_summarize_async (root, NULL, summarize_cb, main_loop); } static void