[PATCH v3 09/27] perf parse-events: Create two hybrid cache events

From: Jin Yao
Date: Mon Mar 29 2021 - 03:02:46 EST


For cache events, they have pre-defined configs. The kernel needs
to know where the cache event comes from (e.g. from cpu_core pmu
or from cpu_atom pmu). But the perf type 'PERF_TYPE_HW_CACHE'
can't carry pmu information.

So the kernel introduces a new type 'PERF_TYPE_HW_CACHE_PMU'.

The new attr.config layout for PERF_TYPE_HW_CACHE_PMU is

0xDD00CCBBAA
AA: hardware cache ID
BB: hardware cache op ID
CC: hardware cache op result ID
DD: PMU type ID

Similar as hardware event, PMU type ID is retrieved from sysfs.

When enabling a hybrid cache event without specified pmu, such as,
'perf stat -e L1-dcache-loads -a', two events are created
automatically. One is for atom, the other is for core.

# ./perf stat -e L1-dcache-loads -vv -a -- sleep 1
Control descriptor is not initialized
------------------------------------------------------------
perf_event_attr:
type 7
size 120
config 0x400000000
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 0 group_fd -1 flags 0x8 = 3
------------------------------------------------------------
perf_event_attr:
type 7
size 120
config 0x400000000
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 1 group_fd -1 flags 0x8 = 4
------------------------------------------------------------

......

------------------------------------------------------------
perf_event_attr:
type 7
size 120
config 0x400000000
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 15 group_fd -1 flags 0x8 = 19
------------------------------------------------------------
perf_event_attr:
type 7
size 120
config 0xa00000000
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 16 group_fd -1 flags 0x8 = 20
------------------------------------------------------------
perf_event_attr:
type 7
size 120
config 0xa00000000
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 17 group_fd -1 flags 0x8 = 21
------------------------------------------------------------

......

------------------------------------------------------------
perf_event_attr:
type 7
size 120
config 0xa00000000
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 23 group_fd -1 flags 0x8 = 27
L1-dcache-loads: 0: 12071 1001549888 1001549888
L1-dcache-loads: 1: 12704 1001602818 1001602818
L1-dcache-loads: 2: 21560 1001687258 1001687258
L1-dcache-loads: 3: 8104 1001727825 1001727825
L1-dcache-loads: 4: 7855 1001738995 1001738995
L1-dcache-loads: 5: 7714 1001766241 1001766241
L1-dcache-loads: 6: 7704 1001790333 1001790333
L1-dcache-loads: 7: 58026 1001826950 1001826950
L1-dcache-loads: 8: 107639 1001641286 1001641286
L1-dcache-loads: 9: 67013 1001682357 1001682357
L1-dcache-loads: 10: 17137 1001700068 1001700068
L1-dcache-loads: 11: 86449 1001696907 1001696907
L1-dcache-loads: 12: 7723 1001716599 1001716599
L1-dcache-loads: 13: 10211 1001743285 1001743285
L1-dcache-loads: 14: 13023 1001765343 1001765343
L1-dcache-loads: 15: 8991 1001788673 1001788673
L1-dcache-loads: 0: 240163 1001800830 1001800830
L1-dcache-loads: 1: 7454 1001773983 1001773983
L1-dcache-loads: 2: 32323 1001686339 1001686339
L1-dcache-loads: 3: 11039 1001732430 1001732430
L1-dcache-loads: 4: 52867 1001753753 1001753753
L1-dcache-loads: 5: 7481 1001756879 1001756879
L1-dcache-loads: 6: 7471 1001814616 1001814616
L1-dcache-loads: 7: 29627 1001815092 1001815092
L1-dcache-loads: 453924 16027424826 16027424826
L1-dcache-loads: 388425 8014133922 8014133922

Performance counter stats for 'system wide':

453,924 cpu_core/L1-dcache-loads/
388,425 cpu_atom/L1-dcache-loads/

1.003644499 seconds time elapsed

type 7 is PERF_TYPE_HW_CACHE_PMU.
0x4 in 0x400000000 indicates the cpu_core pmu.
0xa in 0xa00000000 indicates the cpu_atom pmu.

Signed-off-by: Jin Yao <yao.jin@xxxxxxxxxxxxxxx>
---
v3:
- Hybrid cache event creation is moved to parse-events-hybrid.c.

tools/perf/util/parse-events-hybrid.c | 23 +++++++++++++++++++++++
tools/perf/util/parse-events-hybrid.h | 5 +++++
tools/perf/util/parse-events.c | 8 ++++++++
3 files changed, 36 insertions(+)

diff --git a/tools/perf/util/parse-events-hybrid.c b/tools/perf/util/parse-events-hybrid.c
index bd48563596e0..ff2909bfbf86 100644
--- a/tools/perf/util/parse-events-hybrid.c
+++ b/tools/perf/util/parse-events-hybrid.c
@@ -95,3 +95,26 @@ int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state,

return -1;
}
+
+int parse_events__add_cache_hybrid(struct list_head *list, int *idx,
+ struct perf_event_attr *attr, char *name,
+ struct list_head *config_terms,
+ bool *hybrid)
+{
+ struct perf_pmu *pmu;
+ int ret;
+
+ *hybrid = false;
+ if (!perf_pmu__has_hybrid())
+ return 0;
+
+ *hybrid = true;
+ perf_pmu__for_each_hybrid_pmu(pmu) {
+ ret = create_event_hybrid(PERF_TYPE_HW_CACHE_PMU, idx, list,
+ attr, name, config_terms, pmu);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/tools/perf/util/parse-events-hybrid.h b/tools/perf/util/parse-events-hybrid.h
index d81a76978480..9ad33cd0cef4 100644
--- a/tools/perf/util/parse-events-hybrid.h
+++ b/tools/perf/util/parse-events-hybrid.h
@@ -14,4 +14,9 @@ int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state,
char *name, struct list_head *config_terms,
bool *hybrid);

+int parse_events__add_cache_hybrid(struct list_head *list, int *idx,
+ struct perf_event_attr *attr, char *name,
+ struct list_head *config_terms,
+ bool *hybrid);
+
#endif /* __PERF_PARSE_EVENTS_HYBRID_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 1bbd0ba92ba7..3692fa3c964a 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -458,6 +458,7 @@ int parse_events_add_cache(struct list_head *list, int *idx,
int cache_type = -1, cache_op = -1, cache_result = -1;
char *op_result[2] = { op_result1, op_result2 };
int i, n;
+ bool hybrid;

/*
* No fallback - if we cannot get a clear cache type
@@ -517,6 +518,13 @@ int parse_events_add_cache(struct list_head *list, int *idx,
if (get_config_terms(head_config, &config_terms))
return -ENOMEM;
}
+
+ i = parse_events__add_cache_hybrid(list, idx, &attr,
+ config_name ? : name, &config_terms,
+ &hybrid);
+ if (hybrid)
+ return i;
+
return add_event(list, idx, &attr, config_name ? : name, &config_terms);
}

--
2.17.1