From 9147d45e4a74b5262e9b0ab76c90484795186ac1 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Mon, 10 Jul 2023 14:22:44 -0700 Subject: [PATCH] libsysprof-gtk: start on memory callgraph view --- .../libsysprof-gtk.gresource.xml | 1 + src/libsysprof-gtk/meson.build | 2 + src/libsysprof-gtk/sysprof-gtk.h | 1 + .../sysprof-memory-callgraph-view.c | 363 ++++++++++++++++++ .../sysprof-memory-callgraph-view.h | 42 ++ .../sysprof-memory-callgraph-view.ui | 203 ++++++++++ 6 files changed, 612 insertions(+) create mode 100644 src/libsysprof-gtk/sysprof-memory-callgraph-view.c create mode 100644 src/libsysprof-gtk/sysprof-memory-callgraph-view.h create mode 100644 src/libsysprof-gtk/sysprof-memory-callgraph-view.ui diff --git a/src/libsysprof-gtk/libsysprof-gtk.gresource.xml b/src/libsysprof-gtk/libsysprof-gtk.gresource.xml index f4a262be..f1d9f83c 100644 --- a/src/libsysprof-gtk/libsysprof-gtk.gresource.xml +++ b/src/libsysprof-gtk/libsysprof-gtk.gresource.xml @@ -5,6 +5,7 @@ sysprof-mark-chart.ui sysprof-mark-chart-row.ui sysprof-mark-table.ui + sysprof-memory-callgraph-view.ui sysprof-track-view.ui sysprof-tracks-view.ui sysprof-weighted-callgraph-view.ui diff --git a/src/libsysprof-gtk/meson.build b/src/libsysprof-gtk/meson.build index 7031073c..317d2c06 100644 --- a/src/libsysprof-gtk/meson.build +++ b/src/libsysprof-gtk/meson.build @@ -8,6 +8,7 @@ libsysprof_gtk_public_sources = [ 'sysprof-line-layer.c', 'sysprof-mark-chart.c', 'sysprof-mark-table.c', + 'sysprof-memory-callgraph-view.c', 'sysprof-normalized-series.c', 'sysprof-normalized-series-item.c', 'sysprof-series.c', @@ -42,6 +43,7 @@ libsysprof_gtk_public_headers = [ 'sysprof-line-layer.h', 'sysprof-mark-chart.h', 'sysprof-mark-table.h', + 'sysprof-memory-callgraph-view.h', 'sysprof-normalized-series.h', 'sysprof-normalized-series-item.h', 'sysprof-series.h', diff --git a/src/libsysprof-gtk/sysprof-gtk.h b/src/libsysprof-gtk/sysprof-gtk.h index 26859a26..cdb6b50a 100644 --- a/src/libsysprof-gtk/sysprof-gtk.h +++ b/src/libsysprof-gtk/sysprof-gtk.h @@ -34,6 +34,7 @@ G_BEGIN_DECLS # include "sysprof-line-layer.h" # include "sysprof-mark-chart.h" # include "sysprof-mark-table.h" +# include "sysprof-memory-callgraph-view.h" # include "sysprof-normalized-series.h" # include "sysprof-normalized-series-item.h" # include "sysprof-series.h" diff --git a/src/libsysprof-gtk/sysprof-memory-callgraph-view.c b/src/libsysprof-gtk/sysprof-memory-callgraph-view.c new file mode 100644 index 00000000..f3b84cf2 --- /dev/null +++ b/src/libsysprof-gtk/sysprof-memory-callgraph-view.c @@ -0,0 +1,363 @@ +/* sysprof-memory-callgraph-view.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 "sysprof-callgraph-view-private.h" +#include "sysprof-memory-callgraph-view.h" +#include "sysprof-progress-cell-private.h" + +struct _SysprofMemoryCallgraphView +{ + SysprofCallgraphView parent_instance; + + GtkColumnViewColumn *callers_self_column; + GtkColumnViewColumn *callers_total_column; + GtkCustomSorter *callers_self_sorter; + GtkCustomSorter *callers_total_sorter; + + GtkColumnViewColumn *descendants_self_column; + GtkColumnViewColumn *descendants_total_column; + GtkCustomSorter *descendants_self_sorter; + GtkCustomSorter *descendants_total_sorter; + + GtkColumnViewColumn *functions_self_column; + GtkColumnViewColumn *functions_total_column; + GtkCustomSorter *functions_self_sorter; + GtkCustomSorter *functions_total_sorter; +}; + +struct _SysprofMemoryCallgraphViewClass +{ + SysprofCallgraphViewClass parent_class; +}; + +typedef struct _AugmentMemory +{ + gsize size; + gsize total; +} AugmentMemory; + +G_DEFINE_FINAL_TYPE (SysprofMemoryCallgraphView, sysprof_memory_callgraph_view, SYSPROF_TYPE_CALLGRAPH_VIEW) + +static void +augment_memory (SysprofCallgraph *callgraph, + SysprofCallgraphNode *node, + SysprofDocumentFrame *frame, + gboolean summarize, + gpointer user_data) +{ + AugmentMemory *cur; + AugmentMemory *sum; + gsize size; + + g_assert (SYSPROF_IS_CALLGRAPH (callgraph)); + g_assert (node != NULL); + g_assert (SYSPROF_IS_DOCUMENT_ALLOCATION (frame)); + g_assert (user_data == NULL); + + size = sysprof_document_allocation_get_size (SYSPROF_DOCUMENT_ALLOCATION (frame)); + + cur = sysprof_callgraph_get_augment (callgraph, node); + cur->size += size; + cur->total += size; + + if (summarize) + { + sum = sysprof_callgraph_get_summary_augment (callgraph, node); + sum->size += size; + sum->total += size; + } + + for (node = sysprof_callgraph_node_parent (node); + node != NULL; + node = sysprof_callgraph_node_parent (node)) + { + cur = sysprof_callgraph_get_augment (callgraph, node); + cur->total += size; + + if (summarize) + { + sum = sysprof_callgraph_get_summary_augment (callgraph, node); + sum->total += size; + } + } +} + +static double +get_total_fraction (GObject *item) +{ + g_autoptr(GObject) row = NULL; + + g_object_get (item, "item", &row, NULL); + + if (GTK_IS_TREE_LIST_ROW (row)) + { + GtkTreeListRow *tree_row = GTK_TREE_LIST_ROW (row); + SysprofCallgraphFrame *frame = SYSPROF_CALLGRAPH_FRAME (gtk_tree_list_row_get_item (tree_row)); + SysprofCallgraph *callgraph = sysprof_callgraph_frame_get_callgraph (frame); + AugmentMemory *sum = sysprof_callgraph_frame_get_augment (frame); + AugmentMemory *root = sysprof_callgraph_get_augment (callgraph, NULL); + + if (root->total == 0) + return 0; + + return sum->total / (double)root->total; + } + + return 0; +} + +static double +get_self_fraction (GObject *item) +{ + g_autoptr(GObject) row = NULL; + + g_object_get (item, "item", &row, NULL); + + if (GTK_IS_TREE_LIST_ROW (row)) + { + GtkTreeListRow *tree_row = GTK_TREE_LIST_ROW (row); + SysprofCallgraphFrame *frame = SYSPROF_CALLGRAPH_FRAME (gtk_tree_list_row_get_item (tree_row)); + SysprofCallgraph *callgraph = sysprof_callgraph_frame_get_callgraph (frame); + AugmentMemory *sum = sysprof_callgraph_frame_get_augment (frame); + AugmentMemory *root = sysprof_callgraph_get_augment (callgraph, NULL); + + if (root->total == 0) + return 0; + + return sum->size / (double)root->total; + } + + return .0; +} + +static double +functions_get_total_fraction (GObject *item) +{ + g_autoptr(SysprofCallgraphSymbol) sym = NULL; + + g_object_get (item, "item", &sym, NULL); + + if (SYSPROF_IS_CALLGRAPH_SYMBOL (sym)) + { + SysprofCallgraph *callgraph = sysprof_callgraph_symbol_get_callgraph (sym); + AugmentMemory *sum = sysprof_callgraph_symbol_get_summary_augment (sym); + AugmentMemory *root = sysprof_callgraph_get_augment (callgraph, NULL); + + if (root->total == 0) + return 0; + + return sum->total / (double)root->total; + } + + return 0; +} + +static double +functions_get_self_fraction (GObject *item) +{ + g_autoptr(SysprofCallgraphSymbol) sym = NULL; + + g_object_get (item, "item", &sym, NULL); + + if (SYSPROF_IS_CALLGRAPH_SYMBOL (sym)) + { + SysprofCallgraph *callgraph = sysprof_callgraph_symbol_get_callgraph (sym); + AugmentMemory *sum = sysprof_callgraph_symbol_get_summary_augment (sym); + AugmentMemory *root = sysprof_callgraph_get_augment (callgraph, NULL); + + if (root->total == 0) + return 0; + + return sum->size / (double)root->total; + } + + return 0; +} + +static int +descendants_sort_by_self (gconstpointer a, + gconstpointer b, + gpointer user_data) +{ + SysprofCallgraphFrame *frame_a = (SysprofCallgraphFrame *)a; + SysprofCallgraphFrame *frame_b = (SysprofCallgraphFrame *)b; + AugmentMemory *aug_a = sysprof_callgraph_frame_get_augment (frame_a); + AugmentMemory *aug_b = sysprof_callgraph_frame_get_augment (frame_b); + AugmentMemory *root = user_data; + double self_a = aug_a->size / (double)root->total; + double self_b = aug_b->size / (double)root->total; + + if (self_a < self_b) + return -1; + else if (self_a > self_b) + return 1; + else + return 0; +} + +static int +descendants_sort_by_total (gconstpointer a, + gconstpointer b, + gpointer user_data) +{ + SysprofCallgraphFrame *frame_a = (SysprofCallgraphFrame *)a; + SysprofCallgraphFrame *frame_b = (SysprofCallgraphFrame *)b; + AugmentMemory *aug_a = sysprof_callgraph_frame_get_augment (frame_a); + AugmentMemory *aug_b = sysprof_callgraph_frame_get_augment (frame_b); + AugmentMemory *root = user_data; + double total_a = aug_a->total / (double)root->total; + double total_b = aug_b->total / (double)root->total; + + if (total_a < total_b) + return -1; + else if (total_a > total_b) + return 1; + else + return 0; +} + +static int +functions_sort_by_self (gconstpointer a, + gconstpointer b, + gpointer user_data) +{ + SysprofCallgraphSymbol *sym_a = (SysprofCallgraphSymbol *)a; + SysprofCallgraphSymbol *sym_b = (SysprofCallgraphSymbol *)b; + AugmentMemory *aug_a = sysprof_callgraph_symbol_get_summary_augment (sym_a); + AugmentMemory *aug_b = sysprof_callgraph_symbol_get_summary_augment (sym_b); + AugmentMemory *root = user_data; + double self_a = aug_a->size / (double)root->total; + double self_b = aug_b->size / (double)root->total; + + if (self_a < self_b) + return -1; + else if (self_a > self_b) + return 1; + else + return 0; +} + +static int +functions_sort_by_total (gconstpointer a, + gconstpointer b, + gpointer user_data) +{ + SysprofCallgraphSymbol *sym_a = (SysprofCallgraphSymbol *)a; + SysprofCallgraphSymbol *sym_b = (SysprofCallgraphSymbol *)b; + AugmentMemory *aug_a = sysprof_callgraph_symbol_get_summary_augment (sym_a); + AugmentMemory *aug_b = sysprof_callgraph_symbol_get_summary_augment (sym_b); + AugmentMemory *root = user_data; + double total_a = aug_a->total / (double)root->total; + double total_b = aug_b->total / (double)root->total; + + if (total_a < total_b) + return -1; + else if (total_a > total_b) + return 1; + else + return 0; +} + +static void +sysprof_memory_callgraph_view_load (SysprofCallgraphView *view, + SysprofCallgraph *callgraph) +{ + SysprofMemoryCallgraphView *self = (SysprofMemoryCallgraphView *)view; + AugmentMemory *root; + + g_assert (SYSPROF_IS_MEMORY_CALLGRAPH_VIEW (self)); + g_assert (SYSPROF_IS_CALLGRAPH (callgraph)); + + root = sysprof_callgraph_get_augment (callgraph, NULL); + + gtk_custom_sorter_set_sort_func (self->descendants_self_sorter, + descendants_sort_by_self, root, NULL); + gtk_custom_sorter_set_sort_func (self->descendants_total_sorter, + descendants_sort_by_total, root, NULL); + + gtk_custom_sorter_set_sort_func (self->functions_self_sorter, + functions_sort_by_self, root, NULL); + gtk_custom_sorter_set_sort_func (self->functions_total_sorter, + functions_sort_by_total, root, NULL); + + gtk_custom_sorter_set_sort_func (self->callers_self_sorter, + functions_sort_by_self, root, NULL); + gtk_custom_sorter_set_sort_func (self->callers_total_sorter, + functions_sort_by_total, root, NULL); + + gtk_column_view_sort_by_column (SYSPROF_CALLGRAPH_VIEW (self)->callers_column_view, + self->callers_total_column, + GTK_SORT_DESCENDING); + gtk_column_view_sort_by_column (SYSPROF_CALLGRAPH_VIEW (self)->descendants_column_view, + self->descendants_total_column, + GTK_SORT_DESCENDING); + gtk_column_view_sort_by_column (SYSPROF_CALLGRAPH_VIEW (self)->functions_column_view, + self->functions_total_column, + GTK_SORT_DESCENDING); +} + +static void +sysprof_memory_callgraph_view_class_init (SysprofMemoryCallgraphViewClass *klass) +{ + SysprofCallgraphViewClass *callgraph_view_class = SYSPROF_CALLGRAPH_VIEW_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + callgraph_view_class->augment_size = sizeof (AugmentMemory); + callgraph_view_class->augment_func = augment_memory; + callgraph_view_class->load = sysprof_memory_callgraph_view_load; + + gtk_widget_class_set_template_from_resource (widget_class, "/libsysprof-gtk/sysprof-memory-callgraph-view.ui"); + + gtk_widget_class_bind_template_child (widget_class, SysprofMemoryCallgraphView, callers_self_column); + gtk_widget_class_bind_template_child (widget_class, SysprofMemoryCallgraphView, callers_total_column); + gtk_widget_class_bind_template_child (widget_class, SysprofMemoryCallgraphView, callers_self_sorter); + gtk_widget_class_bind_template_child (widget_class, SysprofMemoryCallgraphView, callers_total_sorter); + + gtk_widget_class_bind_template_child (widget_class, SysprofMemoryCallgraphView, descendants_self_column); + gtk_widget_class_bind_template_child (widget_class, SysprofMemoryCallgraphView, descendants_total_column); + gtk_widget_class_bind_template_child (widget_class, SysprofMemoryCallgraphView, descendants_self_sorter); + gtk_widget_class_bind_template_child (widget_class, SysprofMemoryCallgraphView, descendants_total_sorter); + + gtk_widget_class_bind_template_child (widget_class, SysprofMemoryCallgraphView, functions_self_column); + gtk_widget_class_bind_template_child (widget_class, SysprofMemoryCallgraphView, functions_total_column); + gtk_widget_class_bind_template_child (widget_class, SysprofMemoryCallgraphView, functions_self_sorter); + gtk_widget_class_bind_template_child (widget_class, SysprofMemoryCallgraphView, functions_total_sorter); + + gtk_widget_class_bind_template_callback (widget_class, get_self_fraction); + gtk_widget_class_bind_template_callback (widget_class, get_total_fraction); + gtk_widget_class_bind_template_callback (widget_class, functions_get_self_fraction); + gtk_widget_class_bind_template_callback (widget_class, functions_get_total_fraction); + + g_type_ensure (SYSPROF_TYPE_PROGRESS_CELL); +} + +static void +sysprof_memory_callgraph_view_init (SysprofMemoryCallgraphView *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} + +GtkWidget * +sysprof_memory_callgraph_view_new (void) +{ + return g_object_new (SYSPROF_TYPE_MEMORY_CALLGRAPH_VIEW, NULL); +} diff --git a/src/libsysprof-gtk/sysprof-memory-callgraph-view.h b/src/libsysprof-gtk/sysprof-memory-callgraph-view.h new file mode 100644 index 00000000..6db99547 --- /dev/null +++ b/src/libsysprof-gtk/sysprof-memory-callgraph-view.h @@ -0,0 +1,42 @@ +/* sysprof-memory-callgraph-view.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-view.h" + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_MEMORY_CALLGRAPH_VIEW (sysprof_memory_callgraph_view_get_type()) +#define SYSPROF_IS_MEMORY_CALLGRAPH_VIEW(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_MEMORY_CALLGRAPH_VIEW) +#define SYSPROF_MEMORY_CALLGRAPH_VIEW(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_MEMORY_CALLGRAPH_VIEW, SysprofMemoryCallgraphView) +#define SYSPROF_MEMORY_CALLGRAPH_VIEW_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_MEMORY_CALLGRAPH_VIEW, SysprofMemoryCallgraphViewClass) + +typedef struct _SysprofMemoryCallgraphView SysprofMemoryCallgraphView; +typedef struct _SysprofMemoryCallgraphViewClass SysprofMemoryCallgraphViewClass; + +SYSPROF_AVAILABLE_IN_ALL +GType sysprof_memory_callgraph_view_get_type (void) G_GNUC_CONST; +SYSPROF_AVAILABLE_IN_ALL +GtkWidget *sysprof_memory_callgraph_view_new (void); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofMemoryCallgraphView, g_object_unref) + +G_END_DECLS diff --git a/src/libsysprof-gtk/sysprof-memory-callgraph-view.ui b/src/libsysprof-gtk/sysprof-memory-callgraph-view.ui new file mode 100644 index 00000000..0efb97ac --- /dev/null +++ b/src/libsysprof-gtk/sysprof-memory-callgraph-view.ui @@ -0,0 +1,203 @@ + + + +