sysprof/greeter: apply default recording template to loader

This ensures that the document loader can apply settings from the recording
template (thusly applying future options such as debuginfod or extra debug
directories).

Related: #130
This commit is contained in:
Christian Hergert
2025-01-28 13:29:53 -08:00
parent 72df41485d
commit 3ed3d8e620
10 changed files with 187 additions and 44 deletions

View File

@ -24,6 +24,7 @@
#include "sysprof-application.h" #include "sysprof-application.h"
#include "sysprof-credits.h" #include "sysprof-credits.h"
#include "sysprof-greeter.h" #include "sysprof-greeter.h"
#include "sysprof-recording-template.h"
#include "sysprof-window.h" #include "sysprof-window.h"
struct _SysprofApplication struct _SysprofApplication
@ -67,12 +68,15 @@ sysprof_application_open (GApplication *app,
int n_files, int n_files,
const char *hint) const char *hint)
{ {
g_autoptr(SysprofRecordingTemplate) template = NULL;
g_assert (SYSPROF_IS_APPLICATION (app)); g_assert (SYSPROF_IS_APPLICATION (app));
g_assert (files != NULL || n_files == 0); g_assert (files != NULL || n_files == 0);
template = sysprof_recording_template_new_from_file (NULL, NULL);
for (guint i = 0; i < n_files; i++) for (guint i = 0; i < n_files; i++)
sysprof_window_open (SYSPROF_APPLICATION (app), files[i]); sysprof_window_open (SYSPROF_APPLICATION (app), template, files[i]);
} }
static int static int
@ -147,7 +151,7 @@ sysprof_about (GSimpleAction *action,
g_assert (variant == NULL); g_assert (variant == NULL);
windows = gtk_application_get_windows (app); windows = gtk_application_get_windows (app);
if (windows == NULL) if (windows == NULL)
{ {
g_warning ("No windows found to show about dialog"); g_warning ("No windows found to show about dialog");

View File

@ -32,6 +32,7 @@
#include "sysprof-recording-pad.h" #include "sysprof-recording-pad.h"
#include "sysprof-recording-template.h" #include "sysprof-recording-template.h"
#include "sysprof-stack-size.h" #include "sysprof-stack-size.h"
#include "sysprof-util.h"
#include "sysprof-window.h" #include "sysprof-window.h"
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofCaptureWriter, sysprof_capture_writer_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofCaptureWriter, sysprof_capture_writer_unref)
@ -63,12 +64,6 @@ struct _SysprofGreeter
GtkLabel *user_stacks_caption; GtkLabel *user_stacks_caption;
}; };
static GFile *
get_state_file (void)
{
return g_file_new_build_filename (g_get_user_data_dir (), APP_ID_S, "recording-template.json", NULL);
}
static GObject * static GObject *
sysprof_greeter_get_internal_child (GtkBuildable *buildable, sysprof_greeter_get_internal_child (GtkBuildable *buildable,
GtkBuilder *builder, GtkBuilder *builder,
@ -192,7 +187,7 @@ sysprof_greeter_record_cb (GObject *object,
} }
else else
{ {
GtkWidget *pad = sysprof_recording_pad_new (recording); GtkWidget *pad = sysprof_recording_pad_new (recording, self->recording_template);
gtk_window_present (GTK_WINDOW (pad)); gtk_window_present (GTK_WINDOW (pad));
} }
@ -221,7 +216,7 @@ sysprof_greeter_create_profiler (SysprofGreeter *self,
if (!(profiler = sysprof_recording_template_apply (self->recording_template, error))) if (!(profiler = sysprof_recording_template_apply (self->recording_template, error)))
return NULL; return NULL;
state_file = get_state_file (); state_file = _get_default_state_file ();
dir = g_file_get_parent (state_file); dir = g_file_get_parent (state_file);
if (!g_file_query_exists (dir, NULL)) if (!g_file_query_exists (dir, NULL))
@ -353,7 +348,9 @@ sysprof_greeter_select_file_action (GtkWidget *widget,
const char *action_name, const char *action_name,
GVariant *param) GVariant *param)
{ {
sysprof_window_open_file (GTK_WINDOW (widget)); SysprofGreeter *self = SYSPROF_GREETER (widget);
sysprof_window_open_file (GTK_WINDOW (widget), self->recording_template);
} }
static char * static char *
@ -580,7 +577,7 @@ static void
sysprof_greeter_init (SysprofGreeter *self) sysprof_greeter_init (SysprofGreeter *self)
{ {
g_autoptr(GListModel) power_profiles = sysprof_power_profiles_new (); g_autoptr(GListModel) power_profiles = sysprof_power_profiles_new ();
g_autoptr(GFile) state_file = get_state_file (); g_autoptr(GFile) state_file = _get_default_state_file ();
GtkListBoxRow *row; GtkListBoxRow *row;
if (!(self->recording_template = sysprof_recording_template_new_from_file (state_file, NULL))) if (!(self->recording_template = sysprof_recording_template_new_from_file (state_file, NULL)))

View File

@ -29,18 +29,20 @@
struct _SysprofRecordingPad struct _SysprofRecordingPad
{ {
AdwWindow parent_instance; AdwWindow parent_instance;
SysprofRecording *recording; SysprofRecording *recording;
SysprofRecordingTemplate *template;
GtkButton *stop_button; GtkButton *stop_button;
guint closed : 1; guint closed : 1;
}; };
enum { enum {
PROP_0, PROP_0,
PROP_RECORDING, PROP_RECORDING,
PROP_TEMPLATE,
N_PROPS N_PROPS
}; };
@ -124,7 +126,7 @@ sysprof_recording_pad_wait_cb (GObject *object,
else if (-1 != (fd = sysprof_recording_dup_fd (self->recording))) else if (-1 != (fd = sysprof_recording_dup_fd (self->recording)))
{ {
lseek (fd, 0, SEEK_SET); lseek (fd, 0, SEEK_SET);
sysprof_window_open_fd (SYSPROF_APPLICATION_DEFAULT, fd); sysprof_window_open_fd (SYSPROF_APPLICATION_DEFAULT, self->template, fd);
} }
if (!self->closed) if (!self->closed)
@ -154,6 +156,7 @@ sysprof_recording_pad_dispose (GObject *object)
SysprofRecordingPad *self = (SysprofRecordingPad *)object; SysprofRecordingPad *self = (SysprofRecordingPad *)object;
g_clear_object (&self->recording); g_clear_object (&self->recording);
g_clear_object (&self->template);
G_OBJECT_CLASS (sysprof_recording_pad_parent_class)->dispose (object); G_OBJECT_CLASS (sysprof_recording_pad_parent_class)->dispose (object);
} }
@ -172,6 +175,10 @@ sysprof_recording_pad_get_property (GObject *object,
g_value_set_object (value, self->recording); g_value_set_object (value, self->recording);
break; break;
case PROP_TEMPLATE:
g_value_set_object (value, self->template);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} }
@ -191,6 +198,10 @@ sysprof_recording_pad_set_property (GObject *object,
self->recording = g_value_dup_object (value); self->recording = g_value_dup_object (value);
break; break;
case PROP_TEMPLATE:
self->template = g_value_dup_object (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} }
@ -215,6 +226,11 @@ sysprof_recording_pad_class_init (SysprofRecordingPadClass *klass)
SYSPROF_TYPE_RECORDING, SYSPROF_TYPE_RECORDING,
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
properties [PROP_TEMPLATE] =
g_param_spec_object ("template", NULL, NULL,
SYSPROF_TYPE_RECORDING_TEMPLATE,
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties); g_object_class_install_properties (object_class, N_PROPS, properties);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/sysprof-recording-pad.ui"); gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/sysprof-recording-pad.ui");
@ -232,12 +248,15 @@ sysprof_recording_pad_init (SysprofRecordingPad *self)
} }
GtkWidget * GtkWidget *
sysprof_recording_pad_new (SysprofRecording *recording) sysprof_recording_pad_new (SysprofRecording *recording,
SysprofRecordingTemplate *template)
{ {
g_return_val_if_fail (SYSPROF_IS_RECORDING (recording), NULL); g_return_val_if_fail (SYSPROF_IS_RECORDING (recording), NULL);
g_return_val_if_fail (!template || SYSPROF_IS_RECORDING_TEMPLATE (template), NULL);
return g_object_new (SYSPROF_TYPE_RECORDING_PAD, return g_object_new (SYSPROF_TYPE_RECORDING_PAD,
"application", SYSPROF_APPLICATION_DEFAULT, "application", SYSPROF_APPLICATION_DEFAULT,
"recording", recording, "recording", recording,
"template", template,
NULL); NULL);
} }

View File

@ -24,12 +24,15 @@
#include <sysprof.h> #include <sysprof.h>
#include "sysprof-recording-template.h"
G_BEGIN_DECLS G_BEGIN_DECLS
#define SYSPROF_TYPE_RECORDING_PAD (sysprof_recording_pad_get_type()) #define SYSPROF_TYPE_RECORDING_PAD (sysprof_recording_pad_get_type())
G_DECLARE_FINAL_TYPE (SysprofRecordingPad, sysprof_recording_pad, SYSPROF, RECORDING_PAD, AdwWindow) G_DECLARE_FINAL_TYPE (SysprofRecordingPad, sysprof_recording_pad, SYSPROF, RECORDING_PAD, AdwWindow)
GtkWidget *sysprof_recording_pad_new (SysprofRecording *recording); GtkWidget *sysprof_recording_pad_new (SysprofRecording *recording,
SysprofRecordingTemplate *template);
G_END_DECLS G_END_DECLS

View File

@ -23,6 +23,7 @@
#include <json-glib/json-glib.h> #include <json-glib/json-glib.h>
#include "sysprof-recording-template.h" #include "sysprof-recording-template.h"
#include "sysprof-util.h"
#define DEFAULT_STACK_SIZE (4096*4) #define DEFAULT_STACK_SIZE (4096*4)
@ -687,10 +688,14 @@ sysprof_recording_template_new_from_file (GFile *file,
GError **error) GError **error)
{ {
g_autoptr(JsonParser) parser = NULL; g_autoptr(JsonParser) parser = NULL;
g_autoptr(GFile) state_file = NULL;
SysprofRecordingTemplate *self; SysprofRecordingTemplate *self;
JsonNode *root; JsonNode *root;
g_return_val_if_fail (G_IS_FILE (file), NULL); g_return_val_if_fail (!file || G_IS_FILE (file), NULL);
if (file == NULL)
file = state_file = _get_default_state_file ();
parser = json_parser_new (); parser = json_parser_new ();
@ -743,3 +748,51 @@ sysprof_recording_template_save (SysprofRecordingTemplate *self,
return json_generator_to_stream (generator, G_OUTPUT_STREAM (stream), NULL, error); return json_generator_to_stream (generator, G_OUTPUT_STREAM (stream), NULL, error);
} }
SysprofDocumentLoader *
sysprof_recording_template_create_loader (SysprofRecordingTemplate *self,
int fd,
GError **error)
{
g_autoptr(SysprofDocumentLoader) loader = NULL;
g_autoptr(SysprofMultiSymbolizer) multi = NULL;
g_autoptr(SysprofElfSymbolizer) elf = NULL;
g_return_val_if_fail (SYSPROF_IS_RECORDING_TEMPLATE (self), NULL);
if (!(loader = sysprof_document_loader_new_for_fd (fd, error)))
return NULL;
multi = sysprof_multi_symbolizer_new ();
elf = SYSPROF_ELF_SYMBOLIZER (sysprof_elf_symbolizer_new ());
/* TODO: add extra-debug-directories property and use that to
* call sysprof_elf_symbolizer_set_external_debug_dirs(elf,...)
*/
/* Add in order of priority */
sysprof_multi_symbolizer_take (multi, sysprof_bundled_symbolizer_new ());
sysprof_multi_symbolizer_take (multi, sysprof_kallsyms_symbolizer_new ());
sysprof_multi_symbolizer_take (multi, SYSPROF_SYMBOLIZER (g_steal_pointer (&elf)));
sysprof_multi_symbolizer_take (multi, sysprof_jitmap_symbolizer_new ());
sysprof_document_loader_set_symbolizer (loader, SYSPROF_SYMBOLIZER (multi));
#if HAVE_DEBUGINFOD
#if 0
/* TODO: add enable-debuginfod property. */
if (self->enable_debuginfod)
#endif
{
g_autoptr(SysprofSymbolizer) debuginfod = NULL;
g_autoptr(GError) debuginfod_error = NULL;
if (!(debuginfod = sysprof_debuginfod_symbolizer_new (&debuginfod_error)))
g_warning ("Failed to create debuginfod symbolizer: %s", debuginfod_error->message);
else
sysprof_multi_symbolizer_take (multi, g_steal_pointer (&debuginfod));
}
#endif
return g_steal_pointer (&loader);
}

View File

@ -43,5 +43,8 @@ SysprofRecordingTemplate *sysprof_recording_template_new_from_file (GFile
gboolean sysprof_recording_template_save (SysprofRecordingTemplate *self, gboolean sysprof_recording_template_save (SysprofRecordingTemplate *self,
GFile *file, GFile *file,
GError **error); GError **error);
SysprofDocumentLoader *sysprof_recording_template_create_loader (SysprofRecordingTemplate *self,
int fd,
GError **error);
G_END_DECLS G_END_DECLS

View File

@ -66,3 +66,9 @@ _gtk_widget_hide_with_fade (GtkWidget *widget)
g_memdup2 (&begin_time, sizeof begin_time), g_memdup2 (&begin_time, sizeof begin_time),
g_free); g_free);
} }
GFile *
_get_default_state_file (void)
{
return g_file_new_build_filename (g_get_user_data_dir (), APP_ID_S, "recording-template.json", NULL);
}

View File

@ -24,6 +24,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
void _gtk_widget_hide_with_fade (GtkWidget *widget); void _gtk_widget_hide_with_fade (GtkWidget *widget);
GFile *_get_default_state_file (void);
G_END_DECLS G_END_DECLS

View File

@ -20,7 +20,11 @@
#include "config.h" #include "config.h"
#include <fcntl.h>
#include <errno.h>
#include <glib/gi18n.h> #include <glib/gi18n.h>
#include <glib/gstdio.h>
#include "sysprof-counters-section.h" #include "sysprof-counters-section.h"
#include "sysprof-cpu-section.h" #include "sysprof-cpu-section.h"
@ -34,6 +38,7 @@
#include "sysprof-memory-section.h" #include "sysprof-memory-section.h"
#include "sysprof-metadata-section.h" #include "sysprof-metadata-section.h"
#include "sysprof-network-section.h" #include "sysprof-network-section.h"
#include "sysprof-pair.h"
#include "sysprof-processes-section.h" #include "sysprof-processes-section.h"
#include "sysprof-samples-section.h" #include "sysprof-samples-section.h"
#include "sysprof-sidebar.h" #include "sysprof-sidebar.h"
@ -133,7 +138,9 @@ sysprof_window_open_file_cb (GObject *object,
gpointer user_data) gpointer user_data)
{ {
GtkFileDialog *dialog = (GtkFileDialog *)object; GtkFileDialog *dialog = (GtkFileDialog *)object;
g_autoptr(GtkWindow) transient_for = user_data; g_autoptr(SysprofRecordingTemplate) template = NULL;
g_autoptr(GtkWindow) transient_for = NULL;
g_autoptr(SysprofPair) pair = user_data;
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
g_autoptr(GFile) file = NULL; g_autoptr(GFile) file = NULL;
@ -141,11 +148,19 @@ sysprof_window_open_file_cb (GObject *object,
g_assert (G_IS_ASYNC_RESULT (result)); g_assert (G_IS_ASYNC_RESULT (result));
g_assert (!transient_for || GTK_IS_WINDOW (transient_for)); g_assert (!transient_for || GTK_IS_WINDOW (transient_for));
g_object_get (pair,
"first", &transient_for,
"second", &template,
NULL);
g_assert (!transient_for || GTK_IS_WIDGET (transient_for));
g_assert (!template || SYSPROF_IS_RECORDING_TEMPLATE (template));
if ((file = gtk_file_dialog_open_finish (dialog, result, &error))) if ((file = gtk_file_dialog_open_finish (dialog, result, &error)))
{ {
if (g_file_is_native (file)) if (g_file_is_native (file))
{ {
sysprof_window_open (SYSPROF_APPLICATION_DEFAULT, file); sysprof_window_open (SYSPROF_APPLICATION_DEFAULT, template, file);
if (transient_for && !SYSPROF_IS_WINDOW (transient_for)) if (transient_for && !SYSPROF_IS_WINDOW (transient_for))
gtk_window_destroy (transient_for); gtk_window_destroy (transient_for);
@ -168,7 +183,8 @@ sysprof_window_open_file_cb (GObject *object,
} }
void void
sysprof_window_open_file (GtkWindow *parent) sysprof_window_open_file (GtkWindow *parent,
SysprofRecordingTemplate *template)
{ {
g_autoptr(GtkFileDialog) dialog = NULL; g_autoptr(GtkFileDialog) dialog = NULL;
g_autoptr(GtkFileFilter) filter = NULL; g_autoptr(GtkFileFilter) filter = NULL;
@ -192,7 +208,10 @@ sysprof_window_open_file (GtkWindow *parent)
parent, parent,
NULL, NULL,
sysprof_window_open_file_cb, sysprof_window_open_file_cb,
parent ? g_object_ref (parent) : NULL); g_object_new (SYSPROF_TYPE_PAIR,
"first", parent,
"second", template,
NULL));
} }
static void static void
@ -200,7 +219,12 @@ sysprof_window_open_capture_action (GtkWidget *widget,
const char *action_name, const char *action_name,
GVariant *param) GVariant *param)
{ {
sysprof_window_open_file (GTK_WINDOW (widget)); g_autoptr(SysprofRecordingTemplate) template = NULL;
/* Open for default state file so we can apply settings */
template = sysprof_recording_template_new_from_file (NULL, NULL);
sysprof_window_open_file (GTK_WINDOW (widget), template);
} }
static void static void
@ -780,25 +804,47 @@ sysprof_window_create (SysprofApplication *app,
} }
void void
sysprof_window_open (SysprofApplication *app, sysprof_window_open (SysprofApplication *app,
GFile *file) SysprofRecordingTemplate *template,
GFile *file)
{ {
g_autoptr(SysprofDocumentLoader) loader = NULL; g_autoptr(SysprofDocumentLoader) loader = NULL;
g_autoptr(SysprofRecordingTemplate) alt_template = NULL;
g_autoptr(GError) error = NULL;
g_autofd int fd = -1;
SysprofWindow *self; SysprofWindow *self;
const char *path;
g_return_if_fail (SYSPROF_IS_APPLICATION (app)); g_return_if_fail (SYSPROF_IS_APPLICATION (app));
g_return_if_fail (!template || SYSPROF_IS_RECORDING_TEMPLATE (template));
g_return_if_fail (G_IS_FILE (file)); g_return_if_fail (G_IS_FILE (file));
if (!g_file_is_native (file) || if (template == NULL)
!(loader = sysprof_document_loader_new (g_file_peek_path (file)))) template = alt_template = sysprof_recording_template_new ();
if (!g_file_is_native (file))
{ {
g_autofree char *uri = g_file_get_uri (file); g_autofree char *uri = g_file_get_uri (file);
g_warning ("Cannot open non-native file \"%s\"", uri); g_warning ("Cannot open non-native file \"%s\"", uri);
return; return;
} }
path = g_file_peek_path (file);
if (-1 == (fd = open (path, O_RDONLY)))
{
int errsv = errno;
g_critical ("Failed to open %s: %s", path, g_strerror (errsv));
return;
}
if (!(loader = sysprof_recording_template_create_loader (template, fd, &error)))
{
g_critical ("Failed to create loader: %s", error->message);
return;
}
g_application_hold (G_APPLICATION (app)); g_application_hold (G_APPLICATION (app));
sysprof_window_apply_loader_settings (loader);
self = sysprof_window_create (app, loader); self = sysprof_window_create (app, loader);
sysprof_document_loader_load_async (loader, sysprof_document_loader_load_async (loader,
NULL, NULL,
@ -808,18 +854,25 @@ sysprof_window_open (SysprofApplication *app,
} }
void void
sysprof_window_open_fd (SysprofApplication *app, sysprof_window_open_fd (SysprofApplication *app,
int fd) SysprofRecordingTemplate *template,
int fd)
{ {
g_autoptr(SysprofRecordingTemplate) alt_template = NULL;
g_autoptr(SysprofDocumentLoader) loader = NULL; g_autoptr(SysprofDocumentLoader) loader = NULL;
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
SysprofWindow *self; SysprofWindow *self;
g_return_if_fail (SYSPROF_IS_APPLICATION (app)); g_return_if_fail (SYSPROF_IS_APPLICATION (app));
g_return_if_fail (!template || SYSPROF_IS_RECORDING_TEMPLATE (template));
g_return_if_fail (fd > -1);
if (!(loader = sysprof_document_loader_new_for_fd (fd, &error))) if (template == NULL)
template = alt_template = sysprof_recording_template_new ();
if (!(loader = sysprof_recording_template_create_loader (template, fd, &error)))
{ {
g_critical ("Failed to dup FD: %s", error->message); g_critical ("Failed to create loader: %s", error->message);
return; return;
} }

View File

@ -25,6 +25,7 @@
#include <sysprof.h> #include <sysprof.h>
#include "sysprof-application.h" #include "sysprof-application.h"
#include "sysprof-recording-template.h"
#include "sysprof-session.h" #include "sysprof-session.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -33,14 +34,17 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (SysprofWindow, sysprof_window, SYSPROF, WINDOW, AdwApplicationWindow) G_DECLARE_FINAL_TYPE (SysprofWindow, sysprof_window, SYSPROF, WINDOW, AdwApplicationWindow)
GtkWidget *sysprof_window_new (SysprofApplication *app, GtkWidget *sysprof_window_new (SysprofApplication *app,
SysprofDocument *document); SysprofDocument *document);
void sysprof_window_open_file (GtkWindow *transient_for); void sysprof_window_open_file (GtkWindow *transient_for,
void sysprof_window_open (SysprofApplication *app, SysprofRecordingTemplate *template);
GFile *file); void sysprof_window_open (SysprofApplication *app,
void sysprof_window_open_fd (SysprofApplication *app, SysprofRecordingTemplate *template,
int fd); GFile *file);
SysprofDocument *sysprof_window_get_document (SysprofWindow *self); void sysprof_window_open_fd (SysprofApplication *app,
SysprofSession *sysprof_window_get_session (SysprofWindow *self); SysprofRecordingTemplate *template,
int fd);
SysprofDocument *sysprof_window_get_document (SysprofWindow *self);
SysprofSession *sysprof_window_get_session (SysprofWindow *self);
G_END_DECLS G_END_DECLS