From 2197a0c02e5d7f7193e93f4688acf26606e28f88 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Tue, 27 Sep 2016 21:24:33 -0700 Subject: [PATCH] capture: add end time for captures Update the end time when we flush the buffer to disk. Also add a way to either incrementally get the end time or rely on the header when possible. --- lib/sp-capture-reader.c | 34 ++++++++++++++++++++++++++++++++++ lib/sp-capture-reader.h | 1 + lib/sp-capture-types.h | 3 ++- lib/sp-capture-writer.c | 22 ++++++++++++++++++++-- tests/test-capture.c | 8 ++++++++ 5 files changed, 65 insertions(+), 3 deletions(-) diff --git a/lib/sp-capture-reader.c b/lib/sp-capture-reader.c index 3c845d5f..e50971fd 100644 --- a/lib/sp-capture-reader.c +++ b/lib/sp-capture-reader.c @@ -39,6 +39,7 @@ struct _SpCaptureReader int fd; gint endian; SpCaptureFileHeader header; + gint64 end_time; }; #ifndef SP_DISABLE_GOBJECT @@ -297,6 +298,9 @@ sp_capture_reader_peek_frame (SpCaptureReader *self, sp_capture_reader_bswap_frame (self, frame); + if (frame->time > self->end_time) + self->end_time = frame->time; + return TRUE; } @@ -813,6 +817,36 @@ sp_capture_reader_get_start_time (SpCaptureReader *self) return self->header.time; } +/** + * sp_capture_reader_get_end_time: + * + * This function will return the end time for the capture, which is the + * same as the last event added to the capture. + * + * If the end time has been stored in the capture header, that will be used. + * Otherwise, the time is discovered from the last capture frame and therefore + * the caller must have read all frames to ensure this value is accurate. + * + * Captures created by sysprof versions containing this API will have the + * end time set if the output capture file-descriptor supports seeking. + * + * Since: 3.22.1 + */ +gint64 +sp_capture_reader_get_end_time (SpCaptureReader *self) +{ + g_return_val_if_fail (self != NULL, 0); + + if (self->header.end_time != 0) + { + if (self->endian != G_BYTE_ORDER) + return GUINT64_SWAP_LE_BE (self->header.end_time); + return self->header.end_time; + } + + return self->end_time; +} + /** * sp_capture_reader_copy: * diff --git a/lib/sp-capture-reader.h b/lib/sp-capture-reader.h index bf1d1521..8bf096e9 100644 --- a/lib/sp-capture-reader.h +++ b/lib/sp-capture-reader.h @@ -35,6 +35,7 @@ void sp_capture_reader_unref (SpCapt const gchar *sp_capture_reader_get_filename (SpCaptureReader *self); const gchar *sp_capture_reader_get_time (SpCaptureReader *self); gint64 sp_capture_reader_get_start_time (SpCaptureReader *self); +gint64 sp_capture_reader_get_end_time (SpCaptureReader *self); gboolean sp_capture_reader_skip (SpCaptureReader *self); gboolean sp_capture_reader_peek_type (SpCaptureReader *self, SpCaptureFrameType *type); diff --git a/lib/sp-capture-types.h b/lib/sp-capture-types.h index 65d6b690..94ed1ecf 100644 --- a/lib/sp-capture-types.h +++ b/lib/sp-capture-types.h @@ -78,7 +78,8 @@ typedef struct guint32 padding : 23; gchar capture_time[64]; gint64 time; - gchar suffix[176]; + gint64 end_time; + gchar suffix[168]; } SpCaptureFileHeader; typedef struct diff --git a/lib/sp-capture-writer.c b/lib/sp-capture-writer.c index 4570aea3..087d67bb 100644 --- a/lib/sp-capture-writer.c +++ b/lib/sp-capture-writer.c @@ -62,7 +62,6 @@ struct _SpCaptureWriter * alinged for the write buffer. This improves the performance of large * writes to the target file-descriptor. */ - volatile gint ref_count; /* @@ -397,6 +396,7 @@ sp_capture_writer_new_from_fd (int fd, header->padding = 0; g_strlcpy (header->capture_time, nowstr, sizeof header->capture_time); header->time = SP_CAPTURE_CURRENT_TIME; + header->end_time = 0; memset (header->suffix, 0, sizeof header->suffix); self->pos += sizeof *header; @@ -710,13 +710,31 @@ sp_capture_writer_add_timestamp (SpCaptureWriter *self, return TRUE; } +static gboolean +sp_capture_writer_flush_end_time (SpCaptureWriter *self) +{ + gint64 end_time = SP_CAPTURE_CURRENT_TIME; + + g_assert (self != NULL); + + /* This field is opportunistic, so a failure is okay. */ + + pwrite (self->fd, + &end_time, + sizeof (end_time), + G_STRUCT_OFFSET (SpCaptureFileHeader, end_time)); + + return TRUE; +} + gboolean sp_capture_writer_flush (SpCaptureWriter *self) { g_assert (self != NULL); return (sp_capture_writer_flush_jitmap (self) && - sp_capture_writer_flush_data (self)); + sp_capture_writer_flush_data (self) && + sp_capture_writer_flush_end_time (self)); } /** diff --git a/tests/test-capture.c b/tests/test-capture.c index 635dde11..80739c6d 100644 --- a/tests/test-capture.c +++ b/tests/test-capture.c @@ -50,6 +50,9 @@ test_reader_basic (void) sp_capture_writer_flush (writer); + /* We should have an old header (without end time) */ + g_assert_cmpint (0, ==, sp_capture_reader_get_end_time (reader)); + for (i = 0; i < 100; i++) { SpCaptureFrameType type = -1; @@ -75,6 +78,11 @@ test_reader_basic (void) g_assert_cmpstr (map->filename, ==, str); } + /* Now that we have read a frame, we should start having updated + * end times with each incoming frame. + */ + g_assert_cmpint (0, !=, sp_capture_reader_get_end_time (reader)); + for (i = 0; i < 100; i++) { r = sp_capture_writer_add_timestamp (writer, t, i, -1);