[sysprof] preload: port memory collector to collector API



commit 04d599c718e30c2ef77f9d00489681eabc1a57fb
Author: Christian Hergert <chergert redhat com>
Date:   Thu Feb 13 18:58:03 2020 -0800

    preload: port memory collector to collector API
    
    This uses a simplified form of collection without writing to capture
    files directly. The data is written into a ring buffer for Sysprof to
    pick up and copy into the real destination file. Using the mmap() ring
    buffer allows loss of data when Sysprof cannot keep up, but on the other
    hand allows the inferior to be fast enough to be useful.

 src/libsysprof/preload/gconstructor.h             | 94 ++++++++++++++++++++++
 src/libsysprof/preload/sysprof-memory-collector.c | 95 +++++++----------------
 2 files changed, 123 insertions(+), 66 deletions(-)
---
diff --git a/src/libsysprof/preload/gconstructor.h b/src/libsysprof/preload/gconstructor.h
new file mode 100644
index 0000000..df98f83
--- /dev/null
+++ b/src/libsysprof/preload/gconstructor.h
@@ -0,0 +1,94 @@
+/*
+  If G_HAS_CONSTRUCTORS is true then the compiler support *both* constructors and
+  destructors, in a sane way, including e.g. on library unload. If not you're on
+  your own.
+
+  Some compilers need #pragma to handle this, which does not work with macros,
+  so the way you need to use this is (for constructors):
+
+  #ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
+  #pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(my_constructor)
+  #endif
+  G_DEFINE_CONSTRUCTOR(my_constructor)
+  static void my_constructor(void) {
+   ...
+  }
+
+*/
+
+#ifndef __GTK_DOC_IGNORE__
+
+#if  __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
+
+#define G_HAS_CONSTRUCTORS 1
+
+#define G_DEFINE_CONSTRUCTOR(_func) static void __attribute__((constructor)) _func (void);
+#define G_DEFINE_DESTRUCTOR(_func) static void __attribute__((destructor)) _func (void);
+
+#elif defined (_MSC_VER) && (_MSC_VER >= 1500)
+/* Visual studio 2008 and later has _Pragma */
+
+#define G_HAS_CONSTRUCTORS 1
+
+#define G_DEFINE_CONSTRUCTOR(_func) \
+  static void _func(void); \
+  static int _func ## _wrapper(void) { _func(); return 0; } \
+  __pragma(section(".CRT$XCU",read)) \
+  __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _wrapper;
+
+#define G_DEFINE_DESTRUCTOR(_func) \
+  static void _func(void); \
+  static int _func ## _constructor(void) { atexit (_func); return 0; } \
+  __pragma(section(".CRT$XCU",read)) \
+  __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor;
+
+#elif defined (_MSC_VER)
+
+#define G_HAS_CONSTRUCTORS 1
+
+/* Pre Visual studio 2008 must use #pragma section */
+#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1
+#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1
+
+#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \
+  section(".CRT$XCU",read)
+#define G_DEFINE_CONSTRUCTOR(_func) \
+  static void _func(void); \
+  static int _func ## _wrapper(void) { _func(); return 0; } \
+  __declspec(allocate(".CRT$XCU")) static int (*p)(void) = _func ## _wrapper;
+
+#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \
+  section(".CRT$XCU",read)
+#define G_DEFINE_DESTRUCTOR(_func) \
+  static void _func(void); \
+  static int _func ## _constructor(void) { atexit (_func); return 0; } \
+  __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor;
+
+#elif defined(__SUNPRO_C)
+
+/* This is not tested, but i believe it should work, based on:
+ * http://opensource.apple.com/source/OpenSSL098/OpenSSL098-35/src/fips/fips_premain.c
+ */
+
+#define G_HAS_CONSTRUCTORS 1
+
+#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1
+#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1
+
+#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \
+  init(_func)
+#define G_DEFINE_CONSTRUCTOR(_func) \
+  static void _func(void);
+
+#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \
+  fini(_func)
+#define G_DEFINE_DESTRUCTOR(_func) \
+  static void _func(void);
+
+#else
+
+/* constructors not supported for this compiler */
+
+#endif
+
+#endif /* __GTK_DOC_IGNORE__ */
diff --git a/src/libsysprof/preload/sysprof-memory-collector.c 
b/src/libsysprof/preload/sysprof-memory-collector.c
index 1e6b240..a9b81ac 100644
--- a/src/libsysprof/preload/sysprof-memory-collector.c
+++ b/src/libsysprof/preload/sysprof-memory-collector.c
@@ -16,6 +16,8 @@
 #include <sysprof-capture.h>
 #include <unistd.h>
 
+#include "gconstructor.h"
+
 typedef void *(* RealMalloc)        (size_t);
 typedef void  (* RealFree)          (void *);
 typedef void *(* RealCalloc)        (size_t, size_t);
@@ -36,10 +38,8 @@ static void *scratch_realloc (void *, size_t);
 static void *scratch_calloc  (size_t, size_t);
 static void  scratch_free    (void *);
 
-static G_LOCK_DEFINE (writer);
-static SysprofCaptureWriter *writer;
+static int collector_ready;
 static int hooked;
-static int pid;
 static ScratchAlloc scratch;
 static RealCalloc real_calloc = scratch_calloc;
 static RealFree real_free = scratch_free;
@@ -49,6 +49,22 @@ static RealAlignedAlloc real_aligned_alloc;
 static RealPosixMemalign real_posix_memalign;
 static RealMemalign real_memalign;
 
+#if defined (G_HAS_CONSTRUCTORS)
+# ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
+#  pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(collector_init_ctor)
+# endif
+G_DEFINE_CONSTRUCTOR(collector_init_ctor)
+#else
+# error Your platform/compiler is missing constructor support
+#endif
+
+static void
+collector_init_ctor (void)
+{
+  sysprof_collector_init ();
+  collector_ready = TRUE;
+}
+
 static guint
 backtrace_func (SysprofCaptureAddress *addrs,
                 guint                  n_addrs,
@@ -134,19 +150,9 @@ scratch_free (void *ptr)
     return;
 }
 
-static void
-flush_writer (void)
-{
-  G_LOCK (writer);
-  sysprof_capture_writer_flush (writer);
-  G_UNLOCK (writer);
-}
-
 static void
 hook_memtable (void)
 {
-  const gchar *env;
-
   if (hooked)
     return;
 
@@ -161,70 +167,27 @@ hook_memtable (void)
   real_memalign = dlsym (RTLD_NEXT, "memalign");
 
   unsetenv ("LD_PRELOAD");
-
-  pid = getpid ();
-
-  /* TODO: We want an API that let's us create a new writer
-   * per-thread instead of something like this (or using an
-   * environment variable). That will require a control channel
-   * to sysprof to request new writer/muxed APIs.
-   */
-
-  env = getenv ("MEMPROF_TRACE_FD");
-
-  if (env != NULL)
-    {
-      int fd = atoi (env);
-
-      if (fd > 0)
-        writer = sysprof_capture_writer_new_from_fd (fd, 0);
-    }
-
-  if (writer == NULL)
-    writer = sysprof_capture_writer_new ("memory.syscap", 0);
-
-  atexit (flush_writer);
 }
 
-#define gettid() syscall(__NR_gettid, 0)
-
 static inline void
 track_malloc (void   *ptr,
               size_t  size)
 {
-  if G_UNLIKELY (!writer)
-    return;
-
-  G_LOCK (writer);
-  sysprof_capture_writer_add_allocation (writer,
-                                         SYSPROF_CAPTURE_CURRENT_TIME,
-                                         sched_getcpu (),
-                                         pid,
-                                         gettid(),
-                                         GPOINTER_TO_SIZE (ptr),
-                                         size,
-                                         backtrace_func,
-                                         NULL);
-  G_UNLOCK (writer);
+  if G_LIKELY (ptr && collector_ready)
+    sysprof_collector_allocate (GPOINTER_TO_SIZE (ptr),
+                                size,
+                                backtrace_func,
+                                NULL);
 }
 
 static inline void
 track_free (void *ptr)
 {
-  if G_UNLIKELY (!writer)
-    return;
-
-  G_LOCK (writer);
-  sysprof_capture_writer_add_allocation (writer,
-                                         SYSPROF_CAPTURE_CURRENT_TIME,
-                                         sched_getcpu (),
-                                         pid,
-                                         gettid(),
-                                         GPOINTER_TO_SIZE (ptr),
-                                         0,
-                                         backtrace_func,
-                                         0);
-  G_UNLOCK (writer);
+  if G_LIKELY (ptr && collector_ready)
+    sysprof_collector_allocate (GPOINTER_TO_SIZE (ptr),
+                                0,
+                                backtrace_func,
+                                NULL);
 }
 
 void *


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