3869a62c8e
Resolves: RHEL-65743
507 lines
17 KiB
Diff
507 lines
17 KiB
Diff
From 927b13bb407105517783ab1d03c025fecf1d59d9 Mon Sep 17 00:00:00 2001
|
|
From: Christian Hergert <chergert@redhat.com>
|
|
Date: Sun, 3 Nov 2024 10:57:58 -0800
|
|
Subject: [PATCH 18/18] sysprof: add UI for live unwinding
|
|
|
|
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
|
|
|