Skip to content

Commit 89e3106

Browse files
namhyungacmel
authored andcommitted
libperf: Handle read format in perf_evsel__read()
The perf_counts_values should be increased to read the new lost data. Also adjust values after read according the read format. This supports PERF_FORMAT_GROUP which has a different data format but it's only available for leader events. Currently it doesn't have an API to read sibling (member) events in the group. But users may read the sibling event directly. Also reading from mmap would be disabled when the read format has ID or LOST bit as it's not exposed via mmap. Signed-off-by: Namhyung Kim <[email protected]> Acked-by: Jiri Olsa <[email protected]> Cc: Ian Rogers <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Peter Zijlstra <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 65ba872 commit 89e3106

File tree

3 files changed

+83
-3
lines changed

3 files changed

+83
-3
lines changed

tools/lib/perf/evsel.c

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,9 @@ int perf_evsel__read_size(struct perf_evsel *evsel)
305305
if (read_format & PERF_FORMAT_ID)
306306
entry += sizeof(u64);
307307

308+
if (read_format & PERF_FORMAT_LOST)
309+
entry += sizeof(u64);
310+
308311
if (read_format & PERF_FORMAT_GROUP) {
309312
nr = evsel->nr_members;
310313
size += sizeof(u64);
@@ -314,24 +317,98 @@ int perf_evsel__read_size(struct perf_evsel *evsel)
314317
return size;
315318
}
316319

320+
/* This only reads values for the leader */
321+
static int perf_evsel__read_group(struct perf_evsel *evsel, int cpu_map_idx,
322+
int thread, struct perf_counts_values *count)
323+
{
324+
size_t size = perf_evsel__read_size(evsel);
325+
int *fd = FD(evsel, cpu_map_idx, thread);
326+
u64 read_format = evsel->attr.read_format;
327+
u64 *data;
328+
int idx = 1;
329+
330+
if (fd == NULL || *fd < 0)
331+
return -EINVAL;
332+
333+
data = calloc(1, size);
334+
if (data == NULL)
335+
return -ENOMEM;
336+
337+
if (readn(*fd, data, size) <= 0) {
338+
free(data);
339+
return -errno;
340+
}
341+
342+
/*
343+
* This reads only the leader event intentionally since we don't have
344+
* perf counts values for sibling events.
345+
*/
346+
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
347+
count->ena = data[idx++];
348+
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
349+
count->run = data[idx++];
350+
351+
/* value is always available */
352+
count->val = data[idx++];
353+
if (read_format & PERF_FORMAT_ID)
354+
count->id = data[idx++];
355+
if (read_format & PERF_FORMAT_LOST)
356+
count->lost = data[idx++];
357+
358+
free(data);
359+
return 0;
360+
}
361+
362+
/*
363+
* The perf read format is very flexible. It needs to set the proper
364+
* values according to the read format.
365+
*/
366+
static void perf_evsel__adjust_values(struct perf_evsel *evsel, u64 *buf,
367+
struct perf_counts_values *count)
368+
{
369+
u64 read_format = evsel->attr.read_format;
370+
int n = 0;
371+
372+
count->val = buf[n++];
373+
374+
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
375+
count->ena = buf[n++];
376+
377+
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
378+
count->run = buf[n++];
379+
380+
if (read_format & PERF_FORMAT_ID)
381+
count->id = buf[n++];
382+
383+
if (read_format & PERF_FORMAT_LOST)
384+
count->lost = buf[n++];
385+
}
386+
317387
int perf_evsel__read(struct perf_evsel *evsel, int cpu_map_idx, int thread,
318388
struct perf_counts_values *count)
319389
{
320390
size_t size = perf_evsel__read_size(evsel);
321391
int *fd = FD(evsel, cpu_map_idx, thread);
392+
u64 read_format = evsel->attr.read_format;
393+
struct perf_counts_values buf;
322394

323395
memset(count, 0, sizeof(*count));
324396

325397
if (fd == NULL || *fd < 0)
326398
return -EINVAL;
327399

400+
if (read_format & PERF_FORMAT_GROUP)
401+
return perf_evsel__read_group(evsel, cpu_map_idx, thread, count);
402+
328403
if (MMAP(evsel, cpu_map_idx, thread) &&
404+
!(read_format & (PERF_FORMAT_ID | PERF_FORMAT_LOST)) &&
329405
!perf_mmap__read_self(MMAP(evsel, cpu_map_idx, thread), count))
330406
return 0;
331407

332-
if (readn(*fd, count->values, size) <= 0)
408+
if (readn(*fd, buf.values, size) <= 0)
333409
return -errno;
334410

411+
perf_evsel__adjust_values(evsel, buf.values, count);
335412
return 0;
336413
}
337414

tools/lib/perf/include/perf/event.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ struct perf_record_lost_samples {
7777
};
7878

7979
/*
80-
* PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID
80+
* PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID | PERF_FORMAT_LOST
8181
*/
8282
struct perf_record_read {
8383
struct perf_event_header header;
@@ -86,6 +86,7 @@ struct perf_record_read {
8686
__u64 time_enabled;
8787
__u64 time_running;
8888
__u64 id;
89+
__u64 lost;
8990
};
9091

9192
struct perf_record_throttle {

tools/lib/perf/include/perf/evsel.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ struct perf_counts_values {
1818
uint64_t val;
1919
uint64_t ena;
2020
uint64_t run;
21+
uint64_t id;
22+
uint64_t lost;
2123
};
22-
uint64_t values[3];
24+
uint64_t values[5];
2325
};
2426
};
2527

0 commit comments

Comments
 (0)