Skip to content

Commit f52679b

Browse files
namhyungacmel
authored andcommitted
perf tools: Support reading PERF_FORMAT_LOST
The recent kernel added lost count can be read from either read(2) or ring buffer data with PERF_SAMPLE_READ. As it's a variable length data we need to access it according to the format info. But for perf tools use cases, PERF_FORMAT_ID is always set. So we can only check PERF_FORMAT_LOST bit to determine the data format. Add sample_read_value_size() and next_sample_read_value() helpers to make it a bit easier to access. Use them in all places where it reads the struct sample_read_value. 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 6d395a5 commit f52679b

File tree

6 files changed

+108
-42
lines changed

6 files changed

+108
-42
lines changed

tools/perf/tests/sample-parsing.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,15 @@ static bool samples_same(const struct perf_sample *s1,
8686
COMP(read.time_running);
8787
/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
8888
if (read_format & PERF_FORMAT_GROUP) {
89-
for (i = 0; i < s1->read.group.nr; i++)
90-
MCOMP(read.group.values[i]);
89+
for (i = 0; i < s1->read.group.nr; i++) {
90+
/* FIXME: check values without LOST */
91+
if (read_format & PERF_FORMAT_LOST)
92+
MCOMP(read.group.values[i]);
93+
}
9194
} else {
9295
COMP(read.one.id);
96+
if (read_format & PERF_FORMAT_LOST)
97+
COMP(read.one.lost);
9398
}
9499
}
95100

@@ -263,7 +268,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
263268
.data = (void *)aux_data,
264269
},
265270
};
266-
struct sample_read_value values[] = {{1, 5}, {9, 3}, {2, 7}, {6, 4},};
271+
struct sample_read_value values[] = {{1, 5, 0}, {9, 3, 0}, {2, 7, 0}, {6, 4, 1},};
267272
struct perf_sample sample_out, sample_out_endian;
268273
size_t i, sz, bufsz;
269274
int err, ret = -1;
@@ -286,6 +291,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
286291
} else {
287292
sample.read.one.value = 0x08789faeb786aa87ULL;
288293
sample.read.one.id = 99;
294+
sample.read.one.lost = 1;
289295
}
290296

291297
sz = perf_event__sample_event_size(&sample, sample_type, read_format);
@@ -370,7 +376,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
370376
*/
371377
static int test__sample_parsing(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
372378
{
373-
const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
379+
const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 28, 29, 30, 31};
374380
u64 sample_type;
375381
u64 sample_regs;
376382
size_t i;

tools/perf/util/event.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ struct stack_dump {
6565

6666
struct sample_read_value {
6767
u64 value;
68-
u64 id;
68+
u64 id; /* only if PERF_FORMAT_ID */
69+
u64 lost; /* only if PERF_FORMAT_LOST */
6970
};
7071

7172
struct sample_read {
@@ -80,6 +81,24 @@ struct sample_read {
8081
};
8182
};
8283

84+
static inline size_t sample_read_value_size(u64 read_format)
85+
{
86+
/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
87+
if (read_format & PERF_FORMAT_LOST)
88+
return sizeof(struct sample_read_value);
89+
else
90+
return offsetof(struct sample_read_value, lost);
91+
}
92+
93+
static inline struct sample_read_value *
94+
next_sample_read_value(struct sample_read_value *v, u64 read_format)
95+
{
96+
return (void *)v + sample_read_value_size(read_format);
97+
}
98+
99+
#define sample_read_group__for_each(v, nr, rf) \
100+
for (int __i = 0; __i < (int)nr; v = next_sample_read_value(v, rf), __i++)
101+
83102
struct ip_callchain {
84103
u64 nr;
85104
u64 ips[];

tools/perf/util/evsel.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,7 +1541,7 @@ static int evsel__read_one(struct evsel *evsel, int cpu_map_idx, int thread)
15411541
}
15421542

15431543
static void evsel__set_count(struct evsel *counter, int cpu_map_idx, int thread,
1544-
u64 val, u64 ena, u64 run)
1544+
u64 val, u64 ena, u64 run, u64 lost)
15451545
{
15461546
struct perf_counts_values *count;
15471547

@@ -1550,6 +1550,7 @@ static void evsel__set_count(struct evsel *counter, int cpu_map_idx, int thread,
15501550
count->val = val;
15511551
count->ena = ena;
15521552
count->run = run;
1553+
count->lost = lost;
15531554

15541555
perf_counts__set_loaded(counter->counts, cpu_map_idx, thread, true);
15551556
}
@@ -1558,7 +1559,7 @@ static int evsel__process_group_data(struct evsel *leader, int cpu_map_idx, int
15581559
{
15591560
u64 read_format = leader->core.attr.read_format;
15601561
struct sample_read_value *v;
1561-
u64 nr, ena = 0, run = 0, i;
1562+
u64 nr, ena = 0, run = 0, lost = 0;
15621563

15631564
nr = *data++;
15641565

@@ -1571,18 +1572,18 @@ static int evsel__process_group_data(struct evsel *leader, int cpu_map_idx, int
15711572
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
15721573
run = *data++;
15731574

1574-
v = (struct sample_read_value *) data;
1575-
1576-
evsel__set_count(leader, cpu_map_idx, thread, v[0].value, ena, run);
1577-
1578-
for (i = 1; i < nr; i++) {
1575+
v = (void *)data;
1576+
sample_read_group__for_each(v, nr, read_format) {
15791577
struct evsel *counter;
15801578

1581-
counter = evlist__id2evsel(leader->evlist, v[i].id);
1579+
counter = evlist__id2evsel(leader->evlist, v->id);
15821580
if (!counter)
15831581
return -EINVAL;
15841582

1585-
evsel__set_count(counter, cpu_map_idx, thread, v[i].value, ena, run);
1583+
if (read_format & PERF_FORMAT_LOST)
1584+
lost = v->lost;
1585+
1586+
evsel__set_count(counter, cpu_map_idx, thread, v->value, ena, run, lost);
15861587
}
15871588

15881589
return 0;
@@ -2475,8 +2476,8 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,
24752476

24762477
if (data->read.group.nr > max_group_nr)
24772478
return -EFAULT;
2478-
sz = data->read.group.nr *
2479-
sizeof(struct sample_read_value);
2479+
2480+
sz = data->read.group.nr * sample_read_value_size(read_format);
24802481
OVERFLOW_CHECK(array, sz, max_size);
24812482
data->read.group.values =
24822483
(struct sample_read_value *)array;
@@ -2485,6 +2486,12 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,
24852486
OVERFLOW_CHECK_u64(array);
24862487
data->read.one.id = *array;
24872488
array++;
2489+
2490+
if (read_format & PERF_FORMAT_LOST) {
2491+
OVERFLOW_CHECK_u64(array);
2492+
data->read.one.lost = *array;
2493+
array++;
2494+
}
24882495
}
24892496
}
24902497

tools/perf/util/scripting-engines/trace-event-python.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -642,15 +642,19 @@ static PyObject *python_process_brstacksym(struct perf_sample *sample,
642642
return pylist;
643643
}
644644

645-
static PyObject *get_sample_value_as_tuple(struct sample_read_value *value)
645+
static PyObject *get_sample_value_as_tuple(struct sample_read_value *value,
646+
u64 read_format)
646647
{
647648
PyObject *t;
648649

649-
t = PyTuple_New(2);
650+
t = PyTuple_New(3);
650651
if (!t)
651652
Py_FatalError("couldn't create Python tuple");
652653
PyTuple_SetItem(t, 0, PyLong_FromUnsignedLongLong(value->id));
653654
PyTuple_SetItem(t, 1, PyLong_FromUnsignedLongLong(value->value));
655+
if (read_format & PERF_FORMAT_LOST)
656+
PyTuple_SetItem(t, 2, PyLong_FromUnsignedLongLong(value->lost));
657+
654658
return t;
655659
}
656660

@@ -681,12 +685,17 @@ static void set_sample_read_in_dict(PyObject *dict_sample,
681685
Py_FatalError("couldn't create Python list");
682686

683687
if (read_format & PERF_FORMAT_GROUP) {
684-
for (i = 0; i < sample->read.group.nr; i++) {
685-
PyObject *t = get_sample_value_as_tuple(&sample->read.group.values[i]);
688+
struct sample_read_value *v = sample->read.group.values;
689+
690+
i = 0;
691+
sample_read_group__for_each(v, sample->read.group.nr, read_format) {
692+
PyObject *t = get_sample_value_as_tuple(v, read_format);
686693
PyList_SET_ITEM(values, i, t);
694+
i++;
687695
}
688696
} else {
689-
PyObject *t = get_sample_value_as_tuple(&sample->read.one);
697+
PyObject *t = get_sample_value_as_tuple(&sample->read.one,
698+
read_format);
690699
PyList_SET_ITEM(values, 0, t);
691700
}
692701
pydict_set_item_string_decref(dict_sample, "values", values);

tools/perf/util/session.c

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,21 +1283,25 @@ static void sample_read__printf(struct perf_sample *sample, u64 read_format)
12831283
sample->read.time_running);
12841284

12851285
if (read_format & PERF_FORMAT_GROUP) {
1286-
u64 i;
1286+
struct sample_read_value *value = sample->read.group.values;
12871287

12881288
printf(".... group nr %" PRIu64 "\n", sample->read.group.nr);
12891289

1290-
for (i = 0; i < sample->read.group.nr; i++) {
1291-
struct sample_read_value *value;
1292-
1293-
value = &sample->read.group.values[i];
1290+
sample_read_group__for_each(value, sample->read.group.nr, read_format) {
12941291
printf("..... id %016" PRIx64
1295-
", value %016" PRIx64 "\n",
1292+
", value %016" PRIx64,
12961293
value->id, value->value);
1294+
if (read_format & PERF_FORMAT_LOST)
1295+
printf(", lost %" PRIu64, value->lost);
1296+
printf("\n");
12971297
}
1298-
} else
1299-
printf("..... id %016" PRIx64 ", value %016" PRIx64 "\n",
1298+
} else {
1299+
printf("..... id %016" PRIx64 ", value %016" PRIx64,
13001300
sample->read.one.id, sample->read.one.value);
1301+
if (read_format & PERF_FORMAT_LOST)
1302+
printf(", lost %" PRIu64, sample->read.one.lost);
1303+
printf("\n");
1304+
}
13011305
}
13021306

13031307
static void dump_event(struct evlist *evlist, union perf_event *event,
@@ -1411,6 +1415,9 @@ static void dump_read(struct evsel *evsel, union perf_event *event)
14111415

14121416
if (read_format & PERF_FORMAT_ID)
14131417
printf("... id : %" PRI_lu64 "\n", read_event->id);
1418+
1419+
if (read_format & PERF_FORMAT_LOST)
1420+
printf("... lost : %" PRI_lu64 "\n", read_event->lost);
14141421
}
14151422

14161423
static struct machine *machines__find_for_cpumode(struct machines *machines,
@@ -1479,14 +1486,14 @@ static int deliver_sample_group(struct evlist *evlist,
14791486
struct perf_tool *tool,
14801487
union perf_event *event,
14811488
struct perf_sample *sample,
1482-
struct machine *machine)
1489+
struct machine *machine,
1490+
u64 read_format)
14831491
{
14841492
int ret = -EINVAL;
1485-
u64 i;
1493+
struct sample_read_value *v = sample->read.group.values;
14861494

1487-
for (i = 0; i < sample->read.group.nr; i++) {
1488-
ret = deliver_sample_value(evlist, tool, event, sample,
1489-
&sample->read.group.values[i],
1495+
sample_read_group__for_each(v, sample->read.group.nr, read_format) {
1496+
ret = deliver_sample_value(evlist, tool, event, sample, v,
14901497
machine);
14911498
if (ret)
14921499
break;
@@ -1510,7 +1517,7 @@ static int evlist__deliver_sample(struct evlist *evlist, struct perf_tool *tool,
15101517
/* For PERF_SAMPLE_READ we have either single or group mode. */
15111518
if (read_format & PERF_FORMAT_GROUP)
15121519
return deliver_sample_group(evlist, tool, event, sample,
1513-
machine);
1520+
machine, read_format);
15141521
else
15151522
return deliver_sample_value(evlist, tool, event, sample,
15161523
&sample->read.one, machine);

tools/perf/util/synthetic-events.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,11 +1429,12 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
14291429
result += sizeof(u64);
14301430
/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
14311431
if (read_format & PERF_FORMAT_GROUP) {
1432-
sz = sample->read.group.nr *
1433-
sizeof(struct sample_read_value);
1434-
result += sz;
1432+
sz = sample_read_value_size(read_format);
1433+
result += sz * sample->read.group.nr;
14351434
} else {
14361435
result += sizeof(u64);
1436+
if (read_format & PERF_FORMAT_LOST)
1437+
result += sizeof(u64);
14371438
}
14381439
}
14391440

@@ -1518,6 +1519,20 @@ void __weak arch_perf_synthesize_sample_weight(const struct perf_sample *data,
15181519
*array = data->weight;
15191520
}
15201521

1522+
static __u64 *copy_read_group_values(__u64 *array, __u64 read_format,
1523+
const struct perf_sample *sample)
1524+
{
1525+
size_t sz = sample_read_value_size(read_format);
1526+
struct sample_read_value *v = sample->read.group.values;
1527+
1528+
sample_read_group__for_each(v, sample->read.group.nr, read_format) {
1529+
/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
1530+
memcpy(array, v, sz);
1531+
array = (void *)array + sz;
1532+
}
1533+
return array;
1534+
}
1535+
15211536
int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format,
15221537
const struct perf_sample *sample)
15231538
{
@@ -1599,13 +1614,16 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_fo
15991614

16001615
/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
16011616
if (read_format & PERF_FORMAT_GROUP) {
1602-
sz = sample->read.group.nr *
1603-
sizeof(struct sample_read_value);
1604-
memcpy(array, sample->read.group.values, sz);
1605-
array = (void *)array + sz;
1617+
array = copy_read_group_values(array, read_format,
1618+
sample);
16061619
} else {
16071620
*array = sample->read.one.id;
16081621
array++;
1622+
1623+
if (read_format & PERF_FORMAT_LOST) {
1624+
*array = sample->read.one.lost;
1625+
array++;
1626+
}
16091627
}
16101628
}
16111629

0 commit comments

Comments
 (0)