libsysprof-analyze: pre-sort frames during loading

That way we can be sure that we only have to look forward to find closing
pairs of operation (such as allocation/free, or appended capture data from
controlfd ring buffers).
This commit is contained in:
Christian Hergert
2023-07-06 10:19:55 -07:00
parent 9fd20c306f
commit 7f23fd5e9e

View File

@ -774,6 +774,80 @@ load_progress (Load *load,
load->progress (fraction, message, load->progress_data); load->progress (fraction, message, load->progress_data);
} }
static int
sort_by_time (gconstpointer a,
gconstpointer b,
gpointer base)
{
const SysprofDocumentFramePointer *aptr = a;
const SysprofDocumentFramePointer *bptr = b;
const SysprofCaptureFrame *aframe = (const SysprofCaptureFrame *)((const guint8 *)base + aptr->offset);
const SysprofCaptureFrame *bframe = (const SysprofCaptureFrame *)((const guint8 *)base + bptr->offset);
if (aframe->time < bframe->time)
return -1;
if (aframe->time > bframe->time)
return 1;
if (aframe->type == SYSPROF_CAPTURE_FRAME_MARK && bframe->type == SYSPROF_CAPTURE_FRAME_MARK)
{
const SysprofCaptureMark *amark = (const SysprofCaptureMark *)aframe;
const SysprofCaptureMark *bmark = (const SysprofCaptureMark *)bframe;
if (amark->duration > bmark->duration)
return -1;
else if (amark->duration < bmark->duration)
return 1;
}
return 0;
}
static int
sort_by_time_swapped (gconstpointer a,
gconstpointer b,
gpointer base)
{
const SysprofDocumentFramePointer *aptr = a;
const SysprofDocumentFramePointer *bptr = b;
const SysprofCaptureFrame *aframe = (const SysprofCaptureFrame *)((const guint8 *)base + aptr->offset);
const SysprofCaptureFrame *bframe = (const SysprofCaptureFrame *)((const guint8 *)base + bptr->offset);
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
gint64 atime = GINT64_FROM_BE (aframe->time);
gint64 btime = GINT64_FROM_BE (bframe->time);
#else
gint64 atime = GINT64_FROM_LE (aframe->time);
gint64 btime = GINT64_FROM_LE (bframe->time);
#endif
if (atime < btime)
return -1;
if (atime > btime)
return 1;
if (aframe->type == SYSPROF_CAPTURE_FRAME_MARK && bframe->type == SYSPROF_CAPTURE_FRAME_MARK)
{
const SysprofCaptureMark *amark = (const SysprofCaptureMark *)aframe;
const SysprofCaptureMark *bmark = (const SysprofCaptureMark *)bframe;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
gint64 aduration = GINT64_FROM_BE (amark->duration);
gint64 bduration = GINT64_FROM_BE (bmark->duration);
#else
gint64 aduration = GINT64_FROM_LE (amark->duration);
gint64 bduration = GINT64_FROM_LE (bmark->duration);
#endif
if (aduration > bduration)
return -1;
else if (aduration < bduration)
return 1;
}
return 0;
}
static void static void
sysprof_document_load_worker (GTask *task, sysprof_document_load_worker (GTask *task,
gpointer source_object, gpointer source_object,
@ -830,11 +904,8 @@ sysprof_document_load_worker (GTask *task,
pos = sizeof self->header; pos = sizeof self->header;
while (pos < (len - sizeof(guint16))) while (pos < (len - sizeof(guint16)))
{ {
const SysprofCaptureFrame *tainted;
SysprofDocumentFramePointer ptr; SysprofDocumentFramePointer ptr;
gint64 t;
guint16 frame_len; guint16 frame_len;
int pid;
memcpy (&frame_len, &self->base[pos], sizeof frame_len); memcpy (&frame_len, &self->base[pos], sizeof frame_len);
if (self->needs_swap) if (self->needs_swap)
@ -856,10 +927,32 @@ sysprof_document_load_worker (GTask *task,
ptr.offset = pos; ptr.offset = pos;
ptr.length = frame_len; ptr.length = frame_len;
tainted = (const SysprofCaptureFrame *)(gpointer)&self->base[pos]; pos += frame_len;
count++;
pid = self->needs_swap ? GUINT32_SWAP_LE_BE (tainted->pid) : tainted->pid; g_array_append_val (self->frames, ptr);
t = self->needs_swap ? GUINT64_SWAP_LE_BE (tainted->time) : tainted->time;
if (count % 100 == 0)
load_progress (load,
(pos / (double)len) * .4,
_("Indexing capture data frames"));
}
/* Now sort all the items by their respective frame times as frames
* cat into the writer may be tacked on at the end even though they
* have state which belongs earlier in the capture.
*/
if G_UNLIKELY (self->needs_swap)
g_array_sort_with_data (self->frames, sort_by_time_swapped, (gpointer)self->base);
else
g_array_sort_with_data (self->frames, sort_by_time, (gpointer)self->base);
for (guint f = 0; f < self->frames->len; f++)
{
SysprofDocumentFramePointer *ptr = &g_array_index (self->frames, SysprofDocumentFramePointer, f);
const SysprofCaptureFrame *tainted = (const SysprofCaptureFrame *)(gpointer)&self->base[ptr->offset];
gint64 t = self->needs_swap ? GUINT64_SWAP_LE_BE (tainted->time) : tainted->time;
int pid = self->needs_swap ? GUINT32_SWAP_LE_BE (tainted->pid) : tainted->pid;
if (t > guessed_end_nsec && is_data_type (tainted->type)) if (t > guessed_end_nsec && is_data_type (tainted->type))
guessed_end_nsec = t; guessed_end_nsec = t;
@ -869,45 +962,45 @@ sysprof_document_load_worker (GTask *task,
switch ((int)tainted->type) switch ((int)tainted->type)
{ {
case SYSPROF_CAPTURE_FRAME_ALLOCATION: case SYSPROF_CAPTURE_FRAME_ALLOCATION:
egg_bitset_add (self->allocations, self->frames->len); egg_bitset_add (self->allocations, f);
egg_bitset_add (self->traceables, self->frames->len); egg_bitset_add (self->traceables, f);
break; break;
case SYSPROF_CAPTURE_FRAME_SAMPLE: case SYSPROF_CAPTURE_FRAME_SAMPLE:
egg_bitset_add (self->samples, self->frames->len); egg_bitset_add (self->samples, f);
egg_bitset_add (self->traceables, self->frames->len); egg_bitset_add (self->traceables, f);
break; break;
case SYSPROF_CAPTURE_FRAME_PROCESS: case SYSPROF_CAPTURE_FRAME_PROCESS:
egg_bitset_add (self->processes, self->frames->len); egg_bitset_add (self->processes, f);
break; break;
case SYSPROF_CAPTURE_FRAME_FILE_CHUNK: case SYSPROF_CAPTURE_FRAME_FILE_CHUNK:
egg_bitset_add (self->file_chunks, self->frames->len); egg_bitset_add (self->file_chunks, f);
break; break;
case SYSPROF_CAPTURE_FRAME_CTRDEF: case SYSPROF_CAPTURE_FRAME_CTRDEF:
egg_bitset_add (self->ctrdefs, self->frames->len); egg_bitset_add (self->ctrdefs, f);
break; break;
case SYSPROF_CAPTURE_FRAME_CTRSET: case SYSPROF_CAPTURE_FRAME_CTRSET:
egg_bitset_add (self->ctrsets, self->frames->len); egg_bitset_add (self->ctrsets, f);
break; break;
case SYSPROF_CAPTURE_FRAME_MARK: case SYSPROF_CAPTURE_FRAME_MARK:
egg_bitset_add (self->marks, self->frames->len); egg_bitset_add (self->marks, f);
break; break;
case SYSPROF_CAPTURE_FRAME_JITMAP: case SYSPROF_CAPTURE_FRAME_JITMAP:
egg_bitset_add (self->jitmaps, self->frames->len); egg_bitset_add (self->jitmaps, f);
break; break;
case SYSPROF_CAPTURE_FRAME_MAP: case SYSPROF_CAPTURE_FRAME_MAP:
egg_bitset_add (self->mmaps, self->frames->len); egg_bitset_add (self->mmaps, f);
break; break;
case SYSPROF_CAPTURE_FRAME_OVERLAY: case SYSPROF_CAPTURE_FRAME_OVERLAY:
egg_bitset_add (self->overlays, self->frames->len); egg_bitset_add (self->overlays, f);
break; break;
default: default:
@ -922,13 +1015,13 @@ sysprof_document_load_worker (GTask *task,
!g_hash_table_contains (self->files_first_position, file_chunk->path)) !g_hash_table_contains (self->files_first_position, file_chunk->path))
g_hash_table_insert (self->files_first_position, g_hash_table_insert (self->files_first_position,
g_strdup (file_chunk->path), g_strdup (file_chunk->path),
GUINT_TO_POINTER (self->frames->len)); GUINT_TO_POINTER (f));
} }
else if (tainted->type == SYSPROF_CAPTURE_FRAME_SAMPLE) else if (tainted->type == SYSPROF_CAPTURE_FRAME_SAMPLE)
{ {
const SysprofCaptureSample *sample = (const SysprofCaptureSample *)tainted; const SysprofCaptureSample *sample = (const SysprofCaptureSample *)tainted;
guint n_addrs = self->needs_swap ? GUINT16_SWAP_LE_BE (sample->n_addrs) : sample->n_addrs; guint n_addrs = self->needs_swap ? GUINT16_SWAP_LE_BE (sample->n_addrs) : sample->n_addrs;
const guint8 *endptr = (const guint8 *)tainted + frame_len; const guint8 *endptr = (const guint8 *)tainted + ptr->length;
/* If the sample contains a context-switch, record it */ /* If the sample contains a context-switch, record it */
if ((const guint8 *)sample + (n_addrs * sizeof (SysprofAddress)) <= endptr) if ((const guint8 *)sample + (n_addrs * sizeof (SysprofAddress)) <= endptr)
@ -942,7 +1035,7 @@ sysprof_document_load_worker (GTask *task,
if (sysprof_address_is_context_switch (addr, &last_context) && if (sysprof_address_is_context_switch (addr, &last_context) &&
last_context == SYSPROF_ADDRESS_CONTEXT_KERNEL) last_context == SYSPROF_ADDRESS_CONTEXT_KERNEL)
{ {
egg_bitset_add (self->samples_with_context_switch, self->frames->len); egg_bitset_add (self->samples_with_context_switch, f);
break; break;
} }
} }
@ -951,7 +1044,7 @@ sysprof_document_load_worker (GTask *task,
else if (tainted->type == SYSPROF_CAPTURE_FRAME_MARK) else if (tainted->type == SYSPROF_CAPTURE_FRAME_MARK)
{ {
const SysprofCaptureMark *mark = (const SysprofCaptureMark *)tainted; const SysprofCaptureMark *mark = (const SysprofCaptureMark *)tainted;
const char *endptr = (const char *)tainted + frame_len; const char *endptr = (const char *)tainted + ptr->length;
gint64 duration = self->needs_swap ? GUINT64_SWAP_LE_BE (mark->duration) : mark->duration; gint64 duration = self->needs_swap ? GUINT64_SWAP_LE_BE (mark->duration) : mark->duration;
if (t + duration > guessed_end_nsec) if (t + duration > guessed_end_nsec)
@ -980,19 +1073,9 @@ sysprof_document_load_worker (GTask *task,
g_hash_table_insert (names, g_strdup (name), bitset); g_hash_table_insert (names, g_strdup (name), bitset);
} }
egg_bitset_add (bitset, self->frames->len); egg_bitset_add (bitset, f);
} }
} }
pos += frame_len;
count++;
g_array_append_val (self->frames, ptr);
if (count % 100 == 0)
load_progress (load,
(pos / (double)len) * .4,
_("Indexing capture data frames"));
} }
if (guessed_end_nsec != 0) if (guessed_end_nsec != 0)