2024-04-15 06:36:42

by Ian Rogers

[permalink] [raw]
Subject: [PATCH v1 0/9] Consistently prefer sysfs/json events

As discussed in:
https://lore.kernel.org/lkml/[email protected]/
preferring sysfs/json events consistently (with or without a given
PMU) will enable RISC-V's hope to customize legacy events in the perf
tool.

Some minor clean-up is performed on the way.

Ian Rogers (9):
perf parse-events: Factor out '<event_or_pmu>/.../' parsing
perf parse-events: Directly pass PMU to parse_events_add_pmu
perf parse-events: Avoid copying an empty list
perf pmu: Refactor perf_pmu__match
perf tests parse-events: Use branches rather than cache-references
perf parse-events: Legacy cache names on all PMUs and lower priority
perf parse-events: Handle PE_TERM_HW in name_or_raw
perf parse-events: Constify parse_events_add_numeric
perf parse-events: Prefer sysfs/json hardware events over legacy

tools/perf/tests/parse-events.c | 6 +-
tools/perf/util/parse-events.c | 201 ++++++++++++++++++++++----------
tools/perf/util/parse-events.h | 16 +--
tools/perf/util/parse-events.l | 76 ++++++------
tools/perf/util/parse-events.y | 166 +++++++++-----------------
tools/perf/util/pmu.c | 27 +++--
tools/perf/util/pmu.h | 2 +-
7 files changed, 262 insertions(+), 232 deletions(-)

--
2.44.0.683.g7961c838ac-goog



2024-04-15 06:37:10

by Ian Rogers

[permalink] [raw]
Subject: [PATCH v1 1/9] perf parse-events: Factor out '<event_or_pmu>/.../' parsing

Factor out the case of an event or PMU name followed by a slash based
term list. This is with a view to sharing the code with new legacy
hardware parsing. Use early return to reduce indentation in the code.
Make parse_events_add_pmu static now it doesn't need sharing with
parse-events.y.

Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/util/parse-events.c | 69 +++++++++++++++++++++++++++++++-
tools/perf/util/parse-events.h | 10 +++--
tools/perf/util/parse-events.y | 73 +++-------------------------------
3 files changed, 80 insertions(+), 72 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 6f8b0fa17689..b16c75bf5580 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1385,7 +1385,7 @@ static bool config_term_percore(struct list_head *config_terms)
return false;
}

-int parse_events_add_pmu(struct parse_events_state *parse_state,
+static int parse_events_add_pmu(struct parse_events_state *parse_state,
struct list_head *list, const char *name,
const struct parse_events_terms *const_parsed_terms,
bool auto_merge_stats, void *loc_)
@@ -1618,6 +1618,73 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
return ok ? 0 : -1;
}

+int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state,
+ const char *event_or_pmu,
+ const struct parse_events_terms *const_parsed_terms,
+ struct list_head **listp,
+ void *loc_)
+{
+ char *pattern = NULL;
+ YYLTYPE *loc = loc_;
+ struct perf_pmu *pmu = NULL;
+ int ok = 0;
+ char *help;
+
+ *listp = malloc(sizeof(**listp));
+ if (!*listp)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(*listp);
+
+ /* Attempt to add to list assuming event_or_pmu is a PMU name. */
+ if (!parse_events_add_pmu(parse_state, *listp, event_or_pmu, const_parsed_terms,
+ /*auto_merge_stats=*/false, loc))
+ return 0;
+
+ /* Failed to add, try wildcard expansion of event_or_pmu as a PMU name. */
+ if (asprintf(&pattern, "%s*", event_or_pmu) < 0) {
+ zfree(listp);
+ return -ENOMEM;
+ }
+
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
+ const char *name = pmu->name;
+
+ if (parse_events__filter_pmu(parse_state, pmu))
+ continue;
+
+ if (!strncmp(name, "uncore_", 7) &&
+ strncmp(event_or_pmu, "uncore_", 7))
+ name += 7;
+ if (!perf_pmu__match(pattern, name, event_or_pmu) ||
+ !perf_pmu__match(pattern, pmu->alias_name, event_or_pmu)) {
+ bool auto_merge_stats = perf_pmu__auto_merge_stats(pmu);
+
+ if (!parse_events_add_pmu(parse_state, *listp, pmu->name, const_parsed_terms,
+ auto_merge_stats, loc)) {
+ ok++;
+ parse_state->wild_card_pmus = true;
+ }
+ }
+ }
+ zfree(&pattern);
+ if (ok)
+ return 0;
+
+ /* Failure to add, assume event_or_pmu is an event name. */
+ zfree(listp);
+ if (!parse_events_multi_pmu_add(parse_state, event_or_pmu, const_parsed_terms, listp, loc))
+ return 0;
+
+ if (asprintf(&help, "Unable to find PMU or event on a PMU of '%s'", event_or_pmu) < 0)
+ help = NULL;
+ parse_events_error__handle(parse_state->error, loc->first_column,
+ strdup("Bad event or PMU"),
+ help);
+ zfree(listp);
+ return -EINVAL;
+}
+
int parse_events__modifier_group(struct list_head *list,
char *event_mod)
{
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 809359e8544e..a331b9f0da2b 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -209,10 +209,6 @@ int parse_events_add_breakpoint(struct parse_events_state *parse_state,
struct list_head *list,
u64 addr, char *type, u64 len,
struct parse_events_terms *head_config);
-int parse_events_add_pmu(struct parse_events_state *parse_state,
- struct list_head *list, const char *name,
- const struct parse_events_terms *const_parsed_terms,
- bool auto_merge_stats, void *loc);

struct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr,
const char *name, const char *metric_id,
@@ -223,6 +219,12 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
const struct parse_events_terms *const_parsed_terms,
struct list_head **listp, void *loc);

+int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state,
+ const char *event_or_pmu,
+ const struct parse_events_terms *const_parsed_terms,
+ struct list_head **listp,
+ void *loc_);
+
void parse_events__set_leader(char *name, struct list_head *list);
void parse_events_update_lists(struct list_head *list_event,
struct list_head *list_all);
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index d70f5d84af92..14175eee9489 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -273,78 +273,17 @@ event_def: event_pmu |
event_pmu:
PE_NAME opt_pmu_config
{
- struct parse_events_state *parse_state = _parse_state;
/* List of created evsels. */
struct list_head *list = NULL;
- char *pattern = NULL;
-
-#define CLEANUP \
- do { \
- parse_events_terms__delete($2); \
- free(list); \
- free($1); \
- free(pattern); \
- } while(0)
+ int err = parse_events_multi_pmu_add_or_add_pmu(_parse_state, $1, $2, &list, &@1);

- list = alloc_list();
- if (!list) {
- CLEANUP;
+ parse_events_terms__delete($2);
+ free($1);
+ if (err == -ENOMEM)
YYNOMEM;
- }
- /* Attempt to add to list assuming $1 is a PMU name. */
- if (parse_events_add_pmu(parse_state, list, $1, $2, /*auto_merge_stats=*/false, &@1)) {
- struct perf_pmu *pmu = NULL;
- int ok = 0;
-
- /* Failure to add, try wildcard expansion of $1 as a PMU name. */
- if (asprintf(&pattern, "%s*", $1) < 0) {
- CLEANUP;
- YYNOMEM;
- }
-
- while ((pmu = perf_pmus__scan(pmu)) != NULL) {
- const char *name = pmu->name;
-
- if (parse_events__filter_pmu(parse_state, pmu))
- continue;
-
- if (!strncmp(name, "uncore_", 7) &&
- strncmp($1, "uncore_", 7))
- name += 7;
- if (!perf_pmu__match(pattern, name, $1) ||
- !perf_pmu__match(pattern, pmu->alias_name, $1)) {
- bool auto_merge_stats = perf_pmu__auto_merge_stats(pmu);
-
- if (!parse_events_add_pmu(parse_state, list, pmu->name, $2,
- auto_merge_stats, &@1)) {
- ok++;
- parse_state->wild_card_pmus = true;
- }
- }
- }
-
- if (!ok) {
- /* Failure to add, assume $1 is an event name. */
- zfree(&list);
- ok = !parse_events_multi_pmu_add(parse_state, $1, $2, &list, &@1);
- }
- if (!ok) {
- struct parse_events_error *error = parse_state->error;
- char *help;
-
- if (asprintf(&help, "Unable to find PMU or event on a PMU of '%s'", $1) < 0)
- help = NULL;
- parse_events_error__handle(error, @1.first_column,
- strdup("Bad event or PMU"),
- help);
- CLEANUP;
- YYABORT;
- }
- }
+ if (err)
+ YYABORT;
$$ = list;
- list = NULL;
- CLEANUP;
-#undef CLEANUP
}
|
PE_NAME sep_dc
--
2.44.0.683.g7961c838ac-goog


2024-04-15 06:37:17

by Ian Rogers

[permalink] [raw]
Subject: [PATCH v1 2/9] perf parse-events: Directly pass PMU to parse_events_add_pmu

Avoid passing the name of a PMU then finding it again, just directly
pass the PMU. parse_events_multi_pmu_add_or_add_pmu is the only
version that needs to find a PMU, so move the find there. Remove the
error message as parse_events_multi_pmu_add_or_add_pmu will given an
error at the end when a name isn't either a PMU name or event
name. Without the error message being created the location in the
input parameter (loc) can be removed.

Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/util/parse-events.c | 46 +++++++++++++---------------------
1 file changed, 17 insertions(+), 29 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index b16c75bf5580..bc4a5e3c6c21 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1386,32 +1386,18 @@ static bool config_term_percore(struct list_head *config_terms)
}

static int parse_events_add_pmu(struct parse_events_state *parse_state,
- struct list_head *list, const char *name,
- const struct parse_events_terms *const_parsed_terms,
- bool auto_merge_stats, void *loc_)
+ struct list_head *list, struct perf_pmu *pmu,
+ const struct parse_events_terms *const_parsed_terms,
+ bool auto_merge_stats)
{
struct perf_event_attr attr;
struct perf_pmu_info info;
- struct perf_pmu *pmu;
struct evsel *evsel;
struct parse_events_error *err = parse_state->error;
- YYLTYPE *loc = loc_;
LIST_HEAD(config_terms);
struct parse_events_terms parsed_terms;
bool alias_rewrote_terms = false;

- pmu = parse_state->fake_pmu ?: perf_pmus__find(name);
-
- if (!pmu) {
- char *err_str;
-
- if (asprintf(&err_str,
- "Cannot find PMU `%s'. Missing kernel support?",
- name) >= 0)
- parse_events_error__handle(err, loc->first_column, err_str, NULL);
- return -EINVAL;
- }
-
parse_events_terms__init(&parsed_terms);
if (const_parsed_terms) {
int ret = parse_events_terms__copy(const_parsed_terms, &parsed_terms);
@@ -1425,9 +1411,9 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,

strbuf_init(&sb, /*hint=*/ 0);
if (pmu->selectable && list_empty(&parsed_terms.terms)) {
- strbuf_addf(&sb, "%s//", name);
+ strbuf_addf(&sb, "%s//", pmu->name);
} else {
- strbuf_addf(&sb, "%s/", name);
+ strbuf_addf(&sb, "%s/", pmu->name);
parse_events_terms__to_strbuf(&parsed_terms, &sb);
strbuf_addch(&sb, '/');
}
@@ -1469,7 +1455,7 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,

strbuf_init(&sb, /*hint=*/ 0);
parse_events_terms__to_strbuf(&parsed_terms, &sb);
- fprintf(stderr, "..after resolving event: %s/%s/\n", name, sb.buf);
+ fprintf(stderr, "..after resolving event: %s/%s/\n", pmu->name, sb.buf);
strbuf_release(&sb);
}

@@ -1583,8 +1569,8 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
continue;

auto_merge_stats = perf_pmu__auto_merge_stats(pmu);
- if (!parse_events_add_pmu(parse_state, list, pmu->name,
- &parsed_terms, auto_merge_stats, loc)) {
+ if (!parse_events_add_pmu(parse_state, list, pmu,
+ &parsed_terms, auto_merge_stats)) {
struct strbuf sb;

strbuf_init(&sb, /*hint=*/ 0);
@@ -1596,8 +1582,8 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
}

if (parse_state->fake_pmu) {
- if (!parse_events_add_pmu(parse_state, list, event_name, &parsed_terms,
- /*auto_merge_stats=*/true, loc)) {
+ if (!parse_events_add_pmu(parse_state, list, parse_state->fake_pmu, &parsed_terms,
+ /*auto_merge_stats=*/true)) {
struct strbuf sb;

strbuf_init(&sb, /*hint=*/ 0);
@@ -1626,7 +1612,7 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state
{
char *pattern = NULL;
YYLTYPE *loc = loc_;
- struct perf_pmu *pmu = NULL;
+ struct perf_pmu *pmu;
int ok = 0;
char *help;

@@ -1637,10 +1623,12 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state
INIT_LIST_HEAD(*listp);

/* Attempt to add to list assuming event_or_pmu is a PMU name. */
- if (!parse_events_add_pmu(parse_state, *listp, event_or_pmu, const_parsed_terms,
- /*auto_merge_stats=*/false, loc))
+ pmu = parse_state->fake_pmu ?: perf_pmus__find(event_or_pmu);
+ if (pmu && !parse_events_add_pmu(parse_state, *listp, pmu, const_parsed_terms,
+ /*auto_merge_stats=*/false))
return 0;

+ pmu = NULL;
/* Failed to add, try wildcard expansion of event_or_pmu as a PMU name. */
if (asprintf(&pattern, "%s*", event_or_pmu) < 0) {
zfree(listp);
@@ -1660,8 +1648,8 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state
!perf_pmu__match(pattern, pmu->alias_name, event_or_pmu)) {
bool auto_merge_stats = perf_pmu__auto_merge_stats(pmu);

- if (!parse_events_add_pmu(parse_state, *listp, pmu->name, const_parsed_terms,
- auto_merge_stats, loc)) {
+ if (!parse_events_add_pmu(parse_state, *listp, pmu, const_parsed_terms,
+ auto_merge_stats)) {
ok++;
parse_state->wild_card_pmus = true;
}
--
2.44.0.683.g7961c838ac-goog


2024-04-15 06:37:29

by Ian Rogers

[permalink] [raw]
Subject: [PATCH v1 3/9] perf parse-events: Avoid copying an empty list

In parse_events_add_pmu, delay copying the list of terms until it is
known the list contains terms.

Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/util/parse-events.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index bc4a5e3c6c21..7e23168deeb9 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1398,29 +1398,20 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,
struct parse_events_terms parsed_terms;
bool alias_rewrote_terms = false;

- parse_events_terms__init(&parsed_terms);
- if (const_parsed_terms) {
- int ret = parse_events_terms__copy(const_parsed_terms, &parsed_terms);
-
- if (ret)
- return ret;
- }
-
if (verbose > 1) {
struct strbuf sb;

strbuf_init(&sb, /*hint=*/ 0);
- if (pmu->selectable && list_empty(&parsed_terms.terms)) {
+ if (pmu->selectable && const_parsed_terms && list_empty(&const_parsed_terms->terms)) {
strbuf_addf(&sb, "%s//", pmu->name);
} else {
strbuf_addf(&sb, "%s/", pmu->name);
- parse_events_terms__to_strbuf(&parsed_terms, &sb);
+ parse_events_terms__to_strbuf(const_parsed_terms, &sb);
strbuf_addch(&sb, '/');
}
fprintf(stderr, "Attempt to add: %s\n", sb.buf);
strbuf_release(&sb);
}
- fix_raw(&parsed_terms, pmu);

memset(&attr, 0, sizeof(attr));
if (pmu->perf_event_attr_init_default)
@@ -1428,7 +1419,7 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,

attr.type = pmu->type;

- if (list_empty(&parsed_terms.terms)) {
+ if (!const_parsed_terms || list_empty(&const_parsed_terms->terms)) {
evsel = __add_event(list, &parse_state->idx, &attr,
/*init_attr=*/true, /*name=*/NULL,
/*metric_id=*/NULL, pmu,
@@ -1437,6 +1428,15 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,
return evsel ? 0 : -ENOMEM;
}

+ parse_events_terms__init(&parsed_terms);
+ if (const_parsed_terms) {
+ int ret = parse_events_terms__copy(const_parsed_terms, &parsed_terms);
+
+ if (ret)
+ return ret;
+ }
+ fix_raw(&parsed_terms, pmu);
+
/* Configure attr/terms with a known PMU, this will set hardcoded terms. */
if (config_attr(&attr, &parsed_terms, parse_state->error, config_term_pmu)) {
parse_events_terms__exit(&parsed_terms);
--
2.44.0.683.g7961c838ac-goog


2024-04-15 06:37:55

by Ian Rogers

[permalink] [raw]
Subject: [PATCH v1 4/9] perf pmu: Refactor perf_pmu__match

Move all implementation to pmu code. Don't allocate a fnmatch wildcard
pattern, matching ignoring the suffix already handles this, and only
use fnmatch if the given PMU name has a '*' in it.

Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/util/parse-events.c | 19 ++-----------------
tools/perf/util/pmu.c | 27 +++++++++++++++++++--------
tools/perf/util/pmu.h | 2 +-
3 files changed, 22 insertions(+), 26 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 7e23168deeb9..f4de374dab59 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1610,7 +1610,6 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state
struct list_head **listp,
void *loc_)
{
- char *pattern = NULL;
YYLTYPE *loc = loc_;
struct perf_pmu *pmu;
int ok = 0;
@@ -1630,22 +1629,9 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state

pmu = NULL;
/* Failed to add, try wildcard expansion of event_or_pmu as a PMU name. */
- if (asprintf(&pattern, "%s*", event_or_pmu) < 0) {
- zfree(listp);
- return -ENOMEM;
- }
-
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
- const char *name = pmu->name;
-
- if (parse_events__filter_pmu(parse_state, pmu))
- continue;
-
- if (!strncmp(name, "uncore_", 7) &&
- strncmp(event_or_pmu, "uncore_", 7))
- name += 7;
- if (!perf_pmu__match(pattern, name, event_or_pmu) ||
- !perf_pmu__match(pattern, pmu->alias_name, event_or_pmu)) {
+ if (!parse_events__filter_pmu(parse_state, pmu) &&
+ perf_pmu__match(pmu, event_or_pmu)) {
bool auto_merge_stats = perf_pmu__auto_merge_stats(pmu);

if (!parse_events_add_pmu(parse_state, *listp, pmu, const_parsed_terms,
@@ -1655,7 +1641,6 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state
}
}
}
- zfree(&pattern);
if (ok)
return 0;

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index ce72c99e4f61..d7521d84fe4a 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -2073,18 +2073,29 @@ void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
name ?: "N/A", buf, config_name, config);
}

-int perf_pmu__match(const char *pattern, const char *name, const char *tok)
+bool perf_pmu__match(const struct perf_pmu *pmu, const char *tok)
{
- if (!name)
- return -1;
+ const char *name = pmu->name;
+ bool need_fnmatch = strchr(tok, '*') != NULL;

- if (fnmatch(pattern, name, 0))
- return -1;
+ if (!strncmp(tok, "uncore_", 7))
+ tok += 7;
+ if (!strncmp(name, "uncore_", 7))
+ name += 7;

- if (tok && !perf_pmu__match_ignoring_suffix(name, tok))
- return -1;
+ if (perf_pmu__match_ignoring_suffix(name, tok) ||
+ (need_fnmatch && !fnmatch(tok, name, 0)))
+ return true;

- return 0;
+ name = pmu->alias_name;
+ if (!name)
+ return false;
+
+ if (!strncmp(name, "uncore_", 7))
+ name += 7;
+
+ return perf_pmu__match_ignoring_suffix(name, tok) ||
+ (need_fnmatch && !fnmatch(tok, name, 0));
}

double __weak perf_pmu__cpu_slots_per_cycle(void)
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 152700f78455..93d03bd3ecbe 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -263,7 +263,7 @@ void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
const char *config_name);
void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu);

-int perf_pmu__match(const char *pattern, const char *name, const char *tok);
+bool perf_pmu__match(const struct perf_pmu *pmu, const char *tok);

double perf_pmu__cpu_slots_per_cycle(void);
int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size);
--
2.44.0.683.g7961c838ac-goog


2024-04-15 06:38:12

by Ian Rogers

[permalink] [raw]
Subject: [PATCH v1 5/9] perf tests parse-events: Use branches rather than cache-references

Switch from cache-references to branches in test as Intel has a sysfs
event for cache-references and changing the priority for sysfs over
legacy causes the test to fail.

Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/tests/parse-events.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 0b70451451b3..993e482f094c 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -942,8 +942,8 @@ static int test__group2(struct evlist *evlist)
continue;
}
if (evsel->core.attr.type == PERF_TYPE_HARDWARE &&
- test_config(evsel, PERF_COUNT_HW_CACHE_REFERENCES)) {
- /* cache-references + :u modifier */
+ test_config(evsel, PERF_COUNT_HW_BRANCH_INSTRUCTIONS)) {
+ /* branches + :u modifier */
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_hv", evsel->core.attr.exclude_hv);
@@ -2032,7 +2032,7 @@ static const struct evlist_test test__events[] = {
/* 8 */
},
{
- .name = "{faults:k,cache-references}:u,cycles:k",
+ .name = "{faults:k,branches}:u,cycles:k",
.check = test__group2,
/* 9 */
},
--
2.44.0.683.g7961c838ac-goog


2024-04-15 06:38:40

by Ian Rogers

[permalink] [raw]
Subject: [PATCH v1 6/9] perf parse-events: Legacy cache names on all PMUs and lower priority

Prior behavior is to not look for legacy cache names in sysfs/json and
to create events on all core PMUs. New behavior is to look for
sysfs/json events first on all PMUs, for core PMUs add a legacy event
if the sysfs/json event isn't present.

This is done so that there is consistency with how event names in
terms are handled and their prioritization of sysfs/json over
legacy. It may make sense to use a legacy cache event name as an event
name on a non-core PMU so we should allow it.

Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/util/parse-events.c | 38 +++++++++++++++++++++++++++-------
tools/perf/util/parse-events.h | 2 +-
2 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index f4de374dab59..f711ad9b18f0 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -442,17 +442,21 @@ bool parse_events__filter_pmu(const struct parse_events_state *parse_state,
return strcmp(parse_state->pmu_filter, pmu->name) != 0;
}

+static int parse_events_add_pmu(struct parse_events_state *parse_state,
+ struct list_head *list, struct perf_pmu *pmu,
+ const struct parse_events_terms *const_parsed_terms,
+ bool auto_merge_stats);
+
int parse_events_add_cache(struct list_head *list, int *idx, const char *name,
struct parse_events_state *parse_state,
- struct parse_events_terms *head_config)
+ struct parse_events_terms *parsed_terms)
{
struct perf_pmu *pmu = NULL;
bool found_supported = false;
- const char *config_name = get_config_name(head_config);
- const char *metric_id = get_config_metric_id(head_config);
+ const char *config_name = get_config_name(parsed_terms);
+ const char *metric_id = get_config_metric_id(parsed_terms);

- /* Legacy cache events are only supported by core PMUs. */
- while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
LIST_HEAD(config_terms);
struct perf_event_attr attr;
int ret;
@@ -460,6 +464,24 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name,
if (parse_events__filter_pmu(parse_state, pmu))
continue;

+ if (perf_pmu__have_event(pmu, name)) {
+ /*
+ * The PMU has the event so add as not a legacy cache
+ * event.
+ */
+ ret = parse_events_add_pmu(parse_state, list, pmu,
+ parsed_terms,
+ perf_pmu__auto_merge_stats(pmu));
+ if (ret)
+ return ret;
+ continue;
+ }
+
+ if (!pmu->is_core) {
+ /* Legacy cache events are only supported by core PMUs. */
+ continue;
+ }
+
memset(&attr, 0, sizeof(attr));
attr.type = PERF_TYPE_HW_CACHE;

@@ -469,11 +491,11 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name,

found_supported = true;

- if (head_config) {
- if (config_attr(&attr, head_config, parse_state->error, config_term_common))
+ if (parsed_terms) {
+ if (config_attr(&attr, parsed_terms, parse_state->error, config_term_common))
return -EINVAL;

- if (get_config_terms(head_config, &config_terms))
+ if (get_config_terms(parsed_terms, &config_terms))
return -ENOMEM;
}

diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index a331b9f0da2b..db47913e54bc 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -203,7 +203,7 @@ int parse_events_add_tool(struct parse_events_state *parse_state,
int tool_event);
int parse_events_add_cache(struct list_head *list, int *idx, const char *name,
struct parse_events_state *parse_state,
- struct parse_events_terms *head_config);
+ struct parse_events_terms *parsed_terms);
int parse_events__decode_legacy_cache(const char *name, int pmu_type, __u64 *config);
int parse_events_add_breakpoint(struct parse_events_state *parse_state,
struct list_head *list,
--
2.44.0.683.g7961c838ac-goog


2024-04-15 06:38:45

by Ian Rogers

[permalink] [raw]
Subject: [PATCH v1 7/9] perf parse-events: Handle PE_TERM_HW in name_or_raw

Avoid duplicate logic for name_or_raw and PE_TERM_HW by having a rule
to turn PE_TERM_HW into a name_or_raw.

Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/util/parse-events.y | 31 +++++--------------------------
1 file changed, 5 insertions(+), 26 deletions(-)

diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 14175eee9489..bb9bee5c8a2b 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -605,6 +605,11 @@ event_term
}

name_or_raw: PE_RAW | PE_NAME | PE_LEGACY_CACHE
+|
+PE_TERM_HW
+{
+ $$ = $1.str;
+}

event_term:
PE_RAW
@@ -646,20 +651,6 @@ name_or_raw '=' PE_VALUE
$$ = term;
}
|
-name_or_raw '=' PE_TERM_HW
-{
- struct parse_events_term *term;
- int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
- $1, $3.str, &@1, &@3);
-
- if (err) {
- free($1);
- free($3.str);
- PE_ABORT(err);
- }
- $$ = term;
-}
-|
PE_LEGACY_CACHE
{
struct parse_events_term *term;
@@ -712,18 +703,6 @@ PE_TERM '=' name_or_raw
$$ = term;
}
|
-PE_TERM '=' PE_TERM_HW
-{
- struct parse_events_term *term;
- int err = parse_events_term__str(&term, $1, /*config=*/NULL, $3.str, &@1, &@3);
-
- if (err) {
- free($3.str);
- PE_ABORT(err);
- }
- $$ = term;
-}
-|
PE_TERM '=' PE_TERM
{
struct parse_events_term *term;
--
2.44.0.683.g7961c838ac-goog


2024-04-15 06:39:08

by Ian Rogers

[permalink] [raw]
Subject: [PATCH v1 8/9] perf parse-events: Constify parse_events_add_numeric

Allow the term list to be const so that other functions can pass const
term lists. Add const as necessary to called functions.

Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/util/parse-events.c | 20 +++++++++++---------
tools/perf/util/parse-events.h | 2 +-
2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index f711ad9b18f0..50c4012c737e 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -34,7 +34,8 @@
#ifdef PARSER_DEBUG
extern int parse_events_debug;
#endif
-static int get_config_terms(struct parse_events_terms *head_config, struct list_head *head_terms);
+static int get_config_terms(const struct parse_events_terms *head_config,
+ struct list_head *head_terms);
static int parse_events_terms__copy(const struct parse_events_terms *src,
struct parse_events_terms *dest);

@@ -154,7 +155,7 @@ const char *event_type(int type)
return "unknown";
}

-static char *get_config_str(struct parse_events_terms *head_terms,
+static char *get_config_str(const struct parse_events_terms *head_terms,
enum parse_events__term_type type_term)
{
struct parse_events_term *term;
@@ -169,12 +170,12 @@ static char *get_config_str(struct parse_events_terms *head_terms,
return NULL;
}

-static char *get_config_metric_id(struct parse_events_terms *head_terms)
+static char *get_config_metric_id(const struct parse_events_terms *head_terms)
{
return get_config_str(head_terms, PARSE_EVENTS__TERM_TYPE_METRIC_ID);
}

-static char *get_config_name(struct parse_events_terms *head_terms)
+static char *get_config_name(const struct parse_events_terms *head_terms)
{
return get_config_str(head_terms, PARSE_EVENTS__TERM_TYPE_NAME);
}
@@ -358,7 +359,7 @@ static int config_term_common(struct perf_event_attr *attr,
struct parse_events_term *term,
struct parse_events_error *err);
static int config_attr(struct perf_event_attr *attr,
- struct parse_events_terms *head,
+ const struct parse_events_terms *head,
struct parse_events_error *err,
config_term_func_t config_term);

@@ -1107,7 +1108,7 @@ static int config_term_tracepoint(struct perf_event_attr *attr,
#endif

static int config_attr(struct perf_event_attr *attr,
- struct parse_events_terms *head,
+ const struct parse_events_terms *head,
struct parse_events_error *err,
config_term_func_t config_term)
{
@@ -1120,7 +1121,8 @@ static int config_attr(struct perf_event_attr *attr,
return 0;
}

-static int get_config_terms(struct parse_events_terms *head_config, struct list_head *head_terms)
+static int get_config_terms(const struct parse_events_terms *head_config,
+ struct list_head *head_terms)
{
#define ADD_CONFIG_TERM(__type, __weak) \
struct evsel_config_term *__t; \
@@ -1324,7 +1326,7 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
static int __parse_events_add_numeric(struct parse_events_state *parse_state,
struct list_head *list,
struct perf_pmu *pmu, u32 type, u32 extended_type,
- u64 config, struct parse_events_terms *head_config)
+ u64 config, const struct parse_events_terms *head_config)
{
struct perf_event_attr attr;
LIST_HEAD(config_terms);
@@ -1360,7 +1362,7 @@ static int __parse_events_add_numeric(struct parse_events_state *parse_state,
int parse_events_add_numeric(struct parse_events_state *parse_state,
struct list_head *list,
u32 type, u64 config,
- struct parse_events_terms *head_config,
+ const struct parse_events_terms *head_config,
bool wildcard)
{
struct perf_pmu *pmu = NULL;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index db47913e54bc..5005782766e9 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -196,7 +196,7 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
int parse_events_add_numeric(struct parse_events_state *parse_state,
struct list_head *list,
u32 type, u64 config,
- struct parse_events_terms *head_config,
+ const struct parse_events_terms *head_config,
bool wildcard);
int parse_events_add_tool(struct parse_events_state *parse_state,
struct list_head *list,
--
2.44.0.683.g7961c838ac-goog


2024-04-15 06:39:26

by Ian Rogers

[permalink] [raw]
Subject: [PATCH v1 9/9] perf parse-events: Prefer sysfs/json hardware events over legacy

It was requested that RISC-V be able to add events to the perf tool so
the PMU driver didn't need to map legacy events to config encodings:
https://lore.kernel.org/lkml/[email protected]/

This change makes the priority of events specified without a PMU the
same as those specified with a PMU, namely sysfs and json events are
checked first before using the legacy encoding.

The hw_term is made more generic as a hardware_event that encodes a
pair of string and int value, allowing parse_events_multi_pmu_add to
fall back on a known encoding when the sysfs/json adding fails for
core events. As this covers PE_VALUE_SYM_HW, that token is removed and
related code simplified.

Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/util/parse-events.c | 31 ++++++++++----
tools/perf/util/parse-events.h | 2 +-
tools/perf/util/parse-events.l | 76 +++++++++++++++++-----------------
tools/perf/util/parse-events.y | 62 +++++++++++++++++----------
4 files changed, 103 insertions(+), 68 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 50c4012c737e..71b0c5d518f1 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1541,7 +1541,7 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state,
}

int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
- const char *event_name,
+ const char *event_name, u64 hw_config,
const struct parse_events_terms *const_parsed_terms,
struct list_head **listp, void *loc_)
{
@@ -1549,8 +1549,8 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
struct list_head *list = NULL;
struct perf_pmu *pmu = NULL;
YYLTYPE *loc = loc_;
- int ok = 0;
- const char *config;
+ int ok = 0, core_ok = 0;
+ const char *tmp;
struct parse_events_terms parsed_terms;

*listp = NULL;
@@ -1563,15 +1563,15 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
return ret;
}

- config = strdup(event_name);
- if (!config)
+ tmp = strdup(event_name);
+ if (!tmp)
goto out_err;

if (parse_events_term__num(&term,
PARSE_EVENTS__TERM_TYPE_USER,
- config, /*num=*/1, /*novalue=*/true,
+ tmp, /*num=*/1, /*novalue=*/true,
loc, /*loc_val=*/NULL) < 0) {
- zfree(&config);
+ zfree(&tmp);
goto out_err;
}
list_add_tail(&term->list, &parsed_terms.terms);
@@ -1602,6 +1602,8 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
pr_debug("%s -> %s/%s/\n", event_name, pmu->name, sb.buf);
strbuf_release(&sb);
ok++;
+ if (pmu->is_core)
+ core_ok++;
}
}

@@ -1618,6 +1620,18 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
}
}

+ if (hw_config != PERF_COUNT_HW_MAX && !core_ok) {
+ /*
+ * The event wasn't found on core PMUs but it has a hardware
+ * config version to try.
+ */
+ if (!parse_events_add_numeric(parse_state, list,
+ PERF_TYPE_HARDWARE, hw_config,
+ const_parsed_terms,
+ /*wildcard=*/true))
+ ok++;
+ }
+
out_err:
parse_events_terms__exit(&parsed_terms);
if (ok)
@@ -1670,7 +1684,8 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state

/* Failure to add, assume event_or_pmu is an event name. */
zfree(listp);
- if (!parse_events_multi_pmu_add(parse_state, event_or_pmu, const_parsed_terms, listp, loc))
+ if (!parse_events_multi_pmu_add(parse_state, event_or_pmu, PERF_COUNT_HW_MAX,
+ const_parsed_terms, listp, loc))
return 0;

if (asprintf(&help, "Unable to find PMU or event on a PMU of '%s'", event_or_pmu) < 0)
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 5005782766e9..7e5afad3feb8 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -215,7 +215,7 @@ struct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr,
struct perf_pmu *pmu);

int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
- const char *event_name,
+ const char *event_name, u64 hw_config,
const struct parse_events_terms *const_parsed_terms,
struct list_head **listp, void *loc);

diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index e86c45675e1d..6fe37003ab7b 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -100,12 +100,12 @@ do { \
yyless(0); \
} while (0)

-static int sym(yyscan_t scanner, int type, int config)
+static int sym(yyscan_t scanner, int config)
{
YYSTYPE *yylval = parse_events_get_lval(scanner);

- yylval->num = (type << 16) + config;
- return type == PERF_TYPE_HARDWARE ? PE_VALUE_SYM_HW : PE_VALUE_SYM_SW;
+ yylval->num = config;
+ return PE_VALUE_SYM_SW;
}

static int tool(yyscan_t scanner, enum perf_tool_event event)
@@ -124,13 +124,13 @@ static int term(yyscan_t scanner, enum parse_events__term_type type)
return PE_TERM;
}

-static int hw_term(yyscan_t scanner, int config)
+static int hw(yyscan_t scanner, int config)
{
YYSTYPE *yylval = parse_events_get_lval(scanner);
char *text = parse_events_get_text(scanner);

- yylval->hardware_term.str = strdup(text);
- yylval->hardware_term.num = PERF_TYPE_HARDWARE + config;
+ yylval->hardware_event.str = strdup(text);
+ yylval->hardware_event.num = config;
return PE_TERM_HW;
}

@@ -246,16 +246,16 @@ percore { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_PERCORE); }
aux-output { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT); }
aux-sample-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE); }
metric-id { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_METRIC_ID); }
-cpu-cycles|cycles { return hw_term(yyscanner, PERF_COUNT_HW_CPU_CYCLES); }
-stalled-cycles-frontend|idle-cycles-frontend { return hw_term(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
-stalled-cycles-backend|idle-cycles-backend { return hw_term(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
-instructions { return hw_term(yyscanner, PERF_COUNT_HW_INSTRUCTIONS); }
-cache-references { return hw_term(yyscanner, PERF_COUNT_HW_CACHE_REFERENCES); }
-cache-misses { return hw_term(yyscanner, PERF_COUNT_HW_CACHE_MISSES); }
-branch-instructions|branches { return hw_term(yyscanner, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
-branch-misses { return hw_term(yyscanner, PERF_COUNT_HW_BRANCH_MISSES); }
-bus-cycles { return hw_term(yyscanner, PERF_COUNT_HW_BUS_CYCLES); }
-ref-cycles { return hw_term(yyscanner, PERF_COUNT_HW_REF_CPU_CYCLES); }
+cpu-cycles|cycles { return hw(yyscanner, PERF_COUNT_HW_CPU_CYCLES); }
+stalled-cycles-frontend|idle-cycles-frontend { return hw(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
+stalled-cycles-backend|idle-cycles-backend { return hw(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
+instructions { return hw(yyscanner, PERF_COUNT_HW_INSTRUCTIONS); }
+cache-references { return hw(yyscanner, PERF_COUNT_HW_CACHE_REFERENCES); }
+cache-misses { return hw(yyscanner, PERF_COUNT_HW_CACHE_MISSES); }
+branch-instructions|branches { return hw(yyscanner, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
+branch-misses { return hw(yyscanner, PERF_COUNT_HW_BRANCH_MISSES); }
+bus-cycles { return hw(yyscanner, PERF_COUNT_HW_BUS_CYCLES); }
+ref-cycles { return hw(yyscanner, PERF_COUNT_HW_REF_CPU_CYCLES); }
r{num_raw_hex} { return str(yyscanner, PE_RAW); }
r0x{num_raw_hex} { return str(yyscanner, PE_RAW); }
, { return ','; }
@@ -299,31 +299,31 @@ r0x{num_raw_hex} { return str(yyscanner, PE_RAW); }
<<EOF>> { BEGIN(INITIAL); }
}

-cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
-stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
-stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
-instructions { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
-cache-references { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
-cache-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
-branch-instructions|branches { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
-branch-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
-bus-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
-ref-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
-cpu-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
-task-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
-page-faults|faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
-minor-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
-major-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
-context-switches|cs { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
-cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
-alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
-emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
-dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); }
+cpu-cycles|cycles { return hw(yyscanner, PERF_COUNT_HW_CPU_CYCLES); }
+stalled-cycles-frontend|idle-cycles-frontend { return hw(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
+stalled-cycles-backend|idle-cycles-backend { return hw(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
+instructions { return hw(yyscanner, PERF_COUNT_HW_INSTRUCTIONS); }
+cache-references { return hw(yyscanner, PERF_COUNT_HW_CACHE_REFERENCES); }
+cache-misses { return hw(yyscanner, PERF_COUNT_HW_CACHE_MISSES); }
+branch-instructions|branches { return hw(yyscanner, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
+branch-misses { return hw(yyscanner, PERF_COUNT_HW_BRANCH_MISSES); }
+bus-cycles { return hw(yyscanner, PERF_COUNT_HW_BUS_CYCLES); }
+ref-cycles { return hw(yyscanner, PERF_COUNT_HW_REF_CPU_CYCLES); }
+cpu-clock { return sym(yyscanner, PERF_COUNT_SW_CPU_CLOCK); }
+task-clock { return sym(yyscanner, PERF_COUNT_SW_TASK_CLOCK); }
+page-faults|faults { return sym(yyscanner, PERF_COUNT_SW_PAGE_FAULTS); }
+minor-faults { return sym(yyscanner, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
+major-faults { return sym(yyscanner, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
+context-switches|cs { return sym(yyscanner, PERF_COUNT_SW_CONTEXT_SWITCHES); }
+cpu-migrations|migrations { return sym(yyscanner, PERF_COUNT_SW_CPU_MIGRATIONS); }
+alignment-faults { return sym(yyscanner, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+emulation-faults { return sym(yyscanner, PERF_COUNT_SW_EMULATION_FAULTS); }
+dummy { return sym(yyscanner, PERF_COUNT_SW_DUMMY); }
duration_time { return tool(yyscanner, PERF_TOOL_DURATION_TIME); }
user_time { return tool(yyscanner, PERF_TOOL_USER_TIME); }
system_time { return tool(yyscanner, PERF_TOOL_SYSTEM_TIME); }
-bpf-output { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_BPF_OUTPUT); }
-cgroup-switches { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CGROUP_SWITCHES); }
+bpf-output { return sym(yyscanner, PERF_COUNT_SW_BPF_OUTPUT); }
+cgroup-switches { return sym(yyscanner, PERF_COUNT_SW_CGROUP_SWITCHES); }

{lc_type} { return str(yyscanner, PE_LEGACY_CACHE); }
{lc_type}-{lc_op_result} { return str(yyscanner, PE_LEGACY_CACHE); }
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index bb9bee5c8a2b..ebac73786065 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -55,7 +55,7 @@ static void free_list_evsel(struct list_head* list_evsel)
%}

%token PE_START_EVENTS PE_START_TERMS
-%token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_TERM
+%token PE_VALUE PE_VALUE_SYM_SW PE_TERM
%token PE_VALUE_SYM_TOOL
%token PE_EVENT_NAME
%token PE_RAW PE_NAME
@@ -66,11 +66,9 @@ static void free_list_evsel(struct list_head* list_evsel)
%token PE_DRV_CFG_TERM
%token PE_TERM_HW
%type <num> PE_VALUE
-%type <num> PE_VALUE_SYM_HW
%type <num> PE_VALUE_SYM_SW
%type <num> PE_VALUE_SYM_TOOL
%type <term_type> PE_TERM
-%type <num> value_sym
%type <str> PE_RAW
%type <str> PE_NAME
%type <str> PE_LEGACY_CACHE
@@ -87,6 +85,7 @@ static void free_list_evsel(struct list_head* list_evsel)
%type <list_terms> opt_pmu_config
%destructor { parse_events_terms__delete ($$); } <list_terms>
%type <list_evsel> event_pmu
+%type <list_evsel> event_legacy_hardware
%type <list_evsel> event_legacy_symbol
%type <list_evsel> event_legacy_cache
%type <list_evsel> event_legacy_mem
@@ -104,8 +103,8 @@ static void free_list_evsel(struct list_head* list_evsel)
%destructor { free_list_evsel ($$); } <list_evsel>
%type <tracepoint_name> tracepoint_name
%destructor { free ($$.sys); free ($$.event); } <tracepoint_name>
-%type <hardware_term> PE_TERM_HW
-%destructor { free ($$.str); } <hardware_term>
+%type <hardware_event> PE_TERM_HW
+%destructor { free ($$.str); } <hardware_event>

%union
{
@@ -119,10 +118,10 @@ static void free_list_evsel(struct list_head* list_evsel)
char *sys;
char *event;
} tracepoint_name;
- struct hardware_term {
+ struct hardware_event {
char *str;
u64 num;
- } hardware_term;
+ } hardware_event;
}
%%

@@ -263,6 +262,7 @@ PE_EVENT_NAME event_def
event_def

event_def: event_pmu |
+ event_legacy_hardware |
event_legacy_symbol |
event_legacy_cache sep_dc |
event_legacy_mem sep_dc |
@@ -291,7 +291,7 @@ PE_NAME sep_dc
struct list_head *list;
int err;

- err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list, &@1);
+ err = parse_events_multi_pmu_add(_parse_state, $1, PERF_COUNT_HW_MAX, NULL, &list, &@1);
if (err < 0) {
struct parse_events_state *parse_state = _parse_state;
struct parse_events_error *error = parse_state->error;
@@ -307,24 +307,45 @@ PE_NAME sep_dc
$$ = list;
}

-value_sym:
-PE_VALUE_SYM_HW
+event_legacy_hardware:
+PE_TERM_HW opt_pmu_config
+{
+ /* List of created evsels. */
+ struct list_head *list = NULL;
+ int err = parse_events_multi_pmu_add(_parse_state, $1.str, $1.num, $2, &list, &@1);
+
+ free($1.str);
+ parse_events_terms__delete($2);
+ if (err)
+ PE_ABORT(err);
+
+ $$ = list;
+}
|
-PE_VALUE_SYM_SW
+PE_TERM_HW sep_dc
+{
+ struct list_head *list;
+ int err;
+
+ err = parse_events_multi_pmu_add(_parse_state, $1.str, $1.num, NULL, &list, &@1);
+ free($1.str);
+ if (err)
+ PE_ABORT(err);
+ $$ = list;
+}

event_legacy_symbol:
-value_sym '/' event_config '/'
+PE_VALUE_SYM_SW '/' event_config '/'
{
struct list_head *list;
- int type = $1 >> 16;
- int config = $1 & 255;
int err;
- bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE);

list = alloc_list();
if (!list)
YYNOMEM;
- err = parse_events_add_numeric(_parse_state, list, type, config, $3, wildcard);
+ err = parse_events_add_numeric(_parse_state, list,
+ /*type=*/PERF_TYPE_SOFTWARE, /*config=*/$1,
+ $3, /*wildcard=*/false);
parse_events_terms__delete($3);
if (err) {
free_list_evsel(list);
@@ -333,18 +354,17 @@ value_sym '/' event_config '/'
$$ = list;
}
|
-value_sym sep_slash_slash_dc
+PE_VALUE_SYM_SW sep_slash_slash_dc
{
struct list_head *list;
- int type = $1 >> 16;
- int config = $1 & 255;
- bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE);
int err;

list = alloc_list();
if (!list)
YYNOMEM;
- err = parse_events_add_numeric(_parse_state, list, type, config, /*head_config=*/NULL, wildcard);
+ err = parse_events_add_numeric(_parse_state, list,
+ /*type=*/PERF_TYPE_SOFTWARE, /*config=*/$1,
+ /*head_config=*/NULL, /*wildcard=*/false);
if (err)
PE_ABORT(err);
$$ = list;
--
2.44.0.683.g7961c838ac-goog


2024-04-15 16:59:25

by Ian Rogers

[permalink] [raw]
Subject: Re: [PATCH v1 0/9] Consistently prefer sysfs/json events

On Sun, Apr 14, 2024 at 11:36 PM Ian Rogers <[email protected]> wrote:
>
> As discussed in:
> https://lore.kernel.org/lkml/[email protected]/
> preferring sysfs/json events consistently (with or without a given
> PMU) will enable RISC-V's hope to customize legacy events in the perf
> tool.
>
> Some minor clean-up is performed on the way.

A side-effect of prioritizing sysfs/json events over legacy hardware
events is that the hard coded metric logic in stat-shadow fails:
https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/util/stat-shadow.c?h=perf-tools-next#n100
This is because the hard coded metrics assume that legacy events will
be used. Rather than make the hard coded metrics match sysfs/json I
think it is better to remove the hard coded metrics. This is because
the hard coded metrics lack checks on things like grouping that rather
than fix should be transitioned to json metrics. My preference for the
json metrics is to generate them using the python generation scripts
that are out for review.

Thanks,
Ian

> Ian Rogers (9):
> perf parse-events: Factor out '<event_or_pmu>/.../' parsing
> perf parse-events: Directly pass PMU to parse_events_add_pmu
> perf parse-events: Avoid copying an empty list
> perf pmu: Refactor perf_pmu__match
> perf tests parse-events: Use branches rather than cache-references
> perf parse-events: Legacy cache names on all PMUs and lower priority
> perf parse-events: Handle PE_TERM_HW in name_or_raw
> perf parse-events: Constify parse_events_add_numeric
> perf parse-events: Prefer sysfs/json hardware events over legacy
>
> tools/perf/tests/parse-events.c | 6 +-
> tools/perf/util/parse-events.c | 201 ++++++++++++++++++++++----------
> tools/perf/util/parse-events.h | 16 +--
> tools/perf/util/parse-events.l | 76 ++++++------
> tools/perf/util/parse-events.y | 166 +++++++++-----------------
> tools/perf/util/pmu.c | 27 +++--
> tools/perf/util/pmu.h | 2 +-
> 7 files changed, 262 insertions(+), 232 deletions(-)
>
> --
> 2.44.0.683.g7961c838ac-goog
>