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
+