sysprof: add support for bottom up stack traces

Keep the "All Processes" and "Process N" nodes, but reverse the stack
trace after that point.
This commit is contained in:
Christian Hergert
2023-07-13 21:23:21 -07:00
parent c059689da1
commit 6f76432a17
10 changed files with 106 additions and 11 deletions

View File

@ -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.
*/

View File

@ -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

View File

@ -50,6 +50,7 @@ struct _SysprofCallgraphView
guint reload_source;
guint bottom_up : 1;
guint include_threads : 1;
guint hide_system_libraries : 1;
};

View File

@ -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)
{

View File

@ -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,

View File

@ -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,

View File

@ -76,6 +76,11 @@
<lookup name="session">SysprofMemorySection</lookup>
</lookup>
</binding>
<binding name="bottom-up">
<lookup name="bottom-up" type="SysprofSession">
<lookup name="session">SysprofMemorySection</lookup>
</lookup>
</binding>
<binding name="document">
<lookup name="document" type="SysprofSession">
<lookup name="session">SysprofMemorySection</lookup>

View File

@ -76,6 +76,11 @@
<lookup name="session">SysprofSamplesSection</lookup>
</lookup>
</binding>
<binding name="bottom-up">
<lookup name="bottom-up" type="SysprofSession">
<lookup name="session">SysprofSamplesSection</lookup>
</lookup>
</binding>
<binding name="document">
<lookup name="document" type="SysprofSession">
<lookup name="session">SysprofSamplesSection</lookup>

View File

@ -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));

View File

@ -225,6 +225,10 @@
<attribute name="label" translatable="yes">Include Threads</attribute>
<attribute name="action">win.callgraph.include-threads</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Bottom Up</attribute>
<attribute name="action">win.callgraph.bottom-up</attribute>
</item>
</section>
</menu>
</interface>