From 70bea64f88c7b38ae35b8a81c720871ff1dce57d Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Tue, 18 Feb 2020 13:35:18 -0800 Subject: [PATCH] libsysprof-capture: allow for backtrace skip optimization We want to be backtracing directly into the capture buffer, but also need to skip a small number of frames. If we call the backtrace before filling in information, we can capture to the position *before* ev->addrs and then overwrite that data right after. --- src/libsysprof-capture/sysprof-collector.c | 17 +++++++++++++---- .../preload/sysprof-memory-collector.c | 19 +++++++++++++------ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/libsysprof-capture/sysprof-collector.c b/src/libsysprof-capture/sysprof-collector.c index cd2914e2..effb3e36 100644 --- a/src/libsysprof-capture/sysprof-collector.c +++ b/src/libsysprof-capture/sysprof-collector.c @@ -384,6 +384,19 @@ sysprof_collector_allocate (SysprofCaptureAddress alloc_addr, if ((ev = mapped_ring_buffer_allocate (collector->buffer, len))) { + /* First take a backtrace, so that backtrace_func() can overwrite + * a little bit of data *BEFORE* ev->addrs as stratch space. This + * is useful to allow using unw_backtrace() or backtrace() to skip + * a small number of frames. + * + * We fill in all the other data afterwards which overwrites that + * scratch space anyway. + */ + if (backtrace_func) + ev->n_addrs = backtrace_func (ev->addrs, MAX_UNWIND_DEPTH, backtrace_data); + else + ev->n_addrs = 0; + ev->frame.type = SYSPROF_CAPTURE_FRAME_ALLOCATION; ev->frame.len = len; ev->frame.cpu = _do_getcpu (); @@ -392,10 +405,6 @@ sysprof_collector_allocate (SysprofCaptureAddress alloc_addr, ev->tid = collector->tid; ev->alloc_addr = alloc_addr; ev->alloc_size = alloc_size; - ev->n_addrs = 0; - - if (backtrace_func) - ev->n_addrs = backtrace_func (ev->addrs, MAX_UNWIND_DEPTH, backtrace_data); len = sizeof *ev + sizeof (SysprofCaptureAddress) * ev->n_addrs; _realign (&len); diff --git a/src/libsysprof/preload/sysprof-memory-collector.c b/src/libsysprof/preload/sysprof-memory-collector.c index 3c76bcf4..a2ba8f34 100644 --- a/src/libsysprof/preload/sysprof-memory-collector.c +++ b/src/libsysprof/preload/sysprof-memory-collector.c @@ -77,17 +77,24 @@ backtrace_func (SysprofCaptureAddress *addrs, { #if defined(ENABLE_LIBUNWIND) # if GLIB_SIZEOF_VOID_P == 8 - return unw_backtrace ((void **)addrs, n_addrs); + /* We know that collector will overwrite fields *AFTER* it + * has called the backtrace function allowing us to cheat + * and subtract an offset from addrs to avoid having to + * copy frame pointers around. + */ + return unw_backtrace ((void **)addrs - 1, n_addrs); # else + static const gint skip = 1; void **stack = alloca (n_addrs * sizeof (gpointer)); - guint n = unw_backtrace (stack, n_addrs); - for (guint i = 0; i < n; i++) - addrs[i] = GPOINTER_TO_SIZE (stack[i]); - return n; + gint n = unw_backtrace (stack, n_addrs); + for (guint i = skip; i < n; i++) + addrs[i-skip] = GPOINTER_TO_SIZE (stack[i]); + return MAX (0, n - skip); # endif #elif defined(HAVE_EXECINFO_H) # if GLIB_SIZEOF_VOID_P == 8 - return backtrace ((void **)addrs, n_addrs); + /* See note on unw_backtrace() */ + return backtrace ((void **)addrs - 1, n_addrs); # else /* GLIB_SIZEOF_VOID_P != 8 */ void **stack = alloca (n_addrs * sizeof (gpointer)); guint n = backtrace (stack, n_addrs);