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.
This commit is contained in:
Christian Hergert
2018-05-14 17:15:57 +01:00
parent e6d5d2b70d
commit 4bdbf130b2
8 changed files with 173 additions and 0 deletions

View File

@ -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;

View File

@ -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)
{

View File

@ -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);

View File

@ -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,

View File

@ -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)

View File

@ -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,

View File

@ -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 ();
}

View File

@ -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);