1 // SPDX-License-Identifier: GPL-2.0
3 * Support for libpfm4 event encoding.
5 * Copyright 2020 Google LLC.
7 #include "util/cpumap.h"
8 #include "util/debug.h"
9 #include "util/event.h"
10 #include "util/evlist.h"
11 #include "util/evsel.h"
12 #include "util/parse-events.h"
13 #include "util/pmus.h"
15 #include "util/strbuf.h"
16 #include "util/thread_map.h"
19 #include <linux/kernel.h>
20 #include <perfmon/pfmlib_perf_event.h>
22 static void libpfm_initialize(void)
26 ret
= pfm_initialize();
27 if (ret
!= PFM_SUCCESS
) {
28 ui__warning("libpfm failed to initialize: %s\n",
33 int parse_libpfm_events_option(const struct option
*opt
, const char *str
,
34 int unset __maybe_unused
)
36 struct evlist
*evlist
= *(struct evlist
**)opt
->value
;
37 struct perf_event_attr attr
;
39 struct evsel
*evsel
, *grp_leader
= NULL
;
47 p_orig
= p
= strdup(str
);
51 * force loading of the PMU list
53 perf_pmus__scan(NULL
);
55 for (q
= p
; strsep(&p
, ",{}"); q
= p
) {
56 sep
= p
? str
+ (p
- p_orig
- 1) : "";
60 "nested event groups not supported\n");
70 ui__error("cannot close a non-existing event group\n");
78 memset(&attr
, 0, sizeof(attr
));
79 event_attr_init(&attr
);
81 ret
= pfm_get_perf_event_encoding(q
, PFM_PLM0
|PFM_PLM3
,
84 if (ret
!= PFM_SUCCESS
) {
85 ui__error("failed to parse event %s : %s\n", str
,
90 pmu
= perf_pmus__find_by_type((unsigned int)attr
.type
);
91 evsel
= parse_events__add_event(evlist
->core
.nr_entries
,
92 &attr
, q
, /*metric_id=*/NULL
,
97 evsel
->is_libpfm_event
= true;
99 evlist__add(evlist
, evsel
);
105 evsel__set_leader(evsel
, grp_leader
);
106 grp_leader
->core
.nr_members
++;
113 "cannot close a non-existing event group\n");
127 static bool is_libpfm_event_supported(const char *name
, struct perf_cpu_map
*cpus
,
128 struct perf_thread_map
*threads
)
130 struct perf_pmu
*pmu
;
132 struct perf_event_attr attr
= {};
136 ret
= pfm_get_perf_event_encoding(name
, PFM_PLM0
|PFM_PLM3
,
138 if (ret
!= PFM_SUCCESS
)
141 pmu
= perf_pmus__find_by_type((unsigned int)attr
.type
);
142 evsel
= parse_events__add_event(0, &attr
, name
, /*metric_id=*/NULL
, pmu
);
146 evsel
->is_libpfm_event
= true;
148 ret
= evsel__open(evsel
, cpus
, threads
);
149 if (ret
== -EACCES
) {
151 * This happens if the paranoid value
152 * /proc/sys/kernel/perf_event_paranoid is set to 2
153 * Re-run with exclude_kernel set; we don't do that
154 * by default as some ARM machines do not support it.
157 evsel
->core
.attr
.exclude_kernel
= 1;
158 ret
= evsel__open(evsel
, cpus
, threads
);
165 evsel__delete(evsel
);
170 static const char *srcs
[PFM_ATTR_CTRL_MAX
] = {
171 [PFM_ATTR_CTRL_UNKNOWN
] = "???",
172 [PFM_ATTR_CTRL_PMU
] = "PMU",
173 [PFM_ATTR_CTRL_PERF_EVENT
] = "perf_event",
177 print_attr_flags(struct strbuf
*buf
, const pfm_event_attr_info_t
*info
)
180 strbuf_addf(buf
, "[default] ");
182 if (info
->is_precise
)
183 strbuf_addf(buf
, "[precise] ");
187 print_libpfm_event(const struct print_callbacks
*print_cb
, void *print_state
,
188 const pfm_pmu_info_t
*pinfo
, const pfm_event_info_t
*info
,
192 char topic
[80], name
[80];
193 struct perf_cpu_map
*cpus
= perf_cpu_map__empty_new(1);
194 struct perf_thread_map
*threads
= thread_map__new_by_tid(0);
196 strbuf_setlen(buf
, 0);
197 snprintf(topic
, sizeof(topic
), "pfm %s", pinfo
->name
);
199 snprintf(name
, sizeof(name
), "%s::%s", pinfo
->name
, info
->name
);
200 strbuf_addf(buf
, "Code: 0x%"PRIx64
"\n", info
->code
);
202 pfm_for_each_event_attr(j
, info
) {
203 pfm_event_attr_info_t ainfo
;
206 ainfo
.size
= sizeof(ainfo
);
207 ret
= pfm_get_event_attr_info(info
->idx
, j
, PFM_OS_PERF_EVENT_EXT
, &ainfo
);
208 if (ret
!= PFM_SUCCESS
)
211 if (ainfo
.ctrl
>= PFM_ATTR_CTRL_MAX
)
212 ainfo
.ctrl
= PFM_ATTR_CTRL_UNKNOWN
;
214 src
= srcs
[ainfo
.ctrl
];
215 switch (ainfo
.type
) {
216 case PFM_ATTR_UMASK
: /* Ignore for now */
218 case PFM_ATTR_MOD_BOOL
:
219 strbuf_addf(buf
, " Modif: %s: [%s] : %s (boolean)\n", src
,
220 ainfo
.name
, ainfo
.desc
);
222 case PFM_ATTR_MOD_INTEGER
:
223 strbuf_addf(buf
, " Modif: %s: [%s] : %s (integer)\n", src
,
224 ainfo
.name
, ainfo
.desc
);
227 case PFM_ATTR_RAW_UMASK
:
230 strbuf_addf(buf
, " Attr: %s: [%s] : %s\n", src
,
231 ainfo
.name
, ainfo
.desc
);
235 if (is_libpfm_event_supported(name
, cpus
, threads
)) {
236 print_cb
->print_event(print_state
, topic
, pinfo
->name
,
239 /*deprecated=*/NULL
, "PFM event",
240 info
->desc
, /*long_desc=*/NULL
,
241 /*encoding_desc=*/buf
->buf
);
244 pfm_for_each_event_attr(j
, info
) {
245 pfm_event_attr_info_t ainfo
;
248 strbuf_setlen(buf
, 0);
250 ainfo
.size
= sizeof(ainfo
);
251 ret
= pfm_get_event_attr_info(info
->idx
, j
, PFM_OS_PERF_EVENT_EXT
, &ainfo
);
252 if (ret
!= PFM_SUCCESS
)
255 if (ainfo
.ctrl
>= PFM_ATTR_CTRL_MAX
)
256 ainfo
.ctrl
= PFM_ATTR_CTRL_UNKNOWN
;
258 src
= srcs
[ainfo
.ctrl
];
259 if (ainfo
.type
== PFM_ATTR_UMASK
) {
260 strbuf_addf(buf
, "Umask: 0x%02"PRIx64
" : %s: ",
262 print_attr_flags(buf
, &ainfo
);
263 snprintf(name
, sizeof(name
), "%s::%s:%s",
264 pinfo
->name
, info
->name
, ainfo
.name
);
266 if (!is_libpfm_event_supported(name
, cpus
, threads
))
269 print_cb
->print_event(print_state
,
272 name
, /*alias=*/NULL
,
274 /*deprecated=*/NULL
, "PFM event",
275 ainfo
.desc
, /*long_desc=*/NULL
,
276 /*encoding_desc=*/buf
->buf
);
280 perf_cpu_map__put(cpus
);
281 perf_thread_map__put(threads
);
284 void print_libpfm_events(const struct print_callbacks
*print_cb
, void *print_state
)
286 pfm_event_info_t info
;
287 pfm_pmu_info_t pinfo
;
289 struct strbuf storage
;
293 /* initialize to zero to indicate ABI version */
294 info
.size
= sizeof(info
);
295 pinfo
.size
= sizeof(pinfo
);
297 strbuf_init(&storage
, 2048);
299 pfm_for_all_pmus(p
) {
300 ret
= pfm_get_pmu_info(p
, &pinfo
);
301 if (ret
!= PFM_SUCCESS
)
304 /* only print events that are supported by host HW */
305 if (!pinfo
.is_present
)
308 /* handled by perf directly */
309 if (pinfo
.pmu
== PFM_PMU_PERF_EVENT
)
312 for (int i
= pinfo
.first_event
; i
!= -1; i
= pfm_get_event_next(i
)) {
313 ret
= pfm_get_event_info(i
, PFM_OS_PERF_EVENT_EXT
,
315 if (ret
!= PFM_SUCCESS
)
318 print_libpfm_event(print_cb
, print_state
, &pinfo
, &info
, &storage
);
321 strbuf_release(&storage
);