From 3a94170b0accbe82b28b2a1796d415008d9ab48c Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Tue, 13 Jun 2023 12:11:55 -0700 Subject: [PATCH] libsysprof-capture: add frame type for tracing This is like sample but has an "enter/exit" flag with it. This can be useful when you want to provide tracing instead of sampling. We use a different frame type so that we can denote that this isn't traditional sampling, and the flag can be used to find the next exit for the current enter for calculating durations. The entire stack trace is provided to make things easier on tools which may want to deal with indirect functions that were not instrumented but can be unwound. That may allow for tooling to give the user some insight that it's not *just* this function entering, but some functions before it were entered too. This also adds a SysprofTracer instrument which will preload a libsysprof-tracer-6.so into the process providing the __cyg_profile_func_enter() and __cyg_profile_func_leave() hooks. --- .../sysprof-capture-cursor.c | 4 + .../sysprof-capture-reader.c | 46 ++++++++++ .../sysprof-capture-reader.h | 2 + .../sysprof-capture-types.h | 17 +++- .../sysprof-capture-writer-cat.c | 26 ++++++ .../sysprof-capture-writer.c | 38 +++++++- .../sysprof-capture-writer.h | 9 ++ src/libsysprof-capture/sysprof-collector.c | 37 ++++++++ src/libsysprof-capture/sysprof-collector.h | 4 + src/libsysprof-profile/meson.build | 2 + src/libsysprof-profile/sysprof-profile.h | 1 + src/libsysprof-profile/sysprof-tracer.c | 88 +++++++++++++++++++ src/libsysprof-profile/sysprof-tracer.h | 42 +++++++++ src/libsysprof-profile/tests/test-profiler.c | 8 +- src/preload/meson.build | 7 ++ ...of-tracer.c => sysprof-tracer-collector.c} | 27 ++++-- src/tools/sysprof-dump.c | 20 +++++ 17 files changed, 369 insertions(+), 9 deletions(-) create mode 100644 src/libsysprof-profile/sysprof-tracer.c create mode 100644 src/libsysprof-profile/sysprof-tracer.h rename src/preload/{sysprof-tracer.c => sysprof-tracer-collector.c} (71%) diff --git a/src/libsysprof-capture/sysprof-capture-cursor.c b/src/libsysprof-capture/sysprof-capture-cursor.c index 7697ad48..376e8603 100644 --- a/src/libsysprof-capture/sysprof-capture-cursor.c +++ b/src/libsysprof-capture/sysprof-capture-cursor.c @@ -175,6 +175,10 @@ sysprof_capture_cursor_foreach (SysprofCaptureCursor *self, delegate = READ_DELEGATE (sysprof_capture_reader_read_sample); break; + case SYSPROF_CAPTURE_FRAME_TRACE: + delegate = READ_DELEGATE (sysprof_capture_reader_read_trace); + break; + case SYSPROF_CAPTURE_FRAME_LOG: delegate = READ_DELEGATE (sysprof_capture_reader_read_log); break; diff --git a/src/libsysprof-capture/sysprof-capture-reader.c b/src/libsysprof-capture/sysprof-capture-reader.c index 6b7fa051..6227af9b 100644 --- a/src/libsysprof-capture/sysprof-capture-reader.c +++ b/src/libsysprof-capture/sysprof-capture-reader.c @@ -925,6 +925,52 @@ sysprof_capture_reader_read_sample (SysprofCaptureReader *self) return sample; } +const SysprofCaptureTrace * +sysprof_capture_reader_read_trace (SysprofCaptureReader *self) +{ + SysprofCaptureTrace *trace; + + assert (self != NULL); + assert ((self->pos % SYSPROF_CAPTURE_ALIGN) == 0); + assert (self->pos <= self->bufsz); + + if (!sysprof_capture_reader_ensure_space_for (self, sizeof *trace)) + return NULL; + + trace = (SysprofCaptureTrace *)(void *)&self->buf[self->pos]; + + sysprof_capture_reader_bswap_frame (self, &trace->frame); + + if (trace->frame.type != SYSPROF_CAPTURE_FRAME_TRACE) + return NULL; + + if (trace->frame.len < sizeof *trace) + return NULL; + + if (self->endian != __BYTE_ORDER) + trace->n_addrs = bswap_16 (trace->n_addrs); + + if (trace->frame.len < (sizeof *trace + (sizeof(SysprofCaptureAddress) * trace->n_addrs))) + return NULL; + + if (!sysprof_capture_reader_ensure_space_for (self, trace->frame.len)) + return NULL; + + trace = (SysprofCaptureTrace *)(void *)&self->buf[self->pos]; + + if (SYSPROF_UNLIKELY (self->endian != __BYTE_ORDER)) + { + unsigned int i; + + for (i = 0; i < trace->n_addrs; i++) + trace->addrs[i] = bswap_64 (trace->addrs[i]); + } + + self->pos += trace->frame.len; + + return trace; +} + const SysprofCaptureCounterDefine * sysprof_capture_reader_read_counter_define (SysprofCaptureReader *self) { diff --git a/src/libsysprof-capture/sysprof-capture-reader.h b/src/libsysprof-capture/sysprof-capture-reader.h index 9d10d700..fbf6f143 100644 --- a/src/libsysprof-capture/sysprof-capture-reader.h +++ b/src/libsysprof-capture/sysprof-capture-reader.h @@ -111,6 +111,8 @@ const SysprofCaptureProcess *sysprof_capture_reader_read_process ( SYSPROF_AVAILABLE_IN_ALL const SysprofCaptureSample *sysprof_capture_reader_read_sample (SysprofCaptureReader *self); SYSPROF_AVAILABLE_IN_ALL +const SysprofCaptureTrace *sysprof_capture_reader_read_trace (SysprofCaptureReader *self); +SYSPROF_AVAILABLE_IN_ALL const SysprofCaptureJitmap *sysprof_capture_reader_read_jitmap (SysprofCaptureReader *self); SYSPROF_AVAILABLE_IN_ALL const SysprofCaptureCounterDefine *sysprof_capture_reader_read_counter_define (SysprofCaptureReader *self); diff --git a/src/libsysprof-capture/sysprof-capture-types.h b/src/libsysprof-capture/sysprof-capture-types.h index 20295a2e..9be4a0eb 100644 --- a/src/libsysprof-capture/sysprof-capture-types.h +++ b/src/libsysprof-capture/sysprof-capture-types.h @@ -140,10 +140,11 @@ typedef enum SYSPROF_CAPTURE_FRAME_FILE_CHUNK = 13, SYSPROF_CAPTURE_FRAME_ALLOCATION = 14, SYSPROF_CAPTURE_FRAME_OVERLAY = 15, + SYSPROF_CAPTURE_FRAME_TRACE = 16, } SysprofCaptureFrameType; /* Not part of ABI */ -#define SYSPROF_CAPTURE_FRAME_LAST 16 +#define SYSPROF_CAPTURE_FRAME_LAST 17 SYSPROF_ALIGNED_BEGIN(1) typedef struct @@ -225,6 +226,18 @@ typedef struct } SysprofCaptureSample SYSPROF_ALIGNED_END(1); +SYSPROF_ALIGNED_BEGIN(1) +typedef struct +{ + SysprofCaptureFrame frame; + uint32_t n_addrs : 16; + uint32_t entering : 1; + uint32_t padding1 : 15; + int32_t tid; + SysprofCaptureAddress addrs[0]; +} SysprofCaptureTrace +SYSPROF_ALIGNED_END(1); + SYSPROF_ALIGNED_BEGIN(1) typedef struct { @@ -357,6 +370,7 @@ SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureMap) == 56, "SysprofCaptureMap chan SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureJitmap) == 28, "SysprofCaptureJitmap changed size"); SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureProcess) == 24, "SysprofCaptureProcess changed size"); SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureSample) == 32, "SysprofCaptureSample changed size"); +SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureTrace) == 32, "SysprofCaptureTrace changed size"); SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureFork) == 28, "SysprofCaptureFork changed size"); SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureExit) == 24, "SysprofCaptureExit changed size"); SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureTimestamp) == 24, "SysprofCaptureTimestamp changed size"); @@ -373,6 +387,7 @@ SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureOverlay) == 32, "SysprofCaptureOver SYSPROF_STATIC_ASSERT ((offsetof (SysprofCaptureAllocation, addrs) % SYSPROF_CAPTURE_ALIGN) == 0, "SysprofCaptureAllocation.addrs is not aligned"); SYSPROF_STATIC_ASSERT ((offsetof (SysprofCaptureSample, addrs) % SYSPROF_CAPTURE_ALIGN) == 0, "SysprofCaptureSample.addrs is not aligned"); +SYSPROF_STATIC_ASSERT ((offsetof (SysprofCaptureTrace, addrs) % SYSPROF_CAPTURE_ALIGN) == 0, "SysprofCaptureTrace.addrs is not aligned"); static inline int sysprof_capture_address_compare (SysprofCaptureAddress a, diff --git a/src/libsysprof-capture/sysprof-capture-writer-cat.c b/src/libsysprof-capture/sysprof-capture-writer-cat.c index 35de0620..e8de2367 100644 --- a/src/libsysprof-capture/sysprof-capture-writer-cat.c +++ b/src/libsysprof-capture/sysprof-capture-writer-cat.c @@ -416,6 +416,32 @@ sysprof_capture_writer_cat (SysprofCaptureWriter *self, break; } + case SYSPROF_CAPTURE_FRAME_TRACE: + { + const SysprofCaptureTrace *frame; + + if (!(frame = sysprof_capture_reader_read_trace (reader))) + goto panic; + + { + SysprofCaptureAddress addrs[frame->n_addrs]; + + for (unsigned int z = 0; z < frame->n_addrs; z++) + addrs[z] = translate_table_translate (tables, TRANSLATE_ADDR, frame->addrs[z]); + + sysprof_capture_writer_add_trace (self, + frame->frame.time, + frame->frame.cpu, + frame->frame.pid, + frame->tid, + addrs, + frame->n_addrs, + frame->entering); + } + + break; + } + case SYSPROF_CAPTURE_FRAME_CTRDEF: { const SysprofCaptureCounterDefine *frame; diff --git a/src/libsysprof-capture/sysprof-capture-writer.c b/src/libsysprof-capture/sysprof-capture-writer.c index d05981c2..1e3f57e4 100644 --- a/src/libsysprof-capture/sysprof-capture-writer.c +++ b/src/libsysprof-capture/sysprof-capture-writer.c @@ -798,6 +798,42 @@ sysprof_capture_writer_add_sample (SysprofCaptureWriter *self, return true; } +bool +sysprof_capture_writer_add_trace (SysprofCaptureWriter *self, + int64_t time, + int cpu, + int32_t pid, + int32_t tid, + const SysprofCaptureAddress *addrs, + unsigned int n_addrs, + bool entering) +{ + SysprofCaptureTrace *ev; + size_t len; + + assert (self != NULL); + + len = sizeof *ev + (n_addrs * sizeof (SysprofCaptureAddress)); + + ev = (SysprofCaptureTrace *)sysprof_capture_writer_allocate (self, &len); + if (!ev) + return false; + + sysprof_capture_writer_frame_init (&ev->frame, + len, + cpu, + pid, + time, + SYSPROF_CAPTURE_FRAME_SAMPLE); + ev->n_addrs = n_addrs; + ev->tid = tid; + ev->entering = !!entering; + + memcpy (ev->addrs, addrs, (n_addrs * sizeof (SysprofCaptureAddress))); + + return true; +} + bool sysprof_capture_writer_add_fork (SysprofCaptureWriter *self, int64_t time, @@ -1659,7 +1695,7 @@ _sysprof_capture_writer_add_raw (SysprofCaptureWriter *self, return false; assert (fr->len == len); - assert (fr->type < 16); + assert (fr->type < SYSPROF_CAPTURE_FRAME_LAST); memcpy (begin, fr, fr->len); diff --git a/src/libsysprof-capture/sysprof-capture-writer.h b/src/libsysprof-capture/sysprof-capture-writer.h index 4893c226..6cbbd5ee 100644 --- a/src/libsysprof-capture/sysprof-capture-writer.h +++ b/src/libsysprof-capture/sysprof-capture-writer.h @@ -143,6 +143,15 @@ bool sysprof_capture_writer_add_sample (Sy const SysprofCaptureAddress *addrs, unsigned int n_addrs); SYSPROF_AVAILABLE_IN_ALL +bool sysprof_capture_writer_add_trace (SysprofCaptureWriter *self, + int64_t time, + int cpu, + int32_t pid, + int32_t tid, + const SysprofCaptureAddress *addrs, + unsigned int n_addrs, + bool entering); +SYSPROF_AVAILABLE_IN_ALL bool sysprof_capture_writer_add_fork (SysprofCaptureWriter *self, int64_t time, int cpu, diff --git a/src/libsysprof-capture/sysprof-collector.c b/src/libsysprof-capture/sysprof-collector.c index 803aa02e..c8fad1b8 100644 --- a/src/libsysprof-capture/sysprof-collector.c +++ b/src/libsysprof-capture/sysprof-collector.c @@ -576,6 +576,43 @@ sysprof_collector_sample (SysprofBacktraceFunc backtrace_func, } COLLECTOR_END; } +void +sysprof_collector_trace (SysprofBacktraceFunc backtrace_func, + void *backtrace_data, + bool entering) +{ + COLLECTOR_BEGIN { + SysprofCaptureTrace *ev; + size_t len; + + len = sizeof *ev + (sizeof (SysprofCaptureTrace) * MAX_UNWIND_DEPTH); + + if ((ev = mapped_ring_buffer_allocate (collector->buffer, len))) + { + int n_addrs; + + /* See comment from sysprof_collector_allocate(). */ + if (backtrace_func) + n_addrs = backtrace_func (ev->addrs, MAX_UNWIND_DEPTH, backtrace_data); + else + n_addrs = 0; + + ev->n_addrs = ((n_addrs < 0) ? 0 : (n_addrs > MAX_UNWIND_DEPTH) ? MAX_UNWIND_DEPTH : n_addrs); + ev->frame.len = sizeof *ev + sizeof (SysprofCaptureAddress) * ev->n_addrs; + ev->frame.type = SYSPROF_CAPTURE_FRAME_TRACE; + ev->frame.cpu = _do_getcpu (); + ev->frame.pid = collector->pid; + ev->frame.time = SYSPROF_CAPTURE_CURRENT_TIME; + ev->tid = collector->tid; + ev->entering = !!entering; + ev->padding1 = 0; + + mapped_ring_buffer_advance (collector->buffer, ev->frame.len); + } + + } COLLECTOR_END; +} + void sysprof_collector_mark (int64_t time, int64_t duration, diff --git a/src/libsysprof-capture/sysprof-collector.h b/src/libsysprof-capture/sysprof-collector.h index 6f13a805..c53dc984 100644 --- a/src/libsysprof-capture/sysprof-collector.h +++ b/src/libsysprof-capture/sysprof-collector.h @@ -75,6 +75,10 @@ void sysprof_collector_allocate (SysprofCaptureAddress SYSPROF_AVAILABLE_IN_3_36 void sysprof_collector_sample (SysprofBacktraceFunc backtrace_func, void *backtrace_data); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_collector_trace (SysprofBacktraceFunc backtrace_func, + void *backtrace_data, + bool entering); SYSPROF_AVAILABLE_IN_3_36 void sysprof_collector_mark (int64_t time, int64_t duration, diff --git a/src/libsysprof-profile/meson.build b/src/libsysprof-profile/meson.build index 9f7cbec4..33537699 100644 --- a/src/libsysprof-profile/meson.build +++ b/src/libsysprof-profile/meson.build @@ -13,6 +13,7 @@ libsysprof_profile_public_sources = [ 'sysprof-recording.c', 'sysprof-sampler.c', 'sysprof-spawnable.c', + 'sysprof-tracer.c', ] libsysprof_profile_private_sources = [ @@ -41,6 +42,7 @@ libsysprof_profile_public_headers = [ 'sysprof-recording.h', 'sysprof-sampler.h', 'sysprof-spawnable.h', + 'sysprof-tracer.h', ] if host_machine.system() == 'linux' diff --git a/src/libsysprof-profile/sysprof-profile.h b/src/libsysprof-profile/sysprof-profile.h index 9bf03fcb..d3e9afee 100644 --- a/src/libsysprof-profile/sysprof-profile.h +++ b/src/libsysprof-profile/sysprof-profile.h @@ -39,6 +39,7 @@ G_BEGIN_DECLS # include "sysprof-recording.h" # include "sysprof-sampler.h" # include "sysprof-spawnable.h" +# include "sysprof-tracer.h" #undef SYSPROF_PROFILE_INSIDE G_END_DECLS diff --git a/src/libsysprof-profile/sysprof-tracer.c b/src/libsysprof-profile/sysprof-tracer.c new file mode 100644 index 00000000..8943d0b8 --- /dev/null +++ b/src/libsysprof-profile/sysprof-tracer.c @@ -0,0 +1,88 @@ +/* sysprof-tracer.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-tracer.h" + +/** + * SysprofTracer: + * + * The `SysprofTracer` instrument provides integration with GCC's + * `-finstrument-functions`. It uses an `LD_PRELOAD` on Linux to record + * stacktraces on `__cyg_profile_func_enter` and `__cyg_profile_func_exit`. + * + * On macOS, `profile_func_enter` and `profile_func_exit` are used. + */ + +struct _SysprofTracer +{ + SysprofInstrument parent_instance; +}; + +struct _SysprofTracerClass +{ + SysprofInstrumentClass parent_class; +}; + +G_DEFINE_FINAL_TYPE (SysprofTracer, sysprof_tracer, SYSPROF_TYPE_INSTRUMENT) + +static DexFuture * +sysprof_tracer_prepare (SysprofInstrument *instrument, + SysprofRecording *recording) +{ + SysprofSpawnable *spawnable; + + g_assert (SYSPROF_IS_INSTRUMENT (instrument)); + g_assert (SYSPROF_IS_RECORDING (recording)); + + if ((spawnable = _sysprof_recording_get_spawnable (recording))) + sysprof_spawnable_add_ld_preload (spawnable, + PACKAGE_LIBDIR"/libsysprof-tracer-" API_VERSION_S ".so"); + else + _sysprof_recording_diagnostic (recording, + _("Tracer"), + _("Tracing requires spawning a program compiled with ‘-finstrument-functions’. Tracing will not be available.")); + + return dex_future_new_for_boolean (TRUE); +} + +static void +sysprof_tracer_class_init (SysprofTracerClass *klass) +{ + SysprofInstrumentClass *instrument_class = SYSPROF_INSTRUMENT_CLASS (klass); + + instrument_class->prepare = sysprof_tracer_prepare; +} + +static void +sysprof_tracer_init (SysprofTracer *self) +{ +} + +SysprofInstrument * +sysprof_tracer_new (void) +{ + return g_object_new (SYSPROF_TYPE_TRACER, NULL); +} diff --git a/src/libsysprof-profile/sysprof-tracer.h b/src/libsysprof-profile/sysprof-tracer.h new file mode 100644 index 00000000..f7966fbd --- /dev/null +++ b/src/libsysprof-profile/sysprof-tracer.h @@ -0,0 +1,42 @@ +/* sysprof-tracer.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_TRACER (sysprof_tracer_get_type()) +#define SYSPROF_IS_TRACER(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, SYSPROF_TYPE_TRACER) +#define SYSPROF_TRACER(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, SYSPROF_TYPE_TRACER, SysprofTracer) +#define SYSPROF_TRACER_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, SYSPROF_TYPE_TRACER, SysprofTracerClass) + +typedef struct _SysprofTracer SysprofTracer; +typedef struct _SysprofTracerClass SysprofTracerClass; + +SYSPROF_AVAILABLE_IN_ALL +GType sysprof_tracer_get_type (void) G_GNUC_CONST; +SYSPROF_AVAILABLE_IN_ALL +SysprofInstrument *sysprof_tracer_new (void); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofTracer, g_object_unref) + +G_END_DECLS diff --git a/src/libsysprof-profile/tests/test-profiler.c b/src/libsysprof-profile/tests/test-profiler.c index af2800f5..6c99b7d1 100644 --- a/src/libsysprof-profile/tests/test-profiler.c +++ b/src/libsysprof-profile/tests/test-profiler.c @@ -29,9 +29,11 @@ static GMainLoop *main_loop; static char *capture_file; static SysprofRecording *active_recording; static gboolean memprof; +static gboolean tracer; 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" }, { 0 } }; @@ -172,11 +174,15 @@ main (int argc, 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_sampler_new ()); 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) diff --git a/src/preload/meson.build b/src/preload/meson.build index a1a6e603..9c39af50 100644 --- a/src/preload/meson.build +++ b/src/preload/meson.build @@ -24,3 +24,10 @@ libsysprof_speedtrack_preload = shared_library('sysprof-speedtrack-@0@'.format(l install: true, install_dir: get_option('libdir'), ) + +libsysprof_tracer_preload = shared_library('sysprof-tracer-@0@'.format(libsysprof_api_version), + ['sysprof-tracer-collector.c'], + dependencies: preload_deps, + install: true, + install_dir: get_option('libdir'), +) diff --git a/src/preload/sysprof-tracer.c b/src/preload/sysprof-tracer-collector.c similarity index 71% rename from src/preload/sysprof-tracer.c rename to src/preload/sysprof-tracer-collector.c index 95937b0f..c427c5ad 100644 --- a/src/preload/sysprof-tracer.c +++ b/src/preload/sysprof-tracer-collector.c @@ -28,6 +28,15 @@ #include "gconstructor.h" +#ifdef __GNUC__ +# define GNUC_CHECK_VERSION(major, minor) \ + ((__GNUC__ > (major)) || \ + ((__GNUC__ == (major)) && \ + (__GNUC_MINOR__ >= (minor)))) +#else +# define GNUC_CHECK_VERSION(major, minor) 0 +#endif + #if defined (G_HAS_CONSTRUCTORS) # ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA # pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(collector_init_ctor) @@ -49,24 +58,30 @@ collector_init_ctor (void) sysprof_collector_init (); } -/* TODO: - * - * This is just an example. - * +/* * What we would really want to do is to have a new frame type for enter/exit * tracing so that we can only push/pop the new address to the sample. Then - * when decoding it can recreate stack traces if necessary. + * when decoding it can recreate stack traces if necessary. But for now, we + * can emulate that by just adding a sample when we enter a function and + * leave a function. The rest could be done in post-processing. */ +#if GNUC_CHECK_VERSION(3,0) +__attribute__((no_instrument_function)) +#endif void profile_func_enter (void *func, void *call_site) { - sysprof_collector_sample (backtrace_func, NULL); + sysprof_collector_trace (backtrace_func, NULL, TRUE); } +#if GNUC_CHECK_VERSION(3,0) +__attribute__((no_instrument_function)) +#endif void profile_func_exit (void *func, void *call_site) { + sysprof_collector_trace (backtrace_func, NULL, FALSE); } diff --git a/src/tools/sysprof-dump.c b/src/tools/sysprof-dump.c index 5c12c4b7..1019282a 100644 --- a/src/tools/sysprof-dump.c +++ b/src/tools/sysprof-dump.c @@ -301,6 +301,26 @@ main (gint argc, break; } + case SYSPROF_CAPTURE_FRAME_TRACE: + { + const SysprofCaptureTrace *s = sysprof_capture_reader_read_trace (reader); + gdouble ptime = (s->frame.time - begin_time) / (gdouble)SYSPROF_NSEC_PER_SEC; + SysprofAddressContext context = SYSPROF_ADDRESS_CONTEXT_NONE; + + g_print ("TRACE: pid=%d tid=%d time=%" G_GINT64_FORMAT " (%lf) %s\n", + s->frame.pid, s->tid, s->frame.time, ptime, + s->entering ? "ENTER" : "EXIT"); + + for (guint i = 0; i < s->n_addrs; i++) + { + g_autofree char *name = symbolize (resolvers, &s->frame, &context, s->addrs[i]); + + g_print (" " SYSPROF_CAPTURE_ADDRESS_FORMAT " (%s)\n", s->addrs[i], name); + } + + break; + } + case SYSPROF_CAPTURE_FRAME_TIMESTAMP: { const SysprofCaptureTimestamp *ts = sysprof_capture_reader_read_timestamp (reader);