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.
This commit is contained in:
Christian Hergert
2016-09-27 21:24:33 -07:00
parent 4953731dd7
commit 2197a0c02e
5 changed files with 65 additions and 3 deletions

View File

@ -39,6 +39,7 @@ struct _SpCaptureReader
int fd; int fd;
gint endian; gint endian;
SpCaptureFileHeader header; SpCaptureFileHeader header;
gint64 end_time;
}; };
#ifndef SP_DISABLE_GOBJECT #ifndef SP_DISABLE_GOBJECT
@ -297,6 +298,9 @@ sp_capture_reader_peek_frame (SpCaptureReader *self,
sp_capture_reader_bswap_frame (self, frame); sp_capture_reader_bswap_frame (self, frame);
if (frame->time > self->end_time)
self->end_time = frame->time;
return TRUE; return TRUE;
} }
@ -813,6 +817,36 @@ sp_capture_reader_get_start_time (SpCaptureReader *self)
return self->header.time; 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: * sp_capture_reader_copy:
* *

View File

@ -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_filename (SpCaptureReader *self);
const gchar *sp_capture_reader_get_time (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_start_time (SpCaptureReader *self);
gint64 sp_capture_reader_get_end_time (SpCaptureReader *self);
gboolean sp_capture_reader_skip (SpCaptureReader *self); gboolean sp_capture_reader_skip (SpCaptureReader *self);
gboolean sp_capture_reader_peek_type (SpCaptureReader *self, gboolean sp_capture_reader_peek_type (SpCaptureReader *self,
SpCaptureFrameType *type); SpCaptureFrameType *type);

View File

@ -78,7 +78,8 @@ typedef struct
guint32 padding : 23; guint32 padding : 23;
gchar capture_time[64]; gchar capture_time[64];
gint64 time; gint64 time;
gchar suffix[176]; gint64 end_time;
gchar suffix[168];
} SpCaptureFileHeader; } SpCaptureFileHeader;
typedef struct typedef struct

View File

@ -62,7 +62,6 @@ struct _SpCaptureWriter
* alinged for the write buffer. This improves the performance of large * alinged for the write buffer. This improves the performance of large
* writes to the target file-descriptor. * writes to the target file-descriptor.
*/ */
volatile gint ref_count; volatile gint ref_count;
/* /*
@ -397,6 +396,7 @@ sp_capture_writer_new_from_fd (int fd,
header->padding = 0; header->padding = 0;
g_strlcpy (header->capture_time, nowstr, sizeof header->capture_time); g_strlcpy (header->capture_time, nowstr, sizeof header->capture_time);
header->time = SP_CAPTURE_CURRENT_TIME; header->time = SP_CAPTURE_CURRENT_TIME;
header->end_time = 0;
memset (header->suffix, 0, sizeof header->suffix); memset (header->suffix, 0, sizeof header->suffix);
self->pos += sizeof *header; self->pos += sizeof *header;
@ -710,13 +710,31 @@ sp_capture_writer_add_timestamp (SpCaptureWriter *self,
return TRUE; 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 gboolean
sp_capture_writer_flush (SpCaptureWriter *self) sp_capture_writer_flush (SpCaptureWriter *self)
{ {
g_assert (self != NULL); g_assert (self != NULL);
return (sp_capture_writer_flush_jitmap (self) && 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));
} }
/** /**

View File

@ -50,6 +50,9 @@ test_reader_basic (void)
sp_capture_writer_flush (writer); 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++) for (i = 0; i < 100; i++)
{ {
SpCaptureFrameType type = -1; SpCaptureFrameType type = -1;
@ -75,6 +78,11 @@ test_reader_basic (void)
g_assert_cmpstr (map->filename, ==, str); 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++) for (i = 0; i < 100; i++)
{ {
r = sp_capture_writer_add_timestamp (writer, t, i, -1); r = sp_capture_writer_add_timestamp (writer, t, i, -1);