Linux Audio

Check our new training course

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