[RFC PATCH 1/1] perf tools: Add 'm' event modifier for counting machine

From: Nikita Shubin
Date: Tue Jan 11 2022 - 09:21:15 EST


From: Nikita Shubin <n.shubin@xxxxxxxxx>

Adding 'm' event modifier for machine mode counting.

Any event specified with 'm', will set exclude_machine to zero.

Default behavior is setting exclude_machine to zero, unless kernel or
user specified explicitly.

Adding automated tests.

Signed-off-by: Nikita Shubin <n.shubin@xxxxxxxxx>
---
include/uapi/linux/perf_event.h | 3 ++-
tools/include/uapi/linux/perf_event.h | 3 ++-
tools/perf/Documentation/perf-list.txt | 1 +
tools/perf/tests/parse-events.c | 18 ++++++++++++++++++
tools/perf/util/evsel.c | 4 +++-
tools/perf/util/parse-events.c | 18 +++++++++++++-----
tools/perf/util/parse-events.l | 2 +-
7 files changed, 40 insertions(+), 9 deletions(-)

diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index bd8860eeb291..b70c245664eb 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -409,7 +409,8 @@ struct perf_event_attr {
inherit_thread : 1, /* children only inherit if cloned with CLONE_THREAD */
remove_on_exec : 1, /* event is removed from task on exec */
sigtrap : 1, /* send synchronous SIGTRAP on event */
- __reserved_1 : 26;
+ exclude_machine: 1, /* don't count M-Mode */
+ __reserved_1 : 25;

union {
__u32 wakeup_events; /* wakeup every n events */
diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
index bd8860eeb291..17f4d3ac10da 100644
--- a/tools/include/uapi/linux/perf_event.h
+++ b/tools/include/uapi/linux/perf_event.h
@@ -409,7 +409,8 @@ struct perf_event_attr {
inherit_thread : 1, /* children only inherit if cloned with CLONE_THREAD */
remove_on_exec : 1, /* event is removed from task on exec */
sigtrap : 1, /* send synchronous SIGTRAP on event */
- __reserved_1 : 26;
+ exclude_machine: 1, /* don't count events in M-Mode */
+ __reserved_1 : 25;

union {
__u32 wakeup_events; /* wakeup every n events */
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index 4dc8d0af19df..e6d10d95df70 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -53,6 +53,7 @@ counted. The following modifiers exist:

u - user-space counting
k - kernel counting
+ m - machine counting
h - hypervisor counting
I - non idle counting
G - guest counting (in KVM guests)
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index a508f1dbcb2a..617a66003648 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1323,6 +1323,19 @@ static int test__exclusive_group(struct evlist *evlist)

return 0;
}
+
+static int test__checkevent_exclude_machine_modifier(struct evlist *evlist)
+{
+ struct evsel *evsel = evlist__first(evlist);
+
+ TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_machine", !evsel->core.attr.exclude_machine);
+ TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
+
+ return test__checkevent_symbolic_name(evlist);
+}
+
static int test__checkevent_breakpoint_len(struct evlist *evlist)
{
struct evsel *evsel = evlist__first(evlist);
@@ -1943,6 +1956,11 @@ static struct evlist_test test__events[] = {
.check = test__exclusive_group,
.id = 57,
},
+ {
+ .name = "instructions:m",
+ .check = test__checkevent_exclude_machine_modifier,
+ .id = 58,
+ },
};

static struct evlist_test test__events_pmu[] = {
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index a59fb2ecb84e..a49c995908dc 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -542,9 +542,11 @@ static int evsel__add_modifiers(struct evsel *evsel, char *bf, size_t size)
r += scnprintf(bf + r, size - r, "%c", mod); \
} } while(0)

- if (attr->exclude_kernel || attr->exclude_user || attr->exclude_hv) {
+ if (attr->exclude_kernel || attr->exclude_user ||
+ attr->exclude_hv || attr->exclude_machine) {
MOD_PRINT(kernel, 'k');
MOD_PRINT(user, 'u');
+ MOD_PRINT(machine, 'm');
MOD_PRINT(hv, 'h');
exclude_guest_default = true;
}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5bfb6f892489..920397e1b959 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1867,6 +1867,7 @@ struct event_modifier {
int weak;
int exclusive;
int bpf_counter;
+ int em;
};

static int get_event_modifier(struct event_modifier *mod, char *str,
@@ -1874,6 +1875,7 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
{
int eu = evsel ? evsel->core.attr.exclude_user : 0;
int ek = evsel ? evsel->core.attr.exclude_kernel : 0;
+ int em = evsel ? evsel->core.attr.exclude_machine : 0;
int eh = evsel ? evsel->core.attr.exclude_hv : 0;
int eH = evsel ? evsel->core.attr.exclude_host : 0;
int eG = evsel ? evsel->core.attr.exclude_guest : 0;
@@ -1884,7 +1886,7 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
int pinned = evsel ? evsel->core.attr.pinned : 0;
int exclusive = evsel ? evsel->core.attr.exclusive : 0;

- int exclude = eu | ek | eh;
+ int exclude = eu | ek | eh | em;
int exclude_GH = evsel ? evsel->exclude_GH : 0;
int weak = 0;
int bpf_counter = 0;
@@ -1894,17 +1896,17 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
while (*str) {
if (*str == 'u') {
if (!exclude)
- exclude = eu = ek = eh = 1;
+ exclude = eu = ek = eh = em = 1;
if (!exclude_GH && !perf_guest)
eG = 1;
eu = 0;
} else if (*str == 'k') {
if (!exclude)
- exclude = eu = ek = eh = 1;
+ exclude = eu = ek = eh = em = 1;
ek = 0;
} else if (*str == 'h') {
if (!exclude)
- exclude = eu = ek = eh = 1;
+ exclude = eu = ek = eh = em = 1;
eh = 0;
} else if (*str == 'G') {
if (!exclude_GH)
@@ -1933,6 +1935,10 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
weak = 1;
} else if (*str == 'b') {
bpf_counter = 1;
+ } else if (*str == 'm') {
+ if (!exclude)
+ exclude = eu = ek = eh = em = 1;
+ em = 0;
} else
break;

@@ -1958,6 +1964,7 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
mod->eH = eH;
mod->eG = eG;
mod->eI = eI;
+ mod->em = em;
mod->precise = precise;
mod->precise_max = precise_max;
mod->exclude_GH = exclude_GH;
@@ -1979,7 +1986,7 @@ static int check_modifier(char *str)
char *p = str;

/* The sizeof includes 0 byte as well. */
- if (strlen(str) > (sizeof("ukhGHpppPSDIWeb") - 1))
+ if (strlen(str) > (sizeof("ukmhGHpppPSDIWeb") - 1))
return -1;

while (*p) {
@@ -2011,6 +2018,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add)

evsel->core.attr.exclude_user = mod.eu;
evsel->core.attr.exclude_kernel = mod.ek;
+ evsel->core.attr.exclude_machine= mod.em;
evsel->core.attr.exclude_hv = mod.eh;
evsel->core.attr.precise_ip = mod.precise;
evsel->core.attr.exclude_host = mod.eH;
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 4efe9872c667..5528a52611de 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -214,7 +214,7 @@ name_tag [\'][a-zA-Z_*?\[\]][a-zA-Z0-9_*?\-,\.\[\]:=]*[\']
name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.:]*
drv_cfg_term [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)?
/* If you add a modifier you need to update check_modifier() */
-modifier_event [ukhpPGHSDIWeb]+
+modifier_event [ukhpPGHSDIWebm]+
modifier_bp [rwx]{1,3}

%%
--
2.31.1