1 // SPDX-License-Identifier: GPL-2.0
3 #include <linux/zalloc.h>
11 #include "parse-events.h"
12 #include "parse-events-hybrid.h"
15 #include "pmu-hybrid.h"
18 static void config_hybrid_attr(struct perf_event_attr *attr,
19 int type, int pmu_type)
22 * attr.config layout for type PERF_TYPE_HARDWARE and
25 * PERF_TYPE_HARDWARE: 0xEEEEEEEE000000AA
26 * AA: hardware event ID
27 * EEEEEEEE: PMU type ID
28 * PERF_TYPE_HW_CACHE: 0xEEEEEEEE00DDCCBB
29 * BB: hardware cache ID
30 * CC: hardware cache op ID
31 * DD: hardware cache op result ID
32 * EEEEEEEE: PMU type ID
33 * If the PMU type ID is 0, the PERF_TYPE_RAW will be applied.
36 attr->config = (attr->config & PERF_HW_EVENT_MASK) |
37 ((__u64)pmu_type << PERF_PMU_TYPE_SHIFT);
40 static int create_event_hybrid(__u32 config_type, int *idx,
41 struct list_head *list,
42 struct perf_event_attr *attr, const char *name,
43 const char *metric_id,
44 struct list_head *config_terms,
48 __u32 type = attr->type;
49 __u64 config = attr->config;
51 config_hybrid_attr(attr, config_type, pmu->type);
54 * Some hybrid hardware cache events are only available on one CPU
55 * PMU. For example, the 'L1-dcache-load-misses' is only available
56 * on cpu_core, while the 'L1-icache-loads' is only available on
57 * cpu_atom. We need to remove "not supported" hybrid cache events.
59 if (attr->type == PERF_TYPE_HW_CACHE
60 && !is_event_supported(attr->type, attr->config))
63 evsel = parse_events__add_event_hybrid(list, idx, attr, name, metric_id,
66 evsel->pmu_name = strdup(pmu->name);
72 attr->config = config;
76 static int pmu_cmp(struct parse_events_state *parse_state,
79 if (parse_state->evlist && parse_state->evlist->hybrid_pmu_name)
80 return strcmp(parse_state->evlist->hybrid_pmu_name, pmu->name);
82 if (parse_state->hybrid_pmu_name)
83 return strcmp(parse_state->hybrid_pmu_name, pmu->name);
88 static int add_hw_hybrid(struct parse_events_state *parse_state,
89 struct list_head *list, struct perf_event_attr *attr,
90 const char *name, const char *metric_id,
91 struct list_head *config_terms)
96 perf_pmu__for_each_hybrid_pmu(pmu) {
99 if (pmu_cmp(parse_state, pmu))
102 copy_config_terms(&terms, config_terms);
103 ret = create_event_hybrid(PERF_TYPE_HARDWARE,
104 &parse_state->idx, list, attr, name,
105 metric_id, &terms, pmu);
106 free_config_terms(&terms);
114 static int create_raw_event_hybrid(int *idx, struct list_head *list,
115 struct perf_event_attr *attr,
117 const char *metric_id,
118 struct list_head *config_terms,
119 struct perf_pmu *pmu)
123 attr->type = pmu->type;
124 evsel = parse_events__add_event_hybrid(list, idx, attr, name, metric_id,
127 evsel->pmu_name = strdup(pmu->name);
134 static int add_raw_hybrid(struct parse_events_state *parse_state,
135 struct list_head *list, struct perf_event_attr *attr,
136 const char *name, const char *metric_id,
137 struct list_head *config_terms)
139 struct perf_pmu *pmu;
142 perf_pmu__for_each_hybrid_pmu(pmu) {
145 if (pmu_cmp(parse_state, pmu))
148 copy_config_terms(&terms, config_terms);
149 ret = create_raw_event_hybrid(&parse_state->idx, list, attr,
150 name, metric_id, &terms, pmu);
151 free_config_terms(&terms);
159 int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state,
160 struct list_head *list,
161 struct perf_event_attr *attr,
162 const char *name, const char *metric_id,
163 struct list_head *config_terms,
167 if (attr->type == PERF_TYPE_SOFTWARE)
170 if (!perf_pmu__has_hybrid())
174 if (attr->type != PERF_TYPE_RAW) {
175 return add_hw_hybrid(parse_state, list, attr, name, metric_id,
179 return add_raw_hybrid(parse_state, list, attr, name, metric_id,
183 int parse_events__add_cache_hybrid(struct list_head *list, int *idx,
184 struct perf_event_attr *attr,
186 const char *metric_id,
187 struct list_head *config_terms,
189 struct parse_events_state *parse_state)
191 struct perf_pmu *pmu;
195 if (!perf_pmu__has_hybrid())
199 perf_pmu__for_each_hybrid_pmu(pmu) {
202 if (pmu_cmp(parse_state, pmu))
205 copy_config_terms(&terms, config_terms);
206 ret = create_event_hybrid(PERF_TYPE_HW_CACHE, idx, list,
207 attr, name, metric_id, &terms, pmu);
208 free_config_terms(&terms);