From 97bae7d9e3a412a73665cb3a1b62e19f0baf8b1e Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Tue, 21 May 2019 09:53:34 -0700 Subject: [PATCH] libsysprof-capture: add cat helper --- src/libsysprof-capture/meson.build | 1 + .../sysprof-capture-writer-cat.c | 412 ++++++++++++++++++ .../sysprof-capture-writer.h | 4 + 3 files changed, 417 insertions(+) create mode 100644 src/libsysprof-capture/sysprof-capture-writer-cat.c diff --git a/src/libsysprof-capture/meson.build b/src/libsysprof-capture/meson.build index 70bbcc72..c17c688f 100644 --- a/src/libsysprof-capture/meson.build +++ b/src/libsysprof-capture/meson.build @@ -18,6 +18,7 @@ libsysprof_capture_sources = files([ 'sysprof-capture-reader.c', 'sysprof-capture-util.c', 'sysprof-capture-writer.c', + 'sysprof-capture-writer-cat.c', 'sysprof-clock.c', 'sysprof-platform.c', ]) diff --git a/src/libsysprof-capture/sysprof-capture-writer-cat.c b/src/libsysprof-capture/sysprof-capture-writer-cat.c new file mode 100644 index 00000000..97437404 --- /dev/null +++ b/src/libsysprof-capture/sysprof-capture-writer-cat.c @@ -0,0 +1,412 @@ +/* sysprof-cat.c + * + * Copyright 2018-2019 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#define G_LOG_DOMAIN "sysprof-cat" + +#include "config.h" + +#include +#include +#include +#include + +typedef struct +{ + guint64 src; + guint64 dst; +} TranslateItem; + +enum { + TRANSLATE_ADDR, + TRANSLATE_CTR, + N_TRANSLATE +}; + +static void +translate_table_clear (GArray **tables, + guint table) +{ + g_clear_pointer (&tables[table], g_array_unref); +} + +static gint +compare_by_src (gconstpointer a, + gconstpointer b) +{ + const TranslateItem *itema = a; + const TranslateItem *itemb = a; + + if (itema->src < itemb->src) + return -1; + else if (itema->src > itemb->src) + return 1; + else + return 0; +} + +static void +translate_table_sort (GArray **tables, + guint table) +{ + if (tables[table]) + g_array_sort (tables[table], compare_by_src); +} + +static void +translate_table_add (GArray **tables, + guint table, + guint64 src, + guint64 dst) +{ + TranslateItem item = { src, dst }; + + if (tables[table] == NULL) + tables[table] = g_array_new (FALSE, FALSE, sizeof (TranslateItem)); + + g_array_append_val (tables[table], item); +} + +static guint64 +translate_table_translate (GArray **tables, + guint table, + guint64 src) +{ + const TranslateItem *item; + TranslateItem key = { src, 0 }; + + if (!tables[table]) + return src; + + item = bsearch (&key, + tables[table]->data, + tables[table]->len, + sizeof (TranslateItem), + compare_by_src); + + return item != NULL ? item->dst : src; +} + +gboolean +sysprof_capture_writer_cat (SysprofCaptureWriter *self, + SysprofCaptureReader *reader, + GError **error) +{ + GArray *tables[N_TRANSLATE] = { NULL }; + SysprofCaptureFrameType type; + gint64 start_time; + gint64 first_start_time = G_MAXINT64; + gint64 end_time = -1; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (reader != NULL, FALSE); + + translate_table_clear (tables, TRANSLATE_CTR); + translate_table_clear (tables, TRANSLATE_ADDR); + + start_time = sysprof_capture_reader_get_start_time (reader); + + if (start_time < first_start_time) + first_start_time = start_time; + + while (sysprof_capture_reader_peek_type (reader, &type)) + { + SysprofCaptureFrame fr; + + if (sysprof_capture_reader_peek_frame (reader, &fr)) + { + if (fr.time > end_time) + end_time = fr.time; + } + + switch (type) + { + case SYSPROF_CAPTURE_FRAME_TIMESTAMP: + { + const SysprofCaptureTimestamp *frame; + + if (!(frame = sysprof_capture_reader_read_timestamp (reader))) + goto panic; + + sysprof_capture_writer_add_timestamp (self, + frame->frame.time, + frame->frame.cpu, + frame->frame.pid); + break; + } + + case SYSPROF_CAPTURE_FRAME_MAP: + { + const SysprofCaptureMap *frame; + + if (!(frame = sysprof_capture_reader_read_map (reader))) + goto panic; + + sysprof_capture_writer_add_map (self, + frame->frame.time, + frame->frame.cpu, + frame->frame.pid, + frame->start, + frame->end, + frame->offset, + frame->inode, + frame->filename); + break; + } + + case SYSPROF_CAPTURE_FRAME_MARK: + { + const SysprofCaptureMark *frame; + + if (!(frame = sysprof_capture_reader_read_mark (reader))) + goto panic; + + sysprof_capture_writer_add_mark (self, + frame->frame.time, + frame->frame.cpu, + frame->frame.pid, + frame->duration, + frame->group, + frame->name, + frame->message); + + if (frame->frame.time + frame->duration > end_time) + end_time = frame->frame.time + frame->duration; + + break; + } + + case SYSPROF_CAPTURE_FRAME_PROCESS: + { + const SysprofCaptureProcess *frame; + + if (!(frame = sysprof_capture_reader_read_process (reader))) + goto panic; + + sysprof_capture_writer_add_process (self, + frame->frame.time, + frame->frame.cpu, + frame->frame.pid, + frame->cmdline); + break; + } + + case SYSPROF_CAPTURE_FRAME_FORK: + { + const SysprofCaptureFork *frame; + + if (!(frame = sysprof_capture_reader_read_fork (reader))) + goto panic; + + sysprof_capture_writer_add_fork (self, + frame->frame.time, + frame->frame.cpu, + frame->frame.pid, + frame->child_pid); + break; + } + + case SYSPROF_CAPTURE_FRAME_EXIT: + { + const SysprofCaptureExit *frame; + + if (!(frame = sysprof_capture_reader_read_exit (reader))) + goto panic; + + sysprof_capture_writer_add_exit (self, + frame->frame.time, + frame->frame.cpu, + frame->frame.pid); + break; + } + + case SYSPROF_CAPTURE_FRAME_METADATA: + { + const SysprofCaptureMetadata *frame; + + if (!(frame = sysprof_capture_reader_read_metadata (reader))) + goto panic; + + sysprof_capture_writer_add_metadata (self, + frame->frame.time, + frame->frame.cpu, + frame->frame.pid, + frame->id, + frame->metadata, + frame->frame.len - G_STRUCT_OFFSET (SysprofCaptureMetadata, metadata)); + break; + } + + case SYSPROF_CAPTURE_FRAME_JITMAP: + { + GHashTable *jitmap; + GHashTableIter iter; + const gchar *name; + guint64 addr; + + if (!(jitmap = sysprof_capture_reader_read_jitmap (reader))) + goto panic; + + g_hash_table_iter_init (&iter, jitmap); + while (g_hash_table_iter_next (&iter, (gpointer *)&addr, (gpointer *)&name)) + { + guint64 replace = sysprof_capture_writer_add_jitmap (self, name); + /* We need to keep a table of replacement addresses so that + * we can translate the samples into the destination address + * space that we synthesized for the address identifier. + */ + translate_table_add (tables, TRANSLATE_ADDR, addr, replace); + } + + translate_table_sort (tables, TRANSLATE_ADDR); + + g_hash_table_unref (jitmap); + + break; + } + + case SYSPROF_CAPTURE_FRAME_SAMPLE: + { + const SysprofCaptureSample *frame; + + if (!(frame = sysprof_capture_reader_read_sample (reader))) + goto panic; + + { + SysprofCaptureAddress addrs[frame->n_addrs]; + + for (guint z = 0; z < frame->n_addrs; z++) + addrs[z] = translate_table_translate (tables, TRANSLATE_ADDR, frame->addrs[z]); + + sysprof_capture_writer_add_sample (self, + frame->frame.time, + frame->frame.cpu, + frame->frame.pid, + frame->tid, + addrs, + frame->n_addrs); + } + + break; + } + + case SYSPROF_CAPTURE_FRAME_CTRDEF: + { + const SysprofCaptureFrameCounterDefine *frame; + + if (!(frame = sysprof_capture_reader_read_counter_define (reader))) + goto panic; + + { + g_autoptr(GArray) counter = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter)); + + for (guint z = 0; z < frame->n_counters; z++) + { + SysprofCaptureCounter c = frame->counters[z]; + guint src = c.id; + + c.id = sysprof_capture_writer_request_counter (self, 1); + + if (c.id != src) + translate_table_add (tables, TRANSLATE_CTR, src, c.id); + + g_array_append_val (counter, c); + } + + sysprof_capture_writer_define_counters (self, + frame->frame.time, + frame->frame.cpu, + frame->frame.pid, + (gpointer)counter->data, + counter->len); + + translate_table_sort (tables, TRANSLATE_CTR); + } + + break; + } + + case SYSPROF_CAPTURE_FRAME_CTRSET: + { + const SysprofCaptureFrameCounterSet *frame; + + if (!(frame = sysprof_capture_reader_read_counter_set (reader))) + goto panic; + + { + g_autoptr(GArray) ids = g_array_new (FALSE, FALSE, sizeof (guint)); + g_autoptr(GArray) values = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounterValue)); + + for (guint z = 0; z < frame->n_values; z++) + { + const SysprofCaptureCounterValues *v = &frame->values[z]; + + for (guint y = 0; y < G_N_ELEMENTS (v->ids); y++) + { + if (v->ids[y]) + { + guint dst = translate_table_translate (tables, TRANSLATE_CTR, v->ids[y]); + SysprofCaptureCounterValue value = v->values[y]; + + g_array_append_val (ids, dst); + g_array_append_val (values, value); + } + } + } + + g_assert (ids->len == values->len); + + sysprof_capture_writer_set_counters (self, + frame->frame.time, + frame->frame.cpu, + frame->frame.pid, + (const guint *)(gpointer)ids->data, + (const SysprofCaptureCounterValue *)(gpointer)values->data, + ids->len); + } + + break; + } + + default: + break; + } + } + + sysprof_capture_writer_flush (self); + + /* do this after flushing as it uses pwrite() to replace data */ + _sysprof_capture_writer_set_time_range (self, first_start_time, end_time); + + translate_table_clear (tables, TRANSLATE_ADDR); + translate_table_clear (tables, TRANSLATE_CTR); + + return TRUE; + +panic: + g_set_error (error, + G_FILE_ERROR, + G_FILE_ERROR_FAILED, + "Failed to write data"); + + translate_table_clear (tables, TRANSLATE_ADDR); + translate_table_clear (tables, TRANSLATE_CTR); + + return FALSE; +} diff --git a/src/libsysprof-capture/sysprof-capture-writer.h b/src/libsysprof-capture/sysprof-capture-writer.h index ebb2b8d2..20742613 100644 --- a/src/libsysprof-capture/sysprof-capture-writer.h +++ b/src/libsysprof-capture/sysprof-capture-writer.h @@ -133,6 +133,10 @@ SYSPROF_AVAILABLE_IN_ALL gboolean sysprof_capture_writer_splice (SysprofCaptureWriter *self, SysprofCaptureWriter *dest, GError **error); +SYSPROF_AVAILABLE_IN_ALL +gboolean sysprof_capture_writer_cat (SysprofCaptureWriter *self, + SysprofCaptureReader *reader, + GError **error); G_GNUC_INTERNAL gboolean _sysprof_capture_writer_splice_from_fd (SysprofCaptureWriter *self, int fd,