diff --git a/src/libsysprof-analyze/meson.build b/src/libsysprof-analyze/meson.build index 13659d9a..ae7bd11f 100644 --- a/src/libsysprof-analyze/meson.build +++ b/src/libsysprof-analyze/meson.build @@ -2,6 +2,7 @@ libsysprof_analyze_public_sources = [ 'sysprof-bundled-symbolizer.c', 'sysprof-callgraph.c', 'sysprof-callgraph-frame.c', + 'sysprof-callgraph-symbol.c', 'sysprof-document.c', 'sysprof-document-allocation.c', 'sysprof-document-counter.c', @@ -50,6 +51,7 @@ libsysprof_analyze_public_headers = [ 'sysprof-analyze.h', 'sysprof-callgraph.h', 'sysprof-callgraph-frame.h', + 'sysprof-callgraph-symbol.h', 'sysprof-bundled-symbolizer.h', 'sysprof-document.h', 'sysprof-document-allocation.h', diff --git a/src/libsysprof-analyze/sysprof-analyze.h b/src/libsysprof-analyze/sysprof-analyze.h index 4eda88a9..7e9d2518 100644 --- a/src/libsysprof-analyze/sysprof-analyze.h +++ b/src/libsysprof-analyze/sysprof-analyze.h @@ -28,6 +28,7 @@ G_BEGIN_DECLS # include "sysprof-bundled-symbolizer.h" # include "sysprof-callgraph.h" # include "sysprof-callgraph-frame.h" +# include "sysprof-callgraph-symbol.h" # include "sysprof-document.h" # include "sysprof-document-allocation.h" # include "sysprof-document-counter.h" diff --git a/src/libsysprof-analyze/sysprof-callgraph-private.h b/src/libsysprof-analyze/sysprof-callgraph-private.h index c2eb7c52..53a6da34 100644 --- a/src/libsysprof-analyze/sysprof-callgraph-private.h +++ b/src/libsysprof-analyze/sysprof-callgraph-private.h @@ -47,16 +47,36 @@ struct _SysprofCallgraphNode gpointer augment; }; -void _sysprof_callgraph_new_async (SysprofDocument *document, - GListModel *traceables, - gsize augment_size, - SysprofAugmentationFunc augment_func, - gpointer augment_func_data, - GDestroyNotify augment_func_data_destroy, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -SysprofCallgraph *_sysprof_callgraph_new_finish (GAsyncResult *result, - GError **error); +struct _SysprofCallgraph +{ + GObject parent_instance; + + SysprofDocument *document; + GListModel *traceables; + + GHashTable *symbol_to_summary; + GPtrArray *symbols; + + gsize augment_size; + SysprofAugmentationFunc augment_func; + gpointer augment_func_data; + GDestroyNotify augment_func_data_destroy; + + SysprofCallgraphNode root; +}; + +void _sysprof_callgraph_new_async (SysprofDocument *document, + GListModel *traceables, + gsize augment_size, + SysprofAugmentationFunc augment_func, + gpointer augment_func_data, + GDestroyNotify augment_func_data_destroy, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +SysprofCallgraph *_sysprof_callgraph_new_finish (GAsyncResult *result, + GError **error); +gpointer _sysprof_callgraph_get_symbol_augment (SysprofCallgraph *self, + SysprofSymbol *symbol); G_END_DECLS diff --git a/src/libsysprof-analyze/sysprof-callgraph-symbol-private.h b/src/libsysprof-analyze/sysprof-callgraph-symbol-private.h new file mode 100644 index 00000000..1c3adc97 --- /dev/null +++ b/src/libsysprof-analyze/sysprof-callgraph-symbol-private.h @@ -0,0 +1,29 @@ +/* sysprof-callgraph-symbol-private.h + * + * Copyright 2023 Christian Hergert + * + * 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 3 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, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "sysprof-callgraph.h" + +G_BEGIN_DECLS + +GListModel *_sysprof_callgraph_symbol_list_model_new (SysprofCallgraph *callgraph); + +G_END_DECLS diff --git a/src/libsysprof-analyze/sysprof-callgraph-symbol.c b/src/libsysprof-analyze/sysprof-callgraph-symbol.c new file mode 100644 index 00000000..9fe8a31a --- /dev/null +++ b/src/libsysprof-analyze/sysprof-callgraph-symbol.c @@ -0,0 +1,241 @@ +/* sysprof-callgraph-symbol.c + * + * Copyright 2023 Christian Hergert + * + * 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 3 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, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "config.h" + +#include + +#include "sysprof-callgraph-private.h" +#include "sysprof-callgraph-symbol-private.h" + +struct _SysprofCallgraphSymbol +{ + GObject parent_instance; + SysprofCallgraph *callgraph; + SysprofSymbol *symbol; +}; + +enum { + PROP_0, + PROP_CALLGRAPH, + PROP_SYMBOL, + N_PROPS +}; + +G_DEFINE_FINAL_TYPE (SysprofCallgraphSymbol, sysprof_callgraph_symbol, G_TYPE_OBJECT) + +static GParamSpec *properties [N_PROPS]; + +static void +sysprof_callgraph_symbol_finalize (GObject *object) +{ + SysprofCallgraphSymbol *self = (SysprofCallgraphSymbol *)object; + + g_clear_weak_pointer (&self->callgraph); + g_clear_object (&self->symbol); + + G_OBJECT_CLASS (sysprof_callgraph_symbol_parent_class)->finalize (object); +} + +static void +sysprof_callgraph_symbol_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofCallgraphSymbol *self = SYSPROF_CALLGRAPH_SYMBOL (object); + + switch (prop_id) + { + case PROP_CALLGRAPH: + g_value_set_object (value, self->callgraph); + break; + + case PROP_SYMBOL: + g_value_set_object (value, sysprof_callgraph_symbol_get_symbol (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_callgraph_symbol_class_init (SysprofCallgraphSymbolClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = sysprof_callgraph_symbol_finalize; + object_class->get_property = sysprof_callgraph_symbol_get_property; + + properties [PROP_CALLGRAPH] = + g_param_spec_object ("callgraph", NULL, NULL, + SYSPROF_TYPE_CALLGRAPH, + (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + properties [PROP_SYMBOL] = + g_param_spec_object ("symbol", NULL, NULL, + SYSPROF_TYPE_SYMBOL, + (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +sysprof_callgraph_symbol_init (SysprofCallgraphSymbol *self) +{ +} + +SysprofCallgraphSymbol * +_sysprof_callgraph_symbol_new (SysprofCallgraph *callgraph, + SysprofSymbol *symbol) +{ + SysprofCallgraphSymbol *self; + + g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (callgraph), NULL); + g_return_val_if_fail (SYSPROF_IS_SYMBOL (symbol), NULL); + + self = g_object_new (SYSPROF_TYPE_CALLGRAPH_SYMBOL, NULL); + g_set_weak_pointer (&self->callgraph, callgraph); + g_set_object (&self->symbol, symbol); + + return self; +} + +/** + * sysprof_callgraph_symbol_get_symbol: + * @self: a #SysprofCallgraphSymbol + * + * Gets the symbol for the symbol. + * + * Returns: (nullable) (transfer none): a #SysprofSymbol + */ +SysprofSymbol * +sysprof_callgraph_symbol_get_symbol (SysprofCallgraphSymbol *self) +{ + g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_SYMBOL (self), NULL); + + return self->symbol; +} + +/** + * sysprof_callgraph_symbol_get_summary_augment: (skip) + * @self: a #SysprofCallgraphSymbol + * + * Gets the augmentation that was attached to the summary for + * the callgraph node's symbol. + * + * Returns: (nullable) (transfer none): the augmentation data + */ +gpointer +sysprof_callgraph_symbol_get_summary_augment (SysprofCallgraphSymbol *self) +{ + g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_SYMBOL (self), NULL); + + if (self->callgraph == NULL) + return NULL; + + return _sysprof_callgraph_get_symbol_augment (self->callgraph, self->symbol); +} + +/** + * sysprof_callgraph_symbol_get_callgraph: + * @self: a #SysprofCallgraphSymbol + * + * Gets the callgraph the symbol belongs to. + * + * Returns: (transfer none) (nullable): a #SysprofCallgraph, or %NULL + */ +SysprofCallgraph * +sysprof_callgraph_symbol_get_callgraph (SysprofCallgraphSymbol *self) +{ + g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_SYMBOL (self), NULL); + + return self->callgraph; +} + +struct _SysprofCallgraphSymbolListModel +{ + GObject parent_instance; + SysprofCallgraph *callgraph; +}; + +static guint +sysprof_callgraph_symbol_list_model_get_n_items (GListModel *model) +{ + return SYSPROF_CALLGRAPH_SYMBOL (model)->callgraph->symbols->len; +} + +static GType +sysprof_callgraph_symbol_list_model_get_item_type (GListModel *model) +{ + return SYSPROF_TYPE_CALLGRAPH_SYMBOL; +} + +static gpointer +sysprof_callgraph_symbol_list_model_get_item (GListModel *model, + guint position) +{ + SysprofCallgraphSymbol *self = SYSPROF_CALLGRAPH_SYMBOL (model); + + if (position >= self->callgraph->symbols->len) + return NULL; + + return _sysprof_callgraph_symbol_new (self->callgraph, + g_ptr_array_index (self->callgraph->symbols, position)); +} + +static void +list_model_iface_init (GListModelInterface *iface) +{ + iface->get_n_items = sysprof_callgraph_symbol_list_model_get_n_items; + iface->get_item_type = sysprof_callgraph_symbol_list_model_get_item_type; + iface->get_item = sysprof_callgraph_symbol_list_model_get_item; +} + +#define SYSPROF_TYPE_CALLGRAPH_SYMBOL_LIST_MODEL (sysprof_callgraph_symbol_list_model_get_type()) +G_DECLARE_FINAL_TYPE (SysprofCallgraphSymbolListModel, sysprof_callgraph_symbol_list_model, SYSPROF, CALLGRAPH_SYMBOL_LIST_MODEL, GObject) +G_DEFINE_FINAL_TYPE_WITH_CODE (SysprofCallgraphSymbolListModel, sysprof_callgraph_symbol_list_model, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init)) + +static void +sysprof_callgraph_symbol_list_model_class_init (SysprofCallgraphSymbolListModelClass *klass) +{ +} + +static void +sysprof_callgraph_symbol_list_model_init (SysprofCallgraphSymbolListModel *self) +{ +} + +GListModel * +_sysprof_callgraph_symbol_list_model_new (SysprofCallgraph *callgraph) +{ + SysprofCallgraphSymbolListModel *self; + + g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (callgraph), NULL); + + self = g_object_new (SYSPROF_TYPE_CALLGRAPH_SYMBOL_LIST_MODEL, NULL); + self->callgraph = g_object_ref (callgraph); + + return G_LIST_MODEL (self); +} + +G_END_DECLS diff --git a/src/libsysprof-analyze/sysprof-callgraph-symbol.h b/src/libsysprof-analyze/sysprof-callgraph-symbol.h new file mode 100644 index 00000000..a6360fbd --- /dev/null +++ b/src/libsysprof-analyze/sysprof-callgraph-symbol.h @@ -0,0 +1,41 @@ +/* sysprof-callgraph-symbol.h + * + * Copyright 2023 Christian Hergert + * + * 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 3 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, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +#include + +#include "sysprof-symbol.h" + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_CALLGRAPH_SYMBOL (sysprof_callgraph_symbol_get_type()) + +SYSPROF_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (SysprofCallgraphSymbol, sysprof_callgraph_symbol, SYSPROF, CALLGRAPH_SYMBOL, GObject) + +SYSPROF_AVAILABLE_IN_ALL +SysprofSymbol *sysprof_callgraph_symbol_get_symbol (SysprofCallgraphSymbol *self); +SYSPROF_AVAILABLE_IN_ALL +gpointer sysprof_callgraph_symbol_get_summary_augment (SysprofCallgraphSymbol *self); + +G_END_DECLS diff --git a/src/libsysprof-analyze/sysprof-callgraph.c b/src/libsysprof-analyze/sysprof-callgraph.c index b6d97921..464c893b 100644 --- a/src/libsysprof-analyze/sysprof-callgraph.c +++ b/src/libsysprof-analyze/sysprof-callgraph.c @@ -22,6 +22,7 @@ #include "sysprof-callgraph-private.h" #include "sysprof-callgraph-frame-private.h" +#include "sysprof-callgraph-symbol-private.h" #include "sysprof-document-bitset-index-private.h" #include "sysprof-document-private.h" #include "sysprof-document-traceable.h" @@ -31,23 +32,6 @@ #define MAX_STACK_DEPTH 1024 -struct _SysprofCallgraph -{ - GObject parent_instance; - - SysprofDocument *document; - GListModel *traceables; - - GHashTable *symbol_to_summary; - - gsize augment_size; - SysprofAugmentationFunc augment_func; - gpointer augment_func_data; - GDestroyNotify augment_func_data_destroy; - - SysprofCallgraphNode root; -}; - static GType sysprof_callgraph_get_item_type (GListModel *model) { @@ -119,6 +103,7 @@ sysprof_callgraph_get_summary (SysprofCallgraph *self, summary->symbol = symbol; g_hash_table_insert (self->symbol_to_summary, symbol, summary); + g_ptr_array_add (self->symbols, symbol); } return summary; @@ -400,6 +385,7 @@ _sysprof_callgraph_new_async (SysprofDocument *document, self->augment_func_data = augment_func_data; self->augment_func_data_destroy = augment_func_data_destroy; self->symbol_to_summary = g_hash_table_new_full (NULL, NULL, NULL, summary_free); + self->symbols = g_ptr_array_new (); self->root.summary = sysprof_callgraph_get_summary (self, everything); task = g_task_new (NULL, cancellable, callback, user_data); @@ -453,6 +439,21 @@ sysprof_callgraph_get_summary_augment (SysprofCallgraph *self, return get_augmentation (self, &node->summary->augment); } +gpointer +_sysprof_callgraph_get_symbol_augment (SysprofCallgraph *self, + SysprofSymbol *symbol) +{ + SysprofCallgraphSummary *summary; + + g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (self), NULL); + g_return_val_if_fail (SYSPROF_IS_SYMBOL (symbol), NULL); + + if ((summary = g_hash_table_lookup (self->symbol_to_summary, symbol))) + return get_augmentation (self, &summary->augment); + + return NULL; +} + SysprofCallgraphNode * sysprof_callgraph_node_parent (SysprofCallgraphNode *node) { @@ -512,3 +513,20 @@ sysprof_callgraph_list_traceables_for_symbol (SysprofCallgraph *self, return G_LIST_MODEL (g_list_store_new (SYSPROF_TYPE_DOCUMENT_TRACEABLE)); } + +/** + * sysprof_callgraph_list_symbols: + * @self: a #SysprofCallgraph + * + * Gets a #GListModel of #SysprofCallgraphSymbol that an be used to + * display a function list and associated augmentation data. + * + * Returns: (transfer full): a #GListModel of #SysprofCallgraphSymbol + */ +GListModel * +sysprof_callgraph_list_symbols (SysprofCallgraph *self) +{ + g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (self), NULL); + + return _sysprof_callgraph_symbol_list_model_new (self); +} diff --git a/src/libsysprof-analyze/sysprof-callgraph.h b/src/libsysprof-analyze/sysprof-callgraph.h index 85c19493..3dfbad4b 100644 --- a/src/libsysprof-analyze/sysprof-callgraph.h +++ b/src/libsysprof-analyze/sysprof-callgraph.h @@ -25,6 +25,7 @@ #include #include "sysprof-callgraph-frame.h" +#include "sysprof-callgraph-symbol.h" #include "sysprof-document-frame.h" G_BEGIN_DECLS @@ -57,20 +58,24 @@ typedef void (*SysprofAugmentationFunc) (SysprofCallgraph *callgraph, gpointer user_data); SYSPROF_AVAILABLE_IN_ALL -GListModel *sysprof_callgraph_list_callers (SysprofCallgraph *self, - SysprofCallgraphFrame *frame); +GListModel *sysprof_callgraph_list_symbols (SysprofCallgraph *self); SYSPROF_AVAILABLE_IN_ALL -GListModel *sysprof_callgraph_list_traceables_for_symbol (SysprofCallgraph *self, - SysprofSymbol *symbol); +GListModel *sysprof_callgraph_list_callers (SysprofCallgraph *self, + SysprofCallgraphFrame *frame); SYSPROF_AVAILABLE_IN_ALL -gpointer sysprof_callgraph_get_augment (SysprofCallgraph *self, - SysprofCallgraphNode *node); +GListModel *sysprof_callgraph_list_traceables_for_symbol (SysprofCallgraph *self, + SysprofSymbol *symbol); SYSPROF_AVAILABLE_IN_ALL -gpointer sysprof_callgraph_get_summary_augment (SysprofCallgraph *self, - SysprofCallgraphNode *node); +gpointer sysprof_callgraph_get_augment (SysprofCallgraph *self, + SysprofCallgraphNode *node); SYSPROF_AVAILABLE_IN_ALL -SysprofCallgraphNode *sysprof_callgraph_node_parent (SysprofCallgraphNode *node); +gpointer sysprof_callgraph_get_summary_augment (SysprofCallgraph *self, + SysprofCallgraphNode *node); SYSPROF_AVAILABLE_IN_ALL -SysprofCallgraph *sysprof_callgraph_frame_get_callgraph (SysprofCallgraphFrame *self); +SysprofCallgraphNode *sysprof_callgraph_node_parent (SysprofCallgraphNode *node); +SYSPROF_AVAILABLE_IN_ALL +SysprofCallgraph *sysprof_callgraph_frame_get_callgraph (SysprofCallgraphFrame *self); +SYSPROF_AVAILABLE_IN_ALL +SysprofCallgraph *sysprof_callgraph_symbol_get_callgraph (SysprofCallgraphSymbol *self); G_END_DECLS