libsysprof-gtk: start on some loading progress

This commit is contained in:
Christian Hergert
2023-06-19 19:00:22 -07:00
parent 9d6c60a0d6
commit 43ec0e48f5
4 changed files with 185 additions and 23 deletions

View File

@ -23,6 +23,9 @@
#include <errno.h>
#include <unistd.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include "sysprof-bundled-symbolizer.h"
#include "sysprof-document-loader.h"
#include "sysprof-document-private.h"
@ -34,11 +37,13 @@
struct _SysprofDocumentLoader
{
GObject parent_instance;
GMutex mutex;
SysprofSymbolizer *symbolizer;
char *filename;
char *message;
double fraction;
int fd;
guint notify_source;
};
enum {
@ -53,6 +58,43 @@ G_DEFINE_FINAL_TYPE (SysprofDocumentLoader, sysprof_document_loader, G_TYPE_OBJE
static GParamSpec *properties [N_PROPS];
static gboolean
progress_notify_in_idle (gpointer data)
{
SysprofDocumentLoader *self = data;
g_assert (SYSPROF_IS_DOCUMENT_LOADER (self));
g_mutex_lock (&self->mutex);
self->notify_source = 0;
g_mutex_unlock (&self->mutex);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FRACTION]);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MESSAGE]);
return G_SOURCE_REMOVE;
}
static void
set_progress (double fraction,
const char *message,
gpointer user_data)
{
SysprofDocumentLoader *self = user_data;
g_assert (SYSPROF_IS_DOCUMENT_LOADER (self));
g_mutex_lock (&self->mutex);
self->fraction = fraction;
g_set_str (&self->message, message);
if (!self->notify_source)
self->notify_source = g_idle_add_full (G_PRIORITY_LOW,
progress_notify_in_idle,
g_object_ref (self),
g_object_unref);
g_mutex_unlock (&self->mutex);
}
static void
mapped_file_by_filename (GTask *task,
gpointer source_object,
@ -160,15 +202,12 @@ sysprof_document_loader_finalize (GObject *object)
{
SysprofDocumentLoader *self = (SysprofDocumentLoader *)object;
g_clear_handle_id (&self->notify_source, g_source_remove);
g_clear_object (&self->symbolizer);
g_clear_pointer (&self->filename, g_free);
g_clear_pointer (&self->message, g_free);
if (self->fd != -1)
{
close (self->fd);
self->fd = -1;
}
g_clear_fd (&self->fd, NULL);
g_mutex_clear (&self->mutex);
G_OBJECT_CLASS (sysprof_document_loader_parent_class)->finalize (object);
}
@ -249,6 +288,8 @@ sysprof_document_loader_class_init (SysprofDocumentLoaderClass *klass)
static void
sysprof_document_loader_init (SysprofDocumentLoader *self)
{
g_mutex_init (&self->mutex);
self->fd = -1;
set_default_symbolizer (self);
@ -372,11 +413,16 @@ sysprof_document_loader_load_symbols_cb (GObject *object,
SysprofDocument *document = (SysprofDocument *)object;
g_autoptr(GError) error = NULL;
g_autoptr(GTask) task = user_data;
SysprofDocumentLoader *self;
g_assert (SYSPROF_IS_DOCUMENT (document));
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (G_IS_TASK (task));
self = g_task_get_source_object (task);
set_progress (1., _("Document loaded"), self);
if (!_sysprof_document_symbolize_finish (document, result, &error))
g_task_return_error (task, g_steal_pointer (&error));
else
@ -391,16 +437,20 @@ sysprof_document_loader_load_document_cb (GObject *object,
g_autoptr(SysprofDocument) document = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GTask) task = user_data;
SysprofDocumentLoader *self;
SysprofSymbolizer *symbolizer;
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (G_IS_TASK (task));
self = g_task_get_source_object (task);
symbolizer = g_task_get_task_data (task);
g_assert (symbolizer != NULL);
g_assert (SYSPROF_IS_SYMBOLIZER (symbolizer));
set_progress (.9, _("Symbolizing stack traces"), self);
if (!(document = _sysprof_document_new_finish (result, &error)))
g_task_return_error (task, g_steal_pointer (&error));
else
@ -419,14 +469,20 @@ sysprof_document_loader_load_mapped_file_cb (GObject *object,
g_autoptr(GMappedFile) mapped_file = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GTask) task = user_data;
SysprofDocumentLoader *self;
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (G_IS_TASK (task));
self = g_task_get_source_object (task);
if (!(mapped_file = mapped_file_new_finish (result, &error)))
g_task_return_error (task, g_steal_pointer (&error));
else
_sysprof_document_new_async (mapped_file,
set_progress,
g_object_ref (self),
g_object_unref,
g_task_get_cancellable (task),
sysprof_document_loader_load_document_cb,
g_object_ref (task));
@ -462,6 +518,8 @@ sysprof_document_loader_load_async (SysprofDocumentLoader *self,
g_task_set_task_data (task, g_object_ref (self->symbolizer), g_object_unref);
g_task_set_source_tag (task, sysprof_document_loader_load_async);
set_progress (0., _("Loading document"), self);
if (self->fd != -1)
mapped_file_new_from_fd_async (self->fd,
cancellable,
@ -496,6 +554,8 @@ sysprof_document_loader_load_finish (SysprofDocumentLoader *self,
g_return_val_if_fail (G_IS_TASK (result), NULL);
g_return_val_if_fail (g_task_is_valid (result, self), NULL);
set_progress (1., NULL, self);
ret = g_task_propagate_pointer (G_TASK (result), error);
g_return_val_if_fail (!ret || SYSPROF_IS_DOCUMENT (ret), NULL);

View File

@ -38,7 +38,14 @@ typedef struct _SysprofDocumentTimedValue
};
} SysprofDocumentTimedValue;
typedef void (*ProgressFunc) (double fraction,
const char *message,
gpointer user_data);
void _sysprof_document_new_async (GMappedFile *mapped_file,
ProgressFunc progress,
gpointer progress_data,
GDestroyNotify progress_data_destroy,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);

View File

@ -23,6 +23,7 @@
#include <fcntl.h>
#include <glib/gstdio.h>
#include <glib/gi18n.h>
#include "sysprof-document-private.h"
@ -682,6 +683,38 @@ is_data_type (SysprofCaptureFrameType type)
}
}
typedef struct _Load
{
GMappedFile *mapped_file;
ProgressFunc progress;
gpointer progress_data;
GDestroyNotify progress_data_destroy;
} Load;
static void
load_free (Load *load)
{
g_clear_pointer (&load->mapped_file, g_mapped_file_unref);
if (load->progress_data_destroy)
load->progress_data_destroy (load->progress_data);
load->progress = NULL;
load->progress_data = NULL;
load->progress_data_destroy = NULL;
g_free (load);
}
static inline void
load_progress (Load *load,
double fraction,
const char *message)
{
if (load->progress)
load->progress (fraction, message, load->progress_data);
}
static void
sysprof_document_load_worker (GTask *task,
gpointer source_object,
@ -690,18 +723,19 @@ sysprof_document_load_worker (GTask *task,
{
g_autoptr(SysprofDocument) self = NULL;
g_autoptr(GHashTable) files = NULL;
GMappedFile *mapped_file = task_data;
Load *load = task_data;
gint64 guessed_end_nsec = 0;
goffset pos;
gsize len;
guint count;
g_assert (source_object == NULL);
g_assert (mapped_file != NULL);
g_assert (load != NULL);
self = g_object_new (SYSPROF_TYPE_DOCUMENT, NULL);
self->mapped_file = g_mapped_file_ref (mapped_file);
self->base = (const guint8 *)g_mapped_file_get_contents (mapped_file);
len = g_mapped_file_get_length (mapped_file);
self->mapped_file = g_mapped_file_ref (load->mapped_file);
self->base = (const guint8 *)g_mapped_file_get_contents (load->mapped_file);
len = g_mapped_file_get_length (load->mapped_file);
if (len < sizeof self->header)
{
@ -729,6 +763,9 @@ sysprof_document_load_worker (GTask *task,
self->time_span.begin_nsec = self->header.time;
self->time_span.end_nsec = self->header.end_time;
load_progress (load, .1, _("Indexing capture data frames"));
count = 0;
pos = sizeof self->header;
while (pos < (len - sizeof(guint16)))
{
@ -853,18 +890,35 @@ sysprof_document_load_worker (GTask *task,
}
pos += frame_len;
count++;
g_array_append_val (self->frames, ptr);
if (count % 100 == 0)
load_progress (load,
(pos / (double)len) * .4,
_("Indexing capture data frames"));
}
if (guessed_end_nsec != 0)
self->time_span.end_nsec = guessed_end_nsec;
load_progress (load, .6, _("Discovering file system mounts"));
sysprof_document_load_mounts (self);
load_progress (load, .65, _("Discovering process mount namespaces"));
sysprof_document_load_mountinfos (self);
load_progress (load, .7, _("Analyzing process address layouts"));
sysprof_document_load_memory_maps (self);
load_progress (load, .75, _("Analyzing process command line"));
sysprof_document_load_processes (self);
load_progress (load, .8, _("Analyzing file system overlays"));
sysprof_document_load_overlays (self);
load_progress (load, .85, _("Processing counters"));
sysprof_document_load_counters (self);
g_task_return_pointer (task, g_steal_pointer (&self), g_object_unref);
@ -872,20 +926,28 @@ sysprof_document_load_worker (GTask *task,
void
_sysprof_document_new_async (GMappedFile *mapped_file,
ProgressFunc progress,
gpointer progress_data,
GDestroyNotify progress_data_destroy,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
Load *load;
g_return_if_fail (mapped_file != NULL);
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
load = g_new0 (Load, 1);
load->mapped_file = g_mapped_file_ref (mapped_file);
load->progress = progress;
load->progress_data = progress_data;
load->progress_data_destroy = progress_data_destroy;
task = g_task_new (NULL, cancellable, callback, user_data);
g_task_set_source_tag (task, _sysprof_document_new_async);
g_task_set_task_data (task,
g_mapped_file_ref (mapped_file),
(GDestroyNotify)g_mapped_file_unref);
g_task_set_task_data (task, load, (GDestroyNotify)load_free);
g_task_run_in_thread (task, sysprof_document_load_worker);
}

View File

@ -35,6 +35,28 @@ static const GOptionEntry entries[] = {
{ 0 }
};
static void
load_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
g_autoptr(GtkWidget) view = user_data;
g_autoptr(SysprofDocument) document = NULL;
g_autoptr(GListModel) model = NULL;
g_autoptr(GError) error = NULL;
document = sysprof_document_loader_load_finish (SYSPROF_DOCUMENT_LOADER (object), result, &error);
g_assert_no_error (error);
g_assert_nonnull (document);
model = sysprof_document_list_samples (document);
g_object_set (view,
"document", document,
"traceables", model,
NULL);
}
int
main (int argc,
char *argv[])
@ -43,11 +65,13 @@ main (int argc,
g_autoptr(SysprofDocumentLoader) loader = NULL;
g_autoptr(SysprofDocument) document = NULL;
g_autoptr(SysprofMultiSymbolizer) multi = NULL;
g_autoptr(GListModel) model = NULL;
g_autoptr(GError) error = NULL;
SysprofCallgraphView *view;
GtkWidget *box;
GtkWidget *hbox;
GtkWidget *status;
GtkWidget *progress;
GtkWidget *message;
GtkWidget *threads;
GtkWindow *window;
@ -93,12 +117,6 @@ main (int argc,
loader = sysprof_document_loader_new (filename);
sysprof_document_loader_set_symbolizer (loader, SYSPROF_SYMBOLIZER (multi));
g_print ("Loading %s, ignoring embedded symbols...\n", filename);
if (!(document = sysprof_document_loader_load (loader, NULL, &error)))
g_error ("Failed to load document: %s", error->message);
model = sysprof_document_list_samples (document);
window = g_object_new (GTK_TYPE_WINDOW,
"default-width", 800,
"default-height", 600,
@ -117,19 +135,34 @@ main (int argc,
NULL);
gtk_box_append (GTK_BOX (hbox), threads);
view = g_object_new (SYSPROF_TYPE_WEIGHTED_CALLGRAPH_VIEW,
"traceables", model,
"document", document,
"include-threads", include_threads,
"vexpand", TRUE,
NULL);
gtk_box_append (GTK_BOX (box), GTK_WIDGET (view));
g_signal_connect_swapped (window,
"close-request",
G_CALLBACK (g_main_loop_quit),
main_loop);
status = g_object_new (GTK_TYPE_BOX,
"spacing", 6,
NULL);
message = g_object_new (GTK_TYPE_LABEL,
"xalign", .0f,
"hexpand", TRUE,
NULL);
progress = g_object_new (GTK_TYPE_PROGRESS_BAR,
NULL);
gtk_box_append (GTK_BOX (status), message);
gtk_box_append (GTK_BOX (status), progress);
gtk_box_append (GTK_BOX (box), status);
gtk_window_set_child (window, box);
gtk_window_present (window);
g_object_bind_property (threads, "active", view, "include-threads", 0);
g_object_bind_property (loader, "message", message, "label", 0);
g_object_bind_property (loader, "fraction", progress, "fraction", 0);
sysprof_document_loader_load_async (loader, NULL, load_cb, g_object_ref (view));
g_main_loop_run (main_loop);