From 00ecc4120990a9bb6761550e958ee851cecd6b59 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Fri, 12 May 2023 17:20:10 -0700 Subject: [PATCH] libsysprof-analyze: make SysprofDocumentSymbols private This instead moves to a public API on the document to symbolize now that we've gotten much of the necessary bits private in loading the document. This commit ensures that we only do loading via the loader now (and removes the incorrect use from the tests so they too go through the loader). We check for NoSymbolizer in document symbols so that we can skip any decoding. That keeps various use cases fast where you don't want to waste time on symbolizing if you don't need to look at symbols. There is plenty more we can do to batch decode symbols with some more API changes, but that will come after we have kernel/userland decoding integrated from this library. We may still want to get all symbols into a single symbol cache, but given that we have address ranges associated with them, that may not be very useful beyond the hashtable to pid-specific cache we have now. If symbols were shared between processes, that'd make more sense, but we aren't doing that (albeit strings are shared between symbol instances to reduce that overhead). --- src/libsysprof-analyze/meson.build | 3 +- src/libsysprof-analyze/sysprof-analyze.h | 1 - .../sysprof-document-loader.c | 208 +++++++++++++++--- .../sysprof-document-private.h | 35 +-- .../sysprof-document-symbols-private.h | 29 ++- .../sysprof-document-symbols.c | 14 +- .../sysprof-document-symbols.h | 43 ---- src/libsysprof-analyze/sysprof-document.c | 196 ++++++++++------- src/libsysprof-analyze/sysprof-document.h | 19 +- .../sysprof-multi-symbolizer.c | 4 +- .../sysprof-multi-symbolizer.h | 2 +- .../sysprof-no-symbolizer.c | 22 +- .../sysprof-no-symbolizer.h | 17 +- .../tests/test-capture-model.c | 12 +- .../tests/test-list-files.c | 6 +- .../tests/test-list-processes.c | 6 +- .../tests/test-print-file.c | 6 +- src/libsysprof-analyze/tests/test-symbolize.c | 108 ++++----- 18 files changed, 463 insertions(+), 268 deletions(-) delete mode 100644 src/libsysprof-analyze/sysprof-document-symbols.h diff --git a/src/libsysprof-analyze/meson.build b/src/libsysprof-analyze/meson.build index bd779c7f..ba11a216 100644 --- a/src/libsysprof-analyze/meson.build +++ b/src/libsysprof-analyze/meson.build @@ -14,7 +14,6 @@ libsysprof_analyze_public_sources = [ 'sysprof-document-mmap.c', 'sysprof-document-process.c', 'sysprof-document-sample.c', - 'sysprof-document-symbols.c', 'sysprof-document-traceable.c', 'sysprof-kallsyms-symbolizer.c', 'sysprof-multi-symbolizer.c', @@ -26,6 +25,7 @@ libsysprof_analyze_public_sources = [ libsysprof_analyze_private_sources = [ 'sysprof-address-layout.c', 'sysprof-document-bitset-index.c', + 'sysprof-document-symbols.c', 'sysprof-mount.c', 'sysprof-mount-device.c', 'sysprof-mount-namespace.c', @@ -51,7 +51,6 @@ libsysprof_analyze_public_headers = [ 'sysprof-document-mmap.h', 'sysprof-document-process.h', 'sysprof-document-sample.h', - 'sysprof-document-symbols.h', 'sysprof-document-traceable.h', 'sysprof-mount.h', 'sysprof-kallsyms-symbolizer.h', diff --git a/src/libsysprof-analyze/sysprof-analyze.h b/src/libsysprof-analyze/sysprof-analyze.h index f751127a..0461cd82 100644 --- a/src/libsysprof-analyze/sysprof-analyze.h +++ b/src/libsysprof-analyze/sysprof-analyze.h @@ -40,7 +40,6 @@ G_BEGIN_DECLS # include "sysprof-document-mmap.h" # include "sysprof-document-process.h" # include "sysprof-document-sample.h" -# include "sysprof-document-symbols.h" # include "sysprof-document-traceable.h" # include "sysprof-mount.h" # include "sysprof-kallsyms-symbolizer.h" diff --git a/src/libsysprof-analyze/sysprof-document-loader.c b/src/libsysprof-analyze/sysprof-document-loader.c index 7d4fc8fe..cfe65c52 100644 --- a/src/libsysprof-analyze/sysprof-document-loader.c +++ b/src/libsysprof-analyze/sysprof-document-loader.c @@ -20,8 +20,13 @@ #include "config.h" +#include +#include + +#include "sysprof-bundled-symbolizer.h" #include "sysprof-document-loader.h" #include "sysprof-document-private.h" +#include "sysprof-multi-symbolizer.h" struct _SysprofDocumentLoader { @@ -45,6 +50,105 @@ G_DEFINE_FINAL_TYPE (SysprofDocumentLoader, sysprof_document_loader, G_TYPE_OBJE static GParamSpec *properties [N_PROPS]; +static void +mapped_file_by_filename (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GMappedFile) mapped_file = g_mapped_file_new (task_data, FALSE, &error); + + if (mapped_file != NULL) + g_task_return_pointer (task, + g_steal_pointer (&mapped_file), + (GDestroyNotify)g_mapped_file_unref); + else + g_task_return_error (task, g_steal_pointer (&error)); +} + +static void +mapped_file_new_async (const char *filename, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = g_task_new (NULL, cancellable, callback, user_data); + g_task_set_task_data (task, g_strdup (filename), g_free); + g_task_run_in_thread (task, mapped_file_by_filename); +} + +static void +mapped_file_by_fd (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GMappedFile) mapped_file = g_mapped_file_new_from_fd (GPOINTER_TO_INT (task_data), FALSE, &error); + + if (mapped_file != NULL) + g_task_return_pointer (task, + g_steal_pointer (&mapped_file), + (GDestroyNotify)g_mapped_file_unref); + else + g_task_return_error (task, g_steal_pointer (&error)); +} + +static void +close_fd (gpointer data) +{ + int fd = GPOINTER_TO_INT (data); + close (fd); +} + +static void +mapped_file_new_from_fd_async (int fd, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + int copy_fd; + + task = g_task_new (NULL, cancellable, callback, user_data); + + if (-1 == (copy_fd = dup (fd))) + { + int errsv = errno; + g_task_return_new_error (task, + G_IO_ERROR, + g_io_error_from_errno (errsv), + "%s", + g_strerror (errsv)); + return; + } + + g_task_set_task_data (task, GINT_TO_POINTER (copy_fd), close_fd); + g_task_run_in_thread (task, mapped_file_by_fd); +} + +static GMappedFile * +mapped_file_new_finish (GAsyncResult *result, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (result), error); +} + +static void +set_default_symbolizer (SysprofDocumentLoader *self) +{ + g_autoptr(SysprofMultiSymbolizer) multi = NULL; + + g_assert (SYSPROF_IS_DOCUMENT_LOADER (self)); + + g_clear_object (&self->symbolizer); + + multi = sysprof_multi_symbolizer_new (); + sysprof_multi_symbolizer_take (multi, sysprof_bundled_symbolizer_new ()); + self->symbolizer = SYSPROF_SYMBOLIZER (g_steal_pointer (&multi)); +} + static void sysprof_document_loader_finalize (GObject *object) { @@ -140,6 +244,8 @@ static void sysprof_document_loader_init (SysprofDocumentLoader *self) { self->fd = -1; + + set_default_symbolizer (self); } SysprofDocumentLoader * @@ -210,7 +316,11 @@ sysprof_document_loader_set_symbolizer (SysprofDocumentLoader *self, g_return_if_fail (SYSPROF_IS_DOCUMENT_LOADER (self)); if (g_set_object (&self->symbolizer, symbolizer)) - g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SYMBOLIZER]); + { + if (self->symbolizer == NULL) + set_default_symbolizer (self); + g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SYMBOLIZER]); + } } /** @@ -249,12 +359,11 @@ sysprof_document_loader_get_message (SysprofDocumentLoader *self) } static void -sysprof_document_loader_load_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) +sysprof_document_loader_load_symbols_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) { SysprofDocument *document = (SysprofDocument *)object; - g_autoptr(SysprofDocumentSymbols) symbols = NULL; g_autoptr(GError) error = NULL; g_autoptr(GTask) task = user_data; @@ -262,12 +371,61 @@ sysprof_document_loader_load_cb (GObject *object, g_assert (G_IS_ASYNC_RESULT (result)); g_assert (G_IS_TASK (task)); - if (!(symbols = _sysprof_document_symbolize_finish (document, result, &error))) + if (!_sysprof_document_symbolize_finish (document, result, &error)) g_task_return_error (task, g_steal_pointer (&error)); else g_task_return_pointer (task, g_object_ref (document), g_object_unref); } +static void +sysprof_document_loader_load_document_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr(SysprofDocument) document = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = user_data; + SysprofSymbolizer *symbolizer; + + g_assert (G_IS_ASYNC_RESULT (result)); + g_assert (G_IS_TASK (task)); + + symbolizer = g_task_get_task_data (task); + + g_assert (symbolizer != NULL); + g_assert (SYSPROF_IS_SYMBOLIZER (symbolizer)); + + if (!(document = _sysprof_document_new_finish (result, &error))) + g_task_return_error (task, g_steal_pointer (&error)); + else + _sysprof_document_symbolize_async (document, + symbolizer, + g_task_get_cancellable (task), + sysprof_document_loader_load_symbols_cb, + g_object_ref (task)); +} + +static void +sysprof_document_loader_load_mapped_file_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr(GMappedFile) mapped_file = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = user_data; + + g_assert (G_IS_ASYNC_RESULT (result)); + g_assert (G_IS_TASK (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, + g_task_get_cancellable (task), + sysprof_document_loader_load_document_cb, + g_object_ref (task)); +} + /** * sysprof_document_loader_load_async: * @self: a #SysprofDocumentLoader @@ -285,43 +443,29 @@ sysprof_document_loader_load_async (SysprofDocumentLoader *self, GAsyncReadyCallback callback, gpointer user_data) { - g_autoptr(SysprofDocument) document = NULL; + g_autoptr(SysprofSymbolizer) symbolizer = NULL; + g_autoptr(GMappedFile) mapped_file = NULL; g_autoptr(GError) error = NULL; g_autoptr(GTask) task = NULL; g_return_if_fail (SYSPROF_IS_DOCUMENT_LOADER (self)); g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (self->filename != NULL || self->fd != -1); task = g_task_new (self, cancellable, callback, user_data); + 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); - if (self->fd == -1 && self->filename == NULL) - { - g_task_return_new_error (task, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "SysprofDocumentLoader disposition must have fd or filename set"); - return; - } - if (self->fd != -1) - document = _sysprof_document_new_from_fd (self->fd, &error); - else if (self->filename != NULL) - document = _sysprof_document_new (self->filename, &error); + mapped_file_new_from_fd_async (self->fd, + cancellable, + sysprof_document_loader_load_mapped_file_cb, + g_steal_pointer (&task)); else - g_assert_not_reached (); - - /* TODO: This will probably get renamed to load_async as we want - * to always have a symbolizer for loading. Additionally, the - * document will deal with caches directly instead of the symbols - * object. - */ - - _sysprof_document_symbolize_async (document, - self->symbolizer, - cancellable, - sysprof_document_loader_load_cb, - g_steal_pointer (&task)); + mapped_file_new_async (self->filename, + cancellable, + sysprof_document_loader_load_mapped_file_cb, + g_steal_pointer (&task)); } /** diff --git a/src/libsysprof-analyze/sysprof-document-private.h b/src/libsysprof-analyze/sysprof-document-private.h index 5993e6ea..a289a073 100644 --- a/src/libsysprof-analyze/sysprof-document-private.h +++ b/src/libsysprof-analyze/sysprof-document-private.h @@ -23,24 +23,27 @@ #include #include "sysprof-document.h" +#include "sysprof-symbolizer.h" G_BEGIN_DECLS -SysprofDocument *_sysprof_document_new (const char *filename, - GError **error); -SysprofDocument *_sysprof_document_new_from_fd (int capture_fd, - GError **error); -void _sysprof_document_symbolize_async (SysprofDocument *self, - SysprofSymbolizer *symbolizer, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -SysprofDocumentSymbols *_sysprof_document_symbolize_finish (SysprofDocument *self, - GAsyncResult *result, - GError **error); -gboolean _sysprof_document_is_native (SysprofDocument *self); -char *_sysprof_document_ref_string (SysprofDocument *self, - const char *name); -GtkBitset *_sysprof_document_traceables (SysprofDocument *self); +void _sysprof_document_new_async (GMappedFile *mapped_file, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +SysprofDocument *_sysprof_document_new_finish (GAsyncResult *result, + GError **error); +void _sysprof_document_symbolize_async (SysprofDocument *self, + SysprofSymbolizer *symbolizer, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean _sysprof_document_symbolize_finish (SysprofDocument *self, + GAsyncResult *result, + GError **error); +gboolean _sysprof_document_is_native (SysprofDocument *self); +char *_sysprof_document_ref_string (SysprofDocument *self, + const char *name); +GtkBitset *_sysprof_document_traceables (SysprofDocument *self); G_END_DECLS diff --git a/src/libsysprof-analyze/sysprof-document-symbols-private.h b/src/libsysprof-analyze/sysprof-document-symbols-private.h index 58ac1faa..680b6468 100644 --- a/src/libsysprof-analyze/sysprof-document-symbols-private.h +++ b/src/libsysprof-analyze/sysprof-document-symbols-private.h @@ -21,19 +21,28 @@ #pragma once #include "sysprof-document.h" -#include "sysprof-document-symbols.h" #include "sysprof-process-info-private.h" +#include "sysprof-symbolizer.h" +#include "sysprof-symbol.h" G_BEGIN_DECLS -void _sysprof_document_symbols_new (SysprofDocument *document, - SysprofStrings *strings, - SysprofSymbolizer *symbolizer, - GHashTable *pid_to_process_info, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -SysprofDocumentSymbols *_sysprof_document_symbols_new_finish (GAsyncResult *result, - GError **error); +#define SYSPROF_TYPE_DOCUMENT_SYMBOLS (sysprof_document_symbols_get_type()) + +G_DECLARE_FINAL_TYPE (SysprofDocumentSymbols, sysprof_document_symbols, SYSPROF, DOCUMENT_SYMBOLS, GObject) + +void _sysprof_document_symbols_new (SysprofDocument *document, + SysprofStrings *strings, + SysprofSymbolizer *symbolizer, + GHashTable *pid_to_process_info, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +SysprofDocumentSymbols *_sysprof_document_symbols_new_finish (GAsyncResult *result, + GError **error); +SysprofSymbol *_sysprof_document_symbols_lookup (SysprofDocumentSymbols *symbols, + int pid, + SysprofAddressContext context, + SysprofAddress address); G_END_DECLS diff --git a/src/libsysprof-analyze/sysprof-document-symbols.c b/src/libsysprof-analyze/sysprof-document-symbols.c index b087d0ab..9c499611 100644 --- a/src/libsysprof-analyze/sysprof-document-symbols.c +++ b/src/libsysprof-analyze/sysprof-document-symbols.c @@ -25,6 +25,7 @@ #include "sysprof-document-symbols-private.h" #include "sysprof-document-traceable.h" #include "sysprof-mount-namespace-private.h" +#include "sysprof-no-symbolizer.h" #include "sysprof-symbol-private.h" #include "sysprof-symbol-cache-private.h" #include "sysprof-symbolizer-private.h" @@ -175,7 +176,8 @@ sysprof_document_symbols_worker (GTask *task, } /* Walk through the available traceables which need symbols extracted */ - if (gtk_bitset_iter_init_first (&iter, bitset, &i)) + if (!SYSPROF_IS_NO_SYMBOLIZER (state->symbolizer) && + gtk_bitset_iter_init_first (&iter, bitset, &i)) { do { @@ -243,7 +245,7 @@ _sysprof_document_symbols_new_finish (GAsyncResult *result, } /** - * sysprof_document_symbols_lookup: + * _sysprof_document_symbols_lookup: * @self: a #SysprofDocumentSymbols * @pid: the process identifier * @context: the #SysprofAddressContext for the address @@ -254,10 +256,10 @@ _sysprof_document_symbols_new_finish (GAsyncResult *result, * Returns: (transfer none) (nullable): a #SysprofSymbol or %NULL */ SysprofSymbol * -sysprof_document_symbols_lookup (SysprofDocumentSymbols *self, - int pid, - SysprofAddressContext context, - SysprofAddress address) +_sysprof_document_symbols_lookup (SysprofDocumentSymbols *self, + int pid, + SysprofAddressContext context, + SysprofAddress address) { SysprofAddressContext new_context; SysprofProcessInfo *process_info; diff --git a/src/libsysprof-analyze/sysprof-document-symbols.h b/src/libsysprof-analyze/sysprof-document-symbols.h deleted file mode 100644 index 556476f5..00000000 --- a/src/libsysprof-analyze/sysprof-document-symbols.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * sysprof-document-symbols.h - * - * Copyright 2023 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#pragma once - -#include - -#include - -#include "sysprof-symbol.h" - -G_BEGIN_DECLS - -#define SYSPROF_TYPE_DOCUMENT_SYMBOLS (sysprof_document_symbols_get_type()) - -SYSPROF_AVAILABLE_IN_ALL -G_DECLARE_FINAL_TYPE (SysprofDocumentSymbols, sysprof_document_symbols, SYSPROF, DOCUMENT_SYMBOLS, GObject) - -SYSPROF_AVAILABLE_IN_ALL -SysprofSymbol *sysprof_document_symbols_lookup (SysprofDocumentSymbols *symbols, - int pid, - SysprofAddressContext context, - SysprofAddress address); - -G_END_DECLS diff --git a/src/libsysprof-analyze/sysprof-document.c b/src/libsysprof-analyze/sysprof-document.c index 0449944a..2e8911e8 100644 --- a/src/libsysprof-analyze/sysprof-document.c +++ b/src/libsysprof-analyze/sysprof-document.c @@ -63,6 +63,8 @@ struct _SysprofDocument SysprofMountNamespace *mount_namespace; + SysprofDocumentSymbols *symbols; + SysprofCaptureFileHeader header; guint needs_swap : 1; }; @@ -197,6 +199,7 @@ sysprof_document_finalize (GObject *object) g_clear_pointer (&self->pids, gtk_bitset_unref); g_clear_object (&self->mount_namespace); + g_clear_object (&self->symbols); g_clear_pointer (&self->files_first_position, g_hash_table_unref); @@ -390,26 +393,34 @@ sysprof_document_load_mountinfos (SysprofDocument *self) } } -static gboolean -sysprof_document_load (SysprofDocument *self, - int capture_fd, - GError **error) +static void +sysprof_document_load_worker (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) { + g_autoptr(SysprofDocument) self = NULL; g_autoptr(GHashTable) files = NULL; + GMappedFile *mapped_file = task_data; goffset pos; gsize len; - g_assert (SYSPROF_IS_DOCUMENT (self)); - g_assert (capture_fd > -1); + g_assert (source_object == NULL); + g_assert (mapped_file != NULL); - if (!(self->mapped_file = g_mapped_file_new_from_fd (capture_fd, FALSE, error))) - return FALSE; - - self->base = (const guint8 *)g_mapped_file_get_contents (self->mapped_file); - len = g_mapped_file_get_length (self->mapped_file); + 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); if (len < sizeof self->header) - return FALSE; + { + g_task_return_new_error (task, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "File header too short"); + return; + } /* Keep a copy of our header */ memcpy (&self->header, self->base, sizeof self->header); @@ -479,77 +490,39 @@ sysprof_document_load (SysprofDocument *self, sysprof_document_load_mountinfos (self); sysprof_document_load_memory_maps (self); - return TRUE; + g_task_return_pointer (task, g_steal_pointer (&self), g_object_unref); } -/** - * _sysprof_document_new_from_fd: - * @capture_fd: a file-descriptor to be mapped - * @error: a location for a #GError, or %NULL - * - * Creates a new memory map using @capture_fd to read the underlying - * Sysprof capture. - * - * No ownership of @capture_fd is transferred, and the caller may close - * @capture_fd after calling this function. - * - * Returns: A #SysprofDocument if successful; otherwise %NULL - * and @error is set. - */ -SysprofDocument * -_sysprof_document_new_from_fd (int capture_fd, - GError **error) +void +_sysprof_document_new_async (GMappedFile *mapped_file, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - g_autoptr(SysprofDocument) self = NULL; + g_autoptr(GTask) task = NULL; - g_return_val_if_fail (capture_fd > -1, NULL); + g_return_if_fail (mapped_file != NULL); + g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); - self = g_object_new (SYSPROF_TYPE_DOCUMENT, NULL); - - if (!sysprof_document_load (self, capture_fd, error)) - return NULL; - - return g_steal_pointer (&self); + 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_run_in_thread (task, sysprof_document_load_worker); } -/** - * sysprof_document_new: - * @filename: a path to a capture file - * @error: location for a #GError, or %NULL - * - * Similar to sysprof_document_new_from_fd() but opens the file found - * at @filename as a #GMappedFile. - * - * Returns: a #SysprofDocument if successful; otherwise %NULL - * and @error is set. - * - * Since: 45.0 - */ SysprofDocument * -_sysprof_document_new (const char *filename, - GError **error) +_sysprof_document_new_finish (GAsyncResult *result, + GError **error) { - g_autoptr(SysprofDocument) self = NULL; - g_autofd int capture_fd = -1; + SysprofDocument *ret; - g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (G_IS_TASK (result), NULL); + ret = g_task_propagate_pointer (G_TASK (result), error); + g_return_val_if_fail (!ret || SYSPROF_IS_DOCUMENT (ret), NULL); - if (-1 == (capture_fd = g_open (filename, O_RDONLY|O_CLOEXEC, 0))) - { - int errsv = errno; - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "%s", g_strerror (errsv)); - return NULL; - } - - self = g_object_new (SYSPROF_TYPE_DOCUMENT, NULL); - - if (!sysprof_document_load (self, capture_fd, error)) - return NULL; - - return g_steal_pointer (&self); + return ret; } char * @@ -569,14 +542,25 @@ sysprof_document_symbolize_symbols_cb (GObject *object, g_autoptr(SysprofDocumentSymbols) symbols = NULL; g_autoptr(GTask) task = user_data; g_autoptr(GError) error = NULL; + SysprofDocument *self; g_assert (G_IS_ASYNC_RESULT (result)); g_assert (G_IS_TASK (task)); - if ((symbols = _sysprof_document_symbols_new_finish (result, &error))) - g_task_return_pointer (task, g_steal_pointer (&symbols), g_object_unref); - else - g_task_return_error (task, g_steal_pointer (&error)); + if (!(symbols = _sysprof_document_symbols_new_finish (result, &error))) + { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + self = g_task_get_source_object (task); + + g_assert (self != NULL); + g_assert (SYSPROF_IS_DOCUMENT (self)); + + g_set_object (&self->symbols, symbols); + + g_task_return_boolean (task, TRUE); } static void @@ -635,17 +619,17 @@ _sysprof_document_symbolize_async (SysprofDocument *self, g_steal_pointer (&task)); } -SysprofDocumentSymbols * +gboolean _sysprof_document_symbolize_finish (SysprofDocument *self, GAsyncResult *result, GError **error) { - g_return_val_if_fail (SYSPROF_IS_DOCUMENT (self), NULL); - g_return_val_if_fail (G_IS_TASK (result), NULL); - g_return_val_if_fail (g_task_is_valid (result, self), NULL); - g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == _sysprof_document_symbolize_async, NULL); + g_return_val_if_fail (SYSPROF_IS_DOCUMENT (self), FALSE); + g_return_val_if_fail (G_IS_TASK (result), FALSE); + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == _sysprof_document_symbolize_async, FALSE); - return g_task_propagate_pointer (G_TASK (result), error); + return g_task_propagate_boolean (G_TASK (result), error); } gboolean @@ -796,3 +780,51 @@ sysprof_document_list_processes (SysprofDocument *self) return _sysprof_document_bitset_index_new (G_LIST_MODEL (self), self->processes); } + +/** + * sysprof_document_symbolize_traceable: (skip) + * @self: a #SysprofDocument + * @traceable: the traceable to extract symbols for + * @symbols: an array to store #SysprofSymbols + * @n_symbols: the number of elements in @symbols + * + * Batch symbolizing of a traceable. + * + * No ownership is transfered into @symbols and may be cheaply + * discarded if using the stack for storage. + * + * Returns: The number of symbols or NULL set in @symbols. + */ +guint +sysprof_document_symbolize_traceable (SysprofDocument *self, + SysprofDocumentTraceable *traceable, + SysprofSymbol **symbols, + guint n_symbols) +{ + SysprofAddressContext last_context = SYSPROF_ADDRESS_CONTEXT_NONE; + SysprofAddress *addresses; + guint n_addresses; + int pid; + + g_return_val_if_fail (SYSPROF_IS_DOCUMENT (self), 0); + g_return_val_if_fail (SYSPROF_IS_DOCUMENT_TRACEABLE (traceable), 0); + + if (n_symbols == 0 || symbols == NULL) + return 0; + + pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable)); + addresses = g_alloca (sizeof (SysprofAddress) * n_symbols); + n_addresses = sysprof_document_traceable_get_stack_addresses (traceable, addresses, n_symbols); + + for (guint i = 0; i < n_addresses; i++) + { + SysprofAddressContext context; + + symbols[i] = _sysprof_document_symbols_lookup (self->symbols, pid, last_context, addresses[i]); + + if (sysprof_address_is_context_switch (addresses[i], &context)) + last_context = context; + } + + return n_addresses; +} diff --git a/src/libsysprof-analyze/sysprof-document.h b/src/libsysprof-analyze/sysprof-document.h index aed68f10..19567d2d 100644 --- a/src/libsysprof-analyze/sysprof-document.h +++ b/src/libsysprof-analyze/sysprof-document.h @@ -25,8 +25,8 @@ #include #include "sysprof-document-file.h" -#include "sysprof-document-symbols.h" -#include "sysprof-symbolizer.h" +#include "sysprof-document-traceable.h" +#include "sysprof-symbol.h" G_BEGIN_DECLS @@ -36,13 +36,18 @@ SYSPROF_AVAILABLE_IN_ALL G_DECLARE_FINAL_TYPE (SysprofDocument, sysprof_document, SYSPROF, DOCUMENT, GObject) SYSPROF_AVAILABLE_IN_ALL -SysprofDocumentFile *sysprof_document_lookup_file (SysprofDocument *self, - const char *path); +SysprofDocumentFile *sysprof_document_lookup_file (SysprofDocument *self, + const char *path); SYSPROF_AVAILABLE_IN_ALL -GListModel *sysprof_document_list_files (SysprofDocument *self); +GListModel *sysprof_document_list_files (SysprofDocument *self); SYSPROF_AVAILABLE_IN_ALL -GListModel *sysprof_document_list_traceables (SysprofDocument *self); +GListModel *sysprof_document_list_traceables (SysprofDocument *self); SYSPROF_AVAILABLE_IN_ALL -GListModel *sysprof_document_list_processes (SysprofDocument *self); +GListModel *sysprof_document_list_processes (SysprofDocument *self); +SYSPROF_AVAILABLE_IN_ALL +guint sysprof_document_symbolize_traceable (SysprofDocument *self, + SysprofDocumentTraceable *traceable, + SysprofSymbol **symbols, + guint n_symbols); G_END_DECLS diff --git a/src/libsysprof-analyze/sysprof-multi-symbolizer.c b/src/libsysprof-analyze/sysprof-multi-symbolizer.c index d39008ea..995a3d35 100644 --- a/src/libsysprof-analyze/sysprof-multi-symbolizer.c +++ b/src/libsysprof-analyze/sysprof-multi-symbolizer.c @@ -181,8 +181,8 @@ sysprof_multi_symbolizer_new (void) * that will be queried when @self is queried for symbols. */ void -sysprof_multi_symbolizer_add (SysprofMultiSymbolizer *self, - SysprofSymbolizer *symbolizer) +sysprof_multi_symbolizer_take (SysprofMultiSymbolizer *self, + SysprofSymbolizer *symbolizer) { g_return_if_fail (SYSPROF_IS_MULTI_SYMBOLIZER (self)); g_return_if_fail (SYSPROF_IS_SYMBOLIZER (symbolizer)); diff --git a/src/libsysprof-analyze/sysprof-multi-symbolizer.h b/src/libsysprof-analyze/sysprof-multi-symbolizer.h index 9beffe91..2ac53f47 100644 --- a/src/libsysprof-analyze/sysprof-multi-symbolizer.h +++ b/src/libsysprof-analyze/sysprof-multi-symbolizer.h @@ -37,7 +37,7 @@ GType sysprof_multi_symbolizer_get_type (void) G_GNUC_CONST; SYSPROF_AVAILABLE_IN_ALL SysprofMultiSymbolizer *sysprof_multi_symbolizer_new (void); SYSPROF_AVAILABLE_IN_ALL -void sysprof_multi_symbolizer_add (SysprofMultiSymbolizer *self, +void sysprof_multi_symbolizer_take (SysprofMultiSymbolizer *self, SysprofSymbolizer *symbolizer); G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofMultiSymbolizer, g_object_unref) diff --git a/src/libsysprof-analyze/sysprof-no-symbolizer.c b/src/libsysprof-analyze/sysprof-no-symbolizer.c index 9f803c5c..372fcfe7 100644 --- a/src/libsysprof-analyze/sysprof-no-symbolizer.c +++ b/src/libsysprof-analyze/sysprof-no-symbolizer.c @@ -21,12 +21,18 @@ #include "config.h" #include "sysprof-no-symbolizer.h" +#include "sysprof-symbolizer-private.h" struct _SysprofNoSymbolizer { SysprofSymbolizer parent_instance; }; +struct _SysprofNoSymbolizerClass +{ + SysprofSymbolizerClass parent_class; +}; + G_DEFINE_FINAL_TYPE (SysprofNoSymbolizer, sysprof_no_symbolizer, SYSPROF_TYPE_SYMBOLIZER) static SysprofSymbol * @@ -51,8 +57,20 @@ sysprof_no_symbolizer_init (SysprofNoSymbolizer *self) { } +/** + * sysprof_no_symbolizer_get: + * + * Gets a #SysprofSymbolizer that will never symbolize. + * + * Returns: (transfer none): a #SysprofSymbolizer + */ SysprofSymbolizer * -sysprof_no_symbolizer_new (void) +sysprof_no_symbolizer_get (void) { - return g_object_new (SYSPROF_TYPE_NO_SYMBOLIZER, NULL); + static SysprofSymbolizer *instance; + + if (g_once_init_enter (&instance)) + g_once_init_leave (&instance, g_object_new (SYSPROF_TYPE_NO_SYMBOLIZER, NULL)); + + return instance; } diff --git a/src/libsysprof-analyze/sysprof-no-symbolizer.h b/src/libsysprof-analyze/sysprof-no-symbolizer.h index ebe620b1..e958b670 100644 --- a/src/libsysprof-analyze/sysprof-no-symbolizer.h +++ b/src/libsysprof-analyze/sysprof-no-symbolizer.h @@ -20,18 +20,23 @@ #pragma once -#include - #include "sysprof-symbolizer.h" G_BEGIN_DECLS -#define SYSPROF_TYPE_NO_SYMBOLIZER (sysprof_no_symbolizer_get_type()) +#define SYSPROF_TYPE_NO_SYMBOLIZER (sysprof_no_symbolizer_get_type()) +#define SYSPROF_IS_NO_SYMBOLIZER(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_NO_SYMBOLIZER) +#define SYSPROF_NO_SYMBOLIZER(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_NO_SYMBOLIZER, SysprofNoSymbolizer) +#define SYSPROF_NO_SYMBOLIZER_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_NO_SYMBOLIZER, SysprofNoSymbolizerClass) + +typedef struct _SysprofNoSymbolizer SysprofNoSymbolizer; +typedef struct _SysprofNoSymbolizerClass SysprofNoSymbolizerClass; SYSPROF_AVAILABLE_IN_ALL -G_DECLARE_DERIVABLE_TYPE (SysprofNoSymbolizer, sysprof_no_symbolizer, SYSPROF, NO_SYMBOLIZER, SysprofSymbolizer) - +GType sysprof_no_symbolizer_get_type (void) G_GNUC_CONST; SYSPROF_AVAILABLE_IN_ALL -SysprofSymbolizer *sysprof_no_symbolizer_new (void); +SysprofSymbolizer *sysprof_no_symbolizer_get (void); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofNoSymbolizer, g_object_unref) G_END_DECLS diff --git a/src/libsysprof-analyze/tests/test-capture-model.c b/src/libsysprof-analyze/tests/test-capture-model.c index 2e16ee44..ee4252b4 100644 --- a/src/libsysprof-analyze/tests/test-capture-model.c +++ b/src/libsysprof-analyze/tests/test-capture-model.c @@ -9,9 +9,10 @@ int main (int argc, char *argv[]) { - SysprofDocument *document; + g_autoptr(SysprofDocumentLoader) loader = NULL; + g_autoptr(SysprofDocument) document = NULL; + g_autoptr(GError) error = NULL; const char *filename; - GError *error = NULL; guint n_items; sysprof_clock_init (); @@ -24,7 +25,10 @@ main (int argc, filename = argv[1]; - if (!(document = _sysprof_document_new (filename, &error))) + loader = sysprof_document_loader_new (filename); + sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ()); + + if (!(document = sysprof_document_loader_load (loader, NULL, &error))) { g_printerr ("Failed to load %s: %s\n", filename, error->message); @@ -88,7 +92,5 @@ main (int argc, g_printerr ("%u frames\n", n_items); - g_clear_object (&document); - return 0; } diff --git a/src/libsysprof-analyze/tests/test-list-files.c b/src/libsysprof-analyze/tests/test-list-files.c index a79c4a2d..78b3ae06 100644 --- a/src/libsysprof-analyze/tests/test-list-files.c +++ b/src/libsysprof-analyze/tests/test-list-files.c @@ -26,6 +26,7 @@ int main (int argc, char *argv[]) { + g_autoptr(SysprofDocumentLoader) loader = NULL; g_autoptr(SysprofDocument) document = NULL; g_autoptr(GListModel) files = NULL; g_autoptr(GError) error = NULL; @@ -37,7 +38,10 @@ main (int argc, return 1; } - if (!(document = _sysprof_document_new (argv[1], &error))) + loader = sysprof_document_loader_new (argv[1]); + sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ()); + + if (!(document = sysprof_document_loader_load (loader, NULL, &error))) { g_printerr ("Failed to open capture: %s\n", error->message); return 1; diff --git a/src/libsysprof-analyze/tests/test-list-processes.c b/src/libsysprof-analyze/tests/test-list-processes.c index d3d419da..5b4fffcf 100644 --- a/src/libsysprof-analyze/tests/test-list-processes.c +++ b/src/libsysprof-analyze/tests/test-list-processes.c @@ -26,6 +26,7 @@ int main (int argc, char *argv[]) { + g_autoptr(SysprofDocumentLoader) loader = NULL; g_autoptr(SysprofDocument) document = NULL; g_autoptr(GListModel) processes = NULL; g_autoptr(GError) error = NULL; @@ -37,7 +38,10 @@ main (int argc, return 1; } - if (!(document = _sysprof_document_new (argv[1], &error))) + loader = sysprof_document_loader_new (argv[1]); + sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ()); + + if (!(document = sysprof_document_loader_load (loader, NULL, &error))) { g_printerr ("Failed to open capture: %s\n", error->message); return 1; diff --git a/src/libsysprof-analyze/tests/test-print-file.c b/src/libsysprof-analyze/tests/test-print-file.c index cd8d3720..1e49f19d 100644 --- a/src/libsysprof-analyze/tests/test-print-file.c +++ b/src/libsysprof-analyze/tests/test-print-file.c @@ -26,6 +26,7 @@ int main (int argc, char *argv[]) { + g_autoptr(SysprofDocumentLoader) loader = NULL; g_autoptr(SysprofDocumentFile) file = NULL; g_autoptr(SysprofDocument) document = NULL; g_autoptr(GListModel) files = NULL; @@ -38,7 +39,10 @@ main (int argc, return 1; } - if (!(document = _sysprof_document_new (argv[1], &error))) + loader = sysprof_document_loader_new (argv[1]); + sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ()); + + if (!(document = sysprof_document_loader_load (loader, NULL, &error))) { g_printerr ("Failed to open capture: %s\n", error->message); return 1; diff --git a/src/libsysprof-analyze/tests/test-symbolize.c b/src/libsysprof-analyze/tests/test-symbolize.c index 8265d2da..29e5e3ef 100644 --- a/src/libsysprof-analyze/tests/test-symbolize.c +++ b/src/libsysprof-analyze/tests/test-symbolize.c @@ -7,63 +7,88 @@ static GMainLoop *main_loop; static void -symbolize_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) +load_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) { - SysprofDocument *document = (SysprofDocument *)object; - g_autoptr(SysprofDocumentSymbols) symbols = NULL; + SysprofDocumentLoader *loader = (SysprofDocumentLoader *)object; + g_autoptr(SysprofDocument) document = NULL; g_autoptr(GListModel) traceables = NULL; g_autoptr(GError) error = NULL; - SysprofAddress addresses[128]; + g_autoptr(GString) str = NULL; + SysprofSymbol *symbols[128]; + guint n_symbols; guint n_items; - g_assert (SYSPROF_IS_DOCUMENT (document)); + g_assert (SYSPROF_IS_DOCUMENT_LOADER (loader)); g_assert (G_IS_ASYNC_RESULT (result)); - if (!(symbols = _sysprof_document_symbolize_finish (document, result, &error))) - g_error ("Failed to symbolize: %s", error->message); + if (!(document = sysprof_document_loader_load_finish (loader, result, &error))) + g_error ("Failed to load document: %s", error->message); traceables = sysprof_document_list_traceables (document); n_items = g_list_model_get_n_items (traceables); + str = g_string_new (""); + for (guint i = 0; i < n_items; i++) { g_autoptr(SysprofDocumentTraceable) traceable = g_list_model_get_item (traceables, i); - SysprofAddressContext last_context; - guint depth; - int pid; + + str->len = 0; + str->str[0] = 0; g_assert (traceable != NULL); g_assert (SYSPROF_IS_DOCUMENT_TRACEABLE (traceable)); - last_context = SYSPROF_ADDRESS_CONTEXT_NONE; - pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable)); - depth = sysprof_document_traceable_get_stack_addresses (traceable, addresses, G_N_ELEMENTS (addresses)); + n_symbols = sysprof_document_symbolize_traceable (document, + traceable, + symbols, + G_N_ELEMENTS (symbols)); g_print ("%s depth=%u pid=%u\n", - G_OBJECT_TYPE_NAME (traceable), depth, pid); + G_OBJECT_TYPE_NAME (traceable), + n_symbols, + sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable))); - for (guint j = 0; j < depth; j++) + for (guint j = 0; j < n_symbols; j++) { - SysprofAddress address = addresses[j]; - SysprofSymbol *symbol = sysprof_document_symbols_lookup (symbols, pid, last_context, address); - SysprofAddressContext context; - - if (sysprof_address_is_context_switch (address, &context)) - last_context = context; + SysprofSymbol *symbol = symbols[j]; + const char *name; + const char *path; + const char *nick; if (symbol != NULL) - g_print (" %02d: %p: %s [%s]\n", - j, - GSIZE_TO_POINTER (address), - sysprof_symbol_get_name (symbol), - sysprof_symbol_get_binary_path (symbol) ?: ""); + { + name = sysprof_symbol_get_name (symbol); + path = sysprof_symbol_get_binary_path (symbol); + nick = sysprof_symbol_get_binary_nick (symbol); + } else - g_print (" %02d: %p:\n", j, GSIZE_TO_POINTER (address)); + { + name = path = nick = NULL; + } + + g_string_append_printf (str, + " %02d: 0x%"G_GINT64_MODIFIER"x:", + j, + sysprof_document_traceable_get_stack_address (traceable, j)); + + if (name) + g_string_append_printf (str, " %s", name); + + if (path) + g_string_append_printf (str, " [%s]", path); + + if (nick) + g_string_append_printf (str, " (%s)", nick); + + g_string_append_c (str, '\n'); } - g_print (" ================\n"); + g_string_append (str, " ================\n"); + + write (STDOUT_FILENO, str->str, str->len); } g_print ("Document symbolized\n"); @@ -75,10 +100,8 @@ int main (int argc, char *argv[]) { - g_autoptr(SysprofDocument) document = NULL; - g_autoptr(SysprofMultiSymbolizer) multi = NULL; + g_autoptr(SysprofDocumentLoader) loader = NULL; g_autoptr(GError) error = NULL; - const char *filename; main_loop = g_main_loop_new (NULL, FALSE); @@ -88,23 +111,8 @@ main (int argc, return 1; } - filename = argv[1]; - - if (!(document = _sysprof_document_new (filename, &error))) - { - g_printerr ("Failed to load document: %s\n", error->message); - return 1; - } - - multi = sysprof_multi_symbolizer_new (); - sysprof_multi_symbolizer_add (multi, sysprof_bundled_symbolizer_new ()); - - _sysprof_document_symbolize_async (document, - SYSPROF_SYMBOLIZER (multi), - NULL, - symbolize_cb, - NULL); - + loader = sysprof_document_loader_new (argv[1]); + sysprof_document_loader_load_async (loader, NULL, load_cb, NULL); g_main_loop_run (main_loop); return 0;