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:
45
src/libsysprof/tests/meson.build
Normal file
45
src/libsysprof/tests/meson.build
Normal file
@ -0,0 +1,45 @@
|
||||
libsysprof_test_env = [
|
||||
'G_DEBUG=gc-friendly',
|
||||
'GSETTINGS_BACKEND=memory',
|
||||
'MALLOC_CHECK_=2',
|
||||
]
|
||||
|
||||
libsysprof_testsuite_c_args = [
|
||||
'-DG_ENABLE_DEBUG',
|
||||
'-UG_DISABLE_ASSERT',
|
||||
'-UG_DISABLE_CAST_CHECKS',
|
||||
]
|
||||
|
||||
libsysprof_testsuite = {
|
||||
'test-callgraph' : {'skip': true},
|
||||
'test-capture-model' : {'skip': true},
|
||||
'test-elf-loader' : {'skip': true},
|
||||
'test-list-counters' : {'skip': true},
|
||||
'test-list-cpu' : {'skip': true},
|
||||
'test-list-files' : {'skip': true},
|
||||
'test-list-jitmap' : {'skip': true},
|
||||
'test-list-overlays' : {'skip': true},
|
||||
'test-maps-parser' : {'skip': true},
|
||||
'test-mark-catalog' : {'skip': true},
|
||||
'test-print-file' : {'skip': true},
|
||||
'test-profiler' : {'skip': true},
|
||||
'test-list-processes' : {'skip': true},
|
||||
'test-list-address-layout' : {'skip': true},
|
||||
'test-symbolize' : {'skip': true},
|
||||
'test-strings' : {},
|
||||
'test-symbol-cache' : {},
|
||||
}
|
||||
|
||||
libsysprof_testsuite_deps = [
|
||||
libsysprof_static_dep,
|
||||
]
|
||||
|
||||
foreach test, params: libsysprof_testsuite
|
||||
test_exe = executable(test, '@0@.c'.format(test),
|
||||
c_args: libsysprof_testsuite_c_args,
|
||||
dependencies: libsysprof_testsuite_deps,
|
||||
)
|
||||
if not params.get('skip', false)
|
||||
test(test, test_exe, env: libsysprof_test_env)
|
||||
endif
|
||||
endforeach
|
||||
180
src/libsysprof/tests/test-callgraph.c
Normal file
180
src/libsysprof/tests/test-callgraph.c
Normal file
@ -0,0 +1,180 @@
|
||||
/* test-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 <glib/gi18n.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include <sysprof.h>
|
||||
|
||||
typedef struct _Augment
|
||||
{
|
||||
guint64 toplevel : 1;
|
||||
guint64 size : 31;
|
||||
guint32 total : 32;
|
||||
} Augment;
|
||||
|
||||
static char *kallsyms_path;
|
||||
static gboolean include_threads;
|
||||
static const GOptionEntry entries[] = {
|
||||
{ "kallsyms", 'k', 0, G_OPTION_ARG_FILENAME, &kallsyms_path, "The path to kallsyms to use for decoding", "PATH" },
|
||||
{ "threads", 't', 0, G_OPTION_ARG_NONE, &include_threads, "Include threads in the stack traces" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static void
|
||||
print_callgraph (GListModel *model,
|
||||
guint depth,
|
||||
guint total)
|
||||
{
|
||||
guint n_items = g_list_model_get_n_items (model);
|
||||
|
||||
for (guint i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr(SysprofCallgraphFrame) frame = g_list_model_get_item (model, i);
|
||||
SysprofSymbol *symbol = sysprof_callgraph_frame_get_symbol (frame);
|
||||
Augment *aug = sysprof_callgraph_frame_get_augment (frame);
|
||||
char tstr[16];
|
||||
|
||||
g_snprintf (tstr, sizeof tstr, "%.2lf%%", 100. * (aug->total / (double)total));
|
||||
|
||||
g_print (" [%6u] [%8s] ", aug->total, tstr);
|
||||
for (guint j = 0; j < depth; j++)
|
||||
g_print (" ");
|
||||
g_print ("%s\n", sysprof_symbol_get_name (symbol));
|
||||
|
||||
print_callgraph (G_LIST_MODEL (frame), depth+1, total);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
callgraph_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofDocument *document = SYSPROF_DOCUMENT (object);
|
||||
GMainLoop *main_loop = user_data;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(SysprofCallgraph) callgraph = sysprof_document_callgraph_finish (document, result, &error);
|
||||
g_autoptr(SysprofCallgraphFrame) root = NULL;
|
||||
Augment *aug;
|
||||
|
||||
g_assert_no_error (error);
|
||||
g_assert_true (SYSPROF_IS_CALLGRAPH (callgraph));
|
||||
|
||||
root = g_list_model_get_item (G_LIST_MODEL (callgraph), 0);
|
||||
aug = sysprof_callgraph_frame_get_augment (root);
|
||||
|
||||
g_print (" Hits Percent\n");
|
||||
print_callgraph (G_LIST_MODEL (callgraph), 0, aug->total);
|
||||
|
||||
g_main_loop_quit (main_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
augment_cb (SysprofCallgraph *callgraph,
|
||||
SysprofCallgraphNode *node,
|
||||
SysprofDocumentFrame *frame,
|
||||
gboolean summarize,
|
||||
gpointer user_data)
|
||||
{
|
||||
Augment *aug;
|
||||
|
||||
g_assert (SYSPROF_IS_CALLGRAPH (callgraph));
|
||||
g_assert (node != NULL);
|
||||
g_assert (SYSPROF_IS_DOCUMENT_SAMPLE (frame));
|
||||
g_assert (user_data == NULL);
|
||||
|
||||
aug = sysprof_callgraph_get_augment (callgraph, node);
|
||||
aug->toplevel = TRUE;
|
||||
|
||||
for (; node ; node = sysprof_callgraph_node_parent (node))
|
||||
{
|
||||
aug = sysprof_callgraph_get_augment (callgraph, node);
|
||||
aug->total += 1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(GOptionContext) context = g_option_context_new ("- test callgraph generation");
|
||||
g_autoptr(GMainLoop) main_loop = g_main_loop_new (NULL, FALSE);
|
||||
g_autoptr(SysprofDocumentLoader) loader = NULL;
|
||||
g_autoptr(SysprofDocument) document = NULL;
|
||||
g_autoptr(SysprofMultiSymbolizer) multi = NULL;
|
||||
g_autoptr(GListModel) samples = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
SysprofCallgraphFlags flags = 0;
|
||||
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
textdomain (GETTEXT_PACKAGE);
|
||||
|
||||
g_option_context_add_main_entries (context, entries, NULL);
|
||||
if (!g_option_context_parse (context, &argc, &argv, &error))
|
||||
g_error ("%s", error->message);
|
||||
|
||||
if (argc < 2)
|
||||
g_error ("usage: %s CAPTURE_FILE", argv[0]);
|
||||
|
||||
multi = sysprof_multi_symbolizer_new ();
|
||||
|
||||
if (kallsyms_path)
|
||||
{
|
||||
g_autoptr(GFile) kallsyms_file = g_file_new_for_path (kallsyms_path);
|
||||
GFileInputStream *kallsyms_stream = g_file_read (kallsyms_file, NULL, NULL);
|
||||
|
||||
sysprof_multi_symbolizer_take (multi, sysprof_kallsyms_symbolizer_new_for_symbols (G_INPUT_STREAM (kallsyms_stream)));
|
||||
}
|
||||
else
|
||||
{
|
||||
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 ());
|
||||
|
||||
loader = sysprof_document_loader_new (argv[1]);
|
||||
sysprof_document_loader_set_symbolizer (loader, SYSPROF_SYMBOLIZER (multi));
|
||||
if (!(document = sysprof_document_loader_load (loader, NULL, &error)))
|
||||
g_error ("Failed to load document: %s", error->message);
|
||||
|
||||
samples = sysprof_document_list_samples (document);
|
||||
|
||||
if (include_threads)
|
||||
flags |= SYSPROF_CALLGRAPH_FLAGS_INCLUDE_THREADS;
|
||||
|
||||
sysprof_document_callgraph_async (document,
|
||||
flags,
|
||||
samples,
|
||||
sizeof (Augment),
|
||||
augment_cb, NULL, NULL,
|
||||
NULL,
|
||||
callgraph_cb,
|
||||
main_loop);
|
||||
|
||||
g_main_loop_run (main_loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
147
src/libsysprof/tests/test-capture-model.c
Normal file
147
src/libsysprof/tests/test-capture-model.c
Normal file
@ -0,0 +1,147 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sysprof.h>
|
||||
|
||||
#include "sysprof-document-private.h"
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(SysprofDocumentLoader) loader = NULL;
|
||||
g_autoptr(SysprofDocument) document = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
const char *filename;
|
||||
guint n_items;
|
||||
|
||||
sysprof_clock_init ();
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
g_printerr ("usage: %s FILENAME\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
filename = argv[1];
|
||||
|
||||
loader = sysprof_document_loader_new (filename);
|
||||
sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ());
|
||||
|
||||
if (!(document = sysprof_document_loader_load (loader, NULL, &error)))
|
||||
{
|
||||
g_printerr ("Failed to load %s: %s\n",
|
||||
filename, error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
n_items = g_list_model_get_n_items (G_LIST_MODEL (document));
|
||||
|
||||
for (guint i = 0; i < n_items; i++)
|
||||
{
|
||||
SysprofDocumentFrame *frame = g_list_model_get_item (G_LIST_MODEL (document), i);
|
||||
|
||||
g_print ("%"G_GINT64_FORMAT" [pid %d] [cpu %d] (type %s)",
|
||||
sysprof_document_frame_get_time (frame),
|
||||
sysprof_document_frame_get_pid (frame),
|
||||
sysprof_document_frame_get_cpu (frame),
|
||||
G_OBJECT_TYPE_NAME (frame));
|
||||
|
||||
if (0) {}
|
||||
else if (SYSPROF_IS_DOCUMENT_LOG (frame))
|
||||
g_print (" domain=%s message=%s",
|
||||
sysprof_document_log_get_domain (SYSPROF_DOCUMENT_LOG (frame)),
|
||||
sysprof_document_log_get_message (SYSPROF_DOCUMENT_LOG (frame)));
|
||||
else if (SYSPROF_IS_DOCUMENT_MARK (frame))
|
||||
g_print (" group=%s name=%s message=%s",
|
||||
sysprof_document_mark_get_group (SYSPROF_DOCUMENT_MARK (frame)),
|
||||
sysprof_document_mark_get_name (SYSPROF_DOCUMENT_MARK (frame)),
|
||||
sysprof_document_mark_get_message (SYSPROF_DOCUMENT_MARK (frame)));
|
||||
else if (SYSPROF_IS_DOCUMENT_PROCESS (frame))
|
||||
g_print (" cmdline=%s", sysprof_document_process_get_command_line (SYSPROF_DOCUMENT_PROCESS (frame)));
|
||||
else if (SYSPROF_IS_DOCUMENT_METADATA (frame))
|
||||
g_print (" id=%s value=%s",
|
||||
sysprof_document_metadata_get_id (SYSPROF_DOCUMENT_METADATA (frame)),
|
||||
sysprof_document_metadata_get_value (SYSPROF_DOCUMENT_METADATA (frame)));
|
||||
else if (SYSPROF_IS_DOCUMENT_FILE_CHUNK (frame))
|
||||
g_print (" file-chunk path=%s len=%u",
|
||||
sysprof_document_file_chunk_get_path (SYSPROF_DOCUMENT_FILE_CHUNK (frame)),
|
||||
sysprof_document_file_chunk_get_size (SYSPROF_DOCUMENT_FILE_CHUNK (frame)));
|
||||
else if (SYSPROF_IS_DOCUMENT_FORK (frame))
|
||||
g_print (" child-pid=%d",
|
||||
sysprof_document_fork_get_child_pid (SYSPROF_DOCUMENT_FORK (frame)));
|
||||
else if (SYSPROF_IS_DOCUMENT_OVERLAY (frame))
|
||||
g_print (" layer=%u source=%s destination=%s",
|
||||
sysprof_document_overlay_get_layer (SYSPROF_DOCUMENT_OVERLAY (frame)),
|
||||
sysprof_document_overlay_get_source (SYSPROF_DOCUMENT_OVERLAY (frame)),
|
||||
sysprof_document_overlay_get_destination (SYSPROF_DOCUMENT_OVERLAY (frame)));
|
||||
else if (SYSPROF_IS_DOCUMENT_MMAP (frame))
|
||||
g_print (" begin=0x%"G_GINT64_MODIFIER"x end=0x%"G_GINT64_MODIFIER"x offset=0x%"G_GINT64_MODIFIER"x path=%s",
|
||||
sysprof_document_mmap_get_start_address (SYSPROF_DOCUMENT_MMAP (frame)),
|
||||
sysprof_document_mmap_get_end_address (SYSPROF_DOCUMENT_MMAP (frame)),
|
||||
sysprof_document_mmap_get_file_offset (SYSPROF_DOCUMENT_MMAP (frame)),
|
||||
sysprof_document_mmap_get_file (SYSPROF_DOCUMENT_MMAP (frame)));
|
||||
else if (SYSPROF_IS_DOCUMENT_JITMAP (frame))
|
||||
g_print (" n_jitmaps=%u",
|
||||
sysprof_document_jitmap_get_size (SYSPROF_DOCUMENT_JITMAP (frame)));
|
||||
else if (SYSPROF_IS_DOCUMENT_CTRDEF (frame))
|
||||
{
|
||||
guint n_counters = sysprof_document_ctrdef_get_n_counters (SYSPROF_DOCUMENT_CTRDEF (frame));
|
||||
|
||||
g_print (" n_counters=%u", n_counters);
|
||||
|
||||
for (guint j = 0; j < n_counters; j++)
|
||||
{
|
||||
const char *category, *name;
|
||||
guint id, type;
|
||||
|
||||
sysprof_document_ctrdef_get_counter (SYSPROF_DOCUMENT_CTRDEF (frame),
|
||||
j, &id, &type, &category, &name, NULL);
|
||||
g_print (" [%u<%s>:%s.%s]",
|
||||
id,
|
||||
type == SYSPROF_CAPTURE_COUNTER_INT64 ? "i64" : "f64",
|
||||
category, name);
|
||||
}
|
||||
}
|
||||
else if (SYSPROF_IS_DOCUMENT_CTRSET (frame))
|
||||
{
|
||||
guint n_values = sysprof_document_ctrset_get_n_values (SYSPROF_DOCUMENT_CTRSET (frame));
|
||||
|
||||
g_print (" counters=[");
|
||||
for (guint j = 0; j < n_values; j++)
|
||||
{
|
||||
guint id;
|
||||
guint8 raw[8];
|
||||
|
||||
sysprof_document_ctrset_get_raw_value (SYSPROF_DOCUMENT_CTRSET (frame), j, &id, raw);
|
||||
|
||||
g_print ("%u", id);
|
||||
if (j+1 != n_values)
|
||||
g_print (", ");
|
||||
}
|
||||
g_print ("]");
|
||||
}
|
||||
else if (SYSPROF_IS_DOCUMENT_ALLOCATION (frame))
|
||||
{
|
||||
if (sysprof_document_allocation_is_free (SYSPROF_DOCUMENT_ALLOCATION (frame)))
|
||||
g_print (" 0x%016"G_GINT64_MODIFIER"x: free",
|
||||
sysprof_document_allocation_get_address (SYSPROF_DOCUMENT_ALLOCATION (frame)));
|
||||
else
|
||||
g_print (" 0x%016"G_GINT64_MODIFIER"x: allocate %"G_GUINT64_FORMAT,
|
||||
sysprof_document_allocation_get_address (SYSPROF_DOCUMENT_ALLOCATION (frame)),
|
||||
sysprof_document_allocation_get_size (SYSPROF_DOCUMENT_ALLOCATION (frame)));
|
||||
}
|
||||
|
||||
if (SYSPROF_IS_DOCUMENT_TRACEABLE (frame))
|
||||
g_print (" stack-depth=%u",
|
||||
sysprof_document_traceable_get_stack_depth (SYSPROF_DOCUMENT_TRACEABLE (frame)));
|
||||
|
||||
g_print ("\n");
|
||||
|
||||
g_clear_object (&frame);
|
||||
}
|
||||
|
||||
g_printerr ("%u frames\n", n_items);
|
||||
|
||||
return 0;
|
||||
}
|
||||
86
src/libsysprof/tests/test-elf-loader.c
Normal file
86
src/libsysprof/tests/test-elf-loader.c
Normal file
@ -0,0 +1,86 @@
|
||||
/* test-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 <sysprof.h>
|
||||
|
||||
#include "sysprof-document-process-private.h"
|
||||
#include "sysprof-elf-loader-private.h"
|
||||
|
||||
static const GOptionEntry entries[] = {
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(GOptionContext) context = g_option_context_new ("- test loading of ELF files");
|
||||
g_autoptr(GMainLoop) main_loop = g_main_loop_new (NULL, FALSE);
|
||||
g_autoptr(SysprofDocumentLoader) loader = NULL;
|
||||
g_autoptr(SysprofElfLoader) elf_loader = NULL;
|
||||
g_autoptr(SysprofDocument) document = NULL;
|
||||
g_autoptr(GListModel) processes = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
guint n_processes;
|
||||
|
||||
g_option_context_add_main_entries (context, entries, NULL);
|
||||
if (!g_option_context_parse (context, &argc, &argv, &error))
|
||||
g_error ("%s", error->message);
|
||||
|
||||
if (argc < 2)
|
||||
g_error ("usage: %s CAPTURE_FILE", argv[0]);
|
||||
|
||||
loader = sysprof_document_loader_new (argv[1]);
|
||||
sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ());
|
||||
if (!(document = sysprof_document_loader_load (loader, NULL, &error)))
|
||||
g_error ("Failed to load document: %s", error->message);
|
||||
|
||||
processes = sysprof_document_list_processes (document);
|
||||
n_processes = g_list_model_get_n_items (processes);
|
||||
|
||||
elf_loader = sysprof_elf_loader_new ();
|
||||
|
||||
for (guint i = 0; i < n_processes; i++)
|
||||
{
|
||||
g_autoptr(SysprofDocumentProcess) process = g_list_model_get_item (processes, i);
|
||||
g_autoptr(GListModel) memory_maps = sysprof_document_process_list_memory_maps (process);
|
||||
guint n_memory_maps = g_list_model_get_n_items (memory_maps);
|
||||
SysprofProcessInfo *info = _sysprof_document_process_get_info (process);
|
||||
|
||||
for (guint j = 0; j < n_memory_maps; j++)
|
||||
{
|
||||
g_autoptr(SysprofDocumentMmap) memory_map = g_list_model_get_item (memory_maps, j);
|
||||
const char *file = sysprof_document_mmap_get_file (memory_map);
|
||||
const char *build_id = sysprof_document_mmap_get_build_id (memory_map);
|
||||
guint64 file_inode = sysprof_document_mmap_get_file_inode (memory_map);
|
||||
g_autoptr(SysprofElf) elf = sysprof_elf_loader_load (elf_loader, info->mount_namespace, file, build_id, file_inode, &error);
|
||||
|
||||
if (elf == NULL)
|
||||
g_print ("%u: %s (build-id %s) (inode %"G_GINT64_FORMAT") => [unresolved]\n",
|
||||
info->pid, file, build_id ? build_id : "none", file_inode);
|
||||
else
|
||||
g_print ("%u: %s => %s\n", info->pid, file, sysprof_elf_get_file (elf));
|
||||
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
80
src/libsysprof/tests/test-list-address-layout.c
Normal file
80
src/libsysprof/tests/test-list-address-layout.c
Normal file
@ -0,0 +1,80 @@
|
||||
/* test-list-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 <sysprof.h>
|
||||
|
||||
#include "sysprof-document-private.h"
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(SysprofDocumentLoader) loader = NULL;
|
||||
g_autoptr(SysprofDocument) document = NULL;
|
||||
g_autoptr(GListModel) processes = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
guint n_items;
|
||||
int pid;
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
g_printerr ("usage: %s CAPTURE_FILE PID\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pid = atoi (argv[2]);
|
||||
loader = sysprof_document_loader_new (argv[1]);
|
||||
sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ());
|
||||
|
||||
if (!(document = sysprof_document_loader_load (loader, NULL, &error)))
|
||||
{
|
||||
g_printerr ("Failed to open capture: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
processes = sysprof_document_list_processes (document);
|
||||
n_items = g_list_model_get_n_items (processes);
|
||||
|
||||
for (guint i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr(SysprofDocumentProcess) process = g_list_model_get_item (processes, i);
|
||||
|
||||
if (sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (process)) == pid)
|
||||
{
|
||||
g_autoptr(GListModel) memory_maps = sysprof_document_process_list_memory_maps (process);
|
||||
guint n_maps = g_list_model_get_n_items (memory_maps);
|
||||
|
||||
for (guint j = 0; j < n_maps; j++)
|
||||
{
|
||||
g_autoptr(SysprofDocumentMmap) map = g_list_model_get_item (memory_maps, j);
|
||||
|
||||
g_print (" [0x%"G_GINT64_MODIFIER"x:0x%"G_GINT64_MODIFIER"x] %s <+0x%"G_GINT64_MODIFIER"x>\n",
|
||||
sysprof_document_mmap_get_start_address (map),
|
||||
sysprof_document_mmap_get_end_address (map),
|
||||
sysprof_document_mmap_get_file (map),
|
||||
sysprof_document_mmap_get_file_offset (map));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
108
src/libsysprof/tests/test-list-counters.c
Normal file
108
src/libsysprof/tests/test-list-counters.c
Normal file
@ -0,0 +1,108 @@
|
||||
/* test-list-counters.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 <sysprof.h>
|
||||
|
||||
#include "sysprof-document-private.h"
|
||||
|
||||
static gboolean show_values;
|
||||
static const GOptionEntry entries[] = {
|
||||
{ "values", 'v', 0, G_OPTION_ARG_NONE, &show_values, "Show values along with counter information" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(GOptionContext) context = g_option_context_new ("- list counter information from capture");
|
||||
g_autoptr(SysprofDocumentLoader) loader = NULL;
|
||||
g_autoptr(SysprofDocument) document = NULL;
|
||||
g_autoptr(GListModel) model = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
guint n_items;
|
||||
|
||||
g_option_context_add_main_entries (context, entries, NULL);
|
||||
|
||||
if (!g_option_context_parse (context, &argc, &argv, &error))
|
||||
{
|
||||
g_printerr ("%s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
g_printerr ("usage: %s CAPTURE_FILE\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
loader = sysprof_document_loader_new (argv[1]);
|
||||
sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ());
|
||||
|
||||
if (!(document = sysprof_document_loader_load (loader, NULL, &error)))
|
||||
{
|
||||
g_printerr ("Failed to open capture: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
model = sysprof_document_list_counters (document);
|
||||
n_items = g_list_model_get_n_items (model);
|
||||
|
||||
for (guint i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr(SysprofDocumentCounter) counter = g_list_model_get_item (model, i);
|
||||
|
||||
g_print ("%d<%s> %s.%s: %s (%u values)\n",
|
||||
sysprof_document_counter_get_id (counter),
|
||||
sysprof_document_counter_get_value_type (counter) == G_TYPE_INT64 ? "i64" : "f64",
|
||||
sysprof_document_counter_get_category (counter),
|
||||
sysprof_document_counter_get_name (counter),
|
||||
sysprof_document_counter_get_description (counter),
|
||||
sysprof_document_counter_get_n_values (counter));
|
||||
|
||||
if (show_values)
|
||||
{
|
||||
guint n_values = sysprof_document_counter_get_n_values (counter);
|
||||
|
||||
if (sysprof_document_counter_get_value_type (counter) == G_TYPE_INT64)
|
||||
{
|
||||
for (guint j = 0; j < n_values; j++)
|
||||
{
|
||||
gint64 t;
|
||||
gint64 v = sysprof_document_counter_get_value_int64 (counter, j, &t);
|
||||
|
||||
g_print (" %03u: %"G_GINT64_FORMAT": %"G_GINT64_FORMAT"\n", j, t, v);
|
||||
}
|
||||
}
|
||||
else if (sysprof_document_counter_get_value_type (counter) == G_TYPE_DOUBLE)
|
||||
{
|
||||
for (guint j = 0; j < n_values; j++)
|
||||
{
|
||||
gint64 t;
|
||||
double v = sysprof_document_counter_get_value_double (counter, j, &t);
|
||||
|
||||
g_print (" %03u: %"G_GINT64_FORMAT": %lf\n", j, t, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
76
src/libsysprof/tests/test-list-cpu.c
Normal file
76
src/libsysprof/tests/test-list-cpu.c
Normal file
@ -0,0 +1,76 @@
|
||||
/* test-list-counters.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 <sysprof.h>
|
||||
|
||||
#include "sysprof-document-private.h"
|
||||
|
||||
static const GOptionEntry entries[] = {
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(GOptionContext) context = g_option_context_new ("- list cpu information from capture");
|
||||
g_autoptr(SysprofDocumentLoader) loader = NULL;
|
||||
g_autoptr(SysprofDocument) document = NULL;
|
||||
g_autoptr(GListModel) model = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
guint n_items;
|
||||
|
||||
g_option_context_add_main_entries (context, entries, NULL);
|
||||
|
||||
if (!g_option_context_parse (context, &argc, &argv, &error))
|
||||
{
|
||||
g_printerr ("%s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
g_printerr ("usage: %s CAPTURE_FILE\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
loader = sysprof_document_loader_new (argv[1]);
|
||||
sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ());
|
||||
|
||||
if (!(document = sysprof_document_loader_load (loader, NULL, &error)))
|
||||
{
|
||||
g_printerr ("Failed to open capture: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
model = sysprof_document_list_cpu_info (document);
|
||||
n_items = g_list_model_get_n_items (model);
|
||||
|
||||
for (guint i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr(SysprofCpuInfo) cpu_info = g_list_model_get_item (model, i);
|
||||
|
||||
g_print ("processor %u: %s\n",
|
||||
sysprof_cpu_info_get_id (cpu_info),
|
||||
sysprof_cpu_info_get_model_name (cpu_info));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
61
src/libsysprof/tests/test-list-files.c
Normal file
61
src/libsysprof/tests/test-list-files.c
Normal file
@ -0,0 +1,61 @@
|
||||
/* test-list-files.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 <sysprof.h>
|
||||
|
||||
#include "sysprof-document-private.h"
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(SysprofDocumentLoader) loader = NULL;
|
||||
g_autoptr(SysprofDocument) document = NULL;
|
||||
g_autoptr(GListModel) files = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
guint n_items;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
g_printerr ("usage: %s CAPTURE_FILE\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
loader = sysprof_document_loader_new (argv[1]);
|
||||
sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ());
|
||||
|
||||
if (!(document = sysprof_document_loader_load (loader, NULL, &error)))
|
||||
{
|
||||
g_printerr ("Failed to open capture: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
files = sysprof_document_list_files (document);
|
||||
n_items = g_list_model_get_n_items (files);
|
||||
|
||||
for (guint i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr(SysprofDocumentFile) file = g_list_model_get_item (files, i);
|
||||
|
||||
g_print ("%s\n", sysprof_document_file_get_path (file));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
76
src/libsysprof/tests/test-list-jitmap.c
Normal file
76
src/libsysprof/tests/test-list-jitmap.c
Normal file
@ -0,0 +1,76 @@
|
||||
/* test-list-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 <sysprof.h>
|
||||
|
||||
#include "sysprof-document-private.h"
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(SysprofDocumentLoader) loader = NULL;
|
||||
g_autoptr(SysprofDocument) document = NULL;
|
||||
g_autoptr(GListModel) model = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
guint n_items;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
g_printerr ("usage: %s CAPTURE_FILE\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
loader = sysprof_document_loader_new (argv[1]);
|
||||
sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ());
|
||||
|
||||
if (!(document = sysprof_document_loader_load (loader, NULL, &error)))
|
||||
{
|
||||
g_printerr ("Failed to open capture: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
model = sysprof_document_list_jitmaps (document);
|
||||
n_items = g_list_model_get_n_items (model);
|
||||
|
||||
for (guint i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr(SysprofDocumentFrame) frame = g_list_model_get_item (model, i);
|
||||
|
||||
if (SYSPROF_IS_DOCUMENT_JITMAP (frame))
|
||||
{
|
||||
SysprofDocumentJitmap *jitmap = SYSPROF_DOCUMENT_JITMAP (frame);
|
||||
guint size = sysprof_document_jitmap_get_size (jitmap);
|
||||
|
||||
for (guint j = 0; j < size; j++)
|
||||
{
|
||||
SysprofAddress address;
|
||||
const char *name;
|
||||
|
||||
if (!(name = sysprof_document_jitmap_get_mapping (jitmap, j, &address)))
|
||||
break;
|
||||
|
||||
g_print ("0x%"G_GINT64_MODIFIER"x: %s\n", address, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
107
src/libsysprof/tests/test-list-overlays.c
Normal file
107
src/libsysprof/tests/test-list-overlays.c
Normal file
@ -0,0 +1,107 @@
|
||||
/* test-list-overlays.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 <sysprof.h>
|
||||
|
||||
#include "sysprof-document-private.h"
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(SysprofDocumentLoader) loader = NULL;
|
||||
g_autoptr(SysprofDocument) document = NULL;
|
||||
g_autoptr(GListModel) processes = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
guint n_items;
|
||||
int pid = -1;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
g_printerr ("usage: %s CAPTURE_FILE [PID]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc == 3)
|
||||
pid = atoi (argv[2]);
|
||||
|
||||
loader = sysprof_document_loader_new (argv[1]);
|
||||
sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ());
|
||||
|
||||
if (!(document = sysprof_document_loader_load (loader, NULL, &error)))
|
||||
{
|
||||
g_printerr ("Failed to open capture: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
processes = sysprof_document_list_processes (document);
|
||||
n_items = g_list_model_get_n_items (processes);
|
||||
|
||||
for (guint i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr(SysprofDocumentProcess) process = g_list_model_get_item (processes, i);
|
||||
g_autoptr(GListModel) mounts = sysprof_document_process_list_mounts (process);
|
||||
g_autoptr(GString) str = g_string_new (NULL);
|
||||
guint n_mounts;
|
||||
|
||||
if (pid != -1 && pid != sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (process)))
|
||||
continue;
|
||||
|
||||
n_mounts = g_list_model_get_n_items (mounts);
|
||||
for (guint j = 0; j < n_mounts; j++)
|
||||
{
|
||||
g_autoptr(SysprofMount) mount = g_list_model_get_item (mounts, j);
|
||||
const char *fs_type = sysprof_mount_get_filesystem_type (mount);
|
||||
const char *value;
|
||||
|
||||
if (g_strcmp0 (fs_type, "overlay") == 0)
|
||||
g_string_append_printf (str,
|
||||
" @ID(%d) @ROOT(%s) @MOUNT_POINT(%s) @MOUNT_SOURCE(%s) @FS_TYPE(%s) @OPTIONS(%s)\n",
|
||||
sysprof_mount_get_mount_id (mount),
|
||||
sysprof_mount_get_root (mount),
|
||||
sysprof_mount_get_mount_point (mount),
|
||||
sysprof_mount_get_mount_source (mount),
|
||||
sysprof_mount_get_filesystem_type (mount),
|
||||
sysprof_mount_get_superblock_options (mount));
|
||||
|
||||
if ((value = sysprof_mount_get_superblock_option (mount, "lowerdir")))
|
||||
{
|
||||
g_auto(GStrv) split = g_strsplit (value, ":", 0);
|
||||
|
||||
g_string_append_printf (str, " LOWER: %s\n", value);
|
||||
for (guint k = 0; split[k]; k++)
|
||||
g_string_append_printf (str, " [%d]: %s\n", k, split[k]);
|
||||
}
|
||||
|
||||
if ((value = sysprof_mount_get_superblock_option (mount, "upperdir")))
|
||||
g_string_append_printf (str, " UPPER: %s\n", value);
|
||||
|
||||
if ((value = sysprof_mount_get_superblock_option (mount, "workdir")))
|
||||
g_string_append_printf (str, " WORKDIR: %s\n", value);
|
||||
}
|
||||
|
||||
if (str->len > 0)
|
||||
g_print ("%d:\n%s",
|
||||
sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (process)),
|
||||
str->str);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
122
src/libsysprof/tests/test-list-processes.c
Normal file
122
src/libsysprof/tests/test-list-processes.c
Normal file
@ -0,0 +1,122 @@
|
||||
/* test-list-processes.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 <sysprof.h>
|
||||
|
||||
#include "sysprof-document-private.h"
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(SysprofDocumentLoader) loader = NULL;
|
||||
g_autoptr(SysprofDocument) document = NULL;
|
||||
g_autoptr(GListModel) processes = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
guint n_items;
|
||||
int pid = -1;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
g_printerr ("usage: %s CAPTURE_FILE [PID]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc == 3)
|
||||
pid = atoi (argv[2]);
|
||||
|
||||
loader = sysprof_document_loader_new (argv[1]);
|
||||
sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ());
|
||||
|
||||
if (!(document = sysprof_document_loader_load (loader, NULL, &error)))
|
||||
{
|
||||
g_printerr ("Failed to open capture: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
processes = sysprof_document_list_processes (document);
|
||||
n_items = g_list_model_get_n_items (processes);
|
||||
|
||||
for (guint i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr(SysprofDocumentProcess) process = g_list_model_get_item (processes, i);
|
||||
g_autoptr(GListModel) memory_maps = sysprof_document_process_list_memory_maps (process);
|
||||
g_autoptr(GListModel) mounts = sysprof_document_process_list_mounts (process);
|
||||
g_autoptr(GListModel) threads = sysprof_document_process_list_threads (process);
|
||||
guint n_maps;
|
||||
guint n_mounts;
|
||||
guint n_threads;
|
||||
|
||||
if (pid != -1 && pid != sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (process)))
|
||||
continue;
|
||||
|
||||
g_print ("%d: %s (Duration %lf seconds)\n",
|
||||
sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (process)),
|
||||
sysprof_document_process_get_command_line (process),
|
||||
sysprof_document_process_get_duration (process) / (double)SYSPROF_NSEC_PER_SEC);
|
||||
|
||||
g_print (" Address Layout:\n");
|
||||
n_maps = g_list_model_get_n_items (memory_maps);
|
||||
for (guint j = 0; j < n_maps; j++)
|
||||
{
|
||||
g_autoptr(SysprofDocumentMmap) map = g_list_model_get_item (memory_maps, j);
|
||||
|
||||
g_print (" [0x%"G_GINT64_MODIFIER"x:0x%"G_GINT64_MODIFIER"x] %s\n",
|
||||
sysprof_document_mmap_get_start_address (map),
|
||||
sysprof_document_mmap_get_end_address (map),
|
||||
sysprof_document_mmap_get_file (map));
|
||||
}
|
||||
|
||||
g_print (" Mounts:\n");
|
||||
n_mounts = g_list_model_get_n_items (mounts);
|
||||
for (guint j = 0; j < n_mounts; j++)
|
||||
{
|
||||
g_autoptr(SysprofMount) mount = g_list_model_get_item (mounts, j);
|
||||
g_autofree char *subvol = sysprof_mount_get_superblock_option (mount, "subvol");
|
||||
|
||||
g_print (" %d %d %d:%d %s %s %s %s %s\n",
|
||||
sysprof_mount_get_mount_id (mount),
|
||||
sysprof_mount_get_parent_mount_id (mount),
|
||||
sysprof_mount_get_device_major (mount),
|
||||
sysprof_mount_get_device_minor (mount),
|
||||
sysprof_mount_get_root (mount),
|
||||
sysprof_mount_get_mount_point (mount),
|
||||
sysprof_mount_get_mount_source (mount),
|
||||
sysprof_mount_get_filesystem_type (mount),
|
||||
sysprof_mount_get_superblock_options (mount));
|
||||
|
||||
if (subvol != NULL)
|
||||
g_print (" Had subvol superblock option: %s\n", subvol);
|
||||
}
|
||||
|
||||
g_print (" Threads:\n");
|
||||
n_threads = g_list_model_get_n_items (threads);
|
||||
for (guint j = 0; j < n_threads; j++)
|
||||
{
|
||||
g_autoptr(SysprofThreadInfo) thread = g_list_model_get_item (threads, j);
|
||||
|
||||
g_print (" Thread-Id: %i%s\n",
|
||||
sysprof_thread_info_get_thread_id (thread),
|
||||
sysprof_thread_info_is_main_thread (thread) ? " [Main Thread]" : "");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
51
src/libsysprof/tests/test-maps-parser.c
Normal file
51
src/libsysprof/tests/test-maps-parser.c
Normal file
@ -0,0 +1,51 @@
|
||||
/* test-maps-parser.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-maps-parser-private.h"
|
||||
|
||||
#define ADDR_FORMAT "0x%"G_GINT64_MODIFIER"x"
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autofree char *contents = NULL;
|
||||
SysprofMapsParser parser;
|
||||
guint64 begin, end, offset, inode;
|
||||
char *file;
|
||||
gsize len;
|
||||
|
||||
g_assert_cmpint (argc, >, 1);
|
||||
g_file_get_contents (argv[1], &contents, &len, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
sysprof_maps_parser_init (&parser, contents, len);
|
||||
while (sysprof_maps_parser_next (&parser, &begin, &end, &offset, &inode, &file))
|
||||
{
|
||||
g_print (ADDR_FORMAT" - "ADDR_FORMAT" "ADDR_FORMAT" %"G_GUINT64_FORMAT" %s\n",
|
||||
begin, end, offset, inode, file);
|
||||
g_free (file);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
72
src/libsysprof/tests/test-mark-catalog.c
Normal file
72
src/libsysprof/tests/test-mark-catalog.c
Normal file
@ -0,0 +1,72 @@
|
||||
/* test-mark-catalog.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 <sysprof.h>
|
||||
|
||||
#include "sysprof-document-private.h"
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(SysprofDocumentLoader) loader = NULL;
|
||||
g_autoptr(SysprofDocument) document = NULL;
|
||||
g_autoptr(GListModel) groups = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
guint n_groups;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
g_printerr ("usage: %s CAPTURE_FILE\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
loader = sysprof_document_loader_new (argv[1]);
|
||||
sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ());
|
||||
|
||||
if (!(document = sysprof_document_loader_load (loader, NULL, &error)))
|
||||
{
|
||||
g_printerr ("Failed to open capture: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
groups = sysprof_document_catalog_marks (document);
|
||||
n_groups = g_list_model_get_n_items (groups);
|
||||
|
||||
for (guint i = 0; i < n_groups; i++)
|
||||
{
|
||||
g_autoptr(GListModel) catalogs = g_list_model_get_item (groups, i);
|
||||
guint n_catalogs = g_list_model_get_n_items (catalogs);
|
||||
|
||||
for (guint j = 0; j < n_catalogs; j++)
|
||||
{
|
||||
g_autoptr(SysprofMarkCatalog) catalog = g_list_model_get_item (catalogs, j);
|
||||
const char *group = sysprof_mark_catalog_get_group (catalog);
|
||||
const char *name = sysprof_mark_catalog_get_name (catalog);
|
||||
|
||||
if (j == 0)
|
||||
g_print ("%s\n", group);
|
||||
|
||||
g_print (" %s\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
66
src/libsysprof/tests/test-print-file.c
Normal file
66
src/libsysprof/tests/test-print-file.c
Normal file
@ -0,0 +1,66 @@
|
||||
/* test-print-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 <sysprof.h>
|
||||
|
||||
#include "sysprof-document-private.h"
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(SysprofDocumentLoader) loader = NULL;
|
||||
g_autoptr(SysprofDocumentFile) file = NULL;
|
||||
g_autoptr(SysprofDocument) document = NULL;
|
||||
g_autoptr(GListModel) files = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
g_printerr ("usage: %s CAPTURE_FILE EMBEDDED_FILE_PATH\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
loader = sysprof_document_loader_new (argv[1]);
|
||||
sysprof_document_loader_set_symbolizer (loader, sysprof_no_symbolizer_get ());
|
||||
|
||||
if (!(document = sysprof_document_loader_load (loader, NULL, &error)))
|
||||
{
|
||||
g_printerr ("Failed to open capture: %s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
file = sysprof_document_lookup_file (document, argv[2]);
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
g_printerr ("File \"%s\" not found.\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bytes = sysprof_document_file_dup_bytes (file);
|
||||
|
||||
write (STDOUT_FILENO,
|
||||
g_bytes_get_data (bytes, NULL),
|
||||
g_bytes_get_size (bytes));
|
||||
|
||||
return 0;
|
||||
}
|
||||
235
src/libsysprof/tests/test-profiler.c
Normal file
235
src/libsysprof/tests/test-profiler.c
Normal file
@ -0,0 +1,235 @@
|
||||
/* test-profiler.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-unix.h>
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include <sysprof.h>
|
||||
|
||||
static GMainLoop *main_loop;
|
||||
static char *capture_file;
|
||||
static SysprofRecording *active_recording;
|
||||
static gboolean memprof;
|
||||
static gboolean tracer;
|
||||
static gboolean gnome_shell;
|
||||
static char *power_profile;
|
||||
static const GOptionEntry entries[] = {
|
||||
{ "capture", 'c', 0, G_OPTION_ARG_FILENAME, &capture_file, "The file to capture into", "CAPTURE" },
|
||||
{ "memprof", 'm', 0, G_OPTION_ARG_NONE, &memprof, "Do memory allocation tracking on subprocess" },
|
||||
{ "tracer", 't', 0, G_OPTION_ARG_NONE, &tracer, "Enable tracing with __cyg_profile_enter" },
|
||||
{ "gnome-shell", 's', 0, G_OPTION_ARG_NONE, &gnome_shell, "Request GNOME Shell to provide profiler data" },
|
||||
{ "power-profile", 'p', 0, G_OPTION_ARG_STRING, &power_profile, "Use POWER_PROFILE for duration of recording", "power-saver|balanced|performance" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static void
|
||||
wait_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofRecording *recording = (SysprofRecording *)object;
|
||||
g_autoptr(GError) error = NULL;
|
||||
gboolean r;
|
||||
|
||||
r = sysprof_recording_wait_finish (recording, result, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_true (r);
|
||||
|
||||
g_main_loop_quit (main_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
diagnostics_items_changed_cb (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
gpointer user_data)
|
||||
{
|
||||
for (guint i = 0; i < added; i++)
|
||||
{
|
||||
g_autoptr(SysprofDiagnostic) diagnostic = g_list_model_get_item (model, position+i);
|
||||
|
||||
g_printerr ("%s: %s\n",
|
||||
sysprof_diagnostic_get_domain (diagnostic),
|
||||
sysprof_diagnostic_get_message (diagnostic));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
record_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(SysprofRecording) recording = sysprof_profiler_record_finish (SYSPROF_PROFILER (object), result, &error);
|
||||
g_autoptr(GListModel) diagnostics = NULL;
|
||||
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (recording);
|
||||
g_assert_true (SYSPROF_IS_RECORDING (recording));
|
||||
|
||||
diagnostics = sysprof_recording_list_diagnostics (recording);
|
||||
g_signal_connect (diagnostics,
|
||||
"items-changed",
|
||||
G_CALLBACK (diagnostics_items_changed_cb),
|
||||
NULL);
|
||||
diagnostics_items_changed_cb (diagnostics,
|
||||
0,
|
||||
0,
|
||||
g_list_model_get_n_items (diagnostics),
|
||||
NULL);
|
||||
|
||||
sysprof_recording_wait_async (recording, NULL, wait_cb, NULL);
|
||||
|
||||
active_recording = recording;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sigint_handler (gpointer user_data)
|
||||
{
|
||||
static int count;
|
||||
|
||||
if (count >= 2)
|
||||
{
|
||||
g_main_loop_quit (main_loop);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
g_printerr ("\n");
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
g_printerr ("%s\n", "Stopping profiler. Press twice more ^C to force exit.");
|
||||
sysprof_recording_stop_async (active_recording, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(GOptionContext) context = g_option_context_new ("[-- [COMMAND...]]");
|
||||
g_autoptr(SysprofProfiler) profiler = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_auto(GStrv) argv_copy = NULL;
|
||||
SysprofCaptureWriter *writer = NULL;
|
||||
SysprofCaptureReader *reader = NULL;
|
||||
g_autofd int trace_fd = -1;
|
||||
int argv_copy_len = 0;
|
||||
|
||||
sysprof_clock_init ();
|
||||
|
||||
main_loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
argv_copy = g_new0 (char *, argc+1);
|
||||
for (guint i = 0; i < argc; i++)
|
||||
{
|
||||
if (strcmp ("--", argv[i]) == 0)
|
||||
{
|
||||
argv_copy[i] = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
argv_copy[i] = g_strdup (argv[i]);
|
||||
argv_copy_len++;
|
||||
}
|
||||
|
||||
g_option_context_add_main_entries (context, entries, NULL);
|
||||
|
||||
if (!g_option_context_parse (context, &argv_copy_len, &argv_copy, &error))
|
||||
{
|
||||
g_printerr ("%s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (capture_file == NULL)
|
||||
writer = sysprof_capture_writer_new ("capture.syscap", 0);
|
||||
else
|
||||
writer = sysprof_capture_writer_new (capture_file, 0);
|
||||
|
||||
profiler = sysprof_profiler_new ();
|
||||
|
||||
sysprof_profiler_add_instrument (profiler, sysprof_battery_charge_new ());
|
||||
sysprof_profiler_add_instrument (profiler, sysprof_cpu_usage_new ());
|
||||
sysprof_profiler_add_instrument (profiler, sysprof_disk_usage_new ());
|
||||
sysprof_profiler_add_instrument (profiler, sysprof_energy_usage_new ());
|
||||
sysprof_profiler_add_instrument (profiler, sysprof_memory_usage_new ());
|
||||
sysprof_profiler_add_instrument (profiler, sysprof_network_usage_new ());
|
||||
sysprof_profiler_add_instrument (profiler, sysprof_system_logs_new ());
|
||||
|
||||
if (power_profile)
|
||||
sysprof_profiler_add_instrument (profiler, sysprof_power_profile_new (power_profile));
|
||||
|
||||
if (gnome_shell)
|
||||
sysprof_profiler_add_instrument (profiler,
|
||||
sysprof_proxied_instrument_new (G_BUS_TYPE_SESSION,
|
||||
"org.gnome.Shell",
|
||||
"/org/gnome/Sysprof3/Profiler"));
|
||||
if (memprof)
|
||||
sysprof_profiler_add_instrument (profiler, sysprof_malloc_tracing_new ());
|
||||
|
||||
if (tracer)
|
||||
sysprof_profiler_add_instrument (profiler, sysprof_tracer_new ());
|
||||
else
|
||||
sysprof_profiler_add_instrument (profiler, sysprof_sampler_new ());
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
if (strcmp (argv[i], "--") == 0 && i+1 < argc)
|
||||
{
|
||||
g_autoptr(SysprofSpawnable) spawnable = sysprof_spawnable_new ();
|
||||
|
||||
sysprof_spawnable_append_args (spawnable, (const char * const *)&argv[i+1]);
|
||||
sysprof_spawnable_set_cwd (spawnable, g_get_current_dir ());
|
||||
|
||||
sysprof_profiler_set_spawnable (profiler, spawnable);
|
||||
|
||||
trace_fd = sysprof_spawnable_add_trace_fd (spawnable, NULL);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sysprof_profiler_record_async (profiler, writer, NULL, record_cb, NULL);
|
||||
|
||||
g_unix_signal_add (SIGINT, sigint_handler, main_loop);
|
||||
g_unix_signal_add (SIGTERM, sigint_handler, main_loop);
|
||||
|
||||
g_main_loop_run (main_loop);
|
||||
|
||||
if (trace_fd != -1)
|
||||
{
|
||||
if ((reader = sysprof_capture_reader_new_from_fd (g_steal_fd (&trace_fd))))
|
||||
sysprof_capture_writer_cat (writer, reader);
|
||||
}
|
||||
|
||||
sysprof_capture_writer_flush (writer);
|
||||
|
||||
g_clear_pointer (&reader, sysprof_capture_reader_unref);
|
||||
g_clear_pointer (&writer, sysprof_capture_writer_unref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
48
src/libsysprof/tests/test-strings.c
Normal file
48
src/libsysprof/tests/test-strings.c
Normal file
@ -0,0 +1,48 @@
|
||||
/* test-strings.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.h>
|
||||
|
||||
#include "sysprof-strings-private.h"
|
||||
|
||||
static void
|
||||
test_basic (void)
|
||||
{
|
||||
SysprofStrings *strings = sysprof_strings_new ();
|
||||
|
||||
g_ref_string_release (sysprof_strings_get (strings, "123"));
|
||||
g_ref_string_release (sysprof_strings_get (strings, "456"));
|
||||
|
||||
g_ref_string_release (sysprof_strings_get (strings, "123"));
|
||||
g_ref_string_release (sysprof_strings_get (strings, "456"));
|
||||
|
||||
sysprof_strings_unref (strings);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
g_test_add_func ("/libsysprof/Strings/basic", test_basic);
|
||||
return g_test_run ();
|
||||
}
|
||||
244
src/libsysprof/tests/test-symbol-cache.c
Normal file
244
src/libsysprof/tests/test-symbol-cache.c
Normal file
@ -0,0 +1,244 @@
|
||||
/* test-symbol-cache.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 <stdlib.h>
|
||||
|
||||
#include <sysprof.h>
|
||||
|
||||
#include "sysprof-symbol-private.h"
|
||||
#include "sysprof-symbol-cache-private.h"
|
||||
|
||||
typedef struct _SymbolInfo
|
||||
{
|
||||
const char *name;
|
||||
guint64 begin;
|
||||
guint64 end;
|
||||
int position;
|
||||
int sort;
|
||||
SysprofSymbol *symbol;
|
||||
} SymbolInfo;
|
||||
|
||||
static SysprofSymbol *
|
||||
create_symbol (const char *name,
|
||||
guint64 begin,
|
||||
guint64 end)
|
||||
{
|
||||
g_assert (begin < end);
|
||||
|
||||
return _sysprof_symbol_new (g_ref_string_new (name), NULL, NULL, begin, end, SYSPROF_SYMBOL_KIND_USER);
|
||||
}
|
||||
|
||||
static int
|
||||
sort_by_key (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const SymbolInfo *info_a = a;
|
||||
const SymbolInfo *info_b = b;
|
||||
|
||||
if (info_a->sort < info_b->sort)
|
||||
return -1;
|
||||
else if (info_a->sort > info_b->sort)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sort_by_position (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const SymbolInfo *info_a = a;
|
||||
const SymbolInfo *info_b = b;
|
||||
|
||||
if (info_a->position < info_b->position)
|
||||
return -1;
|
||||
else if (info_a->position > info_b->position)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_interval_tree (void)
|
||||
{
|
||||
SysprofSymbolCache *symbol_cache = sysprof_symbol_cache_new ();
|
||||
SymbolInfo symbols[] = {
|
||||
{ "symbol1", 0x10000, 0x20000 },
|
||||
{ "symbol2", 0x20000, 0x30000 },
|
||||
{ "symbol3", 0x30000, 0x40000 },
|
||||
{ "symbol4", 0x90000, 0xa0000 },
|
||||
{ "symbol5", 0xb0000, 0xb0001 },
|
||||
{ "symbol6", 0xb0001, 0xb0002 },
|
||||
};
|
||||
|
||||
/* Add some randomness on insertion */
|
||||
for (guint i = 0; i < G_N_ELEMENTS (symbols); i++)
|
||||
{
|
||||
symbols[i].position = i;
|
||||
symbols[i].sort = g_random_int ();
|
||||
}
|
||||
|
||||
/* Sort randomly for insertion */
|
||||
qsort (symbols, G_N_ELEMENTS (symbols), sizeof (SymbolInfo), sort_by_key);
|
||||
for (guint i = 0; i < G_N_ELEMENTS (symbols); i++)
|
||||
{
|
||||
SymbolInfo *info = &symbols[i];
|
||||
|
||||
g_assert_cmpint (info->begin, <, info->end);
|
||||
|
||||
info->symbol = create_symbol (info->name, info->begin, info->end);
|
||||
|
||||
g_assert_nonnull (info->symbol);
|
||||
g_assert_true (SYSPROF_IS_SYMBOL (info->symbol));
|
||||
|
||||
sysprof_symbol_cache_take (symbol_cache, g_object_ref (info->symbol));
|
||||
}
|
||||
|
||||
/* Now resort to do lookups with edge checking */
|
||||
qsort (symbols, G_N_ELEMENTS (symbols), sizeof (SymbolInfo), sort_by_position);
|
||||
for (guint i = 0; i < G_N_ELEMENTS (symbols); i++)
|
||||
{
|
||||
const SymbolInfo *info = &symbols[i];
|
||||
const SymbolInfo *prev = i > 0 ? &symbols[i-1] : NULL;
|
||||
const SymbolInfo *next = i + 1 < G_N_ELEMENTS (symbols) ? &symbols[i+1] : NULL;
|
||||
SysprofSymbol *lookup;
|
||||
|
||||
g_assert_cmpint (info->position, ==, i);
|
||||
|
||||
lookup = sysprof_symbol_cache_lookup (symbol_cache, info->begin-1);
|
||||
if (prev && info->begin == prev->end)
|
||||
g_assert_true (lookup == prev->symbol);
|
||||
else
|
||||
g_assert_null (lookup);
|
||||
|
||||
lookup = sysprof_symbol_cache_lookup (symbol_cache, info->begin);
|
||||
g_assert_nonnull (lookup);
|
||||
g_assert_true (lookup == info->symbol);
|
||||
|
||||
lookup = sysprof_symbol_cache_lookup (symbol_cache, info->end);
|
||||
if (next == NULL || next->begin > info->end)
|
||||
g_assert_null (lookup);
|
||||
else
|
||||
g_assert_true (lookup == next->symbol);
|
||||
|
||||
if (info->begin+1 != info->end)
|
||||
{
|
||||
lookup = sysprof_symbol_cache_lookup (symbol_cache, info->begin+1);
|
||||
g_assert_nonnull (lookup);
|
||||
g_assert_true (lookup == info->symbol);
|
||||
}
|
||||
|
||||
lookup = sysprof_symbol_cache_lookup (symbol_cache, info->end-1);
|
||||
g_assert_nonnull (lookup);
|
||||
g_assert_true (lookup == info->symbol);
|
||||
|
||||
lookup = sysprof_symbol_cache_lookup (symbol_cache, info->begin + ((info->end-info->begin)/2));
|
||||
g_assert_nonnull (lookup);
|
||||
g_assert_true (lookup == info->symbol);
|
||||
}
|
||||
|
||||
g_assert_finalize_object (symbol_cache);
|
||||
|
||||
for (guint i = 0; i < G_N_ELEMENTS (symbols); i++)
|
||||
g_assert_finalize_object (symbols[i].symbol);
|
||||
}
|
||||
|
||||
static void
|
||||
test_jitmap (void)
|
||||
{
|
||||
SysprofSymbolCache *symbol_cache = sysprof_symbol_cache_new ();
|
||||
|
||||
for (guint i = 1; i <= 10000; i++)
|
||||
{
|
||||
SysprofAddress begin = 0xE000000000000000 + i;
|
||||
g_autofree char *name = g_strdup_printf ("%u", i);
|
||||
SysprofSymbol *symbol = create_symbol (name, begin, begin+1);
|
||||
|
||||
sysprof_symbol_cache_take (symbol_cache, symbol);
|
||||
}
|
||||
|
||||
g_assert_null (sysprof_symbol_cache_lookup (symbol_cache, 0));
|
||||
g_assert_null (sysprof_symbol_cache_lookup (symbol_cache, 10001));
|
||||
|
||||
for (guint i = 1; i <= 10000; i++)
|
||||
{
|
||||
SysprofAddress begin = 0xE000000000000000 + i;
|
||||
SysprofSymbol *symbol = sysprof_symbol_cache_lookup (symbol_cache, begin);
|
||||
g_autofree char *name = g_strdup_printf ("%u", i);
|
||||
|
||||
g_assert_nonnull (symbol);
|
||||
g_assert_cmpint (begin, ==, symbol->begin_address);
|
||||
g_assert_cmpint (begin+1, ==, symbol->end_address);
|
||||
g_assert_cmpstr (name, ==, symbol->name);
|
||||
}
|
||||
|
||||
g_assert_finalize_object (symbol_cache);
|
||||
}
|
||||
|
||||
static void
|
||||
test_collision (void)
|
||||
{
|
||||
SysprofSymbolCache *symbol_cache = sysprof_symbol_cache_new ();
|
||||
SysprofSymbol *first = NULL;
|
||||
|
||||
for (guint i = 1; i <= 10000; i++)
|
||||
{
|
||||
SysprofAddress begin = 0xe000000000000000 + i;
|
||||
g_autofree char *name = g_strdup_printf ("%u", i);
|
||||
SysprofSymbol *symbol = create_symbol (name, begin, begin+1);
|
||||
|
||||
if (first == NULL)
|
||||
first = g_object_ref (symbol);
|
||||
|
||||
sysprof_symbol_cache_take (symbol_cache, symbol);
|
||||
}
|
||||
|
||||
g_assert_true (SYSPROF_IS_SYMBOL (first));
|
||||
|
||||
for (guint i = 1; i <= 10000; i++)
|
||||
{
|
||||
SysprofAddress begin = 0xE000000000000000 + i;
|
||||
g_autofree char *name = g_strdup_printf ("%u", i);
|
||||
SysprofSymbol *symbol = create_symbol (name, begin, begin+1);
|
||||
|
||||
sysprof_symbol_cache_take (symbol_cache, symbol);
|
||||
}
|
||||
|
||||
g_assert_finalize_object (symbol_cache);
|
||||
g_assert_finalize_object (first);
|
||||
|
||||
/* To test this fully, you need `-Db_sanitize=address` so that
|
||||
* you can detect any leaks from RB_INSERT().
|
||||
*/
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
g_test_add_func ("/libsysprof/SysprofSymbolCache/interval-tree",
|
||||
test_interval_tree);
|
||||
g_test_add_func ("/libsysprof/SysprofSymbolCache/jitmap",
|
||||
test_jitmap);
|
||||
g_test_add_func ("/libsysprof/SysprofSymbolCache/collision",
|
||||
test_collision);
|
||||
return g_test_run ();
|
||||
}
|
||||
173
src/libsysprof/tests/test-symbolize.c
Normal file
173
src/libsysprof/tests/test-symbolize.c
Normal file
@ -0,0 +1,173 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <sysprof.h>
|
||||
|
||||
#include "sysprof-document-private.h"
|
||||
|
||||
static GMainLoop *main_loop;
|
||||
static gboolean silent;
|
||||
static gboolean no_bundled;
|
||||
static char **debug_dirs;
|
||||
static char *kallsyms_path;
|
||||
static const GOptionEntry entries[] = {
|
||||
{ "no-bundled", 'b', 0, G_OPTION_ARG_NONE, &no_bundled, "Ignore symbols bundled in capture file" },
|
||||
{ "silent", 's', 0, G_OPTION_ARG_NONE, &silent, "Do not print symbol information" },
|
||||
{ "debug-dir", 'd', 0, G_OPTION_ARG_FILENAME_ARRAY, &debug_dirs, "Specify external debug directory, may be repeated" },
|
||||
{ "kallsyms", 'k', 0, G_OPTION_ARG_FILENAME, &kallsyms_path, "Specify path to kallsyms for kernel symbolizing" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
load_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofDocumentLoader *loader = (SysprofDocumentLoader *)object;
|
||||
g_autoptr(SysprofDocument) document = NULL;
|
||||
g_autoptr(GListModel) traceables = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GString) str = NULL;
|
||||
SysprofSymbol *symbols[128];
|
||||
guint n_symbols;
|
||||
guint n_items;
|
||||
|
||||
g_assert (SYSPROF_IS_DOCUMENT_LOADER (loader));
|
||||
g_assert (G_IS_ASYNC_RESULT (result));
|
||||
|
||||
if (!(document = sysprof_document_loader_load_finish (loader, result, &error)))
|
||||
g_error ("Failed to load document: %s", error->message);
|
||||
|
||||
traceables = sysprof_document_list_traceables (document);
|
||||
n_items = g_list_model_get_n_items (traceables);
|
||||
|
||||
if (silent)
|
||||
{
|
||||
g_main_loop_quit (main_loop);
|
||||
return;
|
||||
}
|
||||
|
||||
str = g_string_new ("");
|
||||
|
||||
for (guint i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr(SysprofDocumentTraceable) traceable = g_list_model_get_item (traceables, i);
|
||||
|
||||
str->len = 0;
|
||||
str->str[0] = 0;
|
||||
|
||||
g_assert (traceable != NULL);
|
||||
g_assert (SYSPROF_IS_DOCUMENT_TRACEABLE (traceable));
|
||||
|
||||
n_symbols = sysprof_document_symbolize_traceable (document,
|
||||
traceable,
|
||||
symbols,
|
||||
G_N_ELEMENTS (symbols),
|
||||
NULL);
|
||||
|
||||
g_print ("%s depth=%u pid=%u\n",
|
||||
G_OBJECT_TYPE_NAME (traceable),
|
||||
n_symbols,
|
||||
sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable)));
|
||||
|
||||
for (guint j = 0; j < n_symbols; j++)
|
||||
{
|
||||
SysprofSymbol *symbol = symbols[j];
|
||||
const char *name;
|
||||
const char *path;
|
||||
const char *nick;
|
||||
|
||||
if (symbol != NULL)
|
||||
{
|
||||
name = sysprof_symbol_get_name (symbol);
|
||||
path = sysprof_symbol_get_binary_path (symbol);
|
||||
nick = sysprof_symbol_get_binary_nick (symbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = path = nick = NULL;
|
||||
}
|
||||
|
||||
g_string_append_printf (str,
|
||||
" %02d: 0x%"G_GINT64_MODIFIER"x:",
|
||||
j,
|
||||
sysprof_document_traceable_get_stack_address (traceable, j));
|
||||
|
||||
if (name)
|
||||
g_string_append_printf (str, " %s", name);
|
||||
|
||||
if (path)
|
||||
g_string_append_printf (str, " [%s]", path);
|
||||
|
||||
if (nick)
|
||||
g_string_append_printf (str, " (%s)", nick);
|
||||
|
||||
g_string_append_c (str, '\n');
|
||||
}
|
||||
|
||||
g_string_append (str, " ================\n");
|
||||
|
||||
write (STDOUT_FILENO, str->str, str->len);
|
||||
}
|
||||
|
||||
g_print ("Document symbolized\n");
|
||||
|
||||
g_main_loop_quit (main_loop);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr(SysprofDocumentLoader) loader = NULL;
|
||||
g_autoptr(GOptionContext) context = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
main_loop = g_main_loop_new (NULL, FALSE);
|
||||
context = g_option_context_new ("- test document symbolization");
|
||||
g_option_context_add_main_entries (context, entries, NULL);
|
||||
|
||||
if (!g_option_context_parse (context, &argc, &argv, &error))
|
||||
{
|
||||
g_printerr ("%s\n", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc != 2 || !g_file_test (argv[1], G_FILE_TEST_EXISTS))
|
||||
{
|
||||
g_printerr ("usage: %s CAPTURE_FILE\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
loader = sysprof_document_loader_new (argv[1]);
|
||||
|
||||
if (TRUE)
|
||||
{
|
||||
g_autoptr(SysprofMultiSymbolizer) multi = sysprof_multi_symbolizer_new ();
|
||||
SysprofSymbolizer *elf = sysprof_elf_symbolizer_new ();
|
||||
g_autoptr(GFile) kallsyms_file = kallsyms_path ? g_file_new_for_path (kallsyms_path) : NULL;
|
||||
GFileInputStream *kallsyms_stream = kallsyms_file ? g_file_read (kallsyms_file, NULL, NULL) : NULL;
|
||||
|
||||
if (debug_dirs)
|
||||
sysprof_elf_symbolizer_set_external_debug_dirs (SYSPROF_ELF_SYMBOLIZER (elf),
|
||||
(const char * const *)debug_dirs);
|
||||
|
||||
if (!no_bundled)
|
||||
sysprof_multi_symbolizer_take (multi, sysprof_bundled_symbolizer_new ());
|
||||
|
||||
if (kallsyms_stream == NULL)
|
||||
sysprof_multi_symbolizer_take (multi, sysprof_kallsyms_symbolizer_new ());
|
||||
else
|
||||
sysprof_multi_symbolizer_take (multi, sysprof_kallsyms_symbolizer_new_for_symbols (G_INPUT_STREAM (kallsyms_stream)));
|
||||
|
||||
sysprof_multi_symbolizer_take (multi, elf);
|
||||
sysprof_multi_symbolizer_take (multi, sysprof_jitmap_symbolizer_new ());
|
||||
|
||||
sysprof_document_loader_set_symbolizer (loader, SYSPROF_SYMBOLIZER (multi));
|
||||
}
|
||||
|
||||
sysprof_document_loader_load_async (loader, NULL, load_cb, NULL);
|
||||
g_main_loop_run (main_loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user