2024-11-08 23:07:30 +00:00
From f02e19820e5a3b223f2b563946daa80693c98ca2 Mon Sep 17 00:00:00 2001
2024-11-06 20:39:21 +00:00
From: Christian Hergert <chergert@redhat.com>
Date: Sun, 3 Nov 2024 10:57:58 -0800
2024-11-08 23:07:30 +00:00
Subject: [PATCH 19/31] sysprof: add UI for live unwinding
2024-11-06 20:39:21 +00:00
This adds UI to specify the amount of stack contents to copy along with
the CPU registers so that you may unwind in user-space.
---
src/sysprof/meson.build | 1 +
src/sysprof/sysprof-greeter.c | 32 +++++
src/sysprof/sysprof-greeter.ui | 67 +++++++++++
src/sysprof/sysprof-recording-template.c | 41 ++++++-
src/sysprof/sysprof-stack-size.c | 141 +++++++++++++++++++++++
src/sysprof/sysprof-stack-size.h | 35 ++++++
6 files changed, 316 insertions(+), 1 deletion(-)
create mode 100644 src/sysprof/sysprof-stack-size.c
create mode 100644 src/sysprof/sysprof-stack-size.h
diff --git a/src/sysprof/meson.build b/src/sysprof/meson.build
index ca42ead3..ab6a701a 100644
--- a/src/sysprof/meson.build
+++ b/src/sysprof/meson.build
@@ -57,6 +57,7 @@ sysprof_sources = [
'sysprof-sidebar.c',
'sysprof-single-model.c',
'sysprof-split-layer.c',
+ 'sysprof-stack-size.c',
'sysprof-storage-section.c',
'sysprof-symbol-label.c',
'sysprof-task-row.c',
diff --git a/src/sysprof/sysprof-greeter.c b/src/sysprof/sysprof-greeter.c
index 72f4dd5d..52eff370 100644
--- a/src/sysprof/sysprof-greeter.c
+++ b/src/sysprof/sysprof-greeter.c
@@ -31,6 +31,7 @@
#include "sysprof-power-profiles.h"
#include "sysprof-recording-pad.h"
#include "sysprof-recording-template.h"
+#include "sysprof-stack-size.h"
#include "sysprof-window.h"
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofCaptureWriter, sysprof_capture_writer_unref)
@@ -56,6 +57,7 @@ struct _SysprofGreeter
GtkSwitch *bundle_symbols;
GtkButton *record_to_memory;
AdwComboRow *power_combo;
+ AdwComboRow *sample_user_stack_size;
SysprofRecordingTemplate *recording_template;
};
@@ -455,6 +457,26 @@ translate_power_profile (GtkStringObject *strobj)
return g_strdup (str);
}
+static void
+on_stack_size_changed_cb (SysprofGreeter *self,
+ GParamSpec *pspec,
+ AdwComboRow *row)
+{
+ GObject *item;
+
+ g_assert (SYSPROF_IS_GREETER (self));
+ g_assert (ADW_IS_COMBO_ROW (row));
+
+ if ((item = adw_combo_row_get_selected_item (row)))
+ {
+ guint stack_size = sysprof_stack_size_get_size (SYSPROF_STACK_SIZE (item));
+
+ g_object_set (self->recording_template,
+ "stack-size", stack_size,
+ NULL);
+ }
+}
+
static void
sysprof_greeter_dispose (GObject *object)
{
@@ -492,6 +514,7 @@ sysprof_greeter_class_init (SysprofGreeterClass *klass)
gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, recording_template);
gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, sample_javascript_stacks);
gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, sample_native_stacks);
+ gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, sample_user_stack_size);
gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, sidebar_list_box);
gtk_widget_class_bind_template_child (widget_class, SysprofGreeter, view_stack);
@@ -507,6 +530,7 @@ sysprof_greeter_class_init (SysprofGreeterClass *klass)
g_type_ensure (SYSPROF_TYPE_ENTRY_POPOVER);
g_type_ensure (SYSPROF_TYPE_RECORDING_TEMPLATE);
+ g_type_ensure (SYSPROF_TYPE_STACK_SIZE);
}
static void
@@ -540,6 +564,14 @@ sysprof_greeter_init (SysprofGreeter *self)
gtk_list_box_select_row (self->sidebar_list_box, row);
sidebar_row_activated_cb (self, row, self->sidebar_list_box);
+ g_signal_connect_object (self->sample_user_stack_size,
+ "notify::selected-item",
+ G_CALLBACK (on_stack_size_changed_cb),
+ self,
+ G_CONNECT_SWAPPED);
+ /* Set to 16KB */
+ adw_combo_row_set_selected (self->sample_user_stack_size, 1);
+
gtk_widget_grab_focus (GTK_WIDGET (self->record_to_memory));
}
diff --git a/src/sysprof/sysprof-greeter.ui b/src/sysprof/sysprof-greeter.ui
index 35e790f5..f7ebbc29 100644
--- a/src/sysprof/sysprof-greeter.ui
+++ b/src/sysprof/sysprof-greeter.ui
@@ -106,6 +106,41 @@
</child>
</object>
</child>
+ <child>
+ <object class="AdwExpanderRow">
+ <property name="title" translatable="yes">Unwind Stacks in User Space</property>
+ <property name="subtitle" translatable="yes">Copy stack contents and registers for unwinding in user-space</property>
+ <property name="expanded" bind-source="sample_user_stack" bind-property="active" bind-flags="sync-create|bidirectional"/>
+ <child type="action">
+ <object class="GtkSwitch" id="sample_user_stack">
+ <property name="halign">end</property>
+ <property name="valign">center</property>
+ <property name="active" bind-source="recording_template" bind-flags="bidirectional|sync-create" bind-property="user-stacks"/>
+ </object>
+ </child>
+ <child>
+ <object class="AdwComboRow" id="sample_user_stack_size">
+ <property name="title" translatable="yes">Stack Size</property>
+ <property name="subtitle" translatable="yes">The number of bytes to copy from the stack</property>
+ <property name="model">stack_sizes</property>
+ <property name="expression">
+ <lookup name="label" type="SysprofStackSize"/>
+ </property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="label" translatable="yes">Unwinding in user-space has considerable overhead but may help in situations where frame-pointers are unavailable.</property>
+ <property name="xalign">0</property>
+ <property name="margin-top">8</property>
+ <style>
+ <class name="caption"/>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
</object>
</child>
<child>
@@ -664,4 +699,36 @@
</object>
<object class="GtkStringList" id="envvars">
</object>
+ <object class="GListStore" id="stack_sizes">
+ <child>
+ <object class="SysprofStackSize">
+ <property name="label">8 KB</property>
+ <property name="size">8192</property>
+ </object>
+ </child>
+ <child>
+ <object class="SysprofStackSize">
+ <property name="label">16 KB</property>
+ <property name="size">16384</property>
+ </object>
+ </child>
+ <child>
+ <object class="SysprofStackSize">
+ <property name="label">24 KB</property>
+ <property name="size">24576</property>
+ </object>
+ </child>
+ <child>
+ <object class="SysprofStackSize">
+ <property name="label">32 KB</property>
+ <property name="size">32768</property>
+ </object>
+ </child>
+ <child>
+ <object class="SysprofStackSize">
+ <property name="label">64 KB</property>
+ <property name="size">65536</property>
+ </object>
+ </child>
+ </object>
</interface>
diff --git a/src/sysprof/sysprof-recording-template.c b/src/sysprof/sysprof-recording-template.c
index 50f6c957..ee4d4f01 100644
--- a/src/sysprof/sysprof-recording-template.c
+++ b/src/sysprof/sysprof-recording-template.c
@@ -22,6 +22,8 @@
#include "sysprof-recording-template.h"
+#define DEFAULT_STACK_SIZE (4096*4)
+
struct _SysprofRecordingTemplate
{
GObject parent_instance;
@@ -31,6 +33,8 @@ struct _SysprofRecordingTemplate
char *power_profile;
char **environ;
+ guint stack_size;
+
guint battery_charge : 1;
guint bundle_symbols : 1;
guint clear_environ : 1;
@@ -49,6 +53,7 @@ struct _SysprofRecordingTemplate
guint session_bus : 1;
guint system_bus : 1;
guint system_log : 1;
+ guint user_stacks : 1;
};
enum {
@@ -73,8 +78,10 @@ enum {
PROP_POWER_PROFILE,
PROP_SCHEDULER_DETAILS,
PROP_SESSION_BUS,
+ PROP_STACK_SIZE,
PROP_SYSTEM_BUS,
PROP_SYSTEM_LOG,
+ PROP_USER_STACKS,
N_PROPS
};
@@ -185,6 +192,10 @@ sysprof_recording_template_get_property (GObject *object,
g_value_set_boolean (value, self->session_bus);
break;
+ case PROP_STACK_SIZE:
+ g_value_set_uint (value, self->stack_size);
+ break;
+
case PROP_SYSTEM_BUS:
g_value_set_boolean (value, self->system_bus);
break;
@@ -193,6 +204,10 @@ sysprof_recording_template_get_property (GObject *object,
g_value_set_boolean (value, self->system_log);
break;
+ case PROP_USER_STACKS:
+ g_value_set_boolean (value, self->user_stacks);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -289,6 +304,10 @@ sysprof_recording_template_set_property (GObject *object,
self->session_bus = g_value_get_boolean (value);
break;
+ case PROP_STACK_SIZE:
+ self->stack_size = g_value_get_uint (value);
+ break;
+
case PROP_SYSTEM_BUS:
self->system_bus = g_value_get_boolean (value);
break;
@@ -297,6 +316,10 @@ sysprof_recording_template_set_property (GObject *object,
self->system_log = g_value_get_boolean (value);
break;
+ case PROP_USER_STACKS:
+ self->user_stacks = g_value_get_boolean (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -421,6 +444,16 @@ sysprof_recording_template_class_init (SysprofRecordingTemplateClass *klass)
TRUE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ properties[PROP_USER_STACKS] =
+ g_param_spec_boolean ("user-stacks", NULL, NULL,
+ FALSE,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ properties[PROP_STACK_SIZE] =
+ g_param_spec_uint ("stack-size", NULL, NULL,
+ 0, G_MAXUINT, DEFAULT_STACK_SIZE,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
g_object_class_install_properties (object_class, N_PROPS, properties);
}
@@ -439,6 +472,7 @@ sysprof_recording_template_init (SysprofRecordingTemplate *self)
self->system_log = TRUE;
self->command_line = g_strdup ("");
self->cwd = g_strdup("");
+ self->stack_size = DEFAULT_STACK_SIZE;
}
SysprofRecordingTemplate *
@@ -619,7 +653,12 @@ sysprof_recording_template_apply (SysprofRecordingTemplate *self,
sysprof_profiler_add_instrument (profiler, sysprof_memory_usage_new ());
if (self->native_stacks)
- sysprof_profiler_add_instrument (profiler, sysprof_sampler_new ());
+ {
+ if (self->user_stacks)
+ sysprof_profiler_add_instrument (profiler, sysprof_user_sampler_new (self->stack_size));
+ else
+ sysprof_profiler_add_instrument (profiler, sysprof_sampler_new ());
+ }
if (self->network_usage)
sysprof_profiler_add_instrument (profiler, sysprof_network_usage_new ());
diff --git a/src/sysprof/sysprof-stack-size.c b/src/sysprof/sysprof-stack-size.c
new file mode 100644
index 00000000..d6652766
--- /dev/null
+++ b/src/sysprof/sysprof-stack-size.c
@@ -0,0 +1,141 @@
+/*
+ * sysprof-stack-size.c
+ *
+ * Copyright 2024 Christian Hergert <chergert@redhat.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "config.h"
+
+#include "sysprof-stack-size.h"
+
+struct _SysprofStackSize
+{
+ GObject parent_instance;
+ char *label;
+ guint size;
+};
+
+enum {
+ PROP_0,
+ PROP_SIZE,
+ PROP_LABEL,
+ N_PROPS
+};
+
+G_DEFINE_FINAL_TYPE (SysprofStackSize, sysprof_stack_size, G_TYPE_OBJECT)
+
+static GParamSpec *properties[N_PROPS];
+
+static void
+sysprof_stack_size_finalize (GObject *object)
+{
+ SysprofStackSize *self = (SysprofStackSize *)object;
+
+ g_clear_pointer (&self->label, g_free);
+
+ G_OBJECT_CLASS (sysprof_stack_size_parent_class)->finalize (object);
+}
+
+static void
+sysprof_stack_size_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SysprofStackSize *self = SYSPROF_STACK_SIZE (object);
+
+ switch (prop_id)
+ {
+ case PROP_SIZE:
+ g_value_set_uint (value, self->size);
+ break;
+
+ case PROP_LABEL:
+ g_value_set_string (value, self->label);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+sysprof_stack_size_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SysprofStackSize *self = SYSPROF_STACK_SIZE (object);
+
+ switch (prop_id)
+ {
+ case PROP_SIZE:
+ self->size = g_value_get_uint (value);
+ break;
+
+ case PROP_LABEL:
+ g_set_str (&self->label, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+sysprof_stack_size_class_init (SysprofStackSizeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = sysprof_stack_size_finalize;
+ object_class->get_property = sysprof_stack_size_get_property;
+ object_class->set_property = sysprof_stack_size_set_property;
+
+ properties[PROP_SIZE] =
+ g_param_spec_uint ("size", NULL, NULL,
+ 0, (4096*32), 0,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ properties[PROP_LABEL] =
+ g_param_spec_string ("label", NULL, NULL,
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+sysprof_stack_size_init (SysprofStackSize *self)
+{
+}
+
+guint
+sysprof_stack_size_get_size (SysprofStackSize *self)
+{
+ g_return_val_if_fail (SYSPROF_IS_STACK_SIZE (self), 0);
+
+ return self->size;
+}
+
+const char *
+sysprof_stack_size_get_label (SysprofStackSize *self)
+{
+ g_return_val_if_fail (SYSPROF_IS_STACK_SIZE (self), NULL);
+
+ return self->label;
+}
diff --git a/src/sysprof/sysprof-stack-size.h b/src/sysprof/sysprof-stack-size.h
new file mode 100644
index 00000000..5dd7f9c2
--- /dev/null
+++ b/src/sysprof/sysprof-stack-size.h
@@ -0,0 +1,35 @@
+/*
+ * sysprof-stack-size.h
+ *
+ * Copyright 2024 Christian Hergert <chergert@redhat.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define SYSPROF_TYPE_STACK_SIZE (sysprof_stack_size_get_type())
+
+G_DECLARE_FINAL_TYPE (SysprofStackSize, sysprof_stack_size, SYSPROF, STACK_SIZE, GObject)
+
+guint sysprof_stack_size_get_size (SysprofStackSize *self);
+const char *sysprof_stack_size_get_label (SysprofStackSize *self);
+
+G_END_DECLS
--
2.45.2