diff --git a/src/libsysprof-analyze/sysprof-callgraph.c b/src/libsysprof-analyze/sysprof-callgraph.c index 419f64e9..aa539038 100644 --- a/src/libsysprof-analyze/sysprof-callgraph.c +++ b/src/libsysprof-analyze/sysprof-callgraph.c @@ -226,16 +226,6 @@ sysprof_callgraph_add_trace (SysprofCallgraph *self, parent = &self->root; - /* If the first thing we see is a context switch, then there is - * nothing after it to account for. Just skip the symbol as it - * provides nothing to us in the callgraph. - */ - if (_sysprof_symbol_is_context_switch (symbols[0])) - { - symbols++; - n_symbols--; - } - for (guint i = n_symbols - 1; i > 0; i--) { SysprofSymbol *symbol = symbols[i-1]; @@ -279,6 +269,20 @@ sysprof_callgraph_add_trace (SysprofCallgraph *self, return parent; } +static void +reverse_symbols (SysprofSymbol **symbols, + guint n_symbols) +{ + guint half = n_symbols / 2; + + for (guint i = 0; i < half; i++) + { + SysprofSymbol *tmp = symbols[i]; + symbols[i] = symbols[n_symbols-1-i]; + symbols[n_symbols-1-i] = tmp; + } +} + static void sysprof_callgraph_add_traceable (SysprofCallgraph *self, SysprofDocumentTraceable *traceable, @@ -332,6 +336,19 @@ sysprof_callgraph_add_traceable (SysprofCallgraph *self, if (final_context == SYSPROF_ADDRESS_CONTEXT_KERNEL) symbols[n_symbols++] = _sysprof_document_kernel_symbol (self->document); + /* If the first thing we see is a context switch, then there is + * nothing after it to account for. Just skip the symbol as it + * provides nothing to us in the callgraph. + */ + if (_sysprof_symbol_is_context_switch (symbols[0])) + { + symbols++; + n_symbols--; + } + + if ((self->flags & SYSPROF_CALLGRAPH_FLAGS_BOTTOM_UP) != 0) + reverse_symbols (symbols, n_symbols); + /* If the user requested thread-ids within each process, then * insert a symbol for that before the real stacks. */ diff --git a/src/libsysprof-analyze/sysprof-callgraph.h b/src/libsysprof-analyze/sysprof-callgraph.h index 6c77bd1e..04dc44bf 100644 --- a/src/libsysprof-analyze/sysprof-callgraph.h +++ b/src/libsysprof-analyze/sysprof-callgraph.h @@ -67,6 +67,7 @@ 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, } SysprofCallgraphFlags; SYSPROF_AVAILABLE_IN_ALL diff --git a/src/libsysprof-gtk/sysprof-callgraph-view-private.h b/src/libsysprof-gtk/sysprof-callgraph-view-private.h index 07f84992..5a48d3a7 100644 --- a/src/libsysprof-gtk/sysprof-callgraph-view-private.h +++ b/src/libsysprof-gtk/sysprof-callgraph-view-private.h @@ -50,6 +50,7 @@ struct _SysprofCallgraphView guint reload_source; + guint bottom_up : 1; guint include_threads : 1; guint hide_system_libraries : 1; }; diff --git a/src/libsysprof-gtk/sysprof-callgraph-view.c b/src/libsysprof-gtk/sysprof-callgraph-view.c index 56b437e7..39a0af6c 100644 --- a/src/libsysprof-gtk/sysprof-callgraph-view.c +++ b/src/libsysprof-gtk/sysprof-callgraph-view.c @@ -29,6 +29,7 @@ enum { PROP_0, + PROP_BOTTOM_UP, PROP_CALLGRAPH, PROP_DOCUMENT, PROP_HIDE_SYSTEM_LIBRARIES, @@ -336,6 +337,10 @@ sysprof_callgraph_view_get_property (GObject *object, switch (prop_id) { + case PROP_BOTTOM_UP: + g_value_set_boolean (value, sysprof_callgraph_view_get_bottom_up (self)); + break; + case PROP_CALLGRAPH: g_value_set_object (value, sysprof_callgraph_view_get_callgraph (self)); break; @@ -375,6 +380,10 @@ sysprof_callgraph_view_set_property (GObject *object, switch (prop_id) { + case PROP_BOTTOM_UP: + sysprof_callgraph_view_set_bottom_up (self, g_value_get_boolean (value)); + break; + case PROP_DOCUMENT: sysprof_callgraph_view_set_document (self, g_value_get_object (value)); break; @@ -406,6 +415,11 @@ sysprof_callgraph_view_class_init (SysprofCallgraphViewClass *klass) object_class->get_property = sysprof_callgraph_view_get_property; object_class->set_property = sysprof_callgraph_view_set_property; + properties[PROP_BOTTOM_UP] = + g_param_spec_boolean ("bottom-up", NULL, NULL, + FALSE, + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + properties[PROP_CALLGRAPH] = g_param_spec_object ("callgraph", NULL, NULL, SYSPROF_TYPE_CALLGRAPH, @@ -579,6 +593,9 @@ sysprof_callgraph_view_reload (SysprofCallgraphView *self) if (self->hide_system_libraries) flags |= SYSPROF_CALLGRAPH_FLAGS_HIDE_SYSTEM_LIBRARIES; + if (self->bottom_up) + flags |= SYSPROF_CALLGRAPH_FLAGS_BOTTOM_UP; + sysprof_document_callgraph_async (self->document, flags, self->traceables, @@ -713,6 +730,30 @@ sysprof_callgraph_view_get_callgraph (SysprofCallgraphView *self) return self->callgraph; } +gboolean +sysprof_callgraph_view_get_bottom_up (SysprofCallgraphView *self) +{ + g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_VIEW (self), FALSE); + + return self->bottom_up; +} + +void +sysprof_callgraph_view_set_bottom_up (SysprofCallgraphView *self, + gboolean bottom_up) +{ + g_return_if_fail (SYSPROF_IS_CALLGRAPH_VIEW (self)); + + bottom_up = !!bottom_up; + + if (self->bottom_up != bottom_up) + { + self->bottom_up = bottom_up; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BOTTOM_UP]); + sysprof_callgraph_view_queue_reload (self); + } +} + gboolean sysprof_callgraph_view_get_hide_system_libraries (SysprofCallgraphView *self) { diff --git a/src/libsysprof-gtk/sysprof-callgraph-view.h b/src/libsysprof-gtk/sysprof-callgraph-view.h index 596ae1ab..33177b2b 100644 --- a/src/libsysprof-gtk/sysprof-callgraph-view.h +++ b/src/libsysprof-gtk/sysprof-callgraph-view.h @@ -50,6 +50,11 @@ SYSPROF_AVAILABLE_IN_ALL void sysprof_callgraph_view_set_traceables (SysprofCallgraphView *self, GListModel *model); SYSPROF_AVAILABLE_IN_ALL +gboolean sysprof_callgraph_view_get_bottom_up (SysprofCallgraphView *self); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_callgraph_view_set_bottom_up (SysprofCallgraphView *self, + gboolean bottom_up); +SYSPROF_AVAILABLE_IN_ALL gboolean sysprof_callgraph_view_get_include_threads (SysprofCallgraphView *self); SYSPROF_AVAILABLE_IN_ALL void sysprof_callgraph_view_set_include_threads (SysprofCallgraphView *self, diff --git a/src/libsysprof-gtk/sysprof-session.c b/src/libsysprof-gtk/sysprof-session.c index 4939e758..575d3efc 100644 --- a/src/libsysprof-gtk/sysprof-session.c +++ b/src/libsysprof-gtk/sysprof-session.c @@ -42,12 +42,14 @@ struct _SysprofSession SysprofTimeSpan selected_time; SysprofTimeSpan visible_time; + guint bottom_up : 1; guint include_threads : 1; guint hide_system_libraries : 1; }; enum { PROP_0, + PROP_BOTTOM_UP, PROP_DOCUMENT, PROP_DOCUMENT_TIME, PROP_FILTER, @@ -126,6 +128,10 @@ sysprof_session_get_property (GObject *object, switch (prop_id) { + case PROP_BOTTOM_UP: + g_value_set_boolean (value, self->bottom_up); + break; + case PROP_DOCUMENT: g_value_set_object (value, sysprof_session_get_document (self)); break; @@ -181,6 +187,10 @@ sysprof_session_set_property (GObject *object, switch (prop_id) { + case PROP_BOTTOM_UP: + self->bottom_up = g_value_get_boolean (value); + break; + case PROP_DOCUMENT: sysprof_session_set_document (self, g_value_get_object (value)); break; @@ -207,6 +217,11 @@ sysprof_session_class_init (SysprofSessionClass *klass) object_class->get_property = sysprof_session_get_property; object_class->set_property = sysprof_session_set_property; + properties [PROP_BOTTOM_UP] = + g_param_spec_boolean ("bottom-up", NULL, NULL, + FALSE, + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + properties [PROP_DOCUMENT] = g_param_spec_object ("document", NULL, NULL, SYSPROF_TYPE_DOCUMENT, diff --git a/src/sysprof/sysprof-memory-section.ui b/src/sysprof/sysprof-memory-section.ui index c3fa7195..eb688dce 100644 --- a/src/sysprof/sysprof-memory-section.ui +++ b/src/sysprof/sysprof-memory-section.ui @@ -76,6 +76,11 @@ SysprofMemorySection + + + SysprofMemorySection + + SysprofMemorySection diff --git a/src/sysprof/sysprof-samples-section.ui b/src/sysprof/sysprof-samples-section.ui index bf031860..f5693b70 100644 --- a/src/sysprof/sysprof-samples-section.ui +++ b/src/sysprof/sysprof-samples-section.ui @@ -76,6 +76,11 @@ SysprofSamplesSection + + + SysprofSamplesSection + + SysprofSamplesSection diff --git a/src/sysprof/sysprof-window.c b/src/sysprof/sysprof-window.c index 41279296..d9b3e70c 100644 --- a/src/sysprof/sysprof-window.c +++ b/src/sysprof/sysprof-window.c @@ -139,8 +139,9 @@ sysprof_window_set_document (SysprofWindow *self, SysprofDocument *document) { static const char *callgraph_actions[] = { - "include-threads", + "bottom-up", "hide-system-libraries", + "include-threads", }; g_assert (SYSPROF_IS_WINDOW (self)); diff --git a/src/sysprof/sysprof-window.ui b/src/sysprof/sysprof-window.ui index 17cb19a0..6abe341a 100644 --- a/src/sysprof/sysprof-window.ui +++ b/src/sysprof/sysprof-window.ui @@ -225,6 +225,10 @@ Include Threads win.callgraph.include-threads + + Bottom Up + win.callgraph.bottom-up +