libsysprof/sampler: track lost records as a counter/log

This makes it much easier to see what happened from the capture file which
may originate from a user different than the person inspecting it.
This commit is contained in:
Christian Hergert
2024-10-24 12:43:21 -07:00
parent 2838024227
commit c9a1b322cd

View File

@ -31,6 +31,8 @@ struct _SysprofSampler
{ {
SysprofInstrument parent_instance; SysprofInstrument parent_instance;
GPtrArray *perf_event_streams; GPtrArray *perf_event_streams;
guint sample_lost_counter_id;
gint64 lost_count;
}; };
struct _SysprofSamplerClass struct _SysprofSamplerClass
@ -38,8 +40,67 @@ struct _SysprofSamplerClass
SysprofInstrumentClass parent_class; SysprofInstrumentClass parent_class;
}; };
typedef struct
{
SysprofRecording *recording;
SysprofCaptureWriter *writer;
guint lost_counter_id;
gint64 lost;
} StreamData;
G_DEFINE_FINAL_TYPE (SysprofSampler, sysprof_sampler, SYSPROF_TYPE_INSTRUMENT) G_DEFINE_FINAL_TYPE (SysprofSampler, sysprof_sampler, SYSPROF_TYPE_INSTRUMENT)
static StreamData *
stream_data_new (SysprofRecording *recording)
{
SysprofCaptureCounter info = {0};
StreamData *data;
g_assert (SYSPROF_IS_RECORDING (recording));
data = g_atomic_rc_box_new0 (StreamData);
data->recording = g_object_ref (recording);
data->writer = sysprof_capture_writer_ref (_sysprof_recording_writer (recording));
data->lost_counter_id = sysprof_capture_writer_request_counter (data->writer, 1);
data->lost = 0;
g_strlcpy (info.category, "Sampler", sizeof info.category);
g_strlcpy (info.name, "Lost Samples", sizeof info.name);
g_strlcpy (info.description, "Samples dropped due to full ring buffer", sizeof info.description);
info.id = data->lost_counter_id;
info.type = SYSPROF_CAPTURE_COUNTER_INT64;
info.value.v64 = 0;
sysprof_capture_writer_define_counters (data->writer,
SYSPROF_CAPTURE_CURRENT_TIME, -1, -1,
&info, 1);
return data;
}
static StreamData *
stream_data_ref (StreamData *data)
{
return g_atomic_rc_box_acquire (data);
}
static void
stream_data_finalize (gpointer ptr)
{
StreamData *data = ptr;
g_clear_pointer (&data->writer, sysprof_capture_writer_unref);
g_clear_object (&data->recording);
}
static void
stream_data_unref (StreamData *data)
{
g_atomic_rc_box_release_full (data, stream_data_finalize);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (StreamData, stream_data_unref)
static char ** static char **
sysprof_sampler_list_required_policy (SysprofInstrument *instrument) sysprof_sampler_list_required_policy (SysprofInstrument *instrument)
{ {
@ -105,12 +166,13 @@ sysprof_sampler_perf_event_stream_cb (const SysprofPerfEvent *event,
guint cpu, guint cpu,
gpointer user_data) gpointer user_data)
{ {
SysprofRecording *recording = user_data; StreamData *data = user_data;
SysprofCaptureWriter *writer = _sysprof_recording_writer (recording); SysprofRecording *recording = data->recording;
SysprofCaptureWriter *writer = data->writer;
gsize offset; gsize offset;
gint64 time; gint64 time;
g_assert (writer != NULL); g_assert (data != NULL);
g_assert (event != NULL); g_assert (event != NULL);
switch (event->header.type) switch (event->header.type)
@ -157,7 +219,22 @@ sysprof_sampler_perf_event_stream_cb (const SysprofPerfEvent *event,
break; break;
case PERF_RECORD_LOST: case PERF_RECORD_LOST:
break; {
SysprofCaptureCounterValue value;
gint64 now = SYSPROF_CAPTURE_CURRENT_TIME;
char message[64];
g_snprintf (message, sizeof message,
"Lost %"G_GUINT64_FORMAT" samples",
event->lost.lost);
sysprof_capture_writer_add_log (writer, now, -1, -1, G_LOG_LEVEL_CRITICAL,
"Sampler", message);
value.v64 = (data->lost += event->lost.lost);
sysprof_capture_writer_set_counters (writer, now, -1, -1,
&data->lost_counter_id, &value, 1);
break;
}
case PERF_RECORD_MMAP: case PERF_RECORD_MMAP:
offset = strlen (event->mmap.filename) + 1; offset = strlen (event->mmap.filename) + 1;
@ -251,6 +328,7 @@ sysprof_sampler_prepare_fiber (gpointer user_data)
{ {
Prepare *prepare = user_data; Prepare *prepare = user_data;
g_autoptr(GDBusConnection) connection = NULL; g_autoptr(GDBusConnection) connection = NULL;
g_autoptr(StreamData) stream_data = NULL;
g_autoptr(GPtrArray) futures = NULL; g_autoptr(GPtrArray) futures = NULL;
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
struct perf_event_attr attr = {0}; struct perf_event_attr attr = {0};
@ -334,6 +412,7 @@ try_again:
/* Pipeline our request for n_cpu perf_event_open calls and then /* Pipeline our request for n_cpu perf_event_open calls and then
* await them all to complete. * await them all to complete.
*/ */
stream_data = stream_data_new (prepare->recording);
for (guint i = 0; i < n_cpu; i++) for (guint i = 0; i < n_cpu; i++)
g_ptr_array_add (futures, g_ptr_array_add (futures,
sysprof_perf_event_stream_new (connection, sysprof_perf_event_stream_new (connection,
@ -342,8 +421,8 @@ try_again:
-1, -1,
0, 0,
sysprof_sampler_perf_event_stream_cb, sysprof_sampler_perf_event_stream_cb,
g_object_ref (prepare->recording), stream_data_ref (stream_data),
g_object_unref)); (GDestroyNotify)stream_data_unref));
if (!dex_await (dex_future_allv ((DexFuture **)futures->pdata, futures->len), &error)) if (!dex_await (dex_future_allv ((DexFuture **)futures->pdata, futures->len), &error))
{ {