mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
libsysprof: join libsysprof-analyze and libsysprof-profile
This brings together the two libraries back into one now that the whole design is pretty well sorted out. They depend on roughly the same libraries anyway and it's way easier of the single library can both read and write the capture files (along with bringing in libsysprof-capture symbols in a single place).
This commit is contained in:
41
src/libsysprof/mapped-ring-buffer-source-private.h
Normal file
41
src/libsysprof/mapped-ring-buffer-source-private.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* mapped-ring-buffer-source-private.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "mapped-ring-buffer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MappedRingBuffer, mapped_ring_buffer_unref)
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
guint mapped_ring_buffer_create_source (MappedRingBuffer *self,
|
||||
MappedRingBufferCallback callback,
|
||||
gpointer user_data);
|
||||
G_GNUC_INTERNAL
|
||||
guint mapped_ring_buffer_create_source_full (MappedRingBuffer *self,
|
||||
MappedRingBufferCallback callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy);
|
||||
|
||||
G_END_DECLS
|
||||
119
src/libsysprof/mapped-ring-buffer-source.c
Normal file
119
src/libsysprof/mapped-ring-buffer-source.c
Normal file
@ -0,0 +1,119 @@
|
||||
/* mapped-ring-buffer-source.c
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "mapped-ring-buffer-source-private.h"
|
||||
|
||||
typedef struct _MappedRingSource
|
||||
{
|
||||
GSource source;
|
||||
MappedRingBuffer *buffer;
|
||||
} MappedRingSource;
|
||||
|
||||
static gboolean
|
||||
mapped_ring_source_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MappedRingSource *real_source = (MappedRingSource *)source;
|
||||
|
||||
g_assert (source != NULL);
|
||||
|
||||
return mapped_ring_buffer_drain (real_source->buffer,
|
||||
(MappedRingBufferCallback)callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
mapped_ring_source_finalize (GSource *source)
|
||||
{
|
||||
MappedRingSource *real_source = (MappedRingSource *)source;
|
||||
|
||||
if (real_source != NULL)
|
||||
g_clear_pointer (&real_source->buffer, mapped_ring_buffer_unref);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mapped_ring_source_check (GSource *source)
|
||||
{
|
||||
MappedRingSource *real_source = (MappedRingSource *)source;
|
||||
|
||||
g_assert (real_source != NULL);
|
||||
g_assert (real_source->buffer != NULL);
|
||||
|
||||
return !mapped_ring_buffer_is_empty (real_source->buffer);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mapped_ring_source_prepare (GSource *source,
|
||||
gint *timeout_)
|
||||
{
|
||||
MappedRingSource *real_source = (MappedRingSource *)source;
|
||||
|
||||
g_assert (real_source != NULL);
|
||||
g_assert (real_source->buffer != NULL);
|
||||
|
||||
if (!mapped_ring_buffer_is_empty (real_source->buffer))
|
||||
return TRUE;
|
||||
|
||||
*timeout_ = 5;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GSourceFuncs mapped_ring_source_funcs = {
|
||||
.prepare = mapped_ring_source_prepare,
|
||||
.check = mapped_ring_source_check,
|
||||
.dispatch = mapped_ring_source_dispatch,
|
||||
.finalize = mapped_ring_source_finalize,
|
||||
};
|
||||
|
||||
guint
|
||||
mapped_ring_buffer_create_source_full (MappedRingBuffer *self,
|
||||
MappedRingBufferCallback source_func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy)
|
||||
{
|
||||
MappedRingSource *source;
|
||||
guint ret;
|
||||
|
||||
g_return_val_if_fail (self != NULL, 0);
|
||||
g_return_val_if_fail (source_func != NULL, 0);
|
||||
|
||||
source = (MappedRingSource *)g_source_new (&mapped_ring_source_funcs, sizeof (MappedRingSource));
|
||||
source->buffer = mapped_ring_buffer_ref (self);
|
||||
g_source_set_callback ((GSource *)source, (GSourceFunc)source_func, user_data, destroy);
|
||||
g_source_set_name ((GSource *)source, "MappedRingSource");
|
||||
ret = g_source_attach ((GSource *)source, g_main_context_default ());
|
||||
g_source_unref ((GSource *)source);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
guint
|
||||
mapped_ring_buffer_create_source (MappedRingBuffer *self,
|
||||
MappedRingBufferCallback source_func,
|
||||
gpointer user_data)
|
||||
{
|
||||
return mapped_ring_buffer_create_source_full (self, source_func, user_data, NULL);
|
||||
}
|
||||
208
src/libsysprof/meson.build
Normal file
208
src/libsysprof/meson.build
Normal file
@ -0,0 +1,208 @@
|
||||
libsysprof_public_sources = [
|
||||
'sysprof-battery-charge.c',
|
||||
'sysprof-bundled-symbolizer.c',
|
||||
'sysprof-callgraph-frame.c',
|
||||
'sysprof-callgraph-symbol.c',
|
||||
'sysprof-callgraph.c',
|
||||
'sysprof-cpu-info.c',
|
||||
'sysprof-cpu-usage.c',
|
||||
'sysprof-diagnostic.c',
|
||||
'sysprof-disk-usage.c',
|
||||
'sysprof-document-allocation.c',
|
||||
'sysprof-document-counter-value.c',
|
||||
'sysprof-document-counter.c',
|
||||
'sysprof-document-ctrdef.c',
|
||||
'sysprof-document-ctrset.c',
|
||||
'sysprof-document-exit.c',
|
||||
'sysprof-document-file-chunk.c',
|
||||
'sysprof-document-file.c',
|
||||
'sysprof-document-fork.c',
|
||||
'sysprof-document-frame.c',
|
||||
'sysprof-document-jitmap.c',
|
||||
'sysprof-document-loader.c',
|
||||
'sysprof-document-log.c',
|
||||
'sysprof-document-mark.c',
|
||||
'sysprof-document-metadata.c',
|
||||
'sysprof-document-mmap.c',
|
||||
'sysprof-document-overlay.c',
|
||||
'sysprof-document-process.c',
|
||||
'sysprof-document-sample.c',
|
||||
'sysprof-document-traceable.c',
|
||||
'sysprof-document.c',
|
||||
'sysprof-elf-symbolizer.c',
|
||||
'sysprof-energy-usage.c',
|
||||
'sysprof-instrument.c',
|
||||
'sysprof-jitmap-symbolizer.c',
|
||||
'sysprof-kallsyms-symbolizer.c',
|
||||
'sysprof-malloc-tracing.c',
|
||||
'sysprof-mark-catalog.c',
|
||||
'sysprof-memory-usage.c',
|
||||
'sysprof-multi-symbolizer.c',
|
||||
'sysprof-network-usage.c',
|
||||
'sysprof-no-symbolizer.c',
|
||||
'sysprof-power-profile.c',
|
||||
'sysprof-profiler.c',
|
||||
'sysprof-proxied-instrument.c',
|
||||
'sysprof-recording.c',
|
||||
'sysprof-sampler.c',
|
||||
'sysprof-spawnable.c',
|
||||
'sysprof-symbol.c',
|
||||
'sysprof-symbolizer.c',
|
||||
'sysprof-symbols-bundle.c',
|
||||
'sysprof-system-logs.c',
|
||||
'sysprof-thread-info.c',
|
||||
'sysprof-time-span.c',
|
||||
'sysprof-tracer.c',
|
||||
]
|
||||
|
||||
libsysprof_public_headers = [
|
||||
'sysprof.h',
|
||||
'sysprof-battery-charge.h',
|
||||
'sysprof-bundled-symbolizer.h',
|
||||
'sysprof-callgraph-frame.h',
|
||||
'sysprof-callgraph-symbol.h',
|
||||
'sysprof-callgraph.h',
|
||||
'sysprof-cpu-info.h',
|
||||
'sysprof-cpu-usage.h',
|
||||
'sysprof-diagnostic.h',
|
||||
'sysprof-disk-usage.h',
|
||||
'sysprof-document-allocation.h',
|
||||
'sysprof-document-counter-value.h',
|
||||
'sysprof-document-counter.h',
|
||||
'sysprof-document-ctrdef.h',
|
||||
'sysprof-document-ctrset.h',
|
||||
'sysprof-document-exit.h',
|
||||
'sysprof-document-file-chunk.h',
|
||||
'sysprof-document-file.h',
|
||||
'sysprof-document-fork.h',
|
||||
'sysprof-document-frame.h',
|
||||
'sysprof-document-jitmap.h',
|
||||
'sysprof-document-loader.h',
|
||||
'sysprof-document-log.h',
|
||||
'sysprof-document-mark.h',
|
||||
'sysprof-document-metadata.h',
|
||||
'sysprof-document-mmap.h',
|
||||
'sysprof-document-overlay.h',
|
||||
'sysprof-document-process.h',
|
||||
'sysprof-document-sample.h',
|
||||
'sysprof-document-traceable.h',
|
||||
'sysprof-document.h',
|
||||
'sysprof-elf-symbolizer.h',
|
||||
'sysprof-energy-usage.h',
|
||||
'sysprof-instrument.h',
|
||||
'sysprof-jitmap-symbolizer.h',
|
||||
'sysprof-kallsyms-symbolizer.h',
|
||||
'sysprof-malloc-tracing.h',
|
||||
'sysprof-mark-catalog.h',
|
||||
'sysprof-memory-usage.h',
|
||||
'sysprof-mount.h',
|
||||
'sysprof-multi-symbolizer.h',
|
||||
'sysprof-network-usage.h',
|
||||
'sysprof-no-symbolizer.h',
|
||||
'sysprof-power-profile.h',
|
||||
'sysprof-profiler.h',
|
||||
'sysprof-proxied-instrument.h',
|
||||
'sysprof-recording.h',
|
||||
'sysprof-sampler.h',
|
||||
'sysprof-spawnable.h',
|
||||
'sysprof-symbol.h',
|
||||
'sysprof-symbolizer.h',
|
||||
'sysprof-symbols-bundle.h',
|
||||
'sysprof-system-logs.h',
|
||||
'sysprof-thread-info.h',
|
||||
'sysprof-time-span.h',
|
||||
'sysprof-tracer.h',
|
||||
]
|
||||
|
||||
libsysprof_private_sources = [
|
||||
'mapped-ring-buffer-source.c',
|
||||
'sysprof-address-layout.c',
|
||||
'sysprof-controlfd-instrument.c',
|
||||
'sysprof-descendants-model.c',
|
||||
'sysprof-document-bitset-index.c',
|
||||
'sysprof-document-symbols.c',
|
||||
'sysprof-elf-loader.c',
|
||||
'sysprof-elf.c',
|
||||
'sysprof-journald-source.c',
|
||||
'sysprof-maps-parser.c',
|
||||
'sysprof-mount-device.c',
|
||||
'sysprof-mount-namespace.c',
|
||||
'sysprof-mount.c',
|
||||
'sysprof-perf-event-stream.c',
|
||||
'sysprof-podman.c',
|
||||
'sysprof-process-info.c',
|
||||
'sysprof-strings.c',
|
||||
'sysprof-symbol-cache.c',
|
||||
]
|
||||
|
||||
if polkit_dep.found()
|
||||
libsysprof_private_sources += ['sysprof-polkit.c']
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'linux'
|
||||
libsysprof_private_sources += ['sysprof-linux-instrument.c']
|
||||
endif
|
||||
|
||||
libsysprof_deps = [
|
||||
dependency('gio-2.0', version: glib_req_version),
|
||||
dependency('gio-unix-2.0',
|
||||
version: glib_req_version,
|
||||
required: host_machine.system() != 'windows'),
|
||||
dependency('libdex-1', version: dex_req_version),
|
||||
dependency('json-glib-1.0'),
|
||||
|
||||
libsystemd_dep,
|
||||
polkit_dep,
|
||||
|
||||
libeggbitset_static_dep,
|
||||
libelfparser_static_dep,
|
||||
liblinereader_static_dep,
|
||||
libsysprof_capture_dep,
|
||||
]
|
||||
|
||||
libsysprof_static = static_library(
|
||||
'sysprof-analyze-@0@'.format(soname_major_version),
|
||||
libsysprof_public_sources +
|
||||
libsysprof_private_sources,
|
||||
|
||||
include_directories: [include_directories('.'),
|
||||
libsysprof_capture_include_dirs],
|
||||
dependencies: libsysprof_deps,
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
)
|
||||
|
||||
libsysprof_static_dep = declare_dependency(
|
||||
link_with: libsysprof_static,
|
||||
dependencies: libsysprof_deps,
|
||||
include_directories: [include_directories('.'),
|
||||
libsysprof_capture_include_dirs],
|
||||
)
|
||||
|
||||
libsysprof = library('sysprof-analyze-@0@'.format(soname_major_version),
|
||||
dependencies: [libsysprof_static_dep],
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
version: '@0@.0.0'.format(soname_major_version),
|
||||
darwin_versions: '@0@.0'.format(soname_major_version),
|
||||
install: get_option('libsysprof'),
|
||||
)
|
||||
|
||||
libsysprof_dep = declare_dependency(
|
||||
link_with: libsysprof,
|
||||
dependencies: libsysprof_deps,
|
||||
include_directories: [include_directories('.'), libsysprof_capture_include_dirs],
|
||||
)
|
||||
meson.override_dependency('sysprof-analyze-@0@'.format(soname_major_version), libsysprof_dep)
|
||||
|
||||
pkgconfig.generate(libsysprof,
|
||||
subdirs: [sysprof_header_subdir],
|
||||
description: 'A library for recording and analyzing system performance',
|
||||
install_dir: join_paths(get_option('libdir'), 'pkgconfig'),
|
||||
requires: ['gio-2.0'],
|
||||
variables: ['datadir=' + datadir_for_pc_file],
|
||||
)
|
||||
|
||||
install_headers(libsysprof_public_headers, subdir: sysprof_header_subdir)
|
||||
|
||||
if get_option('tests')
|
||||
subdir('tests')
|
||||
endif
|
||||
39
src/libsysprof/sysprof-address-layout-private.h
Normal file
39
src/libsysprof/sysprof-address-layout-private.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* sysprof-address-layout.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "sysprof-document-mmap.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_ADDRESS_LAYOUT (sysprof_address_layout_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofAddressLayout, sysprof_address_layout, SYSPROF, ADDRESS_LAYOUT, GObject)
|
||||
|
||||
SysprofAddressLayout *sysprof_address_layout_new (void);
|
||||
void sysprof_address_layout_take (SysprofAddressLayout *self,
|
||||
SysprofDocumentMmap *map);
|
||||
SysprofDocumentMmap *sysprof_address_layout_lookup (SysprofAddressLayout *self,
|
||||
SysprofAddress address);
|
||||
|
||||
G_END_DECLS
|
||||
227
src/libsysprof/sysprof-address-layout.c
Normal file
227
src/libsysprof/sysprof-address-layout.c
Normal file
@ -0,0 +1,227 @@
|
||||
/* sysprof-address-layout.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <eggbitset.h>
|
||||
|
||||
#include "sysprof-address-layout-private.h"
|
||||
|
||||
struct _SysprofAddressLayout
|
||||
{
|
||||
GObject parent_instance;
|
||||
GPtrArray *mmaps;
|
||||
guint mmaps_dirty : 1;
|
||||
};
|
||||
|
||||
static guint
|
||||
sysprof_address_layout_get_n_items (GListModel *model)
|
||||
{
|
||||
return SYSPROF_ADDRESS_LAYOUT (model)->mmaps->len;
|
||||
}
|
||||
|
||||
static GType
|
||||
sysprof_address_layout_get_item_type (GListModel *model)
|
||||
{
|
||||
return SYSPROF_TYPE_DOCUMENT_MMAP;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
sysprof_address_layout_get_item (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
SysprofAddressLayout *self = SYSPROF_ADDRESS_LAYOUT (model);
|
||||
|
||||
if (position >= self->mmaps->len)
|
||||
return NULL;
|
||||
|
||||
return g_object_ref (g_ptr_array_index (self->mmaps, position));
|
||||
}
|
||||
|
||||
static void
|
||||
list_model_iface_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_n_items = sysprof_address_layout_get_n_items;
|
||||
iface->get_item = sysprof_address_layout_get_item;
|
||||
iface->get_item_type = sysprof_address_layout_get_item_type;
|
||||
}
|
||||
|
||||
G_DEFINE_FINAL_TYPE_WITH_CODE (SysprofAddressLayout, sysprof_address_layout, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
|
||||
|
||||
static void
|
||||
sysprof_address_layout_finalize (GObject *object)
|
||||
{
|
||||
SysprofAddressLayout *self = (SysprofAddressLayout *)object;
|
||||
|
||||
g_clear_pointer (&self->mmaps, g_ptr_array_unref);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_address_layout_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_address_layout_class_init (SysprofAddressLayoutClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_address_layout_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_address_layout_init (SysprofAddressLayout *self)
|
||||
{
|
||||
self->mmaps = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
}
|
||||
|
||||
SysprofAddressLayout *
|
||||
sysprof_address_layout_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_ADDRESS_LAYOUT, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_address_layout_take (SysprofAddressLayout *self,
|
||||
SysprofDocumentMmap *map)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ADDRESS_LAYOUT (self));
|
||||
g_return_if_fail (SYSPROF_IS_DOCUMENT_MMAP (map));
|
||||
|
||||
g_ptr_array_add (self->mmaps, map);
|
||||
|
||||
self->mmaps_dirty = TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_mmaps (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
SysprofDocumentMmap *mmap_a = *(SysprofDocumentMmap * const *)a;
|
||||
SysprofDocumentMmap *mmap_b = *(SysprofDocumentMmap * const *)b;
|
||||
guint64 begin_a = sysprof_document_mmap_get_start_address (mmap_a);
|
||||
guint64 begin_b = sysprof_document_mmap_get_start_address (mmap_b);
|
||||
guint64 end_a = sysprof_document_mmap_get_end_address (mmap_a);
|
||||
guint64 end_b = sysprof_document_mmap_get_end_address (mmap_b);
|
||||
|
||||
if (begin_a < begin_b)
|
||||
return -1;
|
||||
|
||||
if (begin_a > begin_b)
|
||||
return 1;
|
||||
|
||||
if (end_a < end_b)
|
||||
return -1;
|
||||
|
||||
if (end_a > end_b)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mmaps_overlap (SysprofDocumentMmap *a,
|
||||
SysprofDocumentMmap *b)
|
||||
{
|
||||
if ((sysprof_document_mmap_get_start_address (a) <= sysprof_document_mmap_get_start_address (b)) &&
|
||||
(sysprof_document_mmap_get_end_address (a) > sysprof_document_mmap_get_start_address (b)))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static EggBitset *
|
||||
find_duplicates (GPtrArray *sorted)
|
||||
{
|
||||
EggBitset *bitset = egg_bitset_new_empty ();
|
||||
|
||||
if (sorted->len == 0)
|
||||
return bitset;
|
||||
|
||||
for (guint i = 0; i < sorted->len-1; i++)
|
||||
{
|
||||
SysprofDocumentMmap *map = g_ptr_array_index (sorted, i);
|
||||
SysprofDocumentMmap *next = g_ptr_array_index (sorted, i+1);
|
||||
|
||||
/* Take the second one if they overlap, which is generally the large of
|
||||
* the mmaps. That can happen when something like [stack] is resized into
|
||||
* a larger mmap. It's useful to remove duplicates so we get more
|
||||
* predictable bsearch results.
|
||||
*/
|
||||
if (mmaps_overlap (map, next))
|
||||
egg_bitset_add (bitset, i);
|
||||
}
|
||||
|
||||
return bitset;
|
||||
}
|
||||
|
||||
static int
|
||||
find_by_address (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const SysprofAddress *key = a;
|
||||
SysprofDocumentMmap *map = *(SysprofDocumentMmap * const *)b;
|
||||
|
||||
if (*key < sysprof_document_mmap_get_start_address (map))
|
||||
return -1;
|
||||
|
||||
if (*key >= sysprof_document_mmap_get_end_address (map))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SysprofDocumentMmap *
|
||||
sysprof_address_layout_lookup (SysprofAddressLayout *self,
|
||||
SysprofAddress address)
|
||||
{
|
||||
SysprofDocumentMmap **ret;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ADDRESS_LAYOUT (self), NULL);
|
||||
|
||||
if (self->mmaps_dirty)
|
||||
{
|
||||
g_autoptr(EggBitset) dups = NULL;
|
||||
EggBitsetIter iter;
|
||||
guint old_len = self->mmaps->len;
|
||||
guint i;
|
||||
|
||||
self->mmaps_dirty = FALSE;
|
||||
|
||||
g_ptr_array_sort (self->mmaps, compare_mmaps);
|
||||
dups = find_duplicates (self->mmaps);
|
||||
|
||||
if (egg_bitset_iter_init_last (&iter, dups, &i))
|
||||
{
|
||||
do
|
||||
g_ptr_array_remove_index (self->mmaps, i);
|
||||
while (egg_bitset_iter_previous (&iter, &i));
|
||||
}
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, old_len, self->mmaps->len);
|
||||
}
|
||||
|
||||
ret = bsearch (&address,
|
||||
self->mmaps->pdata,
|
||||
self->mmaps->len,
|
||||
sizeof (gpointer),
|
||||
find_by_address);
|
||||
|
||||
return ret ? *ret : NULL;
|
||||
}
|
||||
306
src/libsysprof/sysprof-battery-charge.c
Normal file
306
src/libsysprof/sysprof-battery-charge.c
Normal file
@ -0,0 +1,306 @@
|
||||
/* sysprof-battery-charge.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <glib-unix.h>
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include "line-reader-private.h"
|
||||
|
||||
#include "sysprof-battery-charge.h"
|
||||
#include "sysprof-instrument-private.h"
|
||||
#include "sysprof-recording-private.h"
|
||||
|
||||
#define SYS_CLASS_POWER_SUPPLY "/sys/class/power_supply/"
|
||||
|
||||
struct _SysprofBatteryCharge
|
||||
{
|
||||
SysprofInstrument parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofBatteryChargeClass
|
||||
{
|
||||
SysprofInstrumentClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofBatteryCharge, sysprof_battery_charge, SYSPROF_TYPE_INSTRUMENT)
|
||||
|
||||
typedef struct _Record
|
||||
{
|
||||
SysprofRecording *recording;
|
||||
DexFuture *cancellable;
|
||||
} Record;
|
||||
|
||||
static void
|
||||
record_free (gpointer data)
|
||||
{
|
||||
Record *record = data;
|
||||
|
||||
g_clear_object (&record->recording);
|
||||
dex_clear (&record->cancellable);
|
||||
g_free (record);
|
||||
}
|
||||
|
||||
static void
|
||||
clear_fd (gpointer ptr)
|
||||
{
|
||||
int *fdptr = ptr;
|
||||
g_clear_fd (fdptr, NULL);
|
||||
}
|
||||
|
||||
static char **
|
||||
collect_battery_names (void)
|
||||
{
|
||||
GPtrArray *ar = g_ptr_array_new ();
|
||||
g_autoptr(GDir) dir = NULL;
|
||||
|
||||
if ((dir = g_dir_open (SYS_CLASS_POWER_SUPPLY, 0, NULL)))
|
||||
{
|
||||
const char *name;
|
||||
|
||||
while ((name = g_dir_read_name (dir)))
|
||||
{
|
||||
if (strcmp (name, "AC") == 0)
|
||||
continue;
|
||||
|
||||
g_ptr_array_add (ar, g_strdup (name));
|
||||
}
|
||||
}
|
||||
|
||||
g_ptr_array_add (ar, NULL);
|
||||
|
||||
return (char **)g_ptr_array_free (ar, FALSE);
|
||||
}
|
||||
|
||||
typedef struct _ReadBuffer
|
||||
{
|
||||
char buf[32];
|
||||
} ReadBuffer;
|
||||
|
||||
static DexFuture *
|
||||
sysprof_battery_charge_record_fiber (gpointer user_data)
|
||||
{
|
||||
const int invalid_fd = -1;
|
||||
g_autofree guint *ids = NULL;
|
||||
g_autofree SysprofCaptureCounterValue *values = NULL;
|
||||
g_autofree SysprofCaptureCounter *counters = NULL;
|
||||
g_autofree ReadBuffer *bufs = NULL;
|
||||
SysprofCaptureWriter *writer;
|
||||
Record *record = user_data;
|
||||
g_autoptr(GArray) charge_fds = NULL;
|
||||
g_auto(GStrv) names = NULL;
|
||||
guint n_names;
|
||||
guint n_counters = 1;
|
||||
|
||||
g_assert (record != NULL);
|
||||
g_assert (SYSPROF_IS_RECORDING (record->recording));
|
||||
g_assert (DEX_IS_FUTURE (record->cancellable));
|
||||
|
||||
writer = _sysprof_recording_writer (record->recording);
|
||||
names = collect_battery_names ();
|
||||
n_names = g_strv_length (names);
|
||||
|
||||
/* Use some stack space for our counters and values. */
|
||||
ids = g_new0 (guint, n_names + 1);
|
||||
counters = g_new0 (SysprofCaptureCounter, n_names + 1);
|
||||
values = g_new0 (SysprofCaptureCounterValue, n_names + 1);
|
||||
bufs = g_new0 (ReadBuffer, n_names + 1);
|
||||
|
||||
/* Setup the combined counter which is the total charge of all of
|
||||
* the batteries we discover on the system.
|
||||
*/
|
||||
counters[0].id = ids[0] = sysprof_capture_writer_request_counter (writer, 1);
|
||||
g_strlcpy (counters[0].category, "Battery Charge", sizeof counters[0].category);
|
||||
g_strlcpy (counters[0].name, "Combined", sizeof counters[0].name);
|
||||
g_snprintf (counters[0].description, sizeof counters[0].description, "Combined Battery Charge (µAh)");
|
||||
counters[0].type = SYSPROF_CAPTURE_COUNTER_INT64;
|
||||
counters[0].value.v64 = 0;
|
||||
|
||||
/* Create array to store open FDs to the charge file. We'll do a
|
||||
* positioned read at 0 on these so we get new data on each subsequent
|
||||
* read via AIO. Set the first FD to invalid since that will map to the
|
||||
* position of the combined-counter.
|
||||
*/
|
||||
charge_fds = g_array_new (FALSE, FALSE, sizeof (int));
|
||||
g_array_set_clear_func (charge_fds, clear_fd);
|
||||
g_array_append_val (charge_fds, invalid_fd);
|
||||
|
||||
for (guint i = 0; names[i]; i++)
|
||||
{
|
||||
SysprofCaptureCounter *counter = &counters[n_counters];
|
||||
const char *name = names[i];
|
||||
g_autofree char *charge_path = g_build_filename (SYS_CLASS_POWER_SUPPLY, name, "charge_now", NULL);
|
||||
g_autofree char *model_name_path = g_build_filename (SYS_CLASS_POWER_SUPPLY, name, "model_name", NULL);
|
||||
g_autofree char *type_path = g_build_filename (SYS_CLASS_POWER_SUPPLY, name, "type", NULL);
|
||||
g_autofree char *model_name_data = NULL;
|
||||
g_autofree char *type_data = NULL;
|
||||
g_autofd int charge_fd = -1;
|
||||
|
||||
if (!g_file_get_contents (type_path, &type_data, NULL, NULL) ||
|
||||
!g_str_has_prefix (type_data, "Battery") ||
|
||||
-1 == (charge_fd = open (charge_path, O_RDONLY|O_CLOEXEC)))
|
||||
continue;
|
||||
|
||||
counter->id = ids[n_counters] = sysprof_capture_writer_request_counter (writer, 1);
|
||||
counter->type = SYSPROF_CAPTURE_COUNTER_INT64;
|
||||
g_strlcpy (counter->category, "Battery Charge", sizeof counter->description);
|
||||
if (g_file_get_contents (model_name_path, &model_name_data, NULL, NULL))
|
||||
g_strlcpy (counter->name, g_strstrip (model_name_data), sizeof counter->name);
|
||||
else
|
||||
g_strlcpy (counter->name, name, sizeof counter->name);
|
||||
g_snprintf (counter->description, sizeof counter->description, "%s (µAh)", counter->name);
|
||||
counter->value.v64 = 0;
|
||||
|
||||
g_array_append_val (charge_fds, charge_fd);
|
||||
charge_fd = -1;
|
||||
|
||||
n_counters++;
|
||||
}
|
||||
|
||||
/* If we only have the combined counter, then just short-circuit and
|
||||
* don't record any counters. Otherwise the battery charge row might
|
||||
* show up in UI which we would want to omit.
|
||||
*/
|
||||
if (n_counters == 1)
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
|
||||
sysprof_capture_writer_define_counters (writer,
|
||||
SYSPROF_CAPTURE_CURRENT_TIME,
|
||||
-1,
|
||||
-1,
|
||||
counters,
|
||||
n_counters);
|
||||
|
||||
/* Main recording loop */
|
||||
for (;;)
|
||||
{
|
||||
g_autoptr(GPtrArray) futures = g_ptr_array_new_with_free_func (dex_unref);
|
||||
|
||||
/* Read the contents of all the charge buffers in a single
|
||||
* submission to the AIO layer.
|
||||
*/
|
||||
g_ptr_array_add (futures, dex_future_new_for_boolean (TRUE));
|
||||
for (guint i = 1; i < charge_fds->len; i++)
|
||||
{
|
||||
int charge_fd = g_array_index (charge_fds, int, i);
|
||||
|
||||
g_ptr_array_add (futures,
|
||||
dex_aio_read (NULL,
|
||||
charge_fd,
|
||||
&bufs[i].buf,
|
||||
sizeof bufs[i].buf-1,
|
||||
0));
|
||||
}
|
||||
|
||||
/* Now wait until all the reads complete */
|
||||
if (futures->len > 0)
|
||||
dex_await (dex_future_anyv ((DexFuture **)futures->pdata, futures->len), NULL);
|
||||
|
||||
/* Parse the current charge values */
|
||||
values[0].v64 = 0;
|
||||
for (guint i = 1; i < charge_fds->len; i++)
|
||||
{
|
||||
gssize len = dex_await_int64 (dex_ref (g_ptr_array_index (futures, i)), NULL);
|
||||
guint64 v64;
|
||||
|
||||
if (len <= 0)
|
||||
continue;
|
||||
|
||||
errno = 0;
|
||||
bufs[i].buf[len] = 0;
|
||||
v64 = g_ascii_strtoull (bufs[i].buf, NULL, 10);
|
||||
if (v64 == G_MAXUINT64 || errno != 0)
|
||||
continue;
|
||||
|
||||
values[i].v64 = v64;
|
||||
values[0].v64 += v64;
|
||||
}
|
||||
|
||||
/* Deliver new values to capture */
|
||||
sysprof_capture_writer_set_counters (writer,
|
||||
SYSPROF_CAPTURE_CURRENT_TIME,
|
||||
-1,
|
||||
-1,
|
||||
ids,
|
||||
values,
|
||||
n_counters);
|
||||
|
||||
/* Wait for cancellation or ½ second */
|
||||
dex_await (dex_future_first (dex_ref (record->cancellable),
|
||||
dex_timeout_new_usec (G_USEC_PER_SEC / 2),
|
||||
NULL),
|
||||
NULL);
|
||||
|
||||
/* If cancellable is rejected, then we're done recording */
|
||||
if (dex_future_get_status (record->cancellable) != DEX_FUTURE_STATUS_PENDING)
|
||||
break;
|
||||
}
|
||||
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
sysprof_battery_charge_record (SysprofInstrument *instrument,
|
||||
SysprofRecording *recording,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Record *record;
|
||||
|
||||
g_assert (SYSPROF_IS_BATTERY_CHARGE (instrument));
|
||||
g_assert (SYSPROF_IS_RECORDING (recording));
|
||||
g_assert (G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
record = g_new0 (Record, 1);
|
||||
record->recording = g_object_ref (recording);
|
||||
record->cancellable = dex_cancellable_new_from_cancellable (cancellable);
|
||||
|
||||
return dex_scheduler_spawn (NULL, 0,
|
||||
sysprof_battery_charge_record_fiber,
|
||||
record,
|
||||
record_free);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_battery_charge_class_init (SysprofBatteryChargeClass *klass)
|
||||
{
|
||||
SysprofInstrumentClass *instrument_class = SYSPROF_INSTRUMENT_CLASS (klass);
|
||||
|
||||
instrument_class->record = sysprof_battery_charge_record;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_battery_charge_init (SysprofBatteryCharge *self)
|
||||
{
|
||||
}
|
||||
|
||||
SysprofInstrument *
|
||||
sysprof_battery_charge_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_BATTERY_CHARGE, NULL);
|
||||
}
|
||||
42
src/libsysprof/sysprof-battery-charge.h
Normal file
42
src/libsysprof/sysprof-battery-charge.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* sysprof-battery-charge.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-instrument.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_BATTERY_CHARGE (sysprof_battery_charge_get_type())
|
||||
#define SYSPROF_IS_BATTERY_CHARGE(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_BATTERY_CHARGE)
|
||||
#define SYSPROF_BATTERY_CHARGE(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_BATTERY_CHARGE, SysprofBatteryCharge)
|
||||
#define SYSPROF_BATTERY_CHARGE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_BATTERY_CHARGE, SysprofBatteryChargeClass)
|
||||
|
||||
typedef struct _SysprofBatteryCharge SysprofBatteryCharge;
|
||||
typedef struct _SysprofBatteryChargeClass SysprofBatteryChargeClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_battery_charge_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofInstrument *sysprof_battery_charge_new (void);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofBatteryCharge, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
39
src/libsysprof/sysprof-bundled-symbolizer-private.h
Normal file
39
src/libsysprof/sysprof-bundled-symbolizer-private.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* sysprof-bundled-symbolizer-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-bundled-symbolizer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
SYSPROF_ALIGNED_BEGIN(1)
|
||||
typedef struct _SysprofPackedSymbol
|
||||
{
|
||||
SysprofCaptureAddress addr_begin;
|
||||
SysprofCaptureAddress addr_end;
|
||||
guint32 pid;
|
||||
guint32 offset;
|
||||
guint32 tag_offset;
|
||||
guint32 padding;
|
||||
} SysprofPackedSymbol
|
||||
SYSPROF_ALIGNED_END(1);
|
||||
|
||||
G_END_DECLS
|
||||
260
src/libsysprof/sysprof-bundled-symbolizer.c
Normal file
260
src/libsysprof/sysprof-bundled-symbolizer.c
Normal file
@ -0,0 +1,260 @@
|
||||
/* sysprof-bundled-symbolizer.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-bundled-symbolizer-private.h"
|
||||
#include "sysprof-document-private.h"
|
||||
#include "sysprof-symbolizer-private.h"
|
||||
#include "sysprof-symbol-private.h"
|
||||
|
||||
struct _SysprofBundledSymbolizer
|
||||
{
|
||||
SysprofSymbolizer parent_instance;
|
||||
|
||||
const SysprofPackedSymbol *symbols;
|
||||
guint n_symbols;
|
||||
|
||||
GBytes *bytes;
|
||||
const gchar *beginptr;
|
||||
const gchar *endptr;
|
||||
};
|
||||
|
||||
struct _SysprofBundledSymbolizerClass
|
||||
{
|
||||
SysprofSymbolizerClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofBundledSymbolizer, sysprof_bundled_symbolizer, SYSPROF_TYPE_SYMBOLIZER)
|
||||
|
||||
static void
|
||||
sysprof_bundled_symbolizer_decode (SysprofBundledSymbolizer *self,
|
||||
GBytes *bytes,
|
||||
gboolean is_native)
|
||||
{
|
||||
char *beginptr;
|
||||
char *endptr;
|
||||
|
||||
g_assert (SYSPROF_IS_BUNDLED_SYMBOLIZER (self));
|
||||
g_assert (bytes != NULL);
|
||||
|
||||
/* Our GBytes always contain a trialing \0 after what we think
|
||||
* is the end of the buffer.
|
||||
*/
|
||||
beginptr = (char *)g_bytes_get_data (bytes, NULL);
|
||||
endptr = beginptr + g_bytes_get_size (bytes);
|
||||
|
||||
for (char *ptr = beginptr;
|
||||
ptr < endptr && (ptr + sizeof (SysprofPackedSymbol)) < endptr;
|
||||
ptr += sizeof (SysprofPackedSymbol))
|
||||
{
|
||||
SysprofPackedSymbol *sym = (SysprofPackedSymbol *)ptr;
|
||||
|
||||
if (sym->addr_begin == 0 &&
|
||||
sym->addr_end == 0 &&
|
||||
sym->pid == 0 &&
|
||||
sym->offset == 0)
|
||||
{
|
||||
self->symbols = (const SysprofPackedSymbol *)beginptr;
|
||||
self->n_symbols = sym - self->symbols;
|
||||
break;
|
||||
}
|
||||
else if (!is_native)
|
||||
{
|
||||
sym->addr_begin = GUINT64_SWAP_LE_BE (sym->addr_begin);
|
||||
sym->addr_end = GUINT64_SWAP_LE_BE (sym->addr_end);
|
||||
sym->pid = GUINT32_SWAP_LE_BE (sym->pid);
|
||||
sym->offset = GUINT32_SWAP_LE_BE (sym->offset);
|
||||
sym->tag_offset = GUINT32_SWAP_LE_BE (sym->tag_offset);
|
||||
}
|
||||
}
|
||||
|
||||
self->beginptr = beginptr;
|
||||
self->endptr = endptr;
|
||||
self->bytes = g_bytes_ref (bytes);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_bundled_symbolizer_prepare_async (SysprofSymbolizer *symbolizer,
|
||||
SysprofDocument *document,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofBundledSymbolizer *self = (SysprofBundledSymbolizer *)symbolizer;
|
||||
g_autoptr(SysprofDocumentFile) file = NULL;
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_BUNDLED_SYMBOLIZER (self));
|
||||
g_assert (SYSPROF_IS_DOCUMENT (document));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_bundled_symbolizer_prepare_async);
|
||||
|
||||
if ((file = sysprof_document_lookup_file (document, "__symbols__")) &&
|
||||
(bytes = sysprof_document_file_dup_bytes (file)))
|
||||
sysprof_bundled_symbolizer_decode (self, bytes, _sysprof_document_is_native (document));
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_bundled_symbolizer_prepare_finish (SysprofSymbolizer *symbolizer,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_assert (SYSPROF_IS_BUNDLED_SYMBOLIZER (symbolizer));
|
||||
g_assert (G_IS_TASK (result));
|
||||
g_assert (g_task_is_valid (result, symbolizer));
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static gint
|
||||
search_for_symbol_cb (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const SysprofPackedSymbol *key = a;
|
||||
const SysprofPackedSymbol *ele = b;
|
||||
|
||||
if (key->pid < ele->pid)
|
||||
return -1;
|
||||
|
||||
if (key->pid > ele->pid)
|
||||
return 1;
|
||||
|
||||
g_assert (key->pid == ele->pid);
|
||||
|
||||
if (key->addr_begin < ele->addr_begin)
|
||||
return -1;
|
||||
|
||||
if (key->addr_begin >= ele->addr_end)
|
||||
return 1;
|
||||
|
||||
g_assert (key->addr_begin >= ele->addr_begin);
|
||||
g_assert (key->addr_end <= ele->addr_end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SysprofSymbol *
|
||||
sysprof_bundled_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
|
||||
SysprofStrings *strings,
|
||||
const SysprofProcessInfo *process_info,
|
||||
SysprofAddressContext context,
|
||||
SysprofAddress address)
|
||||
{
|
||||
SysprofBundledSymbolizer *self = SYSPROF_BUNDLED_SYMBOLIZER (symbolizer);
|
||||
g_autoptr(GRefString) tag = NULL;
|
||||
const SysprofPackedSymbol *ret;
|
||||
const SysprofPackedSymbol key = {
|
||||
.addr_begin = address,
|
||||
.addr_end = address,
|
||||
.pid = process_info ? process_info->pid : 0,
|
||||
.offset = 0,
|
||||
.tag_offset = 0,
|
||||
};
|
||||
|
||||
if (self->n_symbols == 0)
|
||||
return NULL;
|
||||
|
||||
g_assert (self->symbols != NULL);
|
||||
g_assert (self->n_symbols > 0);
|
||||
|
||||
ret = bsearch (&key,
|
||||
self->symbols,
|
||||
self->n_symbols,
|
||||
sizeof (SysprofPackedSymbol),
|
||||
search_for_symbol_cb);
|
||||
|
||||
if (ret == NULL || ret->offset == 0)
|
||||
return NULL;
|
||||
|
||||
if (ret->tag_offset > 0)
|
||||
{
|
||||
if (ret->tag_offset < (self->endptr - self->beginptr))
|
||||
tag = sysprof_strings_get (strings, &self->beginptr[ret->tag_offset]);
|
||||
}
|
||||
|
||||
if (ret->offset < (self->endptr - self->beginptr))
|
||||
{
|
||||
const char *name = &self->beginptr[ret->offset];
|
||||
SysprofSymbolKind kind;
|
||||
|
||||
if (g_str_has_prefix (name, "- -"))
|
||||
kind = SYSPROF_SYMBOL_KIND_CONTEXT_SWITCH;
|
||||
else if (context == SYSPROF_ADDRESS_CONTEXT_KERNEL)
|
||||
kind = SYSPROF_SYMBOL_KIND_KERNEL;
|
||||
else if (name[0] == '[')
|
||||
kind = SYSPROF_SYMBOL_KIND_PROCESS;
|
||||
else
|
||||
kind = SYSPROF_SYMBOL_KIND_USER;
|
||||
|
||||
return _sysprof_symbol_new (sysprof_strings_get (strings, name),
|
||||
NULL,
|
||||
g_steal_pointer (&tag),
|
||||
ret->addr_begin,
|
||||
ret->addr_end,
|
||||
kind);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_bundled_symbolizer_finalize (GObject *object)
|
||||
{
|
||||
SysprofBundledSymbolizer *self = (SysprofBundledSymbolizer *)object;
|
||||
|
||||
self->symbols = NULL;
|
||||
self->n_symbols = 0;
|
||||
self->beginptr = NULL;
|
||||
self->endptr = NULL;
|
||||
|
||||
g_clear_pointer (&self->bytes, g_bytes_unref);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_bundled_symbolizer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_bundled_symbolizer_class_init (SysprofBundledSymbolizerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
SysprofSymbolizerClass *symbolizer_class = SYSPROF_SYMBOLIZER_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_bundled_symbolizer_finalize;
|
||||
|
||||
symbolizer_class->prepare_async = sysprof_bundled_symbolizer_prepare_async;
|
||||
symbolizer_class->prepare_finish = sysprof_bundled_symbolizer_prepare_finish;
|
||||
symbolizer_class->symbolize = sysprof_bundled_symbolizer_symbolize;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_bundled_symbolizer_init (SysprofBundledSymbolizer *self)
|
||||
{
|
||||
}
|
||||
|
||||
SysprofSymbolizer *
|
||||
sysprof_bundled_symbolizer_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_BUNDLED_SYMBOLIZER, NULL);
|
||||
}
|
||||
42
src/libsysprof/sysprof-bundled-symbolizer.h
Normal file
42
src/libsysprof/sysprof-bundled-symbolizer.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* sysprof-bundled-symbolizer.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-symbolizer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_BUNDLED_SYMBOLIZER (sysprof_bundled_symbolizer_get_type())
|
||||
#define SYSPROF_IS_BUNDLED_SYMBOLIZER(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_BUNDLED_SYMBOLIZER)
|
||||
#define SYSPROF_BUNDLED_SYMBOLIZER(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_BUNDLED_SYMBOLIZER, SysprofBundledSymbolizer)
|
||||
#define SYSPROF_BUNDLED_SYMBOLIZER_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_BUNDLED_SYMBOLIZER, SysprofBundledSymbolizerClass)
|
||||
|
||||
typedef struct _SysprofBundledSymbolizer SysprofBundledSymbolizer;
|
||||
typedef struct _SysprofBundledSymbolizerClass SysprofBundledSymbolizerClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_bundled_symbolizer_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofSymbolizer *sysprof_bundled_symbolizer_new (void);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofBundledSymbolizer, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
32
src/libsysprof/sysprof-callgraph-frame-private.h
Normal file
32
src/libsysprof/sysprof-callgraph-frame-private.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* sysprof-callgraph-frame-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-callgraph.h"
|
||||
#include "sysprof-callgraph-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
SysprofCallgraphFrame *_sysprof_callgraph_frame_new_for_node (SysprofCallgraph *callgraph,
|
||||
GObject *owner,
|
||||
SysprofCallgraphNode *node);
|
||||
|
||||
G_END_DECLS
|
||||
477
src/libsysprof/sysprof-callgraph-frame.c
Normal file
477
src/libsysprof/sysprof-callgraph-frame.c
Normal file
@ -0,0 +1,477 @@
|
||||
/* sysprof-callgraph-frame.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "sysprof-callgraph-private.h"
|
||||
#include "sysprof-callgraph-frame-private.h"
|
||||
#include "sysprof-symbol-private.h"
|
||||
#include "sysprof-document-bitset-index-private.h"
|
||||
|
||||
#include "eggbitset.h"
|
||||
|
||||
#define MAX_STACK_DEPTH 128
|
||||
|
||||
struct _SysprofCallgraphFrame
|
||||
{
|
||||
GObject parent_instance;
|
||||
SysprofCallgraph *callgraph;
|
||||
GObject *owner;
|
||||
SysprofCallgraphNode *node;
|
||||
guint n_children;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_CALLGRAPH,
|
||||
PROP_SYMBOL,
|
||||
PROP_N_ITEMS,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GType
|
||||
sysprof_callgraph_frame_get_item_type (GListModel *model)
|
||||
{
|
||||
return SYSPROF_TYPE_CALLGRAPH_FRAME;
|
||||
}
|
||||
|
||||
static guint
|
||||
sysprof_callgraph_frame_get_n_items (GListModel *model)
|
||||
{
|
||||
return SYSPROF_CALLGRAPH_FRAME (model)->n_children;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
sysprof_callgraph_frame_get_item (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
SysprofCallgraphFrame *self = SYSPROF_CALLGRAPH_FRAME (model);
|
||||
SysprofCallgraphNode *iter;
|
||||
|
||||
if (self->callgraph == NULL)
|
||||
return NULL;
|
||||
|
||||
iter = self->node->children;
|
||||
|
||||
while (iter != NULL && position > 0)
|
||||
{
|
||||
iter = iter->next;
|
||||
position--;
|
||||
}
|
||||
|
||||
if (iter == NULL)
|
||||
return NULL;
|
||||
|
||||
return _sysprof_callgraph_frame_new_for_node (self->callgraph, self->owner, iter);
|
||||
}
|
||||
|
||||
static void
|
||||
list_model_iface_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = sysprof_callgraph_frame_get_item_type;
|
||||
iface->get_n_items = sysprof_callgraph_frame_get_n_items;
|
||||
iface->get_item = sysprof_callgraph_frame_get_item;
|
||||
}
|
||||
|
||||
G_DEFINE_FINAL_TYPE_WITH_CODE (SysprofCallgraphFrame, sysprof_callgraph_frame, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_callgraph_frame_finalize (GObject *object)
|
||||
{
|
||||
SysprofCallgraphFrame *self = (SysprofCallgraphFrame *)object;
|
||||
|
||||
g_clear_weak_pointer (&self->callgraph);
|
||||
g_clear_object (&self->owner);
|
||||
self->node = NULL;
|
||||
|
||||
G_OBJECT_CLASS (sysprof_callgraph_frame_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_frame_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCallgraphFrame *self = SYSPROF_CALLGRAPH_FRAME (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CALLGRAPH:
|
||||
g_value_set_object (value, self->callgraph);
|
||||
break;
|
||||
|
||||
case PROP_N_ITEMS:
|
||||
g_value_set_uint (value, g_list_model_get_n_items (G_LIST_MODEL (self)));
|
||||
break;
|
||||
|
||||
case PROP_SYMBOL:
|
||||
g_value_set_object (value, sysprof_callgraph_frame_get_symbol (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_frame_class_init (SysprofCallgraphFrameClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_callgraph_frame_finalize;
|
||||
object_class->get_property = sysprof_callgraph_frame_get_property;
|
||||
|
||||
properties [PROP_CALLGRAPH] =
|
||||
g_param_spec_object ("callgraph", NULL, NULL,
|
||||
SYSPROF_TYPE_CALLGRAPH,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_N_ITEMS] =
|
||||
g_param_spec_uint ("n-items", NULL, NULL,
|
||||
0, G_MAXUINT, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_SYMBOL] =
|
||||
g_param_spec_object ("symbol", NULL, NULL,
|
||||
SYSPROF_TYPE_SYMBOL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_frame_init (SysprofCallgraphFrame *self)
|
||||
{
|
||||
}
|
||||
|
||||
SysprofCallgraphFrame *
|
||||
_sysprof_callgraph_frame_new_for_node (SysprofCallgraph *callgraph,
|
||||
GObject *owner,
|
||||
SysprofCallgraphNode *node)
|
||||
{
|
||||
SysprofCallgraphFrame *self;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (callgraph), NULL);
|
||||
g_return_val_if_fail (node != NULL, NULL);
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_CALLGRAPH_FRAME, NULL);
|
||||
g_set_weak_pointer (&self->callgraph, callgraph);
|
||||
g_set_object (&self->owner, owner);
|
||||
self->node = node;
|
||||
|
||||
for (const SysprofCallgraphNode *iter = node->children;
|
||||
iter != NULL;
|
||||
iter = iter->next)
|
||||
self->n_children++;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_callgraph_frame_get_symbol:
|
||||
* @self: a #SysprofCallgraphFrame
|
||||
*
|
||||
* Gets the symbol for the frame.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): a #SysprofSymbol
|
||||
*/
|
||||
SysprofSymbol *
|
||||
sysprof_callgraph_frame_get_symbol (SysprofCallgraphFrame *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_FRAME (self), NULL);
|
||||
|
||||
if (self->callgraph == NULL)
|
||||
return NULL;
|
||||
|
||||
return self->node->summary->symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_callgraph_frame_get_augment: (skip)
|
||||
* @self: a #SysprofCallgraphFrame
|
||||
*
|
||||
* Gets the augmentation that was attached to the callgrpah node.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the augmentation data
|
||||
*/
|
||||
gpointer
|
||||
sysprof_callgraph_frame_get_augment (SysprofCallgraphFrame *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_FRAME (self), NULL);
|
||||
|
||||
if (self->callgraph == NULL)
|
||||
return NULL;
|
||||
|
||||
return sysprof_callgraph_get_augment (self->callgraph, self->node);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_callgraph_frame_get_summary_augment: (skip)
|
||||
* @self: a #SysprofCallgraphFrame
|
||||
*
|
||||
* Gets the augmentation that was attached to the summary for
|
||||
* the callgraph node's symbol.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the augmentation data
|
||||
*/
|
||||
gpointer
|
||||
sysprof_callgraph_frame_get_summary_augment (SysprofCallgraphFrame *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_FRAME (self), NULL);
|
||||
|
||||
if (self->callgraph == NULL)
|
||||
return NULL;
|
||||
|
||||
return sysprof_callgraph_get_summary_augment (self->callgraph, self->node);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_callgraph_frame_get_callgraph:
|
||||
* @self: a #SysprofCallgraphFrame
|
||||
*
|
||||
* Gets the callgraph the frame belongs to.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #SysprofCallgraph, or %NULL
|
||||
*/
|
||||
SysprofCallgraph *
|
||||
sysprof_callgraph_frame_get_callgraph (SysprofCallgraphFrame *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_FRAME (self), NULL);
|
||||
|
||||
return self->callgraph;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
traceable_has_prefix (SysprofDocument *document,
|
||||
SysprofDocumentTraceable *traceable,
|
||||
GPtrArray *prefix)
|
||||
{
|
||||
SysprofAddressContext final_context;
|
||||
SysprofSymbol **symbols;
|
||||
SysprofAddress *addresses;
|
||||
guint s = 0;
|
||||
guint stack_depth;
|
||||
guint n_symbols;
|
||||
|
||||
stack_depth = sysprof_document_traceable_get_stack_depth (traceable);
|
||||
if (stack_depth > MAX_STACK_DEPTH)
|
||||
return FALSE;
|
||||
|
||||
addresses = g_alloca (sizeof (SysprofAddress) * stack_depth);
|
||||
sysprof_document_traceable_get_stack_addresses (traceable, addresses, stack_depth);
|
||||
|
||||
symbols = g_alloca (sizeof (SysprofSymbol *) * stack_depth);
|
||||
n_symbols = sysprof_document_symbolize_traceable (document, traceable, symbols, stack_depth, &final_context);
|
||||
|
||||
if (n_symbols < prefix->len)
|
||||
return FALSE;
|
||||
|
||||
for (guint p = 0; p < prefix->len; p++)
|
||||
{
|
||||
SysprofSymbol *prefix_symbol = g_ptr_array_index (prefix, p);
|
||||
gboolean found = FALSE;
|
||||
|
||||
for (; !found && s < n_symbols; s++)
|
||||
found = sysprof_symbol_equal (prefix_symbol, symbols[s]);
|
||||
|
||||
if (!found)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct _FilterByPrefix
|
||||
{
|
||||
SysprofDocument *document;
|
||||
GListModel *traceables;
|
||||
GPtrArray *prefix;
|
||||
EggBitset *bitset;
|
||||
} FilterByPrefix;
|
||||
|
||||
static void
|
||||
filter_by_prefix_free (FilterByPrefix *state)
|
||||
{
|
||||
g_clear_object (&state->document);
|
||||
g_clear_object (&state->traceables);
|
||||
g_clear_pointer (&state->prefix, g_ptr_array_unref);
|
||||
g_clear_pointer (&state->bitset, egg_bitset_unref);
|
||||
g_free (state);
|
||||
}
|
||||
|
||||
static void
|
||||
filter_by_prefix_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
FilterByPrefix *state = task_data;
|
||||
g_autoptr(EggBitset) bitset = NULL;
|
||||
SysprofDocument *document;
|
||||
GListModel *model;
|
||||
GPtrArray *prefix;
|
||||
EggBitsetIter iter;
|
||||
guint i;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_CALLGRAPH_FRAME (source_object));
|
||||
g_assert (state != NULL);
|
||||
g_assert (G_IS_LIST_MODEL (state->traceables));
|
||||
g_assert (state->prefix != NULL);
|
||||
g_assert (state->prefix->len > 0);
|
||||
g_assert (state->bitset != NULL);
|
||||
g_assert (!egg_bitset_is_empty (state->bitset));
|
||||
|
||||
bitset = egg_bitset_new_empty ();
|
||||
|
||||
model = state->traceables;
|
||||
document = state->document;
|
||||
prefix = state->prefix;
|
||||
|
||||
if (egg_bitset_iter_init_first (&iter, state->bitset, &i))
|
||||
{
|
||||
do
|
||||
{
|
||||
g_autoptr(SysprofDocumentTraceable) traceable = g_list_model_get_item (model, i);
|
||||
|
||||
if (traceable_has_prefix (document, traceable, prefix))
|
||||
egg_bitset_add (bitset, i);
|
||||
}
|
||||
while (egg_bitset_iter_next (&iter, &i));
|
||||
}
|
||||
|
||||
g_task_return_pointer (task,
|
||||
_sysprof_document_bitset_index_new (model, bitset),
|
||||
g_object_unref);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_callgraph_frame_list_traceables:
|
||||
* @self: a #SysprofCallgraphFrame
|
||||
* @cancellable: (nullable): a #GCancellable or %NULL
|
||||
* @callback: a #GAsyncReadyCallback
|
||||
* @user_data: closure data for @callback
|
||||
*
|
||||
* Asynchronously lists the traceables that contain @self.
|
||||
*/
|
||||
void
|
||||
sysprof_callgraph_frame_list_traceables_async (SysprofCallgraphFrame *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GTask) task = NULL;
|
||||
g_autoptr(GPtrArray) prefix = NULL;
|
||||
g_autoptr(EggBitset) bitset = NULL;
|
||||
FilterByPrefix *state;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_CALLGRAPH_FRAME (self));
|
||||
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_callgraph_frame_list_traceables_async);
|
||||
|
||||
if (self->callgraph == NULL)
|
||||
{
|
||||
g_task_return_new_error (task,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"Callgraph already disposed");
|
||||
return;
|
||||
}
|
||||
|
||||
prefix = g_ptr_array_new ();
|
||||
|
||||
for (SysprofCallgraphNode *node = self->node;
|
||||
node != NULL;
|
||||
node = node->parent)
|
||||
{
|
||||
SysprofCallgraphSummary *summary = node->summary;
|
||||
SysprofSymbol *symbol = summary->symbol;
|
||||
|
||||
if (symbol->kind != SYSPROF_SYMBOL_KIND_USER &&
|
||||
symbol->kind != SYSPROF_SYMBOL_KIND_KERNEL)
|
||||
continue;
|
||||
|
||||
if (bitset == NULL)
|
||||
bitset = egg_bitset_copy (summary->traceables);
|
||||
else
|
||||
egg_bitset_intersect (bitset, summary->traceables);
|
||||
|
||||
g_ptr_array_add (prefix, symbol);
|
||||
}
|
||||
|
||||
if (prefix->len == 0 || egg_bitset_is_empty (bitset))
|
||||
{
|
||||
g_task_return_pointer (task,
|
||||
g_list_store_new (SYSPROF_TYPE_DOCUMENT_TRACEABLE),
|
||||
g_object_unref);
|
||||
return;
|
||||
}
|
||||
|
||||
state = g_new0 (FilterByPrefix, 1);
|
||||
state->document = g_object_ref (self->callgraph->document);
|
||||
state->traceables = g_object_ref (self->callgraph->traceables);
|
||||
state->prefix = g_steal_pointer (&prefix);
|
||||
state->bitset = egg_bitset_ref (bitset);
|
||||
|
||||
g_task_set_task_data (task, state, (GDestroyNotify)filter_by_prefix_free);
|
||||
g_task_run_in_thread (task, filter_by_prefix_worker);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_callgraph_frame_list_traceables_finish:
|
||||
* @self: a #SysprofCallgraphFrame
|
||||
*
|
||||
* Completes an asynchronous request to list traceables.
|
||||
*
|
||||
* Returns: (transfer full): a #GListModel of #SysprofDocumentTraceable if
|
||||
* successful; otherwise %NULL and @error is set.
|
||||
*/
|
||||
GListModel *
|
||||
sysprof_callgraph_frame_list_traceables_finish (SysprofCallgraphFrame *self,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
GListModel *ret;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_FRAME (self), 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 || G_IS_LIST_MODEL (ret), NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
sysprof_callgraph_frame_is_leaf (SysprofCallgraphFrame *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_FRAME (self), 0);
|
||||
|
||||
return self->n_children == 0;
|
||||
}
|
||||
54
src/libsysprof/sysprof-callgraph-frame.h
Normal file
54
src/libsysprof/sysprof-callgraph-frame.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* sysprof-callgraph-frame.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
#include "sysprof-symbol.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CALLGRAPH_FRAME (sysprof_callgraph_frame_get_type())
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (SysprofCallgraphFrame, sysprof_callgraph_frame, SYSPROF, CALLGRAPH_FRAME, GObject)
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofSymbol *sysprof_callgraph_frame_get_symbol (SysprofCallgraphFrame *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gpointer sysprof_callgraph_frame_get_augment (SysprofCallgraphFrame *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gpointer sysprof_callgraph_frame_get_summary_augment (SysprofCallgraphFrame *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_callgraph_frame_list_traceables_async (SysprofCallgraphFrame *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_callgraph_frame_list_traceables_finish (SysprofCallgraphFrame *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_callgraph_frame_is_leaf (SysprofCallgraphFrame *self);
|
||||
|
||||
G_END_DECLS
|
||||
87
src/libsysprof/sysprof-callgraph-private.h
Normal file
87
src/libsysprof/sysprof-callgraph-private.h
Normal file
@ -0,0 +1,87 @@
|
||||
/* sysprof-callgraph-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "sysprof-callgraph.h"
|
||||
#include "sysprof-document.h"
|
||||
|
||||
#include "eggbitset.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _SysprofCallgraphSummary
|
||||
{
|
||||
SysprofSymbol *symbol;
|
||||
EggBitset *traceables;
|
||||
GPtrArray *callers;
|
||||
gpointer augment[2];
|
||||
} SysprofCallgraphSummary;
|
||||
|
||||
struct _SysprofCallgraphNode
|
||||
{
|
||||
SysprofCallgraphNode *parent;
|
||||
SysprofCallgraphNode *prev;
|
||||
SysprofCallgraphNode *next;
|
||||
SysprofCallgraphNode *children;
|
||||
SysprofCallgraphSummary *summary;
|
||||
gpointer augment[2];
|
||||
};
|
||||
|
||||
struct _SysprofCallgraph
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
SysprofDocument *document;
|
||||
GListModel *traceables;
|
||||
|
||||
GHashTable *symbol_to_summary;
|
||||
GPtrArray *symbols;
|
||||
|
||||
SysprofCallgraphFlags flags;
|
||||
|
||||
gsize augment_size;
|
||||
SysprofAugmentationFunc augment_func;
|
||||
gpointer augment_func_data;
|
||||
GDestroyNotify augment_func_data_destroy;
|
||||
|
||||
SysprofCallgraphNode root;
|
||||
};
|
||||
|
||||
void _sysprof_callgraph_new_async (SysprofDocument *document,
|
||||
SysprofCallgraphFlags flags,
|
||||
GListModel *traceables,
|
||||
gsize augment_size,
|
||||
SysprofAugmentationFunc augment_func,
|
||||
gpointer augment_func_data,
|
||||
GDestroyNotify augment_func_data_destroy,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
SysprofCallgraph *_sysprof_callgraph_new_finish (GAsyncResult *result,
|
||||
GError **error);
|
||||
gpointer _sysprof_callgraph_get_symbol_augment (SysprofCallgraph *self,
|
||||
SysprofSymbol *symbol);
|
||||
void _sysprof_callgraph_node_free (SysprofCallgraphNode *self,
|
||||
gboolean free_self);
|
||||
|
||||
G_END_DECLS
|
||||
30
src/libsysprof/sysprof-callgraph-symbol-private.h
Normal file
30
src/libsysprof/sysprof-callgraph-symbol-private.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* sysprof-callgraph-symbol-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-callgraph.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GListModel *_sysprof_callgraph_symbol_list_model_new (SysprofCallgraph *callgraph,
|
||||
GPtrArray *symbols);
|
||||
|
||||
G_END_DECLS
|
||||
265
src/libsysprof/sysprof-callgraph-symbol.c
Normal file
265
src/libsysprof/sysprof-callgraph-symbol.c
Normal file
@ -0,0 +1,265 @@
|
||||
/* sysprof-callgraph-symbol.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "sysprof-callgraph-private.h"
|
||||
#include "sysprof-callgraph-symbol-private.h"
|
||||
|
||||
struct _SysprofCallgraphSymbol
|
||||
{
|
||||
GObject parent_instance;
|
||||
SysprofCallgraph *callgraph;
|
||||
SysprofSymbol *symbol;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_CALLGRAPH,
|
||||
PROP_SYMBOL,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofCallgraphSymbol, sysprof_callgraph_symbol, G_TYPE_OBJECT)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_callgraph_symbol_finalize (GObject *object)
|
||||
{
|
||||
SysprofCallgraphSymbol *self = (SysprofCallgraphSymbol *)object;
|
||||
|
||||
g_clear_weak_pointer (&self->callgraph);
|
||||
g_clear_object (&self->symbol);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_callgraph_symbol_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_symbol_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCallgraphSymbol *self = SYSPROF_CALLGRAPH_SYMBOL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CALLGRAPH:
|
||||
g_value_set_object (value, self->callgraph);
|
||||
break;
|
||||
|
||||
case PROP_SYMBOL:
|
||||
g_value_set_object (value, sysprof_callgraph_symbol_get_symbol (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_symbol_class_init (SysprofCallgraphSymbolClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_callgraph_symbol_finalize;
|
||||
object_class->get_property = sysprof_callgraph_symbol_get_property;
|
||||
|
||||
properties [PROP_CALLGRAPH] =
|
||||
g_param_spec_object ("callgraph", NULL, NULL,
|
||||
SYSPROF_TYPE_CALLGRAPH,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_SYMBOL] =
|
||||
g_param_spec_object ("symbol", NULL, NULL,
|
||||
SYSPROF_TYPE_SYMBOL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_symbol_init (SysprofCallgraphSymbol *self)
|
||||
{
|
||||
}
|
||||
|
||||
SysprofCallgraphSymbol *
|
||||
_sysprof_callgraph_symbol_new (SysprofCallgraph *callgraph,
|
||||
SysprofSymbol *symbol)
|
||||
{
|
||||
SysprofCallgraphSymbol *self;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (callgraph), NULL);
|
||||
g_return_val_if_fail (SYSPROF_IS_SYMBOL (symbol), NULL);
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_CALLGRAPH_SYMBOL, NULL);
|
||||
g_set_weak_pointer (&self->callgraph, callgraph);
|
||||
g_set_object (&self->symbol, symbol);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_callgraph_symbol_get_symbol:
|
||||
* @self: a #SysprofCallgraphSymbol
|
||||
*
|
||||
* Gets the symbol for the symbol.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): a #SysprofSymbol
|
||||
*/
|
||||
SysprofSymbol *
|
||||
sysprof_callgraph_symbol_get_symbol (SysprofCallgraphSymbol *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_SYMBOL (self), NULL);
|
||||
|
||||
return self->symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_callgraph_symbol_get_summary_augment: (skip)
|
||||
* @self: a #SysprofCallgraphSymbol
|
||||
*
|
||||
* Gets the augmentation that was attached to the summary for
|
||||
* the callgraph node's symbol.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the augmentation data
|
||||
*/
|
||||
gpointer
|
||||
sysprof_callgraph_symbol_get_summary_augment (SysprofCallgraphSymbol *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_SYMBOL (self), NULL);
|
||||
|
||||
if (self->callgraph == NULL)
|
||||
return NULL;
|
||||
|
||||
return _sysprof_callgraph_get_symbol_augment (self->callgraph, self->symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_callgraph_symbol_get_callgraph:
|
||||
* @self: a #SysprofCallgraphSymbol
|
||||
*
|
||||
* Gets the callgraph the symbol belongs to.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #SysprofCallgraph, or %NULL
|
||||
*/
|
||||
SysprofCallgraph *
|
||||
sysprof_callgraph_symbol_get_callgraph (SysprofCallgraphSymbol *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_SYMBOL (self), NULL);
|
||||
|
||||
return self->callgraph;
|
||||
}
|
||||
|
||||
typedef struct _SysprofCallgraphSymbolListModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
SysprofCallgraph *callgraph;
|
||||
GPtrArray *symbols;
|
||||
} SysprofCallgraphSymbolListModel;
|
||||
|
||||
static guint
|
||||
sysprof_callgraph_symbol_list_model_get_n_items (GListModel *model)
|
||||
{
|
||||
SysprofCallgraphSymbolListModel *self = (SysprofCallgraphSymbolListModel *)model;
|
||||
|
||||
if (self->symbols != NULL)
|
||||
return self->symbols->len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static GType
|
||||
sysprof_callgraph_symbol_list_model_get_item_type (GListModel *model)
|
||||
{
|
||||
return SYSPROF_TYPE_CALLGRAPH_SYMBOL;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
sysprof_callgraph_symbol_list_model_get_item (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
SysprofCallgraphSymbolListModel *self = (SysprofCallgraphSymbolListModel *)model;
|
||||
|
||||
if (self->symbols == NULL || position >= self->symbols->len || self->callgraph == NULL)
|
||||
return NULL;
|
||||
|
||||
return _sysprof_callgraph_symbol_new (self->callgraph,
|
||||
g_ptr_array_index (self->symbols, position));
|
||||
}
|
||||
|
||||
static void
|
||||
list_model_iface_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_n_items = sysprof_callgraph_symbol_list_model_get_n_items;
|
||||
iface->get_item_type = sysprof_callgraph_symbol_list_model_get_item_type;
|
||||
iface->get_item = sysprof_callgraph_symbol_list_model_get_item;
|
||||
}
|
||||
|
||||
#define SYSPROF_TYPE_CALLGRAPH_SYMBOL_LIST_MODEL (sysprof_callgraph_symbol_list_model_get_type())
|
||||
G_DECLARE_FINAL_TYPE (SysprofCallgraphSymbolListModel, sysprof_callgraph_symbol_list_model, SYSPROF, CALLGRAPH_SYMBOL_LIST_MODEL, GObject)
|
||||
G_DEFINE_FINAL_TYPE_WITH_CODE (SysprofCallgraphSymbolListModel, sysprof_callgraph_symbol_list_model, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
|
||||
|
||||
static void
|
||||
sysprof_callgraph_symbol_list_model_dispose (GObject *object)
|
||||
{
|
||||
SysprofCallgraphSymbolListModel *self = (SysprofCallgraphSymbolListModel *)object;
|
||||
|
||||
g_clear_pointer (&self->symbols, g_ptr_array_unref);
|
||||
g_clear_weak_pointer (&self->callgraph);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_callgraph_symbol_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_symbol_list_model_class_init (SysprofCallgraphSymbolListModelClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = sysprof_callgraph_symbol_list_model_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_symbol_list_model_init (SysprofCallgraphSymbolListModel *self)
|
||||
{
|
||||
}
|
||||
|
||||
GListModel *
|
||||
_sysprof_callgraph_symbol_list_model_new (SysprofCallgraph *callgraph,
|
||||
GPtrArray *symbols)
|
||||
{
|
||||
SysprofCallgraphSymbolListModel *self;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (callgraph), NULL);
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_CALLGRAPH_SYMBOL_LIST_MODEL, NULL);
|
||||
g_set_weak_pointer (&self->callgraph, callgraph);
|
||||
|
||||
if (symbols != NULL)
|
||||
self->symbols = g_ptr_array_ref (symbols);
|
||||
|
||||
return G_LIST_MODEL (self);
|
||||
}
|
||||
|
||||
G_END_DECLS
|
||||
41
src/libsysprof/sysprof-callgraph-symbol.h
Normal file
41
src/libsysprof/sysprof-callgraph-symbol.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* sysprof-callgraph-symbol.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
#include "sysprof-symbol.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CALLGRAPH_SYMBOL (sysprof_callgraph_symbol_get_type())
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (SysprofCallgraphSymbol, sysprof_callgraph_symbol, SYSPROF, CALLGRAPH_SYMBOL, GObject)
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofSymbol *sysprof_callgraph_symbol_get_symbol (SysprofCallgraphSymbol *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gpointer sysprof_callgraph_symbol_get_summary_augment (SysprofCallgraphSymbol *self);
|
||||
|
||||
G_END_DECLS
|
||||
658
src/libsysprof/sysprof-callgraph.c
Normal file
658
src/libsysprof/sysprof-callgraph.c
Normal file
@ -0,0 +1,658 @@
|
||||
/* sysprof-callgraph.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-callgraph-private.h"
|
||||
#include "sysprof-callgraph-frame-private.h"
|
||||
#include "sysprof-callgraph-symbol-private.h"
|
||||
#include "sysprof-descendants-model-private.h"
|
||||
#include "sysprof-document-bitset-index-private.h"
|
||||
#include "sysprof-document-private.h"
|
||||
#include "sysprof-document-traceable.h"
|
||||
#include "sysprof-symbol-private.h"
|
||||
|
||||
#include "eggbitset.h"
|
||||
|
||||
#define MAX_STACK_DEPTH 1024
|
||||
#define INLINE_AUGMENT_SIZE (GLIB_SIZEOF_VOID_P*2)
|
||||
|
||||
static GType
|
||||
sysprof_callgraph_get_item_type (GListModel *model)
|
||||
{
|
||||
return SYSPROF_TYPE_CALLGRAPH_FRAME;
|
||||
}
|
||||
|
||||
static guint
|
||||
sysprof_callgraph_get_n_items (GListModel *model)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
sysprof_callgraph_get_item (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
SysprofCallgraph *self = SYSPROF_CALLGRAPH (model);
|
||||
|
||||
if (position > 0)
|
||||
return NULL;
|
||||
|
||||
return _sysprof_callgraph_frame_new_for_node (self, NULL, &self->root);
|
||||
}
|
||||
|
||||
static void
|
||||
list_model_iface_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = sysprof_callgraph_get_item_type;
|
||||
iface->get_n_items = sysprof_callgraph_get_n_items;
|
||||
iface->get_item = sysprof_callgraph_get_item;
|
||||
}
|
||||
|
||||
G_DEFINE_FINAL_TYPE_WITH_CODE (SysprofCallgraph, sysprof_callgraph, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
|
||||
|
||||
static SysprofSymbol *everything;
|
||||
static SysprofSymbol *untraceable;
|
||||
|
||||
static void
|
||||
sysprof_callgraph_summary_free_all (SysprofCallgraphSummary *summary)
|
||||
{
|
||||
g_clear_pointer (&summary->augment[0], g_free);
|
||||
summary->augment[1] = NULL;
|
||||
g_clear_pointer (&summary->callers, g_ptr_array_unref);
|
||||
g_clear_pointer (&summary->traceables, egg_bitset_unref);
|
||||
g_free (summary);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_summary_free_self (SysprofCallgraphSummary *summary)
|
||||
{
|
||||
summary->augment[0] = NULL;
|
||||
summary->augment[1] = NULL;
|
||||
g_clear_pointer (&summary->callers, g_ptr_array_unref);
|
||||
g_clear_pointer (&summary->traceables, egg_bitset_unref);
|
||||
g_free (summary);
|
||||
}
|
||||
|
||||
static inline SysprofCallgraphSummary *
|
||||
sysprof_callgraph_get_summary (SysprofCallgraph *self,
|
||||
SysprofSymbol *symbol)
|
||||
{
|
||||
SysprofCallgraphSummary *summary;
|
||||
|
||||
if G_UNLIKELY (!(summary = g_hash_table_lookup (self->symbol_to_summary, symbol)))
|
||||
{
|
||||
summary = g_new0 (SysprofCallgraphSummary, 1);
|
||||
summary->traceables = egg_bitset_new_empty ();
|
||||
summary->callers = g_ptr_array_new ();
|
||||
summary->symbol = symbol;
|
||||
|
||||
g_hash_table_insert (self->symbol_to_summary, symbol, summary);
|
||||
g_ptr_array_add (self->symbols, symbol);
|
||||
}
|
||||
|
||||
return summary;
|
||||
}
|
||||
void
|
||||
_sysprof_callgraph_node_free (SysprofCallgraphNode *node,
|
||||
gboolean free_self)
|
||||
{
|
||||
SysprofCallgraphNode *iter = node->children;
|
||||
|
||||
while (iter)
|
||||
{
|
||||
SysprofCallgraphNode *to_free = iter;
|
||||
iter = iter->next;
|
||||
_sysprof_callgraph_node_free (to_free, TRUE);
|
||||
}
|
||||
|
||||
if (free_self)
|
||||
g_free (node);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_dispose (GObject *object)
|
||||
{
|
||||
SysprofCallgraph *self = (SysprofCallgraph *)object;
|
||||
GDestroyNotify notify = self->augment_func_data_destroy;
|
||||
gpointer notify_data = self->augment_func_data;
|
||||
|
||||
self->augment_size = 0;
|
||||
self->augment_func = NULL;
|
||||
self->augment_func_data = NULL;
|
||||
self->augment_func_data_destroy = NULL;
|
||||
|
||||
if (notify != NULL)
|
||||
notify (notify_data);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_callgraph_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_finalize (GObject *object)
|
||||
{
|
||||
SysprofCallgraph *self = (SysprofCallgraph *)object;
|
||||
|
||||
g_clear_pointer (&self->symbol_to_summary, g_hash_table_unref);
|
||||
g_clear_pointer (&self->symbols, g_ptr_array_unref);
|
||||
|
||||
g_clear_object (&self->document);
|
||||
g_clear_object (&self->traceables);
|
||||
|
||||
_sysprof_callgraph_node_free (&self->root, FALSE);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_callgraph_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_class_init (SysprofCallgraphClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = sysprof_callgraph_dispose;
|
||||
object_class->finalize = sysprof_callgraph_finalize;
|
||||
|
||||
everything = _sysprof_symbol_new (g_ref_string_new_intern ("All Processes"),
|
||||
NULL, NULL, 0, 0,
|
||||
SYSPROF_SYMBOL_KIND_ROOT);
|
||||
untraceable = _sysprof_symbol_new (g_ref_string_new_intern ("Unwindable"),
|
||||
NULL, NULL, 0, 0,
|
||||
SYSPROF_SYMBOL_KIND_UNWINDABLE);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_init (SysprofCallgraph *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_populate_callers (SysprofCallgraph *self,
|
||||
SysprofCallgraphNode *node,
|
||||
guint list_model_index)
|
||||
{
|
||||
g_assert (SYSPROF_IS_CALLGRAPH (self));
|
||||
g_assert (node != NULL);
|
||||
|
||||
for (const SysprofCallgraphNode *iter = node;
|
||||
iter != NULL;
|
||||
iter = iter->parent)
|
||||
{
|
||||
egg_bitset_add (iter->summary->traceables, list_model_index);
|
||||
|
||||
if (iter->parent != NULL)
|
||||
{
|
||||
SysprofSymbol *parent_symbol = iter->parent->summary->symbol;
|
||||
SysprofSymbolKind parent_kind = sysprof_symbol_get_kind (parent_symbol);
|
||||
guint pos;
|
||||
|
||||
if (parent_kind != SYSPROF_SYMBOL_KIND_PROCESS &&
|
||||
parent_kind != SYSPROF_SYMBOL_KIND_ROOT &&
|
||||
!g_ptr_array_find (iter->summary->callers, parent_symbol, &pos))
|
||||
g_ptr_array_add (iter->summary->callers, parent_symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static SysprofCallgraphNode *
|
||||
sysprof_callgraph_add_trace (SysprofCallgraph *self,
|
||||
SysprofSymbol **symbols,
|
||||
guint n_symbols,
|
||||
guint list_model_index,
|
||||
gboolean hide_system_libraries)
|
||||
{
|
||||
SysprofCallgraphNode *parent = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_CALLGRAPH (self));
|
||||
g_assert (n_symbols >= 2);
|
||||
g_assert (symbols[n_symbols-1] == everything);
|
||||
|
||||
parent = &self->root;
|
||||
|
||||
for (guint i = n_symbols - 1; i > 0; i--)
|
||||
{
|
||||
SysprofSymbol *symbol = symbols[i-1];
|
||||
SysprofCallgraphNode *node = NULL;
|
||||
|
||||
if (hide_system_libraries && _sysprof_symbol_is_system_library (symbol))
|
||||
continue;
|
||||
|
||||
/* Try to find @symbol within the children of @parent */
|
||||
for (SysprofCallgraphNode *iter = parent->children;
|
||||
iter != NULL;
|
||||
iter = iter->next)
|
||||
{
|
||||
g_assert (iter != NULL);
|
||||
g_assert (iter->summary != NULL);
|
||||
g_assert (iter->summary->symbol != NULL);
|
||||
g_assert (symbol != NULL);
|
||||
|
||||
if (_sysprof_symbol_equal (iter->summary->symbol, symbol))
|
||||
{
|
||||
node = iter;
|
||||
goto next_symbol;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise create a new node */
|
||||
node = g_new0 (SysprofCallgraphNode, 1);
|
||||
node->summary = sysprof_callgraph_get_summary (self, symbol);
|
||||
node->parent = parent;
|
||||
node->next = parent->children;
|
||||
if (parent->children)
|
||||
parent->children->prev = node;
|
||||
parent->children = node;
|
||||
|
||||
next_symbol:
|
||||
parent = node;
|
||||
}
|
||||
|
||||
sysprof_callgraph_populate_callers (self, parent, list_model_index);
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
static void
|
||||
reverse_symbols (SysprofSymbol **symbols,
|
||||
guint n_symbols)
|
||||
{
|
||||
guint half = n_symbols / 2;
|
||||
|
||||
for (guint i = 0; i < half; i++)
|
||||
{
|
||||
SysprofSymbol *tmp = symbols[i];
|
||||
symbols[i] = symbols[n_symbols-1-i];
|
||||
symbols[n_symbols-1-i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_add_traceable (SysprofCallgraph *self,
|
||||
SysprofDocumentTraceable *traceable,
|
||||
guint list_model_index)
|
||||
{
|
||||
SysprofAddressContext final_context;
|
||||
SysprofCallgraphNode *node;
|
||||
SysprofSymbol **symbols;
|
||||
guint stack_depth;
|
||||
guint n_symbols;
|
||||
int pid;
|
||||
int tid;
|
||||
|
||||
g_assert (SYSPROF_IS_CALLGRAPH (self));
|
||||
g_assert (SYSPROF_IS_DOCUMENT_TRACEABLE (traceable));
|
||||
|
||||
pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable));
|
||||
tid = sysprof_document_traceable_get_thread_id (traceable);
|
||||
stack_depth = sysprof_document_traceable_get_stack_depth (traceable);
|
||||
|
||||
if (stack_depth == 0 || stack_depth > MAX_STACK_DEPTH)
|
||||
return;
|
||||
|
||||
symbols = g_newa (SysprofSymbol *, stack_depth + 4);
|
||||
n_symbols = sysprof_document_symbolize_traceable (self->document,
|
||||
traceable,
|
||||
symbols,
|
||||
stack_depth,
|
||||
&final_context);
|
||||
|
||||
g_assert (n_symbols <= stack_depth);
|
||||
|
||||
/* Sometimes we get a very unhelpful unwind from the capture
|
||||
* which is basically a single frame of "user space context".
|
||||
* That means we got no amount of the stack, but we should
|
||||
* really account costs to something in the application other
|
||||
* than the [Application] entry itself so that it's more clear
|
||||
* that it was a corrupted unwind when recording.
|
||||
*/
|
||||
if (n_symbols == 1 &&
|
||||
_sysprof_symbol_is_context_switch (symbols[0]) &&
|
||||
final_context == SYSPROF_ADDRESS_CONTEXT_USER)
|
||||
symbols[0] = untraceable;
|
||||
|
||||
/* We saved 3 extra spaces for these above so that we can
|
||||
* tack on the "Process" symbol and the "All Processes" symbol.
|
||||
* If the final address context places us in Kernel, we want
|
||||
* to add a "- - Kernel - -" symbol to ensure that we are
|
||||
* accounting cost to the kernel for the process.
|
||||
*/
|
||||
if (final_context == SYSPROF_ADDRESS_CONTEXT_KERNEL)
|
||||
symbols[n_symbols++] = _sysprof_document_kernel_symbol (self->document);
|
||||
|
||||
/* If the first thing we see is a context switch, then there is
|
||||
* nothing after it to account for. Just skip the symbol as it
|
||||
* provides nothing to us in the callgraph.
|
||||
*/
|
||||
if (_sysprof_symbol_is_context_switch (symbols[0]))
|
||||
{
|
||||
symbols++;
|
||||
n_symbols--;
|
||||
}
|
||||
|
||||
if ((self->flags & SYSPROF_CALLGRAPH_FLAGS_BOTTOM_UP) != 0)
|
||||
reverse_symbols (symbols, n_symbols);
|
||||
|
||||
/* If the user requested thread-ids within each process, then
|
||||
* insert a symbol for that before the real stacks.
|
||||
*/
|
||||
if ((self->flags & SYSPROF_CALLGRAPH_FLAGS_INCLUDE_THREADS) != 0)
|
||||
symbols[n_symbols++] = _sysprof_document_thread_symbol (self->document, pid, tid);
|
||||
|
||||
symbols[n_symbols++] = _sysprof_document_process_symbol (self->document, pid);
|
||||
symbols[n_symbols++] = everything;
|
||||
|
||||
node = sysprof_callgraph_add_trace (self,
|
||||
symbols,
|
||||
n_symbols,
|
||||
list_model_index,
|
||||
!!(self->flags & SYSPROF_CALLGRAPH_FLAGS_HIDE_SYSTEM_LIBRARIES));
|
||||
|
||||
if (node && self->augment_func)
|
||||
self->augment_func (self,
|
||||
node,
|
||||
SYSPROF_DOCUMENT_FRAME (traceable),
|
||||
TRUE,
|
||||
self->augment_func_data);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_new_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
SysprofCallgraph *self = task_data;
|
||||
guint n_items;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (source_object == NULL);
|
||||
g_assert (SYSPROF_IS_CALLGRAPH (self));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
n_items = g_list_model_get_n_items (self->traceables);
|
||||
|
||||
for (guint i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr(SysprofDocumentTraceable) traceable = g_list_model_get_item (self->traceables, i);
|
||||
|
||||
sysprof_callgraph_add_traceable (self, traceable, i);
|
||||
}
|
||||
|
||||
g_task_return_pointer (task, g_object_ref (self), g_object_unref);
|
||||
}
|
||||
|
||||
void
|
||||
_sysprof_callgraph_new_async (SysprofDocument *document,
|
||||
SysprofCallgraphFlags flags,
|
||||
GListModel *traceables,
|
||||
gsize augment_size,
|
||||
SysprofAugmentationFunc augment_func,
|
||||
gpointer augment_func_data,
|
||||
GDestroyNotify augment_func_data_destroy,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(SysprofCallgraph) self = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
GDestroyNotify summary_free;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_DOCUMENT (document));
|
||||
g_return_if_fail (G_IS_LIST_MODEL (traceables));
|
||||
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
if (augment_size > INLINE_AUGMENT_SIZE)
|
||||
summary_free = (GDestroyNotify)sysprof_callgraph_summary_free_all;
|
||||
else
|
||||
summary_free = (GDestroyNotify)sysprof_callgraph_summary_free_self;
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_CALLGRAPH, NULL);
|
||||
self->flags = flags;
|
||||
self->document = g_object_ref (document);
|
||||
self->traceables = g_object_ref (traceables);
|
||||
self->augment_size = augment_size;
|
||||
self->augment_func = augment_func;
|
||||
self->augment_func_data = augment_func_data;
|
||||
self->augment_func_data_destroy = augment_func_data_destroy;
|
||||
self->symbol_to_summary = g_hash_table_new_full ((GHashFunc)sysprof_symbol_hash,
|
||||
(GEqualFunc)sysprof_symbol_equal,
|
||||
NULL,
|
||||
summary_free);
|
||||
self->symbols = g_ptr_array_new ();
|
||||
self->root.summary = sysprof_callgraph_get_summary (self, everything);
|
||||
|
||||
task = g_task_new (NULL, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, _sysprof_callgraph_new_async);
|
||||
g_task_set_task_data (task, g_object_ref (self), g_object_unref);
|
||||
g_task_run_in_thread (task, sysprof_callgraph_new_worker);
|
||||
}
|
||||
|
||||
SysprofCallgraph *
|
||||
_sysprof_callgraph_new_finish (GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_TASK (result), NULL);
|
||||
|
||||
return g_task_propagate_pointer (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static inline gpointer
|
||||
get_augmentation (SysprofCallgraph *self,
|
||||
gpointer *augment_location)
|
||||
{
|
||||
if (self->augment_size == 0)
|
||||
return NULL;
|
||||
|
||||
if (self->augment_size <= INLINE_AUGMENT_SIZE)
|
||||
return augment_location;
|
||||
|
||||
if (*augment_location == NULL)
|
||||
*augment_location = g_malloc0 (self->augment_size);
|
||||
|
||||
return *augment_location;
|
||||
}
|
||||
|
||||
gpointer
|
||||
sysprof_callgraph_get_augment (SysprofCallgraph *self,
|
||||
SysprofCallgraphNode *node)
|
||||
{
|
||||
if (node == NULL)
|
||||
node = &self->root;
|
||||
|
||||
return get_augmentation (self, &node->augment[0]);
|
||||
}
|
||||
|
||||
gpointer
|
||||
sysprof_callgraph_get_summary_augment (SysprofCallgraph *self,
|
||||
SysprofCallgraphNode *node)
|
||||
{
|
||||
if (node == NULL)
|
||||
node = &self->root;
|
||||
|
||||
return get_augmentation (self, &node->summary->augment[0]);
|
||||
}
|
||||
|
||||
gpointer
|
||||
_sysprof_callgraph_get_symbol_augment (SysprofCallgraph *self,
|
||||
SysprofSymbol *symbol)
|
||||
{
|
||||
SysprofCallgraphSummary *summary;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (self), NULL);
|
||||
g_return_val_if_fail (SYSPROF_IS_SYMBOL (symbol), NULL);
|
||||
|
||||
if ((summary = g_hash_table_lookup (self->symbol_to_summary, symbol)))
|
||||
return get_augmentation (self, &summary->augment[0]);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SysprofCallgraphNode *
|
||||
sysprof_callgraph_node_parent (SysprofCallgraphNode *node)
|
||||
{
|
||||
return node->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_callgraph_list_callers:
|
||||
* @self: a #SysprofCallgraph
|
||||
* @symbol: a #SysprofSymbol
|
||||
*
|
||||
* Gets a list of #SysprofSymbol that call @symbol.
|
||||
*
|
||||
* Returns: (trasfer full): a #GListModel of #SysprofCallgraphSymbol
|
||||
*/
|
||||
GListModel *
|
||||
sysprof_callgraph_list_callers (SysprofCallgraph *self,
|
||||
SysprofSymbol *symbol)
|
||||
{
|
||||
SysprofCallgraphSummary *summary;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (self), NULL);
|
||||
g_return_val_if_fail (SYSPROF_IS_SYMBOL (symbol), NULL);
|
||||
|
||||
if ((summary = g_hash_table_lookup (self->symbol_to_summary, symbol)))
|
||||
return _sysprof_callgraph_symbol_list_model_new (self, summary->callers);
|
||||
|
||||
return G_LIST_MODEL (g_list_store_new (SYSPROF_TYPE_CALLGRAPH_SYMBOL));
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_callgraph_list_traceables_for_symbol:
|
||||
* @self: a #SysprofCallgraph
|
||||
* @symbol: a #SysprofSymbol
|
||||
*
|
||||
* Gets a list of all the #SysprofTraceable within the callgraph
|
||||
* that contain @symbol.
|
||||
*
|
||||
* Returns: (transfer full): a #GListModel of #SysprofTraceable
|
||||
*/
|
||||
GListModel *
|
||||
sysprof_callgraph_list_traceables_for_symbol (SysprofCallgraph *self,
|
||||
SysprofSymbol *symbol)
|
||||
{
|
||||
SysprofCallgraphSummary *summary;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (self), NULL);
|
||||
g_return_val_if_fail (SYSPROF_IS_SYMBOL (symbol), NULL);
|
||||
|
||||
if ((summary = g_hash_table_lookup (self->symbol_to_summary, symbol)))
|
||||
return _sysprof_document_bitset_index_new (self->traceables, summary->traceables);
|
||||
|
||||
return G_LIST_MODEL (g_list_store_new (SYSPROF_TYPE_DOCUMENT_TRACEABLE));
|
||||
}
|
||||
|
||||
GListModel *
|
||||
sysprof_callgraph_list_traceables_for_symbols_matching (SysprofCallgraph *self,
|
||||
const char *pattern)
|
||||
{
|
||||
g_autoptr(GPatternSpec) pspec = NULL;
|
||||
g_autoptr(EggBitset) bitset = NULL;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (self), NULL);
|
||||
|
||||
if (pattern == NULL || pattern[0] == 0)
|
||||
return g_object_ref (self->traceables);
|
||||
|
||||
pspec = g_pattern_spec_new (pattern);
|
||||
bitset = egg_bitset_new_empty ();
|
||||
|
||||
for (guint i = 0; i < self->symbols->len; i++)
|
||||
{
|
||||
SysprofSymbol *symbol = g_ptr_array_index (self->symbols, i);
|
||||
const char *name = sysprof_symbol_get_name (symbol);
|
||||
|
||||
if (g_pattern_spec_match (pspec, strlen (name), name, NULL))
|
||||
{
|
||||
SysprofCallgraphSummary *summary = g_hash_table_lookup (self->symbol_to_summary, symbol);
|
||||
|
||||
if (summary != NULL)
|
||||
egg_bitset_union (bitset, summary->traceables);
|
||||
}
|
||||
}
|
||||
|
||||
return _sysprof_document_bitset_index_new (self->traceables, bitset);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_callgraph_list_symbols:
|
||||
* @self: a #SysprofCallgraph
|
||||
*
|
||||
* Gets a #GListModel of #SysprofCallgraphSymbol that an be used to
|
||||
* display a function list and associated augmentation data.
|
||||
*
|
||||
* Returns: (transfer full): a #GListModel of #SysprofCallgraphSymbol
|
||||
*/
|
||||
GListModel *
|
||||
sysprof_callgraph_list_symbols (SysprofCallgraph *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (self), NULL);
|
||||
|
||||
return _sysprof_callgraph_symbol_list_model_new (self, self->symbols);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_descendants_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
SysprofCallgraph *self = source_object;
|
||||
SysprofSymbol *symbol = task_data;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_CALLGRAPH (self));
|
||||
g_assert (SYSPROF_IS_SYMBOL (symbol));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
g_task_return_pointer (task,
|
||||
_sysprof_descendants_model_new (self, symbol),
|
||||
g_object_unref);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_callgraph_descendants_async (SysprofCallgraph *self,
|
||||
SysprofSymbol *symbol,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GTask) task = NULL;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_CALLGRAPH (self));
|
||||
g_return_if_fail (SYSPROF_IS_SYMBOL (symbol));
|
||||
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_callgraph_descendants_async);
|
||||
g_task_set_task_data (task, g_object_ref (symbol), g_object_unref);
|
||||
g_task_run_in_thread (task, sysprof_callgraph_descendants_worker);
|
||||
}
|
||||
|
||||
GListModel *
|
||||
sysprof_callgraph_descendants_finish (SysprofCallgraph *self,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (self), NULL);
|
||||
g_return_val_if_fail (G_IS_TASK (result), NULL);
|
||||
|
||||
return g_task_propagate_pointer (G_TASK (result), error);
|
||||
}
|
||||
109
src/libsysprof/sysprof-callgraph.h
Normal file
109
src/libsysprof/sysprof-callgraph.h
Normal file
@ -0,0 +1,109 @@
|
||||
/* sysprof-callgraph.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
#include "sysprof-callgraph-frame.h"
|
||||
#include "sysprof-callgraph-symbol.h"
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CALLGRAPH (sysprof_callgraph_get_type())
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (SysprofCallgraph, sysprof_callgraph, SYSPROF, CALLGRAPH, GObject)
|
||||
|
||||
typedef struct _SysprofCallgraphNode SysprofCallgraphNode;
|
||||
|
||||
/**
|
||||
* SysprofAugmentationFunc:
|
||||
* @callgraph: the callgraph being augmented
|
||||
* @node: the node within the callgraph
|
||||
* @frame: the frame used to generate this node
|
||||
* @summarize: if summaries should be generated
|
||||
* @user_data: closure data for augmentation func
|
||||
*
|
||||
* This function is called for the bottom most node in a trace as it is added
|
||||
* to a callgraph.
|
||||
*
|
||||
* The augmentation func should augment the node in whatever way it sees fit
|
||||
* and generally will want to walk up the node tree to the root to augment the
|
||||
* parents as it goes. Your augmentation function is not called for each node,
|
||||
* only the deepest node.
|
||||
*
|
||||
* If @summarize is %TRUE, then you should also generate summary augmentation
|
||||
* using sysprof_callgraph_get_summary_augment() or similar.
|
||||
*/
|
||||
typedef void (*SysprofAugmentationFunc) (SysprofCallgraph *callgraph,
|
||||
SysprofCallgraphNode *node,
|
||||
SysprofDocumentFrame *frame,
|
||||
gboolean summarize,
|
||||
gpointer user_data);
|
||||
|
||||
typedef enum _SysprofCallgraphFlags
|
||||
{
|
||||
SYSPROF_CALLGRAPH_FLAGS_NONE = 0,
|
||||
SYSPROF_CALLGRAPH_FLAGS_INCLUDE_THREADS = 1 << 1,
|
||||
SYSPROF_CALLGRAPH_FLAGS_HIDE_SYSTEM_LIBRARIES = 1 << 2,
|
||||
SYSPROF_CALLGRAPH_FLAGS_BOTTOM_UP = 1 << 3,
|
||||
} SysprofCallgraphFlags;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_callgraph_flags_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_callgraph_list_symbols (SysprofCallgraph *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_callgraph_list_callers (SysprofCallgraph *self,
|
||||
SysprofSymbol *symbol);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_callgraph_list_traceables_for_symbol (SysprofCallgraph *self,
|
||||
SysprofSymbol *symbol);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_callgraph_list_traceables_for_symbols_matching (SysprofCallgraph *self,
|
||||
const char *pattern);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_callgraph_descendants_async (SysprofCallgraph *self,
|
||||
SysprofSymbol *symbol,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_callgraph_descendants_finish (SysprofCallgraph *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gpointer sysprof_callgraph_get_augment (SysprofCallgraph *self,
|
||||
SysprofCallgraphNode *node);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gpointer sysprof_callgraph_get_summary_augment (SysprofCallgraph *self,
|
||||
SysprofCallgraphNode *node);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofCallgraphNode *sysprof_callgraph_node_parent (SysprofCallgraphNode *node);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofCallgraph *sysprof_callgraph_frame_get_callgraph (SysprofCallgraphFrame *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofCallgraph *sysprof_callgraph_symbol_get_callgraph (SysprofCallgraphSymbol *self);
|
||||
|
||||
G_END_DECLS
|
||||
33
src/libsysprof/sysprof-controlfd-instrument-private.h
Normal file
33
src/libsysprof/sysprof-controlfd-instrument-private.h
Normal file
@ -0,0 +1,33 @@
|
||||
/* sysprof-controlfd-instrument-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-instrument-private.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CONTROLFD_INSTRUMENT (sysprof_controlfd_instrument_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofControlfdInstrument, sysprof_controlfd_instrument, SYSPROF, CONTROLFD_INSTRUMENT, SysprofInstrument)
|
||||
|
||||
SysprofInstrument *_sysprof_controlfd_instrument_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
352
src/libsysprof/sysprof-controlfd-instrument.c
Normal file
352
src/libsysprof/sysprof-controlfd-instrument.c
Normal file
@ -0,0 +1,352 @@
|
||||
/* sysprof-controlfd-instrument.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
# include <fcntl.h>
|
||||
# include <glib-unix.h>
|
||||
# include <glib/gstdio.h>
|
||||
# include <gio/gunixinputstream.h>
|
||||
# include <gio/gunixoutputstream.h>
|
||||
# include <gio/gunixconnection.h>
|
||||
# include <sys/socket.h>
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "sysprof-controlfd-instrument-private.h"
|
||||
#include "sysprof-recording-private.h"
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
# include "mapped-ring-buffer.h"
|
||||
# include "mapped-ring-buffer-source-private.h"
|
||||
#endif
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofCaptureReader, sysprof_capture_reader_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofCaptureWriter, sysprof_capture_writer_unref)
|
||||
|
||||
struct _SysprofControlfdInstrument
|
||||
{
|
||||
SysprofInstrument parent_instance;
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
GUnixConnection *connection;
|
||||
char read_buf[10];
|
||||
#endif
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofControlfdInstrument, sysprof_controlfd_instrument, SYSPROF_TYPE_INSTRUMENT)
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
typedef struct _RingData
|
||||
{
|
||||
SysprofCaptureWriter *writer;
|
||||
GArray *source_ids;
|
||||
guint id;
|
||||
} RingData;
|
||||
|
||||
static void
|
||||
ring_data_free (gpointer data)
|
||||
{
|
||||
RingData *ring_data = data;
|
||||
|
||||
for (guint i = 0; i < ring_data->source_ids->len; i++)
|
||||
{
|
||||
guint *id = &g_array_index (ring_data->source_ids, guint, i);
|
||||
|
||||
if (*id == ring_data->id)
|
||||
{
|
||||
*id = 0;
|
||||
g_array_remove_index_fast (ring_data->source_ids, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ring_data->id = 0;
|
||||
|
||||
g_clear_pointer (&ring_data->writer, sysprof_capture_writer_unref);
|
||||
g_array_unref (ring_data->source_ids);
|
||||
g_free (ring_data);
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
sysprof_controlfd_instrument_prepare (SysprofInstrument *instrument,
|
||||
SysprofRecording *recording)
|
||||
{
|
||||
SysprofControlfdInstrument *self = (SysprofControlfdInstrument *)instrument;
|
||||
SysprofSpawnable *spawnable;
|
||||
g_autofree char *child_no_str = NULL;
|
||||
g_autoptr(GSocketConnection) stream = NULL;
|
||||
g_autoptr(GSocket) sock = NULL;
|
||||
int fds[2] = {-1, -1};
|
||||
int child_no;
|
||||
|
||||
g_assert (SYSPROF_IS_CONTROLFD_INSTRUMENT (self));
|
||||
g_assert (SYSPROF_IS_RECORDING (recording));
|
||||
|
||||
/* If the recording is not spawning a process, then there is
|
||||
* nothing for us to do.
|
||||
*/
|
||||
if (!(spawnable = _sysprof_recording_get_spawnable (recording)))
|
||||
goto finish;
|
||||
|
||||
/* Create a socket pair to send control messages over */
|
||||
if (socketpair (AF_LOCAL, SOCK_STREAM, 0, fds) != 0)
|
||||
return dex_future_new_reject (G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_CONNECTED,
|
||||
"Failed to create socketpair");
|
||||
|
||||
/* Set FDs non-blocking so that we can use them from main
|
||||
* context iteration without blocking.
|
||||
*/
|
||||
g_unix_set_fd_nonblocking (fds[0], TRUE, NULL);
|
||||
g_unix_set_fd_nonblocking (fds[1], TRUE, NULL);
|
||||
|
||||
/* @child_no is assigned the FD the child will receive. We can
|
||||
* use that to set the environment variable of the control FD.
|
||||
*/
|
||||
child_no = sysprof_spawnable_take_fd (spawnable, fds[1], -1);
|
||||
child_no_str = g_strdup_printf ("%d", child_no);
|
||||
sysprof_spawnable_setenv (spawnable, "SYSPROF_CONTROL_FD", child_no_str);
|
||||
|
||||
if (!(sock = g_socket_new_from_fd (fds[0], NULL)))
|
||||
{
|
||||
close (fds[0]);
|
||||
return dex_future_new_reject (G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_CONNECTED,
|
||||
"Failed to create socket from FD");
|
||||
}
|
||||
|
||||
self->connection = G_UNIX_CONNECTION (g_socket_connection_factory_create_connection (sock));
|
||||
|
||||
finish:
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
}
|
||||
|
||||
typedef struct _SysprofControlfdRecording
|
||||
{
|
||||
GIOStream *stream;
|
||||
SysprofRecording *recording;
|
||||
DexFuture *cancellable;
|
||||
GArray *source_ids;
|
||||
} SysprofControlfdRecording;
|
||||
|
||||
static void
|
||||
sysprof_controlfd_recording_free (gpointer data)
|
||||
{
|
||||
SysprofControlfdRecording *state = data;
|
||||
|
||||
dex_clear (&state->cancellable);
|
||||
g_clear_pointer (&state->source_ids, g_array_unref);
|
||||
g_clear_object (&state->recording);
|
||||
g_clear_object (&state->stream);
|
||||
g_free (state);
|
||||
}
|
||||
|
||||
static bool
|
||||
sysprof_controlfd_instrument_frame_cb (gconstpointer data,
|
||||
gsize *length,
|
||||
gpointer user_data)
|
||||
{
|
||||
const SysprofCaptureFrame *fr = data;
|
||||
RingData *ring_data = user_data;
|
||||
|
||||
g_assert (ring_data != NULL);
|
||||
g_assert (ring_data->source_ids != NULL);
|
||||
g_assert (ring_data->writer != NULL);
|
||||
g_assert (ring_data->id > 0);
|
||||
|
||||
if G_UNLIKELY (*length < sizeof *fr ||
|
||||
*length < fr->len ||
|
||||
fr->type >= SYSPROF_CAPTURE_FRAME_LAST)
|
||||
return G_SOURCE_REMOVE;
|
||||
|
||||
_sysprof_capture_writer_add_raw (ring_data->writer, fr);
|
||||
|
||||
*length = fr->len;
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
sysprof_controlfd_instrument_record_fiber (gpointer user_data)
|
||||
{
|
||||
SysprofControlfdRecording *state = user_data;
|
||||
g_autoptr(SysprofCaptureWriter) temp_writer = NULL;
|
||||
SysprofCaptureWriter *writer;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autofd int mem_fd = -1;
|
||||
GInputStream *input;
|
||||
|
||||
g_assert (state != NULL);
|
||||
g_assert (SYSPROF_IS_RECORDING (state->recording));
|
||||
g_assert (DEX_IS_CANCELLABLE (state->cancellable));
|
||||
g_assert (state->source_ids != NULL);
|
||||
|
||||
input = g_io_stream_get_input_stream (G_IO_STREAM (state->stream));
|
||||
|
||||
if (!(mem_fd = sysprof_memfd_create ("[controlfd-memfd]")))
|
||||
return dex_future_new_for_errno (errno);
|
||||
|
||||
temp_writer = sysprof_capture_writer_new_from_fd (g_steal_fd (&mem_fd), 0);
|
||||
writer = _sysprof_recording_writer (state->recording);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
g_autoptr(DexFuture) future = dex_input_stream_read_bytes (input, 10, 0);
|
||||
g_autoptr(MappedRingBuffer) ring_buffer = NULL;
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
const guint8 *data;
|
||||
gsize len;
|
||||
|
||||
dex_await (dex_future_any (dex_ref (future),
|
||||
dex_ref (state->cancellable),
|
||||
NULL),
|
||||
&error);
|
||||
|
||||
if (error != NULL)
|
||||
goto handle_error;
|
||||
|
||||
if (!(bytes = dex_await_boxed (dex_ref (future), &error)))
|
||||
goto handle_error;
|
||||
|
||||
data = g_bytes_get_data (bytes, &len);
|
||||
if (len != 10 || memcmp (data, "CreatRing\0", 10) != 0)
|
||||
break;
|
||||
|
||||
if ((ring_buffer = mapped_ring_buffer_new_reader (0)))
|
||||
{
|
||||
int fd = mapped_ring_buffer_get_fd (ring_buffer);
|
||||
RingData *ring_data;
|
||||
|
||||
ring_data = g_new0 (RingData, 1);
|
||||
ring_data->writer = sysprof_capture_writer_ref (temp_writer);
|
||||
ring_data->source_ids = g_array_ref (state->source_ids);
|
||||
ring_data->id = mapped_ring_buffer_create_source_full (ring_buffer,
|
||||
sysprof_controlfd_instrument_frame_cb,
|
||||
ring_data,
|
||||
(GDestroyNotify)ring_data_free);
|
||||
|
||||
g_array_append_val (state->source_ids, ring_data->id);
|
||||
|
||||
g_unix_connection_send_fd (G_UNIX_CONNECTION (state->stream), fd, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
handle_error:
|
||||
while (state->source_ids->len > 0)
|
||||
{
|
||||
guint id = g_array_index (state->source_ids, guint, state->source_ids->len-1);
|
||||
state->source_ids->len--;
|
||||
g_source_remove (id);
|
||||
}
|
||||
|
||||
if (temp_writer != NULL)
|
||||
{
|
||||
g_autoptr(SysprofCaptureReader) reader = sysprof_capture_writer_create_reader (temp_writer);
|
||||
|
||||
if (reader != NULL)
|
||||
sysprof_capture_writer_cat (writer, reader);
|
||||
}
|
||||
|
||||
if (error != NULL)
|
||||
return dex_future_new_for_error (g_steal_pointer (&error));
|
||||
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
_g_clear_source (gpointer data)
|
||||
{
|
||||
guint *id = data;
|
||||
|
||||
if (*id != 0)
|
||||
g_source_remove (*id);
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
sysprof_controlfd_instrument_record (SysprofInstrument *instrument,
|
||||
SysprofRecording *recording,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
SysprofControlfdInstrument *self = (SysprofControlfdInstrument *)instrument;
|
||||
SysprofControlfdRecording *state;
|
||||
SysprofSpawnable *spawnable;
|
||||
|
||||
g_assert (SYSPROF_IS_CONTROLFD_INSTRUMENT (self));
|
||||
g_assert (SYSPROF_IS_RECORDING (recording));
|
||||
|
||||
if (!(spawnable = _sysprof_recording_get_spawnable (recording)))
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
|
||||
state = g_new0 (SysprofControlfdRecording, 1);
|
||||
state->recording = g_object_ref (recording);
|
||||
state->stream = g_object_ref (G_IO_STREAM (self->connection));
|
||||
state->cancellable = dex_cancellable_new_from_cancellable (cancellable);
|
||||
state->source_ids = g_array_new (FALSE, FALSE, sizeof (guint));
|
||||
g_array_set_clear_func (state->source_ids, _g_clear_source);
|
||||
|
||||
return dex_scheduler_spawn (NULL, 0,
|
||||
sysprof_controlfd_instrument_record_fiber,
|
||||
state,
|
||||
sysprof_controlfd_recording_free);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_controlfd_instrument_finalize (GObject *object)
|
||||
{
|
||||
SysprofControlfdInstrument *self = (SysprofControlfdInstrument *)object;
|
||||
|
||||
g_clear_object (&self->connection);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_controlfd_instrument_parent_class)->finalize (object);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
sysprof_controlfd_instrument_class_init (SysprofControlfdInstrumentClass *klass)
|
||||
{
|
||||
#ifdef G_OS_UNIX
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
SysprofInstrumentClass *instrument_class = SYSPROF_INSTRUMENT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_controlfd_instrument_finalize;
|
||||
|
||||
instrument_class->prepare = sysprof_controlfd_instrument_prepare;
|
||||
instrument_class->record = sysprof_controlfd_instrument_record;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_controlfd_instrument_init (SysprofControlfdInstrument *self)
|
||||
{
|
||||
}
|
||||
|
||||
SysprofInstrument *
|
||||
_sysprof_controlfd_instrument_new (void)
|
||||
{
|
||||
#ifndef G_OS_UNIX
|
||||
g_warning_once ("SysprofControlfdInstrument not supported on this platform");
|
||||
#endif
|
||||
|
||||
return g_object_new (SYSPROF_TYPE_CONTROLFD_INSTRUMENT, NULL);
|
||||
}
|
||||
32
src/libsysprof/sysprof-cpu-info-private.h
Normal file
32
src/libsysprof/sysprof-cpu-info-private.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* sysprof-cpu-info-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-cpu-info.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void _sysprof_cpu_info_set_core_id (SysprofCpuInfo *self,
|
||||
guint core_id);
|
||||
void _sysprof_cpu_info_set_model_name (SysprofCpuInfo *self,
|
||||
const char *model_name);
|
||||
|
||||
G_END_DECLS
|
||||
186
src/libsysprof/sysprof-cpu-info.c
Normal file
186
src/libsysprof/sysprof-cpu-info.c
Normal file
@ -0,0 +1,186 @@
|
||||
/* sysprof-cpu-info.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-cpu-info.h"
|
||||
|
||||
struct _SysprofCpuInfo
|
||||
{
|
||||
GObject parent_instance;
|
||||
char *model_name;
|
||||
guint id;
|
||||
guint core_id;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ID,
|
||||
PROP_CORE_ID,
|
||||
PROP_MODEL_NAME,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofCpuInfo, sysprof_cpu_info, G_TYPE_OBJECT)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_cpu_info_finalize (GObject *object)
|
||||
{
|
||||
SysprofCpuInfo *self = (SysprofCpuInfo *)object;
|
||||
|
||||
g_clear_pointer (&self->model_name, g_free);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_cpu_info_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_info_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCpuInfo *self = SYSPROF_CPU_INFO (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ID:
|
||||
g_value_set_uint (value, self->id);
|
||||
break;
|
||||
|
||||
case PROP_CORE_ID:
|
||||
g_value_set_uint (value, self->core_id);
|
||||
break;
|
||||
|
||||
case PROP_MODEL_NAME:
|
||||
g_value_set_string (value, self->model_name);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_info_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCpuInfo *self = SYSPROF_CPU_INFO (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ID:
|
||||
self->id = g_value_get_uint (value);
|
||||
break;
|
||||
|
||||
case PROP_CORE_ID:
|
||||
self->core_id = g_value_get_uint (value);
|
||||
break;
|
||||
|
||||
case PROP_MODEL_NAME:
|
||||
self->model_name = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_info_class_init (SysprofCpuInfoClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_cpu_info_finalize;
|
||||
object_class->get_property = sysprof_cpu_info_get_property;
|
||||
object_class->set_property = sysprof_cpu_info_set_property;
|
||||
|
||||
properties[PROP_ID] =
|
||||
g_param_spec_uint ("id", NULL, NULL,
|
||||
0, G_MAXUINT, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties[PROP_CORE_ID] =
|
||||
g_param_spec_uint ("core-id", NULL, NULL,
|
||||
0, G_MAXUINT, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties[PROP_MODEL_NAME] =
|
||||
g_param_spec_string ("model-name", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_info_init (SysprofCpuInfo *self)
|
||||
{
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_cpu_info_get_model_name (SysprofCpuInfo *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_CPU_INFO (self), NULL);
|
||||
|
||||
return self->model_name;
|
||||
}
|
||||
|
||||
guint
|
||||
sysprof_cpu_info_get_id (SysprofCpuInfo *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_CPU_INFO (self), 0);
|
||||
|
||||
return self->id;
|
||||
}
|
||||
|
||||
void
|
||||
_sysprof_cpu_info_set_model_name (SysprofCpuInfo *self,
|
||||
const char *model_name)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_CPU_INFO (self));
|
||||
|
||||
if (g_set_str (&self->model_name, model_name))
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL_NAME]);
|
||||
}
|
||||
|
||||
guint
|
||||
sysprof_cpu_info_get_core_id (SysprofCpuInfo *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_CPU_INFO (self), 0);
|
||||
|
||||
return self->core_id;
|
||||
}
|
||||
|
||||
void
|
||||
_sysprof_cpu_info_set_core_id (SysprofCpuInfo *self,
|
||||
guint core_id)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_CPU_INFO (self));
|
||||
|
||||
if (self->core_id != core_id)
|
||||
{
|
||||
self->core_id = core_id;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CORE_ID]);
|
||||
}
|
||||
}
|
||||
41
src/libsysprof/sysprof-cpu-info.h
Normal file
41
src/libsysprof/sysprof-cpu-info.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* sysprof-cpu-info.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CPU_INFO (sysprof_cpu_info_get_type())
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (SysprofCpuInfo, sysprof_cpu_info, SYSPROF, CPU_INFO, GObject)
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint sysprof_cpu_info_get_id (SysprofCpuInfo *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint sysprof_cpu_info_get_core_id (SysprofCpuInfo *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_cpu_info_get_model_name (SysprofCpuInfo *self);
|
||||
|
||||
G_END_DECLS
|
||||
401
src/libsysprof/sysprof-cpu-usage.c
Normal file
401
src/libsysprof/sysprof-cpu-usage.c
Normal file
@ -0,0 +1,401 @@
|
||||
/* sysprof-cpu-usage.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <glib-unix.h>
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include "line-reader-private.h"
|
||||
|
||||
#include "sysprof-cpu-usage.h"
|
||||
#include "sysprof-instrument-private.h"
|
||||
#include "sysprof-recording-private.h"
|
||||
|
||||
#define PROC_STAT_BUF_SIZE (4096*4)
|
||||
|
||||
struct _SysprofCpuUsage
|
||||
{
|
||||
SysprofInstrument parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofCpuUsageClass
|
||||
{
|
||||
SysprofInstrumentClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofCpuUsage, sysprof_cpu_usage, SYSPROF_TYPE_INSTRUMENT)
|
||||
|
||||
typedef struct _CpuInfo
|
||||
{
|
||||
int counter_base;
|
||||
double total;
|
||||
glong last_user;
|
||||
glong last_idle;
|
||||
glong last_system;
|
||||
glong last_nice;
|
||||
glong last_iowait;
|
||||
glong last_irq;
|
||||
glong last_softirq;
|
||||
glong last_steal;
|
||||
glong last_guest;
|
||||
glong last_guest_nice;
|
||||
} CpuInfo;
|
||||
|
||||
typedef struct _CpuFreq
|
||||
{
|
||||
gint64 max;
|
||||
int stat_fd;
|
||||
char buf[116];
|
||||
} CpuFreq;
|
||||
|
||||
typedef struct _Record
|
||||
{
|
||||
SysprofRecording *recording;
|
||||
DexFuture *cancellable;
|
||||
} Record;
|
||||
|
||||
static void
|
||||
record_free (gpointer data)
|
||||
{
|
||||
Record *record = data;
|
||||
|
||||
g_clear_object (&record->recording);
|
||||
dex_clear (&record->cancellable);
|
||||
g_free (record);
|
||||
}
|
||||
|
||||
static void
|
||||
freq_info_clear (gpointer data)
|
||||
{
|
||||
CpuFreq *cpu_freq = data;
|
||||
g_clear_fd (&cpu_freq->stat_fd, NULL);
|
||||
}
|
||||
|
||||
static double
|
||||
get_cpu_freq (int stat_fd,
|
||||
guint cpu,
|
||||
double max,
|
||||
char *buf,
|
||||
gssize len)
|
||||
{
|
||||
gint64 val;
|
||||
|
||||
if (stat_fd == -1)
|
||||
return .0;
|
||||
|
||||
if (len <= 0)
|
||||
return .0;
|
||||
|
||||
buf[len] = 0;
|
||||
g_strchug (buf);
|
||||
val = g_ascii_strtoll (buf, NULL, 10);
|
||||
|
||||
val = CLAMP (val, .0, max);
|
||||
|
||||
return (double)val / max * 100.;
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
sysprof_cpu_usage_record_fiber (gpointer user_data)
|
||||
{
|
||||
Record *record = user_data;
|
||||
g_autoptr(GArray) cpu_info = NULL;
|
||||
g_autoptr(GArray) freq_info = NULL;
|
||||
g_autofd int stat_fd = -1;
|
||||
g_autofree char *read_buffer = NULL;
|
||||
g_autofree SysprofCaptureCounterValue *values = NULL;
|
||||
g_autofree SysprofCaptureCounter *counters = NULL;
|
||||
g_autofree guint *ids = NULL;
|
||||
SysprofCaptureCounter *counter;
|
||||
SysprofCaptureWriter *writer;
|
||||
guint n_cpu;
|
||||
|
||||
g_assert (record != NULL);
|
||||
g_assert (SYSPROF_IS_RECORDING (record->recording));
|
||||
g_assert (DEX_IS_FUTURE (record->cancellable));
|
||||
|
||||
writer = _sysprof_recording_writer (record->recording);
|
||||
n_cpu = g_get_num_processors ();
|
||||
stat_fd = open ("/proc/stat", O_RDONLY|O_CLOEXEC);
|
||||
g_unix_set_fd_nonblocking (stat_fd, TRUE, NULL);
|
||||
read_buffer = g_malloc (PROC_STAT_BUF_SIZE);
|
||||
|
||||
counters = g_new0 (SysprofCaptureCounter, (n_cpu * 2) + 1);
|
||||
ids = g_new0 (guint, (n_cpu * 2) + 1);
|
||||
values = g_new0 (SysprofCaptureCounterValue, (n_cpu * 2) + 1);
|
||||
|
||||
cpu_info = g_array_new (FALSE, TRUE, sizeof (CpuInfo));
|
||||
g_array_set_size (cpu_info, n_cpu);
|
||||
|
||||
freq_info = g_array_new (FALSE, TRUE, sizeof (CpuFreq));
|
||||
g_array_set_clear_func (freq_info, freq_info_clear);
|
||||
|
||||
/* Create counter information for all of our counters that we will need
|
||||
* to submit in upcoming parses.
|
||||
*/
|
||||
for (guint i = 0; i < n_cpu; i++)
|
||||
{
|
||||
g_autofree char *max_path = g_strdup_printf ("/sys/devices/system/cpu/cpu%u/cpufreq/scaling_max_freq", i);
|
||||
g_autofree char *cur_path = g_strdup_printf ("/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", i);
|
||||
g_autofree char *max_value = NULL;
|
||||
CpuFreq cf;
|
||||
|
||||
ids[i*2] = sysprof_capture_writer_request_counter (writer, 1);
|
||||
ids[i*2+1] = sysprof_capture_writer_request_counter (writer, 1);
|
||||
|
||||
counter = &counters[i*2];
|
||||
counter->id = ids[i*2];
|
||||
counter->type = SYSPROF_CAPTURE_COUNTER_DOUBLE;
|
||||
counter->value.vdbl = 0;
|
||||
g_strlcpy (counter->category, "CPU Percent", sizeof counter->category);
|
||||
g_snprintf (counter->name, sizeof counter->name, "Total CPU %d", i);
|
||||
g_snprintf (counter->description, sizeof counter->description,
|
||||
"Total CPU usage %d", i);
|
||||
|
||||
counter = &counters[i*2+1];
|
||||
counter->id = ids[i*2+1];
|
||||
counter->type = SYSPROF_CAPTURE_COUNTER_DOUBLE;
|
||||
counter->value.vdbl = 0;
|
||||
g_strlcpy (counter->category, "CPU Frequency", sizeof counter->category);
|
||||
g_snprintf (counter->name, sizeof counter->name, "CPU %d", i);
|
||||
g_snprintf (counter->description, sizeof counter->description,
|
||||
"Frequency of CPU %d", i);
|
||||
|
||||
cf.stat_fd = open (cur_path, O_RDONLY|O_CLOEXEC);
|
||||
g_unix_set_fd_nonblocking (cf.stat_fd, TRUE, NULL);
|
||||
cf.buf[0] = 0;
|
||||
if (g_file_get_contents (max_path, &max_value, NULL, NULL))
|
||||
cf.max = g_ascii_strtoll (max_value, NULL, 10);
|
||||
else
|
||||
cf.max = 0;
|
||||
g_array_append_val (freq_info, cf);
|
||||
}
|
||||
|
||||
/* Now create our combined counter */
|
||||
ids[n_cpu*2] = sysprof_capture_writer_request_counter (writer, 1);
|
||||
counter = &counters[n_cpu*2];
|
||||
counter->id = ids[n_cpu*2];
|
||||
counter->type = SYSPROF_CAPTURE_COUNTER_DOUBLE;
|
||||
counter->value.vdbl = 0;
|
||||
g_strlcpy (counter->category, "CPU Percent", sizeof counter->category);
|
||||
g_snprintf (counter->name, sizeof counter->name, "Combined");
|
||||
g_snprintf (counter->description, sizeof counter->description, "Combined CPU usage");
|
||||
|
||||
/* Register all the counters as a group */
|
||||
sysprof_capture_writer_define_counters (writer,
|
||||
SYSPROF_CAPTURE_CURRENT_TIME,
|
||||
-1,
|
||||
-1,
|
||||
counters,
|
||||
n_cpu * 2 + 1);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
g_autoptr(GPtrArray) futures = g_ptr_array_new_with_free_func (dex_unref);
|
||||
g_autoptr(DexFuture) cpu_future = NULL;
|
||||
LineReader reader;
|
||||
glong total_usage = 0;
|
||||
gsize line_len;
|
||||
char *line;
|
||||
|
||||
/* First collect all our reads and then wait for them to finish before
|
||||
* parsing in a pass. With io_uring, this lets us coalesce all the lseek
|
||||
* and reads into a single set of iops.
|
||||
*/
|
||||
for (guint i = 0; i < n_cpu; i++)
|
||||
{
|
||||
CpuFreq *cf = &g_array_index (freq_info, CpuFreq, i);
|
||||
|
||||
g_ptr_array_add (futures, dex_aio_read (NULL, cf->stat_fd, cf->buf, sizeof cf->buf - 1, 0));
|
||||
}
|
||||
cpu_future = dex_aio_read (NULL, stat_fd, read_buffer, PROC_STAT_BUF_SIZE, 0);
|
||||
g_ptr_array_add (futures, dex_ref (cpu_future));
|
||||
if (!dex_await (dex_future_first (dex_ref (record->cancellable),
|
||||
dex_future_allv ((DexFuture **)futures->pdata, futures->len),
|
||||
NULL),
|
||||
NULL))
|
||||
break;
|
||||
|
||||
/* Now parse all the contents of the stat files which should be
|
||||
* populated in the various files.
|
||||
*/
|
||||
line_reader_init (&reader, read_buffer, dex_await_int64 (dex_ref (cpu_future), NULL));
|
||||
while ((line = line_reader_next (&reader, &line_len)))
|
||||
{
|
||||
CpuInfo *ci;
|
||||
char cpu[64];
|
||||
glong user;
|
||||
glong sys;
|
||||
glong nice;
|
||||
glong idle;
|
||||
int id;
|
||||
int ret;
|
||||
glong iowait;
|
||||
glong irq;
|
||||
glong softirq;
|
||||
glong steal;
|
||||
glong guest;
|
||||
glong guest_nice;
|
||||
glong user_calc;
|
||||
glong system_calc;
|
||||
glong nice_calc;
|
||||
glong idle_calc;
|
||||
glong iowait_calc;
|
||||
glong irq_calc;
|
||||
glong softirq_calc;
|
||||
glong steal_calc;
|
||||
glong guest_calc;
|
||||
glong guest_nice_calc;
|
||||
glong total;
|
||||
|
||||
line[line_len] = 0;
|
||||
|
||||
/* CPU lines come first, short-circuit after */
|
||||
if (!g_str_has_prefix (line, "cpu"))
|
||||
break;
|
||||
|
||||
/* First line is "cpu ..." */
|
||||
if (!g_ascii_isdigit (line[3]))
|
||||
continue;
|
||||
|
||||
/* Parse the various counters in order */
|
||||
user = nice = sys = idle = id = 0;
|
||||
ret = sscanf (line, "%63s %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
|
||||
cpu, &user, &nice, &sys, &idle,
|
||||
&iowait, &irq, &softirq, &steal, &guest, &guest_nice);
|
||||
if (ret != 11)
|
||||
continue;
|
||||
|
||||
/* Get the CPU identifier */
|
||||
ret = sscanf (cpu, "cpu%d", &id);
|
||||
if (ret != 1 || id < 0 || id >= n_cpu)
|
||||
continue;
|
||||
|
||||
ci = &g_array_index (cpu_info, CpuInfo, id);
|
||||
|
||||
user_calc = user - ci->last_user;
|
||||
nice_calc = nice - ci->last_nice;
|
||||
system_calc = sys - ci->last_system;
|
||||
idle_calc = idle - ci->last_idle;
|
||||
iowait_calc = iowait - ci->last_iowait;
|
||||
irq_calc = irq - ci->last_irq;
|
||||
softirq_calc = softirq - ci->last_softirq;
|
||||
steal_calc = steal - ci->last_steal;
|
||||
guest_calc = guest - ci->last_guest;
|
||||
guest_nice_calc = guest_nice - ci->last_guest_nice;
|
||||
|
||||
total = user_calc + nice_calc + system_calc + idle_calc + iowait_calc + irq_calc + softirq_calc + steal_calc + guest_calc + guest_nice_calc;
|
||||
ci->total = ((total - idle_calc) / (double)total) * 100.;
|
||||
|
||||
ci->last_user = user;
|
||||
ci->last_nice = nice;
|
||||
ci->last_idle = idle;
|
||||
ci->last_system = sys;
|
||||
ci->last_iowait = iowait;
|
||||
ci->last_irq = irq;
|
||||
ci->last_softirq = softirq;
|
||||
ci->last_steal = steal;
|
||||
ci->last_guest = guest;
|
||||
ci->last_guest_nice = guest_nice;
|
||||
}
|
||||
|
||||
/* Publish counters to the capture file */
|
||||
for (guint i = 0; i < n_cpu; i++)
|
||||
{
|
||||
const CpuInfo *ci = &g_array_index (cpu_info, CpuInfo, i);
|
||||
CpuFreq *cf = &g_array_index (freq_info, CpuFreq, i);
|
||||
DexFuture *freq_future = g_ptr_array_index (futures, i);
|
||||
gssize len = dex_await_int64 (dex_ref (freq_future), NULL);
|
||||
|
||||
values[i*2].vdbl = ci->total;
|
||||
values[i*2+1].vdbl = get_cpu_freq (cf->stat_fd, i, cf->max, cf->buf, len);
|
||||
|
||||
total_usage += ci->total;
|
||||
}
|
||||
|
||||
values[n_cpu*2].vdbl = total_usage / (double)n_cpu;
|
||||
sysprof_capture_writer_set_counters (writer,
|
||||
SYSPROF_CAPTURE_CURRENT_TIME,
|
||||
-1,
|
||||
-1,
|
||||
ids,
|
||||
values,
|
||||
n_cpu * 2 + 1);
|
||||
|
||||
/* Wait for cancellation or ⅕ second */
|
||||
dex_await (dex_future_first (dex_ref (record->cancellable),
|
||||
dex_timeout_new_usec (G_USEC_PER_SEC / 5),
|
||||
NULL),
|
||||
NULL);
|
||||
if (dex_future_get_status (record->cancellable) != DEX_FUTURE_STATUS_PENDING)
|
||||
break;
|
||||
}
|
||||
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
sysprof_cpu_usage_record (SysprofInstrument *instrument,
|
||||
SysprofRecording *recording,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Record *record;
|
||||
|
||||
g_assert (SYSPROF_IS_CPU_USAGE (instrument));
|
||||
g_assert (SYSPROF_IS_RECORDING (recording));
|
||||
g_assert (G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
record = g_new0 (Record, 1);
|
||||
record->recording = g_object_ref (recording);
|
||||
record->cancellable = dex_cancellable_new_from_cancellable (cancellable);
|
||||
|
||||
return dex_scheduler_spawn (NULL, 0,
|
||||
sysprof_cpu_usage_record_fiber,
|
||||
record,
|
||||
record_free);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_usage_class_init (SysprofCpuUsageClass *klass)
|
||||
{
|
||||
SysprofInstrumentClass *instrument_class = SYSPROF_INSTRUMENT_CLASS (klass);
|
||||
|
||||
instrument_class->record = sysprof_cpu_usage_record;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_usage_init (SysprofCpuUsage *self)
|
||||
{
|
||||
}
|
||||
|
||||
SysprofInstrument *
|
||||
sysprof_cpu_usage_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_CPU_USAGE, NULL);
|
||||
}
|
||||
42
src/libsysprof/sysprof-cpu-usage.h
Normal file
42
src/libsysprof/sysprof-cpu-usage.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* sysprof-cpu-usage.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-instrument.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CPU_USAGE (sysprof_cpu_usage_get_type())
|
||||
#define SYSPROF_IS_CPU_USAGE(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_CPU_USAGE)
|
||||
#define SYSPROF_CPU_USAGE(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_CPU_USAGE, SysprofCpuUsage)
|
||||
#define SYSPROF_CPU_USAGE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_CPU_USAGE, SysprofCpuUsageClass)
|
||||
|
||||
typedef struct _SysprofCpuUsage SysprofCpuUsage;
|
||||
typedef struct _SysprofCpuUsageClass SysprofCpuUsageClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_cpu_usage_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofInstrument *sysprof_cpu_usage_new (void);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofCpuUsage, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
35
src/libsysprof/sysprof-descendants-model-private.h
Normal file
35
src/libsysprof/sysprof-descendants-model-private.h
Normal file
@ -0,0 +1,35 @@
|
||||
/* sysprof-descendants-model-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-callgraph.h"
|
||||
#include "sysprof-symbol.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DESCENDANTS_MODEL (sysprof_descendants_model_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofDescendantsModel, sysprof_descendants_model, SYSPROF, DESCENDANTS_MODEL, GObject)
|
||||
|
||||
GListModel *_sysprof_descendants_model_new (SysprofCallgraph *callgraph,
|
||||
SysprofSymbol *symbol);
|
||||
|
||||
G_END_DECLS
|
||||
257
src/libsysprof/sysprof-descendants-model.c
Normal file
257
src/libsysprof/sysprof-descendants-model.c
Normal file
@ -0,0 +1,257 @@
|
||||
/* sysprof-descendants-model.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-callgraph-private.h"
|
||||
#include "sysprof-callgraph-frame-private.h"
|
||||
#include "sysprof-descendants-model-private.h"
|
||||
#include "sysprof-document-private.h"
|
||||
#include "sysprof-symbol-private.h"
|
||||
|
||||
#define MAX_STACK_DEPTH 128
|
||||
|
||||
struct _SysprofDescendantsModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
SysprofCallgraph *callgraph;
|
||||
SysprofSymbol *symbol;
|
||||
SysprofCallgraphNode root;
|
||||
};
|
||||
|
||||
static GType
|
||||
sysprof_descendants_model_get_item_type (GListModel *model)
|
||||
{
|
||||
return SYSPROF_TYPE_CALLGRAPH_FRAME;
|
||||
}
|
||||
|
||||
static guint
|
||||
sysprof_descendants_model_get_n_items (GListModel *model)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
sysprof_descendants_model_get_item (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
SysprofDescendantsModel *self = SYSPROF_DESCENDANTS_MODEL (model);
|
||||
|
||||
if (position != 0)
|
||||
return NULL;
|
||||
|
||||
return _sysprof_callgraph_frame_new_for_node (self->callgraph, G_OBJECT (self), &self->root);
|
||||
}
|
||||
|
||||
static void
|
||||
list_model_iface_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = sysprof_descendants_model_get_item_type;
|
||||
iface->get_n_items = sysprof_descendants_model_get_n_items;
|
||||
iface->get_item = sysprof_descendants_model_get_item;
|
||||
}
|
||||
|
||||
G_DEFINE_FINAL_TYPE_WITH_CODE (SysprofDescendantsModel, sysprof_descendants_model, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
|
||||
|
||||
static void
|
||||
sysprof_descendants_model_finalize (GObject *object)
|
||||
{
|
||||
SysprofDescendantsModel *self = (SysprofDescendantsModel *)object;
|
||||
|
||||
_sysprof_callgraph_node_free (&self->root, FALSE);
|
||||
|
||||
g_clear_object (&self->callgraph);
|
||||
g_clear_object (&self->symbol);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_descendants_model_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_descendants_model_class_init (SysprofDescendantsModelClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_descendants_model_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_descendants_model_init (SysprofDescendantsModel *self)
|
||||
{
|
||||
}
|
||||
|
||||
static SysprofCallgraphNode *
|
||||
sysprof_descendants_model_add_trace (SysprofDescendantsModel *self,
|
||||
SysprofSymbol **symbols,
|
||||
guint n_symbols)
|
||||
{
|
||||
SysprofCallgraphNode *parent = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_DESCENDANTS_MODEL (self));
|
||||
g_assert (symbols != NULL);
|
||||
g_assert (n_symbols > 0);
|
||||
|
||||
parent = &self->root;
|
||||
|
||||
for (guint i = n_symbols; i > 0; i--)
|
||||
{
|
||||
SysprofSymbol *symbol = symbols[i-1];
|
||||
SysprofCallgraphNode *node = NULL;
|
||||
SysprofCallgraphSummary *summary;
|
||||
|
||||
/* Try to find @symbol within the children of @parent */
|
||||
for (SysprofCallgraphNode *iter = parent->children;
|
||||
iter != NULL;
|
||||
iter = iter->next)
|
||||
{
|
||||
g_assert (iter != NULL);
|
||||
g_assert (iter->summary != NULL);
|
||||
g_assert (iter->summary->symbol != NULL);
|
||||
g_assert (symbol != NULL);
|
||||
|
||||
if (_sysprof_symbol_equal (iter->summary->symbol, symbol))
|
||||
{
|
||||
node = iter;
|
||||
goto next_symbol;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(summary = g_hash_table_lookup (self->callgraph->symbol_to_summary, symbol)))
|
||||
{
|
||||
node = parent;
|
||||
goto next_symbol;
|
||||
}
|
||||
|
||||
/* Otherwise create a new node */
|
||||
node = g_new0 (SysprofCallgraphNode, 1);
|
||||
node->summary = summary;
|
||||
node->parent = parent;
|
||||
node->next = parent->children;
|
||||
if (parent->children)
|
||||
parent->children->prev = node;
|
||||
parent->children = node;
|
||||
|
||||
g_assert (node->summary != NULL);
|
||||
|
||||
next_symbol:
|
||||
parent = node;
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_descendants_model_add_traceable (SysprofDescendantsModel *self,
|
||||
SysprofDocument *document,
|
||||
SysprofDocumentTraceable *traceable,
|
||||
SysprofSymbol *from_symbol,
|
||||
gboolean include_threads)
|
||||
{
|
||||
SysprofAddressContext final_context;
|
||||
SysprofSymbol **symbols;
|
||||
SysprofSymbolKind kind;
|
||||
guint stack_depth;
|
||||
guint n_symbols;
|
||||
|
||||
g_assert (SYSPROF_IS_DESCENDANTS_MODEL (self));
|
||||
g_assert (SYSPROF_IS_DOCUMENT (document));
|
||||
g_assert (SYSPROF_IS_DOCUMENT_TRACEABLE (traceable));
|
||||
g_assert (SYSPROF_IS_SYMBOL (from_symbol));
|
||||
|
||||
stack_depth = MIN (MAX_STACK_DEPTH, sysprof_document_traceable_get_stack_depth (traceable));
|
||||
symbols = g_alloca (sizeof (SysprofSymbol *) * (stack_depth + 2));
|
||||
n_symbols = sysprof_document_symbolize_traceable (document, traceable, symbols, stack_depth, &final_context);
|
||||
|
||||
kind = sysprof_symbol_get_kind (from_symbol);
|
||||
|
||||
if (kind == SYSPROF_SYMBOL_KIND_PROCESS || kind == SYSPROF_SYMBOL_KIND_THREAD)
|
||||
{
|
||||
int pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable));
|
||||
|
||||
if (include_threads)
|
||||
{
|
||||
int thread_id = sysprof_document_traceable_get_thread_id (traceable);
|
||||
symbols[n_symbols++] = _sysprof_document_thread_symbol (document, pid, thread_id);
|
||||
}
|
||||
|
||||
symbols[n_symbols++] = _sysprof_document_process_symbol (document, pid);
|
||||
}
|
||||
|
||||
for (guint i = n_symbols; i > 0; i--)
|
||||
{
|
||||
SysprofSymbol *symbol = symbols[i-1];
|
||||
|
||||
n_symbols--;
|
||||
|
||||
if (_sysprof_symbol_equal (symbol, from_symbol))
|
||||
break;
|
||||
}
|
||||
|
||||
if (n_symbols > 0)
|
||||
{
|
||||
SysprofCallgraphNode *node;
|
||||
|
||||
node = sysprof_descendants_model_add_trace (self, symbols, n_symbols);
|
||||
|
||||
if (node && self->callgraph->augment_func)
|
||||
self->callgraph->augment_func (self->callgraph,
|
||||
node,
|
||||
SYSPROF_DOCUMENT_FRAME (traceable),
|
||||
FALSE,
|
||||
self->callgraph->augment_func_data);
|
||||
}
|
||||
}
|
||||
|
||||
GListModel *
|
||||
_sysprof_descendants_model_new (SysprofCallgraph *callgraph,
|
||||
SysprofSymbol *symbol)
|
||||
{
|
||||
SysprofDescendantsModel *self;
|
||||
g_autoptr(SysprofDocument) document = NULL;
|
||||
g_autoptr(GListModel) model = NULL;
|
||||
gboolean include_threads;
|
||||
guint n_items;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH (callgraph), NULL);
|
||||
g_return_val_if_fail (SYSPROF_IS_SYMBOL (symbol), NULL);
|
||||
|
||||
model = sysprof_callgraph_list_traceables_for_symbol (callgraph, symbol);
|
||||
document = g_object_ref (callgraph->document);
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_DESCENDANTS_MODEL, NULL);
|
||||
self->callgraph = g_object_ref (callgraph);
|
||||
self->symbol = g_object_ref (symbol);
|
||||
self->root.summary = g_hash_table_lookup (callgraph->symbol_to_summary, symbol);
|
||||
|
||||
g_assert (self->root.summary != NULL);
|
||||
g_assert (_sysprof_symbol_equal (self->root.summary->symbol, symbol));
|
||||
|
||||
include_threads = (callgraph->flags & SYSPROF_CALLGRAPH_FLAGS_INCLUDE_THREADS) != 0;
|
||||
n_items = g_list_model_get_n_items (model);
|
||||
|
||||
for (guint i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr(SysprofDocumentTraceable) traceable = g_list_model_get_item (model, i);
|
||||
|
||||
sysprof_descendants_model_add_traceable (self, document, traceable, symbol, include_threads);
|
||||
}
|
||||
|
||||
return G_LIST_MODEL (self);
|
||||
}
|
||||
31
src/libsysprof/sysprof-diagnostic-private.h
Normal file
31
src/libsysprof/sysprof-diagnostic-private.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* sysprof-diagnostic-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-diagnostic.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
SysprofDiagnostic *_sysprof_diagnostic_new (char *domain,
|
||||
char *message,
|
||||
gboolean fatal);
|
||||
|
||||
G_END_DECLS
|
||||
151
src/libsysprof/sysprof-diagnostic.c
Normal file
151
src/libsysprof/sysprof-diagnostic.c
Normal file
@ -0,0 +1,151 @@
|
||||
/* sysprof-diagnostic.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-diagnostic-private.h"
|
||||
|
||||
struct _SysprofDiagnostic
|
||||
{
|
||||
GObject parent_instance;
|
||||
GRefString *domain;
|
||||
char *message;
|
||||
guint fatal : 1;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_DOMAIN,
|
||||
PROP_MESSAGE,
|
||||
PROP_FATAL,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDiagnostic, sysprof_diagnostic, G_TYPE_OBJECT)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_diagnostic_finalize (GObject *object)
|
||||
{
|
||||
SysprofDiagnostic *self = (SysprofDiagnostic *)object;
|
||||
|
||||
g_clear_pointer (&self->domain, g_free);
|
||||
g_clear_pointer (&self->message, g_free);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_diagnostic_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_diagnostic_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDiagnostic *self = SYSPROF_DIAGNOSTIC (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DOMAIN:
|
||||
g_value_set_string (value, self->domain);
|
||||
break;
|
||||
|
||||
case PROP_MESSAGE:
|
||||
g_value_set_string (value, self->message);
|
||||
break;
|
||||
|
||||
case PROP_FATAL:
|
||||
g_value_set_boolean (value, self->fatal);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_diagnostic_class_init (SysprofDiagnosticClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_diagnostic_finalize;
|
||||
object_class->get_property = sysprof_diagnostic_get_property;
|
||||
|
||||
properties [PROP_DOMAIN] =
|
||||
g_param_spec_string ("domain", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_MESSAGE] =
|
||||
g_param_spec_string ("message", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_FATAL] =
|
||||
g_param_spec_boolean ("fatal", NULL, NULL,
|
||||
FALSE,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_diagnostic_init (SysprofDiagnostic *self)
|
||||
{
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_diagnostic_get_domain (SysprofDiagnostic *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DIAGNOSTIC (self), NULL);
|
||||
|
||||
return self->domain;
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_diagnostic_get_message (SysprofDiagnostic *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DIAGNOSTIC (self), NULL);
|
||||
|
||||
return self->message;
|
||||
}
|
||||
|
||||
gboolean
|
||||
sysprof_diagnostic_get_fatal (SysprofDiagnostic *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DIAGNOSTIC (self), FALSE);
|
||||
|
||||
return self->fatal;
|
||||
}
|
||||
|
||||
SysprofDiagnostic *
|
||||
_sysprof_diagnostic_new (char *domain,
|
||||
char *message,
|
||||
gboolean fatal)
|
||||
{
|
||||
SysprofDiagnostic *self;
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_DIAGNOSTIC, NULL);
|
||||
self->message = message;
|
||||
self->domain = domain;
|
||||
self->fatal = !!fatal;
|
||||
|
||||
return self;
|
||||
}
|
||||
41
src/libsysprof/sysprof-diagnostic.h
Normal file
41
src/libsysprof/sysprof-diagnostic.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* sysprof-diagnostic.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DIAGNOSTIC (sysprof_diagnostic_get_type())
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (SysprofDiagnostic, sysprof_diagnostic, SYSPROF, DIAGNOSTIC, GObject)
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_diagnostic_get_domain (SysprofDiagnostic *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_diagnostic_get_message (SysprofDiagnostic *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_diagnostic_get_fatal (SysprofDiagnostic *self);
|
||||
|
||||
G_END_DECLS
|
||||
442
src/libsysprof/sysprof-disk-usage.c
Normal file
442
src/libsysprof/sysprof-disk-usage.c
Normal file
@ -0,0 +1,442 @@
|
||||
/* sysprof-disk-usage.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include "sysprof-disk-usage.h"
|
||||
#include "sysprof-instrument-private.h"
|
||||
#include "sysprof-recording-private.h"
|
||||
|
||||
#include "line-reader-private.h"
|
||||
|
||||
#define ADD_FROM_CHAR(v, c) (((v)*10L)+((c)-'0'))
|
||||
|
||||
struct _SysprofDiskUsage
|
||||
{
|
||||
SysprofInstrument parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofDiskUsageClass
|
||||
{
|
||||
SysprofInstrumentClass parent_class;
|
||||
};
|
||||
|
||||
typedef struct _DiskUsage
|
||||
{
|
||||
/* Counter IDs */
|
||||
guint reads_total_id;
|
||||
guint writes_total_id;
|
||||
|
||||
/* Index where values are stored */
|
||||
guint values_at;
|
||||
|
||||
char device[32];
|
||||
|
||||
gint64 reads_total;
|
||||
gint64 reads_merged;
|
||||
gint64 reads_sectors;
|
||||
gint64 reads_msec;
|
||||
gint64 writes_total;
|
||||
gint64 writes_merged;
|
||||
gint64 writes_sectors;
|
||||
gint64 writes_msec;
|
||||
gint64 iops_active;
|
||||
gint64 iops_msec;
|
||||
gint64 iops_msec_weighted;
|
||||
} DiskUsage;
|
||||
|
||||
typedef enum _Column
|
||||
{
|
||||
/* -2 */ COLUMN_MAJOR,
|
||||
/* -1 */ COLUMN_MINOR,
|
||||
/* 0 */ COLUMN_NAME,
|
||||
/* 1 */ COLUMN_READS_TOTAL,
|
||||
/* 2 */ COLUMN_READS_MERGED,
|
||||
/* 3 */ COLUMN_READS_SECTORS,
|
||||
/* 4 */ COLUMN_READS_MSEC,
|
||||
/* 5 */ COLUMN_WRITES_TOTAL,
|
||||
/* 6 */ COLUMN_WRITES_MERGED,
|
||||
/* 7 */ COLUMN_WRITES_SECTORS,
|
||||
/* 8 */ COLUMN_WRITES_MSEC,
|
||||
/* 9 */ COLUMN_IOPS_ACTIVE,
|
||||
/* 10 */ COLUMN_IOPS_MSEC,
|
||||
/* 11 */ COLUMN_IOPS_MSEC_WEIGHTED,
|
||||
} Column;
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDiskUsage, sysprof_disk_usage, SYSPROF_TYPE_INSTRUMENT)
|
||||
|
||||
typedef struct _Record
|
||||
{
|
||||
SysprofRecording *recording;
|
||||
DexFuture *cancellable;
|
||||
GArray *devices;
|
||||
GArray *ids;
|
||||
GArray *values;
|
||||
} Record;
|
||||
|
||||
static void
|
||||
record_free (gpointer data)
|
||||
{
|
||||
Record *record = data;
|
||||
|
||||
g_clear_object (&record->recording);
|
||||
g_clear_pointer (&record->devices, g_array_unref);
|
||||
g_clear_pointer (&record->ids, g_array_unref);
|
||||
g_clear_pointer (&record->values, g_array_unref);
|
||||
dex_clear (&record->cancellable);
|
||||
g_free (record);
|
||||
}
|
||||
|
||||
static DiskUsage *
|
||||
register_counters_by_name (Record *record,
|
||||
const char *name)
|
||||
{
|
||||
static const SysprofCaptureCounterValue zeroval = {0};
|
||||
SysprofCaptureCounter ctr[2] = {0};
|
||||
SysprofCaptureWriter *writer;
|
||||
DiskUsage ds = {0};
|
||||
|
||||
g_assert (record != NULL);
|
||||
g_assert (name != NULL);
|
||||
|
||||
writer = _sysprof_recording_writer (record->recording);
|
||||
|
||||
ds.values_at = record->ids->len;
|
||||
ds.reads_total_id = sysprof_capture_writer_request_counter (writer, 1);
|
||||
ds.writes_total_id = sysprof_capture_writer_request_counter (writer, 1);
|
||||
|
||||
g_strlcpy (ds.device, name, sizeof ds.device);
|
||||
|
||||
g_strlcpy (ctr[0].category, "Disk", sizeof ctr[0].category);
|
||||
g_snprintf (ctr[0].name, sizeof ctr[0].name, "Total Reads (%s)", name);
|
||||
g_strlcpy (ctr[0].description, name, sizeof ctr[0].description);
|
||||
ctr[0].id = ds.reads_total_id;
|
||||
ctr[0].type = SYSPROF_CAPTURE_COUNTER_INT64;
|
||||
ctr[0].value.v64 = 0;
|
||||
|
||||
g_strlcpy (ctr[1].category, "Disk", sizeof ctr[1].category);
|
||||
g_snprintf (ctr[1].name, sizeof ctr[1].name, "Total Writes (%s)", name);
|
||||
g_strlcpy (ctr[1].description, name, sizeof ctr[1].description);
|
||||
ctr[1].id = ds.writes_total_id;
|
||||
ctr[1].type = SYSPROF_CAPTURE_COUNTER_INT64;
|
||||
ctr[1].value.v64 = 0;
|
||||
|
||||
sysprof_capture_writer_define_counters (writer,
|
||||
SYSPROF_CAPTURE_CURRENT_TIME,
|
||||
-1,
|
||||
-1,
|
||||
ctr,
|
||||
G_N_ELEMENTS (ctr));
|
||||
|
||||
g_array_append_val (record->devices, ds);
|
||||
g_array_append_val (record->ids, ds.reads_total_id);
|
||||
g_array_append_val (record->ids, ds.writes_total_id);
|
||||
g_array_append_val (record->values, zeroval);
|
||||
g_array_append_val (record->values, zeroval);
|
||||
|
||||
return &g_array_index (record->devices, DiskUsage, record->devices->len-1);
|
||||
}
|
||||
|
||||
static DiskUsage *
|
||||
find_device_by_name (Record *record,
|
||||
const char *name)
|
||||
{
|
||||
g_assert (record != NULL);
|
||||
g_assert (record->devices != NULL);
|
||||
g_assert (name != NULL);
|
||||
|
||||
for (guint i = 0; i < record->devices->len; i++)
|
||||
{
|
||||
DiskUsage *ds = &g_array_index (record->devices, DiskUsage, i);
|
||||
|
||||
if (strcmp (name, ds->device) == 0)
|
||||
return ds;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
sysprof_disk_usage_record_fiber (gpointer user_data)
|
||||
{
|
||||
g_autoptr(GByteArray) buf = NULL;
|
||||
Record *record = user_data;
|
||||
SysprofCaptureWriter *writer;
|
||||
g_autofd int stat_fd = -1;
|
||||
LineReader reader;
|
||||
DiskUsage *combined;
|
||||
gint64 combined_reads_total = 0;
|
||||
gint64 combined_writes_total = 0;
|
||||
gboolean skip_publish = TRUE;
|
||||
|
||||
g_assert (record != NULL);
|
||||
g_assert (SYSPROF_IS_RECORDING (record->recording));
|
||||
g_assert (DEX_IS_CANCELLABLE (record->cancellable));
|
||||
|
||||
buf = g_byte_array_new ();
|
||||
g_byte_array_set_size (buf, 4096*4);
|
||||
|
||||
if (-1 == (stat_fd = open ("/proc/diskstats", O_RDONLY|O_CLOEXEC)))
|
||||
return dex_future_new_for_errno (errno);
|
||||
|
||||
writer = _sysprof_recording_writer (record->recording);
|
||||
|
||||
register_counters_by_name (record, "Combined");
|
||||
|
||||
for (;;)
|
||||
{
|
||||
g_autoptr(DexFuture) read_future = NULL;
|
||||
gssize n_read;
|
||||
char *line;
|
||||
gsize line_len;
|
||||
|
||||
/* Read a new copy of our diskstats or bail from our
|
||||
* recording loop. If cancellation future rejects, then
|
||||
* we also break out of our recording loop.
|
||||
*/
|
||||
read_future = dex_aio_read (NULL, stat_fd, buf->data, buf->len-1, 0);
|
||||
if (!dex_await (dex_future_first (dex_ref (record->cancellable),
|
||||
dex_ref (read_future),
|
||||
NULL),
|
||||
NULL))
|
||||
break;
|
||||
|
||||
n_read = dex_await_int64 (dex_ref (read_future), NULL);
|
||||
if (n_read < 0)
|
||||
break;
|
||||
|
||||
line_reader_init (&reader, (char *)buf->data, n_read);
|
||||
while ((line = line_reader_next (&reader, &line_len)))
|
||||
{
|
||||
DiskUsage ds = {0};
|
||||
DiskUsage *found;
|
||||
gint64 dummy = 0;
|
||||
int column = COLUMN_MAJOR;
|
||||
|
||||
line[line_len] = 0;
|
||||
|
||||
/* Skip past initial space */
|
||||
while (g_ascii_isspace (*line))
|
||||
line++;
|
||||
|
||||
for (const char *ptr = line; *ptr; ptr++)
|
||||
{
|
||||
char ch;
|
||||
|
||||
/* Skip past space and advance to next column */
|
||||
if (g_ascii_isspace (*ptr))
|
||||
{
|
||||
while (g_ascii_isspace (*ptr))
|
||||
ptr++;
|
||||
column++;
|
||||
}
|
||||
|
||||
ch = *ptr;
|
||||
|
||||
switch (column)
|
||||
{
|
||||
case COLUMN_MAJOR:
|
||||
case COLUMN_MINOR:
|
||||
default:
|
||||
dummy = ADD_FROM_CHAR (dummy, ch);
|
||||
break;
|
||||
|
||||
case COLUMN_NAME:
|
||||
{
|
||||
guint j;
|
||||
|
||||
for (j = 0; j < sizeof ds.device && ds.device[j] != 0; j++) { /* Do Nothing */ }
|
||||
if (j < sizeof ds.device)
|
||||
ds.device[j] = ch;
|
||||
ds.device[sizeof ds.device - 1] = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case COLUMN_READS_TOTAL:
|
||||
ds.reads_total = ADD_FROM_CHAR (ds.reads_total, ch);
|
||||
break;
|
||||
|
||||
case COLUMN_READS_MERGED:
|
||||
ds.reads_merged = ADD_FROM_CHAR (ds.reads_merged, ch);
|
||||
break;
|
||||
|
||||
case COLUMN_READS_SECTORS:
|
||||
ds.reads_sectors = ADD_FROM_CHAR (ds.reads_sectors, ch);
|
||||
break;
|
||||
|
||||
case COLUMN_READS_MSEC:
|
||||
ds.reads_msec = ADD_FROM_CHAR (ds.reads_msec, ch);
|
||||
break;
|
||||
|
||||
case COLUMN_WRITES_TOTAL:
|
||||
ds.writes_total = ADD_FROM_CHAR (ds.writes_total, ch);
|
||||
break;
|
||||
|
||||
case COLUMN_WRITES_MERGED:
|
||||
ds.writes_merged = ADD_FROM_CHAR (ds.writes_merged, ch);
|
||||
break;
|
||||
|
||||
case COLUMN_WRITES_SECTORS:
|
||||
ds.writes_sectors = ADD_FROM_CHAR (ds.writes_sectors, ch);
|
||||
break;
|
||||
|
||||
case COLUMN_WRITES_MSEC:
|
||||
ds.writes_msec = ADD_FROM_CHAR (ds.writes_msec, ch);
|
||||
break;
|
||||
|
||||
case COLUMN_IOPS_ACTIVE:
|
||||
ds.iops_active = ADD_FROM_CHAR (ds.iops_active, ch);
|
||||
break;
|
||||
|
||||
case COLUMN_IOPS_MSEC:
|
||||
ds.iops_msec = ADD_FROM_CHAR (ds.iops_msec, ch);
|
||||
break;
|
||||
|
||||
case COLUMN_IOPS_MSEC_WEIGHTED:
|
||||
ds.iops_msec_weighted = ADD_FROM_CHAR (ds.iops_msec_weighted, ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_strstrip (ds.device);
|
||||
|
||||
if (ds.device[0])
|
||||
{
|
||||
guint p;
|
||||
gint64 reads_total;
|
||||
gint64 writes_total;
|
||||
|
||||
if (!(found = find_device_by_name (record, ds.device)))
|
||||
found = register_counters_by_name (record, ds.device);
|
||||
|
||||
/* Calculate new value, based on diff from previous */
|
||||
reads_total = ds.reads_total - found->reads_total;
|
||||
writes_total = ds.writes_total - found->writes_total;
|
||||
|
||||
/* Update value for publishing */
|
||||
p = found->values_at;
|
||||
g_array_index (record->values, SysprofCaptureCounterValue, p).v64 = reads_total;
|
||||
g_array_index (record->values, SysprofCaptureCounterValue, p+1).v64 = writes_total;
|
||||
|
||||
/* Update combined values */
|
||||
combined_reads_total += reads_total;
|
||||
combined_writes_total += writes_total;
|
||||
|
||||
/* Save current value for diff on next poll */
|
||||
found->reads_total = ds.reads_total;
|
||||
found->writes_total = ds.writes_total;
|
||||
}
|
||||
}
|
||||
|
||||
if ((combined = find_device_by_name (record, "Combined")))
|
||||
{
|
||||
/* TODO: It would be nice to not double count disk ops multiple
|
||||
* times based on the parition, etc.
|
||||
*
|
||||
* For example: nvme0n1 nvme0n1p1 nvme0n1p2 nvme0n1p3 may get
|
||||
* accounted multiple times even though they are all nvme0n1.
|
||||
*
|
||||
* The other option, is to just not do "Combined" counters.
|
||||
*/
|
||||
|
||||
g_array_index (record->values,
|
||||
SysprofCaptureCounterValue,
|
||||
combined->values_at).v64
|
||||
= combined_reads_total - combined->reads_total;
|
||||
g_array_index (record->values,
|
||||
SysprofCaptureCounterValue,
|
||||
combined->values_at+1).v64
|
||||
= combined_writes_total - combined->writes_total;
|
||||
|
||||
combined->reads_total = combined_reads_total;
|
||||
combined->writes_total = combined_writes_total;
|
||||
}
|
||||
|
||||
g_assert (record->ids->len == record->values->len);
|
||||
|
||||
if (skip_publish)
|
||||
skip_publish = FALSE;
|
||||
else
|
||||
sysprof_capture_writer_set_counters (writer,
|
||||
SYSPROF_CAPTURE_CURRENT_TIME,
|
||||
-1,
|
||||
-1,
|
||||
(const guint *)(gpointer)record->ids->data,
|
||||
(const SysprofCaptureCounterValue *)(gpointer)record->values->data,
|
||||
record->ids->len);
|
||||
|
||||
dex_await (dex_future_first (dex_ref (record->cancellable),
|
||||
dex_timeout_new_usec (G_USEC_PER_SEC / 2),
|
||||
NULL),
|
||||
NULL);
|
||||
if (dex_future_get_status (record->cancellable) != DEX_FUTURE_STATUS_PENDING)
|
||||
break;
|
||||
}
|
||||
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
sysprof_disk_usage_record (SysprofInstrument *instrument,
|
||||
SysprofRecording *recording,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Record *record;
|
||||
|
||||
g_assert (SYSPROF_IS_INSTRUMENT (instrument));
|
||||
g_assert (SYSPROF_IS_RECORDING (recording));
|
||||
g_assert (G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
record = g_new0 (Record, 1);
|
||||
record->recording = g_object_ref (recording);
|
||||
record->cancellable = dex_cancellable_new_from_cancellable (cancellable);
|
||||
record->devices = g_array_new (FALSE, FALSE, sizeof (DiskUsage));
|
||||
record->ids = g_array_new (FALSE, FALSE, sizeof (guint));
|
||||
record->values = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounterValue));
|
||||
|
||||
return dex_scheduler_spawn (NULL, 0,
|
||||
sysprof_disk_usage_record_fiber,
|
||||
record,
|
||||
record_free);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_disk_usage_class_init (SysprofDiskUsageClass *klass)
|
||||
{
|
||||
SysprofInstrumentClass *instrument_class = SYSPROF_INSTRUMENT_CLASS (klass);
|
||||
|
||||
instrument_class->record = sysprof_disk_usage_record;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_disk_usage_init (SysprofDiskUsage *self)
|
||||
{
|
||||
}
|
||||
|
||||
SysprofInstrument *
|
||||
sysprof_disk_usage_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_DISK_USAGE, NULL);
|
||||
}
|
||||
42
src/libsysprof/sysprof-disk-usage.h
Normal file
42
src/libsysprof/sysprof-disk-usage.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* sysprof-disk-usage.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-instrument.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DISK_USAGE (sysprof_disk_usage_get_type())
|
||||
#define SYSPROF_IS_DISK_USAGE(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DISK_USAGE)
|
||||
#define SYSPROF_DISK_USAGE(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DISK_USAGE, SysprofDiskUsage)
|
||||
#define SYSPROF_DISK_USAGE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DISK_USAGE, SysprofDiskUsageClass)
|
||||
|
||||
typedef struct _SysprofDiskUsage SysprofDiskUsage;
|
||||
typedef struct _SysprofDiskUsageClass SysprofDiskUsageClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_disk_usage_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofInstrument *sysprof_disk_usage_new (void);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDiskUsage, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
258
src/libsysprof/sysprof-document-allocation.c
Normal file
258
src/libsysprof/sysprof-document-allocation.c
Normal file
@ -0,0 +1,258 @@
|
||||
/* sysprof-document-allocation.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
|
||||
#include "sysprof-document-allocation.h"
|
||||
#include "sysprof-document-traceable.h"
|
||||
|
||||
struct _SysprofDocumentAllocation
|
||||
{
|
||||
SysprofDocumentFrame parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentAllocationClass
|
||||
{
|
||||
SysprofDocumentFrameClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ADDRESS,
|
||||
PROP_IS_FREE,
|
||||
PROP_SIZE,
|
||||
PROP_STACK_DEPTH,
|
||||
PROP_THREAD_ID,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static guint
|
||||
sysprof_document_allocation_get_stack_depth (SysprofDocumentTraceable *traceable)
|
||||
{
|
||||
const SysprofCaptureAllocation *allocation = SYSPROF_DOCUMENT_FRAME_GET (traceable, SysprofCaptureAllocation);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_UINT16 (traceable, allocation->n_addrs);
|
||||
}
|
||||
|
||||
static guint64
|
||||
sysprof_document_allocation_get_stack_address (SysprofDocumentTraceable *traceable,
|
||||
guint position)
|
||||
{
|
||||
const SysprofCaptureAllocation *allocation = SYSPROF_DOCUMENT_FRAME_GET (traceable, SysprofCaptureAllocation);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_UINT16 (traceable, allocation->addrs[position]);
|
||||
}
|
||||
|
||||
static guint
|
||||
sysprof_document_allocation_get_stack_addresses (SysprofDocumentTraceable *traceable,
|
||||
guint64 *addresses,
|
||||
guint n_addresses)
|
||||
{
|
||||
const SysprofCaptureAllocation *allocation = SYSPROF_DOCUMENT_FRAME_GET (traceable, SysprofCaptureAllocation);
|
||||
guint depth = MIN (n_addresses, SYSPROF_DOCUMENT_FRAME_UINT16 (traceable, allocation->n_addrs));
|
||||
|
||||
for (guint i = 0; i < depth; i++)
|
||||
addresses[i] = SYSPROF_DOCUMENT_FRAME_UINT64 (traceable, allocation->addrs[i]);
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
static int
|
||||
sysprof_document_allocation_get_thread_id (SysprofDocumentTraceable *traceable)
|
||||
{
|
||||
SysprofDocumentAllocation *self = (SysprofDocumentAllocation *)traceable;
|
||||
const SysprofCaptureAllocation *allocation;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_ALLOCATION (self), 0);
|
||||
|
||||
allocation = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureAllocation);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_INT32 (self, allocation->tid);
|
||||
}
|
||||
|
||||
static void
|
||||
traceable_iface_init (SysprofDocumentTraceableInterface *iface)
|
||||
{
|
||||
iface->get_stack_depth = sysprof_document_allocation_get_stack_depth;
|
||||
iface->get_stack_address = sysprof_document_allocation_get_stack_address;
|
||||
iface->get_stack_addresses = sysprof_document_allocation_get_stack_addresses;
|
||||
iface->get_thread_id = sysprof_document_allocation_get_thread_id;
|
||||
}
|
||||
|
||||
G_DEFINE_FINAL_TYPE_WITH_CODE (SysprofDocumentAllocation, sysprof_document_allocation, SYSPROF_TYPE_DOCUMENT_FRAME,
|
||||
G_IMPLEMENT_INTERFACE (SYSPROF_TYPE_DOCUMENT_TRACEABLE, traceable_iface_init))
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_document_allocation_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentAllocation *self = SYSPROF_DOCUMENT_ALLOCATION (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ADDRESS:
|
||||
g_value_set_uint64 (value, sysprof_document_allocation_get_address (self));
|
||||
break;
|
||||
|
||||
case PROP_IS_FREE:
|
||||
g_value_set_boolean (value, sysprof_document_allocation_is_free (self));
|
||||
break;
|
||||
|
||||
case PROP_SIZE:
|
||||
g_value_set_int64 (value, sysprof_document_allocation_get_size (self));
|
||||
break;
|
||||
|
||||
case PROP_STACK_DEPTH:
|
||||
g_value_set_uint (value, sysprof_document_traceable_get_stack_depth (SYSPROF_DOCUMENT_TRACEABLE (self)));
|
||||
break;
|
||||
|
||||
case PROP_THREAD_ID:
|
||||
g_value_set_int (value, sysprof_document_traceable_get_thread_id (SYSPROF_DOCUMENT_TRACEABLE (self)));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_allocation_class_init (SysprofDocumentAllocationClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
SysprofDocumentFrameClass *document_frame_class = SYSPROF_DOCUMENT_FRAME_CLASS (klass);
|
||||
|
||||
object_class->get_property = sysprof_document_allocation_get_property;
|
||||
|
||||
document_frame_class->type_name = N_("Allocation");
|
||||
|
||||
/**
|
||||
* SysprofDocumentAllocation:thread-id:
|
||||
*
|
||||
* The thread-id where the stack was traced.
|
||||
*
|
||||
* On Linux, this is generally set to the value of `gettid()`.
|
||||
*
|
||||
* Since: 45
|
||||
*/
|
||||
properties [PROP_THREAD_ID] =
|
||||
g_param_spec_int ("thread-id", NULL, NULL,
|
||||
-1, G_MAXINT32, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* SysprofDocumentAllocation:address:
|
||||
*
|
||||
* The address that was allocated or freed.
|
||||
*
|
||||
* Since: 45
|
||||
*/
|
||||
properties [PROP_ADDRESS] =
|
||||
g_param_spec_uint64 ("address", NULL, NULL,
|
||||
0, G_MAXUINT64, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* SysprofDocumentAllocation:size:
|
||||
*
|
||||
* The size of the memory that was allocated or freed.
|
||||
*
|
||||
* Since: 45
|
||||
*/
|
||||
properties [PROP_SIZE] =
|
||||
g_param_spec_int64 ("size", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* SysprofDocumentAllocation:is-free:
|
||||
*
|
||||
* If this allocation record is a call to release
|
||||
* #SysprofDocumentAllocation:address.
|
||||
*
|
||||
* Since: 45
|
||||
*/
|
||||
properties [PROP_IS_FREE] =
|
||||
g_param_spec_boolean ("is-free", NULL, NULL,
|
||||
FALSE,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* SysprofDocumentAllocation:stack-depth:
|
||||
*
|
||||
* The depth of the stack trace.
|
||||
*
|
||||
* Since: 45
|
||||
*/
|
||||
properties [PROP_STACK_DEPTH] =
|
||||
g_param_spec_uint ("stack-depth", NULL, NULL,
|
||||
0, G_MAXUINT16, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_allocation_init (SysprofDocumentAllocation *self)
|
||||
{
|
||||
}
|
||||
|
||||
guint64
|
||||
sysprof_document_allocation_get_address (SysprofDocumentAllocation *self)
|
||||
{
|
||||
const SysprofCaptureAllocation *allocation;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_ALLOCATION (self), 0);
|
||||
|
||||
allocation = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureAllocation);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_UINT64 (self, allocation->alloc_addr);
|
||||
}
|
||||
|
||||
gint64
|
||||
sysprof_document_allocation_get_size (SysprofDocumentAllocation *self)
|
||||
{
|
||||
const SysprofCaptureAllocation *allocation;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_ALLOCATION (self), 0);
|
||||
|
||||
allocation = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureAllocation);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_INT64 (self, allocation->alloc_size);
|
||||
}
|
||||
|
||||
gboolean
|
||||
sysprof_document_allocation_is_free (SysprofDocumentAllocation *self)
|
||||
{
|
||||
const SysprofCaptureAllocation *allocation;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_ALLOCATION (self), 0);
|
||||
|
||||
allocation = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureAllocation);
|
||||
|
||||
return allocation->alloc_size == 0;
|
||||
}
|
||||
48
src/libsysprof/sysprof-document-allocation.h
Normal file
48
src/libsysprof/sysprof-document-allocation.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* sysprof-document-allocation.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_ALLOCATION (sysprof_document_allocation_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_ALLOCATION(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_ALLOCATION)
|
||||
#define SYSPROF_DOCUMENT_ALLOCATION(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_ALLOCATION, SysprofDocumentAllocation)
|
||||
#define SYSPROF_DOCUMENT_ALLOCATION_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_ALLOCATION, SysprofDocumentAllocationClass)
|
||||
|
||||
typedef struct _SysprofDocumentAllocation SysprofDocumentAllocation;
|
||||
typedef struct _SysprofDocumentAllocationClass SysprofDocumentAllocationClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_allocation_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint64 sysprof_document_allocation_get_address (SysprofDocumentAllocation *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gint64 sysprof_document_allocation_get_size (SysprofDocumentAllocation *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
int sysprof_document_allocation_get_tid (SysprofDocumentAllocation *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_document_allocation_is_free (SysprofDocumentAllocation *self);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentAllocation, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
35
src/libsysprof/sysprof-document-bitset-index-private.h
Normal file
35
src/libsysprof/sysprof-document-bitset-index-private.h
Normal file
@ -0,0 +1,35 @@
|
||||
/* sysprof-document-bitset-index.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <eggbitset.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_BITSET_INDEX (sysprof_document_bitset_index_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofDocumentBitsetIndex, sysprof_document_bitset_index, SYSPROF, DOCUMENT_BITSET_INDEX, GObject)
|
||||
|
||||
GListModel *_sysprof_document_bitset_index_new (GListModel *model,
|
||||
EggBitset *bitset);
|
||||
|
||||
G_END_DECLS
|
||||
154
src/libsysprof/sysprof-document-bitset-index.c
Normal file
154
src/libsysprof/sysprof-document-bitset-index.c
Normal file
@ -0,0 +1,154 @@
|
||||
/* sysprof-document-bitset-index.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-document-bitset-index-private.h"
|
||||
|
||||
struct _SysprofDocumentBitsetIndex
|
||||
{
|
||||
GObject parent_instance;
|
||||
GListModel *model;
|
||||
EggBitset *bitset;
|
||||
};
|
||||
|
||||
static GType
|
||||
sysprof_document_bitset_index_get_item_type (GListModel *model)
|
||||
{
|
||||
SysprofDocumentBitsetIndex *self = SYSPROF_DOCUMENT_BITSET_INDEX (model);
|
||||
|
||||
if (self->model != NULL)
|
||||
return g_list_model_get_item_type (self->model);
|
||||
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
sysprof_document_bitset_index_get_n_items (GListModel *model)
|
||||
{
|
||||
SysprofDocumentBitsetIndex *self = SYSPROF_DOCUMENT_BITSET_INDEX (model);
|
||||
|
||||
if (self->bitset != NULL)
|
||||
return egg_bitset_get_size (self->bitset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
sysprof_document_bitset_index_get_item (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
SysprofDocumentBitsetIndex *self = SYSPROF_DOCUMENT_BITSET_INDEX (model);
|
||||
|
||||
if (self->model == NULL || self->bitset == NULL)
|
||||
return NULL;
|
||||
|
||||
if (position >= egg_bitset_get_size (self->bitset))
|
||||
return NULL;
|
||||
|
||||
return g_list_model_get_item (self->model,
|
||||
egg_bitset_get_nth (self->bitset, position));
|
||||
}
|
||||
|
||||
static void
|
||||
list_model_iface_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item = sysprof_document_bitset_index_get_item;
|
||||
iface->get_item_type = sysprof_document_bitset_index_get_item_type;
|
||||
iface->get_n_items = sysprof_document_bitset_index_get_n_items;
|
||||
}
|
||||
|
||||
G_DEFINE_FINAL_TYPE_WITH_CODE (SysprofDocumentBitsetIndex, sysprof_document_bitset_index, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_N_ITEMS,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_document_bitset_index_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentBitsetIndex *self = SYSPROF_DOCUMENT_BITSET_INDEX (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_N_ITEMS:
|
||||
g_value_set_uint (value, g_list_model_get_n_items (G_LIST_MODEL (self)));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_bitset_index_dispose (GObject *object)
|
||||
{
|
||||
SysprofDocumentBitsetIndex *self = (SysprofDocumentBitsetIndex *)object;
|
||||
|
||||
g_clear_pointer (&self->bitset, egg_bitset_unref);
|
||||
g_clear_object (&self->model);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_document_bitset_index_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_bitset_index_class_init (SysprofDocumentBitsetIndexClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = sysprof_document_bitset_index_dispose;
|
||||
object_class->get_property = sysprof_document_bitset_index_get_property;
|
||||
|
||||
properties[PROP_N_ITEMS] =
|
||||
g_param_spec_uint ("n-items", NULL, NULL,
|
||||
0, G_MAXUINT, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_bitset_index_init (SysprofDocumentBitsetIndex *self)
|
||||
{
|
||||
}
|
||||
|
||||
GListModel *
|
||||
_sysprof_document_bitset_index_new (GListModel *model,
|
||||
EggBitset *bitset)
|
||||
{
|
||||
SysprofDocumentBitsetIndex *self;
|
||||
|
||||
g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
|
||||
g_return_val_if_fail (bitset != NULL, NULL);
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_DOCUMENT_BITSET_INDEX, NULL);
|
||||
self->model = g_object_ref (model);
|
||||
self->bitset = egg_bitset_ref (bitset);
|
||||
|
||||
return G_LIST_MODEL (self);
|
||||
}
|
||||
50
src/libsysprof/sysprof-document-counter-private.h
Normal file
50
src/libsysprof/sysprof-document-counter-private.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* sysprof-document-counter-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-counter.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
struct _SysprofDocumentCounter
|
||||
{
|
||||
GObject parent_instance;
|
||||
GRefString *category;
|
||||
GRefString *description;
|
||||
GRefString *name;
|
||||
GArray *values;
|
||||
double min_value;
|
||||
double max_value;
|
||||
gint64 begin_time;
|
||||
guint id;
|
||||
guint type;
|
||||
};
|
||||
|
||||
SysprofDocumentCounter *_sysprof_document_counter_new (guint id,
|
||||
guint type,
|
||||
GRefString *category,
|
||||
GRefString *name,
|
||||
GRefString *description,
|
||||
GArray *values,
|
||||
gint64 begin_time);
|
||||
void _sysprof_document_counter_calculate_range (SysprofDocumentCounter *self);
|
||||
|
||||
G_END_DECLS
|
||||
32
src/libsysprof/sysprof-document-counter-value-private.h
Normal file
32
src/libsysprof/sysprof-document-counter-value-private.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* sysprof-document-counter-value-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-counter-value.h"
|
||||
#include "sysprof-document-private.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
SysprofDocumentCounterValue *_sysprof_document_counter_value_new (guint type,
|
||||
const SysprofDocumentTimedValue *value,
|
||||
SysprofDocumentCounter *counter);
|
||||
|
||||
G_END_DECLS
|
||||
220
src/libsysprof/sysprof-document-counter-value.c
Normal file
220
src/libsysprof/sysprof-document-counter-value.c
Normal file
@ -0,0 +1,220 @@
|
||||
/* sysprof-document-counter-value.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-document-counter-private.h"
|
||||
#include "sysprof-document-counter-value-private.h"
|
||||
|
||||
struct _SysprofDocumentCounterValue
|
||||
{
|
||||
GObject parent_instance;
|
||||
SysprofDocumentCounter *counter;
|
||||
SysprofDocumentTimedValue value;
|
||||
guint type;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_COUNTER,
|
||||
PROP_TIME,
|
||||
PROP_TIME_OFFSET,
|
||||
PROP_VALUE_DOUBLE,
|
||||
PROP_VALUE_INT64,
|
||||
PROP_VALUE_STRING,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentCounterValue, sysprof_document_counter_value, G_TYPE_OBJECT)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_document_counter_value_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentCounterValue *self = SYSPROF_DOCUMENT_COUNTER_VALUE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_COUNTER:
|
||||
g_value_set_object (value, sysprof_document_counter_value_get_counter (self));
|
||||
break;
|
||||
|
||||
case PROP_TIME:
|
||||
g_value_set_int64 (value, sysprof_document_counter_value_get_time (self));
|
||||
break;
|
||||
|
||||
case PROP_TIME_OFFSET:
|
||||
g_value_set_int64 (value, sysprof_document_counter_value_get_time_offset (self));
|
||||
break;
|
||||
|
||||
case PROP_VALUE_DOUBLE:
|
||||
g_value_set_double (value, sysprof_document_counter_value_get_value_double (self));
|
||||
break;
|
||||
|
||||
case PROP_VALUE_INT64:
|
||||
g_value_set_int64 (value, sysprof_document_counter_value_get_value_int64 (self));
|
||||
break;
|
||||
|
||||
case PROP_VALUE_STRING:
|
||||
g_value_take_string (value, sysprof_document_counter_value_format (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_counter_value_class_init (SysprofDocumentCounterValueClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->get_property = sysprof_document_counter_value_get_property;
|
||||
|
||||
properties [PROP_COUNTER] =
|
||||
g_param_spec_object ("counter", NULL, NULL,
|
||||
SYSPROF_TYPE_DOCUMENT_COUNTER,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_TIME] =
|
||||
g_param_spec_int64 ("time", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_TIME_OFFSET] =
|
||||
g_param_spec_int64 ("time-offset", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties[PROP_VALUE_DOUBLE] =
|
||||
g_param_spec_double ("value-double", NULL, NULL,
|
||||
-G_MAXDOUBLE, G_MAXDOUBLE, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties[PROP_VALUE_INT64] =
|
||||
g_param_spec_int64 ("value-int64", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties[PROP_VALUE_STRING] =
|
||||
g_param_spec_string ("value-string", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_counter_value_init (SysprofDocumentCounterValue *self)
|
||||
{
|
||||
}
|
||||
|
||||
SysprofDocumentCounterValue *
|
||||
_sysprof_document_counter_value_new (guint type,
|
||||
const SysprofDocumentTimedValue *value,
|
||||
SysprofDocumentCounter *counter)
|
||||
{
|
||||
SysprofDocumentCounterValue *self;
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_DOCUMENT_COUNTER_VALUE, NULL);
|
||||
self->type = type;
|
||||
self->value = *value;
|
||||
self->counter = g_object_ref (counter);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
gint64
|
||||
sysprof_document_counter_value_get_time (SysprofDocumentCounterValue *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER_VALUE (self), 0);
|
||||
|
||||
return self->value.time;
|
||||
}
|
||||
|
||||
gint64
|
||||
sysprof_document_counter_value_get_time_offset (SysprofDocumentCounterValue *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER_VALUE (self), 0);
|
||||
|
||||
return self->value.time - self->counter->begin_time;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_document_counter_value_get_value (SysprofDocumentCounterValue *self,
|
||||
GValue *value)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_DOCUMENT_COUNTER_VALUE (self));
|
||||
g_return_if_fail (G_IS_VALUE (value));
|
||||
|
||||
if (G_VALUE_HOLDS_INT64 (value))
|
||||
g_value_set_int64 (value, self->value.v_int64);
|
||||
else if (G_VALUE_HOLDS_DOUBLE (value))
|
||||
g_value_set_double (value, self->value.v_double);
|
||||
else
|
||||
g_warning_once ("Unsupported value type %s", G_VALUE_TYPE_NAME (value));
|
||||
}
|
||||
|
||||
gint64
|
||||
sysprof_document_counter_value_get_value_int64 (SysprofDocumentCounterValue *self)
|
||||
{
|
||||
if (self->type == SYSPROF_CAPTURE_COUNTER_INT64)
|
||||
return self->value.v_int64;
|
||||
else
|
||||
return (gint64)self->value.v_double;
|
||||
}
|
||||
|
||||
double
|
||||
sysprof_document_counter_value_get_value_double (SysprofDocumentCounterValue *self)
|
||||
{
|
||||
if (self->type == SYSPROF_CAPTURE_COUNTER_DOUBLE)
|
||||
return self->value.v_double;
|
||||
else
|
||||
return (double)self->value.v_int64;
|
||||
}
|
||||
|
||||
char *
|
||||
sysprof_document_counter_value_format (SysprofDocumentCounterValue *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER_VALUE (self), NULL);
|
||||
|
||||
if (self->type == SYSPROF_CAPTURE_COUNTER_DOUBLE)
|
||||
return g_strdup_printf ("%lf", self->value.v_double);
|
||||
else
|
||||
return g_strdup_printf ("%ld", self->value.v_int64);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_counter_value_get_counter:
|
||||
* @self: a #SysprofDocumentCounterValue
|
||||
*
|
||||
* Returns: (transfer none): a #SysprofDocumentCounter
|
||||
*/
|
||||
SysprofDocumentCounter *
|
||||
sysprof_document_counter_value_get_counter (SysprofDocumentCounterValue *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER_VALUE (self), NULL);
|
||||
|
||||
return self->counter;
|
||||
}
|
||||
53
src/libsysprof/sysprof-document-counter-value.h
Normal file
53
src/libsysprof/sysprof-document-counter-value.h
Normal file
@ -0,0 +1,53 @@
|
||||
/* sysprof-document-counter-value.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
#include "sysprof-document-counter.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_COUNTER_VALUE (sysprof_document_counter_value_get_type())
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (SysprofDocumentCounterValue, sysprof_document_counter_value, SYSPROF, DOCUMENT_COUNTER_VALUE, GObject)
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofDocumentCounter *sysprof_document_counter_value_get_counter (SysprofDocumentCounterValue *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gint64 sysprof_document_counter_value_get_time (SysprofDocumentCounterValue *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gint64 sysprof_document_counter_value_get_time_offset (SysprofDocumentCounterValue *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_document_counter_value_get_value (SysprofDocumentCounterValue *self,
|
||||
GValue *value);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gint64 sysprof_document_counter_value_get_value_int64 (SysprofDocumentCounterValue *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
double sysprof_document_counter_value_get_value_double (SysprofDocumentCounterValue *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
char *sysprof_document_counter_value_format (SysprofDocumentCounterValue *self);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
409
src/libsysprof/sysprof-document-counter.c
Normal file
409
src/libsysprof/sysprof-document-counter.c
Normal file
@ -0,0 +1,409 @@
|
||||
/* sysprof-document-counter.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "sysprof-document-counter-private.h"
|
||||
#include "sysprof-document-counter-value-private.h"
|
||||
#include "sysprof-document-private.h"
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_CATEGORY,
|
||||
PROP_DESCRIPTION,
|
||||
PROP_ID,
|
||||
PROP_KEY,
|
||||
PROP_MAX_VALUE,
|
||||
PROP_MIN_VALUE,
|
||||
PROP_NAME,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static guint
|
||||
sysprof_document_counter_get_n_items (GListModel *model)
|
||||
{
|
||||
return sysprof_document_counter_get_n_values (SYSPROF_DOCUMENT_COUNTER (model));
|
||||
}
|
||||
|
||||
static GType
|
||||
sysprof_document_counter_get_item_type (GListModel *model)
|
||||
{
|
||||
return SYSPROF_TYPE_DOCUMENT_COUNTER_VALUE;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
sysprof_document_counter_get_item (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
SysprofDocumentCounter *self = SYSPROF_DOCUMENT_COUNTER (model);
|
||||
const SysprofDocumentTimedValue *value;
|
||||
|
||||
if (position >= self->values->len)
|
||||
return NULL;
|
||||
|
||||
value = &g_array_index (self->values, SysprofDocumentTimedValue, position);
|
||||
|
||||
return _sysprof_document_counter_value_new (self->type, value, self);
|
||||
}
|
||||
|
||||
static void
|
||||
list_model_iface_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_n_items = sysprof_document_counter_get_n_items;
|
||||
iface->get_item_type = sysprof_document_counter_get_item_type;
|
||||
iface->get_item = sysprof_document_counter_get_item;
|
||||
}
|
||||
|
||||
G_DEFINE_FINAL_TYPE_WITH_CODE (SysprofDocumentCounter, sysprof_document_counter, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_document_counter_finalize (GObject *object)
|
||||
{
|
||||
SysprofDocumentCounter *self = (SysprofDocumentCounter *)object;
|
||||
|
||||
g_clear_pointer (&self->category, g_ref_string_release);
|
||||
g_clear_pointer (&self->description, g_ref_string_release);
|
||||
g_clear_pointer (&self->name, g_ref_string_release);
|
||||
g_clear_pointer (&self->values, g_array_unref);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_document_counter_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_counter_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentCounter *self = SYSPROF_DOCUMENT_COUNTER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CATEGORY:
|
||||
g_value_set_string (value, sysprof_document_counter_get_category (self));
|
||||
break;
|
||||
|
||||
case PROP_DESCRIPTION:
|
||||
g_value_set_string (value, sysprof_document_counter_get_description (self));
|
||||
break;
|
||||
|
||||
case PROP_MIN_VALUE:
|
||||
g_value_set_double (value, self->min_value);
|
||||
break;
|
||||
|
||||
case PROP_MAX_VALUE:
|
||||
g_value_set_double (value, self->max_value);
|
||||
break;
|
||||
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, sysprof_document_counter_get_name (self));
|
||||
break;
|
||||
|
||||
case PROP_KEY:
|
||||
g_value_take_string (value, sysprof_document_counter_dup_key (self));
|
||||
break;
|
||||
|
||||
case PROP_ID:
|
||||
g_value_set_uint (value, sysprof_document_counter_get_id (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_counter_class_init (SysprofDocumentCounterClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_document_counter_finalize;
|
||||
object_class->get_property = sysprof_document_counter_get_property;
|
||||
|
||||
properties [PROP_ID] =
|
||||
g_param_spec_uint ("id", NULL, NULL,
|
||||
0, G_MAXUINT, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_CATEGORY] =
|
||||
g_param_spec_string ("category", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_DESCRIPTION] =
|
||||
g_param_spec_string ("description", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_KEY] =
|
||||
g_param_spec_string ("key", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_NAME] =
|
||||
g_param_spec_string ("name", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties[PROP_MIN_VALUE] =
|
||||
g_param_spec_double ("min-value", NULL, NULL,
|
||||
-G_MAXDOUBLE, G_MAXDOUBLE, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties[PROP_MAX_VALUE] =
|
||||
g_param_spec_double ("max-value", NULL, NULL,
|
||||
-G_MAXDOUBLE, G_MAXDOUBLE, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_counter_init (SysprofDocumentCounter *self)
|
||||
{
|
||||
}
|
||||
|
||||
SysprofDocumentCounter *
|
||||
_sysprof_document_counter_new (guint id,
|
||||
guint type,
|
||||
GRefString *category,
|
||||
GRefString *name,
|
||||
GRefString *description,
|
||||
GArray *values,
|
||||
gint64 begin_time)
|
||||
{
|
||||
SysprofDocumentCounter *self;
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_DOCUMENT_COUNTER, NULL);
|
||||
self->id = id;
|
||||
self->type = type;
|
||||
self->category = category;
|
||||
self->name = name;
|
||||
self->description = description;
|
||||
self->values = values;
|
||||
self->begin_time = begin_time;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_counter_get_category (SysprofDocumentCounter *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER (self), NULL);
|
||||
|
||||
return self->category;
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_counter_get_description (SysprofDocumentCounter *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER (self), NULL);
|
||||
|
||||
return self->description;
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_counter_get_name (SysprofDocumentCounter *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER (self), NULL);
|
||||
|
||||
return self->name;
|
||||
}
|
||||
|
||||
guint
|
||||
sysprof_document_counter_get_id (SysprofDocumentCounter *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER (self), 0);
|
||||
|
||||
return self->id;
|
||||
}
|
||||
|
||||
GType
|
||||
sysprof_document_counter_get_value_type (SysprofDocumentCounter *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER (self), G_TYPE_INVALID);
|
||||
|
||||
if (self->type == SYSPROF_CAPTURE_COUNTER_INT64)
|
||||
return G_TYPE_INT64;
|
||||
|
||||
if (self->type == SYSPROF_CAPTURE_COUNTER_DOUBLE)
|
||||
return G_TYPE_DOUBLE;
|
||||
|
||||
g_return_val_if_reached (G_TYPE_INVALID);
|
||||
}
|
||||
|
||||
guint
|
||||
sysprof_document_counter_get_n_values (SysprofDocumentCounter *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER (self), 0);
|
||||
|
||||
return self->values->len;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_document_counter_get_value (SysprofDocumentCounter *self,
|
||||
guint nth,
|
||||
gint64 *time,
|
||||
GValue *value)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_DOCUMENT_COUNTER (self));
|
||||
g_return_if_fail (nth < self->values->len);
|
||||
g_return_if_fail (value == NULL || G_IS_VALUE (value));
|
||||
|
||||
if (time != NULL)
|
||||
*time = g_array_index (self->values, SysprofDocumentTimedValue, nth).time;
|
||||
|
||||
if (value == NULL)
|
||||
return;
|
||||
|
||||
if (G_VALUE_HOLDS_INT64 (value))
|
||||
g_value_set_int64 (value, g_array_index (self->values, SysprofDocumentTimedValue, nth).v_int64);
|
||||
else if (G_VALUE_HOLDS_DOUBLE (value))
|
||||
g_value_set_double (value, g_array_index (self->values, SysprofDocumentTimedValue, nth).v_double);
|
||||
}
|
||||
|
||||
gint64
|
||||
sysprof_document_counter_get_value_int64 (SysprofDocumentCounter *self,
|
||||
guint nth,
|
||||
gint64 *time)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER (self), 0);
|
||||
g_return_val_if_fail (nth < self->values->len, 0);
|
||||
|
||||
if (time != NULL)
|
||||
*time = g_array_index (self->values, SysprofDocumentTimedValue, nth).time;
|
||||
|
||||
return g_array_index (self->values, SysprofDocumentTimedValue, nth).v_int64;
|
||||
}
|
||||
|
||||
double
|
||||
sysprof_document_counter_get_value_double (SysprofDocumentCounter *self,
|
||||
guint nth,
|
||||
gint64 *time)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER (self), 0);
|
||||
g_return_val_if_fail (nth < self->values->len, 0);
|
||||
|
||||
if (time != NULL)
|
||||
*time = g_array_index (self->values, SysprofDocumentTimedValue, nth).time;
|
||||
|
||||
return g_array_index (self->values, SysprofDocumentTimedValue, nth).v_double;
|
||||
}
|
||||
|
||||
static inline double
|
||||
value_as_double (guint type,
|
||||
const SysprofDocumentTimedValue *value)
|
||||
{
|
||||
if (type == SYSPROF_CAPTURE_COUNTER_DOUBLE)
|
||||
return value->v_double;
|
||||
else if (type == SYSPROF_CAPTURE_COUNTER_INT64)
|
||||
return value->v_int64;
|
||||
else
|
||||
return .0;
|
||||
}
|
||||
|
||||
static int
|
||||
sort_by_time (gconstpointer aptr,
|
||||
gconstpointer bptr)
|
||||
{
|
||||
const SysprofDocumentTimedValue *a = aptr;
|
||||
const SysprofDocumentTimedValue *b = bptr;
|
||||
|
||||
if (a->time < b->time)
|
||||
return -1;
|
||||
|
||||
if (a->time > b->time)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
_sysprof_document_counter_calculate_range (SysprofDocumentCounter *self)
|
||||
{
|
||||
const SysprofDocumentTimedValue *values;
|
||||
gboolean min_value_changed = FALSE;
|
||||
gboolean max_value_changed = FALSE;
|
||||
double min_value;
|
||||
double max_value;
|
||||
guint n_values;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_DOCUMENT_COUNTER (self));
|
||||
|
||||
if (self->values->len == 0)
|
||||
return;
|
||||
|
||||
g_array_sort (self->values, sort_by_time);
|
||||
|
||||
values = &g_array_index (self->values, SysprofDocumentTimedValue, 0);
|
||||
n_values = self->values->len;
|
||||
|
||||
min_value = value_as_double (self->type, &values[0]);
|
||||
max_value = min_value;
|
||||
|
||||
for (guint i = 1; i < n_values; i++)
|
||||
{
|
||||
double value = value_as_double (self->type, &values[i]);
|
||||
|
||||
min_value = MIN (min_value, value);
|
||||
max_value = MAX (max_value, value);
|
||||
}
|
||||
|
||||
min_value_changed = self->min_value != min_value;
|
||||
max_value_changed = self->max_value != max_value;
|
||||
|
||||
self->min_value = min_value;
|
||||
self->max_value = max_value;
|
||||
|
||||
if (min_value_changed)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MIN_VALUE]);
|
||||
|
||||
if (max_value_changed)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MAX_VALUE]);
|
||||
}
|
||||
|
||||
double
|
||||
sysprof_document_counter_get_max_value (SysprofDocumentCounter *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER (self), .0);
|
||||
|
||||
return self->max_value;
|
||||
}
|
||||
|
||||
double
|
||||
sysprof_document_counter_get_min_value (SysprofDocumentCounter *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER (self), .0);
|
||||
|
||||
return self->min_value;
|
||||
}
|
||||
|
||||
char *
|
||||
sysprof_document_counter_dup_key (SysprofDocumentCounter *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_COUNTER (self), NULL);
|
||||
|
||||
return g_strdup_printf ("%s/%s", self->category, self->name);
|
||||
}
|
||||
66
src/libsysprof/sysprof-document-counter.h
Normal file
66
src/libsysprof/sysprof-document-counter.h
Normal file
@ -0,0 +1,66 @@
|
||||
/* sysprof-document-counter.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_COUNTER (sysprof_document_counter_get_type())
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (SysprofDocumentCounter, sysprof_document_counter, SYSPROF, DOCUMENT_COUNTER, GObject)
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
char *sysprof_document_counter_dup_key (SysprofDocumentCounter *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_counter_get_category (SysprofDocumentCounter *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_counter_get_description (SysprofDocumentCounter *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_counter_get_name (SysprofDocumentCounter *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint sysprof_document_counter_get_id (SysprofDocumentCounter *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_counter_get_value_type (SysprofDocumentCounter *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint sysprof_document_counter_get_n_values (SysprofDocumentCounter *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_document_counter_get_value (SysprofDocumentCounter *self,
|
||||
guint nth,
|
||||
gint64 *time,
|
||||
GValue *value);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gint64 sysprof_document_counter_get_value_int64 (SysprofDocumentCounter *self,
|
||||
guint nth,
|
||||
gint64 *time);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
double sysprof_document_counter_get_value_double (SysprofDocumentCounter *self,
|
||||
guint nth,
|
||||
gint64 *time);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
double sysprof_document_counter_get_max_value (SysprofDocumentCounter *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
double sysprof_document_counter_get_min_value (SysprofDocumentCounter *self);
|
||||
|
||||
G_END_DECLS
|
||||
105
src/libsysprof/sysprof-document-ctrdef.c
Normal file
105
src/libsysprof/sysprof-document-ctrdef.c
Normal file
@ -0,0 +1,105 @@
|
||||
/* sysprof-document-ctrdef.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
#include "sysprof-document-ctrdef.h"
|
||||
|
||||
struct _SysprofDocumentCtrdef
|
||||
{
|
||||
SysprofDocumentFrame parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentCtrdefClass
|
||||
{
|
||||
SysprofDocumentFrameClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentCtrdef, sysprof_document_ctrdef, SYSPROF_TYPE_DOCUMENT_FRAME)
|
||||
|
||||
static void
|
||||
sysprof_document_ctrdef_class_init (SysprofDocumentCtrdefClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_ctrdef_init (SysprofDocumentCtrdef *self)
|
||||
{
|
||||
}
|
||||
|
||||
guint
|
||||
sysprof_document_ctrdef_get_n_counters (SysprofDocumentCtrdef *self)
|
||||
{
|
||||
const SysprofCaptureCounterDefine *ctrdef;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_CTRDEF (self), 0);
|
||||
|
||||
ctrdef = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureCounterDefine);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_UINT16 (self, ctrdef->n_counters);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_ctrdef_get_counter:
|
||||
* @self: a #SysprofDocumentCtrdef
|
||||
* @nth: a value between 0 and sysprof_document_ctrdef_get_n_counters()
|
||||
* @id: (out): a location for the id of the counter
|
||||
* @type: (out): a location for either %SYSPROF_CAPTURE_COUNTER_INT64
|
||||
* or %SYSPROF_CAPTURE_COUNTER_DOUBLE
|
||||
* @category: (out): a location for the category
|
||||
* @name: (out): a location for the name
|
||||
* @description: (out): a location for the description
|
||||
*
|
||||
* Gets information about a counter defined in @self.
|
||||
*/
|
||||
void
|
||||
sysprof_document_ctrdef_get_counter (SysprofDocumentCtrdef *self,
|
||||
guint nth,
|
||||
guint *id,
|
||||
guint *type,
|
||||
const char **category,
|
||||
const char **name,
|
||||
const char **description)
|
||||
{
|
||||
const SysprofCaptureCounterDefine *ctrdef;
|
||||
const SysprofCaptureCounter *ctr;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_DOCUMENT_CTRDEF (self));
|
||||
g_return_if_fail (nth < sysprof_document_ctrdef_get_n_counters (self));
|
||||
|
||||
ctrdef = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureCounterDefine);
|
||||
ctr = &ctrdef->counters[nth];
|
||||
|
||||
if (id != NULL)
|
||||
*id = SYSPROF_DOCUMENT_FRAME_UINT32 (self, ctr->id);
|
||||
|
||||
if (type != NULL)
|
||||
*type = ctr->type;
|
||||
|
||||
if (category != NULL)
|
||||
*category = SYSPROF_DOCUMENT_FRAME_CSTRING (self, ctr->category);
|
||||
|
||||
if (name != NULL)
|
||||
*name = SYSPROF_DOCUMENT_FRAME_CSTRING (self, ctr->name);
|
||||
|
||||
if (description != NULL)
|
||||
*description = SYSPROF_DOCUMENT_FRAME_CSTRING (self, ctr->description);
|
||||
}
|
||||
53
src/libsysprof/sysprof-document-ctrdef.h
Normal file
53
src/libsysprof/sysprof-document-ctrdef.h
Normal file
@ -0,0 +1,53 @@
|
||||
/* sysprof-document-ctrdef.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_CTRDEF (sysprof_document_ctrdef_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_CTRDEF(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_CTRDEF)
|
||||
#define SYSPROF_DOCUMENT_CTRDEF(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_CTRDEF, SysprofDocumentCtrdef)
|
||||
#define SYSPROF_DOCUMENT_CTRDEF_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_CTRDEF, SysprofDocumentCtrdefClass)
|
||||
|
||||
typedef struct _SysprofDocumentCtrdef SysprofDocumentCtrdef;
|
||||
typedef struct _SysprofDocumentCtrdefClass SysprofDocumentCtrdefClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_ctrdef_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint sysprof_document_ctrdef_get_n_counters (SysprofDocumentCtrdef *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_document_ctrdef_get_counter (SysprofDocumentCtrdef *self,
|
||||
guint nth,
|
||||
guint *id,
|
||||
guint *type,
|
||||
const char **category,
|
||||
const char **name,
|
||||
const char **description);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentCtrdef, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
116
src/libsysprof/sysprof-document-ctrset.c
Normal file
116
src/libsysprof/sysprof-document-ctrset.c
Normal file
@ -0,0 +1,116 @@
|
||||
/* sysprof-document-ctrset.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
#include "sysprof-document-ctrset.h"
|
||||
|
||||
struct _SysprofDocumentCtrset
|
||||
{
|
||||
SysprofDocumentFrame parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentCtrsetClass
|
||||
{
|
||||
SysprofDocumentFrameClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentCtrset, sysprof_document_ctrset, SYSPROF_TYPE_DOCUMENT_FRAME)
|
||||
|
||||
static void
|
||||
sysprof_document_ctrset_class_init (SysprofDocumentCtrsetClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_ctrset_init (SysprofDocumentCtrset *self)
|
||||
{
|
||||
}
|
||||
|
||||
guint
|
||||
sysprof_document_ctrset_get_n_values (SysprofDocumentCtrset *self)
|
||||
{
|
||||
const SysprofCaptureCounterSet *ctrset;
|
||||
gconstpointer endptr;
|
||||
guint n_groups;
|
||||
guint n_values = 0;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_CTRSET (self), 0);
|
||||
|
||||
endptr = SYSPROF_DOCUMENT_FRAME_ENDPTR (self);
|
||||
ctrset = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureCounterSet);
|
||||
|
||||
n_groups = SYSPROF_DOCUMENT_FRAME_UINT16 (self, ctrset->n_values);
|
||||
|
||||
for (guint i = 0; i < n_groups; i++)
|
||||
{
|
||||
const SysprofCaptureCounterValues *values = &ctrset->values[i];
|
||||
|
||||
/* Don't allow overflowing the frame zone */
|
||||
if ((gconstpointer)&values[1] > endptr)
|
||||
break;
|
||||
|
||||
for (guint j = 0; j < G_N_ELEMENTS (values->ids); j++)
|
||||
{
|
||||
if (values->ids[j] == 0)
|
||||
break;
|
||||
n_values++;
|
||||
}
|
||||
}
|
||||
|
||||
return n_values;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_ctrset_get_raw_value: (skip)
|
||||
* @self: a #SysprofDocumentCtrset
|
||||
* @nth: the nth value to get
|
||||
* @id: (out): a location for the counter id
|
||||
* @value: a location to store the raw value
|
||||
*
|
||||
* The raw value is 8 bytes and may not be converted to local
|
||||
* byte ordering.
|
||||
*
|
||||
* @nth must be less-than sysprof_document_ctrset_get_n_values().
|
||||
*/
|
||||
void
|
||||
sysprof_document_ctrset_get_raw_value (SysprofDocumentCtrset *self,
|
||||
guint nth,
|
||||
guint *id,
|
||||
guint8 value[restrict 8])
|
||||
{
|
||||
const SysprofCaptureCounterSet *ctrset;
|
||||
guint group;
|
||||
guint pos;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_DOCUMENT_CTRSET (self));
|
||||
g_return_if_fail (nth < sysprof_document_ctrset_get_n_values (self));
|
||||
g_return_if_fail (value != NULL);
|
||||
|
||||
group = nth / 8;
|
||||
pos = nth % 8;
|
||||
|
||||
ctrset = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureCounterSet);
|
||||
|
||||
*id = SYSPROF_DOCUMENT_FRAME_UINT32 (self, ctrset->values[group].ids[pos]);
|
||||
|
||||
memcpy (value, &ctrset->values[group].values[pos], 8);
|
||||
}
|
||||
50
src/libsysprof/sysprof-document-ctrset.h
Normal file
50
src/libsysprof/sysprof-document-ctrset.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* sysprof-document-ctrset.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_CTRSET (sysprof_document_ctrset_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_CTRSET(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_CTRSET)
|
||||
#define SYSPROF_DOCUMENT_CTRSET(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_CTRSET, SysprofDocumentCtrset)
|
||||
#define SYSPROF_DOCUMENT_CTRSET_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_CTRSET, SysprofDocumentCtrsetClass)
|
||||
|
||||
typedef struct _SysprofDocumentCtrset SysprofDocumentCtrset;
|
||||
typedef struct _SysprofDocumentCtrsetClass SysprofDocumentCtrsetClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_ctrset_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint sysprof_document_ctrset_get_n_values (SysprofDocumentCtrset *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_document_ctrset_get_raw_value (SysprofDocumentCtrset *self,
|
||||
guint nth,
|
||||
guint *id,
|
||||
guint8 value[restrict 8]);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentCtrset, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
46
src/libsysprof/sysprof-document-exit.c
Normal file
46
src/libsysprof/sysprof-document-exit.c
Normal file
@ -0,0 +1,46 @@
|
||||
/* sysprof-document-exit.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
#include "sysprof-document-exit.h"
|
||||
|
||||
struct _SysprofDocumentExit
|
||||
{
|
||||
SysprofDocumentFrame parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentExitClass
|
||||
{
|
||||
SysprofDocumentFrameClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentExit, sysprof_document_exit, SYSPROF_TYPE_DOCUMENT_FRAME)
|
||||
|
||||
static void
|
||||
sysprof_document_exit_class_init (SysprofDocumentExitClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_exit_init (SysprofDocumentExit *self)
|
||||
{
|
||||
}
|
||||
41
src/libsysprof/sysprof-document-exit.h
Normal file
41
src/libsysprof/sysprof-document-exit.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* sysprof-document-exit.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_EXIT (sysprof_document_exit_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_EXIT(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_EXIT)
|
||||
#define SYSPROF_DOCUMENT_EXIT(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_EXIT, SysprofDocumentExit)
|
||||
#define SYSPROF_DOCUMENT_EXIT_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_EXIT, SysprofDocumentExitClass)
|
||||
|
||||
typedef struct _SysprofDocumentExit SysprofDocumentExit;
|
||||
typedef struct _SysprofDocumentExitClass SysprofDocumentExitClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_exit_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentExit, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
156
src/libsysprof/sysprof-document-file-chunk.c
Normal file
156
src/libsysprof/sysprof-document-file-chunk.c
Normal file
@ -0,0 +1,156 @@
|
||||
/* sysprof-document-file-chunk.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
|
||||
#include "sysprof-document-file-chunk.h"
|
||||
|
||||
struct _SysprofDocumentFileChunk
|
||||
{
|
||||
SysprofDocumentFrame parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentFileChunkClass
|
||||
{
|
||||
SysprofDocumentFrameClass parent_instance;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_IS_LAST,
|
||||
PROP_SIZE,
|
||||
PROP_PATH,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentFileChunk, sysprof_document_file_chunk, SYSPROF_TYPE_DOCUMENT_FRAME)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_document_file_chunk_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentFileChunk *self = SYSPROF_DOCUMENT_FILE_CHUNK (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_IS_LAST:
|
||||
g_value_set_boolean (value, sysprof_document_file_chunk_get_is_last (self));
|
||||
break;
|
||||
|
||||
case PROP_SIZE:
|
||||
g_value_set_uint (value, sysprof_document_file_chunk_get_size (self));
|
||||
break;
|
||||
|
||||
case PROP_PATH:
|
||||
g_value_set_string (value, sysprof_document_file_chunk_get_path (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_file_chunk_class_init (SysprofDocumentFileChunkClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->get_property = sysprof_document_file_chunk_get_property;
|
||||
|
||||
properties [PROP_IS_LAST] =
|
||||
g_param_spec_boolean ("is-last", NULL, NULL,
|
||||
FALSE,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_SIZE] =
|
||||
g_param_spec_uint ("size", NULL, NULL,
|
||||
0, G_MAXUINT16, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_PATH] =
|
||||
g_param_spec_string ("path", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_file_chunk_init (SysprofDocumentFileChunk *self)
|
||||
{
|
||||
}
|
||||
|
||||
gboolean
|
||||
sysprof_document_file_chunk_get_is_last (SysprofDocumentFileChunk *self)
|
||||
{
|
||||
const SysprofCaptureFileChunk *file_chunk;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FILE_CHUNK (self), FALSE);
|
||||
|
||||
file_chunk = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureFileChunk);
|
||||
|
||||
return file_chunk->is_last;
|
||||
}
|
||||
|
||||
guint
|
||||
sysprof_document_file_chunk_get_size (SysprofDocumentFileChunk *self)
|
||||
{
|
||||
const SysprofCaptureFileChunk *file_chunk;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FILE_CHUNK (self), FALSE);
|
||||
|
||||
file_chunk = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureFileChunk);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_UINT16 (self, file_chunk->len);
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_file_chunk_get_path (SysprofDocumentFileChunk *self)
|
||||
{
|
||||
const SysprofCaptureFileChunk *file_chunk;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FILE_CHUNK (self), FALSE);
|
||||
|
||||
file_chunk = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureFileChunk);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_CSTRING (self, file_chunk->path);
|
||||
}
|
||||
|
||||
const guint8 *
|
||||
sysprof_document_file_chunk_get_data (SysprofDocumentFileChunk *self,
|
||||
guint *size)
|
||||
{
|
||||
const SysprofCaptureFileChunk *file_chunk;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FILE_CHUNK (self), FALSE);
|
||||
|
||||
file_chunk = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureFileChunk);
|
||||
|
||||
if (size != NULL)
|
||||
*size = sysprof_document_file_chunk_get_size (self);
|
||||
|
||||
return file_chunk->data;
|
||||
}
|
||||
49
src/libsysprof/sysprof-document-file-chunk.h
Normal file
49
src/libsysprof/sysprof-document-file-chunk.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* sysprof-document-file-chunk.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_FILE_CHUNK (sysprof_document_file_chunk_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_FILE_CHUNK(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_FILE_CHUNK)
|
||||
#define SYSPROF_DOCUMENT_FILE_CHUNK(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_FILE_CHUNK, SysprofDocumentFileChunk)
|
||||
#define SYSPROF_DOCUMENT_FILE_CHUNK_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_FILE_CHUNK, SysprofDocumentFileChunkClass)
|
||||
|
||||
typedef struct _SysprofDocumentFileChunk SysprofDocumentFileChunk;
|
||||
typedef struct _SysprofDocumentFileChunkClass SysprofDocumentFileChunkClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_file_chunk_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_document_file_chunk_get_is_last (SysprofDocumentFileChunk *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint sysprof_document_file_chunk_get_size (SysprofDocumentFileChunk *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_file_chunk_get_path (SysprofDocumentFileChunk *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const guint8 *sysprof_document_file_chunk_get_data (SysprofDocumentFileChunk *self,
|
||||
guint *size);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentFileChunk, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
31
src/libsysprof/sysprof-document-file-private.h
Normal file
31
src/libsysprof/sysprof-document-file-private.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* sysprof-document-file-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-file.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
SysprofDocumentFile *_sysprof_document_file_new (const char *path,
|
||||
GPtrArray *file_chunks,
|
||||
gboolean compressed);
|
||||
|
||||
G_END_DECLS
|
||||
279
src/libsysprof/sysprof-document-file.c
Normal file
279
src/libsysprof/sysprof-document-file.c
Normal file
@ -0,0 +1,279 @@
|
||||
/* sysprof-document-file.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-document-file-chunk.h"
|
||||
#include "sysprof-document-file-private.h"
|
||||
#include "sysprof-document-frame-private.h"
|
||||
|
||||
struct _SysprofDocumentFile
|
||||
{
|
||||
GObject parent_instance;
|
||||
char *path;
|
||||
GPtrArray *file_chunks;
|
||||
guint compressed : 1;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_BYTES,
|
||||
PROP_IS_COMPRESSED,
|
||||
PROP_PATH,
|
||||
PROP_SIZE,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentFile, sysprof_document_file, G_TYPE_OBJECT)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_document_file_finalize (GObject *object)
|
||||
{
|
||||
SysprofDocumentFile *self = (SysprofDocumentFile *)object;
|
||||
|
||||
g_clear_pointer (&self->path, g_free);
|
||||
g_clear_pointer (&self->file_chunks, g_ptr_array_unref);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_document_file_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_file_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentFile *self = SYSPROF_DOCUMENT_FILE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PATH:
|
||||
g_value_set_string (value, sysprof_document_file_get_path (self));
|
||||
break;
|
||||
|
||||
case PROP_BYTES:
|
||||
g_value_take_boxed (value, sysprof_document_file_dup_bytes (self));
|
||||
break;
|
||||
|
||||
case PROP_IS_COMPRESSED:
|
||||
g_value_set_boolean (value, sysprof_document_file_is_compressed (self));
|
||||
break;
|
||||
|
||||
case PROP_SIZE:
|
||||
g_value_set_uint64 (value, sysprof_document_file_get_size (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_file_class_init (SysprofDocumentFileClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_document_file_finalize;
|
||||
object_class->get_property = sysprof_document_file_get_property;
|
||||
|
||||
properties [PROP_PATH] =
|
||||
g_param_spec_string ("path", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_BYTES] =
|
||||
g_param_spec_boxed ("bytes", NULL, NULL,
|
||||
G_TYPE_BYTES,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_IS_COMPRESSED] =
|
||||
g_param_spec_boolean ("is-compressed", NULL, NULL,
|
||||
FALSE,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_SIZE] =
|
||||
g_param_spec_uint64 ("size", NULL, NULL,
|
||||
0, G_MAXUINT64, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_file_init (SysprofDocumentFile *self)
|
||||
{
|
||||
}
|
||||
|
||||
SysprofDocumentFile *
|
||||
_sysprof_document_file_new (const char *path,
|
||||
GPtrArray *file_chunks,
|
||||
gboolean compressed)
|
||||
{
|
||||
SysprofDocumentFile *self;
|
||||
|
||||
g_return_val_if_fail (path != NULL, NULL);
|
||||
g_return_val_if_fail (file_chunks != NULL, NULL);
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_DOCUMENT_FILE, NULL);
|
||||
self->path = g_strdup (path);
|
||||
self->file_chunks = file_chunks;
|
||||
self->compressed = !!compressed;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_file_get_path (SysprofDocumentFile *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FILE (self), NULL);
|
||||
|
||||
return self->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_file_dup_contents:
|
||||
* @self: a #SysprofDocumentFile
|
||||
*
|
||||
* Creates a new #GBytes containing the contents of the file.
|
||||
*
|
||||
* Returns: (transfer full): a #GBytes
|
||||
*/
|
||||
GBytes *
|
||||
sysprof_document_file_dup_bytes (SysprofDocumentFile *self)
|
||||
{
|
||||
GArray *ar;
|
||||
guint len;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FILE (self), NULL);
|
||||
|
||||
ar = g_array_new (TRUE, FALSE, sizeof (char));
|
||||
|
||||
for (guint i = 0; i < self->file_chunks->len; i++)
|
||||
{
|
||||
SysprofDocumentFileChunk *file_chunk = g_ptr_array_index (self->file_chunks, i);
|
||||
const guint8 *data = sysprof_document_file_chunk_get_data (file_chunk, &len);
|
||||
|
||||
g_array_append_vals (ar, data, len);
|
||||
}
|
||||
|
||||
len = ar->len;
|
||||
|
||||
if (self->compressed)
|
||||
{
|
||||
guint8 *data = (guint8 *)g_array_free (ar, FALSE);
|
||||
g_autoptr(GInputStream) input = g_memory_input_stream_new_from_data (data, len, g_free);
|
||||
g_autoptr(GOutputStream) memory_output = g_memory_output_stream_new_resizable ();
|
||||
g_autoptr(GZlibDecompressor) zlib = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
|
||||
g_autoptr(GOutputStream) zlib_output = g_converter_output_stream_new (memory_output, G_CONVERTER (zlib));
|
||||
|
||||
g_output_stream_splice (zlib_output,
|
||||
input,
|
||||
(G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
|
||||
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET),
|
||||
NULL, NULL);
|
||||
|
||||
return g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (memory_output));
|
||||
}
|
||||
|
||||
return g_bytes_new_take (g_array_free (ar, FALSE), len);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_file_read:
|
||||
* @self: a #SysprofDocumentFile
|
||||
*
|
||||
* Creates a new input stream containing the contents of the file
|
||||
* within the document.
|
||||
*
|
||||
* Returns: (transfer full): a #GInputstream
|
||||
*/
|
||||
GInputStream *
|
||||
sysprof_document_file_read (SysprofDocumentFile *self)
|
||||
{
|
||||
g_autoptr(GInputStream) input = NULL;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FILE (self), NULL);
|
||||
|
||||
input = g_memory_input_stream_new ();
|
||||
|
||||
for (guint i = 0; i < self->file_chunks->len; i++)
|
||||
{
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
SysprofDocumentFileChunk *file_chunk;
|
||||
const guint8 *data;
|
||||
guint len;
|
||||
|
||||
file_chunk = g_ptr_array_index (self->file_chunks, i);
|
||||
data = sysprof_document_file_chunk_get_data (file_chunk, &len);
|
||||
|
||||
bytes = g_bytes_new_with_free_func (data,
|
||||
len,
|
||||
(GDestroyNotify)g_mapped_file_unref,
|
||||
g_mapped_file_ref (SYSPROF_DOCUMENT_FRAME (file_chunk)->mapped_file));
|
||||
|
||||
g_memory_input_stream_add_bytes (G_MEMORY_INPUT_STREAM (input), bytes);
|
||||
}
|
||||
|
||||
if (self->compressed)
|
||||
{
|
||||
g_autoptr(GZlibDecompressor) zlib = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
|
||||
|
||||
return g_converter_input_stream_new (input, G_CONVERTER (zlib));
|
||||
}
|
||||
|
||||
return g_steal_pointer (&input);
|
||||
}
|
||||
|
||||
gsize
|
||||
sysprof_document_file_get_size (SysprofDocumentFile *self)
|
||||
{
|
||||
gsize size = 0;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FILE (self), 0);
|
||||
|
||||
for (guint i = 0; i < self->file_chunks->len; i++)
|
||||
{
|
||||
SysprofDocumentFileChunk *file_chunk = g_ptr_array_index (self->file_chunks, i);
|
||||
|
||||
size += sysprof_document_file_chunk_get_size (file_chunk);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_file_is_compressed:
|
||||
* @self: a #SysprofDocumentFile
|
||||
*
|
||||
* Checks if the embedded file is compressed. If so, %TRUE is returned.
|
||||
*
|
||||
* Note that files are transparently decompressed when opening streams.
|
||||
*
|
||||
* Returns: %TRUE if the embedded file was compressed
|
||||
*/
|
||||
gboolean
|
||||
sysprof_document_file_is_compressed (SysprofDocumentFile *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FILE (self), FALSE);
|
||||
|
||||
return self->compressed;
|
||||
}
|
||||
45
src/libsysprof/sysprof-document-file.h
Normal file
45
src/libsysprof/sysprof-document-file.h
Normal file
@ -0,0 +1,45 @@
|
||||
/* sysprof-document-file.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_FILE (sysprof_document_file_get_type())
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (SysprofDocumentFile, sysprof_document_file, SYSPROF, DOCUMENT_FILE, GObject)
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_file_get_path (SysprofDocumentFile *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GBytes *sysprof_document_file_dup_bytes (SysprofDocumentFile *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GInputStream *sysprof_document_file_read (SysprofDocumentFile *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gsize sysprof_document_file_get_size (SysprofDocumentFile *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_document_file_is_compressed (SysprofDocumentFile *self);
|
||||
|
||||
G_END_DECLS
|
||||
95
src/libsysprof/sysprof-document-fork.c
Normal file
95
src/libsysprof/sysprof-document-fork.c
Normal file
@ -0,0 +1,95 @@
|
||||
/* sysprof-document-fork.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
#include "sysprof-document-fork.h"
|
||||
|
||||
struct _SysprofDocumentFork
|
||||
{
|
||||
SysprofDocumentFrame parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentForkClass
|
||||
{
|
||||
SysprofDocumentFrameClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_CHILD_PID,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentFork, sysprof_document_fork, SYSPROF_TYPE_DOCUMENT_FRAME)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_document_fork_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentFork *self = SYSPROF_DOCUMENT_FORK (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CHILD_PID:
|
||||
g_value_set_int (value, sysprof_document_fork_get_child_pid (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_fork_class_init (SysprofDocumentForkClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->get_property = sysprof_document_fork_get_property;
|
||||
|
||||
properties [PROP_CHILD_PID] =
|
||||
g_param_spec_int ("child-pid", NULL, NULL,
|
||||
G_MININT, G_MAXINT, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_fork_init (SysprofDocumentFork *self)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
sysprof_document_fork_get_child_pid (SysprofDocumentFork *self)
|
||||
{
|
||||
const SysprofCaptureFork *fork;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FORK (self), 0);
|
||||
|
||||
fork = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureFork);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_INT32 (self, fork->child_pid);
|
||||
}
|
||||
43
src/libsysprof/sysprof-document-fork.h
Normal file
43
src/libsysprof/sysprof-document-fork.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* sysprof-document-fork.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_FORK (sysprof_document_fork_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_FORK(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_FORK)
|
||||
#define SYSPROF_DOCUMENT_FORK(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_FORK, SysprofDocumentFork)
|
||||
#define SYSPROF_DOCUMENT_FORK_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_FORK, SysprofDocumentForkClass)
|
||||
|
||||
typedef struct _SysprofDocumentFork SysprofDocumentFork;
|
||||
typedef struct _SysprofDocumentForkClass SysprofDocumentForkClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_fork_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
int sysprof_document_fork_get_child_pid (SysprofDocumentFork *self);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentFork, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
112
src/libsysprof/sysprof-document-frame-private.h
Normal file
112
src/libsysprof/sysprof-document-frame-private.h
Normal file
@ -0,0 +1,112 @@
|
||||
/* sysprof-document-frame-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
struct _SysprofDocumentFrame
|
||||
{
|
||||
GObject parent;
|
||||
GMappedFile *mapped_file;
|
||||
const SysprofCaptureFrame *frame;
|
||||
gint64 time_offset;
|
||||
guint32 frame_len : 16;
|
||||
guint32 needs_swap : 1;
|
||||
guint32 padding : 15;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentFrameClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
const char *type_name;
|
||||
char *(*dup_tooltip) (SysprofDocumentFrame *self);
|
||||
};
|
||||
|
||||
SysprofDocumentFrame *_sysprof_document_frame_new (GMappedFile *mapped,
|
||||
const SysprofCaptureFrame *frame,
|
||||
guint16 frame_len,
|
||||
gboolean needs_swap,
|
||||
gint64 begin_time,
|
||||
gint64 end_time);
|
||||
|
||||
#define SYSPROF_DOCUMENT_FRAME_GET_CLASS(obj) \
|
||||
G_TYPE_INSTANCE_GET_CLASS(obj, SYSPROF_TYPE_DOCUMENT_FRAME, SysprofDocumentFrameClass)
|
||||
|
||||
#define SYSPROF_DOCUMENT_FRAME_ENDPTR(obj) \
|
||||
(&((const guint8 *)SYSPROF_DOCUMENT_FRAME(obj)->frame)[SYSPROF_DOCUMENT_FRAME(obj)->frame_len])
|
||||
|
||||
#define SYSPROF_DOCUMENT_FRAME_GET(obj, type) \
|
||||
((const type *)(SYSPROF_DOCUMENT_FRAME(obj)->frame))
|
||||
|
||||
#define SYSPROF_DOCUMENT_FRAME_NEEDS_SWAP(obj) \
|
||||
(SYSPROF_DOCUMENT_FRAME (obj)->needs_swap)
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
# define SYSPROF_DOCUMENT_FRAME_UINT16(obj, val) \
|
||||
(SYSPROF_DOCUMENT_FRAME_NEEDS_SWAP(obj) ? GUINT16_TO_LE(val) : (val))
|
||||
# define SYSPROF_DOCUMENT_FRAME_INT16(obj, val) \
|
||||
(SYSPROF_DOCUMENT_FRAME_NEEDS_SWAP(obj) ? GINT16_TO_LE(val) : (val))
|
||||
# define SYSPROF_DOCUMENT_FRAME_UINT32(obj, val) \
|
||||
(SYSPROF_DOCUMENT_FRAME_NEEDS_SWAP(obj) ? GUINT32_TO_LE(val) : (val))
|
||||
# define SYSPROF_DOCUMENT_FRAME_INT32(obj, val) \
|
||||
(SYSPROF_DOCUMENT_FRAME_NEEDS_SWAP(obj) ? GINT32_TO_LE(val) : (val))
|
||||
# define SYSPROF_DOCUMENT_FRAME_UINT64(obj, val) \
|
||||
(SYSPROF_DOCUMENT_FRAME_NEEDS_SWAP(obj) ? GUINT64_TO_LE(val) : (val))
|
||||
# define SYSPROF_DOCUMENT_FRAME_INT64(obj, val) \
|
||||
(SYSPROF_DOCUMENT_FRAME_NEEDS_SWAP(obj) ? GINT64_TO_LE(val) : (val))
|
||||
#else
|
||||
# define SYSPROF_DOCUMENT_FRAME_UINT16(obj, val) \
|
||||
(SYSPROF_DOCUMENT_FRAME_NEEDS_SWAP(obj) ? GUINT16_TO_BE(val) : (val))
|
||||
# define SYSPROF_DOCUMENT_FRAME_INT16(obj, val) \
|
||||
(SYSPROF_DOCUMENT_FRAME_NEEDS_SWAP(obj) ? GINT16_TO_BE(val) : (val))
|
||||
# define SYSPROF_DOCUMENT_FRAME_UINT32(obj, val) \
|
||||
(SYSPROF_DOCUMENT_FRAME_NEEDS_SWAP(obj) ? GUINT32_TO_BE(val) : (val))
|
||||
# define SYSPROF_DOCUMENT_FRAME_INT32(obj, val) \
|
||||
(SYSPROF_DOCUMENT_FRAME_NEEDS_SWAP(obj) ? GINT32_TO_BE(val) : (val))
|
||||
# define SYSPROF_DOCUMENT_FRAME_UINT64(obj, val) \
|
||||
(SYSPROF_DOCUMENT_FRAME_NEEDS_SWAP(obj) ? GUINT64_TO_BE(val) : (val))
|
||||
# define SYSPROF_DOCUMENT_FRAME_INT64(obj, val) \
|
||||
(SYSPROF_DOCUMENT_FRAME_NEEDS_SWAP(obj) ? GINT64_TO_BE(val) : (val))
|
||||
#endif
|
||||
|
||||
static inline const char *
|
||||
_SYSPROF_DOCUMENT_FRAME_CSTRING (SysprofDocumentFrame *self,
|
||||
const char *str)
|
||||
{
|
||||
const char *endptr = (const char *)self->frame + self->frame_len;
|
||||
|
||||
for (const char *c = str; c < endptr; c++)
|
||||
{
|
||||
if (*c == 0)
|
||||
return str;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define SYSPROF_DOCUMENT_FRAME_CSTRING(obj,str) \
|
||||
_SYSPROF_DOCUMENT_FRAME_CSTRING(SYSPROF_DOCUMENT_FRAME(obj),str)
|
||||
|
||||
G_END_DECLS
|
||||
363
src/libsysprof/sysprof-document-frame.c
Normal file
363
src/libsysprof/sysprof-document-frame.c
Normal file
@ -0,0 +1,363 @@
|
||||
/* sysprof-document-frame.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
|
||||
#include "sysprof-document-allocation.h"
|
||||
#include "sysprof-document-ctrdef.h"
|
||||
#include "sysprof-document-ctrset.h"
|
||||
#include "sysprof-document-exit.h"
|
||||
#include "sysprof-document-file-chunk.h"
|
||||
#include "sysprof-document-fork.h"
|
||||
#include "sysprof-document-log.h"
|
||||
#include "sysprof-document-jitmap.h"
|
||||
#include "sysprof-document-mark.h"
|
||||
#include "sysprof-document-metadata.h"
|
||||
#include "sysprof-document-mmap.h"
|
||||
#include "sysprof-document-overlay.h"
|
||||
#include "sysprof-document-process.h"
|
||||
#include "sysprof-document-sample.h"
|
||||
|
||||
G_DEFINE_TYPE (SysprofDocumentFrame, sysprof_document_frame, G_TYPE_OBJECT)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_CPU,
|
||||
PROP_PID,
|
||||
PROP_TIME,
|
||||
PROP_TIME_OFFSET,
|
||||
PROP_TIME_STRING,
|
||||
PROP_TOOLTIP,
|
||||
PROP_TYPE_NAME,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS];
|
||||
|
||||
static char *
|
||||
sysprof_document_frame_real_dup_tooltip (SysprofDocumentFrame *self)
|
||||
{
|
||||
g_autofree char *time_string = sysprof_document_frame_dup_time_string (self);
|
||||
|
||||
return g_strdup_printf ("%s: %s",
|
||||
time_string,
|
||||
SYSPROF_DOCUMENT_FRAME_GET_CLASS (self)->type_name);
|
||||
}
|
||||
|
||||
static const char *
|
||||
sysprof_document_frame_get_type_name (SysprofDocumentFrame *self)
|
||||
{
|
||||
return g_dgettext (GETTEXT_PACKAGE, SYSPROF_DOCUMENT_FRAME_GET_CLASS (self)->type_name);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_frame_finalize (GObject *object)
|
||||
{
|
||||
SysprofDocumentFrame *self = (SysprofDocumentFrame *)object;
|
||||
|
||||
g_clear_pointer (&self->mapped_file, g_mapped_file_unref);
|
||||
|
||||
self->frame = NULL;
|
||||
self->needs_swap = 0;
|
||||
|
||||
G_OBJECT_CLASS (sysprof_document_frame_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_frame_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentFrame *self = SYSPROF_DOCUMENT_FRAME (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CPU:
|
||||
g_value_set_int (value, sysprof_document_frame_get_cpu (self));
|
||||
break;
|
||||
|
||||
case PROP_PID:
|
||||
g_value_set_int (value, sysprof_document_frame_get_pid (self));
|
||||
break;
|
||||
|
||||
case PROP_TIME:
|
||||
g_value_set_int64 (value, sysprof_document_frame_get_time (self));
|
||||
break;
|
||||
|
||||
case PROP_TIME_OFFSET:
|
||||
g_value_set_int64 (value, sysprof_document_frame_get_time_offset (self));
|
||||
break;
|
||||
|
||||
case PROP_TIME_STRING:
|
||||
g_value_take_string (value, sysprof_document_frame_dup_time_string (self));
|
||||
break;
|
||||
|
||||
case PROP_TOOLTIP:
|
||||
g_value_take_string (value, sysprof_document_frame_dup_tooltip (self));
|
||||
break;
|
||||
|
||||
case PROP_TYPE_NAME:
|
||||
g_value_set_static_string (value, sysprof_document_frame_get_type_name (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_frame_class_init (SysprofDocumentFrameClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_document_frame_finalize;
|
||||
object_class->get_property = sysprof_document_frame_get_property;
|
||||
|
||||
klass->type_name = N_("Frame");
|
||||
klass->dup_tooltip = sysprof_document_frame_real_dup_tooltip;
|
||||
|
||||
properties[PROP_CPU] =
|
||||
g_param_spec_int ("cpu", NULL, NULL,
|
||||
G_MININT32,
|
||||
G_MAXINT32,
|
||||
-1,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties[PROP_PID] =
|
||||
g_param_spec_int ("pid", NULL, NULL,
|
||||
G_MININT32,
|
||||
G_MAXINT32,
|
||||
-1,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties[PROP_TIME] =
|
||||
g_param_spec_int64 ("time", NULL, NULL,
|
||||
G_MININT64,
|
||||
G_MAXINT64,
|
||||
0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties[PROP_TIME_OFFSET] =
|
||||
g_param_spec_int64 ("time-offset", NULL, NULL,
|
||||
G_MININT64,
|
||||
G_MAXINT64,
|
||||
0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties[PROP_TIME_STRING] =
|
||||
g_param_spec_string ("time-string", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties[PROP_TYPE_NAME] =
|
||||
g_param_spec_string ("type-name", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties[PROP_TOOLTIP] =
|
||||
g_param_spec_string ("tooltip", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_frame_init (SysprofDocumentFrame *self)
|
||||
{
|
||||
}
|
||||
|
||||
SysprofDocumentFrame *
|
||||
_sysprof_document_frame_new (GMappedFile *mapped_file,
|
||||
const SysprofCaptureFrame *frame,
|
||||
guint16 frame_len,
|
||||
gboolean needs_swap,
|
||||
gint64 begin_time,
|
||||
gint64 end_time)
|
||||
{
|
||||
SysprofDocumentFrame *self;
|
||||
GType gtype;
|
||||
|
||||
switch (frame->type)
|
||||
{
|
||||
case SYSPROF_CAPTURE_FRAME_SAMPLE:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_SAMPLE;
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_MAP:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_MMAP;
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_LOG:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_LOG;
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_MARK:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_MARK;
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_METADATA:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_METADATA;
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_PROCESS:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_PROCESS;
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_EXIT:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_EXIT;
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_FORK:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_FORK;
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_ALLOCATION:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_ALLOCATION;
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_FILE_CHUNK:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_FILE_CHUNK;
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_OVERLAY:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_OVERLAY;
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_JITMAP:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_JITMAP;
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_CTRDEF:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_CTRDEF;
|
||||
break;
|
||||
|
||||
case SYSPROF_CAPTURE_FRAME_CTRSET:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_CTRSET;
|
||||
break;
|
||||
|
||||
default:
|
||||
gtype = SYSPROF_TYPE_DOCUMENT_FRAME;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
self = g_object_new (gtype, NULL);
|
||||
self->mapped_file = g_mapped_file_ref (mapped_file);
|
||||
self->frame = frame;
|
||||
self->frame_len = frame_len;
|
||||
self->needs_swap = !!needs_swap;
|
||||
|
||||
self->time_offset = CLAMP (sysprof_document_frame_get_time (self) - begin_time, 0, G_MAXINT64);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
int
|
||||
sysprof_document_frame_get_cpu (SysprofDocumentFrame *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FRAME (self), 0);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_INT32 (self, self->frame->cpu);
|
||||
}
|
||||
|
||||
int
|
||||
sysprof_document_frame_get_pid (SysprofDocumentFrame *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FRAME (self), 0);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_INT32 (self, self->frame->pid);
|
||||
}
|
||||
|
||||
gint64
|
||||
sysprof_document_frame_get_time (SysprofDocumentFrame *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FRAME (self), 0);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_INT64 (self, self->frame->time);
|
||||
}
|
||||
|
||||
gint64
|
||||
sysprof_document_frame_get_time_offset (SysprofDocumentFrame *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FRAME (self), 0);
|
||||
|
||||
return self->time_offset;
|
||||
}
|
||||
|
||||
gboolean
|
||||
sysprof_document_frame_equal (const SysprofDocumentFrame *a,
|
||||
const SysprofDocumentFrame *b)
|
||||
{
|
||||
return a->frame == b->frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_frame_dup_time_string:
|
||||
* @self: a #SysprofDocumentFrame
|
||||
*
|
||||
* Gets the time formatted as a string such as `00:00:00.1234`.
|
||||
*
|
||||
* Returns: (transfer full): a new string
|
||||
*/
|
||||
char *
|
||||
sysprof_document_frame_dup_time_string (SysprofDocumentFrame *self)
|
||||
{
|
||||
int hours;
|
||||
int minutes;
|
||||
int seconds;
|
||||
double time;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FRAME (self), NULL);
|
||||
|
||||
time = self->time_offset / (double)SYSPROF_NSEC_PER_SEC;
|
||||
|
||||
hours = time / (60 * 60);
|
||||
time -= hours * (60 * 60);
|
||||
|
||||
minutes = time / 60;
|
||||
time -= minutes * 60;
|
||||
|
||||
seconds = time / SYSPROF_NSEC_PER_SEC;
|
||||
time -= seconds * SYSPROF_NSEC_PER_SEC;
|
||||
|
||||
return g_strdup_printf ("%02d:%02d:%02d.%04d", hours, minutes, seconds, (int)(time * 10000));
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_frame_dup_tooltip:
|
||||
* @self: a #SysprofDocumentFrame
|
||||
*
|
||||
* Returns a new string containing suggested tooltip text.
|
||||
*
|
||||
* Returns: (transfer full): a string
|
||||
*/
|
||||
char *
|
||||
sysprof_document_frame_dup_tooltip (SysprofDocumentFrame *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FRAME (self), NULL);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_GET_CLASS (self)->dup_tooltip (self);
|
||||
}
|
||||
57
src/libsysprof/sysprof-document-frame.h
Normal file
57
src/libsysprof/sysprof-document-frame.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* sysprof-document-frame.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_FRAME (sysprof_document_frame_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_FRAME(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_FRAME)
|
||||
#define SYSPROF_DOCUMENT_FRAME(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_FRAME, SysprofDocumentFrame)
|
||||
#define SYSPROF_DOCUMENT_FRAME_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_FRAME, SysprofDocumentFrameClass)
|
||||
|
||||
typedef struct _SysprofDocumentFrame SysprofDocumentFrame;
|
||||
typedef struct _SysprofDocumentFrameClass SysprofDocumentFrameClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_frame_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
int sysprof_document_frame_get_cpu (SysprofDocumentFrame *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
int sysprof_document_frame_get_pid (SysprofDocumentFrame *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gint64 sysprof_document_frame_get_time (SysprofDocumentFrame *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gint64 sysprof_document_frame_get_time_offset (SysprofDocumentFrame *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_document_frame_equal (const SysprofDocumentFrame *a,
|
||||
const SysprofDocumentFrame *b);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
char *sysprof_document_frame_dup_tooltip (SysprofDocumentFrame *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
char *sysprof_document_frame_dup_time_string (SysprofDocumentFrame *self);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentFrame, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
169
src/libsysprof/sysprof-document-jitmap.c
Normal file
169
src/libsysprof/sysprof-document-jitmap.c
Normal file
@ -0,0 +1,169 @@
|
||||
/* sysprof-document-jitmap.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
#include "sysprof-document-jitmap.h"
|
||||
|
||||
typedef struct _Jitmap
|
||||
{
|
||||
SysprofAddress address;
|
||||
const char *name;
|
||||
} Jitmap;
|
||||
|
||||
struct _SysprofDocumentJitmap
|
||||
{
|
||||
SysprofDocumentFrame parent_instance;
|
||||
GArray *jitmaps;
|
||||
guint initialized : 1;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentJitmapClass
|
||||
{
|
||||
SysprofDocumentFrameClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_SIZE,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentJitmap, sysprof_document_jitmap, SYSPROF_TYPE_DOCUMENT_FRAME)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_document_jitmap_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentJitmap *self = SYSPROF_DOCUMENT_JITMAP (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SIZE:
|
||||
g_value_set_uint (value, sysprof_document_jitmap_get_size (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_jitmap_class_init (SysprofDocumentJitmapClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->get_property = sysprof_document_jitmap_get_property;
|
||||
|
||||
properties [PROP_SIZE] =
|
||||
g_param_spec_string ("size", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_jitmap_init (SysprofDocumentJitmap *self)
|
||||
{
|
||||
self->jitmaps = g_array_new (FALSE, FALSE, sizeof (Jitmap));
|
||||
}
|
||||
|
||||
guint
|
||||
sysprof_document_jitmap_get_size (SysprofDocumentJitmap *self)
|
||||
{
|
||||
const SysprofCaptureJitmap *jitmap;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_JITMAP (self), 0);
|
||||
|
||||
jitmap = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureJitmap);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_UINT32 (self, jitmap->n_jitmaps);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_jitmap_get_mapping:
|
||||
* @self: a #SysprofDocumentJitmap
|
||||
* @nth: the index of the mapping
|
||||
* @address: (out): a location for the address
|
||||
*
|
||||
* Gets the @nth mapping and returns it as @address and the return value
|
||||
* of this function.
|
||||
*
|
||||
* Returns: (nullable): the name of the symbol, or %NULL if @nth is
|
||||
* out of bounds.
|
||||
*/
|
||||
const char *
|
||||
sysprof_document_jitmap_get_mapping (SysprofDocumentJitmap *self,
|
||||
guint nth,
|
||||
SysprofAddress *address)
|
||||
{
|
||||
const SysprofCaptureJitmap *frame;
|
||||
const Jitmap *j;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_JITMAP (self), NULL);
|
||||
g_return_val_if_fail (address != NULL, NULL);
|
||||
|
||||
if G_UNLIKELY (!self->initialized)
|
||||
{
|
||||
const guint8 *pos;
|
||||
const guint8 *endptr;
|
||||
|
||||
self->initialized = TRUE;
|
||||
|
||||
frame = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureJitmap);
|
||||
endptr = SYSPROF_DOCUMENT_FRAME_ENDPTR (self);
|
||||
pos = frame->data;
|
||||
|
||||
while (pos < endptr)
|
||||
{
|
||||
SysprofAddress addr;
|
||||
Jitmap map;
|
||||
|
||||
if (pos + sizeof addr >= endptr)
|
||||
break;
|
||||
|
||||
memcpy (&addr, pos, sizeof addr);
|
||||
pos += sizeof addr;
|
||||
|
||||
map.address = SYSPROF_DOCUMENT_FRAME_UINT64 (self, addr);
|
||||
|
||||
if (!(map.name = SYSPROF_DOCUMENT_FRAME_CSTRING (self, (const char *)pos)))
|
||||
break;
|
||||
|
||||
pos += strlen (map.name) + 1;
|
||||
|
||||
g_array_append_val (self->jitmaps, map);
|
||||
}
|
||||
}
|
||||
|
||||
if (nth >= self->jitmaps->len)
|
||||
return NULL;
|
||||
|
||||
j = &g_array_index (self->jitmaps, Jitmap, nth);
|
||||
*address = j->address;
|
||||
return j->name;
|
||||
}
|
||||
|
||||
49
src/libsysprof/sysprof-document-jitmap.h
Normal file
49
src/libsysprof/sysprof-document-jitmap.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* sysprof-document-jitmap.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_JITMAP (sysprof_document_jitmap_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_JITMAP(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_JITMAP)
|
||||
#define SYSPROF_DOCUMENT_JITMAP(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_JITMAP, SysprofDocumentJitmap)
|
||||
#define SYSPROF_DOCUMENT_JITMAP_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_JITMAP, SysprofDocumentJitmapClass)
|
||||
|
||||
typedef struct _SysprofDocumentJitmap SysprofDocumentJitmap;
|
||||
typedef struct _SysprofDocumentJitmapClass SysprofDocumentJitmapClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_jitmap_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint sysprof_document_jitmap_get_size (SysprofDocumentJitmap *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_jitmap_get_mapping (SysprofDocumentJitmap *self,
|
||||
guint position,
|
||||
SysprofAddress *address);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentJitmap, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
659
src/libsysprof/sysprof-document-loader.c
Normal file
659
src/libsysprof/sysprof-document-loader.c
Normal file
@ -0,0 +1,659 @@
|
||||
/* sysprof-document-loader.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include "sysprof-bundled-symbolizer.h"
|
||||
#include "sysprof-document-bitset-index-private.h"
|
||||
#include "sysprof-document-loader.h"
|
||||
#include "sysprof-document-private.h"
|
||||
#include "sysprof-elf-symbolizer.h"
|
||||
#include "sysprof-jitmap-symbolizer.h"
|
||||
#include "sysprof-kallsyms-symbolizer.h"
|
||||
#include "sysprof-multi-symbolizer.h"
|
||||
|
||||
struct _SysprofDocumentLoader
|
||||
{
|
||||
GObject parent_instance;
|
||||
GMutex mutex;
|
||||
SysprofSymbolizer *symbolizer;
|
||||
char *filename;
|
||||
char *message;
|
||||
double fraction;
|
||||
int fd;
|
||||
guint notify_source;
|
||||
guint symbolizing : 1;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_FRACTION,
|
||||
PROP_MESSAGE,
|
||||
PROP_SYMBOLIZER,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentLoader, sysprof_document_loader, G_TYPE_OBJECT)
|
||||
|
||||
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 * .5;
|
||||
|
||||
if (self->symbolizing)
|
||||
self->fraction += .5;
|
||||
|
||||
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,
|
||||
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 ());
|
||||
sysprof_multi_symbolizer_take (multi, sysprof_kallsyms_symbolizer_new ());
|
||||
sysprof_multi_symbolizer_take (multi, sysprof_elf_symbolizer_new ());
|
||||
sysprof_multi_symbolizer_take (multi, sysprof_jitmap_symbolizer_new ());
|
||||
self->symbolizer = SYSPROF_SYMBOLIZER (g_steal_pointer (&multi));
|
||||
}
|
||||
|
||||
static void
|
||||
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);
|
||||
g_clear_fd (&self->fd, NULL);
|
||||
g_mutex_clear (&self->mutex);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_document_loader_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_loader_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentLoader *self = SYSPROF_DOCUMENT_LOADER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FRACTION:
|
||||
g_value_set_double (value, sysprof_document_loader_get_fraction (self));
|
||||
break;
|
||||
|
||||
case PROP_MESSAGE:
|
||||
g_value_set_string (value, sysprof_document_loader_get_message (self));
|
||||
break;
|
||||
|
||||
case PROP_SYMBOLIZER:
|
||||
g_value_set_object (value, sysprof_document_loader_get_symbolizer (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_loader_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentLoader *self = SYSPROF_DOCUMENT_LOADER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SYMBOLIZER:
|
||||
sysprof_document_loader_set_symbolizer (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_loader_class_init (SysprofDocumentLoaderClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_document_loader_finalize;
|
||||
object_class->get_property = sysprof_document_loader_get_property;
|
||||
object_class->set_property = sysprof_document_loader_set_property;
|
||||
|
||||
properties [PROP_FRACTION] =
|
||||
g_param_spec_double ("fraction", NULL, NULL,
|
||||
0, 1, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_MESSAGE] =
|
||||
g_param_spec_string ("message", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_SYMBOLIZER] =
|
||||
g_param_spec_object ("symbolizer", NULL, NULL,
|
||||
SYSPROF_TYPE_SYMBOLIZER,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
g_type_ensure (SYSPROF_TYPE_DOCUMENT);
|
||||
g_type_ensure (SYSPROF_TYPE_DOCUMENT_BITSET_INDEX);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_loader_init (SysprofDocumentLoader *self)
|
||||
{
|
||||
g_mutex_init (&self->mutex);
|
||||
|
||||
self->fd = -1;
|
||||
|
||||
set_default_symbolizer (self);
|
||||
}
|
||||
|
||||
SysprofDocumentLoader *
|
||||
sysprof_document_loader_new (const char *filename)
|
||||
{
|
||||
SysprofDocumentLoader *self;
|
||||
|
||||
g_return_val_if_fail (filename != NULL, NULL);
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_DOCUMENT_LOADER, NULL);
|
||||
self->filename = g_strdup (filename);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
SysprofDocumentLoader *
|
||||
sysprof_document_loader_new_for_fd (int fd,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(SysprofDocumentLoader) self = NULL;
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_DOCUMENT_LOADER, NULL);
|
||||
|
||||
if (-1 == (self->fd = dup (fd)))
|
||||
{
|
||||
int errsv = errno;
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
g_io_error_from_errno (errsv),
|
||||
g_strerror (errsv));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_steal_pointer (&self);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_loader_get_symbolizer:
|
||||
* @self: a #SysprofDocumentLoader
|
||||
*
|
||||
* Gets the #SysprofSymbolizer to use to symbolize traces within
|
||||
* the document.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #SysprofSymbolizer or %NULL
|
||||
*/
|
||||
SysprofSymbolizer *
|
||||
sysprof_document_loader_get_symbolizer (SysprofDocumentLoader *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_LOADER (self), NULL);
|
||||
|
||||
return self->symbolizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_loader_set_symbolizer:
|
||||
* @self: a #SysprofDocumentLoader
|
||||
* @symbolizer: (nullable): a #SysprofSymbolizer or %NULL
|
||||
*
|
||||
* Sets the symbolizer to use to convert instruction pointers to
|
||||
* symbol names in the document.
|
||||
*
|
||||
* If set to %NULL, a sensible default will be chosen when loading.
|
||||
*/
|
||||
void
|
||||
sysprof_document_loader_set_symbolizer (SysprofDocumentLoader *self,
|
||||
SysprofSymbolizer *symbolizer)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_DOCUMENT_LOADER (self));
|
||||
|
||||
if (g_set_object (&self->symbolizer, symbolizer))
|
||||
{
|
||||
if (self->symbolizer == NULL)
|
||||
set_default_symbolizer (self);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SYMBOLIZER]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_loader_get_fraction:
|
||||
* @self: a #SysprofDocumentLoader
|
||||
*
|
||||
* Gets the fraction between 0 and 1 for the loading that has occurred.
|
||||
*
|
||||
* Returns: A value between 0 and 1.
|
||||
*/
|
||||
double
|
||||
sysprof_document_loader_get_fraction (SysprofDocumentLoader *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_LOADER (self), .0);
|
||||
|
||||
return self->fraction;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_loader_get_message:
|
||||
* @self: a #SysprofDocumentLoader
|
||||
*
|
||||
* Gets a text message representing what is happenin with loading.
|
||||
*
|
||||
* This only updates between calls of sysprof_document_loader_load_async()
|
||||
* and sysprof_document_loader_load_finish().
|
||||
*
|
||||
* Returns: (nullable): a string containing a load message
|
||||
*/
|
||||
const char *
|
||||
sysprof_document_loader_get_message (SysprofDocumentLoader *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_LOADER (self), NULL);
|
||||
|
||||
return self->message;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_loader_load_symbols_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
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 (0., _("Document loaded"), self);
|
||||
|
||||
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;
|
||||
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));
|
||||
|
||||
if (!(document = _sysprof_document_new_finish (result, &error)))
|
||||
{
|
||||
g_task_return_error (task, g_steal_pointer (&error));
|
||||
set_progress (1., _("Loading failed"), self);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->filename != NULL)
|
||||
{
|
||||
g_autofree char *title = g_path_get_basename (self->filename);
|
||||
_sysprof_document_set_title (document, title);
|
||||
}
|
||||
|
||||
self->symbolizing = TRUE;
|
||||
|
||||
set_progress (.0, _("Symbolizing stack traces"), self);
|
||||
|
||||
_sysprof_document_symbolize_async (document,
|
||||
symbolizer,
|
||||
set_progress,
|
||||
g_object_ref (self),
|
||||
g_object_unref,
|
||||
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;
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_loader_load_async:
|
||||
* @self: a #SysprofDocumentLoader
|
||||
* @cancellable: (nullable): a #GCancellable or %NULL
|
||||
* @callback: a callback to execute upon completion
|
||||
* @user_data: closure data for @callback
|
||||
*
|
||||
* Asynchronously loads the document.
|
||||
*
|
||||
* @callback should call sysprof_document_loader_load_finish().
|
||||
*/
|
||||
void
|
||||
sysprof_document_loader_load_async (SysprofDocumentLoader *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
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);
|
||||
|
||||
set_progress (0., _("Loading document"), self);
|
||||
|
||||
if (self->fd != -1)
|
||||
mapped_file_new_from_fd_async (self->fd,
|
||||
cancellable,
|
||||
sysprof_document_loader_load_mapped_file_cb,
|
||||
g_steal_pointer (&task));
|
||||
else
|
||||
mapped_file_new_async (self->filename,
|
||||
cancellable,
|
||||
sysprof_document_loader_load_mapped_file_cb,
|
||||
g_steal_pointer (&task));
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_loader_load_finish:
|
||||
* @self: a #SysprofDocumentLoader
|
||||
* @result: a #GAsyncResult
|
||||
* @error: a location for a #GError, or %NULL
|
||||
*
|
||||
* Completes a request to load a document asynchronously.
|
||||
*
|
||||
* Returns: (transfer full): a #SysprofDocumentLoader or %NULL
|
||||
* and @error is set.
|
||||
*/
|
||||
SysprofDocument *
|
||||
sysprof_document_loader_load_finish (SysprofDocumentLoader *self,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
SysprofDocument *ret;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_LOADER (self), NULL);
|
||||
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);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct SysprofDocumentLoaderSync
|
||||
{
|
||||
GMainContext *main_context;
|
||||
SysprofDocument *document;
|
||||
GError *error;
|
||||
} SysprofDocumentLoaderSync;
|
||||
|
||||
static void
|
||||
sysprof_document_loader_load_sync_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofDocumentLoader *loader = (SysprofDocumentLoader *)object;
|
||||
SysprofDocumentLoaderSync *state = user_data;
|
||||
|
||||
g_assert (SYSPROF_IS_DOCUMENT_LOADER (loader));
|
||||
g_assert (G_IS_ASYNC_RESULT (result));
|
||||
g_assert (state != NULL);
|
||||
g_assert (state->main_context != NULL);
|
||||
|
||||
state->document = sysprof_document_loader_load_finish (loader, result, &state->error);
|
||||
|
||||
g_main_context_wakeup (state->main_context);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_loader_load:
|
||||
* @self: a #SysprofDocumentLoader
|
||||
* @cancellable: (nullable): a #GCancellable or %NULL
|
||||
* @error: a location for a #GError, or %NULL
|
||||
*
|
||||
* Synchronously loads the document.
|
||||
*
|
||||
* This function requires a #GMainContext to be set for the current
|
||||
* thread and uses the asynchronously loader API underneath.
|
||||
*
|
||||
* Returns: (transfer full): a #SysprofDocument if successful; otherwise
|
||||
* %NULL and @error is set.
|
||||
*/
|
||||
SysprofDocument *
|
||||
sysprof_document_loader_load (SysprofDocumentLoader *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
SysprofDocumentLoaderSync state;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_LOADER (self), NULL);
|
||||
g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
|
||||
|
||||
state.main_context = g_main_context_ref_thread_default ();
|
||||
state.document = NULL;
|
||||
state.error = NULL;
|
||||
|
||||
sysprof_document_loader_load_async (self,
|
||||
cancellable,
|
||||
sysprof_document_loader_load_sync_cb,
|
||||
&state);
|
||||
|
||||
while (state.document == NULL && state.error == NULL)
|
||||
g_main_context_iteration (state.main_context, TRUE);
|
||||
|
||||
g_main_context_unref (state.main_context);
|
||||
|
||||
if (state.error != NULL)
|
||||
g_propagate_error (error, state.error);
|
||||
|
||||
return state.document;
|
||||
}
|
||||
65
src/libsysprof/sysprof-document-loader.h
Normal file
65
src/libsysprof/sysprof-document-loader.h
Normal file
@ -0,0 +1,65 @@
|
||||
/* sysprof-document-loader.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
#include "sysprof-document.h"
|
||||
#include "sysprof-symbolizer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_LOADER (sysprof_document_loader_get_type())
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (SysprofDocumentLoader, sysprof_document_loader, SYSPROF, DOCUMENT_LOADER, GObject)
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofDocumentLoader *sysprof_document_loader_new (const char *filename);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofDocumentLoader *sysprof_document_loader_new_for_fd (int fd,
|
||||
GError **error);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofSymbolizer *sysprof_document_loader_get_symbolizer (SysprofDocumentLoader *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_document_loader_set_symbolizer (SysprofDocumentLoader *self,
|
||||
SysprofSymbolizer *symbolizer);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
double sysprof_document_loader_get_fraction (SysprofDocumentLoader *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_loader_get_message (SysprofDocumentLoader *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofDocument *sysprof_document_loader_load (SysprofDocumentLoader *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_document_loader_load_async (SysprofDocumentLoader *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofDocument *sysprof_document_loader_load_finish (SysprofDocumentLoader *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
144
src/libsysprof/sysprof-document-log.c
Normal file
144
src/libsysprof/sysprof-document-log.c
Normal file
@ -0,0 +1,144 @@
|
||||
/* sysprof-document-log.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
#include "sysprof-document-log.h"
|
||||
|
||||
struct _SysprofDocumentLog
|
||||
{
|
||||
SysprofDocumentFrame parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentLogClass
|
||||
{
|
||||
SysprofDocumentFrameClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_DOMAIN,
|
||||
PROP_MESSAGE,
|
||||
PROP_SEVERITY,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentLog, sysprof_document_log, SYSPROF_TYPE_DOCUMENT_FRAME)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_document_log_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentLog *self = SYSPROF_DOCUMENT_LOG (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SEVERITY:
|
||||
g_value_set_uint (value, sysprof_document_log_get_severity (self));
|
||||
break;
|
||||
|
||||
case PROP_MESSAGE:
|
||||
g_value_set_string (value, sysprof_document_log_get_message (self));
|
||||
break;
|
||||
|
||||
case PROP_DOMAIN:
|
||||
g_value_set_string (value, sysprof_document_log_get_domain (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_log_class_init (SysprofDocumentLogClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
SysprofDocumentFrameClass *document_frame_class = SYSPROF_DOCUMENT_FRAME_CLASS (klass);
|
||||
|
||||
object_class->get_property = sysprof_document_log_get_property;
|
||||
|
||||
document_frame_class->type_name = N_("Log");
|
||||
|
||||
properties [PROP_SEVERITY] =
|
||||
g_param_spec_uint ("severity", NULL, NULL,
|
||||
0, G_MAXUINT16, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_DOMAIN] =
|
||||
g_param_spec_string ("domain", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_MESSAGE] =
|
||||
g_param_spec_string ("message", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_log_init (SysprofDocumentLog *self)
|
||||
{
|
||||
}
|
||||
|
||||
GLogLevelFlags
|
||||
sysprof_document_log_get_severity (SysprofDocumentLog *self)
|
||||
{
|
||||
const SysprofCaptureLog *log;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_LOG (self), 0);
|
||||
|
||||
log = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureLog);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_UINT16 (self, log->severity);
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_log_get_message (SysprofDocumentLog *self)
|
||||
{
|
||||
const SysprofCaptureLog *log;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_LOG (self), 0);
|
||||
|
||||
log = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureLog);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_CSTRING (self, log->message);
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_log_get_domain (SysprofDocumentLog *self)
|
||||
{
|
||||
const SysprofCaptureLog *log;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_LOG (self), 0);
|
||||
|
||||
log = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureLog);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_CSTRING (self, log->domain);
|
||||
}
|
||||
46
src/libsysprof/sysprof-document-log.h
Normal file
46
src/libsysprof/sysprof-document-log.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* sysprof-document-log.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_LOG (sysprof_document_log_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_LOG(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_LOG)
|
||||
#define SYSPROF_DOCUMENT_LOG(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_LOG, SysprofDocumentLog)
|
||||
#define SYSPROF_DOCUMENT_LOG_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_LOG, SysprofDocumentLogClass)
|
||||
|
||||
typedef struct _SysprofDocumentLog SysprofDocumentLog;
|
||||
typedef struct _SysprofDocumentLogClass SysprofDocumentLogClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_log_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_log_get_message (SysprofDocumentLog *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GLogLevelFlags sysprof_document_log_get_severity (SysprofDocumentLog *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_log_get_domain (SysprofDocumentLog *self);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentLog, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
204
src/libsysprof/sysprof-document-mark.c
Normal file
204
src/libsysprof/sysprof-document-mark.c
Normal file
@ -0,0 +1,204 @@
|
||||
/* sysprof-document-mark.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
#include "sysprof-document-mark.h"
|
||||
|
||||
struct _SysprofDocumentMark
|
||||
{
|
||||
SysprofDocumentFrame parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentMarkClass
|
||||
{
|
||||
SysprofDocumentFrameClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_DURATION,
|
||||
PROP_END_TIME,
|
||||
PROP_GROUP,
|
||||
PROP_MESSAGE,
|
||||
PROP_NAME,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentMark, sysprof_document_mark, SYSPROF_TYPE_DOCUMENT_FRAME)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static char *
|
||||
sysprof_document_mark_dup_tooltip (SysprofDocumentFrame *frame)
|
||||
{
|
||||
SysprofDocumentMark *self = (SysprofDocumentMark *)frame;
|
||||
g_autofree char *time_string = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_DOCUMENT_MARK (self));
|
||||
|
||||
time_string = sysprof_document_frame_dup_time_string (SYSPROF_DOCUMENT_FRAME (self));
|
||||
|
||||
return g_strdup_printf ("%s: %s: %s: %s",
|
||||
time_string,
|
||||
sysprof_document_mark_get_group (self),
|
||||
sysprof_document_mark_get_name (self),
|
||||
sysprof_document_mark_get_message (self));
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_mark_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentMark *self = SYSPROF_DOCUMENT_MARK (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DURATION:
|
||||
g_value_set_int64 (value, sysprof_document_mark_get_duration (self));
|
||||
break;
|
||||
|
||||
case PROP_END_TIME:
|
||||
g_value_set_int64 (value, sysprof_document_mark_get_end_time (self));
|
||||
break;
|
||||
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, sysprof_document_mark_get_name (self));
|
||||
break;
|
||||
|
||||
case PROP_GROUP:
|
||||
g_value_set_string (value, sysprof_document_mark_get_group (self));
|
||||
break;
|
||||
|
||||
case PROP_MESSAGE:
|
||||
g_value_set_string (value, sysprof_document_mark_get_message (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_mark_class_init (SysprofDocumentMarkClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
SysprofDocumentFrameClass *document_frame_class = SYSPROF_DOCUMENT_FRAME_CLASS (klass);
|
||||
|
||||
object_class->get_property = sysprof_document_mark_get_property;
|
||||
|
||||
document_frame_class->type_name = N_("Mark");
|
||||
document_frame_class->dup_tooltip = sysprof_document_mark_dup_tooltip;
|
||||
|
||||
properties [PROP_DURATION] =
|
||||
g_param_spec_int64 ("duration", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_END_TIME] =
|
||||
g_param_spec_int64 ("end-time", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_GROUP] =
|
||||
g_param_spec_string ("group", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_NAME] =
|
||||
g_param_spec_string ("name", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_MESSAGE] =
|
||||
g_param_spec_string ("message", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_mark_init (SysprofDocumentMark *self)
|
||||
{
|
||||
}
|
||||
|
||||
gint64
|
||||
sysprof_document_mark_get_duration (SysprofDocumentMark *self)
|
||||
{
|
||||
const SysprofCaptureMark *mark;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_MARK (self), 0);
|
||||
|
||||
mark = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureMark);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_INT64 (self, mark->duration);
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_mark_get_group (SysprofDocumentMark *self)
|
||||
{
|
||||
const SysprofCaptureMark *mark;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_MARK (self), 0);
|
||||
|
||||
mark = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureMark);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_CSTRING (self, mark->group);
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_mark_get_name (SysprofDocumentMark *self)
|
||||
{
|
||||
const SysprofCaptureMark *mark;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_MARK (self), 0);
|
||||
|
||||
mark = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureMark);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_CSTRING (self, mark->name);
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_mark_get_message (SysprofDocumentMark *self)
|
||||
{
|
||||
const SysprofCaptureMark *mark;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_MARK (self), 0);
|
||||
|
||||
mark = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureMark);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_CSTRING (self, mark->message);
|
||||
}
|
||||
|
||||
gint64
|
||||
sysprof_document_mark_get_end_time (SysprofDocumentMark *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_MARK (self), 0);
|
||||
|
||||
return sysprof_document_frame_get_time (SYSPROF_DOCUMENT_FRAME (self))
|
||||
+ sysprof_document_mark_get_duration (self);
|
||||
}
|
||||
51
src/libsysprof/sysprof-document-mark.h
Normal file
51
src/libsysprof/sysprof-document-mark.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* sysprof-document-mark.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_MARK (sysprof_document_mark_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_MARK(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_MARK)
|
||||
#define SYSPROF_DOCUMENT_MARK(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_MARK, SysprofDocumentMark)
|
||||
#define SYSPROF_DOCUMENT_MARK_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_MARK, SysprofDocumentMarkClass)
|
||||
|
||||
typedef struct _SysprofDocumentMark SysprofDocumentMark;
|
||||
typedef struct _SysprofDocumentMarkClass SysprofDocumentMarkClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_mark_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gint64 sysprof_document_mark_get_duration (SysprofDocumentMark *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_mark_get_group (SysprofDocumentMark *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_mark_get_name (SysprofDocumentMark *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_mark_get_message (SysprofDocumentMark *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gint64 sysprof_document_mark_get_end_time (SysprofDocumentMark *self);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentMark, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
117
src/libsysprof/sysprof-document-metadata.c
Normal file
117
src/libsysprof/sysprof-document-metadata.c
Normal file
@ -0,0 +1,117 @@
|
||||
/* sysprof-document-metadata.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
#include "sysprof-document-metadata.h"
|
||||
|
||||
struct _SysprofDocumentMetadata
|
||||
{
|
||||
SysprofDocumentFrame parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentMetadataClass
|
||||
{
|
||||
SysprofDocumentFrameClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ID,
|
||||
PROP_VALUE,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentMetadata, sysprof_document_metadata, SYSPROF_TYPE_DOCUMENT_FRAME)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_document_metadata_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentMetadata *self = SYSPROF_DOCUMENT_METADATA (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ID:
|
||||
g_value_set_string (value, sysprof_document_metadata_get_id (self));
|
||||
break;
|
||||
|
||||
case PROP_VALUE:
|
||||
g_value_set_string (value, sysprof_document_metadata_get_value (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_metadata_class_init (SysprofDocumentMetadataClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->get_property = sysprof_document_metadata_get_property;
|
||||
|
||||
properties [PROP_ID] =
|
||||
g_param_spec_string ("id", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_VALUE] =
|
||||
g_param_spec_string ("value", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_metadata_init (SysprofDocumentMetadata *self)
|
||||
{
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_metadata_get_id (SysprofDocumentMetadata *self)
|
||||
{
|
||||
const SysprofCaptureMetadata *meta;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_METADATA (self), 0);
|
||||
|
||||
meta = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureMetadata);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_CSTRING (self, meta->id);
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_metadata_get_value (SysprofDocumentMetadata *self)
|
||||
{
|
||||
const SysprofCaptureMetadata *meta;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_METADATA (self), 0);
|
||||
|
||||
meta = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureMetadata);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_CSTRING (self, meta->metadata);
|
||||
}
|
||||
45
src/libsysprof/sysprof-document-metadata.h
Normal file
45
src/libsysprof/sysprof-document-metadata.h
Normal file
@ -0,0 +1,45 @@
|
||||
/* sysprof-document-metadata.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_METADATA (sysprof_document_metadata_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_METADATA(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_METADATA)
|
||||
#define SYSPROF_DOCUMENT_METADATA(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_METADATA, SysprofDocumentMetadata)
|
||||
#define SYSPROF_DOCUMENT_METADATA_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_METADATA, SysprofDocumentMetadataClass)
|
||||
|
||||
typedef struct _SysprofDocumentMetadata SysprofDocumentMetadata;
|
||||
typedef struct _SysprofDocumentMetadataClass SysprofDocumentMetadataClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_metadata_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_metadata_get_id (SysprofDocumentMetadata *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_metadata_get_value (SysprofDocumentMetadata *self);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentMetadata, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
223
src/libsysprof/sysprof-document-mmap.c
Normal file
223
src/libsysprof/sysprof-document-mmap.c
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* sysprof-document-mmap.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
#include "sysprof-document-mmap.h"
|
||||
|
||||
struct _SysprofDocumentMmap
|
||||
{
|
||||
SysprofDocumentFrame parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentMmapClass
|
||||
{
|
||||
SysprofDocumentFrameClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_BUILD_ID,
|
||||
PROP_END_ADDRESS,
|
||||
PROP_FILE,
|
||||
PROP_FILE_INODE,
|
||||
PROP_FILE_OFFSET,
|
||||
PROP_START_ADDRESS,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentMmap, sysprof_document_mmap, SYSPROF_TYPE_DOCUMENT_FRAME)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_document_mmap_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentMmap *self = SYSPROF_DOCUMENT_MMAP (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_START_ADDRESS:
|
||||
g_value_set_uint64 (value, sysprof_document_mmap_get_start_address (self));
|
||||
break;
|
||||
|
||||
case PROP_END_ADDRESS:
|
||||
g_value_set_uint64 (value, sysprof_document_mmap_get_end_address (self));
|
||||
break;
|
||||
|
||||
case PROP_FILE:
|
||||
g_value_set_string (value, sysprof_document_mmap_get_file (self));
|
||||
break;
|
||||
|
||||
case PROP_FILE_OFFSET:
|
||||
g_value_set_uint64 (value, sysprof_document_mmap_get_file_offset (self));
|
||||
break;
|
||||
|
||||
case PROP_FILE_INODE:
|
||||
g_value_set_uint64 (value, sysprof_document_mmap_get_file_inode (self));
|
||||
break;
|
||||
|
||||
case PROP_BUILD_ID:
|
||||
g_value_set_string (value, sysprof_document_mmap_get_build_id (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_mmap_class_init (SysprofDocumentMmapClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->get_property = sysprof_document_mmap_get_property;
|
||||
|
||||
properties [PROP_START_ADDRESS] =
|
||||
g_param_spec_uint64 ("start-address", NULL, NULL,
|
||||
0, G_MAXUINT64, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_END_ADDRESS] =
|
||||
g_param_spec_uint64 ("end-address", NULL, NULL,
|
||||
0, G_MAXUINT64, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_FILE] =
|
||||
g_param_spec_string ("file", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_FILE_INODE] =
|
||||
g_param_spec_uint64 ("file-inode", NULL, NULL,
|
||||
0, G_MAXUINT64, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_FILE_OFFSET] =
|
||||
g_param_spec_uint64 ("file-offset", NULL, NULL,
|
||||
0, G_MAXUINT64, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_BUILD_ID] =
|
||||
g_param_spec_string ("build-id", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_mmap_init (SysprofDocumentMmap *self)
|
||||
{
|
||||
}
|
||||
|
||||
guint64
|
||||
sysprof_document_mmap_get_start_address (SysprofDocumentMmap *self)
|
||||
{
|
||||
const SysprofCaptureMap *mmap;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_MMAP (self), 0);
|
||||
|
||||
mmap = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureMap);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_UINT64 (self, mmap->start);
|
||||
}
|
||||
|
||||
guint64
|
||||
sysprof_document_mmap_get_end_address (SysprofDocumentMmap *self)
|
||||
{
|
||||
const SysprofCaptureMap *mmap;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_MMAP (self), 0);
|
||||
|
||||
mmap = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureMap);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_UINT64 (self, mmap->end);
|
||||
}
|
||||
|
||||
guint64
|
||||
sysprof_document_mmap_get_file_inode (SysprofDocumentMmap *self)
|
||||
{
|
||||
const SysprofCaptureMap *mmap;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_MMAP (self), 0);
|
||||
|
||||
mmap = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureMap);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_UINT64 (self, mmap->inode);
|
||||
}
|
||||
|
||||
guint64
|
||||
sysprof_document_mmap_get_file_offset (SysprofDocumentMmap *self)
|
||||
{
|
||||
const SysprofCaptureMap *mmap;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_MMAP (self), 0);
|
||||
|
||||
mmap = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureMap);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_UINT64 (self, mmap->offset);
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_mmap_get_file (SysprofDocumentMmap *self)
|
||||
{
|
||||
const SysprofCaptureMap *mmap;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_MMAP (self), NULL);
|
||||
|
||||
mmap = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureMap);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_CSTRING (self, mmap->filename);
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_mmap_get_build_id (SysprofDocumentMmap *self)
|
||||
{
|
||||
const char *file;
|
||||
const char *build_id;
|
||||
gsize len;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_MMAP (self), NULL);
|
||||
|
||||
if (!(file = sysprof_document_mmap_get_file (self)))
|
||||
return NULL;
|
||||
|
||||
/* The build-id may be tacked on after the filename if after the
|
||||
* Nil byte we get '@'. SYSPROF_DOCUMENT_FRAME_CSTRING() will check
|
||||
* for bounds so we can feed it a position we don't know is part
|
||||
* of our frame or not. We expect "FILE\0@BUILD_ID_IN_HEX\0".
|
||||
*/
|
||||
|
||||
len = strlen (file);
|
||||
|
||||
if (!(build_id = SYSPROF_DOCUMENT_FRAME_CSTRING (self, &file[len+1])))
|
||||
return NULL;
|
||||
|
||||
if (build_id[0] != '@')
|
||||
return NULL;
|
||||
|
||||
return &build_id[1];
|
||||
}
|
||||
53
src/libsysprof/sysprof-document-mmap.h
Normal file
53
src/libsysprof/sysprof-document-mmap.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* sysprof-document-mmap.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_MMAP (sysprof_document_mmap_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_MMAP(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_MMAP)
|
||||
#define SYSPROF_DOCUMENT_MMAP(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_MMAP, SysprofDocumentMmap)
|
||||
#define SYSPROF_DOCUMENT_MMAP_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_MMAP, SysprofDocumentMmapClass)
|
||||
|
||||
typedef struct _SysprofDocumentMmap SysprofDocumentMmap;
|
||||
typedef struct _SysprofDocumentMmapClass SysprofDocumentMmapClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_mmap_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint64 sysprof_document_mmap_get_start_address (SysprofDocumentMmap *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint64 sysprof_document_mmap_get_end_address (SysprofDocumentMmap *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint64 sysprof_document_mmap_get_file_inode (SysprofDocumentMmap *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint64 sysprof_document_mmap_get_file_offset (SysprofDocumentMmap *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_mmap_get_file (SysprofDocumentMmap *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_mmap_get_build_id (SysprofDocumentMmap *self);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentMmap, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
142
src/libsysprof/sysprof-document-overlay.c
Normal file
142
src/libsysprof/sysprof-document-overlay.c
Normal file
@ -0,0 +1,142 @@
|
||||
/* sysprof-document-overlay.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
#include "sysprof-document-overlay.h"
|
||||
|
||||
struct _SysprofDocumentOverlay
|
||||
{
|
||||
SysprofDocumentFrame parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentOverlayClass
|
||||
{
|
||||
SysprofDocumentFrameClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_DESTINATION,
|
||||
PROP_LAYER,
|
||||
PROP_SOURCE,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentOverlay, sysprof_document_overlay, SYSPROF_TYPE_DOCUMENT_FRAME)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_document_overlay_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentOverlay *self = SYSPROF_DOCUMENT_OVERLAY (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DESTINATION:
|
||||
g_value_set_string (value, sysprof_document_overlay_get_destination (self));
|
||||
break;
|
||||
|
||||
case PROP_LAYER:
|
||||
g_value_set_uint (value, sysprof_document_overlay_get_layer (self));
|
||||
break;
|
||||
|
||||
case PROP_SOURCE:
|
||||
g_value_set_string (value, sysprof_document_overlay_get_source (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_overlay_class_init (SysprofDocumentOverlayClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->get_property = sysprof_document_overlay_get_property;
|
||||
|
||||
properties [PROP_LAYER] =
|
||||
g_param_spec_uint ("layer", NULL, NULL,
|
||||
0, G_MAXUINT, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_DESTINATION] =
|
||||
g_param_spec_string ("destination", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_SOURCE] =
|
||||
g_param_spec_string ("source", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_overlay_init (SysprofDocumentOverlay *self)
|
||||
{
|
||||
}
|
||||
|
||||
guint
|
||||
sysprof_document_overlay_get_layer (SysprofDocumentOverlay *self)
|
||||
{
|
||||
const SysprofCaptureOverlay *overlay;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_OVERLAY (self), 0);
|
||||
|
||||
overlay = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureOverlay);
|
||||
|
||||
return overlay->layer;
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_overlay_get_source (SysprofDocumentOverlay *self)
|
||||
{
|
||||
const SysprofCaptureOverlay *overlay;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_OVERLAY (self), 0);
|
||||
|
||||
overlay = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureOverlay);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_CSTRING (self, overlay->data);
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_overlay_get_destination (SysprofDocumentOverlay *self)
|
||||
{
|
||||
const SysprofCaptureOverlay *overlay;
|
||||
guint16 offset;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_OVERLAY (self), 0);
|
||||
|
||||
overlay = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureOverlay);
|
||||
|
||||
offset = SYSPROF_DOCUMENT_FRAME_UINT16 (self, overlay->src_len);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_CSTRING (self, &overlay->data[offset+1]);
|
||||
}
|
||||
47
src/libsysprof/sysprof-document-overlay.h
Normal file
47
src/libsysprof/sysprof-document-overlay.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* sysprof-document-overlay.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_OVERLAY (sysprof_document_overlay_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_OVERLAY(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_OVERLAY)
|
||||
#define SYSPROF_DOCUMENT_OVERLAY(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_OVERLAY, SysprofDocumentOverlay)
|
||||
#define SYSPROF_DOCUMENT_OVERLAY_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_OVERLAY, SysprofDocumentOverlayClass)
|
||||
|
||||
typedef struct _SysprofDocumentOverlay SysprofDocumentOverlay;
|
||||
typedef struct _SysprofDocumentOverlayClass SysprofDocumentOverlayClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_overlay_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint sysprof_document_overlay_get_layer (SysprofDocumentOverlay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_overlay_get_source (SysprofDocumentOverlay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_overlay_get_destination (SysprofDocumentOverlay *self);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentOverlay, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
78
src/libsysprof/sysprof-document-private.h
Normal file
78
src/libsysprof/sysprof-document-private.h
Normal file
@ -0,0 +1,78 @@
|
||||
/* sysprof-document-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <eggbitset.h>
|
||||
|
||||
#include "sysprof-document.h"
|
||||
#include "sysprof-symbolizer.h"
|
||||
#include "sysprof-symbol.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _SysprofDocumentTimedValue
|
||||
{
|
||||
gint64 time;
|
||||
union {
|
||||
gint64 v_int64;
|
||||
double v_double;
|
||||
guint8 v_raw[8];
|
||||
};
|
||||
} 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);
|
||||
SysprofDocument *_sysprof_document_new_finish (GAsyncResult *result,
|
||||
GError **error);
|
||||
void _sysprof_document_set_title (SysprofDocument *self,
|
||||
const char *title);
|
||||
void _sysprof_document_symbolize_async (SysprofDocument *self,
|
||||
SysprofSymbolizer *symbolizer,
|
||||
ProgressFunc progress_func,
|
||||
gpointer progress_data,
|
||||
GDestroyNotify progress_data_destroy,
|
||||
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);
|
||||
GRefString *_sysprof_document_ref_string (SysprofDocument *self,
|
||||
const char *name);
|
||||
EggBitset *_sysprof_document_traceables (SysprofDocument *self);
|
||||
SysprofSymbol *_sysprof_document_process_symbol (SysprofDocument *self,
|
||||
int pid);
|
||||
SysprofSymbol *_sysprof_document_thread_symbol (SysprofDocument *self,
|
||||
int pid,
|
||||
int tid);
|
||||
SysprofSymbol *_sysprof_document_kernel_symbol (SysprofDocument *self);
|
||||
|
||||
G_END_DECLS
|
||||
32
src/libsysprof/sysprof-document-process-private.h
Normal file
32
src/libsysprof/sysprof-document-process-private.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* sysprof-document-process-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-process.h"
|
||||
#include "sysprof-process-info-private.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
SysprofProcessInfo *_sysprof_document_process_get_info (SysprofDocumentProcess *self);
|
||||
void _sysprof_document_process_set_info (SysprofDocumentProcess *self,
|
||||
SysprofProcessInfo *process_info);
|
||||
|
||||
G_END_DECLS
|
||||
323
src/libsysprof/sysprof-document-process.c
Normal file
323
src/libsysprof/sysprof-document-process.c
Normal file
@ -0,0 +1,323 @@
|
||||
/* sysprof-document-process.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
#include "sysprof-document-process-private.h"
|
||||
#include "sysprof-mount.h"
|
||||
#include "sysprof-thread-info.h"
|
||||
|
||||
struct _SysprofDocumentProcess
|
||||
{
|
||||
SysprofDocumentFrame parent_instance;
|
||||
SysprofProcessInfo *process_info;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentProcessClass
|
||||
{
|
||||
SysprofDocumentFrameClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_COMMAND_LINE,
|
||||
PROP_DURATION,
|
||||
PROP_MEMORY_MAPS,
|
||||
PROP_MOUNTS,
|
||||
PROP_EXIT_TIME,
|
||||
PROP_THREADS,
|
||||
PROP_TITLE,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentProcess, sysprof_document_process, SYSPROF_TYPE_DOCUMENT_FRAME)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_document_process_finalize (GObject *object)
|
||||
{
|
||||
SysprofDocumentProcess *self = (SysprofDocumentProcess *)object;
|
||||
|
||||
g_clear_pointer (&self->process_info, sysprof_process_info_unref);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_document_process_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_process_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentProcess *self = SYSPROF_DOCUMENT_PROCESS (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_COMMAND_LINE:
|
||||
g_value_set_string (value, sysprof_document_process_get_command_line (self));
|
||||
break;
|
||||
|
||||
case PROP_DURATION:
|
||||
g_value_set_int64 (value, sysprof_document_process_get_duration (self));
|
||||
break;
|
||||
|
||||
case PROP_EXIT_TIME:
|
||||
g_value_set_int64 (value, sysprof_document_process_get_exit_time (self));
|
||||
break;
|
||||
|
||||
case PROP_MEMORY_MAPS:
|
||||
g_value_take_object (value, sysprof_document_process_list_memory_maps (self));
|
||||
break;
|
||||
|
||||
case PROP_MOUNTS:
|
||||
g_value_take_object (value, sysprof_document_process_list_mounts (self));
|
||||
break;
|
||||
|
||||
case PROP_THREADS:
|
||||
g_value_take_object (value, sysprof_document_process_list_threads (self));
|
||||
break;
|
||||
|
||||
case PROP_TITLE:
|
||||
g_value_take_string (value, sysprof_document_process_dup_title (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_process_class_init (SysprofDocumentProcessClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_document_process_finalize;
|
||||
object_class->get_property = sysprof_document_process_get_property;
|
||||
|
||||
properties [PROP_COMMAND_LINE] =
|
||||
g_param_spec_string ("command-line", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_DURATION] =
|
||||
g_param_spec_int64 ("duration", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_EXIT_TIME] =
|
||||
g_param_spec_int64 ("exit-time", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_MEMORY_MAPS] =
|
||||
g_param_spec_object ("memory-maps", NULL, NULL,
|
||||
G_TYPE_LIST_MODEL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_MOUNTS] =
|
||||
g_param_spec_object ("mounts", NULL, NULL,
|
||||
G_TYPE_LIST_MODEL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_THREADS] =
|
||||
g_param_spec_object ("threads", NULL, NULL,
|
||||
G_TYPE_LIST_MODEL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_TITLE] =
|
||||
g_param_spec_string ("title", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_process_init (SysprofDocumentProcess *self)
|
||||
{
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_document_process_get_command_line (SysprofDocumentProcess *self)
|
||||
{
|
||||
const SysprofCaptureProcess *proc;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_PROCESS (self), 0);
|
||||
|
||||
proc = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureProcess);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_CSTRING (self, proc->cmdline);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_process_list_memory_maps:
|
||||
* @self: a #SysprofDocumentProcess
|
||||
*
|
||||
* Lists the #SysprofDocumentMmap that are associated with the process.
|
||||
*
|
||||
* Returns: (transfer full): a #GListModel of #SysprofDocumentMmap
|
||||
*/
|
||||
GListModel *
|
||||
sysprof_document_process_list_memory_maps (SysprofDocumentProcess *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_PROCESS (self), NULL);
|
||||
|
||||
if (self->process_info == NULL)
|
||||
return G_LIST_MODEL (g_list_store_new (SYSPROF_TYPE_DOCUMENT_MMAP));
|
||||
|
||||
return g_object_ref (G_LIST_MODEL (self->process_info->address_layout));
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_process_list_mounts:
|
||||
* @self: a #SysprofDocumentProcess
|
||||
*
|
||||
* Lists the #SysprofMount that are associated with the process.
|
||||
*
|
||||
* Returns: (transfer full): a #GListModel of #SysprofMount
|
||||
*/
|
||||
GListModel *
|
||||
sysprof_document_process_list_mounts (SysprofDocumentProcess *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_PROCESS (self), NULL);
|
||||
|
||||
if (self->process_info == NULL)
|
||||
return G_LIST_MODEL (g_list_store_new (SYSPROF_TYPE_MOUNT));
|
||||
|
||||
return g_object_ref (G_LIST_MODEL (self->process_info->mount_namespace));
|
||||
}
|
||||
|
||||
SysprofProcessInfo *
|
||||
_sysprof_document_process_get_info (SysprofDocumentProcess *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_PROCESS (self), NULL);
|
||||
|
||||
return self->process_info;
|
||||
}
|
||||
|
||||
void
|
||||
_sysprof_document_process_set_info (SysprofDocumentProcess *self,
|
||||
SysprofProcessInfo *process_info)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_DOCUMENT_PROCESS (self));
|
||||
g_return_if_fail (process_info != NULL);
|
||||
g_return_if_fail (self->process_info == NULL);
|
||||
|
||||
self->process_info = sysprof_process_info_ref (process_info);
|
||||
}
|
||||
|
||||
gint64
|
||||
sysprof_document_process_get_exit_time (SysprofDocumentProcess *self)
|
||||
{
|
||||
gint64 exit_time = 0;
|
||||
gint64 t;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_PROCESS (self), 0);
|
||||
|
||||
if (self->process_info != NULL)
|
||||
exit_time = self->process_info->exit_time;
|
||||
|
||||
t = sysprof_document_frame_get_time (SYSPROF_DOCUMENT_FRAME (self));
|
||||
|
||||
return MAX (t, exit_time);
|
||||
}
|
||||
|
||||
gint64
|
||||
sysprof_document_process_get_duration (SysprofDocumentProcess *self)
|
||||
{
|
||||
gint64 t;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_PROCESS (self), 0);
|
||||
|
||||
t = sysprof_document_frame_get_time (SYSPROF_DOCUMENT_FRAME (self));
|
||||
|
||||
return sysprof_document_process_get_exit_time (self) - t;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_process_dup_title:
|
||||
* @self: a #SysprofDocumentProcess
|
||||
*
|
||||
* Gets a suitable title for the process.
|
||||
*
|
||||
* Returns: (transfer full): a string containing a process title
|
||||
*/
|
||||
char *
|
||||
sysprof_document_process_dup_title (SysprofDocumentProcess *self)
|
||||
{
|
||||
const char *command_line;
|
||||
int pid;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_PROCESS (self), NULL);
|
||||
|
||||
pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (self));
|
||||
|
||||
if ((command_line = sysprof_document_process_get_command_line (self)))
|
||||
return g_strdup_printf (_("%s [Process %d]"), command_line, pid);
|
||||
|
||||
return g_strdup_printf (_("Process %d"), pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_document_process_list_threads:
|
||||
* @self: a #SysprofDocumentProcess
|
||||
*
|
||||
* Gets the list of threads for the process.
|
||||
*
|
||||
* Returns: (transfer full): a #GListModel of #SysprofThreadInfo.
|
||||
*/
|
||||
GListModel *
|
||||
sysprof_document_process_list_threads (SysprofDocumentProcess *self)
|
||||
{
|
||||
GListStore *store;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_PROCESS (self), NULL);
|
||||
|
||||
store = g_list_store_new (SYSPROF_TYPE_THREAD_INFO);
|
||||
|
||||
if (self->process_info != NULL)
|
||||
{
|
||||
g_autoptr(GPtrArray) threads = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
EggBitsetIter iter;
|
||||
guint i;
|
||||
|
||||
if (egg_bitset_iter_init_first (&iter, self->process_info->thread_ids, &i))
|
||||
{
|
||||
do
|
||||
{
|
||||
g_ptr_array_add (threads,
|
||||
g_object_new (SYSPROF_TYPE_THREAD_INFO,
|
||||
"process", self,
|
||||
"thread-id", i,
|
||||
NULL));
|
||||
}
|
||||
while (egg_bitset_iter_next (&iter, &i));
|
||||
}
|
||||
|
||||
if (threads->len > 0)
|
||||
g_list_store_splice (store, 0, 0, threads->pdata, threads->len);
|
||||
}
|
||||
|
||||
return G_LIST_MODEL (store);
|
||||
}
|
||||
57
src/libsysprof/sysprof-document-process.h
Normal file
57
src/libsysprof/sysprof-document-process.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* sysprof-document-process.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_PROCESS (sysprof_document_process_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_PROCESS(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_PROCESS)
|
||||
#define SYSPROF_DOCUMENT_PROCESS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_PROCESS, SysprofDocumentProcess)
|
||||
#define SYSPROF_DOCUMENT_PROCESS_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_PROCESS, SysprofDocumentProcessClass)
|
||||
|
||||
typedef struct _SysprofDocumentProcess SysprofDocumentProcess;
|
||||
typedef struct _SysprofDocumentProcessClass SysprofDocumentProcessClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_process_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char *sysprof_document_process_get_command_line (SysprofDocumentProcess *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gint64 sysprof_document_process_get_exit_time (SysprofDocumentProcess *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gint64 sysprof_document_process_get_duration (SysprofDocumentProcess *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
char *sysprof_document_process_dup_title (SysprofDocumentProcess *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_process_list_memory_maps (SysprofDocumentProcess *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_process_list_mounts (SysprofDocumentProcess *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_process_list_threads (SysprofDocumentProcess *self);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentProcess, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
170
src/libsysprof/sysprof-document-sample.c
Normal file
170
src/libsysprof/sysprof-document-sample.c
Normal file
@ -0,0 +1,170 @@
|
||||
/* sysprof-document-sample.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-document-frame-private.h"
|
||||
|
||||
#include "sysprof-document-sample.h"
|
||||
#include "sysprof-document-traceable.h"
|
||||
|
||||
struct _SysprofDocumentSample
|
||||
{
|
||||
SysprofDocumentFrame parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofDocumentSampleClass
|
||||
{
|
||||
SysprofDocumentFrameClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_STACK_DEPTH,
|
||||
PROP_THREAD_ID,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static guint
|
||||
sysprof_document_sample_get_stack_depth (SysprofDocumentTraceable *traceable)
|
||||
{
|
||||
const SysprofCaptureSample *sample = SYSPROF_DOCUMENT_FRAME_GET (traceable, SysprofCaptureSample);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_UINT16 (traceable, sample->n_addrs);
|
||||
}
|
||||
|
||||
static guint64
|
||||
sysprof_document_sample_get_stack_address (SysprofDocumentTraceable *traceable,
|
||||
guint position)
|
||||
{
|
||||
const SysprofCaptureSample *sample = SYSPROF_DOCUMENT_FRAME_GET (traceable, SysprofCaptureSample);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_UINT16 (traceable, sample->addrs[position]);
|
||||
}
|
||||
|
||||
static guint
|
||||
sysprof_document_sample_get_stack_addresses (SysprofDocumentTraceable *traceable,
|
||||
guint64 *addresses,
|
||||
guint n_addresses)
|
||||
{
|
||||
const SysprofCaptureSample *sample = SYSPROF_DOCUMENT_FRAME_GET (traceable, SysprofCaptureSample);
|
||||
guint depth = MIN (n_addresses, SYSPROF_DOCUMENT_FRAME_UINT16 (traceable, sample->n_addrs));
|
||||
|
||||
for (guint i = 0; i < depth; i++)
|
||||
addresses[i] = SYSPROF_DOCUMENT_FRAME_UINT64 (traceable, sample->addrs[i]);
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
static int
|
||||
sysprof_document_sample_get_thread_id (SysprofDocumentTraceable *traceable)
|
||||
{
|
||||
SysprofDocumentSample *self = (SysprofDocumentSample *)traceable;
|
||||
const SysprofCaptureSample *sample;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_SAMPLE (self), -1);
|
||||
|
||||
sample = SYSPROF_DOCUMENT_FRAME_GET (self, SysprofCaptureSample);
|
||||
|
||||
return SYSPROF_DOCUMENT_FRAME_INT32 (self, sample->tid);
|
||||
}
|
||||
|
||||
static void
|
||||
traceable_iface_init (SysprofDocumentTraceableInterface *iface)
|
||||
{
|
||||
iface->get_stack_depth = sysprof_document_sample_get_stack_depth;
|
||||
iface->get_stack_address = sysprof_document_sample_get_stack_address;
|
||||
iface->get_stack_addresses = sysprof_document_sample_get_stack_addresses;
|
||||
iface->get_thread_id = sysprof_document_sample_get_thread_id;
|
||||
}
|
||||
|
||||
G_DEFINE_FINAL_TYPE_WITH_CODE (SysprofDocumentSample, sysprof_document_sample, SYSPROF_TYPE_DOCUMENT_FRAME,
|
||||
G_IMPLEMENT_INTERFACE (SYSPROF_TYPE_DOCUMENT_TRACEABLE, traceable_iface_init))
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_document_sample_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofDocumentSample *self = SYSPROF_DOCUMENT_SAMPLE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_STACK_DEPTH:
|
||||
g_value_set_uint (value, sysprof_document_traceable_get_stack_depth (SYSPROF_DOCUMENT_TRACEABLE (self)));
|
||||
break;
|
||||
|
||||
case PROP_THREAD_ID:
|
||||
g_value_set_int (value, sysprof_document_sample_get_thread_id (SYSPROF_DOCUMENT_TRACEABLE (self)));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_sample_class_init (SysprofDocumentSampleClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
SysprofDocumentFrameClass *document_frame_class = SYSPROF_DOCUMENT_FRAME_CLASS (klass);
|
||||
|
||||
object_class->get_property = sysprof_document_sample_get_property;
|
||||
|
||||
document_frame_class->type_name = N_("Sample");
|
||||
|
||||
/**
|
||||
* SysprofDocumentSample:thread-id:
|
||||
*
|
||||
* The thread-id where the sample occurred.
|
||||
*
|
||||
* On Linux, this is generally set to the value of gettid().
|
||||
*
|
||||
* Since: 45
|
||||
*/
|
||||
properties [PROP_THREAD_ID] =
|
||||
g_param_spec_int ("thread-id", NULL, NULL,
|
||||
-1, G_MAXINT32, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* SysprofDocumentSample:stack-depth:
|
||||
*
|
||||
* The depth of the stack trace.
|
||||
*
|
||||
* Since: 45
|
||||
*/
|
||||
properties [PROP_STACK_DEPTH] =
|
||||
g_param_spec_uint ("stack-depth", NULL, NULL,
|
||||
0, G_MAXUINT32, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_sample_init (SysprofDocumentSample *self)
|
||||
{
|
||||
}
|
||||
42
src/libsysprof/sysprof-document-sample.h
Normal file
42
src/libsysprof/sysprof-document-sample.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* sysprof-document-sample.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_SAMPLE (sysprof_document_sample_get_type())
|
||||
#define SYSPROF_IS_DOCUMENT_SAMPLE(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_DOCUMENT_SAMPLE)
|
||||
#define SYSPROF_DOCUMENT_SAMPLE(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_DOCUMENT_SAMPLE, SysprofDocumentSample)
|
||||
#define SYSPROF_DOCUMENT_SAMPLE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_DOCUMENT_SAMPLE, SysprofDocumentSampleClass)
|
||||
|
||||
typedef struct _SysprofDocumentSample SysprofDocumentSample;
|
||||
typedef struct _SysprofDocumentSampleClass SysprofDocumentSampleClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_document_sample_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
int sysprof_document_sample_get_tid (SysprofDocumentSample *self);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentSample, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
59
src/libsysprof/sysprof-document-symbols-private.h
Normal file
59
src/libsysprof/sysprof-document-symbols-private.h
Normal file
@ -0,0 +1,59 @@
|
||||
/* sysprof-document-symbols-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document.h"
|
||||
#include "sysprof-process-info-private.h"
|
||||
#include "sysprof-symbol-cache-private.h"
|
||||
#include "sysprof-symbol.h"
|
||||
#include "sysprof-symbolizer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_SYMBOLS (sysprof_document_symbols_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofDocumentSymbols, sysprof_document_symbols, SYSPROF, DOCUMENT_SYMBOLS, GObject)
|
||||
|
||||
struct _SysprofDocumentSymbols
|
||||
{
|
||||
GObject parent_instance;
|
||||
SysprofSymbol *context_switches[SYSPROF_ADDRESS_CONTEXT_GUEST_USER+1];
|
||||
SysprofSymbolCache *kernel_symbols;
|
||||
};
|
||||
|
||||
void _sysprof_document_symbols_new (SysprofDocument *document,
|
||||
SysprofStrings *strings,
|
||||
SysprofSymbolizer *symbolizer,
|
||||
GHashTable *pid_to_process_info,
|
||||
ProgressFunc progress_func,
|
||||
gpointer progress_data,
|
||||
GDestroyNotify progress_data_destroy,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
SysprofDocumentSymbols *_sysprof_document_symbols_new_finish (GAsyncResult *result,
|
||||
GError **error);
|
||||
SysprofSymbol *_sysprof_document_symbols_lookup (SysprofDocumentSymbols *symbols,
|
||||
const SysprofProcessInfo *process_info,
|
||||
SysprofAddressContext context,
|
||||
SysprofAddress address);
|
||||
|
||||
G_END_DECLS
|
||||
307
src/libsysprof/sysprof-document-symbols.c
Normal file
307
src/libsysprof/sysprof-document-symbols.c
Normal file
@ -0,0 +1,307 @@
|
||||
/* sysprof-document-symbols.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-address-layout-private.h"
|
||||
#include "sysprof-document-private.h"
|
||||
#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-symbolizer-private.h"
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofDocumentSymbols, sysprof_document_symbols, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
sysprof_document_symbols_finalize (GObject *object)
|
||||
{
|
||||
SysprofDocumentSymbols *self = (SysprofDocumentSymbols *)object;
|
||||
|
||||
for (guint i = 0; i < G_N_ELEMENTS (self->context_switches); i++)
|
||||
g_clear_object (&self->context_switches[i]);
|
||||
|
||||
g_clear_object (&self->kernel_symbols);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_document_symbols_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_symbols_class_init (SysprofDocumentSymbolsClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_document_symbols_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_symbols_init (SysprofDocumentSymbols *self)
|
||||
{
|
||||
self->kernel_symbols = sysprof_symbol_cache_new ();
|
||||
}
|
||||
|
||||
typedef struct _Symbolize
|
||||
{
|
||||
SysprofDocument *document;
|
||||
SysprofSymbolizer *symbolizer;
|
||||
SysprofDocumentSymbols *symbols;
|
||||
SysprofStrings *strings;
|
||||
GHashTable *pid_to_process_info;
|
||||
ProgressFunc progress_func;
|
||||
gpointer progress_data;
|
||||
GDestroyNotify progress_data_destroy;
|
||||
} Symbolize;
|
||||
|
||||
static void
|
||||
symbolize_free (Symbolize *state)
|
||||
{
|
||||
if (state->progress_data_destroy)
|
||||
state->progress_data_destroy (state->progress_data);
|
||||
g_clear_object (&state->document);
|
||||
g_clear_object (&state->symbolizer);
|
||||
g_clear_object (&state->symbols);
|
||||
g_clear_pointer (&state->strings, sysprof_strings_unref);
|
||||
g_clear_pointer (&state->pid_to_process_info, g_hash_table_unref);
|
||||
g_free (state);
|
||||
}
|
||||
|
||||
static void
|
||||
add_traceable (SysprofDocumentSymbols *self,
|
||||
SysprofStrings *strings,
|
||||
SysprofProcessInfo *process_info,
|
||||
SysprofDocumentTraceable *traceable,
|
||||
SysprofSymbolizer *symbolizer)
|
||||
{
|
||||
SysprofAddressContext last_context;
|
||||
guint64 *addresses;
|
||||
guint n_addresses;
|
||||
|
||||
g_assert (SYSPROF_IS_DOCUMENT_TRACEABLE (traceable));
|
||||
g_assert (SYSPROF_IS_SYMBOLIZER (symbolizer));
|
||||
|
||||
n_addresses = sysprof_document_traceable_get_stack_depth (traceable);
|
||||
addresses = g_alloca (sizeof (guint64) * n_addresses);
|
||||
sysprof_document_traceable_get_stack_addresses (traceable, addresses, n_addresses);
|
||||
|
||||
last_context = SYSPROF_ADDRESS_CONTEXT_NONE;
|
||||
|
||||
for (guint i = 0; i < n_addresses; i++)
|
||||
{
|
||||
SysprofAddress address = addresses[i];
|
||||
SysprofAddressContext context = SYSPROF_ADDRESS_CONTEXT_NONE;
|
||||
|
||||
if (sysprof_address_is_context_switch (address, &context))
|
||||
{
|
||||
last_context = context;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (last_context == SYSPROF_ADDRESS_CONTEXT_KERNEL)
|
||||
{
|
||||
g_autoptr(SysprofSymbol) symbol = NULL;
|
||||
|
||||
if (sysprof_symbol_cache_lookup (self->kernel_symbols, address) != NULL)
|
||||
continue;
|
||||
|
||||
if ((symbol = _sysprof_symbolizer_symbolize (symbolizer, strings, process_info, last_context, address)))
|
||||
sysprof_symbol_cache_take (self->kernel_symbols, g_steal_pointer (&symbol));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autoptr(SysprofSymbol) symbol = NULL;
|
||||
|
||||
if (process_info != NULL &&
|
||||
sysprof_symbol_cache_lookup (process_info->symbol_cache, address) != NULL)
|
||||
continue;
|
||||
|
||||
if ((symbol = _sysprof_symbolizer_symbolize (symbolizer, strings, process_info, last_context, address)))
|
||||
sysprof_symbol_cache_take (process_info->symbol_cache, g_steal_pointer (&symbol));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_document_symbols_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
static const struct {
|
||||
const char *name;
|
||||
guint value;
|
||||
} context_switches[] = {
|
||||
{ "- - Hypervisor - -", SYSPROF_ADDRESS_CONTEXT_HYPERVISOR },
|
||||
{ "- - Kernel - -", SYSPROF_ADDRESS_CONTEXT_KERNEL },
|
||||
{ "- - User - -", SYSPROF_ADDRESS_CONTEXT_USER },
|
||||
{ "- - Guest - -", SYSPROF_ADDRESS_CONTEXT_GUEST },
|
||||
{ "- - Guest Kernel - -", SYSPROF_ADDRESS_CONTEXT_GUEST_KERNEL },
|
||||
{ "- - Guest User - -", SYSPROF_ADDRESS_CONTEXT_GUEST_USER },
|
||||
};
|
||||
g_autoptr(GRefString) context_switch = g_ref_string_new_intern ("Context Switch");
|
||||
Symbolize *state = task_data;
|
||||
EggBitsetIter iter;
|
||||
EggBitset *bitset;
|
||||
GListModel *model;
|
||||
guint count = 0;
|
||||
guint i;
|
||||
|
||||
g_assert (source_object == NULL);
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
g_assert (state != NULL);
|
||||
g_assert (SYSPROF_IS_DOCUMENT (state->document));
|
||||
g_assert (SYSPROF_IS_SYMBOLIZER (state->symbolizer));
|
||||
g_assert (SYSPROF_IS_DOCUMENT_SYMBOLS (state->symbols));
|
||||
|
||||
bitset = _sysprof_document_traceables (state->document);
|
||||
model = G_LIST_MODEL (state->document);
|
||||
|
||||
/* Create static symbols for context switch use */
|
||||
for (guint cs = 0; cs < G_N_ELEMENTS (context_switches); cs++)
|
||||
{
|
||||
g_autoptr(SysprofSymbol) symbol = _sysprof_symbol_new (g_ref_string_new_intern (context_switches[cs].name),
|
||||
NULL,
|
||||
g_ref_string_acquire (context_switch),
|
||||
0, 0,
|
||||
SYSPROF_SYMBOL_KIND_CONTEXT_SWITCH);
|
||||
|
||||
/* TODO: It would be nice if we had enough insight from the capture header
|
||||
* as to the host system, so we can show "vmlinuz" and "Linux" respectively
|
||||
* for binary-path and binary-nick when the capture came from Linux.
|
||||
*/
|
||||
|
||||
state->symbols->context_switches[context_switches[cs].value] = g_steal_pointer (&symbol);
|
||||
}
|
||||
|
||||
/* Walk through the available traceables which need symbols extracted */
|
||||
if (!SYSPROF_IS_NO_SYMBOLIZER (state->symbolizer) &&
|
||||
egg_bitset_iter_init_first (&iter, bitset, &i))
|
||||
{
|
||||
guint n_items = egg_bitset_get_size (bitset);
|
||||
|
||||
do
|
||||
{
|
||||
g_autoptr(SysprofDocumentTraceable) traceable = g_list_model_get_item (model, i);
|
||||
int pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable));
|
||||
SysprofProcessInfo *process_info = g_hash_table_lookup (state->pid_to_process_info, GINT_TO_POINTER (pid));
|
||||
|
||||
add_traceable (state->symbols,
|
||||
state->strings,
|
||||
process_info,
|
||||
traceable,
|
||||
state->symbolizer);
|
||||
|
||||
count++;
|
||||
|
||||
if (state->progress_func != NULL && count % 100 == 0)
|
||||
state->progress_func (count / (double)n_items, _("Symbolizing stack traces"), state->progress_data);
|
||||
}
|
||||
while (egg_bitset_iter_next (&iter, &i));
|
||||
}
|
||||
|
||||
g_task_return_pointer (task,
|
||||
g_object_ref (state->symbols),
|
||||
g_object_unref);
|
||||
}
|
||||
|
||||
void
|
||||
_sysprof_document_symbols_new (SysprofDocument *document,
|
||||
SysprofStrings *strings,
|
||||
SysprofSymbolizer *symbolizer,
|
||||
GHashTable *pid_to_process_info,
|
||||
ProgressFunc progress_func,
|
||||
gpointer progress_data,
|
||||
GDestroyNotify progress_data_destroy,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Symbolize *state;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_DOCUMENT (document));
|
||||
g_return_if_fail (SYSPROF_IS_SYMBOLIZER (symbolizer));
|
||||
|
||||
state = g_new0 (Symbolize, 1);
|
||||
state->document = g_object_ref (document);
|
||||
state->symbolizer = g_object_ref (symbolizer);
|
||||
state->symbols = g_object_new (SYSPROF_TYPE_DOCUMENT_SYMBOLS, NULL);
|
||||
state->strings = sysprof_strings_ref (strings);
|
||||
state->pid_to_process_info = g_hash_table_ref (pid_to_process_info);
|
||||
state->progress_func = progress_func;
|
||||
state->progress_data = progress_data;
|
||||
state->progress_data_destroy = progress_data_destroy;
|
||||
|
||||
task = g_task_new (NULL, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, _sysprof_document_symbols_new);
|
||||
g_task_set_task_data (task, state, (GDestroyNotify)symbolize_free);
|
||||
g_task_run_in_thread (task, sysprof_document_symbols_worker);
|
||||
}
|
||||
|
||||
SysprofDocumentSymbols *
|
||||
_sysprof_document_symbols_new_finish (GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_TASK (result), NULL);
|
||||
g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
|
||||
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == _sysprof_document_symbols_new, NULL);
|
||||
|
||||
return g_task_propagate_pointer (G_TASK (result), error);
|
||||
}
|
||||
|
||||
/**
|
||||
* _sysprof_document_symbols_lookup:
|
||||
* @self: a #SysprofDocumentSymbols
|
||||
* @process_info: (nullable): the process info if necessary
|
||||
* @context: the #SysprofAddressContext for the address
|
||||
* @address: a #SysprofAddress to lookup the symbol for
|
||||
*
|
||||
* Locates the symbol that is found at @address within @context of @pid.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #SysprofSymbol or %NULL
|
||||
*/
|
||||
SysprofSymbol *
|
||||
_sysprof_document_symbols_lookup (SysprofDocumentSymbols *self,
|
||||
const SysprofProcessInfo *process_info,
|
||||
SysprofAddressContext context,
|
||||
SysprofAddress address)
|
||||
{
|
||||
SysprofAddressContext new_context;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_SYMBOLS (self), NULL);
|
||||
g_return_val_if_fail (context <= SYSPROF_ADDRESS_CONTEXT_GUEST_USER, NULL);
|
||||
|
||||
if (context == SYSPROF_ADDRESS_CONTEXT_NONE)
|
||||
context = SYSPROF_ADDRESS_CONTEXT_USER;
|
||||
|
||||
if (sysprof_address_is_context_switch (address, &new_context))
|
||||
return self->context_switches[context];
|
||||
|
||||
if (context == SYSPROF_ADDRESS_CONTEXT_KERNEL)
|
||||
return sysprof_symbol_cache_lookup (self->kernel_symbols, address);
|
||||
|
||||
if (process_info != NULL)
|
||||
return sysprof_symbol_cache_lookup (process_info->symbol_cache, address);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
90
src/libsysprof/sysprof-document-traceable.c
Normal file
90
src/libsysprof/sysprof-document-traceable.c
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* sysprof-document-traceable.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-document-traceable.h"
|
||||
|
||||
G_DEFINE_INTERFACE (SysprofDocumentTraceable, sysprof_document_traceable, SYSPROF_TYPE_DOCUMENT_FRAME)
|
||||
|
||||
static void
|
||||
sysprof_document_traceable_default_init (SysprofDocumentTraceableInterface *iface)
|
||||
{
|
||||
/**
|
||||
* SysprofDocumentTraceable:stack-depth:
|
||||
*
|
||||
* The "stack-depth" property contains the number of addresses collected
|
||||
* in the backtrace.
|
||||
*
|
||||
* You may use this value to retrieve the addresses from 0 to ("stack-depth"-1)
|
||||
* by calling sysprof_document_traceable_get_stack_address().
|
||||
*
|
||||
* Since: 45
|
||||
*/
|
||||
g_object_interface_install_property (iface,
|
||||
g_param_spec_uint ("stack-depth", NULL, NULL,
|
||||
0, G_MAXUINT16, 0,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
/**
|
||||
* SysprofDocumentTraceable:thread-id:
|
||||
*
|
||||
* The "thread-id" property contains the thread identifier for the traceable.
|
||||
*
|
||||
* Since: 45
|
||||
*/
|
||||
g_object_interface_install_property (iface,
|
||||
g_param_spec_int ("thread-id", NULL, NULL,
|
||||
-1, G_MAXINT, -1,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
|
||||
}
|
||||
|
||||
guint
|
||||
sysprof_document_traceable_get_stack_depth (SysprofDocumentTraceable *self)
|
||||
{
|
||||
return SYSPROF_DOCUMENT_TRACEABLE_GET_IFACE (self)->get_stack_depth (self);
|
||||
}
|
||||
|
||||
guint64
|
||||
sysprof_document_traceable_get_stack_address (SysprofDocumentTraceable *self,
|
||||
guint position)
|
||||
{
|
||||
return SYSPROF_DOCUMENT_TRACEABLE_GET_IFACE (self)->get_stack_address (self, position);
|
||||
}
|
||||
|
||||
int
|
||||
sysprof_document_traceable_get_thread_id (SysprofDocumentTraceable *self)
|
||||
{
|
||||
return SYSPROF_DOCUMENT_TRACEABLE_GET_IFACE (self)->get_thread_id (self);
|
||||
}
|
||||
|
||||
guint
|
||||
sysprof_document_traceable_get_stack_addresses (SysprofDocumentTraceable *self,
|
||||
guint64 *addresses,
|
||||
guint n_addresses)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_TRACEABLE (self), 0);
|
||||
|
||||
if (addresses == NULL || n_addresses == 0)
|
||||
return 0;
|
||||
|
||||
return SYSPROF_DOCUMENT_TRACEABLE_GET_IFACE (self)->get_stack_addresses (self, addresses, n_addresses);
|
||||
}
|
||||
58
src/libsysprof/sysprof-document-traceable.h
Normal file
58
src/libsysprof/sysprof-document-traceable.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* sysprof-document-traceable.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-document-frame.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT_TRACEABLE (sysprof_document_traceable_get_type ())
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
G_DECLARE_INTERFACE (SysprofDocumentTraceable, sysprof_document_traceable, SYSPROF, DOCUMENT_TRACEABLE, SysprofDocumentFrame)
|
||||
|
||||
struct _SysprofDocumentTraceableInterface
|
||||
{
|
||||
GTypeInterface parent;
|
||||
|
||||
guint (*get_stack_depth) (SysprofDocumentTraceable *self);
|
||||
guint64 (*get_stack_address) (SysprofDocumentTraceable *self,
|
||||
guint position);
|
||||
guint (*get_stack_addresses) (SysprofDocumentTraceable *self,
|
||||
guint64 *addresses,
|
||||
guint n_addresses);
|
||||
int (*get_thread_id) (SysprofDocumentTraceable *self);
|
||||
};
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint sysprof_document_traceable_get_stack_depth (SysprofDocumentTraceable *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint64 sysprof_document_traceable_get_stack_address (SysprofDocumentTraceable *self,
|
||||
guint position);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint sysprof_document_traceable_get_stack_addresses (SysprofDocumentTraceable *self,
|
||||
guint64 *addresses,
|
||||
guint n_addresses);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
int sysprof_document_traceable_get_thread_id (SysprofDocumentTraceable *self);
|
||||
|
||||
G_END_DECLS
|
||||
2456
src/libsysprof/sysprof-document.c
Normal file
2456
src/libsysprof/sysprof-document.c
Normal file
File diff suppressed because it is too large
Load Diff
118
src/libsysprof/sysprof-document.h
Normal file
118
src/libsysprof/sysprof-document.h
Normal file
@ -0,0 +1,118 @@
|
||||
/* sysprof-document.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
#include "sysprof-callgraph.h"
|
||||
#include "sysprof-document-counter.h"
|
||||
#include "sysprof-document-file.h"
|
||||
#include "sysprof-document-traceable.h"
|
||||
#include "sysprof-mark-catalog.h"
|
||||
#include "sysprof-symbol.h"
|
||||
#include "sysprof-time-span.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DOCUMENT (sysprof_document_get_type())
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (SysprofDocument, sysprof_document, SYSPROF, DOCUMENT, GObject)
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
char *sysprof_document_dup_title (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const SysprofTimeSpan *sysprof_document_get_time_span (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofDocumentFile *sysprof_document_lookup_file (SysprofDocument *self,
|
||||
const char *path);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_cpu_info (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_files (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_traceables (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_allocations (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_logs (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_metadata (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_samples (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_samples_with_context_switch (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_samples_without_context_switch (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_processes (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_jitmaps (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_counters (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_marks (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_marks_by_group (SysprofDocument *self,
|
||||
const char *group);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_catalog_marks (SysprofDocument *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofDocumentCounter *sysprof_document_find_counter (SysprofDocument *self,
|
||||
const char *category,
|
||||
const char *name);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_document_list_symbols_in_traceable (SysprofDocument *self,
|
||||
SysprofDocumentTraceable *traceable);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
guint sysprof_document_symbolize_traceable (SysprofDocument *self,
|
||||
SysprofDocumentTraceable *traceable,
|
||||
SysprofSymbol **symbols,
|
||||
guint n_symbols,
|
||||
SysprofAddressContext *final_context);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_document_callgraph_async (SysprofDocument *self,
|
||||
SysprofCallgraphFlags flags,
|
||||
GListModel *traceables,
|
||||
gsize augment_size,
|
||||
SysprofAugmentationFunc augment_func,
|
||||
gpointer augment_func_data,
|
||||
GDestroyNotify augment_func_data_destroy,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofCallgraph *sysprof_document_callgraph_finish (SysprofDocument *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_document_serialize_symbols_async (SysprofDocument *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GBytes *sysprof_document_serialize_symbols_finish (SysprofDocument *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
50
src/libsysprof/sysprof-elf-loader-private.h
Normal file
50
src/libsysprof/sysprof-elf-loader-private.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* sysprof-elf-loader-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "sysprof-elf-private.h"
|
||||
#include "sysprof-mount-namespace-private.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_ELF_LOADER (sysprof_elf_loader_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofElfLoader, sysprof_elf_loader, SYSPROF, ELF_LOADER, GObject)
|
||||
|
||||
SysprofElfLoader *sysprof_elf_loader_new (void);
|
||||
const char * const *sysprof_elf_loader_get_debug_dirs (SysprofElfLoader *self);
|
||||
void sysprof_elf_loader_set_debug_dirs (SysprofElfLoader *self,
|
||||
const char * const *debug_dirs);
|
||||
const char * const *sysprof_elf_loader_get_external_debug_dirs (SysprofElfLoader *self);
|
||||
void sysprof_elf_loader_set_external_debug_dirs (SysprofElfLoader *self,
|
||||
const char * const *debug_dirs);
|
||||
SysprofElf *sysprof_elf_loader_load (SysprofElfLoader *self,
|
||||
SysprofMountNamespace *mount_namespace,
|
||||
const char *file,
|
||||
const char *build_id,
|
||||
guint64 file_inode,
|
||||
GError **error);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
499
src/libsysprof/sysprof-elf-loader.c
Normal file
499
src/libsysprof/sysprof-elf-loader.c
Normal file
@ -0,0 +1,499 @@
|
||||
/* sysprof-elf-loader.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "sysprof-elf-private.h"
|
||||
#include "sysprof-elf-loader-private.h"
|
||||
#include "sysprof-strings-private.h"
|
||||
|
||||
#define DEFAULT_DEBUG_DIRS SYSPROF_STRV_INIT("/usr/lib/debug")
|
||||
|
||||
struct _SysprofElfLoader
|
||||
{
|
||||
GObject parent_instance;
|
||||
GHashTable *cache;
|
||||
char **debug_dirs;
|
||||
char **external_debug_dirs;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_DEBUG_DIRS,
|
||||
PROP_EXTERNAL_DEBUG_DIRS,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofElfLoader, sysprof_elf_loader, G_TYPE_OBJECT)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
static gboolean in_flatpak;
|
||||
static gboolean in_podman;
|
||||
|
||||
SysprofElfLoader *
|
||||
sysprof_elf_loader_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_ELF_LOADER, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
_g_object_xunref (gpointer data)
|
||||
{
|
||||
if (data != NULL)
|
||||
g_object_unref (data);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_loader_finalize (GObject *object)
|
||||
{
|
||||
SysprofElfLoader *self = (SysprofElfLoader *)object;
|
||||
|
||||
g_clear_pointer (&self->debug_dirs, g_strfreev);
|
||||
g_clear_pointer (&self->external_debug_dirs, g_strfreev);
|
||||
g_clear_pointer (&self->cache, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_elf_loader_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_loader_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofElfLoader *self = SYSPROF_ELF_LOADER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEBUG_DIRS:
|
||||
g_value_set_boxed (value, sysprof_elf_loader_get_debug_dirs (self));
|
||||
break;
|
||||
|
||||
case PROP_EXTERNAL_DEBUG_DIRS:
|
||||
g_value_set_boxed (value, sysprof_elf_loader_get_external_debug_dirs (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_loader_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofElfLoader *self = SYSPROF_ELF_LOADER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEBUG_DIRS:
|
||||
sysprof_elf_loader_set_debug_dirs (self, g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
case PROP_EXTERNAL_DEBUG_DIRS:
|
||||
sysprof_elf_loader_set_external_debug_dirs (self, g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_loader_class_init (SysprofElfLoaderClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_elf_loader_finalize;
|
||||
object_class->get_property = sysprof_elf_loader_get_property;
|
||||
object_class->set_property = sysprof_elf_loader_set_property;
|
||||
|
||||
properties [PROP_DEBUG_DIRS] =
|
||||
g_param_spec_boxed ("debug-dirs", NULL, NULL,
|
||||
G_TYPE_STRV,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_EXTERNAL_DEBUG_DIRS] =
|
||||
g_param_spec_boxed ("external-debug-dirs", NULL, NULL,
|
||||
G_TYPE_STRV,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
in_flatpak = g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS);
|
||||
in_podman = g_file_test ("/run/.containerenv", G_FILE_TEST_EXISTS);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_loader_init (SysprofElfLoader *self)
|
||||
{
|
||||
self->debug_dirs = g_strdupv ((char **)DEFAULT_DEBUG_DIRS);
|
||||
self->cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, _g_object_xunref);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_elf_loader_get_debug_dirs:
|
||||
* @self: a #SysprofElfLoader
|
||||
*
|
||||
* Gets the #SysprofElfLoader:debug-dirs property.
|
||||
*
|
||||
* See sysprof_elf_loader_set_debug_dirs() for information on how
|
||||
* these directories are used.
|
||||
*
|
||||
* Returns: (nullable): an array of debug directories, or %NULL
|
||||
*/
|
||||
const char * const *
|
||||
sysprof_elf_loader_get_debug_dirs (SysprofElfLoader *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ELF_LOADER (self), NULL);
|
||||
|
||||
return (const char * const *)self->debug_dirs;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_elf_loader_set_debug_dirs:
|
||||
* @self: a #SysprofElfLoader
|
||||
* @debug_dirs: the new debug directories to use
|
||||
*
|
||||
* Sets the #SysprofElfLoader:debug-dirs prpoerty.
|
||||
*
|
||||
* If @debug_dirs is %NULL, the default debug directories will
|
||||
* be used.
|
||||
*
|
||||
* These directories will be used to resolve debug symbols within
|
||||
* the mount namespace of the process whose symbols are being
|
||||
* resolved.
|
||||
*
|
||||
* To set a global directory that may contain debug symbols, use
|
||||
* sysprof_elf_loader_set_external_debug_dirs() which can be searched
|
||||
* regardless of what mount namespace the resolving process was in.
|
||||
*/
|
||||
void
|
||||
sysprof_elf_loader_set_debug_dirs (SysprofElfLoader *self,
|
||||
const char * const *debug_dirs)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ELF_LOADER (self));
|
||||
g_return_if_fail (self->debug_dirs != NULL);
|
||||
|
||||
if (sysprof_set_strv (&self->debug_dirs, debug_dirs))
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DEBUG_DIRS]);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_elf_loader_get_external_debug_dirs:
|
||||
* @self: a #SysprofElfLoader
|
||||
*
|
||||
* Gets the #SysprofElfLoader:external-debug-dirs property.
|
||||
*
|
||||
* See sysprof_elf_loader_set_external_debug_dirs() for how this
|
||||
* property is used to locate ELF files.
|
||||
*
|
||||
* Returns: (nullable): an array of external debug directories, or %NULL
|
||||
*/
|
||||
const char * const *
|
||||
sysprof_elf_loader_get_external_debug_dirs (SysprofElfLoader *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ELF_LOADER (self), NULL);
|
||||
|
||||
return (const char * const *)self->external_debug_dirs;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_elf_loader_set_external_debug_dirs:
|
||||
* @self: a #SysprofElfLoader
|
||||
* @external_debug_dirs: (nullable): array of debug directories to resolve
|
||||
* `.gnu_debuglink` references in ELF files.
|
||||
*
|
||||
* Sets the #SysprofElfLoader:external-debug-dirs property.
|
||||
*
|
||||
* This is used to resolve `.gnu_debuglink` files across any process that is
|
||||
* loading ELF files with this #SysprofElfLoader. That allows for symbolizing
|
||||
* a capture file that was recording on a different system for which the
|
||||
* debug symbols only exist locally.
|
||||
*
|
||||
* Note that this has no effect on stack trace unwinding, that must occur
|
||||
* independently of this, when the samples are recorded by the specific
|
||||
* unwinder in use.
|
||||
*/
|
||||
void
|
||||
sysprof_elf_loader_set_external_debug_dirs (SysprofElfLoader *self,
|
||||
const char * const *external_debug_dirs)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ELF_LOADER (self));
|
||||
|
||||
if (sysprof_set_strv (&self->external_debug_dirs, external_debug_dirs))
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_EXTERNAL_DEBUG_DIRS]);
|
||||
}
|
||||
|
||||
static char *
|
||||
access_path_from_container (const char *path)
|
||||
{
|
||||
if ((in_flatpak && !g_str_has_prefix (path, "/home/")) || in_podman)
|
||||
return g_build_filename ("/var/run/host", path, NULL);
|
||||
return g_strdup (path);
|
||||
}
|
||||
|
||||
static SysprofElf *
|
||||
get_deepest_debuglink (SysprofElf *elf)
|
||||
{
|
||||
SysprofElf *debug_link = sysprof_elf_get_debug_link_elf (elf);
|
||||
return debug_link ? get_deepest_debuglink (debug_link) : elf;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
try_load_build_id (SysprofElfLoader *self,
|
||||
SysprofMountNamespace *mount_namespace,
|
||||
SysprofElf *elf,
|
||||
const char *build_id,
|
||||
const char *debug_dir)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ELF_LOADER (self));
|
||||
g_assert (!mount_namespace || SYSPROF_IS_MOUNT_NAMESPACE (mount_namespace));
|
||||
g_assert (SYSPROF_IS_ELF (elf));
|
||||
|
||||
if (build_id && build_id[0] && build_id[1])
|
||||
{
|
||||
char prefix[3] = {build_id[0], build_id[1], 0};
|
||||
g_autofree char *build_id_path = g_build_filename (debug_dir, ".build-id", prefix, build_id, NULL);
|
||||
g_autoptr(SysprofElf) debug_link_elf = sysprof_elf_loader_load (self, mount_namespace, build_id_path, build_id, 0, NULL);
|
||||
|
||||
if (debug_link_elf != NULL)
|
||||
{
|
||||
sysprof_elf_set_debug_link_elf (elf, debug_link_elf);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_loader_annotate (SysprofElfLoader *self,
|
||||
SysprofMountNamespace *mount_namespace,
|
||||
const char *orig_file,
|
||||
SysprofElf *elf,
|
||||
const char *debug_link)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ELF_LOADER (self));
|
||||
g_assert (SYSPROF_IS_MOUNT_NAMESPACE (mount_namespace));
|
||||
g_assert (SYSPROF_IS_ELF (elf));
|
||||
g_assert (debug_link != NULL);
|
||||
|
||||
if (self->debug_dirs != NULL)
|
||||
{
|
||||
for (guint i = 0; self->debug_dirs[i]; i++)
|
||||
{
|
||||
g_autoptr(SysprofElf) debug_link_elf = NULL;
|
||||
g_autofree char *directory_name = NULL;
|
||||
g_autofree char *debug_path = NULL;
|
||||
g_autofree char *container_path = NULL;
|
||||
const char *debug_dir = self->debug_dirs[i];
|
||||
const char *build_id;
|
||||
|
||||
directory_name = g_path_get_dirname (orig_file);
|
||||
debug_path = g_build_filename (debug_dir, directory_name, debug_link, NULL);
|
||||
build_id = sysprof_elf_get_build_id (elf);
|
||||
|
||||
if (try_load_build_id (self, mount_namespace, elf, build_id, debug_dir))
|
||||
return;
|
||||
|
||||
if ((debug_link_elf = sysprof_elf_loader_load (self, mount_namespace, debug_path, build_id, 0, NULL)))
|
||||
{
|
||||
sysprof_elf_set_debug_link_elf (elf, get_deepest_debuglink (debug_link_elf));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self->external_debug_dirs != NULL)
|
||||
{
|
||||
for (guint i = 0; self->external_debug_dirs[i]; i++)
|
||||
{
|
||||
g_autoptr(SysprofElf) debug_link_elf = NULL;
|
||||
g_autofree char *directory_name = NULL;
|
||||
g_autofree char *debug_path = NULL;
|
||||
g_autofree char *container_path = NULL;
|
||||
const char *debug_dir = self->external_debug_dirs[i];
|
||||
const char *build_id;
|
||||
|
||||
directory_name = g_path_get_dirname (orig_file);
|
||||
debug_path = g_build_filename (debug_dir, directory_name, debug_link, NULL);
|
||||
build_id = sysprof_elf_get_build_id (elf);
|
||||
|
||||
if (try_load_build_id (self, NULL, elf, build_id, debug_dir))
|
||||
return;
|
||||
|
||||
if ((debug_link_elf = sysprof_elf_loader_load (self, NULL, debug_path, build_id, 0, NULL)))
|
||||
{
|
||||
sysprof_elf_set_debug_link_elf (elf, get_deepest_debuglink (debug_link_elf));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_file_and_inode (const char *path,
|
||||
GMappedFile **mapped_file,
|
||||
guint64 *file_inode)
|
||||
{
|
||||
struct stat stbuf;
|
||||
int fd;
|
||||
|
||||
g_assert (path != NULL);
|
||||
g_assert (mapped_file != NULL);
|
||||
g_assert (file_inode != NULL);
|
||||
|
||||
*mapped_file = NULL;
|
||||
*file_inode = 0;
|
||||
|
||||
fd = open (path, O_RDONLY|O_CLOEXEC, 0);
|
||||
if (fd == -1)
|
||||
return FALSE;
|
||||
|
||||
if (fstat (fd, &stbuf) == 0)
|
||||
*file_inode = (guint64)stbuf.st_ino;
|
||||
*mapped_file = g_mapped_file_new_from_fd (fd, FALSE, NULL);
|
||||
close (fd);
|
||||
|
||||
return *mapped_file != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_elf_loader_load:
|
||||
* @self: a #SysprofElfLoader
|
||||
* @mount_namespace: a #SysprofMountNamespace for path resolving
|
||||
* @file: the path of the file to load within the mount namespace
|
||||
* @build_id: (nullable): an optional build-id that can be used to resolve
|
||||
* the file alternatively to the file path
|
||||
* @file_inode: expected inode for @file
|
||||
* @error: a location for a #GError, or %NULL
|
||||
*
|
||||
* Attempts to load a #SysprofElf for @file (or optionally by @build_id).
|
||||
*
|
||||
* This attempts to follow `.gnu_debuglink` ELF section headers and attach
|
||||
* them to the resulting #SysprofElf so that additional symbol information
|
||||
* is available.
|
||||
*
|
||||
* Returns: (transfer full): a #SysprofElf, or %NULL if the file could
|
||||
* not be resolved.
|
||||
*/
|
||||
SysprofElf *
|
||||
sysprof_elf_loader_load (SysprofElfLoader *self,
|
||||
SysprofMountNamespace *mount_namespace,
|
||||
const char *file,
|
||||
const char *build_id,
|
||||
guint64 file_inode,
|
||||
GError **error)
|
||||
{
|
||||
const char * const fallback_paths[2] = { file, NULL };
|
||||
g_auto(GStrv) paths = NULL;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ELF_LOADER (self), NULL);
|
||||
g_return_val_if_fail (!mount_namespace || SYSPROF_IS_MOUNT_NAMESPACE (mount_namespace), NULL);
|
||||
|
||||
/* We must translate the file into a number of paths that may possibly
|
||||
* locate the file in the case that there are overlays in the mount
|
||||
* namespace. Each of the paths could be in a lower overlay layer.
|
||||
*
|
||||
* To allow for zero-translation, we allow a NULL mount namespace.
|
||||
* sysprof_elf_loader_annotate() will use that to load from external
|
||||
* directories for which on additional translation is necessary.
|
||||
*/
|
||||
if (mount_namespace == NULL)
|
||||
paths = g_strdupv ((char **)fallback_paths);
|
||||
else
|
||||
paths = sysprof_mount_namespace_translate (mount_namespace, file);
|
||||
|
||||
if (paths == NULL)
|
||||
goto failure;
|
||||
|
||||
for (guint i = 0; paths[i]; i++)
|
||||
{
|
||||
g_autoptr(GMappedFile) mapped_file = NULL;
|
||||
g_autoptr(SysprofElf) elf = NULL;
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
g_autofree char *container_path = NULL;
|
||||
SysprofElf *cached_elf = NULL;
|
||||
const char *path = paths[i];
|
||||
const char *debug_link;
|
||||
guint64 mapped_file_inode;
|
||||
|
||||
if (in_flatpak || in_podman)
|
||||
path = container_path = access_path_from_container (path);
|
||||
|
||||
/* Lookup to see if we've already parsed this ELF and handle cases where
|
||||
* we've failed to load it too. In the case we failed to load a key is
|
||||
* stored in the cache with a NULL value.
|
||||
*/
|
||||
if (g_hash_table_lookup_extended (self->cache, path, NULL, (gpointer *)&cached_elf))
|
||||
{
|
||||
if (cached_elf != NULL)
|
||||
{
|
||||
if (sysprof_elf_matches (cached_elf, file_inode, build_id))
|
||||
return g_object_ref (cached_elf);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Try to mmap the file and parse it. If the parser fails to parse the
|
||||
* section headers, then this probably isn't an ELF file and we should
|
||||
* store a failure record in the cache so that we don't attempt to load
|
||||
* it again.
|
||||
*/
|
||||
if (get_file_and_inode (path, &mapped_file, &mapped_file_inode))
|
||||
elf = sysprof_elf_new (path, g_steal_pointer (&mapped_file), mapped_file_inode, &local_error);
|
||||
|
||||
g_hash_table_insert (self->cache,
|
||||
g_strdup (path),
|
||||
elf ? g_object_ref (elf) : NULL);
|
||||
|
||||
if (elf != NULL)
|
||||
{
|
||||
if (mount_namespace && (debug_link = sysprof_elf_get_debug_link (elf)))
|
||||
sysprof_elf_loader_annotate (self, mount_namespace, file, elf, debug_link);
|
||||
|
||||
/* If we loaded the ELF, but it doesn't match what this request is looking
|
||||
* for in terms of inode/build-id, then we need to bail and not return it.
|
||||
* We can, however, leave it in the cache incase another process/sample
|
||||
* will need the ELF.
|
||||
*/
|
||||
if (!sysprof_elf_matches (elf, file_inode, build_id))
|
||||
g_clear_object (&elf);
|
||||
}
|
||||
|
||||
if (elf != NULL)
|
||||
return g_steal_pointer (&elf);
|
||||
}
|
||||
|
||||
failure:
|
||||
g_set_error_literal (error,
|
||||
G_FILE_ERROR,
|
||||
G_FILE_ERROR_NOENT,
|
||||
"Failed to locate file");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
51
src/libsysprof/sysprof-elf-private.h
Normal file
51
src/libsysprof/sysprof-elf-private.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* sysprof-elf-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_ELF (sysprof_elf_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofElf, sysprof_elf, SYSPROF, ELF, GObject)
|
||||
|
||||
SysprofElf *sysprof_elf_new (const char *filename,
|
||||
GMappedFile *mapped_file,
|
||||
guint64 file_inode,
|
||||
GError **error);
|
||||
gboolean sysprof_elf_matches (SysprofElf *self,
|
||||
guint64 file_inode,
|
||||
const char *build_id);
|
||||
const char *sysprof_elf_get_nick (SysprofElf *self);
|
||||
const char *sysprof_elf_get_file (SysprofElf *self);
|
||||
const char *sysprof_elf_get_build_id (SysprofElf *self);
|
||||
const char *sysprof_elf_get_debug_link (SysprofElf *self);
|
||||
char *sysprof_elf_get_symbol_at_address (SysprofElf *self,
|
||||
guint64 address,
|
||||
guint64 *begin_address,
|
||||
guint64 *end_address,
|
||||
gboolean *is_fallback);
|
||||
SysprofElf *sysprof_elf_get_debug_link_elf (SysprofElf *self);
|
||||
void sysprof_elf_set_debug_link_elf (SysprofElf *self,
|
||||
SysprofElf *debug_link_elf);
|
||||
|
||||
G_END_DECLS
|
||||
312
src/libsysprof/sysprof-elf-symbolizer.c
Normal file
312
src/libsysprof/sysprof-elf-symbolizer.c
Normal file
@ -0,0 +1,312 @@
|
||||
/* sysprof-elf-symbolizer.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-elf-private.h"
|
||||
#include "sysprof-elf-loader-private.h"
|
||||
#include "sysprof-elf-symbolizer.h"
|
||||
#include "sysprof-document-private.h"
|
||||
#include "sysprof-strings-private.h"
|
||||
#include "sysprof-symbolizer-private.h"
|
||||
#include "sysprof-symbol-private.h"
|
||||
|
||||
struct _SysprofElfSymbolizer
|
||||
{
|
||||
SysprofSymbolizer parent_instance;
|
||||
SysprofElfLoader *loader;
|
||||
};
|
||||
|
||||
struct _SysprofElfSymbolizerClass
|
||||
{
|
||||
SysprofSymbolizerClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofElfSymbolizer, sysprof_elf_symbolizer, SYSPROF_TYPE_SYMBOLIZER)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_DEBUG_DIRS,
|
||||
PROP_EXTERNAL_DEBUG_DIRS,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static SysprofSymbol *
|
||||
sysprof_elf_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
|
||||
SysprofStrings *strings,
|
||||
const SysprofProcessInfo *process_info,
|
||||
SysprofAddressContext context,
|
||||
SysprofAddress address)
|
||||
{
|
||||
SysprofElfSymbolizer *self = (SysprofElfSymbolizer *)symbolizer;
|
||||
g_autoptr(SysprofElf) elf = NULL;
|
||||
SysprofDocumentMmap *map;
|
||||
g_autofree char *name = NULL;
|
||||
const char *path;
|
||||
const char *build_id;
|
||||
gboolean is_fallback = FALSE;
|
||||
guint64 map_begin;
|
||||
guint64 map_end;
|
||||
guint64 relative_address;
|
||||
guint64 begin_address;
|
||||
guint64 end_address;
|
||||
guint64 file_inode;
|
||||
guint64 file_offset;
|
||||
SysprofSymbol *ret;
|
||||
|
||||
if (process_info == NULL ||
|
||||
process_info->address_layout == NULL ||
|
||||
process_info->mount_namespace == NULL ||
|
||||
(context != SYSPROF_ADDRESS_CONTEXT_NONE &&
|
||||
context != SYSPROF_ADDRESS_CONTEXT_USER))
|
||||
return NULL;
|
||||
|
||||
/* Always ignore jitmap functions, no matter the ordering */
|
||||
if ((address & 0xFFFFFFFF00000000) == 0xE000000000000000)
|
||||
return NULL;
|
||||
|
||||
/* First find out what was mapped at that address */
|
||||
if (!(map = sysprof_address_layout_lookup (process_info->address_layout, address)))
|
||||
return NULL;
|
||||
|
||||
map_begin = sysprof_document_mmap_get_start_address (map);
|
||||
map_end = sysprof_document_mmap_get_end_address (map);
|
||||
|
||||
g_assert (address >= map_begin);
|
||||
g_assert (address < map_end);
|
||||
|
||||
file_offset = sysprof_document_mmap_get_file_offset (map);
|
||||
|
||||
relative_address = address;
|
||||
relative_address -= map_begin;
|
||||
relative_address += file_offset;
|
||||
|
||||
path = sysprof_document_mmap_get_file (map);
|
||||
build_id = sysprof_document_mmap_get_build_id (map);
|
||||
file_inode = sysprof_document_mmap_get_file_inode (map);
|
||||
|
||||
/* See if we can load an ELF at the path . It will be translated from the
|
||||
* mount namespace into something hopefully we can access.
|
||||
*/
|
||||
if (!(elf = sysprof_elf_loader_load (self->loader,
|
||||
process_info->mount_namespace,
|
||||
path,
|
||||
build_id,
|
||||
file_inode,
|
||||
NULL)))
|
||||
goto fallback;
|
||||
|
||||
/* Try to get the symbol name at the address and the begin/end address
|
||||
* so that it can be inserted into our symbol cache.
|
||||
*/
|
||||
if (!(name = sysprof_elf_get_symbol_at_address (elf,
|
||||
relative_address,
|
||||
&begin_address,
|
||||
&end_address,
|
||||
&is_fallback)))
|
||||
goto fallback;
|
||||
|
||||
/* Sanitize address ranges if we have to. Sometimes that can happen
|
||||
* for us, but it seems to be limited to glibc.
|
||||
*/
|
||||
begin_address = CLAMP (begin_address, file_offset, file_offset + (map_end - map_begin));
|
||||
end_address = CLAMP (end_address, file_offset, file_offset + (map_end - map_begin));
|
||||
if (end_address == begin_address)
|
||||
end_address++;
|
||||
|
||||
ret = _sysprof_symbol_new (sysprof_strings_get (strings, name),
|
||||
sysprof_strings_get (strings, path),
|
||||
sysprof_strings_get (strings, sysprof_elf_get_nick (elf)),
|
||||
map_begin + (begin_address - file_offset),
|
||||
map_begin + (end_address - file_offset),
|
||||
SYSPROF_SYMBOL_KIND_USER);
|
||||
ret->is_fallback = is_fallback;
|
||||
|
||||
return ret;
|
||||
|
||||
fallback:
|
||||
/* Fallback, we failed to locate the symbol within a file we can
|
||||
* access, so tell the user about what file contained the symbol
|
||||
* and where (relative to that file) the IP was.
|
||||
*/
|
||||
name = g_strdup_printf ("In File %s+0x%"G_GINT64_MODIFIER"x",
|
||||
sysprof_document_mmap_get_file (map),
|
||||
relative_address);
|
||||
begin_address = address;
|
||||
end_address = address + 1;
|
||||
|
||||
ret = _sysprof_symbol_new (sysprof_strings_get (strings, name),
|
||||
NULL, NULL, begin_address, end_address,
|
||||
SYSPROF_SYMBOL_KIND_USER);
|
||||
ret->is_fallback = TRUE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_symbolizer_loader_notify_cb (SysprofElfSymbolizer *self,
|
||||
GParamSpec *pspec,
|
||||
SysprofElfLoader *loader)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ELF_SYMBOLIZER (self));
|
||||
g_assert (pspec != NULL);
|
||||
g_assert (SYSPROF_IS_ELF_LOADER (loader));
|
||||
|
||||
if (0) {}
|
||||
else if (g_strcmp0 (pspec->name, "debug-dirs") == 0)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DEBUG_DIRS]);
|
||||
else if (g_strcmp0 (pspec->name, "external-debug-dirs") == 0)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EXTERNAL_DEBUG_DIRS]);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_symbolizer_finalize (GObject *object)
|
||||
{
|
||||
SysprofElfSymbolizer *self = (SysprofElfSymbolizer *)object;
|
||||
|
||||
g_clear_object (&self->loader);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_elf_symbolizer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_symbolizer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofElfSymbolizer *self = SYSPROF_ELF_SYMBOLIZER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEBUG_DIRS:
|
||||
g_value_set_boxed (value, sysprof_elf_symbolizer_get_debug_dirs (self));
|
||||
break;
|
||||
|
||||
case PROP_EXTERNAL_DEBUG_DIRS:
|
||||
g_value_set_boxed (value, sysprof_elf_symbolizer_get_external_debug_dirs (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_symbolizer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofElfSymbolizer *self = SYSPROF_ELF_SYMBOLIZER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEBUG_DIRS:
|
||||
sysprof_elf_symbolizer_set_debug_dirs (self, g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
case PROP_EXTERNAL_DEBUG_DIRS:
|
||||
sysprof_elf_symbolizer_set_external_debug_dirs (self, g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_symbolizer_class_init (SysprofElfSymbolizerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
SysprofSymbolizerClass *symbolizer_class = SYSPROF_SYMBOLIZER_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_elf_symbolizer_finalize;
|
||||
object_class->get_property = sysprof_elf_symbolizer_get_property;
|
||||
object_class->set_property = sysprof_elf_symbolizer_set_property;
|
||||
|
||||
symbolizer_class->symbolize = sysprof_elf_symbolizer_symbolize;
|
||||
|
||||
properties[PROP_DEBUG_DIRS] =
|
||||
g_param_spec_boxed ("debug-dirs", NULL, NULL,
|
||||
G_TYPE_STRV,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties[PROP_EXTERNAL_DEBUG_DIRS] =
|
||||
g_param_spec_boxed ("external-debug-dirs", NULL, NULL,
|
||||
G_TYPE_STRV,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_symbolizer_init (SysprofElfSymbolizer *self)
|
||||
{
|
||||
self->loader = sysprof_elf_loader_new ();
|
||||
|
||||
g_signal_connect_object (self->loader,
|
||||
"notify",
|
||||
G_CALLBACK (sysprof_elf_symbolizer_loader_notify_cb),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
}
|
||||
|
||||
SysprofSymbolizer *
|
||||
sysprof_elf_symbolizer_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_ELF_SYMBOLIZER, NULL);
|
||||
}
|
||||
|
||||
const char * const *
|
||||
sysprof_elf_symbolizer_get_debug_dirs (SysprofElfSymbolizer *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ELF_SYMBOLIZER (self), NULL);
|
||||
|
||||
return sysprof_elf_loader_get_debug_dirs (self->loader);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_elf_symbolizer_set_debug_dirs (SysprofElfSymbolizer *self,
|
||||
const char * const *debug_dirs)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ELF_SYMBOLIZER (self));
|
||||
|
||||
sysprof_elf_loader_set_debug_dirs (self->loader, debug_dirs);
|
||||
}
|
||||
|
||||
const char * const *
|
||||
sysprof_elf_symbolizer_get_external_debug_dirs (SysprofElfSymbolizer *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ELF_SYMBOLIZER (self), NULL);
|
||||
|
||||
return sysprof_elf_loader_get_external_debug_dirs (self->loader);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_elf_symbolizer_set_external_debug_dirs (SysprofElfSymbolizer *self,
|
||||
const char * const *external_debug_dirs)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ELF_SYMBOLIZER (self));
|
||||
|
||||
sysprof_elf_loader_set_external_debug_dirs (self->loader, external_debug_dirs);
|
||||
}
|
||||
52
src/libsysprof/sysprof-elf-symbolizer.h
Normal file
52
src/libsysprof/sysprof-elf-symbolizer.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* sysprof-elf-symbolizer.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-symbolizer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_ELF_SYMBOLIZER (sysprof_elf_symbolizer_get_type())
|
||||
#define SYSPROF_IS_ELF_SYMBOLIZER(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_ELF_SYMBOLIZER)
|
||||
#define SYSPROF_ELF_SYMBOLIZER(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_ELF_SYMBOLIZER, SysprofElfSymbolizer)
|
||||
#define SYSPROF_ELF_SYMBOLIZER_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_ELF_SYMBOLIZER, SysprofElfSymbolizerClass)
|
||||
|
||||
typedef struct _SysprofElfSymbolizer SysprofElfSymbolizer;
|
||||
typedef struct _SysprofElfSymbolizerClass SysprofElfSymbolizerClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_elf_symbolizer_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofSymbolizer *sysprof_elf_symbolizer_new (void);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char * const *sysprof_elf_symbolizer_get_debug_dirs (SysprofElfSymbolizer *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_elf_symbolizer_set_debug_dirs (SysprofElfSymbolizer *self,
|
||||
const char * const *debug_dirs);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
const char * const *sysprof_elf_symbolizer_get_external_debug_dirs (SysprofElfSymbolizer *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_elf_symbolizer_set_external_debug_dirs (SysprofElfSymbolizer *self,
|
||||
const char * const *external_debug_dirs);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofElfSymbolizer, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
498
src/libsysprof/sysprof-elf.c
Normal file
498
src/libsysprof/sysprof-elf.c
Normal file
@ -0,0 +1,498 @@
|
||||
/* sysprof-elf.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "elfparser.h"
|
||||
|
||||
#include "sysprof-elf-private.h"
|
||||
|
||||
struct _SysprofElf
|
||||
{
|
||||
GObject parent_instance;
|
||||
const char *nick;
|
||||
char *build_id;
|
||||
char *file;
|
||||
SysprofElf *debug_link_elf;
|
||||
ElfParser *parser;
|
||||
guint64 file_inode;
|
||||
gulong text_offset;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_BUILD_ID,
|
||||
PROP_DEBUG_LINK,
|
||||
PROP_DEBUG_LINK_ELF,
|
||||
PROP_FILE,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofElf, sysprof_elf, G_TYPE_OBJECT)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
static GHashTable *nicks;
|
||||
static const struct {
|
||||
const char *library;
|
||||
const char *nick;
|
||||
} nick_table[] = {
|
||||
{ "libc.so", "libc" },
|
||||
{ "libffi.so", "libffi" },
|
||||
{ "ld-linux-x86-64.so", "glibc" },
|
||||
{ "libnss_sss.so", "NSS" },
|
||||
{ "libsss_debug.so", "SSSD" },
|
||||
{ "libsss_util.so", "SSSD" },
|
||||
{ "libnss_systemd.so", "NSS" },
|
||||
{ "libpcre2-8.so", "PCRE" },
|
||||
{ "libselinux.so", "SELinux" },
|
||||
{ "libssl3.so", "NSS" },
|
||||
{ "libstdc++.so", "libc" },
|
||||
{ "libsystemd.so", "systemd" },
|
||||
{ "libudev.so", "udev" },
|
||||
{ "libxul.so", "XUL" },
|
||||
{ "libz.so", "Zlib" },
|
||||
{ "libzstd.so", "Zstd" },
|
||||
|
||||
/* GObject */
|
||||
{ "libglib-2.0.so", "GLib" },
|
||||
{ "libgobject-2.0.so", "GObject" },
|
||||
{ "libgio-2.0.so", "Gio" },
|
||||
{ "libgirepository-1.0.so", "Introspection" },
|
||||
|
||||
/* Cairo/Pixman */
|
||||
{ "libcairo-gobject.so", "Cairo" },
|
||||
{ "libcairo.so", "Cairo" },
|
||||
{ "libpixman-1.so", "Pixman" },
|
||||
|
||||
/* Various GNOME Platform Libraries */
|
||||
{ "libdex-1.so", "Dex" },
|
||||
{ "libgjs.so", "GJS" },
|
||||
{ "libgstreamer-1-0.so", "GStreamer" },
|
||||
{ "libgudev-1.0.so", "udev" },
|
||||
{ "libibus-1.0.so", "IBus" },
|
||||
{ "libjson-glib-1.0.so", "JSON-GLib" },
|
||||
{ "libjsonrpc-glib-1.0.so", "JSONRPC-GLib" },
|
||||
{ "libpolkit-agent-1.so", "PolicyKit" },
|
||||
{ "libpolkit-gobject-1.so", "PolicyKit" },
|
||||
{ "libvte-2.91-gtk4.so", "VTE" },
|
||||
{ "libvte-2.91.so", "VTE" },
|
||||
|
||||
/* Pango and Harfbuzz */
|
||||
{ "libfribidi.so", "Fribidi" },
|
||||
{ "libpango-1.0.so", "Pango" },
|
||||
{ "libpangocairo-1.0.so", "Pango" },
|
||||
{ "libpangoft2-1.0.so", "Pango" },
|
||||
{ "libharfbuzz-cairo.so", "Harfbuzz" },
|
||||
{ "libharfbuzz-gobject.so", "Harfbuzz" },
|
||||
{ "libharfbuzz-icu.so", "Harfbuzz" },
|
||||
{ "libharfbuzz-subset.so", "Harfbuzz" },
|
||||
{ "libharfbuzz.so", "Harfbuzz" },
|
||||
|
||||
/* GTK */
|
||||
{ "libgtk-3.so", "GTK 3" },
|
||||
{ "libgdk-3.so", "GTK 3" },
|
||||
{ "libgtk-4.so", "GTK 4" },
|
||||
{ "libgraphene-1.0.so", "Graphene" },
|
||||
{ "libgdk_pixbuf-2.0.so", "GdkPixbuf" },
|
||||
{ "librsvg-2.so", "rsvg" },
|
||||
|
||||
/* Xorg/X11 */
|
||||
{ "libX11-xcb.so", "X11" },
|
||||
{ "libX11.so", "X11" },
|
||||
{ "libxcb.so", "X11" },
|
||||
{ "libxkbcommon.so", "XKB" },
|
||||
|
||||
/* Wayland */
|
||||
{ "libwayland-client.so", "Wayland Client" },
|
||||
{ "libwayland-cursor.so", "Wayland Cursor" },
|
||||
{ "libwayland-egl.so", "Wayland EGL" },
|
||||
{ "libwayland-server.so", "Wayland Server" },
|
||||
|
||||
/* Mutter/Clutter/Shell */
|
||||
{ "libclutter-1.0.so", "Clutter" },
|
||||
{ "libclutter-glx-1.0.so", "Clutter" },
|
||||
{ "libinput.so", "libinput" },
|
||||
{ "libmutter-12.so", "Mutter" },
|
||||
{ "libmutter-cogl-12.so", "Mutter" },
|
||||
{ "libmutter-clutter-12.so", "Mutter" },
|
||||
{ "libst-12.so", "GNOME Shell" },
|
||||
|
||||
/* GtkSourceView */
|
||||
{ "libgtksourceview-3.0.so", "GtkSourceView" },
|
||||
{ "libgtksourceview-4.so", "GtkSourceView" },
|
||||
{ "libgtksourceview-5.so", "GtkSourceView" },
|
||||
|
||||
/* Pipewire and Legacy Audio modules */
|
||||
{ "libasound.so", "ALSA" },
|
||||
{ "libpipewire-0.3.so", "Pipewire" },
|
||||
{ "libpipewire-module-client-node.so", "Pipewire" },
|
||||
{ "libpipewire-module-protocol-pulse.so", "Pipewire" },
|
||||
{ "libpulse.so", "PulseAudio" },
|
||||
{ "libpulsecommon-16.1.so", "PulseAudio" },
|
||||
{ "libspa-alsa.so", "Pipewire" },
|
||||
{ "libspa-audioconvert.so", "Pipewire" },
|
||||
{ "libspa-support.so", "Pipewire" },
|
||||
|
||||
/* OpenGL base libraries */
|
||||
{ "libEGL.so", "EGL" },
|
||||
{ "libGL.so", "GL" },
|
||||
|
||||
/* Mesa and DRI Drivers */
|
||||
{ "crocus_dri.so", "Mesa" },
|
||||
{ "i915_dri.so", "Mesa" },
|
||||
{ "i965_drv_video.so", "Mesa" },
|
||||
{ "iHD_drv_video.so", "Mesa" },
|
||||
{ "iris_dri.so", "Mesa" },
|
||||
{ "kms_swrast_dri.so", "Mesa" },
|
||||
{ "libEGL_mesa.so", "Mesa" },
|
||||
{ "libdrm.so", "Mesa" },
|
||||
{ "nouveau_dri.so", "Mesa" },
|
||||
{ "r300_dri.so", "Mesa" },
|
||||
{ "r600_dri.so", "Mesa" },
|
||||
{ "radeonsi_dri.so", "Mesa" },
|
||||
{ "swrast_dri.so", "Mesa" },
|
||||
{ "virtio_gpu_dri.so", "Mesa" },
|
||||
{ "vmwgfx_dri.so", "Mesa" },
|
||||
{ "zink_dri.so", "Mesa" },
|
||||
};
|
||||
|
||||
static void
|
||||
sysprof_elf_finalize (GObject *object)
|
||||
{
|
||||
SysprofElf *self = (SysprofElf *)object;
|
||||
|
||||
g_clear_pointer (&self->file, g_free);
|
||||
g_clear_pointer (&self->parser, elf_parser_free);
|
||||
g_clear_object (&self->debug_link_elf);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_elf_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofElf *self = SYSPROF_ELF (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_BUILD_ID:
|
||||
g_value_set_string (value, sysprof_elf_get_build_id (self));
|
||||
break;
|
||||
|
||||
case PROP_DEBUG_LINK:
|
||||
g_value_set_string (value, sysprof_elf_get_debug_link (self));
|
||||
break;
|
||||
|
||||
case PROP_DEBUG_LINK_ELF:
|
||||
g_value_set_object (value, sysprof_elf_get_debug_link_elf (self));
|
||||
break;
|
||||
|
||||
case PROP_FILE:
|
||||
g_value_set_string (value, sysprof_elf_get_file (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofElf *self = SYSPROF_ELF (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEBUG_LINK_ELF:
|
||||
sysprof_elf_set_debug_link_elf (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_class_init (SysprofElfClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_elf_finalize;
|
||||
object_class->get_property = sysprof_elf_get_property;
|
||||
object_class->set_property = sysprof_elf_set_property;
|
||||
|
||||
properties [PROP_BUILD_ID] =
|
||||
g_param_spec_string ("build-id", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_DEBUG_LINK] =
|
||||
g_param_spec_string ("debug-link", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_DEBUG_LINK_ELF] =
|
||||
g_param_spec_object ("debug-link-elf", NULL, NULL,
|
||||
SYSPROF_TYPE_ELF,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_FILE] =
|
||||
g_param_spec_string ("file", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
nicks = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
for (guint i = 0; i < G_N_ELEMENTS (nick_table); i++)
|
||||
{
|
||||
g_assert (g_str_has_suffix (nick_table[i].library, ".so"));
|
||||
g_hash_table_insert (nicks,
|
||||
(char *)nick_table[i].library,
|
||||
(char *)nick_table[i].nick);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_elf_init (SysprofElf *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
guess_nick (SysprofElf *self,
|
||||
const char *name,
|
||||
const char *endptr)
|
||||
{
|
||||
char key[32];
|
||||
|
||||
if (endptr <= name)
|
||||
return;
|
||||
|
||||
if (endptr - name >= sizeof key)
|
||||
return;
|
||||
|
||||
memcpy (key, name, endptr-name);
|
||||
key[endptr-name] = 0;
|
||||
|
||||
self->nick = g_hash_table_lookup (nicks, key);
|
||||
}
|
||||
|
||||
SysprofElf *
|
||||
sysprof_elf_new (const char *filename,
|
||||
GMappedFile *mapped_file,
|
||||
guint64 file_inode,
|
||||
GError **error)
|
||||
{
|
||||
SysprofElf *self;
|
||||
ElfParser *parser;
|
||||
|
||||
g_return_val_if_fail (mapped_file != NULL, NULL);
|
||||
|
||||
if (!(parser = elf_parser_new_from_mmap (g_steal_pointer (&mapped_file), error)))
|
||||
return NULL;
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_ELF, NULL);
|
||||
self->file = g_strdup (filename);
|
||||
self->parser = g_steal_pointer (&parser);
|
||||
self->file_inode = file_inode;
|
||||
self->text_offset = elf_parser_get_text_offset (self->parser);
|
||||
|
||||
if (filename != NULL)
|
||||
{
|
||||
const char *base;
|
||||
const char *endptr;
|
||||
|
||||
if ((base = strrchr (filename, '/')))
|
||||
{
|
||||
endptr = strstr (++base, ".so");
|
||||
|
||||
if (endptr != NULL && (endptr[3] == 0 || endptr[3] == '.'))
|
||||
guess_nick (self, base, &endptr[3]);
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_elf_get_file (SysprofElf *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ELF (self), NULL);
|
||||
|
||||
return self->file;
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_elf_get_build_id (SysprofElf *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ELF (self), NULL);
|
||||
|
||||
return elf_parser_get_build_id (self->parser);
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_elf_get_debug_link (SysprofElf *self)
|
||||
{
|
||||
guint crc32;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ELF (self), NULL);
|
||||
|
||||
return elf_parser_get_debug_link (self->parser, &crc32);
|
||||
}
|
||||
|
||||
static char *
|
||||
sysprof_elf_get_symbol_at_address_internal (SysprofElf *self,
|
||||
const char *filename,
|
||||
guint64 address,
|
||||
guint64 *begin_address,
|
||||
guint64 *end_address,
|
||||
guint64 text_offset,
|
||||
gboolean *is_fallback)
|
||||
{
|
||||
const ElfSym *symbol;
|
||||
char *ret = NULL;
|
||||
gulong begin = 0;
|
||||
gulong end = 0;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ELF (self), NULL);
|
||||
|
||||
if (self->debug_link_elf != NULL)
|
||||
{
|
||||
ret = sysprof_elf_get_symbol_at_address_internal (self->debug_link_elf, filename, address, begin_address, end_address, text_offset, is_fallback);
|
||||
|
||||
if (ret != NULL)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((symbol = elf_parser_lookup_symbol (self->parser, address - text_offset)))
|
||||
{
|
||||
const char *name;
|
||||
|
||||
if (begin_address || end_address)
|
||||
{
|
||||
elf_parser_get_sym_address_range (self->parser, symbol, &begin, &end);
|
||||
begin += text_offset;
|
||||
end += text_offset;
|
||||
}
|
||||
|
||||
name = elf_parser_get_sym_name (self->parser, symbol);
|
||||
|
||||
if (name != NULL && name[0] == '_' && name[1] == 'Z')
|
||||
ret = elf_demangle (name);
|
||||
else
|
||||
ret = g_strdup (name);
|
||||
}
|
||||
else
|
||||
{
|
||||
begin = address;
|
||||
end = address + 1;
|
||||
ret = g_strdup_printf ("In File %s+0x%"G_GINT64_MODIFIER"x", filename, address);
|
||||
if (is_fallback)
|
||||
*is_fallback = TRUE;
|
||||
}
|
||||
|
||||
if (begin_address)
|
||||
*begin_address = begin;
|
||||
|
||||
if (end_address)
|
||||
*end_address = end;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
sysprof_elf_get_symbol_at_address (SysprofElf *self,
|
||||
guint64 address,
|
||||
guint64 *begin_address,
|
||||
guint64 *end_address,
|
||||
gboolean *is_fallback)
|
||||
{
|
||||
return sysprof_elf_get_symbol_at_address_internal (self,
|
||||
self->file,
|
||||
address,
|
||||
begin_address,
|
||||
end_address,
|
||||
self->text_offset,
|
||||
is_fallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_elf_get_debug_link_elf:
|
||||
* @self: a #SysprofElf
|
||||
*
|
||||
* Gets a #SysprofElf that was resolved from the `.gnu_debuglink`
|
||||
* ELF section header.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #SysprofElf or %NULL
|
||||
*/
|
||||
SysprofElf *
|
||||
sysprof_elf_get_debug_link_elf (SysprofElf *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ELF (self), NULL);
|
||||
|
||||
return self->debug_link_elf;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_elf_set_debug_link_elf (SysprofElf *self,
|
||||
SysprofElf *debug_link_elf)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ELF (self));
|
||||
g_return_if_fail (!debug_link_elf || SYSPROF_IS_ELF (debug_link_elf));
|
||||
|
||||
if (g_set_object (&self->debug_link_elf, debug_link_elf))
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DEBUG_LINK_ELF]);
|
||||
}
|
||||
|
||||
gboolean
|
||||
sysprof_elf_matches (SysprofElf *self,
|
||||
guint64 file_inode,
|
||||
const char *build_id)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ELF (self), FALSE);
|
||||
|
||||
if (build_id != NULL)
|
||||
{
|
||||
const char *elf_build_id = elf_parser_get_build_id (self->parser);
|
||||
|
||||
/* Not matching build-id, you definitely don't want this ELF */
|
||||
if (elf_build_id != NULL && !g_str_equal (build_id, elf_build_id))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (file_inode && self->file_inode && file_inode != self->file_inode)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const char *
|
||||
sysprof_elf_get_nick (SysprofElf *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ELF (self), NULL);
|
||||
|
||||
return self->nick;
|
||||
}
|
||||
57
src/libsysprof/sysprof-energy-usage.c
Normal file
57
src/libsysprof/sysprof-energy-usage.c
Normal file
@ -0,0 +1,57 @@
|
||||
/* sysprof-energy-usage.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-proxied-instrument-private.h"
|
||||
#include "sysprof-energy-usage.h"
|
||||
|
||||
struct _SysprofEnergyUsage
|
||||
{
|
||||
SysprofProxiedInstrument parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofEnergyUsageClass
|
||||
{
|
||||
SysprofProxiedInstrumentClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofEnergyUsage, sysprof_energy_usage, SYSPROF_TYPE_PROXIED_INSTRUMENT)
|
||||
|
||||
static void
|
||||
sysprof_energy_usage_class_init (SysprofEnergyUsageClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_energy_usage_init (SysprofEnergyUsage *self)
|
||||
{
|
||||
SYSPROF_PROXIED_INSTRUMENT (self)->call_stop_first = TRUE;
|
||||
}
|
||||
|
||||
SysprofInstrument *
|
||||
sysprof_energy_usage_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_ENERGY_USAGE,
|
||||
"bus-type", G_BUS_TYPE_SYSTEM,
|
||||
"bus-name", "org.gnome.Sysprof3",
|
||||
"object-path", "/org/gnome/Sysprof3/RAPL",
|
||||
NULL);
|
||||
}
|
||||
42
src/libsysprof/sysprof-energy-usage.h
Normal file
42
src/libsysprof/sysprof-energy-usage.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* sysprof-energy-usage.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-instrument.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_ENERGY_USAGE (sysprof_energy_usage_get_type())
|
||||
#define SYSPROF_IS_ENERGY_USAGE(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_ENERGY_USAGE)
|
||||
#define SYSPROF_ENERGY_USAGE(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_ENERGY_USAGE, SysprofEnergyUsage)
|
||||
#define SYSPROF_ENERGY_USAGE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_ENERGY_USAGE, SysprofEnergyUsageClass)
|
||||
|
||||
typedef struct _SysprofEnergyUsage SysprofEnergyUsage;
|
||||
typedef struct _SysprofEnergyUsageClass SysprofEnergyUsageClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_energy_usage_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofInstrument *sysprof_energy_usage_new (void);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofEnergyUsage, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
67
src/libsysprof/sysprof-instrument-private.h
Normal file
67
src/libsysprof/sysprof-instrument-private.h
Normal file
@ -0,0 +1,67 @@
|
||||
/* sysprof-instrument-private.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libdex.h>
|
||||
|
||||
#include "sysprof-instrument.h"
|
||||
#include "sysprof-recording.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_INSTRUMENT_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS(obj, SYSPROF_TYPE_INSTRUMENT, SysprofInstrumentClass)
|
||||
|
||||
struct _SysprofInstrument
|
||||
{
|
||||
GObject parent;
|
||||
};
|
||||
|
||||
struct _SysprofInstrumentClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
char **(*list_required_policy) (SysprofInstrument *self);
|
||||
DexFuture *(*prepare) (SysprofInstrument *self,
|
||||
SysprofRecording *recording);
|
||||
DexFuture *(*record) (SysprofInstrument *self,
|
||||
SysprofRecording *recording,
|
||||
GCancellable *cancellable);
|
||||
DexFuture *(*augment) (SysprofInstrument *self,
|
||||
SysprofRecording *recording);
|
||||
DexFuture *(*process_started) (SysprofInstrument *self,
|
||||
SysprofRecording *recording,
|
||||
int pid);
|
||||
};
|
||||
|
||||
DexFuture *_sysprof_instruments_acquire_policy (GPtrArray *instruments,
|
||||
SysprofRecording *recording);
|
||||
DexFuture *_sysprof_instruments_prepare (GPtrArray *instruments,
|
||||
SysprofRecording *recording);
|
||||
DexFuture *_sysprof_instruments_record (GPtrArray *instruments,
|
||||
SysprofRecording *recording,
|
||||
GCancellable *cancellable);
|
||||
DexFuture *_sysprof_instruments_augment (GPtrArray *instruments,
|
||||
SysprofRecording *recording);
|
||||
DexFuture *_sysprof_instruments_process_started (GPtrArray *instruments,
|
||||
SysprofRecording *recording,
|
||||
int pid);
|
||||
|
||||
G_END_DECLS
|
||||
311
src/libsysprof/sysprof-instrument.c
Normal file
311
src/libsysprof/sysprof-instrument.c
Normal file
@ -0,0 +1,311 @@
|
||||
/* sysprof-instrument.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-instrument-private.h"
|
||||
|
||||
#if HAVE_POLKIT
|
||||
# include "sysprof-polkit-private.h"
|
||||
#endif
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (SysprofInstrument, sysprof_instrument, G_TYPE_OBJECT)
|
||||
|
||||
static char **
|
||||
sysprof_instrument_real_list_required_policy (SysprofInstrument *instrument)
|
||||
{
|
||||
g_assert (SYSPROF_IS_INSTRUMENT (instrument));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
sysprof_instrument_real_prepare (SysprofInstrument *instrument,
|
||||
SysprofRecording *recording)
|
||||
{
|
||||
g_assert (SYSPROF_IS_INSTRUMENT (instrument));
|
||||
g_assert (SYSPROF_IS_RECORDING (recording));
|
||||
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
sysprof_instrument_real_record (SysprofInstrument *instrument,
|
||||
SysprofRecording *recording,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
g_assert (SYSPROF_IS_INSTRUMENT (instrument));
|
||||
g_assert (SYSPROF_IS_RECORDING (recording));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_instrument_class_init (SysprofInstrumentClass *klass)
|
||||
{
|
||||
klass->list_required_policy = sysprof_instrument_real_list_required_policy;
|
||||
klass->prepare = sysprof_instrument_real_prepare;
|
||||
klass->record = sysprof_instrument_real_record;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_instrument_init (SysprofInstrument *self)
|
||||
{
|
||||
}
|
||||
|
||||
static char **
|
||||
_sysprof_instrument_list_required_policy (SysprofInstrument *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_INSTRUMENT (self));
|
||||
|
||||
if (SYSPROF_INSTRUMENT_GET_CLASS (self)->list_required_policy)
|
||||
return SYSPROF_INSTRUMENT_GET_CLASS (self)->list_required_policy (self);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
_sysprof_instrument_prepare (SysprofInstrument *self,
|
||||
SysprofRecording *recording)
|
||||
{
|
||||
g_assert (SYSPROF_IS_INSTRUMENT (self));
|
||||
g_assert (SYSPROF_IS_RECORDING (recording));
|
||||
|
||||
if (SYSPROF_INSTRUMENT_GET_CLASS (self)->prepare)
|
||||
return SYSPROF_INSTRUMENT_GET_CLASS (self)->prepare (self, recording);
|
||||
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
_sysprof_instrument_record (SysprofInstrument *self,
|
||||
SysprofRecording *recording,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
g_assert (SYSPROF_IS_INSTRUMENT (self));
|
||||
g_assert (SYSPROF_IS_RECORDING (recording));
|
||||
g_assert (G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
if (SYSPROF_INSTRUMENT_GET_CLASS (self)->record)
|
||||
return SYSPROF_INSTRUMENT_GET_CLASS (self)->record (self, recording, cancellable);
|
||||
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
_sysprof_instrument_augment (SysprofInstrument *self,
|
||||
SysprofRecording *recording)
|
||||
{
|
||||
g_assert (SYSPROF_IS_INSTRUMENT (self));
|
||||
g_assert (SYSPROF_IS_RECORDING (recording));
|
||||
|
||||
if (SYSPROF_INSTRUMENT_GET_CLASS (self)->augment)
|
||||
return SYSPROF_INSTRUMENT_GET_CLASS (self)->augment (self, recording);
|
||||
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
_sysprof_instrument_process_started (SysprofInstrument *self,
|
||||
SysprofRecording *recording,
|
||||
int pid)
|
||||
{
|
||||
g_assert (SYSPROF_IS_INSTRUMENT (self));
|
||||
g_assert (SYSPROF_IS_RECORDING (recording));
|
||||
|
||||
if (SYSPROF_INSTRUMENT_GET_CLASS (self)->process_started)
|
||||
return SYSPROF_INSTRUMENT_GET_CLASS (self)->process_started (self, recording, pid);
|
||||
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
}
|
||||
|
||||
static char **
|
||||
_sysprof_instruments_list_required_policy (GPtrArray *instruments)
|
||||
{
|
||||
g_autoptr(GPtrArray) all_policy = NULL;
|
||||
|
||||
g_return_val_if_fail (instruments != NULL, NULL);
|
||||
|
||||
all_policy = g_ptr_array_new_null_terminated (0, g_free, TRUE);
|
||||
|
||||
for (guint i = 0; i < instruments->len; i++)
|
||||
{
|
||||
SysprofInstrument *instrument = g_ptr_array_index (instruments, i);
|
||||
g_auto(GStrv) policy = _sysprof_instrument_list_required_policy (instrument);
|
||||
|
||||
if (policy == NULL || policy[0] == NULL)
|
||||
continue;
|
||||
|
||||
for (guint j = 0; policy[j]; j++)
|
||||
{
|
||||
gboolean found = FALSE;
|
||||
|
||||
for (guint k = 0; !found && k < all_policy->len; k++)
|
||||
found = strcmp (policy[j], g_ptr_array_index (all_policy, k)) == 0;
|
||||
|
||||
if (!found)
|
||||
g_ptr_array_add (all_policy, g_strdup (policy[j]));
|
||||
}
|
||||
}
|
||||
|
||||
if (all_policy->len == 0)
|
||||
return NULL;
|
||||
|
||||
return (char **)g_ptr_array_free (g_steal_pointer (&all_policy), FALSE);
|
||||
}
|
||||
|
||||
DexFuture *
|
||||
_sysprof_instruments_acquire_policy (GPtrArray *instruments,
|
||||
SysprofRecording *recording)
|
||||
{
|
||||
g_autoptr(GDBusConnection) connection = NULL;
|
||||
g_autoptr(PolkitDetails) details = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_auto(GStrv) required_policy = NULL;
|
||||
|
||||
g_return_val_if_fail (instruments != NULL, NULL);
|
||||
g_return_val_if_fail (SYSPROF_IS_RECORDING (recording), NULL);
|
||||
|
||||
/* Ensure we have access to the System D-Bus so that we can get
|
||||
* access to sysprofd for system information.
|
||||
*/
|
||||
if (!(connection = dex_await_object (dex_bus_get (G_BUS_TYPE_SYSTEM), &error)))
|
||||
return dex_future_new_for_error (g_steal_pointer (&error));
|
||||
|
||||
/* First ensure that all our required policy have been acquired on
|
||||
* the bus so that we don't need to individually acquire them from
|
||||
* each of the instruments.
|
||||
*/
|
||||
if ((required_policy = _sysprof_instruments_list_required_policy (instruments)))
|
||||
{
|
||||
#if HAVE_POLKIT
|
||||
for (guint i = 0; required_policy[i]; i++)
|
||||
{
|
||||
if (!dex_await_boolean (_sysprof_polkit_authorize (connection,
|
||||
required_policy[i],
|
||||
details,
|
||||
TRUE), &error))
|
||||
return dex_future_new_for_error (g_steal_pointer (&error));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
}
|
||||
|
||||
DexFuture *
|
||||
_sysprof_instruments_prepare (GPtrArray *instruments,
|
||||
SysprofRecording *recording)
|
||||
{
|
||||
g_autoptr(GPtrArray) futures = NULL;
|
||||
|
||||
g_return_val_if_fail (instruments != NULL, NULL);
|
||||
g_return_val_if_fail (SYSPROF_IS_RECORDING (recording), NULL);
|
||||
|
||||
futures = g_ptr_array_new_with_free_func (dex_unref);
|
||||
|
||||
for (guint i = 0; i < instruments->len; i++)
|
||||
{
|
||||
SysprofInstrument *instrument = g_ptr_array_index (instruments, i);
|
||||
|
||||
g_ptr_array_add (futures, _sysprof_instrument_prepare (instrument, recording));
|
||||
}
|
||||
|
||||
if (futures->len == 0)
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
|
||||
return dex_future_allv ((DexFuture **)futures->pdata, futures->len);
|
||||
}
|
||||
|
||||
DexFuture *
|
||||
_sysprof_instruments_record (GPtrArray *instruments,
|
||||
SysprofRecording *recording,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
g_autoptr(GPtrArray) futures = NULL;
|
||||
|
||||
g_return_val_if_fail (instruments != NULL, NULL);
|
||||
g_return_val_if_fail (SYSPROF_IS_RECORDING (recording), NULL);
|
||||
g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
|
||||
|
||||
futures = g_ptr_array_new_with_free_func (dex_unref);
|
||||
|
||||
for (guint i = 0; i < instruments->len; i++)
|
||||
{
|
||||
SysprofInstrument *instrument = g_ptr_array_index (instruments, i);
|
||||
|
||||
g_ptr_array_add (futures, _sysprof_instrument_record (instrument, recording, cancellable));
|
||||
}
|
||||
|
||||
if (futures->len == 0)
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
|
||||
return dex_future_allv ((DexFuture **)futures->pdata, futures->len);
|
||||
}
|
||||
|
||||
DexFuture *
|
||||
_sysprof_instruments_augment (GPtrArray *instruments,
|
||||
SysprofRecording *recording)
|
||||
{
|
||||
g_autoptr(GPtrArray) futures = NULL;
|
||||
|
||||
g_return_val_if_fail (instruments != NULL, NULL);
|
||||
g_return_val_if_fail (SYSPROF_IS_RECORDING (recording), NULL);
|
||||
|
||||
futures = g_ptr_array_new_with_free_func (dex_unref);
|
||||
|
||||
for (guint i = 0; i < instruments->len; i++)
|
||||
{
|
||||
SysprofInstrument *instrument = g_ptr_array_index (instruments, i);
|
||||
|
||||
g_ptr_array_add (futures, _sysprof_instrument_augment (instrument, recording));
|
||||
}
|
||||
|
||||
if (futures->len == 0)
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
|
||||
return dex_future_allv ((DexFuture **)futures->pdata, futures->len);
|
||||
}
|
||||
|
||||
DexFuture *
|
||||
_sysprof_instruments_process_started (GPtrArray *instruments,
|
||||
SysprofRecording *recording,
|
||||
int pid)
|
||||
{
|
||||
g_autoptr(GPtrArray) futures = NULL;
|
||||
|
||||
g_return_val_if_fail (instruments != NULL, NULL);
|
||||
g_return_val_if_fail (SYSPROF_IS_RECORDING (recording), NULL);
|
||||
|
||||
futures = g_ptr_array_new_with_free_func (dex_unref);
|
||||
|
||||
for (guint i = 0; i < instruments->len; i++)
|
||||
{
|
||||
SysprofInstrument *instrument = g_ptr_array_index (instruments, i);
|
||||
|
||||
g_ptr_array_add (futures, _sysprof_instrument_process_started (instrument, recording, pid));
|
||||
}
|
||||
|
||||
if (futures->len == 0)
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
|
||||
return dex_future_allv ((DexFuture **)futures->pdata, futures->len);
|
||||
}
|
||||
42
src/libsysprof/sysprof-instrument.h
Normal file
42
src/libsysprof/sysprof-instrument.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* sysprof-instrument.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_INSTRUMENT (sysprof_instrument_get_type())
|
||||
#define SYSPROF_IS_INSTRUMENT(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_INSTRUMENT)
|
||||
#define SYSPROF_INSTRUMENT(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_INSTRUMENT, SysprofInstrument)
|
||||
#define SYSPROF_INSTRUMENT_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_INSTRUMENT, SysprofInstrumentClass)
|
||||
|
||||
typedef struct _SysprofInstrument SysprofInstrument;
|
||||
typedef struct _SysprofInstrumentClass SysprofInstrumentClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_instrument_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofInstrument, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
251
src/libsysprof/sysprof-jitmap-symbolizer.c
Normal file
251
src/libsysprof/sysprof-jitmap-symbolizer.c
Normal file
@ -0,0 +1,251 @@
|
||||
/* sysprof-jitmap-symbolizer.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sysprof-document-jitmap.h"
|
||||
#include "sysprof-document-private.h"
|
||||
#include "sysprof-jitmap-symbolizer.h"
|
||||
#include "sysprof-symbol-private.h"
|
||||
#include "sysprof-symbolizer-private.h"
|
||||
|
||||
typedef struct _Jitmap
|
||||
{
|
||||
SysprofAddress address;
|
||||
GRefString *name;
|
||||
} Jitmap;
|
||||
|
||||
struct _SysprofJitmapSymbolizer
|
||||
{
|
||||
SysprofSymbolizer parent_instance;
|
||||
GArray *jitmaps;
|
||||
};
|
||||
|
||||
struct _SysprofJitmapSymbolizerClass
|
||||
{
|
||||
SysprofSymbolizerClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofJitmapSymbolizer, sysprof_jitmap_symbolizer, SYSPROF_TYPE_SYMBOLIZER)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofDocument *document;
|
||||
GListModel *model;
|
||||
} Prepare;
|
||||
|
||||
static void
|
||||
prepare_free (gpointer data)
|
||||
{
|
||||
Prepare *prepare = data;
|
||||
|
||||
g_clear_object (&prepare->model);
|
||||
g_clear_object (&prepare->document);
|
||||
g_free (prepare);
|
||||
}
|
||||
|
||||
static void
|
||||
jitmap_clear (gpointer data)
|
||||
{
|
||||
Jitmap *j = data;
|
||||
g_clear_pointer (&j->name, g_ref_string_release);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_by_address (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const Jitmap *jitmap_a = a;
|
||||
const Jitmap *jitmap_b = b;
|
||||
|
||||
if (jitmap_a->address < jitmap_b->address)
|
||||
return -1;
|
||||
else if (jitmap_a->address > jitmap_b->address)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_jitmap_symbolizer_prepare_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
SysprofJitmapSymbolizer *self = source_object;
|
||||
Prepare *prepare = task_data;
|
||||
guint n_jitmaps;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_JITMAP_SYMBOLIZER (self));
|
||||
g_assert (prepare != NULL);
|
||||
g_assert (SYSPROF_IS_DOCUMENT (prepare->document));
|
||||
g_assert (G_IS_LIST_MODEL (prepare->model));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
n_jitmaps = g_list_model_get_n_items (prepare->model);
|
||||
|
||||
for (guint i = 0; i < n_jitmaps; i++)
|
||||
{
|
||||
g_autoptr(SysprofDocumentJitmap) jitmap = g_list_model_get_item (prepare->model, i);
|
||||
guint size = sysprof_document_jitmap_get_size (jitmap);
|
||||
|
||||
for (guint j = 0; j < size; j++)
|
||||
{
|
||||
const char *name;
|
||||
Jitmap map;
|
||||
|
||||
if (!(name = sysprof_document_jitmap_get_mapping (jitmap, j, &map.address)))
|
||||
continue;
|
||||
|
||||
map.name = _sysprof_document_ref_string (prepare->document, name);
|
||||
g_array_append_val (self->jitmaps, map);
|
||||
}
|
||||
}
|
||||
|
||||
g_array_sort (self->jitmaps, compare_by_address);
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_jitmap_symbolizer_prepare_async (SysprofSymbolizer *symbolizer,
|
||||
SysprofDocument *document,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofJitmapSymbolizer *self = (SysprofJitmapSymbolizer *)symbolizer;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Prepare *prepare;
|
||||
|
||||
g_assert (SYSPROF_IS_JITMAP_SYMBOLIZER (self));
|
||||
g_assert (SYSPROF_IS_DOCUMENT (document));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
prepare = g_new0 (Prepare, 1);
|
||||
prepare->document = g_object_ref (document);
|
||||
prepare->model = sysprof_document_list_jitmaps (document);
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_jitmap_symbolizer_prepare_async);
|
||||
g_task_set_task_data (task, prepare, prepare_free);
|
||||
g_task_run_in_thread (task, sysprof_jitmap_symbolizer_prepare_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_jitmap_symbolizer_prepare_finish (SysprofSymbolizer *symbolizer,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_assert (SYSPROF_IS_JITMAP_SYMBOLIZER (symbolizer));
|
||||
g_assert (G_IS_TASK (result));
|
||||
g_assert (g_task_is_valid (result, symbolizer));
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static SysprofSymbol *
|
||||
sysprof_jitmap_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
|
||||
SysprofStrings *strings,
|
||||
const SysprofProcessInfo *process_info,
|
||||
SysprofAddressContext context,
|
||||
SysprofAddress address)
|
||||
{
|
||||
SysprofJitmapSymbolizer *self = (SysprofJitmapSymbolizer *)symbolizer;
|
||||
const Jitmap key = { address, NULL };
|
||||
guint guess = (address & 0xFFFF) - 1;
|
||||
const Jitmap *match;
|
||||
|
||||
if (context != SYSPROF_ADDRESS_CONTEXT_NONE &&
|
||||
context != SYSPROF_ADDRESS_CONTEXT_USER)
|
||||
return NULL;
|
||||
|
||||
if ((address & 0xFFFFFFFF00000000) != 0xE000000000000000)
|
||||
return NULL;
|
||||
|
||||
/* Jitmap addresses generally start at 1 and work their way up
|
||||
* monotonically (after masking off the high 0xE...............
|
||||
* bits). So we can try for a fast index lookup to skip any sort
|
||||
* of searching in the well behaved case.
|
||||
*/
|
||||
if G_LIKELY (guess < self->jitmaps->len)
|
||||
{
|
||||
match = &g_array_index (self->jitmaps, Jitmap, guess);
|
||||
|
||||
if G_LIKELY (match->address == address)
|
||||
goto create_symbol;
|
||||
}
|
||||
|
||||
match = bsearch (&key,
|
||||
self->jitmaps->data,
|
||||
self->jitmaps->len,
|
||||
sizeof (Jitmap),
|
||||
compare_by_address);
|
||||
|
||||
if (match == NULL)
|
||||
return NULL;
|
||||
|
||||
create_symbol:
|
||||
return _sysprof_symbol_new (g_ref_string_acquire (match->name),
|
||||
NULL,
|
||||
NULL,
|
||||
match->address,
|
||||
match->address + 1,
|
||||
SYSPROF_SYMBOL_KIND_USER);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_jitmap_symbolizer_finalize (GObject *object)
|
||||
{
|
||||
SysprofJitmapSymbolizer *self = (SysprofJitmapSymbolizer *)object;
|
||||
|
||||
g_clear_pointer (&self->jitmaps, g_array_unref);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_jitmap_symbolizer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_jitmap_symbolizer_class_init (SysprofJitmapSymbolizerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
SysprofSymbolizerClass *symbolizer_class = SYSPROF_SYMBOLIZER_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_jitmap_symbolizer_finalize;
|
||||
|
||||
symbolizer_class->prepare_async = sysprof_jitmap_symbolizer_prepare_async;
|
||||
symbolizer_class->prepare_finish = sysprof_jitmap_symbolizer_prepare_finish;
|
||||
symbolizer_class->symbolize = sysprof_jitmap_symbolizer_symbolize;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_jitmap_symbolizer_init (SysprofJitmapSymbolizer *self)
|
||||
{
|
||||
self->jitmaps = g_array_new (FALSE, FALSE, sizeof (Jitmap));
|
||||
g_array_set_clear_func (self->jitmaps, jitmap_clear);
|
||||
}
|
||||
|
||||
SysprofSymbolizer *
|
||||
sysprof_jitmap_symbolizer_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_JITMAP_SYMBOLIZER, NULL);
|
||||
}
|
||||
42
src/libsysprof/sysprof-jitmap-symbolizer.h
Normal file
42
src/libsysprof/sysprof-jitmap-symbolizer.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* sysprof-jitmap-symbolizer.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-symbolizer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_JITMAP_SYMBOLIZER (sysprof_jitmap_symbolizer_get_type())
|
||||
#define SYSPROF_IS_JITMAP_SYMBOLIZER(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_JITMAP_SYMBOLIZER)
|
||||
#define SYSPROF_JITMAP_SYMBOLIZER(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_JITMAP_SYMBOLIZER, SysprofJitmapSymbolizer)
|
||||
#define SYSPROF_JITMAP_SYMBOLIZER_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_JITMAP_SYMBOLIZER, SysprofJitmapSymbolizerClass)
|
||||
|
||||
typedef struct _SysprofJitmapSymbolizer SysprofJitmapSymbolizer;
|
||||
typedef struct _SysprofJitmapSymbolizerClass SysprofJitmapSymbolizerClass;
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GType sysprof_jitmap_symbolizer_get_type (void) G_GNUC_CONST;
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofSymbolizer *sysprof_jitmap_symbolizer_new (void);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofJitmapSymbolizer, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
107
src/libsysprof/sysprof-journald-source.c
Normal file
107
src/libsysprof/sysprof-journald-source.c
Normal file
@ -0,0 +1,107 @@
|
||||
/* sysprof-journald-source.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <systemd/sd-journal.h>
|
||||
|
||||
#include "sysprof-journald-source.h"
|
||||
|
||||
typedef struct _SysprofJournaldSource
|
||||
{
|
||||
GSource parent_instance;
|
||||
sd_journal *journal;
|
||||
SysprofJournaldSourceFunc func;
|
||||
gpointer func_data;
|
||||
GDestroyNotify func_data_destroy;
|
||||
} SysprofJournaldSource;
|
||||
|
||||
static void
|
||||
sysprof_journald_source_finalize (GSource *source)
|
||||
{
|
||||
SysprofJournaldSource *self = (SysprofJournaldSource *)source;
|
||||
|
||||
if (self->func_data_destroy)
|
||||
self->func_data_destroy (self->func_data);
|
||||
|
||||
g_clear_pointer (&self->journal, sd_journal_close);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_journald_source_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofJournaldSource *self = (SysprofJournaldSource *)source;
|
||||
|
||||
if (sd_journal_process (self->journal) == SD_JOURNAL_APPEND)
|
||||
{
|
||||
if (sd_journal_next (self->journal) > 0)
|
||||
return self->func (self->func_data, self->journal);
|
||||
}
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static GSourceFuncs sysprof_journald_source_funcs = {
|
||||
.dispatch = sysprof_journald_source_dispatch,
|
||||
.finalize = sysprof_journald_source_finalize,
|
||||
};
|
||||
|
||||
GSource *
|
||||
sysprof_journald_source_new (SysprofJournaldSourceFunc func,
|
||||
gpointer func_data,
|
||||
GDestroyNotify func_data_destroy)
|
||||
{
|
||||
SysprofJournaldSource *self;
|
||||
sd_journal *journal = NULL;
|
||||
int fd;
|
||||
|
||||
if (sd_journal_open (&journal, 0) < 0)
|
||||
return NULL;
|
||||
|
||||
if (sd_journal_seek_tail (journal) < 0)
|
||||
goto failure;
|
||||
|
||||
if (sd_journal_previous (journal) < 0)
|
||||
goto failure;
|
||||
|
||||
if (sd_journal_next (journal) < 0)
|
||||
goto failure;
|
||||
|
||||
if (-1 == (fd = sd_journal_get_fd (journal)))
|
||||
goto failure;
|
||||
|
||||
self = (SysprofJournaldSource *)g_source_new (&sysprof_journald_source_funcs,
|
||||
sizeof (SysprofJournaldSource));
|
||||
self->journal = journal;
|
||||
self->func = func;
|
||||
self->func_data = func_data;
|
||||
self->func_data_destroy = func_data_destroy;
|
||||
|
||||
g_source_add_unix_fd ((GSource *)self, fd, sd_journal_get_events (journal));
|
||||
|
||||
return (GSource *)self;
|
||||
|
||||
failure:
|
||||
g_clear_pointer (&journal, sd_journal_close);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
36
src/libsysprof/sysprof-journald-source.h
Normal file
36
src/libsysprof/sysprof-journald-source.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* sysprof-journald-source.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <systemd/sd-journal.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef gboolean (*SysprofJournaldSourceFunc) (gpointer user_data,
|
||||
sd_journal *journal);
|
||||
|
||||
GSource *sysprof_journald_source_new (SysprofJournaldSourceFunc func,
|
||||
gpointer func_data,
|
||||
GDestroyNotify func_data_destroy);
|
||||
|
||||
G_END_DECLS
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user