From 92d2cedb8d2cbf1177564a90e13fca450c874158 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Thu, 20 Jul 2023 11:26:10 -0700 Subject: [PATCH] libsysprof: add API to categorize callgraph This just gets the plumbing in place with some basic categorization for callgraph information. The real work of categorizing by nick/symbol still needs to be done (some can be copied from SysprofCategoryIcon). This also adds a property and getter for SysprofCallgraphFrame which will expose the node's category to the UI code. --- src/libsysprof/sysprof-callgraph-frame.c | 32 +++++++++++ src/libsysprof/sysprof-callgraph-private.h | 13 +++-- src/libsysprof/sysprof-callgraph.c | 49 ++++++++++++++++ src/libsysprof/sysprof-callgraph.h | 66 ++++++++++++++-------- 4 files changed, 132 insertions(+), 28 deletions(-) diff --git a/src/libsysprof/sysprof-callgraph-frame.c b/src/libsysprof/sysprof-callgraph-frame.c index b2c61293..19ea103d 100644 --- a/src/libsysprof/sysprof-callgraph-frame.c +++ b/src/libsysprof/sysprof-callgraph-frame.c @@ -24,6 +24,7 @@ #include "sysprof-callgraph-private.h" #include "sysprof-callgraph-frame-private.h" +#include "sysprof-enums.h" #include "sysprof-symbol-private.h" #include "sysprof-document-bitset-index-private.h" @@ -43,6 +44,7 @@ struct _SysprofCallgraphFrame enum { PROP_0, PROP_CALLGRAPH, + PROP_CATEGORY, PROP_SYMBOL, PROP_N_ITEMS, N_PROPS @@ -123,6 +125,10 @@ sysprof_callgraph_frame_get_property (GObject *object, g_value_set_object (value, self->callgraph); break; + case PROP_CATEGORY: + g_value_set_enum (value, sysprof_callgraph_frame_get_category (self)); + break; + case PROP_N_ITEMS: g_value_set_uint (value, g_list_model_get_n_items (G_LIST_MODEL (self))); break; @@ -149,6 +155,12 @@ sysprof_callgraph_frame_class_init (SysprofCallgraphFrameClass *klass) SYSPROF_TYPE_CALLGRAPH, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + properties [PROP_CATEGORY] = + g_param_spec_enum ("category", NULL, NULL, + SYSPROF_TYPE_CALLGRAPH_CATEGORY, + SYSPROF_CALLGRAPH_CATEGORY_UNCATEGORIZED, + (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + properties [PROP_N_ITEMS] = g_param_spec_uint ("n-items", NULL, NULL, 0, G_MAXUINT, 0, @@ -475,3 +487,23 @@ sysprof_callgraph_frame_is_leaf (SysprofCallgraphFrame *self) return self->n_children == 0; } + +/** + * sysprof_callgraph_frame_get_category: + * @self: a #SysprofCallgraphFrame + * + * Gets the category of the node if %SYSPROF_CALLGRAPH_FLAGS_CATEGORIZE_FRAMES + * was set when generating the callgraph. Otherwise 0. + * + * Returns: 0 or a callgraph category + */ +SysprofCallgraphCategory +sysprof_callgraph_frame_get_category (SysprofCallgraphFrame *self) +{ + g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_FRAME (self), 0); + + if (self->callgraph == NULL || self->node == NULL) + return 0; + + return self->node->category; +} diff --git a/src/libsysprof/sysprof-callgraph-private.h b/src/libsysprof/sysprof-callgraph-private.h index 5adeee63..5b5ca5ff 100644 --- a/src/libsysprof/sysprof-callgraph-private.h +++ b/src/libsysprof/sysprof-callgraph-private.h @@ -39,12 +39,13 @@ typedef struct _SysprofCallgraphSummary struct _SysprofCallgraphNode { - SysprofCallgraphNode *parent; - SysprofCallgraphNode *prev; - SysprofCallgraphNode *next; - SysprofCallgraphNode *children; - SysprofCallgraphSummary *summary; - gpointer augment[2]; + SysprofCallgraphNode *parent; + SysprofCallgraphNode *prev; + SysprofCallgraphNode *next; + SysprofCallgraphNode *children; + SysprofCallgraphSummary *summary; + gpointer augment[2]; + SysprofCallgraphCategory category; }; struct _SysprofCallgraph diff --git a/src/libsysprof/sysprof-callgraph.c b/src/libsysprof/sysprof-callgraph.c index aa539038..118ba745 100644 --- a/src/libsysprof/sysprof-callgraph.c +++ b/src/libsysprof/sysprof-callgraph.c @@ -283,6 +283,52 @@ reverse_symbols (SysprofSymbol **symbols, } } +static void +sysprof_callgraph_categorize (SysprofCallgraph *self, + SysprofCallgraphNode *node) +{ + SysprofSymbol *symbol = node->summary->symbol; + + if (node->category) + return; + + if (node->parent && node->parent->category == 0) + sysprof_callgraph_categorize (self, node->parent); + + switch (symbol->kind) + { + case SYSPROF_SYMBOL_KIND_ROOT: + case SYSPROF_SYMBOL_KIND_THREAD: + case SYSPROF_SYMBOL_KIND_PROCESS: + node->category = SYSPROF_CALLGRAPH_CATEGORY_PRESENTATION; + break; + + case SYSPROF_SYMBOL_KIND_CONTEXT_SWITCH: + node->category = SYSPROF_CALLGRAPH_CATEGORY_CONTEXT_SWITCH; + break; + + case SYSPROF_SYMBOL_KIND_KERNEL: + node->category = SYSPROF_CALLGRAPH_CATEGORY_KERNEL; + break; + + case SYSPROF_SYMBOL_KIND_UNWINDABLE: + node->category = SYSPROF_CALLGRAPH_CATEGORY_UNWINDABLE; + break; + + case SYSPROF_SYMBOL_KIND_USER: + + G_GNUC_FALLTHROUGH; + + default: + if (node->parent) + node->category = node->parent->category; + else + node->category = SYSPROF_CALLGRAPH_CATEGORY_UNCATEGORIZED; + break; + } + +} + static void sysprof_callgraph_add_traceable (SysprofCallgraph *self, SysprofDocumentTraceable *traceable, @@ -370,6 +416,9 @@ sysprof_callgraph_add_traceable (SysprofCallgraph *self, SYSPROF_DOCUMENT_FRAME (traceable), TRUE, self->augment_func_data); + + if ((self->flags & SYSPROF_CALLGRAPH_FLAGS_CATEGORIZE_FRAMES) != 0) + sysprof_callgraph_categorize (self, node); } static void diff --git a/src/libsysprof/sysprof-callgraph.h b/src/libsysprof/sysprof-callgraph.h index 1833d005..57509f87 100644 --- a/src/libsysprof/sysprof-callgraph.h +++ b/src/libsysprof/sysprof-callgraph.h @@ -62,46 +62,68 @@ typedef void (*SysprofAugmentationFunc) (SysprofCallgraph *callgraph, gboolean summarize, gpointer user_data); +typedef enum _SysprofCallgraphCategory +{ + SYSPROF_CALLGRAPH_CATEGORY_UNCATEGORIZED = 1, + SYSPROF_CALLGRAPH_CATEGORY_A11Y, + SYSPROF_CALLGRAPH_CATEGORY_ACTIONS, + SYSPROF_CALLGRAPH_CATEGORY_CONSTRUCTORS, + SYSPROF_CALLGRAPH_CATEGORY_CONTEXT_SWITCH, + SYSPROF_CALLGRAPH_CATEGORY_INPUT, + SYSPROF_CALLGRAPH_CATEGORY_KERNEL, + SYSPROF_CALLGRAPH_CATEGORY_LAYOUT, + SYSPROF_CALLGRAPH_CATEGORY_MAIN_LOOP, + SYSPROF_CALLGRAPH_CATEGORY_PAINT, + SYSPROF_CALLGRAPH_CATEGORY_PRESENTATION, + SYSPROF_CALLGRAPH_CATEGORY_SIGNALS, + SYSPROF_CALLGRAPH_CATEGORY_TEMPLATES, + SYSPROF_CALLGRAPH_CATEGORY_UNWINDABLE, + SYSPROF_CALLGRAPH_CATEGORY_WINDOWING, +} SysprofCallgraphCategory; + typedef enum _SysprofCallgraphFlags { SYSPROF_CALLGRAPH_FLAGS_NONE = 0, SYSPROF_CALLGRAPH_FLAGS_INCLUDE_THREADS = 1 << 1, SYSPROF_CALLGRAPH_FLAGS_HIDE_SYSTEM_LIBRARIES = 1 << 2, SYSPROF_CALLGRAPH_FLAGS_BOTTOM_UP = 1 << 3, + SYSPROF_CALLGRAPH_FLAGS_CATEGORIZE_FRAMES = 1 << 4, } SysprofCallgraphFlags; SYSPROF_AVAILABLE_IN_ALL -GListModel *sysprof_callgraph_list_symbols (SysprofCallgraph *self); +GListModel *sysprof_callgraph_list_symbols (SysprofCallgraph *self); SYSPROF_AVAILABLE_IN_ALL -GListModel *sysprof_callgraph_list_callers (SysprofCallgraph *self, - SysprofSymbol *symbol); +GListModel *sysprof_callgraph_list_callers (SysprofCallgraph *self, + SysprofSymbol *symbol); SYSPROF_AVAILABLE_IN_ALL -GListModel *sysprof_callgraph_list_traceables_for_symbol (SysprofCallgraph *self, - SysprofSymbol *symbol); +GListModel *sysprof_callgraph_list_traceables_for_symbol (SysprofCallgraph *self, + SysprofSymbol *symbol); SYSPROF_AVAILABLE_IN_ALL -GListModel *sysprof_callgraph_list_traceables_for_symbols_matching (SysprofCallgraph *self, - const char *pattern); +GListModel *sysprof_callgraph_list_traceables_for_symbols_matching (SysprofCallgraph *self, + const char *pattern); SYSPROF_AVAILABLE_IN_ALL -void sysprof_callgraph_descendants_async (SysprofCallgraph *self, - SysprofSymbol *symbol, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); +void sysprof_callgraph_descendants_async (SysprofCallgraph *self, + SysprofSymbol *symbol, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); SYSPROF_AVAILABLE_IN_ALL -GListModel *sysprof_callgraph_descendants_finish (SysprofCallgraph *self, - GAsyncResult *result, - GError **error); +GListModel *sysprof_callgraph_descendants_finish (SysprofCallgraph *self, + GAsyncResult *result, + GError **error); SYSPROF_AVAILABLE_IN_ALL -gpointer sysprof_callgraph_get_augment (SysprofCallgraph *self, - SysprofCallgraphNode *node); +gpointer sysprof_callgraph_get_augment (SysprofCallgraph *self, + SysprofCallgraphNode *node); SYSPROF_AVAILABLE_IN_ALL -gpointer sysprof_callgraph_get_summary_augment (SysprofCallgraph *self, - SysprofCallgraphNode *node); +gpointer sysprof_callgraph_get_summary_augment (SysprofCallgraph *self, + SysprofCallgraphNode *node); SYSPROF_AVAILABLE_IN_ALL -SysprofCallgraphNode *sysprof_callgraph_node_parent (SysprofCallgraphNode *node); +SysprofCallgraphNode *sysprof_callgraph_node_parent (SysprofCallgraphNode *node); SYSPROF_AVAILABLE_IN_ALL -SysprofCallgraph *sysprof_callgraph_frame_get_callgraph (SysprofCallgraphFrame *self); +SysprofCallgraph *sysprof_callgraph_frame_get_callgraph (SysprofCallgraphFrame *self); SYSPROF_AVAILABLE_IN_ALL -SysprofCallgraph *sysprof_callgraph_symbol_get_callgraph (SysprofCallgraphSymbol *self); +SysprofCallgraphCategory sysprof_callgraph_frame_get_category (SysprofCallgraphFrame *self); +SYSPROF_AVAILABLE_IN_ALL +SysprofCallgraph *sysprof_callgraph_symbol_get_callgraph (SysprofCallgraphSymbol *self); G_END_DECLS