]> Git Repo - linux.git/blob - tools/perf/util/parse-events-hybrid.c
scsi: zfcp: Trace when request remove fails after qdio send fails
[linux.git] / tools / perf / util / parse-events-hybrid.c
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
18 static 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 & PERF_HW_EVENT_MASK) |
37                         ((__u64)pmu_type << PERF_PMU_TYPE_SHIFT);
38 }
39
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,
45                                struct perf_pmu *pmu)
46 {
47         struct evsel *evsel;
48         __u32 type = attr->type;
49         __u64 config = attr->config;
50
51         config_hybrid_attr(attr, config_type, pmu->type);
52
53         /*
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.
58          */
59         if (attr->type == PERF_TYPE_HW_CACHE
60             && !is_event_supported(attr->type, attr->config))
61                 return 0;
62
63         evsel = parse_events__add_event_hybrid(list, idx, attr, name, metric_id,
64                                                pmu, config_terms);
65         if (evsel) {
66                 evsel->pmu_name = strdup(pmu->name);
67                 if (!evsel->pmu_name)
68                         return -ENOMEM;
69         } else
70                 return -ENOMEM;
71         attr->type = type;
72         attr->config = config;
73         return 0;
74 }
75
76 static int pmu_cmp(struct parse_events_state *parse_state,
77                    struct perf_pmu *pmu)
78 {
79         if (parse_state->evlist && parse_state->evlist->hybrid_pmu_name)
80                 return strcmp(parse_state->evlist->hybrid_pmu_name, pmu->name);
81
82         if (parse_state->hybrid_pmu_name)
83                 return strcmp(parse_state->hybrid_pmu_name, pmu->name);
84
85         return 0;
86 }
87
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)
92 {
93         struct perf_pmu *pmu;
94         int ret;
95
96         perf_pmu__for_each_hybrid_pmu(pmu) {
97                 LIST_HEAD(terms);
98
99                 if (pmu_cmp(parse_state, pmu))
100                         continue;
101
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);
107                 if (ret)
108                         return ret;
109         }
110
111         return 0;
112 }
113
114 static int create_raw_event_hybrid(int *idx, struct list_head *list,
115                                    struct perf_event_attr *attr,
116                                    const char *name,
117                                    const char *metric_id,
118                                    struct list_head *config_terms,
119                                    struct perf_pmu *pmu)
120 {
121         struct evsel *evsel;
122
123         attr->type = pmu->type;
124         evsel = parse_events__add_event_hybrid(list, idx, attr, name, metric_id,
125                                                pmu, config_terms);
126         if (evsel)
127                 evsel->pmu_name = strdup(pmu->name);
128         else
129                 return -ENOMEM;
130
131         return 0;
132 }
133
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)
138 {
139         struct perf_pmu *pmu;
140         int ret;
141
142         perf_pmu__for_each_hybrid_pmu(pmu) {
143                 LIST_HEAD(terms);
144
145                 if (pmu_cmp(parse_state, pmu))
146                         continue;
147
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);
152                 if (ret)
153                         return ret;
154         }
155
156         return 0;
157 }
158
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,
164                                      bool *hybrid)
165 {
166         *hybrid = false;
167         if (attr->type == PERF_TYPE_SOFTWARE)
168                 return 0;
169
170         if (!perf_pmu__has_hybrid())
171                 return 0;
172
173         *hybrid = true;
174         if (attr->type != PERF_TYPE_RAW) {
175                 return add_hw_hybrid(parse_state, list, attr, name, metric_id,
176                                      config_terms);
177         }
178
179         return add_raw_hybrid(parse_state, list, attr, name, metric_id,
180                               config_terms);
181 }
182
183 int parse_events__add_cache_hybrid(struct list_head *list, int *idx,
184                                    struct perf_event_attr *attr,
185                                    const char *name,
186                                    const char *metric_id,
187                                    struct list_head *config_terms,
188                                    bool *hybrid,
189                                    struct parse_events_state *parse_state)
190 {
191         struct perf_pmu *pmu;
192         int ret;
193
194         *hybrid = false;
195         if (!perf_pmu__has_hybrid())
196                 return 0;
197
198         *hybrid = true;
199         perf_pmu__for_each_hybrid_pmu(pmu) {
200                 LIST_HEAD(terms);
201
202                 if (pmu_cmp(parse_state, pmu))
203                         continue;
204
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);
209                 if (ret)
210                         return ret;
211         }
212
213         return 0;
214 }
This page took 0.042732 seconds and 4 git commands to generate.