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:
Christian Hergert
2023-07-19 17:40:41 -07:00
parent a990fc6b3c
commit dbb7833cbf
217 changed files with 187 additions and 316 deletions

View 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

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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 ();
}

View 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 ();
}

View 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;
}