Loading...
Note: File does not exist in v6.9.4.
1// 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,
41 struct perf_event_attr *attr, char *name,
42 struct list_head *config_terms,
43 struct perf_pmu *pmu)
44{
45 struct evsel *evsel;
46 __u32 type = attr->type;
47 __u64 config = attr->config;
48
49 config_hybrid_attr(attr, config_type, pmu->type);
50 evsel = parse_events__add_event_hybrid(list, idx, attr, name,
51 pmu, config_terms);
52 if (evsel)
53 evsel->pmu_name = strdup(pmu->name);
54 else
55 return -ENOMEM;
56
57 attr->type = type;
58 attr->config = config;
59 return 0;
60}
61
62static int pmu_cmp(struct parse_events_state *parse_state,
63 struct perf_pmu *pmu)
64{
65 if (!parse_state->hybrid_pmu_name)
66 return 0;
67
68 return strcmp(parse_state->hybrid_pmu_name, pmu->name);
69}
70
71static int add_hw_hybrid(struct parse_events_state *parse_state,
72 struct list_head *list, struct perf_event_attr *attr,
73 char *name, struct list_head *config_terms)
74{
75 struct perf_pmu *pmu;
76 int ret;
77
78 perf_pmu__for_each_hybrid_pmu(pmu) {
79 if (pmu_cmp(parse_state, pmu))
80 continue;
81
82 ret = create_event_hybrid(PERF_TYPE_HARDWARE,
83 &parse_state->idx, list, attr, name,
84 config_terms, pmu);
85 if (ret)
86 return ret;
87 }
88
89 return 0;
90}
91
92static int create_raw_event_hybrid(int *idx, struct list_head *list,
93 struct perf_event_attr *attr, char *name,
94 struct list_head *config_terms,
95 struct perf_pmu *pmu)
96{
97 struct evsel *evsel;
98
99 attr->type = pmu->type;
100 evsel = parse_events__add_event_hybrid(list, idx, attr, name,
101 pmu, config_terms);
102 if (evsel)
103 evsel->pmu_name = strdup(pmu->name);
104 else
105 return -ENOMEM;
106
107 return 0;
108}
109
110static int add_raw_hybrid(struct parse_events_state *parse_state,
111 struct list_head *list, struct perf_event_attr *attr,
112 char *name, struct list_head *config_terms)
113{
114 struct perf_pmu *pmu;
115 int ret;
116
117 perf_pmu__for_each_hybrid_pmu(pmu) {
118 if (pmu_cmp(parse_state, pmu))
119 continue;
120
121 ret = create_raw_event_hybrid(&parse_state->idx, list, attr,
122 name, config_terms, pmu);
123 if (ret)
124 return ret;
125 }
126
127 return 0;
128}
129
130int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state,
131 struct list_head *list,
132 struct perf_event_attr *attr,
133 char *name, struct list_head *config_terms,
134 bool *hybrid)
135{
136 *hybrid = false;
137 if (attr->type == PERF_TYPE_SOFTWARE)
138 return 0;
139
140 if (!perf_pmu__has_hybrid())
141 return 0;
142
143 *hybrid = true;
144 if (attr->type != PERF_TYPE_RAW) {
145 return add_hw_hybrid(parse_state, list, attr, name,
146 config_terms);
147 }
148
149 return add_raw_hybrid(parse_state, list, attr, name,
150 config_terms);
151}
152
153int parse_events__add_cache_hybrid(struct list_head *list, int *idx,
154 struct perf_event_attr *attr, char *name,
155 struct list_head *config_terms,
156 bool *hybrid,
157 struct parse_events_state *parse_state)
158{
159 struct perf_pmu *pmu;
160 int ret;
161
162 *hybrid = false;
163 if (!perf_pmu__has_hybrid())
164 return 0;
165
166 *hybrid = true;
167 perf_pmu__for_each_hybrid_pmu(pmu) {
168 if (pmu_cmp(parse_state, pmu))
169 continue;
170
171 ret = create_event_hybrid(PERF_TYPE_HW_CACHE, idx, list,
172 attr, name, config_terms, pmu);
173 if (ret)
174 return ret;
175 }
176
177 return 0;
178}