Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Support for libpfm4 event encoding.
  4 *
  5 * Copyright 2020 Google LLC.
  6 */
  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/pmu.h"
 14#include "util/pfm.h"
 15
 16#include <string.h>
 17#include <linux/kernel.h>
 18#include <perfmon/pfmlib_perf_event.h>
 19
 20static void libpfm_initialize(void)
 21{
 22	int ret;
 23
 24	ret = pfm_initialize();
 25	if (ret != PFM_SUCCESS) {
 26		ui__warning("libpfm failed to initialize: %s\n",
 27			pfm_strerror(ret));
 28	}
 29}
 30
 31int parse_libpfm_events_option(const struct option *opt, const char *str,
 32			int unset __maybe_unused)
 33{
 34	struct evlist *evlist = *(struct evlist **)opt->value;
 35	struct perf_event_attr attr;
 36	struct perf_pmu *pmu;
 37	struct evsel *evsel, *grp_leader = NULL;
 38	char *p, *q, *p_orig;
 39	const char *sep;
 40	int grp_evt = -1;
 41	int ret;
 42
 43	libpfm_initialize();
 44
 45	p_orig = p = strdup(str);
 46	if (!p)
 47		return -1;
 48	/*
 49	 * force loading of the PMU list
 50	 */
 51	perf_pmu__scan(NULL);
 52
 53	for (q = p; strsep(&p, ",{}"); q = p) {
 54		sep = p ? str + (p - p_orig - 1) : "";
 55		if (*sep == '{') {
 56			if (grp_evt > -1) {
 57				ui__error(
 58					"nested event groups not supported\n");
 59				goto error;
 60			}
 61			grp_evt++;
 62		}
 63
 64		/* no event */
 65		if (*q == '\0') {
 66			if (*sep == '}') {
 67				if (grp_evt < 0) {
 68					ui__error("cannot close a non-existing event group\n");
 69					goto error;
 70				}
 71				grp_evt--;
 72			}
 73			continue;
 74		}
 75
 76		memset(&attr, 0, sizeof(attr));
 77		event_attr_init(&attr);
 78
 79		ret = pfm_get_perf_event_encoding(q, PFM_PLM0|PFM_PLM3,
 80						&attr, NULL, NULL);
 81
 82		if (ret != PFM_SUCCESS) {
 83			ui__error("failed to parse event %s : %s\n", str,
 84				  pfm_strerror(ret));
 85			goto error;
 86		}
 87
 88		pmu = perf_pmu__find_by_type((unsigned int)attr.type);
 89		evsel = parse_events__add_event(evlist->core.nr_entries,
 90						&attr, q, pmu);
 91		if (evsel == NULL)
 92			goto error;
 93
 94		evsel->is_libpfm_event = true;
 95
 96		evlist__add(evlist, evsel);
 97
 98		if (grp_evt == 0)
 99			grp_leader = evsel;
100
101		if (grp_evt > -1) {
102			evsel__set_leader(evsel, grp_leader);
103			grp_leader->core.nr_members++;
104			grp_evt++;
105		}
106
107		if (*sep == '}') {
108			if (grp_evt < 0) {
109				ui__error(
110				   "cannot close a non-existing event group\n");
111				goto error;
112			}
113			evlist->core.nr_groups++;
114			grp_leader = NULL;
115			grp_evt = -1;
116		}
117	}
118	free(p_orig);
119	return 0;
120error:
121	free(p_orig);
122	return -1;
123}
124
125static const char *srcs[PFM_ATTR_CTRL_MAX] = {
126	[PFM_ATTR_CTRL_UNKNOWN] = "???",
127	[PFM_ATTR_CTRL_PMU] = "PMU",
128	[PFM_ATTR_CTRL_PERF_EVENT] = "perf_event",
129};
130
131static void
132print_attr_flags(pfm_event_attr_info_t *info)
133{
134	int n = 0;
135
136	if (info->is_dfl) {
137		printf("[default] ");
138		n++;
139	}
140
141	if (info->is_precise) {
142		printf("[precise] ");
143		n++;
144	}
145
146	if (!n)
147		printf("- ");
148}
149
150static void
151print_libpfm_events_detailed(pfm_event_info_t *info, bool long_desc)
152{
153	pfm_event_attr_info_t ainfo;
154	const char *src;
155	int j, ret;
156
157	ainfo.size = sizeof(ainfo);
158
159	printf("  %s\n", info->name);
160	printf("    [%s]\n", info->desc);
161	if (long_desc) {
162		if (info->equiv)
163			printf("      Equiv: %s\n", info->equiv);
164
165		printf("      Code  : 0x%"PRIx64"\n", info->code);
166	}
167	pfm_for_each_event_attr(j, info) {
168		ret = pfm_get_event_attr_info(info->idx, j,
169					      PFM_OS_PERF_EVENT_EXT, &ainfo);
170		if (ret != PFM_SUCCESS)
171			continue;
172
173		if (ainfo.type == PFM_ATTR_UMASK) {
174			printf("      %s:%s\n", info->name, ainfo.name);
175			printf("        [%s]\n", ainfo.desc);
176		}
177
178		if (!long_desc)
179			continue;
180
181		if (ainfo.ctrl >= PFM_ATTR_CTRL_MAX)
182			ainfo.ctrl = PFM_ATTR_CTRL_UNKNOWN;
183
184		src = srcs[ainfo.ctrl];
185		switch (ainfo.type) {
186		case PFM_ATTR_UMASK:
187			printf("        Umask : 0x%02"PRIx64" : %s: ",
188				ainfo.code, src);
189			print_attr_flags(&ainfo);
190			putchar('\n');
191			break;
192		case PFM_ATTR_MOD_BOOL:
193			printf("      Modif : %s: [%s] : %s (boolean)\n", src,
194				ainfo.name, ainfo.desc);
195			break;
196		case PFM_ATTR_MOD_INTEGER:
197			printf("      Modif : %s: [%s] : %s (integer)\n", src,
198				ainfo.name, ainfo.desc);
199			break;
200		case PFM_ATTR_NONE:
201		case PFM_ATTR_RAW_UMASK:
202		case PFM_ATTR_MAX:
203		default:
204			printf("      Attr  : %s: [%s] : %s\n", src,
205				ainfo.name, ainfo.desc);
206		}
207	}
208}
209
210/*
211 * list all pmu::event:umask, pmu::event
212 * printed events may not be all valid combinations of umask for an event
213 */
214static void
215print_libpfm_events_raw(pfm_pmu_info_t *pinfo, pfm_event_info_t *info)
216{
217	pfm_event_attr_info_t ainfo;
218	int j, ret;
219	bool has_umask = false;
220
221	ainfo.size = sizeof(ainfo);
222
223	pfm_for_each_event_attr(j, info) {
224		ret = pfm_get_event_attr_info(info->idx, j,
225					      PFM_OS_PERF_EVENT_EXT, &ainfo);
226		if (ret != PFM_SUCCESS)
227			continue;
228
229		if (ainfo.type != PFM_ATTR_UMASK)
230			continue;
231
232		printf("%s::%s:%s\n", pinfo->name, info->name, ainfo.name);
233		has_umask = true;
234	}
235	if (!has_umask)
236		printf("%s::%s\n", pinfo->name, info->name);
237}
238
239void print_libpfm_events(bool name_only, bool long_desc)
240{
241	pfm_event_info_t info;
242	pfm_pmu_info_t pinfo;
243	int i, p, ret;
244
245	libpfm_initialize();
246
247	/* initialize to zero to indicate ABI version */
248	info.size  = sizeof(info);
249	pinfo.size = sizeof(pinfo);
250
251	if (!name_only)
252		puts("\nList of pre-defined events (to be used in --pfm-events):\n");
253
254	pfm_for_all_pmus(p) {
255		bool printed_pmu = false;
256
257		ret = pfm_get_pmu_info(p, &pinfo);
258		if (ret != PFM_SUCCESS)
259			continue;
260
261		/* only print events that are supported by host HW */
262		if (!pinfo.is_present)
263			continue;
264
265		/* handled by perf directly */
266		if (pinfo.pmu == PFM_PMU_PERF_EVENT)
267			continue;
268
269		for (i = pinfo.first_event; i != -1;
270		     i = pfm_get_event_next(i)) {
271
272			ret = pfm_get_event_info(i, PFM_OS_PERF_EVENT_EXT,
273						&info);
274			if (ret != PFM_SUCCESS)
275				continue;
276
277			if (!name_only && !printed_pmu) {
278				printf("%s:\n", pinfo.name);
279				printed_pmu = true;
280			}
281
282			if (!name_only)
283				print_libpfm_events_detailed(&info, long_desc);
284			else
285				print_libpfm_events_raw(&pinfo, &info);
286		}
287		if (!name_only && printed_pmu)
288			putchar('\n');
289	}
290}