blob: 9fc86971027b8614362be607d7fa2dcef0c3530f [file] [log] [blame]
Jin Yao9cbfa2f2021-04-27 15:01:21 +08001// SPDX-License-Identifier: GPL-2.0
2#include <linux/err.h>
3#include <linux/zalloc.h>
4#include <errno.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8#include <sys/param.h>
9#include "evlist.h"
10#include "evsel.h"
11#include "parse-events.h"
12#include "parse-events-hybrid.h"
13#include "debug.h"
14#include "pmu.h"
15#include "pmu-hybrid.h"
16#include "perf.h"
17
18static void config_hybrid_attr(struct perf_event_attr *attr,
19 int type, int pmu_type)
20{
21 /*
22 * attr.config layout for type PERF_TYPE_HARDWARE and
23 * PERF_TYPE_HW_CACHE
24 *
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.
34 */
35 attr->type = type;
36 attr->config = attr->config | ((__u64)pmu_type << PERF_PMU_TYPE_SHIFT);
37}
38
39static int create_event_hybrid(__u32 config_type, int *idx,
40 struct list_head *list,
Ian Rogers8e8bbfb2021-10-15 10:21:24 -070041 struct perf_event_attr *attr, const char *name,
Ian Rogers2b62b3a2021-10-15 10:21:25 -070042 const char *metric_id,
Jin Yao9cbfa2f2021-04-27 15:01:21 +080043 struct list_head *config_terms,
44 struct perf_pmu *pmu)
45{
46 struct evsel *evsel;
47 __u32 type = attr->type;
48 __u64 config = attr->config;
49
50 config_hybrid_attr(attr, config_type, pmu->type);
Ian Rogers2b62b3a2021-10-15 10:21:25 -070051 evsel = parse_events__add_event_hybrid(list, idx, attr, name, metric_id,
Jin Yao9cbfa2f2021-04-27 15:01:21 +080052 pmu, config_terms);
53 if (evsel)
54 evsel->pmu_name = strdup(pmu->name);
55 else
56 return -ENOMEM;
57
58 attr->type = type;
59 attr->config = config;
60 return 0;
61}
62
Jin Yaoc93afad2021-04-27 15:01:24 +080063static int pmu_cmp(struct parse_events_state *parse_state,
64 struct perf_pmu *pmu)
65{
66 if (!parse_state->hybrid_pmu_name)
67 return 0;
68
69 return strcmp(parse_state->hybrid_pmu_name, pmu->name);
70}
71
Jin Yao9cbfa2f2021-04-27 15:01:21 +080072static int add_hw_hybrid(struct parse_events_state *parse_state,
73 struct list_head *list, struct perf_event_attr *attr,
Ian Rogers2b62b3a2021-10-15 10:21:25 -070074 const char *name, const char *metric_id,
75 struct list_head *config_terms)
Jin Yao9cbfa2f2021-04-27 15:01:21 +080076{
77 struct perf_pmu *pmu;
78 int ret;
79
80 perf_pmu__for_each_hybrid_pmu(pmu) {
Adrian Hunter99fc5942021-09-09 15:55:08 +030081 LIST_HEAD(terms);
82
Jin Yaoc93afad2021-04-27 15:01:24 +080083 if (pmu_cmp(parse_state, pmu))
84 continue;
85
Adrian Hunter99fc5942021-09-09 15:55:08 +030086 copy_config_terms(&terms, config_terms);
Jin Yao9cbfa2f2021-04-27 15:01:21 +080087 ret = create_event_hybrid(PERF_TYPE_HARDWARE,
88 &parse_state->idx, list, attr, name,
Ian Rogers2b62b3a2021-10-15 10:21:25 -070089 metric_id, &terms, pmu);
Adrian Hunter99fc5942021-09-09 15:55:08 +030090 free_config_terms(&terms);
Jin Yao9cbfa2f2021-04-27 15:01:21 +080091 if (ret)
92 return ret;
93 }
94
95 return 0;
96}
97
Jin Yao94da5912021-04-27 15:01:23 +080098static int create_raw_event_hybrid(int *idx, struct list_head *list,
Ian Rogers8e8bbfb2021-10-15 10:21:24 -070099 struct perf_event_attr *attr,
100 const char *name,
Ian Rogers2b62b3a2021-10-15 10:21:25 -0700101 const char *metric_id,
Jin Yao94da5912021-04-27 15:01:23 +0800102 struct list_head *config_terms,
103 struct perf_pmu *pmu)
104{
105 struct evsel *evsel;
106
107 attr->type = pmu->type;
Ian Rogers2b62b3a2021-10-15 10:21:25 -0700108 evsel = parse_events__add_event_hybrid(list, idx, attr, name, metric_id,
Jin Yao94da5912021-04-27 15:01:23 +0800109 pmu, config_terms);
110 if (evsel)
111 evsel->pmu_name = strdup(pmu->name);
112 else
113 return -ENOMEM;
114
115 return 0;
116}
117
118static int add_raw_hybrid(struct parse_events_state *parse_state,
119 struct list_head *list, struct perf_event_attr *attr,
Ian Rogers2b62b3a2021-10-15 10:21:25 -0700120 const char *name, const char *metric_id,
121 struct list_head *config_terms)
Jin Yao94da5912021-04-27 15:01:23 +0800122{
123 struct perf_pmu *pmu;
124 int ret;
125
126 perf_pmu__for_each_hybrid_pmu(pmu) {
Adrian Hunter99fc5942021-09-09 15:55:08 +0300127 LIST_HEAD(terms);
128
Jin Yaoc93afad2021-04-27 15:01:24 +0800129 if (pmu_cmp(parse_state, pmu))
130 continue;
131
Adrian Hunter99fc5942021-09-09 15:55:08 +0300132 copy_config_terms(&terms, config_terms);
Jin Yao94da5912021-04-27 15:01:23 +0800133 ret = create_raw_event_hybrid(&parse_state->idx, list, attr,
Ian Rogers2b62b3a2021-10-15 10:21:25 -0700134 name, metric_id, &terms, pmu);
Adrian Hunter99fc5942021-09-09 15:55:08 +0300135 free_config_terms(&terms);
Jin Yao94da5912021-04-27 15:01:23 +0800136 if (ret)
137 return ret;
138 }
139
140 return 0;
141}
142
Jin Yao9cbfa2f2021-04-27 15:01:21 +0800143int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state,
144 struct list_head *list,
145 struct perf_event_attr *attr,
Ian Rogers2b62b3a2021-10-15 10:21:25 -0700146 const char *name, const char *metric_id,
Ian Rogers8e8bbfb2021-10-15 10:21:24 -0700147 struct list_head *config_terms,
Jin Yao9cbfa2f2021-04-27 15:01:21 +0800148 bool *hybrid)
149{
150 *hybrid = false;
151 if (attr->type == PERF_TYPE_SOFTWARE)
152 return 0;
153
154 if (!perf_pmu__has_hybrid())
155 return 0;
156
157 *hybrid = true;
158 if (attr->type != PERF_TYPE_RAW) {
Ian Rogers2b62b3a2021-10-15 10:21:25 -0700159 return add_hw_hybrid(parse_state, list, attr, name, metric_id,
Jin Yao9cbfa2f2021-04-27 15:01:21 +0800160 config_terms);
161 }
162
Ian Rogers2b62b3a2021-10-15 10:21:25 -0700163 return add_raw_hybrid(parse_state, list, attr, name, metric_id,
Jin Yao94da5912021-04-27 15:01:23 +0800164 config_terms);
Jin Yao9cbfa2f2021-04-27 15:01:21 +0800165}
Jin Yao30def612021-04-27 15:01:22 +0800166
167int parse_events__add_cache_hybrid(struct list_head *list, int *idx,
Ian Rogers8e8bbfb2021-10-15 10:21:24 -0700168 struct perf_event_attr *attr,
169 const char *name,
Ian Rogers2b62b3a2021-10-15 10:21:25 -0700170 const char *metric_id,
Jin Yao30def612021-04-27 15:01:22 +0800171 struct list_head *config_terms,
Jin Yaoc93afad2021-04-27 15:01:24 +0800172 bool *hybrid,
173 struct parse_events_state *parse_state)
Jin Yao30def612021-04-27 15:01:22 +0800174{
175 struct perf_pmu *pmu;
176 int ret;
177
178 *hybrid = false;
179 if (!perf_pmu__has_hybrid())
180 return 0;
181
182 *hybrid = true;
183 perf_pmu__for_each_hybrid_pmu(pmu) {
Adrian Hunter99fc5942021-09-09 15:55:08 +0300184 LIST_HEAD(terms);
185
Jin Yaoc93afad2021-04-27 15:01:24 +0800186 if (pmu_cmp(parse_state, pmu))
187 continue;
188
Adrian Hunter99fc5942021-09-09 15:55:08 +0300189 copy_config_terms(&terms, config_terms);
Jin Yao30def612021-04-27 15:01:22 +0800190 ret = create_event_hybrid(PERF_TYPE_HW_CACHE, idx, list,
Ian Rogers2b62b3a2021-10-15 10:21:25 -0700191 attr, name, metric_id, &terms, pmu);
Adrian Hunter99fc5942021-09-09 15:55:08 +0300192 free_config_terms(&terms);
Jin Yao30def612021-04-27 15:01:22 +0800193 if (ret)
194 return ret;
195 }
196
197 return 0;
198}