Linux Audio

Check our new training course

Buildroot integration, development and maintenance

Need a Buildroot system for your embedded project?
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			continue;
 67
 68		memset(&attr, 0, sizeof(attr));
 69		event_attr_init(&attr);
 70
 71		ret = pfm_get_perf_event_encoding(q, PFM_PLM0|PFM_PLM3,
 72						&attr, NULL, NULL);
 73
 74		if (ret != PFM_SUCCESS) {
 75			ui__error("failed to parse event %s : %s\n", str,
 76				  pfm_strerror(ret));
 77			goto error;
 78		}
 79
 80		pmu = perf_pmu__find_by_type((unsigned int)attr.type);
 81		evsel = parse_events__add_event(evlist->core.nr_entries,
 82						&attr, q, pmu);
 83		if (evsel == NULL)
 84			goto error;
 85
 86		evsel->is_libpfm_event = true;
 87
 88		evlist__add(evlist, evsel);
 89
 90		if (grp_evt == 0)
 91			grp_leader = evsel;
 92
 93		if (grp_evt > -1) {
 94			evsel->leader = grp_leader;
 95			grp_leader->core.nr_members++;
 96			grp_evt++;
 97		}
 98
 99		if (*sep == '}') {
100			if (grp_evt < 0) {
101				ui__error(
102				   "cannot close a non-existing event group\n");
103				goto error;
104			}
105			evlist->nr_groups++;
106			grp_leader = NULL;
107			grp_evt = -1;
108		}
109	}
110	return 0;
111error:
112	free(p_orig);
113	return -1;
114}
115
116static const char *srcs[PFM_ATTR_CTRL_MAX] = {
117	[PFM_ATTR_CTRL_UNKNOWN] = "???",
118	[PFM_ATTR_CTRL_PMU] = "PMU",
119	[PFM_ATTR_CTRL_PERF_EVENT] = "perf_event",
120};
121
122static void
123print_attr_flags(pfm_event_attr_info_t *info)
124{
125	int n = 0;
126
127	if (info->is_dfl) {
128		printf("[default] ");
129		n++;
130	}
131
132	if (info->is_precise) {
133		printf("[precise] ");
134		n++;
135	}
136
137	if (!n)
138		printf("- ");
139}
140
141static void
142print_libpfm_events_detailed(pfm_event_info_t *info, bool long_desc)
143{
144	pfm_event_attr_info_t ainfo;
145	const char *src;
146	int j, ret;
147
148	ainfo.size = sizeof(ainfo);
149
150	printf("  %s\n", info->name);
151	printf("    [%s]\n", info->desc);
152	if (long_desc) {
153		if (info->equiv)
154			printf("      Equiv: %s\n", info->equiv);
155
156		printf("      Code  : 0x%"PRIx64"\n", info->code);
157	}
158	pfm_for_each_event_attr(j, info) {
159		ret = pfm_get_event_attr_info(info->idx, j,
160					      PFM_OS_PERF_EVENT_EXT, &ainfo);
161		if (ret != PFM_SUCCESS)
162			continue;
163
164		if (ainfo.type == PFM_ATTR_UMASK) {
165			printf("      %s:%s\n", info->name, ainfo.name);
166			printf("        [%s]\n", ainfo.desc);
167		}
168
169		if (!long_desc)
170			continue;
171
172		if (ainfo.ctrl >= PFM_ATTR_CTRL_MAX)
173			ainfo.ctrl = PFM_ATTR_CTRL_UNKNOWN;
174
175		src = srcs[ainfo.ctrl];
176		switch (ainfo.type) {
177		case PFM_ATTR_UMASK:
178			printf("        Umask : 0x%02"PRIx64" : %s: ",
179				ainfo.code, src);
180			print_attr_flags(&ainfo);
181			putchar('\n');
182			break;
183		case PFM_ATTR_MOD_BOOL:
184			printf("      Modif : %s: [%s] : %s (boolean)\n", src,
185				ainfo.name, ainfo.desc);
186			break;
187		case PFM_ATTR_MOD_INTEGER:
188			printf("      Modif : %s: [%s] : %s (integer)\n", src,
189				ainfo.name, ainfo.desc);
190			break;
191		case PFM_ATTR_NONE:
192		case PFM_ATTR_RAW_UMASK:
193		case PFM_ATTR_MAX:
194		default:
195			printf("      Attr  : %s: [%s] : %s\n", src,
196				ainfo.name, ainfo.desc);
197		}
198	}
199}
200
201/*
202 * list all pmu::event:umask, pmu::event
203 * printed events may not be all valid combinations of umask for an event
204 */
205static void
206print_libpfm_events_raw(pfm_pmu_info_t *pinfo, pfm_event_info_t *info)
207{
208	pfm_event_attr_info_t ainfo;
209	int j, ret;
210	bool has_umask = false;
211
212	ainfo.size = sizeof(ainfo);
213
214	pfm_for_each_event_attr(j, info) {
215		ret = pfm_get_event_attr_info(info->idx, j,
216					      PFM_OS_PERF_EVENT_EXT, &ainfo);
217		if (ret != PFM_SUCCESS)
218			continue;
219
220		if (ainfo.type != PFM_ATTR_UMASK)
221			continue;
222
223		printf("%s::%s:%s\n", pinfo->name, info->name, ainfo.name);
224		has_umask = true;
225	}
226	if (!has_umask)
227		printf("%s::%s\n", pinfo->name, info->name);
228}
229
230void print_libpfm_events(bool name_only, bool long_desc)
231{
232	pfm_event_info_t info;
233	pfm_pmu_info_t pinfo;
234	int i, p, ret;
235
236	libpfm_initialize();
237
238	/* initialize to zero to indicate ABI version */
239	info.size  = sizeof(info);
240	pinfo.size = sizeof(pinfo);
241
242	if (!name_only)
243		puts("\nList of pre-defined events (to be used in --pfm-events):\n");
244
245	pfm_for_all_pmus(p) {
246		bool printed_pmu = false;
247
248		ret = pfm_get_pmu_info(p, &pinfo);
249		if (ret != PFM_SUCCESS)
250			continue;
251
252		/* only print events that are supported by host HW */
253		if (!pinfo.is_present)
254			continue;
255
256		/* handled by perf directly */
257		if (pinfo.pmu == PFM_PMU_PERF_EVENT)
258			continue;
259
260		for (i = pinfo.first_event; i != -1;
261		     i = pfm_get_event_next(i)) {
262
263			ret = pfm_get_event_info(i, PFM_OS_PERF_EVENT_EXT,
264						&info);
265			if (ret != PFM_SUCCESS)
266				continue;
267
268			if (!name_only && !printed_pmu) {
269				printf("%s:\n", pinfo.name);
270				printed_pmu = true;
271			}
272
273			if (!name_only)
274				print_libpfm_events_detailed(&info, long_desc);
275			else
276				print_libpfm_events_raw(&pinfo, &info);
277		}
278		if (!name_only && printed_pmu)
279			putchar('\n');
280	}
281}