[sysprof/wip/chergert/mem-preload: 15/43] capture: capture backtraces from libsysprof-capture



commit 92fba60884cdbeac7069ee15e77f1d1d6a66fc21
Author: Christian Hergert <chergert redhat com>
Date:   Mon Feb 3 12:49:45 2020 -0800

    capture: capture backtraces from libsysprof-capture
    
    This allows us to capture the backtrace directly into the binary write
    buffer instead of on the stack with a memcpy(). The side effect of that is
    that we have to link against libunwind (if supported) from
    libsysprof-capture.a. If libunwind is not available, we use backtrace()
    from execinfo.h which is a bit slower it appears for the stacks I've
    tested with (on Sysprof itself).
    
    It would be nice if we could have a really fast unwinder even if it wasn't
    very complete in handling DWARF/external debugging information.

 meson.build                                       |  9 +++
 src/libsysprof-capture/meson.build                |  1 +
 src/libsysprof-capture/sysprof-capture-types.h    |  2 +
 src/libsysprof-capture/sysprof-capture-writer.c   | 81 +++++++++++++++++++++++
 src/libsysprof-capture/sysprof-capture-writer.h   |  9 +++
 src/libsysprof/meson.build                        |  1 +
 src/libsysprof/preload/meson.build                |  6 +-
 src/libsysprof/preload/sysprof-memory-collector.c | 57 ++--------------
 8 files changed, 111 insertions(+), 55 deletions(-)
---
diff --git a/meson.build b/meson.build
index cde3d5b..5c87f79 100644
--- a/meson.build
+++ b/meson.build
@@ -83,6 +83,15 @@ config_h.set10('ENABLE_NLS', true)
 config_h.set_quoted('PACKAGE_LOCALE_DIR', join_paths(get_option('prefix'), get_option('datadir'), 'locale'))
 config_h.set('LOCALEDIR', 'PACKAGE_LOCALE_DIR')
 
+if cc.has_header('execinfo.h')
+  config_h.set10('HAVE_EXECINFO_H', true)
+endif
+
+libunwind_dep = dependency('libunwind-generic', required: false)
+if libunwind_dep.found()
+  config_h.set10('ENABLE_LIBUNWIND', libunwind_dep.found())
+endif
+
 # Development build setup
 config_h.set('DEVELOPMENT_BUILD', version_split[1].to_int().is_odd())
 
diff --git a/src/libsysprof-capture/meson.build b/src/libsysprof-capture/meson.build
index 8c499c7..a7b2989 100644
--- a/src/libsysprof-capture/meson.build
+++ b/src/libsysprof-capture/meson.build
@@ -34,6 +34,7 @@ configure_file(
 
 libsysprof_capture_deps = [
   glib_dep,
+  libunwind_dep,
 ]
 
 libsysprof_capture = static_library(
diff --git a/src/libsysprof-capture/sysprof-capture-types.h b/src/libsysprof-capture/sysprof-capture-types.h
index 707420b..0a6e40e 100644
--- a/src/libsysprof-capture/sysprof-capture-types.h
+++ b/src/libsysprof-capture/sysprof-capture-types.h
@@ -352,6 +352,8 @@ G_STATIC_ASSERT (sizeof (SysprofCaptureMark) == 96);
 G_STATIC_ASSERT (sizeof (SysprofCaptureMetadata) == 64);
 G_STATIC_ASSERT (sizeof (SysprofCaptureLog) == 64);
 G_STATIC_ASSERT (sizeof (SysprofCaptureFileChunk) == 284);
+G_STATIC_ASSERT (sizeof (SysprofCaptureMemoryAlloc) == 48);
+G_STATIC_ASSERT ((G_STRUCT_OFFSET (SysprofCaptureMemoryAlloc, addrs) % 8) == 0);
 
 static inline gint
 sysprof_capture_address_compare (SysprofCaptureAddress a,
diff --git a/src/libsysprof-capture/sysprof-capture-writer.c b/src/libsysprof-capture/sysprof-capture-writer.c
index 25b565b..c411ed9 100644
--- a/src/libsysprof-capture/sysprof-capture-writer.c
+++ b/src/libsysprof-capture/sysprof-capture-writer.c
@@ -63,8 +63,14 @@
 #endif
 
 #include <errno.h>
+#ifdef HAVE_EXECINFO_H
+# include <execinfo.h>
+#endif
 #include <fcntl.h>
 #include <glib/gstdio.h>
+#ifdef ENABLE_LIBUNWIND
+# include <libunwind.h>
+#endif
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
@@ -78,6 +84,7 @@
 #define DEFAULT_BUFFER_SIZE (_sysprof_getpagesize() * 64L)
 #define INVALID_ADDRESS     (G_GUINT64_CONSTANT(0))
 #define MAX_COUNTERS        ((1 << 24) - 1)
+#define MAX_UNWIND_DEPTH    64
 
 typedef struct
 {
@@ -1551,6 +1558,80 @@ sysprof_capture_writer_add_memory_alloc (SysprofCaptureWriter        *self,
   return TRUE;
 }
 
+gboolean
+sysprof_capture_writer_add_memory_alloc_with_backtrace (SysprofCaptureWriter  *self,
+                                                        gint64                 time,
+                                                        gint                   cpu,
+                                                        gint32                 pid,
+                                                        gint32                 tid,
+                                                        SysprofCaptureAddress  alloc_addr,
+                                                        gsize                  alloc_size)
+{
+  SysprofCaptureMemoryAlloc *ev;
+  gsize len;
+
+  g_assert (self != NULL);
+
+  len = sizeof *ev + (MAX_UNWIND_DEPTH * sizeof (SysprofCaptureAddress));
+  ev = (SysprofCaptureMemoryAlloc *)sysprof_capture_writer_allocate (self, &len);
+  if (!ev)
+    return FALSE;
+
+  sysprof_capture_writer_frame_init (&ev->frame,
+                                     len,
+                                     cpu,
+                                     pid,
+                                     time,
+                                     SYSPROF_CAPTURE_FRAME_MEMORY_ALLOC);
+
+  ev->alloc_size = alloc_size;
+  ev->alloc_addr = alloc_addr;
+  ev->padding1 = 0;
+  ev->tid = tid;
+  ev->n_addrs = 0;
+
+#if defined(ENABLE_LIBUNWIND)
+  {
+    unw_context_t uc;
+    unw_cursor_t cursor;
+    unw_word_t ip;
+
+    unw_getcontext (&uc);
+    unw_init_local (&cursor, &uc);
+
+    while (ev->n_addrs < MAX_UNWIND_DEPTH && unw_step (&cursor) > 0)
+      {
+        unw_get_reg (&cursor, UNW_REG_IP, &ip);
+        ev->addrs[ev->n_addrs++] = ip;
+      }
+  }
+#elif defined(HAVE_EXECINFO_H)
+# if GLIB_SIZEOF_VOID_P == 8
+  ev->n_addrs = backtrace ((void **)ev->addrs, MAX_UNWIND_DEPTH);
+# else /* GLIB_SIZEOF_VOID_P != 8 */
+  {
+    void *stack[MAX_UNWIND_DEPTH];
+
+    ev->n_addrs = backtrace (stack, MAX_UNWIND_DEPTH);
+    for (guint i = 0; i < ev->n_addrs; i++)
+      ev->addrs[i] = GPOINTER_TO_SIZE (stack[i]);
+  }
+# endif /* GLIB_SIZEOF_VOID_P */
+#endif
+
+  if (ev->n_addrs < MAX_UNWIND_DEPTH)
+    {
+      gsize diff = (sizeof (SysprofCaptureAddress) * (MAX_UNWIND_DEPTH - ev->n_addrs));
+
+      ev->frame.len -= diff;
+      self->pos -= diff;
+    }
+
+  self->stat.frame_count[SYSPROF_CAPTURE_FRAME_MEMORY_ALLOC]++;
+
+  return TRUE;
+}
+
 gboolean
 sysprof_capture_writer_add_memory_free (SysprofCaptureWriter        *self,
                                         gint64                       time,
diff --git a/src/libsysprof-capture/sysprof-capture-writer.h b/src/libsysprof-capture/sysprof-capture-writer.h
index 2580749..e651ae7 100644
--- a/src/libsysprof-capture/sysprof-capture-writer.h
+++ b/src/libsysprof-capture/sysprof-capture-writer.h
@@ -194,6 +194,14 @@ gboolean              sysprof_capture_writer_add_memory_alloc(SysprofCaptureWrit
                                                               const SysprofCaptureAddress       *addrs,
                                                               guint                              n_addrs);
 SYSPROF_AVAILABLE_IN_3_36
+gboolean              sysprof_capture_writer_add_memory_alloc_with_backtrace (SysprofCaptureWriter  *self,
+                                                                              gint64                 time,
+                                                                              gint                   cpu,
+                                                                              gint32                 pid,
+                                                                              gint32                 tid,
+                                                                              SysprofCaptureAddress  
alloc_addr,
+                                                                              gsize                  
alloc_size);
+SYSPROF_AVAILABLE_IN_3_36
 gboolean              sysprof_capture_writer_add_memory_free (SysprofCaptureWriter              *self,
                                                               gint64                             time,
                                                               gint                               cpu,
@@ -229,6 +237,7 @@ gboolean              _sysprof_capture_writer_set_time_range (SysprofCaptureWrit
                                                               gint64                             start_time,
                                                               gint64                             end_time) 
G_GNUC_INTERNAL;
 
+
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofCaptureWriter, sysprof_capture_writer_unref)
 
 G_END_DECLS
diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build
index 459b093..b887248 100644
--- a/src/libsysprof/meson.build
+++ b/src/libsysprof/meson.build
@@ -93,6 +93,7 @@ librax_dep = declare_dependency(
 )
 
 libsysprof_deps = [
+  libsysprof_capture_deps,
   gio_dep,
   gio_unix_dep,
   polkit_dep,
diff --git a/src/libsysprof/preload/meson.build b/src/libsysprof/preload/meson.build
index b32d838..b2a7d8a 100644
--- a/src/libsysprof/preload/meson.build
+++ b/src/libsysprof/preload/meson.build
@@ -1,13 +1,9 @@
-libunwind_dep = dependency('libunwind-generic', required: false)
-
 libsysprof_memory_preload_deps = [
-  libsysprof_capture_dep,
   cc.find_library('dl', required: false),
+  libsysprof_capture_dep,
   libunwind_dep,
 ]
 
-config_h.set10('ENABLE_LIBUNWIND', libunwind_dep.found())
-
 libsysprof_memory_preload = shared_library('sysprof-memory-collector',
   ['sysprof-memory-collector.c'],
   dependencies: libsysprof_memory_preload_deps,
diff --git a/src/libsysprof/preload/sysprof-memory-collector.c 
b/src/libsysprof/preload/sysprof-memory-collector.c
index 66a05a2..6fbbcda 100644
--- a/src/libsysprof/preload/sysprof-memory-collector.c
+++ b/src/libsysprof/preload/sysprof-memory-collector.c
@@ -3,16 +3,12 @@
 #include "config.h"
 
 #include <dlfcn.h>
-#include <execinfo.h>
 #include <sched.h>
 #include <stdlib.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
 #include <sysprof-capture.h>
 #include <unistd.h>
-#include <libunwind.h>
-
-#define CAPTURE_MAX_STACK_DEPTH 32
 
 typedef void *(* RealMalloc)        (size_t);
 typedef void  (* RealFree)          (void *);
@@ -146,56 +142,17 @@ static inline void
 track_malloc (void   *ptr,
               size_t  size)
 {
-  SysprofCaptureAddress addrs[CAPTURE_MAX_STACK_DEPTH];
-#if !ENABLE_LIBUNWIND && GLIB_SIZEOF_VOID_P != 8
-  gpointer voidp_addrs[CAPTURE_MAX_STACK_DEPTH];
-#endif
-  guint n_addrs = 0;
-
   if G_UNLIKELY (!writer)
     return;
 
-#if ENABLE_LIBUNWIND
-  {
-    unw_context_t uc;
-    unw_cursor_t cursor;
-    unw_word_t ip;
-
-    /* Get a stacktrace for the current allocation, but walk past our
-     * current function because we don't care about that stack frame.
-     */
-    unw_getcontext (&uc);
-    unw_init_local (&cursor, &uc);
-    if (unw_step (&cursor) > 0)
-      {
-        while (n_addrs < G_N_ELEMENTS (addrs) && unw_step (&cursor) > 0)
-          {
-            unw_get_reg (&cursor, UNW_REG_IP, &ip);
-            addrs[n_addrs++] = ip;
-          }
-      }
-  }
-#else
-#if GLIB_SIZEOF_VOID_P == 8
-  n_addrs = backtrace ((void **)addrs, CAPTURE_MAX_STACK_DEPTH);
-# else
-  n_addrs = backtrace (voidp_addrs, CAPTURE_MAX_STACK_DEPTH);
-  for (guint i = 0; i < n_addrs; i++)
-    addrs[i] = GPOINTER_TO_SIZE (voidp_addrs[i]);
-# endif
-#endif
-
   G_LOCK (writer);
-
-  sysprof_capture_writer_add_memory_alloc (writer,
-                                           SYSPROF_CAPTURE_CURRENT_TIME,
-                                           sched_getcpu (),
-                                           pid,
-                                           gettid(),
-                                           GPOINTER_TO_SIZE (ptr),
-                                           size,
-                                           addrs,
-                                           n_addrs);
+  sysprof_capture_writer_add_memory_alloc_with_backtrace (writer,
+                                                          SYSPROF_CAPTURE_CURRENT_TIME,
+                                                          sched_getcpu (),
+                                                          pid,
+                                                          gettid(),
+                                                          GPOINTER_TO_SIZE (ptr),
+                                                          size);
   G_UNLOCK (writer);
 }
 


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