From 4bdbf130b23ab0a63a52c7db613936bd6e0f5e05 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Mon, 14 May 2018 17:15:57 +0100 Subject: [PATCH] capture: add simple mark support The goal here is to have an API that allows us to record things like frame timing data. We might iterate on this API a bit, but this gets us started. A SpCaptureMark with a zero duration should be treated like an epoch mark once a visualizer is created. SpCaptureMark with a non-zero duration should be treated like a begin/end of operation. This may be useful in generating something like a flame graph. --- lib/capture/sp-capture-cursor.c | 4 +++ lib/capture/sp-capture-reader.c | 52 +++++++++++++++++++++++++++++++++ lib/capture/sp-capture-reader.h | 1 + lib/capture/sp-capture-types.h | 10 +++++++ lib/capture/sp-capture-writer.c | 39 +++++++++++++++++++++++++ lib/capture/sp-capture-writer.h | 7 +++++ tests/test-capture.c | 46 +++++++++++++++++++++++++++++ tools/sysprof-dump.c | 14 +++++++++ 8 files changed, 173 insertions(+) diff --git a/lib/capture/sp-capture-cursor.c b/lib/capture/sp-capture-cursor.c index b629ea5d..eb675243 100644 --- a/lib/capture/sp-capture-cursor.c +++ b/lib/capture/sp-capture-cursor.c @@ -99,6 +99,10 @@ sp_capture_cursor_foreach (SpCaptureCursor *self, delegate = READ_DELEGATE (sp_capture_reader_read_map); break; + case SP_CAPTURE_FRAME_MARK: + delegate = READ_DELEGATE (sp_capture_reader_read_mark); + break; + case SP_CAPTURE_FRAME_PROCESS: delegate = READ_DELEGATE (sp_capture_reader_read_process); break; diff --git a/lib/capture/sp-capture-reader.c b/lib/capture/sp-capture-reader.c index 495bd297..df331747 100644 --- a/lib/capture/sp-capture-reader.c +++ b/lib/capture/sp-capture-reader.c @@ -198,6 +198,17 @@ sp_capture_reader_bswap_map (SpCaptureReader *self, } } +static inline void +sp_capture_reader_bswap_mark (SpCaptureReader *self, + SpCaptureMark *mark) +{ + g_assert (self != NULL); + g_assert (mark != NULL); + + if (G_UNLIKELY (self->endian != G_BYTE_ORDER)) + mark->duration = GUINT64_SWAP_LE_BE (mark->duration); +} + static inline void sp_capture_reader_bswap_jitmap (SpCaptureReader *self, SpCaptureJitmap *jitmap) @@ -426,6 +437,47 @@ sp_capture_reader_read_map (SpCaptureReader *self) return map; } +const SpCaptureMark * +sp_capture_reader_read_mark (SpCaptureReader *self) +{ + SpCaptureMark *mark; + + 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 *mark)) + return NULL; + + mark = (SpCaptureMark *)(gpointer)&self->buf[self->pos]; + + sp_capture_reader_bswap_frame (self, &mark->frame); + + if (mark->frame.type != SP_CAPTURE_FRAME_MARK) + return NULL; + + if (mark->frame.len < (sizeof *mark + 1)) + return NULL; + + if (!sp_capture_reader_ensure_space_for (self, mark->frame.len)) + return NULL; + + mark = (SpCaptureMark *)(gpointer)&self->buf[self->pos]; + + sp_capture_reader_bswap_mark (self, mark); + + self->pos += mark->frame.len; + + if ((self->pos % SP_CAPTURE_ALIGN) != 0) + return NULL; + + /* Ensure trailing \0 in name and message */ + mark->name[sizeof mark->name - 1] = 0; + self->buf[self->pos + mark->frame.len - 1] = 0; + + return mark; +} + const SpCaptureProcess * sp_capture_reader_read_process (SpCaptureReader *self) { diff --git a/lib/capture/sp-capture-reader.h b/lib/capture/sp-capture-reader.h index bc9a5fe4..15886d29 100644 --- a/lib/capture/sp-capture-reader.h +++ b/lib/capture/sp-capture-reader.h @@ -42,6 +42,7 @@ gboolean sp_capture_reader_peek_type (SpCapt gboolean sp_capture_reader_peek_frame (SpCaptureReader *self, SpCaptureFrame *frame); const SpCaptureMap *sp_capture_reader_read_map (SpCaptureReader *self); +const SpCaptureMark *sp_capture_reader_read_mark (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); diff --git a/lib/capture/sp-capture-types.h b/lib/capture/sp-capture-types.h index 49736253..8c169210 100644 --- a/lib/capture/sp-capture-types.h +++ b/lib/capture/sp-capture-types.h @@ -68,6 +68,7 @@ typedef enum SP_CAPTURE_FRAME_JITMAP = 7, SP_CAPTURE_FRAME_CTRDEF = 8, SP_CAPTURE_FRAME_CTRSET = 9, + SP_CAPTURE_FRAME_MARK = 10, } SpCaptureFrameType; #pragma pack(push, 1) @@ -179,6 +180,14 @@ typedef struct SpCaptureCounterValues values[0]; } SpCaptureFrameCounterSet; +typedef struct +{ + SpCaptureFrame frame; + gint64 duration; + gchar name[32]; + gchar message[0]; +} SpCaptureMark; + #pragma pack(pop) G_STATIC_ASSERT (sizeof (SpCaptureFileHeader) == 256); @@ -194,6 +203,7 @@ G_STATIC_ASSERT (sizeof (SpCaptureCounter) == 128); G_STATIC_ASSERT (sizeof (SpCaptureCounterValues) == 96); G_STATIC_ASSERT (sizeof (SpCaptureFrameCounterDefine) == 32); G_STATIC_ASSERT (sizeof (SpCaptureFrameCounterSet) == 32); +G_STATIC_ASSERT (sizeof (SpCaptureMark) == 64); static inline gint sp_capture_address_compare (SpCaptureAddress a, diff --git a/lib/capture/sp-capture-writer.c b/lib/capture/sp-capture-writer.c index 610e22f4..c9097bbe 100644 --- a/lib/capture/sp-capture-writer.c +++ b/lib/capture/sp-capture-writer.c @@ -536,6 +536,45 @@ sp_capture_writer_add_map (SpCaptureWriter *self, return TRUE; } +gboolean +sp_capture_writer_add_mark (SpCaptureWriter *self, + gint64 time, + gint cpu, + GPid pid, + guint64 duration, + const gchar *name, + const gchar *message) +{ + SpCaptureMark *ev; + gsize message_len; + gsize len; + + g_assert (self != NULL); + g_assert (name != NULL); + + if (message == NULL) + message = ""; + message_len = strlen (message) + 1; + + len = sizeof *ev + message_len; + ev = (SpCaptureMark *)sp_capture_writer_allocate (self, &len); + if (!ev) + return FALSE; + + sp_capture_writer_frame_init (&ev->frame, + len, + cpu, + pid, + time, + SP_CAPTURE_FRAME_MARK); + + ev->duration = duration; + memcpy (ev->name, name, sizeof ev->name); + memcpy (ev->message, message, message_len); + + return TRUE; +} + SpCaptureAddress sp_capture_writer_add_jitmap (SpCaptureWriter *self, const gchar *name) diff --git a/lib/capture/sp-capture-writer.h b/lib/capture/sp-capture-writer.h index fae25ed0..0c208e78 100644 --- a/lib/capture/sp-capture-writer.h +++ b/lib/capture/sp-capture-writer.h @@ -55,6 +55,13 @@ gboolean sp_capture_writer_add_map (SpCaptureWriter * guint64 offset, guint64 inode, const gchar *filename); +gboolean sp_capture_writer_add_mark (SpCaptureWriter *self, + gint64 time, + gint cpu, + GPid pid, + guint64 duration, + const gchar *name, + const gchar *message); guint64 sp_capture_writer_add_jitmap (SpCaptureWriter *self, const gchar *name); gboolean sp_capture_writer_add_process (SpCaptureWriter *self, diff --git a/tests/test-capture.c b/tests/test-capture.c index 236d875d..ecc88ad5 100644 --- a/tests/test-capture.c +++ b/tests/test-capture.c @@ -531,6 +531,51 @@ test_reader_splice (void) g_unlink ("writer3.syscap"); } +static void +test_reader_writer_mark (void) +{ + SpCaptureWriter *writer; + SpCaptureReader *reader; + const SpCaptureMark *mark; + SpCaptureFrameType type; + GError *error = NULL; + gint r; + + writer = sp_capture_writer_new ("mark1.syscap", 0); + + sp_capture_writer_add_mark (writer, SP_CAPTURE_CURRENT_TIME, -1, -1, 125, "Draw", "hdmi-1"); + sp_capture_writer_add_mark (writer, SP_CAPTURE_CURRENT_TIME, -1, -1, 0, "Deadline", "hdmi-1"); + + g_clear_pointer (&writer, sp_capture_writer_unref); + + reader = sp_capture_reader_new ("mark1.syscap", &error); + g_assert_no_error (error); + g_assert (reader != NULL); + + mark = sp_capture_reader_read_mark (reader); + g_assert_nonnull (mark); + g_assert_cmpstr (mark->name, ==, "Draw"); + g_assert_cmpint (mark->duration, ==, 125); + g_assert_cmpstr (mark->message, ==, "hdmi-1"); + g_assert_cmpint (mark->frame.time, >, 0); + g_assert_cmpint (mark->frame.cpu, ==, -1); + + mark = sp_capture_reader_read_mark (reader); + g_assert_nonnull (mark); + g_assert_cmpstr (mark->name, ==, "Deadline"); + g_assert_cmpint (mark->duration, ==, 0); + g_assert_cmpstr (mark->message, ==, "hdmi-1"); + g_assert_cmpint (mark->frame.time, >, 0); + g_assert_cmpint (mark->frame.cpu, ==, -1); + + r = sp_capture_reader_peek_type (reader, &type); + g_assert_cmpint (r, ==, FALSE); + + g_clear_pointer (&reader, sp_capture_reader_unref); + + g_unlink ("mark1.syscap"); +} + int main (int argc, char *argv[]) @@ -540,5 +585,6 @@ main (int argc, g_test_add_func ("/SpCapture/ReaderWriter", test_reader_basic); g_test_add_func ("/SpCapture/Writer/splice", test_writer_splice); g_test_add_func ("/SpCapture/Reader/splice", test_reader_splice); + g_test_add_func ("/SpCapture/ReaderWriter/mark", test_reader_writer_mark); return g_test_run (); } diff --git a/tools/sysprof-dump.c b/tools/sysprof-dump.c index 2fdb4351..e6a87cd0 100644 --- a/tools/sysprof-dump.c +++ b/tools/sysprof-dump.c @@ -115,6 +115,20 @@ main (gint argc, break; } + case SP_CAPTURE_FRAME_MARK: + { + const SpCaptureMark *mark = sp_capture_reader_read_mark (reader); + + g_print ("MARK: pid=%d time=%"G_GINT64_FORMAT"\n" + " name = %s\n" + " duration = %"G_GUINT64_FORMAT"\n" + " message = %s\n", + mark->frame.pid, mark->frame.time, + mark->name, mark->duration, mark->message); + + break; + } + case SP_CAPTURE_FRAME_PROCESS: { const SpCaptureProcess *pr = sp_capture_reader_read_process (reader);