[sysprof] capture: add frame type for defining and setting counters



commit c87a90cd9a2a687161125512ce7b4f2df31783fa
Author: Christian Hergert <christian hergert me>
Date:   Thu Apr 14 18:29:39 2016 -0700

    capture: add frame type for defining and setting counters
    
    We might want to add a CTRADD type later on, for relative values rather
    than absolute. But this should get us started.
    
    Simply define counters upfront, and then set them during the capture
    process.
    
    Obviously, we need to come up with a good way to visualize this
    information in the UI.

 lib/sp-capture-reader.c |  101 +++++++++++++++++++++++++++++++++++++-
 lib/sp-capture-reader.h |   52 ++++++++++---------
 lib/sp-capture-types.h  |   44 ++++++++++++++++
 lib/sp-capture-writer.c |  125 +++++++++++++++++++++++++++++++++++++++++++++++
 lib/sp-capture-writer.h |   13 +++++
 tests/test-capture.c    |   83 +++++++++++++++++++++++++++++++
 6 files changed, 392 insertions(+), 26 deletions(-)
---
diff --git a/lib/sp-capture-reader.c b/lib/sp-capture-reader.c
index f5d4544..69582b7 100644
--- a/lib/sp-capture-reader.c
+++ b/lib/sp-capture-reader.c
@@ -539,7 +539,7 @@ sp_capture_reader_read_sample (SpCaptureReader *self)
 
   sample = (SpCaptureSample *)(gpointer)&self->buf[self->pos];
 
-  if (self->endian != G_BYTE_ORDER)
+  if (G_UNLIKELY (self->endian != G_BYTE_ORDER))
     {
       guint i;
 
@@ -552,6 +552,105 @@ sp_capture_reader_read_sample (SpCaptureReader *self)
   return sample;
 }
 
+const SpCaptureFrameCounterDefine *
+sp_capture_reader_read_counter_define (SpCaptureReader *self)
+{
+  SpCaptureFrameCounterDefine *def;
+
+  g_assert (self != NULL);
+  g_assert ((self->pos % SP_CAPTURE_ALIGN) == 0);
+  g_assert (self->pos <= self->bufsz);
+
+  if (!sp_capture_reader_ensure_space_for (self, sizeof *def))
+    return NULL;
+
+  def = (SpCaptureFrameCounterDefine *)(gpointer)&self->buf[self->pos];
+
+  if (def->frame.type != SP_CAPTURE_FRAME_CTRDEF)
+    return NULL;
+
+  if (def->frame.len < sizeof *def)
+    return NULL;
+
+  if (G_UNLIKELY (self->endian != G_BYTE_ORDER))
+    def->n_counters = GUINT16_SWAP_LE_BE (def->n_counters);
+
+  if (def->frame.len < (sizeof *def + (sizeof (SpCaptureFrameCounterDefine) * def->n_counters)))
+    return NULL;
+
+  if (!sp_capture_reader_ensure_space_for (self, def->frame.len))
+    return NULL;
+
+  def = (SpCaptureFrameCounterDefine *)(gpointer)&self->buf[self->pos];
+
+  if (G_UNLIKELY (self->endian != G_BYTE_ORDER))
+    {
+      guint i;
+
+      for (i = 0; i < def->n_counters; i++)
+        {
+          def->counters[i].id = GUINT32_SWAP_LE_BE (def->counters[i].id);
+          def->counters[i].value = GUINT64_SWAP_LE_BE (def->counters[i].value);
+        }
+    }
+
+  self->pos += def->frame.len;
+
+  return def;
+}
+
+const SpCaptureFrameCounterSet *
+sp_capture_reader_read_counter_set (SpCaptureReader *self)
+{
+  SpCaptureFrameCounterSet *set;
+
+  g_assert (self != NULL);
+  g_assert ((self->pos % SP_CAPTURE_ALIGN) == 0);
+  g_assert (self->pos <= self->bufsz);
+
+  if (!sp_capture_reader_ensure_space_for (self, sizeof *set))
+    return NULL;
+
+  set = (SpCaptureFrameCounterSet *)(gpointer)&self->buf[self->pos];
+
+  if (set->frame.type != SP_CAPTURE_FRAME_CTRSET)
+    return NULL;
+
+  if (set->frame.len < sizeof *set)
+    return NULL;
+
+  if (self->endian != G_BYTE_ORDER)
+    set->n_values = GUINT16_SWAP_LE_BE (set->n_values);
+
+  if (set->frame.len < (sizeof *set + (sizeof (SpCaptureCounterValues) * set->n_values)))
+    return NULL;
+
+  if (!sp_capture_reader_ensure_space_for (self, set->frame.len))
+    return NULL;
+
+  set = (SpCaptureFrameCounterSet *)(gpointer)&self->buf[self->pos];
+
+  if (G_UNLIKELY (self->endian != G_BYTE_ORDER))
+    {
+      guint i;
+
+      for (i = 0; i < set->n_values; i++)
+        {
+          guint j;
+
+          for (j = 0; j < G_N_ELEMENTS (set->values[0].values); i++)
+            {
+              set->values[i].ids[j] = GUINT32_SWAP_LE_BE (set->values[i].ids[j]);
+              set->values[i].values[j] = GUINT64_SWAP_LE_BE (set->values[i].values[j]);
+            }
+        }
+    }
+
+  self->pos += set->frame.len;
+
+  return set;
+}
+
 gboolean
 sp_capture_reader_reset (SpCaptureReader *self)
 {
diff --git a/lib/sp-capture-reader.h b/lib/sp-capture-reader.h
index 14d93c8..f703b3d 100644
--- a/lib/sp-capture-reader.h
+++ b/lib/sp-capture-reader.h
@@ -25,31 +25,33 @@ G_BEGIN_DECLS
 
 typedef struct _SpCaptureReader SpCaptureReader;
 
-SpCaptureReader          *sp_capture_reader_new            (const gchar         *filename,
-                                                            GError             **error);
-SpCaptureReader          *sp_capture_reader_new_from_fd    (int                  fd,
-                                                            GError             **error);
-SpCaptureReader          *sp_capture_reader_ref            (SpCaptureReader     *self);
-void                      sp_capture_reader_unref          (SpCaptureReader     *self);
-const gchar              *sp_capture_reader_get_filename   (SpCaptureReader     *self);
-const gchar              *sp_capture_reader_get_time       (SpCaptureReader     *self);
-gboolean                  sp_capture_reader_skip           (SpCaptureReader     *self);
-gboolean                  sp_capture_reader_peek_type      (SpCaptureReader     *self,
-                                                            SpCaptureFrameType  *type);
-const SpCaptureMap       *sp_capture_reader_read_map       (SpCaptureReader     *self);
-const SpCaptureExit      *sp_capture_reader_read_exit      (SpCaptureReader     *self);
-const SpCaptureFork      *sp_capture_reader_read_fork      (SpCaptureReader     *self);
-const SpCaptureTimestamp *sp_capture_reader_read_timestamp (SpCaptureReader     *self);
-const SpCaptureProcess   *sp_capture_reader_read_process   (SpCaptureReader     *self);
-const SpCaptureSample    *sp_capture_reader_read_sample    (SpCaptureReader     *self);
-GHashTable               *sp_capture_reader_read_jitmap    (SpCaptureReader     *self);
-gboolean                  sp_capture_reader_reset          (SpCaptureReader     *self);
-gboolean                  sp_capture_reader_splice         (SpCaptureReader     *self,
-                                                            SpCaptureWriter     *dest,
-                                                            GError             **error);
-gboolean                  sp_capture_reader_save_as        (SpCaptureReader     *self,
-                                                            const gchar         *filename,
-                                                            GError             **error);
+SpCaptureReader                   *sp_capture_reader_new                 (const gchar         *filename,
+                                                                          GError             **error);
+SpCaptureReader                   *sp_capture_reader_new_from_fd         (int                  fd,
+                                                                          GError             **error);
+SpCaptureReader                   *sp_capture_reader_ref                 (SpCaptureReader     *self);
+void                               sp_capture_reader_unref               (SpCaptureReader     *self);
+const gchar                       *sp_capture_reader_get_filename        (SpCaptureReader     *self);
+const gchar                       *sp_capture_reader_get_time            (SpCaptureReader     *self);
+gboolean                           sp_capture_reader_skip                (SpCaptureReader     *self);
+gboolean                           sp_capture_reader_peek_type           (SpCaptureReader     *self,
+                                                                          SpCaptureFrameType  *type);
+const SpCaptureMap                *sp_capture_reader_read_map            (SpCaptureReader     *self);
+const SpCaptureExit               *sp_capture_reader_read_exit           (SpCaptureReader     *self);
+const SpCaptureFork               *sp_capture_reader_read_fork           (SpCaptureReader     *self);
+const SpCaptureTimestamp          *sp_capture_reader_read_timestamp      (SpCaptureReader     *self);
+const SpCaptureProcess            *sp_capture_reader_read_process        (SpCaptureReader     *self);
+const SpCaptureSample             *sp_capture_reader_read_sample         (SpCaptureReader     *self);
+GHashTable                        *sp_capture_reader_read_jitmap         (SpCaptureReader     *self);
+const SpCaptureFrameCounterDefine *sp_capture_reader_read_counter_define (SpCaptureReader     *self);
+const SpCaptureFrameCounterSet    *sp_capture_reader_read_counter_set    (SpCaptureReader     *self);
+gboolean                           sp_capture_reader_reset               (SpCaptureReader     *self);
+gboolean                           sp_capture_reader_splice              (SpCaptureReader     *self,
+                                                                          SpCaptureWriter     *dest,
+                                                                          GError             **error);
+gboolean                           sp_capture_reader_save_as             (SpCaptureReader     *self,
+                                                                          const gchar         *filename,
+                                                                          GError             **error);
 
 #ifndef SP_DISABLE_GOBJECT
 # define SP_TYPE_CAPTURE_READER (sp_capture_reader_get_type())
diff --git a/lib/sp-capture-types.h b/lib/sp-capture-types.h
index 7bb3ab7..ce66128 100644
--- a/lib/sp-capture-types.h
+++ b/lib/sp-capture-types.h
@@ -54,6 +54,9 @@ typedef enum
   SP_CAPTURE_FRAME_FORK      = 5,
   SP_CAPTURE_FRAME_EXIT      = 6,
   SP_CAPTURE_FRAME_JITMAP    = 7,
+  SP_CAPTURE_FRAME_CTRDEF    = 8,
+  SP_CAPTURE_FRAME_CTRADD    = 9,
+  SP_CAPTURE_FRAME_CTRSET    = 10,
 } SpCaptureFrameType;
 
 #pragma pack(push, 1)
@@ -126,6 +129,43 @@ typedef struct
   SpCaptureFrame frame;
 } SpCaptureTimestamp;
 
+typedef struct
+{
+  gchar   category[32];
+  gchar   name[32];
+  gchar   description[52];
+  guint32 id : 24;
+  guint8  type;
+  gint64  value;
+} SpCaptureCounter;
+
+typedef struct
+{
+  SpCaptureFrame   frame;
+  guint16          n_counters;
+  guint64          padding : 48;
+  SpCaptureCounter counters[0];
+} SpCaptureFrameCounterDefine;
+
+typedef struct
+{
+  /*
+   * 96 bytes might seem a bit odd, but the counter frame header is 32
+   * bytes.  So this makes a nice 2-cacheline aligned size which is
+   * useful when the number of counters is rather small.
+   */
+  guint32 ids[8];
+  gint64  values[8];
+} SpCaptureCounterValues;
+
+typedef struct
+{
+  SpCaptureFrame         frame;
+  guint16                n_values;
+  guint64                padding : 48;
+  SpCaptureCounterValues values[0];
+} SpCaptureFrameCounterSet;
+
 #pragma pack(pop)
 
 G_STATIC_ASSERT (sizeof (SpCaptureFileHeader) == 256);
@@ -137,6 +177,10 @@ G_STATIC_ASSERT (sizeof (SpCaptureSample) == 32);
 G_STATIC_ASSERT (sizeof (SpCaptureFork) == 28);
 G_STATIC_ASSERT (sizeof (SpCaptureExit) == 24);
 G_STATIC_ASSERT (sizeof (SpCaptureTimestamp) == 24);
+G_STATIC_ASSERT (sizeof (SpCaptureCounter) == 128);
+G_STATIC_ASSERT (sizeof (SpCaptureCounterValues) == 96);
+G_STATIC_ASSERT (sizeof (SpCaptureFrameCounterDefine) == 32);
+G_STATIC_ASSERT (sizeof (SpCaptureFrameCounterSet) == 32);
 
 static inline gint
 sp_capture_address_compare (SpCaptureAddress a,
diff --git a/lib/sp-capture-writer.c b/lib/sp-capture-writer.c
index f0f725f..794fa38 100644
--- a/lib/sp-capture-writer.c
+++ b/lib/sp-capture-writer.c
@@ -176,6 +176,10 @@ static inline gboolean
 sp_capture_writer_ensure_space_for (SpCaptureWriter *self,
                                     gsize            len)
 {
+  /* Check for max frame size */
+  if (len > G_MAXUSHORT)
+    return FALSE;
+
   if ((self->len - self->pos) < len)
     {
       if (!sp_capture_writer_flush_data (self))
@@ -952,3 +956,124 @@ sp_capture_writer_stat (SpCaptureWriter *self,
 
   *stat = self->stat;
 }
+
+gboolean
+sp_capture_writer_define_counters (SpCaptureWriter        *self,
+                                   gint64                  time,
+                                   gint                    cpu,
+                                   GPid                    pid,
+                                   const SpCaptureCounter *counters,
+                                   guint                   n_counters)
+{
+  SpCaptureFrameCounterDefine *def;
+  gsize len;
+  guint i;
+
+  g_assert (self != NULL);
+  g_assert (counters != NULL);
+  g_assert ((self->pos % SP_CAPTURE_ALIGN) == 0);
+
+  if (n_counters == 0)
+    return TRUE;
+
+  len = sizeof *def + (sizeof *counters * n_counters);
+
+  sp_capture_writer_realign (&len);
+
+  if (!sp_capture_writer_ensure_space_for (self, len))
+    return FALSE;
+
+  g_assert ((self->pos % SP_CAPTURE_ALIGN) == 0);
+
+  def = (SpCaptureFrameCounterDefine *)&self->buf[self->pos];
+  def->frame.len = len;
+  def->frame.cpu = cpu;
+  def->frame.pid = pid;
+  def->frame.time = time;
+  def->frame.type = SP_CAPTURE_FRAME_CTRDEF;
+  def->frame.padding = 0;
+  def->padding = 0;
+  def->n_counters = n_counters;
+
+  for (i = 0; i < n_counters; i++)
+    def->counters[i] = counters[i];
+
+  self->pos += def->frame.len;
+
+  g_assert ((self->pos % SP_CAPTURE_ALIGN) == 0);
+
+  self->stat.frame_count[SP_CAPTURE_FRAME_CTRDEF]++;
+
+  return TRUE;
+}
+
+gboolean
+sp_capture_writer_set_counters (SpCaptureWriter *self,
+                                gint64           time,
+                                gint             cpu,
+                                GPid             pid,
+                                const guint     *counters_ids,
+                                const gint64    *values,
+                                guint            n_counters)
+{
+  SpCaptureFrameCounterSet *set;
+  gsize len;
+  guint n_groups;
+  guint group;
+  guint field;
+  guint i;
+
+  g_assert (self != NULL);
+  g_assert (counters_ids != NULL);
+  g_assert (values != NULL || !n_counters);
+  g_assert ((self->pos % SP_CAPTURE_ALIGN) == 0);
+
+  if (n_counters == 0)
+    return TRUE;
+
+  /* Determine how many value groups we need */
+  n_groups = n_counters / G_N_ELEMENTS (set->values[0].values);
+  if ((n_groups * G_N_ELEMENTS (set->values[0].values)) != n_counters)
+    n_groups++;
+
+  len = sizeof *set + (n_groups * sizeof (SpCaptureCounterValues));
+
+  sp_capture_writer_realign (&len);
+
+  if (!sp_capture_writer_ensure_space_for (self, len))
+    return FALSE;
+
+  g_assert ((self->pos % SP_CAPTURE_ALIGN) == 0);
+
+  set = (SpCaptureFrameCounterSet *)&self->buf[self->pos];
+  set->frame.len = len;
+  set->frame.cpu = cpu;
+  set->frame.pid = pid;
+  set->frame.time = time;
+  set->frame.type = SP_CAPTURE_FRAME_CTRSET;
+  set->frame.padding = 0;
+  set->padding = 0;
+  set->n_values = n_groups;
+
+  for (i = 0, group = 0, field = 0; i < n_counters; i++)
+    {
+      set->values[group].ids[field] = counters_ids[i];
+      set->values[group].values[field] = values[i];
+
+      field++;
+
+      if (field == G_N_ELEMENTS (set->values[0].values))
+        {
+          field = 0;
+          group++;
+        }
+    }
+
+  self->pos += set->frame.len;
+
+  g_assert ((self->pos % SP_CAPTURE_ALIGN) == 0);
+
+  self->stat.frame_count[SP_CAPTURE_FRAME_CTRSET]++;
+
+  return TRUE;
+}
diff --git a/lib/sp-capture-writer.h b/lib/sp-capture-writer.h
index 1846fd1..81de7de 100644
--- a/lib/sp-capture-writer.h
+++ b/lib/sp-capture-writer.h
@@ -81,6 +81,19 @@ gboolean            sp_capture_writer_add_timestamp   (SpCaptureWriter         *
                                                        gint64                   time,
                                                        gint                     cpu,
                                                        GPid                     pid);
+gboolean            sp_capture_writer_define_counters (SpCaptureWriter         *self,
+                                                       gint64                   time,
+                                                       gint                     cpu,
+                                                       GPid                     pid,
+                                                       const SpCaptureCounter  *counters,
+                                                       guint                    n_counters);
+gboolean            sp_capture_writer_set_counters    (SpCaptureWriter         *self,
+                                                       gint64                   time,
+                                                       gint                     cpu,
+                                                       GPid                     pid,
+                                                       const guint             *counters_ids,
+                                                       const gint64            *values,
+                                                       guint                    n_counters);
 gboolean            sp_capture_writer_flush           (SpCaptureWriter         *self);
 gboolean            sp_capture_writer_save_as         (SpCaptureWriter         *self,
                                                        const gchar             *filename,
diff --git a/tests/test-capture.c b/tests/test-capture.c
index 7ddb956..f353a93 100644
--- a/tests/test-capture.c
+++ b/tests/test-capture.c
@@ -183,6 +183,89 @@ test_reader_basic (void)
       g_assert_cmpint (ex->child_pid, ==, i);
     }
 
+  {
+    SpCaptureCounter counters[10];
+
+    t = SP_CAPTURE_CURRENT_TIME;
+
+    for (i = 0; i < G_N_ELEMENTS (counters); i++)
+      {
+        g_snprintf (counters[i].category, sizeof counters[i].category, "cat%d", i);
+        g_snprintf (counters[i].name, sizeof counters[i].name, "name%d", i);
+        g_snprintf (counters[i].description, sizeof counters[i].description, "desc%d", i);
+        counters[i].id = i + 1;
+        counters[i].type = 0;
+        counters[i].value = i * G_GINT64_CONSTANT (100000000000);
+      }
+
+    r = sp_capture_writer_define_counters (writer, t, -1, -1, counters, G_N_ELEMENTS (counters));
+    g_assert_cmpint (r, ==, TRUE);
+  }
+
+  sp_capture_writer_flush (writer);
+
+  {
+    const SpCaptureFrameCounterDefine *def;
+
+    def = sp_capture_reader_read_counter_define (reader);
+    g_assert (def != NULL);
+    g_assert_cmpint (def->n_counters, ==, 10);
+
+    for (i = 0; i < def->n_counters; i++)
+      {
+        g_autofree gchar *cat = g_strdup_printf ("cat%d", i);
+        g_autofree gchar *name = g_strdup_printf ("name%d", i);
+        g_autofree gchar *desc = g_strdup_printf ("desc%d", i);
+
+        g_assert_cmpstr (def->counters[i].category, ==, cat);
+        g_assert_cmpstr (def->counters[i].name, ==, name);
+        g_assert_cmpstr (def->counters[i].description, ==, desc);
+      }
+  }
+
+  for (i = 0; i < 1000; i++)
+    {
+      gint ids[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+      gint64 values[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+      r = sp_capture_writer_set_counters (writer, t, -1,  -1, ids, values, G_N_ELEMENTS (values));
+      g_assert_cmpint (r, ==, TRUE);
+    }
+
+  sp_capture_writer_flush (writer);
+
+  for (i = 0; i < 1000; i++)
+    {
+      const SpCaptureFrameCounterSet *set;
+
+      set = sp_capture_reader_read_counter_set (reader);
+      g_assert (set != NULL);
+
+      /* 8 per chunk */
+      g_assert_cmpint (set->n_values, ==, 2);
+
+      g_assert_cmpint (1, ==, set->values[0].ids[0]);
+      g_assert_cmpint (2, ==, set->values[0].ids[1]);
+      g_assert_cmpint (3, ==, set->values[0].ids[2]);
+      g_assert_cmpint (4, ==, set->values[0].ids[3]);
+      g_assert_cmpint (5, ==, set->values[0].ids[4]);
+      g_assert_cmpint (6, ==, set->values[0].ids[5]);
+      g_assert_cmpint (7, ==, set->values[0].ids[6]);
+      g_assert_cmpint (8, ==, set->values[0].ids[7]);
+      g_assert_cmpint (9, ==, set->values[1].ids[0]);
+      g_assert_cmpint (10, ==, set->values[1].ids[1]);
+      g_assert_cmpint (1, ==, set->values[0].values[0]);
+      g_assert_cmpint (2, ==, set->values[0].values[1]);
+      g_assert_cmpint (3, ==, set->values[0].values[2]);
+      g_assert_cmpint (4, ==, set->values[0].values[3]);
+      g_assert_cmpint (5, ==, set->values[0].values[4]);
+      g_assert_cmpint (6, ==, set->values[0].values[5]);
+      g_assert_cmpint (7, ==, set->values[0].values[6]);
+      g_assert_cmpint (8, ==, set->values[0].values[7]);
+      g_assert_cmpint (9, ==, set->values[1].values[0]);
+      g_assert_cmpint (10, ==, set->values[1].values[1]);
+    }
+
   for (i = 0; i < 1000; i++)
     {
       SpCaptureAddress addr;


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