[sysprof/wip/chergert/mem-preload: 2/5] capture: add memory alloc and free capture frames



commit fc171ce2ce27cedac4ef4c9af214e0e0170714da
Author: Christian Hergert <chergert redhat com>
Date:   Thu Jan 30 18:24:04 2020 -0800

    capture: add memory alloc and free capture frames
    
    This adds a new SysprofCaptureMemoryAlloc and
    SysprofCaptureMemoryFree capture frame types. The Alloc frame also
    allows setting the backtrace that led to the allocation in addition
    to the thread identifier (such as from gettid).
    
    The goal for this initially is to track fragmentation, but ultimately
    we could use it for tracking allocations in general in terms of flame
    graphs and similar.

 src/libsysprof-capture/sysprof-capture-cursor.c    |  8 +++
 src/libsysprof-capture/sysprof-capture-reader.c    | 73 ++++++++++++++++++++++
 src/libsysprof-capture/sysprof-capture-reader.h    |  4 ++
 src/libsysprof-capture/sysprof-capture-types.h     | 50 +++++++++++----
 .../sysprof-capture-writer-cat.c                   | 33 ++++++++++
 src/libsysprof-capture/sysprof-capture-writer.c    | 72 +++++++++++++++++++++
 src/libsysprof-capture/sysprof-capture-writer.h    | 17 +++++
 src/tools/sysprof-dump.c                           | 23 +++++++
 8 files changed, 267 insertions(+), 13 deletions(-)
---
diff --git a/src/libsysprof-capture/sysprof-capture-cursor.c b/src/libsysprof-capture/sysprof-capture-cursor.c
index d94569f..788526a 100644
--- a/src/libsysprof-capture/sysprof-capture-cursor.c
+++ b/src/libsysprof-capture/sysprof-capture-cursor.c
@@ -207,6 +207,14 @@ sysprof_capture_cursor_foreach (SysprofCaptureCursor         *self,
           delegate = READ_DELEGATE (sysprof_capture_reader_read_file);
           break;
 
+        case SYSPROF_CAPTURE_FRAME_MEMORY_ALLOC:
+          delegate = READ_DELEGATE (sysprof_capture_reader_read_memory_alloc);
+          break;
+
+        case SYSPROF_CAPTURE_FRAME_MEMORY_FREE:
+          delegate = READ_DELEGATE (sysprof_capture_reader_read_memory_free);
+          break;
+
         default:
           if (!sysprof_capture_reader_skip (self->reader))
             return;
diff --git a/src/libsysprof-capture/sysprof-capture-reader.c b/src/libsysprof-capture/sysprof-capture-reader.c
index 5bf03a1..925cedd 100644
--- a/src/libsysprof-capture/sysprof-capture-reader.c
+++ b/src/libsysprof-capture/sysprof-capture-reader.c
@@ -1352,3 +1352,76 @@ sysprof_capture_reader_find_file (SysprofCaptureReader *self,
 
   return NULL;
 }
+
+const SysprofCaptureMemoryAlloc *
+sysprof_capture_reader_read_memory_alloc (SysprofCaptureReader *self)
+{
+  SysprofCaptureMemoryAlloc *ma;
+
+  g_assert (self != NULL);
+  g_assert ((self->pos % SYSPROF_CAPTURE_ALIGN) == 0);
+  g_assert (self->pos <= self->bufsz);
+
+  if (!sysprof_capture_reader_ensure_space_for (self, sizeof *ma))
+    return NULL;
+
+  ma = (SysprofCaptureMemoryAlloc *)(gpointer)&self->buf[self->pos];
+
+  sysprof_capture_reader_bswap_frame (self, &ma->frame);
+
+  if (ma->frame.type != SYSPROF_CAPTURE_FRAME_MEMORY_ALLOC)
+    return NULL;
+
+  if (ma->frame.len < sizeof *ma)
+    return NULL;
+
+  if (self->endian != G_BYTE_ORDER)
+    {
+      ma->n_addrs = GUINT16_SWAP_LE_BE (ma->n_addrs);
+      ma->alloc_size = GUINT64_SWAP_LE_BE (ma->alloc_size);
+      ma->alloc_addr = GUINT64_SWAP_LE_BE (ma->alloc_addr);
+      ma->tid = GUINT32_SWAP_LE_BE (ma->tid);
+    }
+
+  if (ma->frame.len < (sizeof *ma + (sizeof(SysprofCaptureAddress) * ma->n_addrs)))
+    return NULL;
+
+  if (!sysprof_capture_reader_ensure_space_for (self, ma->frame.len))
+    return NULL;
+
+  ma = (SysprofCaptureMemoryAlloc *)(gpointer)&self->buf[self->pos];
+
+  if (G_UNLIKELY (self->endian != G_BYTE_ORDER))
+    {
+      for (guint i = 0; i < ma->n_addrs; i++)
+        ma->addrs[i] = GUINT64_SWAP_LE_BE (ma->addrs[i]);
+    }
+
+  self->pos += ma->frame.len;
+
+  return ma;
+}
+
+const SysprofCaptureMemoryFree *
+sysprof_capture_reader_read_memory_free (SysprofCaptureReader *self)
+{
+  SysprofCaptureMemoryFree *mf;
+
+  g_assert (self != NULL);
+
+  mf = (SysprofCaptureMemoryFree *)
+    sysprof_capture_reader_read_basic (self,
+                                       SYSPROF_CAPTURE_FRAME_MEMORY_FREE,
+                                       sizeof *mf - sizeof (SysprofCaptureFrame));
+
+  if (mf != NULL)
+    {
+      if (G_UNLIKELY (self->endian != G_BYTE_ORDER))
+        {
+          mf->tid = GUINT32_SWAP_LE_BE (mf->tid);
+          mf->alloc_addr = GUINT64_SWAP_LE_BE (mf->alloc_addr);
+        }
+    }
+
+  return mf;
+}
diff --git a/src/libsysprof-capture/sysprof-capture-reader.h b/src/libsysprof-capture/sysprof-capture-reader.h
index 8467540..10b34d0 100644
--- a/src/libsysprof-capture/sysprof-capture-reader.h
+++ b/src/libsysprof-capture/sysprof-capture-reader.h
@@ -119,6 +119,10 @@ SYSPROF_AVAILABLE_IN_ALL
 const SysprofCaptureCounterSet         *sysprof_capture_reader_read_counter_set    (SysprofCaptureReader     
*self);
 SYSPROF_AVAILABLE_IN_ALL
 const SysprofCaptureFileChunk          *sysprof_capture_reader_read_file           (SysprofCaptureReader     
*self);
+SYSPROF_AVAILABLE_IN_3_36
+const SysprofCaptureMemoryAlloc        *sysprof_capture_reader_read_memory_alloc   (SysprofCaptureReader     
*self);
+SYSPROF_AVAILABLE_IN_3_36
+const SysprofCaptureMemoryFree         *sysprof_capture_reader_read_memory_free    (SysprofCaptureReader     
*self);
 SYSPROF_AVAILABLE_IN_ALL
 gboolean                                sysprof_capture_reader_reset               (SysprofCaptureReader     
*self);
 SYSPROF_AVAILABLE_IN_ALL
diff --git a/src/libsysprof-capture/sysprof-capture-types.h b/src/libsysprof-capture/sysprof-capture-types.h
index 29667ef..bf13ac2 100644
--- a/src/libsysprof-capture/sysprof-capture-types.h
+++ b/src/libsysprof-capture/sysprof-capture-types.h
@@ -115,19 +115,21 @@ typedef union
 
 typedef enum
 {
-  SYSPROF_CAPTURE_FRAME_TIMESTAMP  = 1,
-  SYSPROF_CAPTURE_FRAME_SAMPLE     = 2,
-  SYSPROF_CAPTURE_FRAME_MAP        = 3,
-  SYSPROF_CAPTURE_FRAME_PROCESS    = 4,
-  SYSPROF_CAPTURE_FRAME_FORK       = 5,
-  SYSPROF_CAPTURE_FRAME_EXIT       = 6,
-  SYSPROF_CAPTURE_FRAME_JITMAP     = 7,
-  SYSPROF_CAPTURE_FRAME_CTRDEF     = 8,
-  SYSPROF_CAPTURE_FRAME_CTRSET     = 9,
-  SYSPROF_CAPTURE_FRAME_MARK       = 10,
-  SYSPROF_CAPTURE_FRAME_METADATA   = 11,
-  SYSPROF_CAPTURE_FRAME_LOG        = 12,
-  SYSPROF_CAPTURE_FRAME_FILE_CHUNK = 13,
+  SYSPROF_CAPTURE_FRAME_TIMESTAMP    = 1,
+  SYSPROF_CAPTURE_FRAME_SAMPLE       = 2,
+  SYSPROF_CAPTURE_FRAME_MAP          = 3,
+  SYSPROF_CAPTURE_FRAME_PROCESS      = 4,
+  SYSPROF_CAPTURE_FRAME_FORK         = 5,
+  SYSPROF_CAPTURE_FRAME_EXIT         = 6,
+  SYSPROF_CAPTURE_FRAME_JITMAP       = 7,
+  SYSPROF_CAPTURE_FRAME_CTRDEF       = 8,
+  SYSPROF_CAPTURE_FRAME_CTRSET       = 9,
+  SYSPROF_CAPTURE_FRAME_MARK         = 10,
+  SYSPROF_CAPTURE_FRAME_METADATA     = 11,
+  SYSPROF_CAPTURE_FRAME_LOG          = 12,
+  SYSPROF_CAPTURE_FRAME_FILE_CHUNK   = 13,
+  SYSPROF_CAPTURE_FRAME_MEMORY_ALLOC = 14,
+  SYSPROF_CAPTURE_FRAME_MEMORY_FREE  = 15,
 } SysprofCaptureFrameType;
 
 SYSPROF_ALIGNED_BEGIN(1)
@@ -311,6 +313,28 @@ typedef struct
 } SysprofCaptureFileChunk
 SYSPROF_ALIGNED_END(1);
 
+SYSPROF_ALIGNED_BEGIN(1)
+typedef struct
+{
+  SysprofCaptureFrame   frame;
+  SysprofCaptureAddress alloc_addr;
+  gint64                alloc_size;
+  guint32               n_addrs : 16;
+  guint32               padding1 : 16;
+  gint32                tid;
+  SysprofCaptureAddress addrs[0];
+} SysprofCaptureMemoryAlloc
+SYSPROF_ALIGNED_END(1);
+
+SYSPROF_ALIGNED_BEGIN(1)
+typedef struct
+{
+  SysprofCaptureFrame   frame;
+  SysprofCaptureAddress alloc_addr;
+  gint32                tid;
+} SysprofCaptureMemoryFree
+SYSPROF_ALIGNED_END(1);
+
 G_STATIC_ASSERT (sizeof (SysprofCaptureFileHeader) == 256);
 G_STATIC_ASSERT (sizeof (SysprofCaptureFrame) == 24);
 G_STATIC_ASSERT (sizeof (SysprofCaptureMap) == 56);
diff --git a/src/libsysprof-capture/sysprof-capture-writer-cat.c 
b/src/libsysprof-capture/sysprof-capture-writer-cat.c
index 6dc2fce..2ea6e32 100644
--- a/src/libsysprof-capture/sysprof-capture-writer-cat.c
+++ b/src/libsysprof-capture/sysprof-capture-writer-cat.c
@@ -477,6 +477,39 @@ sysprof_capture_writer_cat (SysprofCaptureWriter  *self,
             goto panic;
           break;
 
+        case SYSPROF_CAPTURE_FRAME_MEMORY_ALLOC: {
+          const SysprofCaptureMemoryAlloc *frame;
+
+          if (!(frame = sysprof_capture_reader_read_memory_alloc (reader)))
+            goto panic;
+
+          sysprof_capture_writer_add_memory_alloc (self,
+                                                   frame->frame.time,
+                                                   frame->frame.cpu,
+                                                   frame->frame.pid,
+                                                   frame->tid,
+                                                   frame->alloc_addr,
+                                                   frame->alloc_size,
+                                                   frame->addrs,
+                                                   frame->n_addrs);
+          break;
+        }
+
+        case SYSPROF_CAPTURE_FRAME_MEMORY_FREE: {
+          const SysprofCaptureMemoryFree *frame;
+
+          if (!(frame = sysprof_capture_reader_read_memory_free (reader)))
+            goto panic;
+
+          sysprof_capture_writer_add_memory_free (self,
+                                                  frame->frame.time,
+                                                  frame->frame.cpu,
+                                                  frame->frame.pid,
+                                                  frame->tid,
+                                                  frame->alloc_addr);
+          break;
+        }
+
         default:
           /* Silently drop, which is better than looping. We could potentially
            * copy this over using the raw bytes at some point.
diff --git a/src/libsysprof-capture/sysprof-capture-writer.c b/src/libsysprof-capture/sysprof-capture-writer.c
index 956340e..25b565b 100644
--- a/src/libsysprof-capture/sysprof-capture-writer.c
+++ b/src/libsysprof-capture/sysprof-capture-writer.c
@@ -1510,3 +1510,75 @@ sysprof_capture_writer_set_flush_delay (SysprofCaptureWriter *self,
 
   g_source_attach (self->periodic_flush, main_context);
 }
+
+gboolean
+sysprof_capture_writer_add_memory_alloc (SysprofCaptureWriter        *self,
+                                         gint64                       time,
+                                         gint                         cpu,
+                                         gint32                       pid,
+                                         gint32                       tid,
+                                         SysprofCaptureAddress        alloc_addr,
+                                         gsize                        alloc_size,
+                                         const SysprofCaptureAddress *addrs,
+                                         guint                        n_addrs)
+{
+  SysprofCaptureMemoryAlloc *ev;
+  gsize len;
+
+  g_assert (self != NULL);
+
+  len = sizeof *ev + (n_addrs * 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->n_addrs = n_addrs;
+  ev->tid = tid;
+
+  memcpy (ev->addrs, addrs, (n_addrs * sizeof (SysprofCaptureAddress)));
+
+  self->stat.frame_count[SYSPROF_CAPTURE_FRAME_MEMORY_ALLOC]++;
+
+  return TRUE;
+}
+
+gboolean
+sysprof_capture_writer_add_memory_free (SysprofCaptureWriter        *self,
+                                        gint64                       time,
+                                        gint                         cpu,
+                                        gint32                       pid,
+                                        gint32                       tid,
+                                        SysprofCaptureAddress        alloc_addr)
+{
+  SysprofCaptureMemoryFree *ev;
+  gsize len = sizeof *ev;
+
+  g_assert (self != NULL);
+
+  ev = (SysprofCaptureMemoryFree *)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_FREE);
+
+  ev->tid = tid;
+  ev->alloc_addr = alloc_addr;
+
+  self->stat.frame_count[SYSPROF_CAPTURE_FRAME_MEMORY_FREE]++;
+
+  return TRUE;
+}
diff --git a/src/libsysprof-capture/sysprof-capture-writer.h b/src/libsysprof-capture/sysprof-capture-writer.h
index 8d9859a..2580749 100644
--- a/src/libsysprof-capture/sysprof-capture-writer.h
+++ b/src/libsysprof-capture/sysprof-capture-writer.h
@@ -183,6 +183,23 @@ gboolean              sysprof_capture_writer_add_log         (SysprofCaptureWrit
                                                               GLogLevelFlags                     severity,
                                                               const gchar                       *domain,
                                                               const gchar                       *message);
+SYSPROF_AVAILABLE_IN_3_36
+gboolean              sysprof_capture_writer_add_memory_alloc(SysprofCaptureWriter              *self,
+                                                              gint64                             time,
+                                                              gint                               cpu,
+                                                              gint32                             pid,
+                                                              gint32                             tid,
+                                                              SysprofCaptureAddress              alloc_addr,
+                                                              gsize                              alloc_size,
+                                                              const SysprofCaptureAddress       *addrs,
+                                                              guint                              n_addrs);
+SYSPROF_AVAILABLE_IN_3_36
+gboolean              sysprof_capture_writer_add_memory_free (SysprofCaptureWriter              *self,
+                                                              gint64                             time,
+                                                              gint                               cpu,
+                                                              gint32                             pid,
+                                                              gint32                             tid,
+                                                              SysprofCaptureAddress              alloc_addr);
 SYSPROF_AVAILABLE_IN_ALL
 gboolean              sysprof_capture_writer_flush           (SysprofCaptureWriter              *self);
 SYSPROF_AVAILABLE_IN_ALL
diff --git a/src/tools/sysprof-dump.c b/src/tools/sysprof-dump.c
index f93a177..a35cb7e 100644
--- a/src/tools/sysprof-dump.c
+++ b/src/tools/sysprof-dump.c
@@ -299,6 +299,29 @@ main (gint argc,
           }
           break;
 
+        case SYSPROF_CAPTURE_FRAME_MEMORY_ALLOC:
+          {
+            const SysprofCaptureMemoryAlloc *ev = sysprof_capture_reader_read_memory_alloc (reader);
+            gdouble ptime = (ev->frame.time - begin_time) / (gdouble)SYSPROF_NSEC_PER_SEC;
+
+            g_print ("MALLOC: pid=%d tid=%d addr=%"G_GUINT64_FORMAT"x size=%"G_GUINT64_FORMAT" 
time=%"G_GINT64_FORMAT" (%lf)\n",
+                     ev->frame.pid, ev->tid,
+                     ev->alloc_addr, ev->alloc_size,
+                     ev->frame.time, ptime);
+          }
+          break;
+
+        case SYSPROF_CAPTURE_FRAME_MEMORY_FREE:
+          {
+            const SysprofCaptureMemoryFree *ev = sysprof_capture_reader_read_memory_free (reader);
+            gdouble ptime = (ev->frame.time - begin_time) / (gdouble)SYSPROF_NSEC_PER_SEC;
+
+            g_print ("FREE: pid=%d tid=%d addr=%"G_GUINT64_FORMAT"x time=%"G_GINT64_FORMAT" (%lf)\n",
+                     ev->frame.pid, ev->tid, ev->alloc_addr,
+                     ev->frame.time, ptime);
+          }
+          break;
+
         default:
           g_print ("Skipping unknown frame type: (%d): ", type);
           if (!sysprof_capture_reader_skip (reader))


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