mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
libsysprof-gtk: start on some loading progress
This commit is contained in:
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user