From nobody Sat Apr 11 06:30:42 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 06100C282E7 for ; Mon, 15 Aug 2022 20:32:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1347533AbiHOUbT (ORCPT ); Mon, 15 Aug 2022 16:31:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49434 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347109AbiHOUX3 (ORCPT ); Mon, 15 Aug 2022 16:23:29 -0400 Received: from mail-pl1-x631.google.com (mail-pl1-x631.google.com [IPv6:2607:f8b0:4864:20::631]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0CBE14BD01; Mon, 15 Aug 2022 12:02:48 -0700 (PDT) Received: by mail-pl1-x631.google.com with SMTP id z19so7153916plb.1; Mon, 15 Aug 2022 12:02:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:from:to:cc; bh=eGwWLAV+VmdnzL2DzlRl4cqZkvkUk0pyXNIXElL51oM=; b=J/lvfr3edKFmTE604ZrQ7c46BPEPDrQKT6POvbxYhQTGKf2baJhUBrNqQfEkBLsqdc TgJ7BiBQTb3owvJ6CiWD6ROAXyvRIurtJIQwkM2cuZWotTw2iDFP0FAiVLw7Tzr8NIG8 pvnuQfBhV1H9PEy+8he0i7Zh/WPiwPTPdwrO69CT6ANnLKxY7SGWhXkk8wpv4jrI1xC/ 35Lr9JrCPzOYxOJtg6t5AILyWhQZYM4YN3F6QcTRKceC3R1saINrFc6xsvk0k3y5+klO scUx+HQquIZAhb91/vt6XvoU7WNvZ/xStfKf7SNPZe4Bn9yCBSDZAKoTTEEAcKSff9OU H9qA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:x-gm-message-state:from :to:cc; bh=eGwWLAV+VmdnzL2DzlRl4cqZkvkUk0pyXNIXElL51oM=; b=fOYCsm5W42ChTZGkB9MYqMFI1FuYSFOpnfg64FOexc4Mbba37arQrT2aIozsGRnqdz 7Vqr3vi1VOsr+9fAUUcAp887nDminOkOsj/4VbFWl385qBya4m9JKKAJrZ3rMcBWjVNT WSH0w6EiahhMyS3BRH0ppbQXnlSRyJIDibOfwUhrsopGQBUT/GF1ZQtid/6rBCOHN20x QQ8581086/VcexbrVzVL7vgbmGR7RI+RKG117ZuPTcVPDkk8nAdLZy9z7MyvspEA+45T Hfm91mA2wPjSzAvzUSqteZDAxSGd4sp0TW0ty0r5oubtbkvbkAka7RF5bvnp8WYcDvgR Fvtg== X-Gm-Message-State: ACgBeo1iVMQt7QsbPSCWUvNXBiJYyywwNmZiNc/kUYuj8/HfYVBY29QQ 4IIxDNhiPyCidGZ6QtFKCeo= X-Google-Smtp-Source: AA6agR6FsoK6jpHF+J6IYoYqVk42xSZCvYEAqxFRv568MP0hdMRmGFRKiEerc48b+ygoz4rlYkImEw== X-Received: by 2002:a17:902:b903:b0:170:9964:b47b with SMTP id bf3-20020a170902b90300b001709964b47bmr18023909plb.83.1660590167848; Mon, 15 Aug 2022 12:02:47 -0700 (PDT) Received: from youngsil.svl.corp.google.com ([2620:15c:2d4:203:df3e:22e0:b905:822b]) by smtp.gmail.com with ESMTPSA id q13-20020a170902a3cd00b0016a4db13429sm7266926plb.192.2022.08.15.12.02.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Aug 2022 12:02:46 -0700 (PDT) Sender: Namhyung Kim From: Namhyung Kim To: Arnaldo Carvalho de Melo , Jiri Olsa Cc: LKML , Ian Rogers , linux-perf-users@vger.kernel.org Subject: [PATCH 4/4] perf tools: Support reading PERF_FORMAT_LOST Date: Mon, 15 Aug 2022 12:01:06 -0700 Message-Id: <20220815190106.1293082-5-namhyung@kernel.org> X-Mailer: git-send-email 2.37.1.595.g718a3a8f04-goog In-Reply-To: <20220815190106.1293082-1-namhyung@kernel.org> References: <20220815190106.1293082-1-namhyung@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" 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 --- tools/perf/tests/sample-parsing.c | 14 +++++--- tools/perf/util/event.h | 18 +++++++++- tools/perf/util/evsel.c | 33 +++++++++++++----- .../scripting-engines/trace-event-python.c | 16 ++++++--- tools/perf/util/session.c | 32 +++++++++++------ tools/perf/util/synthetic-events.c | 34 +++++++++++++++---- 6 files changed, 112 insertions(+), 35 deletions(-) diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-pa= rsing.c index 07f2411b0ad4..20930dd48ee0 100644 --- a/tools/perf/tests/sample-parsing.c +++ b/tools/perf/tests/sample-parsing.c @@ -86,10 +86,15 @@ static bool samples_same(const struct perf_sample *s1, COMP(read.time_running); /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ if (read_format & PERF_FORMAT_GROUP) { - for (i =3D 0; i < s1->read.group.nr; i++) - MCOMP(read.group.values[i]); + for (i =3D 0; i < s1->read.group.nr; i++) { + /* FIXME: check values without LOST */ + if (read_format & PERF_FORMAT_LOST) + MCOMP(read.group.values[i]); + } } else { COMP(read.one.id); + if (read_format & PERF_FORMAT_LOST) + COMP(read.one.lost); } } =20 @@ -263,7 +268,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u6= 4 read_format) .data =3D (void *)aux_data, }, }; - struct sample_read_value values[] =3D {{1, 5}, {9, 3}, {2, 7}, {6, 4},}; + struct sample_read_value values[] =3D {{1, 5, 0}, {9, 3, 0}, {2, 7, 0}, {= 6, 4, 1},}; struct perf_sample sample_out, sample_out_endian; size_t i, sz, bufsz; int err, ret =3D -1; @@ -286,6 +291,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u6= 4 read_format) } else { sample.read.one.value =3D 0x08789faeb786aa87ULL; sample.read.one.id =3D 99; + sample.read.one.lost =3D 1; } =20 sz =3D perf_event__sample_event_size(&sample, sample_type, read_format); @@ -370,7 +376,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u6= 4 read_format) */ static int test__sample_parsing(struct test_suite *test __maybe_unused, in= t subtest __maybe_unused) { - const u64 rf[] =3D {4, 5, 6, 7, 12, 13, 14, 15}; + const u64 rf[] =3D {4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 28, 29, 30, 3= 1}; u64 sample_type; u64 sample_regs; size_t i; diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index a7b0931d5137..7753368d70d6 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -65,7 +65,8 @@ struct stack_dump { =20 struct sample_read_value { u64 value; - u64 id; + u64 id; /* only if PERF_FORMAT_ID */ + u64 lost; /* only if PERF_FORMAT_LOST */ }; =20 struct sample_read { @@ -80,6 +81,21 @@ struct sample_read { }; }; =20 +static inline size_t sample_read_value_size(u64 read_format) +{ + /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ + if (read_format & PERF_FORMAT_LOST) + return sizeof(struct sample_read_value); + else + return offsetof(struct sample_read_value, lost); +} + +static inline struct sample_read_value * +next_sample_read_value(struct sample_read_value *v, u64 read_format) +{ + return (void *)v + sample_read_value_size(read_format); +} + struct ip_callchain { u64 nr; u64 ips[]; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 4852089e1d79..781367ccdb84 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1541,7 +1541,7 @@ static int evsel__read_one(struct evsel *evsel, int c= pu_map_idx, int thread) } =20 static void evsel__set_count(struct evsel *counter, int cpu_map_idx, int t= hread, - u64 val, u64 ena, u64 run) + u64 val, u64 ena, u64 run, u64 lost) { struct perf_counts_values *count; =20 @@ -1550,6 +1550,7 @@ static void evsel__set_count(struct evsel *counter, i= nt cpu_map_idx, int thread, count->val =3D val; count->ena =3D ena; count->run =3D run; + count->lost =3D lost; =20 perf_counts__set_loaded(counter->counts, cpu_map_idx, thread, true); } @@ -1558,7 +1559,7 @@ static int evsel__process_group_data(struct evsel *le= ader, int cpu_map_idx, int { u64 read_format =3D leader->core.attr.read_format; struct sample_read_value *v; - u64 nr, ena =3D 0, run =3D 0, i; + u64 nr, ena =3D 0, run =3D 0, lost =3D 0, i; =20 nr =3D *data++; =20 @@ -1573,16 +1574,25 @@ static int evsel__process_group_data(struct evsel *= leader, int cpu_map_idx, int =20 v =3D (struct sample_read_value *) data; =20 - evsel__set_count(leader, cpu_map_idx, thread, v[0].value, ena, run); + if (read_format & PERF_FORMAT_LOST) + lost =3D v->lost; + + evsel__set_count(leader, cpu_map_idx, thread, v[0].value, ena, run, lost); + + v =3D next_sample_read_value(v, read_format); =20 for (i =3D 1; i < nr; i++) { struct evsel *counter; =20 - counter =3D evlist__id2evsel(leader->evlist, v[i].id); + counter =3D evlist__id2evsel(leader->evlist, v->id); if (!counter) return -EINVAL; =20 - evsel__set_count(counter, cpu_map_idx, thread, v[i].value, ena, run); + if (read_format & PERF_FORMAT_LOST) + lost =3D v->lost; + + evsel__set_count(counter, cpu_map_idx, thread, v->value, ena, run, lost); + v =3D next_sample_read_value(v, read_format); } =20 return 0; @@ -2475,16 +2485,21 @@ int evsel__parse_sample(struct evsel *evsel, union = perf_event *event, =20 if (data->read.group.nr > max_group_nr) return -EFAULT; - sz =3D data->read.group.nr * - sizeof(struct sample_read_value); + + sz =3D data->read.group.nr * sample_read_value_size(read_format); OVERFLOW_CHECK(array, sz, max_size); - data->read.group.values =3D - (struct sample_read_value *)array; + data->read.group.values =3D (void *)array; array =3D (void *)array + sz; } else { OVERFLOW_CHECK_u64(array); data->read.one.id =3D *array; array++; + + if (read_format & PERF_FORMAT_LOST) { + OVERFLOW_CHECK_u64(array); + data->read.one.lost =3D *array; + array++; + } } } =20 diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools= /perf/util/scripting-engines/trace-event-python.c index 9ef2406e0ede..7e15e64f311b 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -642,15 +642,19 @@ static PyObject *python_process_brstacksym(struct per= f_sample *sample, return pylist; } =20 -static PyObject *get_sample_value_as_tuple(struct sample_read_value *value) +static PyObject *get_sample_value_as_tuple(struct sample_read_value *value, + u64 read_format) { PyObject *t; =20 - t =3D PyTuple_New(2); + t =3D PyTuple_New(3); if (!t) Py_FatalError("couldn't create Python tuple"); PyTuple_SetItem(t, 0, PyLong_FromUnsignedLongLong(value->id)); PyTuple_SetItem(t, 1, PyLong_FromUnsignedLongLong(value->value)); + if (read_format & PERF_FORMAT_LOST) + PyTuple_SetItem(t, 2, PyLong_FromUnsignedLongLong(value->lost)); + return t; } =20 @@ -681,12 +685,16 @@ static void set_sample_read_in_dict(PyObject *dict_sa= mple, Py_FatalError("couldn't create Python list"); =20 if (read_format & PERF_FORMAT_GROUP) { + struct sample_read_value *v =3D sample->read.group.values; + for (i =3D 0; i < sample->read.group.nr; i++) { - PyObject *t =3D get_sample_value_as_tuple(&sample->read.group.values[i]= ); + PyObject *t =3D get_sample_value_as_tuple(v, read_format); PyList_SET_ITEM(values, i, t); + v =3D next_sample_read_value(v, read_format); } } else { - PyObject *t =3D get_sample_value_as_tuple(&sample->read.one); + PyObject *t =3D get_sample_value_as_tuple(&sample->read.one, + read_format); PyList_SET_ITEM(values, 0, t); } pydict_set_item_string_decref(dict_sample, "values", values); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 98e16659a149..dd818764bd4d 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1284,20 +1284,26 @@ static void sample_read__printf(struct perf_sample = *sample, u64 read_format) =20 if (read_format & PERF_FORMAT_GROUP) { u64 i; + struct sample_read_value *value =3D sample->read.group.values; =20 printf(".... group nr %" PRIu64 "\n", sample->read.group.nr); =20 for (i =3D 0; i < sample->read.group.nr; i++) { - struct sample_read_value *value; - - value =3D &sample->read.group.values[i]; printf("..... id %016" PRIx64 - ", value %016" PRIx64 "\n", + ", value %016" PRIx64, value->id, value->value); + if (read_format & PERF_FORMAT_LOST) + printf(", lost %" PRIu64, value->lost); + printf("\n"); + value =3D next_sample_read_value(value, read_format); } - } else - printf("..... id %016" PRIx64 ", value %016" PRIx64 "\n", + } else { + printf("..... id %016" PRIx64 ", value %016" PRIx64, sample->read.one.id, sample->read.one.value); + if (read_format & PERF_FORMAT_LOST) + printf(", lost %" PRIu64, sample->read.one.lost); + printf("\n"); + } } =20 static void dump_event(struct evlist *evlist, union perf_event *event, @@ -1411,6 +1417,9 @@ static void dump_read(struct evsel *evsel, union perf= _event *event) =20 if (read_format & PERF_FORMAT_ID) printf("... id : %" PRI_lu64 "\n", read_event->id); + + if (read_format & PERF_FORMAT_LOST) + printf("... lost : %" PRI_lu64 "\n", read_event->lost); } =20 static struct machine *machines__find_for_cpumode(struct machines *machine= s, @@ -1479,17 +1488,20 @@ static int deliver_sample_group(struct evlist *evli= st, struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct machine *machine) + struct machine *machine, + u64 read_format) { int ret =3D -EINVAL; u64 i; + struct sample_read_value *v =3D sample->read.group.values; =20 for (i =3D 0; i < sample->read.group.nr; i++) { - ret =3D deliver_sample_value(evlist, tool, event, sample, - &sample->read.group.values[i], + ret =3D deliver_sample_value(evlist, tool, event, sample, v, machine); if (ret) break; + + v =3D next_sample_read_value(v, read_format); } =20 return ret; @@ -1510,7 +1522,7 @@ static int evlist__deliver_sample(struct evlist *evli= st, struct perf_tool *tool, /* For PERF_SAMPLE_READ we have either single or group mode. */ if (read_format & PERF_FORMAT_GROUP) return deliver_sample_group(evlist, tool, event, sample, - machine); + machine, read_format); else return deliver_sample_value(evlist, tool, event, sample, &sample->read.one, machine); diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic= -events.c index 2ae59c03ae77..9b8dc7633a02 100644 --- a/tools/perf/util/synthetic-events.c +++ b/tools/perf/util/synthetic-events.c @@ -1432,11 +1432,12 @@ size_t perf_event__sample_event_size(const struct p= erf_sample *sample, u64 type, result +=3D sizeof(u64); /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ if (read_format & PERF_FORMAT_GROUP) { - sz =3D sample->read.group.nr * - sizeof(struct sample_read_value); - result +=3D sz; + sz =3D sample_read_value_size(read_format); + result +=3D sz * sample->read.group.nr; } else { result +=3D sizeof(u64); + if (read_format & PERF_FORMAT_LOST) + result +=3D sizeof(u64); } } =20 @@ -1521,6 +1522,22 @@ void __weak arch_perf_synthesize_sample_weight(const= struct perf_sample *data, *array =3D data->weight; } =20 +static __u64 *copy_read_group_values(__u64 *array, __u64 read_format, + const struct perf_sample *sample) +{ + size_t i, sz; + void *data =3D sample->read.group.values; + + sz =3D sample_read_value_size(read_format); + for (i =3D 0; i < sample->read.group.nr; i++) { + memcpy(array, data, sz); + + data +=3D sz; + array =3D (void *)array + sz; + } + return array; +} + int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 r= ead_format, const struct perf_sample *sample) { @@ -1602,13 +1619,16 @@ int perf_event__synthesize_sample(union perf_event = *event, u64 type, u64 read_fo =20 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ if (read_format & PERF_FORMAT_GROUP) { - sz =3D sample->read.group.nr * - sizeof(struct sample_read_value); - memcpy(array, sample->read.group.values, sz); - array =3D (void *)array + sz; + array =3D copy_read_group_values(array, read_format, + sample); } else { *array =3D sample->read.one.id; array++; + + if (read_format & PERF_FORMAT_LOST) { + *array =3D sample->read.one.lost; + array++; + } } } =20 --=20 2.37.1.595.g718a3a8f04-goog