[sysprof/wip/chergert/mem-preload] capture: capture backtraces from libsysprof-capture
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [sysprof/wip/chergert/mem-preload] capture: capture backtraces from libsysprof-capture
- Date: Mon, 3 Feb 2020 20:51:08 +0000 (UTC)
commit de7bb447983aae3d43a60ef4c9150e25cfdbce65
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 dfbde1c..69303c7 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 bf13ac2..f6e939e 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]