diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build index 6fd8b7f7..e7855fa8 100644 --- a/src/libsysprof/meson.build +++ b/src/libsysprof/meson.build @@ -57,6 +57,7 @@ libsysprof_public_sources = [ 'sysprof-system-logs.c', 'sysprof-thread-info.c', 'sysprof-time-span.c', + 'sysprof-tracefd-consumer.c', 'sysprof-tracer.c', ] @@ -118,6 +119,7 @@ libsysprof_public_headers = [ 'sysprof-system-logs.h', 'sysprof-thread-info.h', 'sysprof-time-span.h', + 'sysprof-tracefd-consumer.h', 'sysprof-tracer.h', ] diff --git a/src/libsysprof/sysprof-tracefd-consumer.c b/src/libsysprof/sysprof-tracefd-consumer.c new file mode 100644 index 00000000..c68e0fe8 --- /dev/null +++ b/src/libsysprof/sysprof-tracefd-consumer.c @@ -0,0 +1,116 @@ +/* sysprof-tracefd-consumer.c + * + * Copyright 2023 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "config.h" + +#include + +#include "sysprof-instrument-private.h" +#include "sysprof-recording-private.h" +#include "sysprof-tracefd-consumer.h" + +struct _SysprofTracefdConsumer +{ + SysprofInstrument parent_instance; + int trace_fd; +}; + +struct _SysprofTracefdConsumerClass +{ + SysprofInstrumentClass parent_class; +}; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofCaptureReader, sysprof_capture_reader_unref) + +G_DEFINE_FINAL_TYPE (SysprofTracefdConsumer, sysprof_tracefd_consumer, SYSPROF_TYPE_INSTRUMENT) + +static DexFuture * +sysprof_tracefd_consumer_augment (SysprofInstrument *instrument, + SysprofRecording *recording) +{ + SysprofTracefdConsumer *self = (SysprofTracefdConsumer *)instrument; + g_autoptr(SysprofCaptureReader) reader = NULL; + SysprofCaptureWriter *writer; + + g_assert (SYSPROF_IS_TRACEFD_CONSUMER (self)); + g_assert (SYSPROF_IS_RECORDING (recording)); + + if (self->trace_fd == -1) + return dex_future_new_for_boolean (TRUE); + + writer = _sysprof_recording_writer (recording); + + lseek (self->trace_fd, 0, SEEK_SET); + + if ((reader = sysprof_capture_reader_new_from_fd (g_steal_fd (&self->trace_fd)))) + sysprof_capture_writer_cat (writer, reader); + + return dex_future_new_for_boolean (TRUE); +} + +static void +sysprof_tracefd_consumer_finalize (GObject *object) +{ + SysprofTracefdConsumer *self = (SysprofTracefdConsumer *)object; + + g_clear_fd (&self->trace_fd, NULL); + + G_OBJECT_CLASS (sysprof_tracefd_consumer_parent_class)->finalize (object); +} + +static void +sysprof_tracefd_consumer_class_init (SysprofTracefdConsumerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + SysprofInstrumentClass *instrument_class = SYSPROF_INSTRUMENT_CLASS (klass); + + object_class->finalize = sysprof_tracefd_consumer_finalize; + + instrument_class->augment = sysprof_tracefd_consumer_augment; +} + +static void +sysprof_tracefd_consumer_init (SysprofTracefdConsumer *self) +{ + self->trace_fd = -1; +} + +/** + * sysprof_tracefd_consumer_new: + * @trace_fd: a file-descriptor to read from + * + * This function will take ownership of @trace_fd, If you need to keep a + * copy of your FD then it is suggested you use `dup()` to copy the file + * descriptor. + * + * Returns: (transfer full): a #SysprofInstrument + */ +SysprofInstrument * +sysprof_tracefd_consumer_new (int trace_fd) +{ + SysprofTracefdConsumer *self; + + g_return_val_if_fail (trace_fd >= -1, NULL); + + self = g_object_new (SYSPROF_TYPE_TRACEFD_CONSUMER, NULL); + self->trace_fd = trace_fd; + + return SYSPROF_INSTRUMENT (self); +} diff --git a/src/libsysprof/sysprof-tracefd-consumer.h b/src/libsysprof/sysprof-tracefd-consumer.h new file mode 100644 index 00000000..c459bd0e --- /dev/null +++ b/src/libsysprof/sysprof-tracefd-consumer.h @@ -0,0 +1,42 @@ +/* sysprof-tracefd-consumer.h + * + * Copyright 2023 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "sysprof-instrument.h" + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_TRACEFD_CONSUMER (sysprof_tracefd_consumer_get_type()) +#define SYSPROF_IS_TRACEFD_CONSUMER(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_TRACEFD_CONSUMER) +#define SYSPROF_TRACEFD_CONSUMER(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_TRACEFD_CONSUMER, SysprofTracefdConsumer) +#define SYSPROF_TRACEFD_CONSUMER_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_TRACEFD_CONSUMER, SysprofTracefdConsumerClass) + +typedef struct _SysprofTracefdConsumer SysprofTracefdConsumer; +typedef struct _SysprofTracefdConsumerClass SysprofTracefdConsumerClass; + +SYSPROF_AVAILABLE_IN_ALL +GType sysprof_tracefd_consumer_get_type (void) G_GNUC_CONST; +SYSPROF_AVAILABLE_IN_ALL +SysprofInstrument *sysprof_tracefd_consumer_new (int trace_fd); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofTracefdConsumer, g_object_unref) + +G_END_DECLS diff --git a/src/libsysprof/sysprof.h b/src/libsysprof/sysprof.h index 88444e11..4cc7d765 100644 --- a/src/libsysprof/sysprof.h +++ b/src/libsysprof/sysprof.h @@ -83,6 +83,7 @@ G_BEGIN_DECLS # include "sysprof-system-logs.h" # include "sysprof-thread-info.h" # include "sysprof-time-span.h" +# include "sysprof-tracefd-consumer.h" # include "sysprof-tracer.h" #undef SYSPROF_INSIDE diff --git a/src/libsysprof/tests/test-profiler.c b/src/libsysprof/tests/test-profiler.c index 8430254e..c1d5ddb0 100644 --- a/src/libsysprof/tests/test-profiler.c +++ b/src/libsysprof/tests/test-profiler.c @@ -34,11 +34,13 @@ static gboolean gnome_shell; static gboolean bundle_symbols; static gboolean session_bus; static gboolean system_bus; +static gboolean gjs; 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" }, + { "gjs", 'g', 0, G_OPTION_ARG_NONE, &gjs, "export GJS_TRACE_FD" }, { "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" }, { "session-bus", 0, 0, G_OPTION_ARG_NONE, &session_bus, "Record D-Bus messages on the session bus" }, @@ -144,6 +146,7 @@ main (int argc, SysprofCaptureWriter *writer = NULL; SysprofCaptureReader *reader = NULL; g_autofd int trace_fd = -1; + g_autofd int gjs_trace_fd = -1; int argv_copy_len = 0; sysprof_clock_init (); @@ -224,10 +227,16 @@ main (int argc, trace_fd = sysprof_spawnable_add_trace_fd (spawnable, NULL); + if (gjs) + gjs_trace_fd = sysprof_spawnable_add_trace_fd (spawnable, "GJS_TRACE_FD"); + break; } } + sysprof_profiler_add_instrument (profiler, sysprof_tracefd_consumer_new (g_steal_fd (&gjs_trace_fd))); + sysprof_profiler_add_instrument (profiler, sysprof_tracefd_consumer_new (g_steal_fd (&trace_fd))); + sysprof_profiler_record_async (profiler, writer, NULL, record_cb, NULL); g_unix_signal_add (SIGINT, sigint_handler, main_loop);