From 275869b198c637b7b907656867638b7fcc81afd9 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Tue, 6 Jun 2023 17:30:13 -0700 Subject: [PATCH] libsysprof-analyze: implement basic callers listing This doesn't give us augmentation data like we would have from the existing callgraphs, but we can deal with that later. --- src/libsysprof-analyze/sysprof-callgraph.c | 67 +++++++++++++++++++++- src/libsysprof-analyze/sysprof-callgraph.h | 12 ++-- 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/libsysprof-analyze/sysprof-callgraph.c b/src/libsysprof-analyze/sysprof-callgraph.c index aff9b6b3..bf3af842 100644 --- a/src/libsysprof-analyze/sysprof-callgraph.c +++ b/src/libsysprof-analyze/sysprof-callgraph.c @@ -37,6 +37,8 @@ struct _SysprofCallgraph SysprofSymbol *everything; + GHashTable *callers; + gsize augment_size; SysprofAugmentationFunc augment_func; gpointer augment_func_data; @@ -120,6 +122,8 @@ sysprof_callgraph_finalize (GObject *object) { SysprofCallgraph *self = (SysprofCallgraph *)object; + g_clear_pointer (&self->callers, g_hash_table_unref); + g_clear_object (&self->document); g_clear_object (&self->traceables); g_clear_object (&self->everything); @@ -142,15 +146,45 @@ static void sysprof_callgraph_init (SysprofCallgraph *self) { self->everything = _sysprof_symbol_new (g_ref_string_new_intern ("[Everything]"), NULL, NULL, 0, 0); + self->callers = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_ptr_array_unref); self->root.symbol = self->everything; } +static void +sysprof_callgraph_populate_callers (SysprofCallgraph *self, + SysprofCallgraphNode *node) +{ + GHashTable *hash; + + g_assert (SYSPROF_IS_CALLGRAPH (self)); + g_assert (node != NULL); + + hash = self->callers; + + for (const SysprofCallgraphNode *iter = node; + iter != NULL && iter->parent != NULL; + iter = iter->parent) + { + GPtrArray *callers; + + if (!(callers = g_hash_table_lookup (hash, iter->symbol))) + { + callers = g_ptr_array_new (); + g_hash_table_insert (hash, iter->symbol, callers); + } + + g_assert (iter->parent->symbol != NULL); + + g_ptr_array_add (callers, iter->parent->symbol); + } +} + static SysprofCallgraphNode * sysprof_callgraph_add_trace (SysprofCallgraph *self, SysprofSymbol **symbols, guint n_symbols) { - SysprofCallgraphNode *parent; + SysprofCallgraphNode *parent = NULL; g_assert (SYSPROF_IS_CALLGRAPH (self)); g_assert (n_symbols >= 2); @@ -202,6 +236,8 @@ sysprof_callgraph_add_trace (SysprofCallgraph *self, parent = node; } + sysprof_callgraph_populate_callers (self, parent); + return parent; } @@ -341,3 +377,32 @@ sysprof_callgraph_node_parent (SysprofCallgraphNode *node) { return node->parent; } + +/** + * sysprof_callgraph_list_callers: + * @self: a #SysprofCallgraph + * @node: a #SysprofCallgraphFrame + * + * Gets a list of #SysprofSymbol that call @node. + * + * Returns: (trasfer full): a #GListModel of #SysprofSymbol + */ +GListModel * +sysprof_callgraph_list_callers (SysprofCallgraph *self, + SysprofCallgraphFrame *frame) +{ + SysprofSymbol *symbol; + GListStore *store; + GPtrArray *callers; + + g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (self), NULL); + g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_FRAME (frame), NULL); + + store = g_list_store_new (SYSPROF_TYPE_SYMBOL); + symbol = sysprof_callgraph_frame_get_symbol (frame); + + if ((callers = g_hash_table_lookup (self->callers, symbol))) + g_list_store_splice (store, 0, 0, callers->pdata, callers->len); + + return G_LIST_MODEL (store); +} diff --git a/src/libsysprof-analyze/sysprof-callgraph.h b/src/libsysprof-analyze/sysprof-callgraph.h index 5407b62d..1ae27b46 100644 --- a/src/libsysprof-analyze/sysprof-callgraph.h +++ b/src/libsysprof-analyze/sysprof-callgraph.h @@ -20,10 +20,11 @@ #pragma once -#include +#include #include +#include "sysprof-callgraph-frame.h" #include "sysprof-document-frame.h" G_BEGIN_DECLS @@ -56,9 +57,12 @@ typedef void (*SysprofAugmentationFunc) (SysprofCallgraph *callgraph, gpointer user_data); SYSPROF_AVAILABLE_IN_ALL -gpointer sysprof_callgraph_get_augment (SysprofCallgraph *callgraph, - SysprofCallgraphNode *node); +GListModel *sysprof_callgraph_list_callers (SysprofCallgraph *self, + SysprofCallgraphFrame *frame); SYSPROF_AVAILABLE_IN_ALL -SysprofCallgraphNode *sysprof_callgraph_node_parent (SysprofCallgraphNode *node); +gpointer sysprof_callgraph_get_augment (SysprofCallgraph *self, + SysprofCallgraphNode *node); +SYSPROF_AVAILABLE_IN_ALL +SysprofCallgraphNode *sysprof_callgraph_node_parent (SysprofCallgraphNode *node); G_END_DECLS