From 19f8c6b39fb08242fc6cb7c0616c30716d134313 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Thu, 23 May 2019 16:17:54 -0700 Subject: [PATCH] replay: add stubs and plumbing to implement a re-record The goal here is to be able to do a duplicate recording to the previous with a quick key-combination like Ctrl+R. We still need to extract the metadata from the capture file and setup a new profiler, but this gets the mechanics in place. --- src/libsysprof-ui/sysprof-capture-view.c | 24 ++++++++- src/libsysprof-ui/sysprof-capture-view.h | 2 + src/libsysprof-ui/sysprof-display.c | 33 +++++++++++++ src/libsysprof-ui/sysprof-display.h | 4 ++ src/libsysprof-ui/sysprof-notebook.c | 63 ++++++++++++++++++++++++ src/libsysprof-ui/sysprof-notebook.h | 18 ++++--- src/sysprof/gtk/menus.ui | 7 +++ src/sysprof/sysprof-application.c | 1 + src/sysprof/sysprof-window.c | 35 ++++++++++++- 9 files changed, 177 insertions(+), 10 deletions(-) diff --git a/src/libsysprof-ui/sysprof-capture-view.c b/src/libsysprof-ui/sysprof-capture-view.c index dd7e4776..2d36e79b 100644 --- a/src/libsysprof-ui/sysprof-capture-view.c +++ b/src/libsysprof-ui/sysprof-capture-view.c @@ -41,6 +41,7 @@ typedef struct guint has_samples : 1; guint has_counters : 1; guint has_marks : 1; + guint can_replay : 1; } SysprofCaptureFeatures; typedef struct @@ -64,6 +65,7 @@ typedef struct guint busy; + guint can_replay : 1; guint needs_fit : 1; } SysprofCaptureViewPrivate; @@ -318,7 +320,17 @@ sysprof_capture_view_scan_worker (GTask *task, st_buf.frame_count[frame.type]++; - if (frame.type == SYSPROF_CAPTURE_FRAME_MARK) + if (frame.type == SYSPROF_CAPTURE_FRAME_METADATA) + { + const SysprofCaptureMetadata *meta; + + if ((meta = sysprof_capture_reader_read_metadata (reader))) + { + if (g_strcmp0 (meta->id, "local-profiler") == 0) + features.can_replay = TRUE; + } + } + else if (frame.type == SYSPROF_CAPTURE_FRAME_MARK) { const SysprofCaptureMark *mark; @@ -997,3 +1009,13 @@ sysprof_capture_view_get_reader (SysprofCaptureView *self) return priv->reader; } + +gboolean +sysprof_capture_view_get_can_replay (SysprofCaptureView *self) +{ + SysprofCaptureViewPrivate *priv = sysprof_capture_view_get_instance_private (self); + + g_return_val_if_fail (SYSPROF_IS_CAPTURE_VIEW (self), FALSE); + + return priv->features.can_replay; +} diff --git a/src/libsysprof-ui/sysprof-capture-view.h b/src/libsysprof-ui/sysprof-capture-view.h index 3dad57df..dac9b10b 100644 --- a/src/libsysprof-ui/sysprof-capture-view.h +++ b/src/libsysprof-ui/sysprof-capture-view.h @@ -69,5 +69,7 @@ SYSPROF_AVAILABLE_IN_ALL gboolean sysprof_capture_view_get_busy (SysprofCaptureView *self); SYSPROF_AVAILABLE_IN_ALL void sysprof_capture_view_fit_to_width (SysprofCaptureView *self); +SYSPROF_AVAILABLE_IN_ALL +gboolean sysprof_capture_view_get_can_replay (SysprofCaptureView *self); G_END_DECLS diff --git a/src/libsysprof-ui/sysprof-display.c b/src/libsysprof-ui/sysprof-display.c index 1b7b2358..328d6ffb 100644 --- a/src/libsysprof-ui/sysprof-display.c +++ b/src/libsysprof-ui/sysprof-display.c @@ -53,6 +53,7 @@ G_DEFINE_TYPE_WITH_PRIVATE (SysprofDisplay, sysprof_display, GTK_TYPE_BIN) enum { PROP_0, + PROP_CAN_REPLAY, PROP_CAN_SAVE, PROP_RECORDING, PROP_TITLE, @@ -91,6 +92,7 @@ sysprof_display_load_cb (SysprofCaptureView *view, if (!sysprof_capture_view_load_finish (view, result, &error)) g_warning ("Failed to load capture: %s", error->message); + g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_REPLAY]); g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_SAVE]); } @@ -148,6 +150,7 @@ sysprof_display_profiler_stopped_cb (SysprofDisplay *self, } notify: + g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_REPLAY]); g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_SAVE]); g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RECORDING]); g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]); @@ -297,6 +300,10 @@ sysprof_display_get_property (GObject *object, switch (prop_id) { + case PROP_CAN_REPLAY: + g_value_set_boolean (value, sysprof_display_get_can_replay (self)); + break; + case PROP_CAN_SAVE: g_value_set_boolean (value, sysprof_display_get_can_save (self)); break; @@ -325,6 +332,13 @@ sysprof_display_class_init (SysprofDisplayClass *klass) widget_class->parent_set = sysprof_display_parent_set; + properties [PROP_CAN_REPLAY] = + g_param_spec_boolean ("can-replay", + "Can Replay", + "If the capture contains enough information to re-run the recording", + FALSE, + (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + properties [PROP_CAN_SAVE] = g_param_spec_boolean ("can-save", "Can Save", @@ -593,3 +607,22 @@ _sysprof_display_focus_record (SysprofDisplay *self) _sysprof_profiler_assistant_focus_record (priv->assistant); } + +gboolean +sysprof_display_get_can_replay (SysprofDisplay *self) +{ + SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self); + + g_return_val_if_fail (SYSPROF_IS_DISPLAY (self), FALSE); + + return !sysprof_display_is_empty (self) && + sysprof_capture_view_get_can_replay (priv->capture_view); +} + +SysprofDisplay * +sysprof_display_replay (SysprofDisplay *self) +{ + g_return_val_if_fail (SYSPROF_IS_DISPLAY (self), NULL); + + return NULL; +} diff --git a/src/libsysprof-ui/sysprof-display.h b/src/libsysprof-ui/sysprof-display.h index fbfc6975..190f5363 100644 --- a/src/libsysprof-ui/sysprof-display.h +++ b/src/libsysprof-ui/sysprof-display.h @@ -57,5 +57,9 @@ SYSPROF_AVAILABLE_IN_ALL gboolean sysprof_display_get_can_save (SysprofDisplay *self); SYSPROF_AVAILABLE_IN_ALL void sysprof_display_stop_recording (SysprofDisplay *self); +SYSPROF_AVAILABLE_IN_ALL +gboolean sysprof_display_get_can_replay (SysprofDisplay *self); +SYSPROF_AVAILABLE_IN_ALL +SysprofDisplay *sysprof_display_replay (SysprofDisplay *self); G_END_DECLS diff --git a/src/libsysprof-ui/sysprof-notebook.c b/src/libsysprof-ui/sysprof-notebook.c index d1267b98..038bd3cc 100644 --- a/src/libsysprof-ui/sysprof-notebook.c +++ b/src/libsysprof-ui/sysprof-notebook.c @@ -31,6 +31,7 @@ G_DEFINE_TYPE (SysprofNotebook, sysprof_notebook, GTK_TYPE_NOTEBOOK) enum { PROP_0, + PROP_CAN_REPLAY, PROP_CAN_SAVE, PROP_CURRENT, N_PROPS @@ -64,6 +65,17 @@ sysprof_notebook_notify_can_save_cb (SysprofNotebook *self, g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_SAVE]); } +static void +sysprof_notebook_notify_can_replay_cb (SysprofNotebook *self, + GParamSpec *pspec, + SysprofDisplay *display) +{ + g_assert (SYSPROF_IS_NOTEBOOK (self)); + g_assert (SYSPROF_IS_DISPLAY (display)); + + g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_REPLAY]); +} + static void sysprof_notebook_page_added (GtkNotebook *notebook, GtkWidget *child, @@ -82,12 +94,19 @@ sysprof_notebook_page_added (GtkNotebook *notebook, gtk_notebook_set_tab_label (notebook, child, tab); gtk_notebook_set_tab_reorderable (notebook, child, TRUE); + g_signal_connect_object (child, + "notify::can-replay", + G_CALLBACK (sysprof_notebook_notify_can_replay_cb), + notebook, + G_CONNECT_SWAPPED); + g_signal_connect_object (child, "notify::can-save", G_CALLBACK (sysprof_notebook_notify_can_save_cb), notebook, G_CONNECT_SWAPPED); + g_object_notify_by_pspec (G_OBJECT (notebook), properties [PROP_CAN_REPLAY]); g_object_notify_by_pspec (G_OBJECT (notebook), properties [PROP_CAN_SAVE]); g_object_notify_by_pspec (G_OBJECT (notebook), properties [PROP_CURRENT]); @@ -116,6 +135,7 @@ sysprof_notebook_page_removed (GtkNotebook *notebook, G_CALLBACK (sysprof_notebook_notify_can_save_cb), notebook); + g_object_notify_by_pspec (G_OBJECT (notebook), properties [PROP_CAN_REPLAY]); g_object_notify_by_pspec (G_OBJECT (notebook), properties [PROP_CAN_SAVE]); g_object_notify_by_pspec (G_OBJECT (notebook), properties [PROP_CURRENT]); } @@ -134,6 +154,7 @@ sysprof_notebook_switch_page (GtkNotebook *notebook, GTK_NOTEBOOK_CLASS (sysprof_notebook_parent_class)->switch_page (notebook, widget, page); + g_object_notify_by_pspec (G_OBJECT (notebook), properties [PROP_CAN_REPLAY]); g_object_notify_by_pspec (G_OBJECT (notebook), properties [PROP_CAN_SAVE]); g_object_notify_by_pspec (G_OBJECT (notebook), properties [PROP_CURRENT]); } @@ -148,6 +169,10 @@ sysprof_notebook_get_property (GObject *object, switch (prop_id) { + case PROP_CAN_REPLAY: + g_value_set_boolean (value, sysprof_notebook_get_can_replay (self)); + break; + case PROP_CAN_SAVE: g_value_set_boolean (value, sysprof_notebook_get_can_save (self)); break; @@ -173,6 +198,13 @@ sysprof_notebook_class_init (SysprofNotebookClass *klass) notebook_class->page_removed = sysprof_notebook_page_removed; notebook_class->switch_page = sysprof_notebook_switch_page; + properties [PROP_CAN_REPLAY] = + g_param_spec_boolean ("can-replay", + "Can Replay", + "If the current display can replay a recording", + FALSE, + (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + properties [PROP_CAN_SAVE] = g_param_spec_boolean ("can-save", "Can Save", @@ -293,3 +325,34 @@ sysprof_notebook_get_can_save (SysprofNotebook *self) return FALSE; } + +gboolean +sysprof_notebook_get_can_replay (SysprofNotebook *self) +{ + SysprofDisplay *display; + + g_return_val_if_fail (SYSPROF_IS_NOTEBOOK (self), FALSE); + + if ((display = sysprof_notebook_get_current (self))) + return sysprof_display_get_can_replay (display); + + return FALSE; +} + +void +sysprof_notebook_replay (SysprofNotebook *self) +{ + SysprofDisplay *display; + SysprofDisplay *replay; + + g_return_if_fail (SYSPROF_IS_NOTEBOOK (self)); + + if (!(display = sysprof_notebook_get_current (self)) || + !sysprof_display_get_can_replay (display) || + !(replay = sysprof_display_replay (display))) + return; + + g_return_if_fail (SYSPROF_IS_DISPLAY (replay)); + + gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (replay)); +} diff --git a/src/libsysprof-ui/sysprof-notebook.h b/src/libsysprof-ui/sysprof-notebook.h index ebf68c97..36aa1fe8 100644 --- a/src/libsysprof-ui/sysprof-notebook.h +++ b/src/libsysprof-ui/sysprof-notebook.h @@ -41,17 +41,21 @@ struct _SysprofNotebookClass }; SYSPROF_AVAILABLE_IN_ALL -GtkWidget *sysprof_notebook_new (void); +GtkWidget *sysprof_notebook_new (void); SYSPROF_AVAILABLE_IN_ALL -SysprofDisplay *sysprof_notebook_get_current (SysprofNotebook *self); +SysprofDisplay *sysprof_notebook_get_current (SysprofNotebook *self); SYSPROF_AVAILABLE_IN_ALL -void sysprof_notebook_close_current (SysprofNotebook *self); +void sysprof_notebook_close_current (SysprofNotebook *self); SYSPROF_AVAILABLE_IN_ALL -void sysprof_notebook_open (SysprofNotebook *self, - GFile *file); +void sysprof_notebook_open (SysprofNotebook *self, + GFile *file); SYSPROF_AVAILABLE_IN_ALL -void sysprof_notebook_save (SysprofNotebook *self); +void sysprof_notebook_save (SysprofNotebook *self); SYSPROF_AVAILABLE_IN_ALL -gboolean sysprof_notebook_get_can_save (SysprofNotebook *self); +gboolean sysprof_notebook_get_can_save (SysprofNotebook *self); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_notebook_replay (SysprofNotebook *self); +SYSPROF_AVAILABLE_IN_ALL +gboolean sysprof_notebook_get_can_replay (SysprofNotebook *self); G_END_DECLS diff --git a/src/sysprof/gtk/menus.ui b/src/sysprof/gtk/menus.ui index d267eeb6..3e0a61f2 100644 --- a/src/sysprof/gtk/menus.ui +++ b/src/sysprof/gtk/menus.ui @@ -25,6 +25,13 @@ <primary>s +
+ + Record Again + win.replay-capture + <primary>r + +
Close diff --git a/src/sysprof/sysprof-application.c b/src/sysprof/sysprof-application.c index ae0f9969..421961ab 100644 --- a/src/sysprof/sysprof-application.c +++ b/src/sysprof/sysprof-application.c @@ -44,6 +44,7 @@ struct { { "zoom.zoom-one", { "0", "KP_0", NULL } }, { "win.new-tab", { "t", NULL } }, { "win.close-tab", { "w", NULL } }, + { "win.replay-capture", { "r", NULL } }, { "win.save-capture", { "s", NULL } }, { "win.switch-tab(1)", { "1", NULL } }, { "win.switch-tab(2)", { "2", NULL } }, diff --git a/src/sysprof/sysprof-window.c b/src/sysprof/sysprof-window.c index 85cf4be4..a861acfe 100644 --- a/src/sysprof/sysprof-window.c +++ b/src/sysprof/sysprof-window.c @@ -54,6 +54,19 @@ sysprof_window_new (SysprofApplication *application) NULL); } +static void +sysprof_window_notify_can_replay_cb (SysprofWindow *self, + GParamSpec *pspec, + SysprofNotebook *notebook) +{ + g_assert (SYSPROF_IS_WINDOW (self)); + g_assert (SYSPROF_IS_NOTEBOOK (notebook)); + + dzl_gtk_widget_action_set (GTK_WIDGET (self), "win", "replay-capture", + "enabled", sysprof_notebook_get_can_replay (notebook), + NULL); +} + static void sysprof_window_notify_can_save_cb (SysprofWindow *self, GParamSpec *pspec, @@ -121,15 +134,23 @@ close_tab_cb (GSimpleAction *action, sysprof_notebook_close_current (self->notebook); } +static void +replay_capture_cb (GSimpleAction *action, + GVariant *param, + gpointer user_data) +{ + SysprofWindow *self = user_data; + g_return_if_fail (SYSPROF_IS_WINDOW (self)); + sysprof_notebook_replay (self->notebook); +} + static void save_capture_cb (GSimpleAction *action, GVariant *param, gpointer user_data) { SysprofWindow *self = user_data; - g_return_if_fail (SYSPROF_IS_WINDOW (self)); - sysprof_notebook_save (self->notebook); } @@ -184,6 +205,7 @@ sysprof_window_init (SysprofWindow *self) { "close-tab", close_tab_cb }, { "new-tab", new_tab_cb }, { "switch-tab", switch_tab_cb, "i" }, + { "replay-capture", replay_capture_cb }, { "save-capture", save_capture_cb }, { "stop-recording", stop_recording_cb }, }; @@ -195,6 +217,12 @@ sysprof_window_init (SysprofWindow *self) G_N_ELEMENTS (actions), self); + g_signal_connect_object (self->notebook, + "notify::can-replay", + G_CALLBACK (sysprof_window_notify_can_replay_cb), + self, + G_CONNECT_SWAPPED); + g_signal_connect_object (self->notebook, "notify::can-save", G_CALLBACK (sysprof_window_notify_can_save_cb), @@ -216,6 +244,9 @@ sysprof_window_init (SysprofWindow *self) dzl_gtk_widget_action_set (GTK_WIDGET (self), "win", "save-capture", "enabled", FALSE, NULL); + dzl_gtk_widget_action_set (GTK_WIDGET (self), "win", "replay-capture", + "enabled", FALSE, + NULL); } void