[sysprof] libsysprof-capture: allow for backtrace skip optimization



commit 70bea64f88c7b38ae35b8a81c720871ff1dce57d
Author: Christian Hergert <chergert redhat com>
Date:   Tue Feb 18 13:35:18 2020 -0800

    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 +++++++++++++----
 src/libsysprof/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 cd2914e..effb3e3 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 3c76bcf..a2ba8f3 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);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]