Linux Audio

Check our new training course

Loading...
v3.15
 
  1#include <linux/list.h>
  2#include <sys/types.h>
 
  3#include <unistd.h>
  4#include <stdio.h>
  5#include <dirent.h>
  6#include <api/fs/fs.h>
  7#include <locale.h>
  8#include "util.h"
  9#include "pmu.h"
 10#include "parse-events.h"
 11#include "cpumap.h"
 12
 13#define UNIT_MAX_LEN	31 /* max length for event unit name */
 14
 15struct perf_pmu_alias {
 16	char *name;
 17	struct list_head terms;
 18	struct list_head list;
 19	char unit[UNIT_MAX_LEN+1];
 20	double scale;
 21};
 22
 23struct perf_pmu_format {
 24	char *name;
 25	int value;
 26	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
 27	struct list_head list;
 28};
 29
 30#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
 31
 32int perf_pmu_parse(struct list_head *list, char *name);
 33extern FILE *perf_pmu_in;
 34
 35static LIST_HEAD(pmus);
 36
 37/*
 38 * Parse & process all the sysfs attributes located under
 39 * the directory specified in 'dir' parameter.
 40 */
 41int perf_pmu__format_parse(char *dir, struct list_head *head)
 42{
 43	struct dirent *evt_ent;
 44	DIR *format_dir;
 45	int ret = 0;
 46
 47	format_dir = opendir(dir);
 48	if (!format_dir)
 49		return -EINVAL;
 50
 51	while (!ret && (evt_ent = readdir(format_dir))) {
 52		char path[PATH_MAX];
 53		char *name = evt_ent->d_name;
 54		FILE *file;
 55
 56		if (!strcmp(name, ".") || !strcmp(name, ".."))
 57			continue;
 58
 59		snprintf(path, PATH_MAX, "%s/%s", dir, name);
 60
 61		ret = -EINVAL;
 62		file = fopen(path, "r");
 63		if (!file)
 64			break;
 65
 66		perf_pmu_in = file;
 67		ret = perf_pmu_parse(head, name);
 68		fclose(file);
 69	}
 70
 71	closedir(format_dir);
 72	return ret;
 73}
 74
 75/*
 76 * Reading/parsing the default pmu format definition, which should be
 77 * located at:
 78 * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
 79 */
 80static int pmu_format(const char *name, struct list_head *format)
 81{
 82	struct stat st;
 83	char path[PATH_MAX];
 84	const char *sysfs = sysfs__mountpoint();
 85
 
 86	if (!sysfs)
 87		return -1;
 88
 89	snprintf(path, PATH_MAX,
 90		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);
 91
 92	if (stat(path, &st) < 0)
 93		return 0;	/* no error if format does not exist */
 94
 95	if (perf_pmu__format_parse(path, format))
 96		return -1;
 97
 98	return 0;
 99}
100
101static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name)
102{
103	struct stat st;
104	ssize_t sret;
105	char scale[128];
106	int fd, ret = -1;
107	char path[PATH_MAX];
108	const char *lc;
109
110	snprintf(path, PATH_MAX, "%s/%s.scale", dir, name);
111
112	fd = open(path, O_RDONLY);
113	if (fd == -1)
114		return -1;
115
116	if (fstat(fd, &st) < 0)
117		goto error;
118
119	sret = read(fd, scale, sizeof(scale)-1);
120	if (sret < 0)
121		goto error;
122
123	scale[sret] = '\0';
124	/*
125	 * save current locale
126	 */
127	lc = setlocale(LC_NUMERIC, NULL);
128
129	/*
130	 * force to C locale to ensure kernel
131	 * scale string is converted correctly.
132	 * kernel uses default C locale.
133	 */
134	setlocale(LC_NUMERIC, "C");
135
136	alias->scale = strtod(scale, NULL);
137
138	/* restore locale */
139	setlocale(LC_NUMERIC, lc);
140
141	ret = 0;
142error:
143	close(fd);
144	return ret;
145}
146
147static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name)
148{
149	char path[PATH_MAX];
150	ssize_t sret;
151	int fd;
152
153	snprintf(path, PATH_MAX, "%s/%s.unit", dir, name);
154
155	fd = open(path, O_RDONLY);
156	if (fd == -1)
157		return -1;
158
159		sret = read(fd, alias->unit, UNIT_MAX_LEN);
160	if (sret < 0)
161		goto error;
162
163	close(fd);
164
165	alias->unit[sret] = '\0';
166
167	return 0;
168error:
169	close(fd);
170	alias->unit[0] = '\0';
171	return -1;
172}
173
174static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file)
175{
176	struct perf_pmu_alias *alias;
177	char buf[256];
178	int ret;
179
180	ret = fread(buf, 1, sizeof(buf), file);
181	if (ret == 0)
182		return -EINVAL;
183	buf[ret] = 0;
184
185	alias = malloc(sizeof(*alias));
186	if (!alias)
187		return -ENOMEM;
188
189	INIT_LIST_HEAD(&alias->terms);
190	alias->scale = 1.0;
191	alias->unit[0] = '\0';
192
193	ret = parse_events_terms(&alias->terms, buf);
194	if (ret) {
195		free(alias);
196		return ret;
197	}
198
199	alias->name = strdup(name);
200	/*
201	 * load unit name and scale if available
202	 */
203	perf_pmu__parse_unit(alias, dir, name);
204	perf_pmu__parse_scale(alias, dir, name);
205
206	list_add_tail(&alias->list, list);
207
208	return 0;
209}
210
211/*
212 * Process all the sysfs attributes located under the directory
213 * specified in 'dir' parameter.
214 */
215static int pmu_aliases_parse(char *dir, struct list_head *head)
216{
217	struct dirent *evt_ent;
218	DIR *event_dir;
219	size_t len;
220	int ret = 0;
221
222	event_dir = opendir(dir);
223	if (!event_dir)
224		return -EINVAL;
225
226	while (!ret && (evt_ent = readdir(event_dir))) {
227		char path[PATH_MAX];
228		char *name = evt_ent->d_name;
229		FILE *file;
230
231		if (!strcmp(name, ".") || !strcmp(name, ".."))
232			continue;
233
234		/*
235		 * skip .unit and .scale info files
236		 * parsed in perf_pmu__new_alias()
237		 */
238		len = strlen(name);
239		if (len > 5 && !strcmp(name + len - 5, ".unit"))
240			continue;
241		if (len > 6 && !strcmp(name + len - 6, ".scale"))
242			continue;
243
244		snprintf(path, PATH_MAX, "%s/%s", dir, name);
245
246		ret = -EINVAL;
247		file = fopen(path, "r");
248		if (!file)
249			break;
250
251		ret = perf_pmu__new_alias(head, dir, name, file);
252		fclose(file);
253	}
254
255	closedir(event_dir);
256	return ret;
257}
258
259/*
260 * Reading the pmu event aliases definition, which should be located at:
261 * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
262 */
263static int pmu_aliases(const char *name, struct list_head *head)
264{
265	struct stat st;
266	char path[PATH_MAX];
267	const char *sysfs = sysfs__mountpoint();
268
269	if (!sysfs)
270		return -1;
271
272	snprintf(path, PATH_MAX,
273		 "%s/bus/event_source/devices/%s/events", sysfs, name);
274
275	if (stat(path, &st) < 0)
276		return 0;	 /* no error if 'events' does not exist */
277
278	if (pmu_aliases_parse(path, head))
279		return -1;
280
281	return 0;
282}
283
284static int pmu_alias_terms(struct perf_pmu_alias *alias,
285			   struct list_head *terms)
286{
287	struct parse_events_term *term, *clone;
288	LIST_HEAD(list);
289	int ret;
290
291	list_for_each_entry(term, &alias->terms, list) {
292		ret = parse_events_term__clone(&clone, term);
293		if (ret) {
294			parse_events__free_terms(&list);
295			return ret;
296		}
297		list_add_tail(&clone->list, &list);
298	}
299	list_splice(&list, terms);
300	return 0;
301}
302
303/*
304 * Reading/parsing the default pmu type value, which should be
305 * located at:
306 * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
307 */
308static int pmu_type(const char *name, __u32 *type)
309{
310	struct stat st;
311	char path[PATH_MAX];
 
312	FILE *file;
313	int ret = 0;
314	const char *sysfs = sysfs__mountpoint();
315
 
316	if (!sysfs)
317		return -1;
318
319	snprintf(path, PATH_MAX,
320		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);
321
322	if (stat(path, &st) < 0)
323		return -1;
324
325	file = fopen(path, "r");
326	if (!file)
327		return -EINVAL;
328
329	if (1 != fscanf(file, "%u", type))
330		ret = -1;
331
332	fclose(file);
333	return ret;
334}
335
336/* Add all pmus in sysfs to pmu list: */
337static void pmu_read_sysfs(void)
338{
339	char path[PATH_MAX];
340	DIR *dir;
341	struct dirent *dent;
342	const char *sysfs = sysfs__mountpoint();
343
344	if (!sysfs)
345		return;
346
347	snprintf(path, PATH_MAX,
348		 "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
349
350	dir = opendir(path);
351	if (!dir)
352		return;
353
354	while ((dent = readdir(dir))) {
355		if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
356			continue;
357		/* add to static LIST_HEAD(pmus): */
358		perf_pmu__find(dent->d_name);
359	}
360
361	closedir(dir);
362}
363
364static struct cpu_map *pmu_cpumask(const char *name)
365{
366	struct stat st;
367	char path[PATH_MAX];
368	FILE *file;
369	struct cpu_map *cpus;
370	const char *sysfs = sysfs__mountpoint();
371
372	if (!sysfs)
373		return NULL;
374
375	snprintf(path, PATH_MAX,
376		 "%s/bus/event_source/devices/%s/cpumask", sysfs, name);
377
378	if (stat(path, &st) < 0)
379		return NULL;
380
381	file = fopen(path, "r");
382	if (!file)
383		return NULL;
384
385	cpus = cpu_map__read(file);
386	fclose(file);
387	return cpus;
388}
389
390static struct perf_pmu *pmu_lookup(const char *name)
391{
392	struct perf_pmu *pmu;
393	LIST_HEAD(format);
394	LIST_HEAD(aliases);
395	__u32 type;
396
397	/*
398	 * The pmu data we store & need consists of the pmu
399	 * type value and format definitions. Load both right
400	 * now.
401	 */
402	if (pmu_format(name, &format))
403		return NULL;
404
405	if (pmu_aliases(name, &aliases))
406		return NULL;
407
408	if (pmu_type(name, &type))
409		return NULL;
410
411	pmu = zalloc(sizeof(*pmu));
412	if (!pmu)
413		return NULL;
414
415	pmu->cpus = pmu_cpumask(name);
416
417	INIT_LIST_HEAD(&pmu->format);
418	INIT_LIST_HEAD(&pmu->aliases);
419	list_splice(&format, &pmu->format);
420	list_splice(&aliases, &pmu->aliases);
421	pmu->name = strdup(name);
422	pmu->type = type;
423	list_add_tail(&pmu->list, &pmus);
424	return pmu;
425}
426
427static struct perf_pmu *pmu_find(const char *name)
428{
429	struct perf_pmu *pmu;
430
431	list_for_each_entry(pmu, &pmus, list)
432		if (!strcmp(pmu->name, name))
433			return pmu;
434
435	return NULL;
436}
437
438struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
439{
440	/*
441	 * pmu iterator: If pmu is NULL, we start at the begin,
442	 * otherwise return the next pmu. Returns NULL on end.
443	 */
444	if (!pmu) {
445		pmu_read_sysfs();
446		pmu = list_prepare_entry(pmu, &pmus, list);
447	}
448	list_for_each_entry_continue(pmu, &pmus, list)
449		return pmu;
450	return NULL;
451}
452
453struct perf_pmu *perf_pmu__find(const char *name)
454{
455	struct perf_pmu *pmu;
456
457	/*
458	 * Once PMU is loaded it stays in the list,
459	 * so we keep us from multiple reading/parsing
460	 * the pmu format definitions.
461	 */
462	pmu = pmu_find(name);
463	if (pmu)
464		return pmu;
465
466	return pmu_lookup(name);
467}
468
469static struct perf_pmu_format *
470pmu_find_format(struct list_head *formats, char *name)
471{
472	struct perf_pmu_format *format;
473
474	list_for_each_entry(format, formats, list)
475		if (!strcmp(format->name, name))
476			return format;
477
478	return NULL;
479}
480
481/*
482 * Returns value based on the format definition (format parameter)
483 * and unformated value (value parameter).
484 *
485 * TODO maybe optimize a little ;)
486 */
487static __u64 pmu_format_value(unsigned long *format, __u64 value)
488{
489	unsigned long fbit, vbit;
490	__u64 v = 0;
491
492	for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
493
494		if (!test_bit(fbit, format))
495			continue;
496
497		if (!(value & (1llu << vbit++)))
498			continue;
499
500		v |= (1llu << fbit);
501	}
502
503	return v;
504}
505
506/*
507 * Setup one of config[12] attr members based on the
508 * user input data - term parameter.
509 */
510static int pmu_config_term(struct list_head *formats,
511			   struct perf_event_attr *attr,
512			   struct parse_events_term *term)
513{
514	struct perf_pmu_format *format;
515	__u64 *vp;
516
517	/*
518	 * Support only for hardcoded and numnerial terms.
519	 * Hardcoded terms should be already in, so nothing
520	 * to be done for them.
521	 */
522	if (parse_events__is_hardcoded_term(term))
523		return 0;
524
525	if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
526		return -EINVAL;
527
528	format = pmu_find_format(formats, term->config);
529	if (!format)
530		return -EINVAL;
531
532	switch (format->value) {
533	case PERF_PMU_FORMAT_VALUE_CONFIG:
534		vp = &attr->config;
535		break;
536	case PERF_PMU_FORMAT_VALUE_CONFIG1:
537		vp = &attr->config1;
538		break;
539	case PERF_PMU_FORMAT_VALUE_CONFIG2:
540		vp = &attr->config2;
541		break;
542	default:
543		return -EINVAL;
544	}
545
546	/*
547	 * XXX If we ever decide to go with string values for
548	 * non-hardcoded terms, here's the place to translate
549	 * them into value.
550	 */
551	*vp |= pmu_format_value(format->bits, term->val.num);
552	return 0;
553}
554
555int perf_pmu__config_terms(struct list_head *formats,
556			   struct perf_event_attr *attr,
557			   struct list_head *head_terms)
558{
559	struct parse_events_term *term;
560
561	list_for_each_entry(term, head_terms, list)
562		if (pmu_config_term(formats, attr, term))
563			return -EINVAL;
564
565	return 0;
566}
567
568/*
569 * Configures event's 'attr' parameter based on the:
570 * 1) users input - specified in terms parameter
571 * 2) pmu format definitions - specified by pmu parameter
572 */
573int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
574		     struct list_head *head_terms)
575{
576	attr->type = pmu->type;
577	return perf_pmu__config_terms(&pmu->format, attr, head_terms);
578}
579
580static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
581					     struct parse_events_term *term)
582{
583	struct perf_pmu_alias *alias;
584	char *name;
585
586	if (parse_events__is_hardcoded_term(term))
587		return NULL;
588
589	if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
590		if (term->val.num != 1)
591			return NULL;
592		if (pmu_find_format(&pmu->format, term->config))
593			return NULL;
594		name = term->config;
595	} else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
596		if (strcasecmp(term->config, "event"))
597			return NULL;
598		name = term->val.str;
599	} else {
600		return NULL;
601	}
602
603	list_for_each_entry(alias, &pmu->aliases, list) {
604		if (!strcasecmp(alias->name, name))
605			return alias;
606	}
607	return NULL;
608}
609
610
611static int check_unit_scale(struct perf_pmu_alias *alias,
612			    const char **unit, double *scale)
613{
614	/*
615	 * Only one term in event definition can
616	 * define unit and scale, fail if there's
617	 * more than one.
618	 */
619	if ((*unit && alias->unit) ||
620	    (*scale && alias->scale))
621		return -EINVAL;
622
623	if (alias->unit)
624		*unit = alias->unit;
625
626	if (alias->scale)
627		*scale = alias->scale;
628
629	return 0;
630}
631
632/*
633 * Find alias in the terms list and replace it with the terms
634 * defined for the alias
635 */
636int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
637			  const char **unit, double *scale)
638{
639	struct parse_events_term *term, *h;
640	struct perf_pmu_alias *alias;
641	int ret;
642
643	/*
644	 * Mark unit and scale as not set
645	 * (different from default values, see below)
646	 */
647	*unit   = NULL;
648	*scale  = 0.0;
649
650	list_for_each_entry_safe(term, h, head_terms, list) {
651		alias = pmu_find_alias(pmu, term);
652		if (!alias)
653			continue;
654		ret = pmu_alias_terms(alias, &term->list);
655		if (ret)
656			return ret;
657
658		ret = check_unit_scale(alias, unit, scale);
659		if (ret)
660			return ret;
661
662		list_del(&term->list);
663		free(term);
664	}
665
666	/*
667	 * if no unit or scale foundin aliases, then
668	 * set defaults as for evsel
669	 * unit cannot left to NULL
670	 */
671	if (*unit == NULL)
672		*unit   = "";
673
674	if (*scale == 0.0)
675		*scale  = 1.0;
676
677	return 0;
678}
679
680int perf_pmu__new_format(struct list_head *list, char *name,
681			 int config, unsigned long *bits)
682{
683	struct perf_pmu_format *format;
684
685	format = zalloc(sizeof(*format));
686	if (!format)
687		return -ENOMEM;
688
689	format->name = strdup(name);
690	format->value = config;
691	memcpy(format->bits, bits, sizeof(format->bits));
692
693	list_add_tail(&format->list, list);
694	return 0;
695}
696
697void perf_pmu__set_format(unsigned long *bits, long from, long to)
698{
699	long b;
700
701	if (!to)
702		to = from;
703
704	memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS));
705	for (b = from; b <= to; b++)
706		set_bit(b, bits);
707}
708
709static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
710			  struct perf_pmu_alias *alias)
711{
712	snprintf(buf, len, "%s/%s/", pmu->name, alias->name);
713	return buf;
714}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
715
716static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
717			     struct perf_pmu_alias *alias)
 
 
 
718{
719	snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name);
720	return buf;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
721}
722
723static int cmp_string(const void *a, const void *b)
 
724{
725	const char * const *as = a;
726	const char * const *bs = b;
727	return strcmp(*as, *bs);
 
 
 
 
728}
729
730void print_pmu_events(const char *event_glob, bool name_only)
731{
732	struct perf_pmu *pmu;
733	struct perf_pmu_alias *alias;
734	char buf[1024];
735	int printed = 0;
736	int len, j;
737	char **aliases;
738
739	pmu = NULL;
740	len = 0;
741	while ((pmu = perf_pmu__scan(pmu)) != NULL)
742		list_for_each_entry(alias, &pmu->aliases, list)
743			len++;
744	aliases = malloc(sizeof(char *) * len);
745	if (!aliases)
746		return;
747	pmu = NULL;
748	j = 0;
749	while ((pmu = perf_pmu__scan(pmu)) != NULL)
750		list_for_each_entry(alias, &pmu->aliases, list) {
751			char *name = format_alias(buf, sizeof(buf), pmu, alias);
752			bool is_cpu = !strcmp(pmu->name, "cpu");
753
754			if (event_glob != NULL &&
755			    !(strglobmatch(name, event_glob) ||
756			      (!is_cpu && strglobmatch(alias->name,
757						       event_glob))))
758				continue;
759			aliases[j] = name;
760			if (is_cpu && !name_only)
761				aliases[j] = format_alias_or(buf, sizeof(buf),
762							      pmu, alias);
763			aliases[j] = strdup(aliases[j]);
764			j++;
765		}
766	len = j;
767	qsort(aliases, len, sizeof(char *), cmp_string);
768	for (j = 0; j < len; j++) {
769		if (name_only) {
770			printf("%s ", aliases[j]);
771			continue;
772		}
773		printf("  %-50s [Kernel PMU event]\n", aliases[j]);
774		zfree(&aliases[j]);
775		printed++;
776	}
777	if (printed)
778		printf("\n");
779	free(aliases);
780}
781
782bool pmu_have_event(const char *pname, const char *name)
 
 
783{
784	struct perf_pmu *pmu;
785	struct perf_pmu_alias *alias;
 
 
786
787	pmu = NULL;
788	while ((pmu = perf_pmu__scan(pmu)) != NULL) {
789		if (strcmp(pname, pmu->name))
790			continue;
791		list_for_each_entry(alias, &pmu->aliases, list)
792			if (!strcmp(alias->name, name))
793				return true;
794	}
795	return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
796}
v3.5.6
  1
  2#include <linux/list.h>
  3#include <sys/types.h>
  4#include <sys/stat.h>
  5#include <unistd.h>
  6#include <stdio.h>
  7#include <dirent.h>
  8#include "sysfs.h"
 
  9#include "util.h"
 10#include "pmu.h"
 11#include "parse-events.h"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 12
 13int perf_pmu_parse(struct list_head *list, char *name);
 14extern FILE *perf_pmu_in;
 15
 16static LIST_HEAD(pmus);
 17
 18/*
 19 * Parse & process all the sysfs attributes located under
 20 * the directory specified in 'dir' parameter.
 21 */
 22static int pmu_format_parse(char *dir, struct list_head *head)
 23{
 24	struct dirent *evt_ent;
 25	DIR *format_dir;
 26	int ret = 0;
 27
 28	format_dir = opendir(dir);
 29	if (!format_dir)
 30		return -EINVAL;
 31
 32	while (!ret && (evt_ent = readdir(format_dir))) {
 33		char path[PATH_MAX];
 34		char *name = evt_ent->d_name;
 35		FILE *file;
 36
 37		if (!strcmp(name, ".") || !strcmp(name, ".."))
 38			continue;
 39
 40		snprintf(path, PATH_MAX, "%s/%s", dir, name);
 41
 42		ret = -EINVAL;
 43		file = fopen(path, "r");
 44		if (!file)
 45			break;
 46
 47		perf_pmu_in = file;
 48		ret = perf_pmu_parse(head, name);
 49		fclose(file);
 50	}
 51
 52	closedir(format_dir);
 53	return ret;
 54}
 55
 56/*
 57 * Reading/parsing the default pmu format definition, which should be
 58 * located at:
 59 * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
 60 */
 61static int pmu_format(char *name, struct list_head *format)
 62{
 63	struct stat st;
 64	char path[PATH_MAX];
 65	const char *sysfs;
 66
 67	sysfs = sysfs_find_mountpoint();
 68	if (!sysfs)
 69		return -1;
 70
 71	snprintf(path, PATH_MAX,
 72		 "%s/bus/event_source/devices/%s/format", sysfs, name);
 73
 74	if (stat(path, &st) < 0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 75		return -1;
 76
 77	if (pmu_format_parse(path, format))
 
 
 
 
 
 
 78		return -1;
 79
 80	return 0;
 81}
 82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 83/*
 84 * Reading/parsing the default pmu type value, which should be
 85 * located at:
 86 * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
 87 */
 88static int pmu_type(char *name, __u32 *type)
 89{
 90	struct stat st;
 91	char path[PATH_MAX];
 92	const char *sysfs;
 93	FILE *file;
 94	int ret = 0;
 
 95
 96	sysfs = sysfs_find_mountpoint();
 97	if (!sysfs)
 98		return -1;
 99
100	snprintf(path, PATH_MAX,
101		 "%s/bus/event_source/devices/%s/type", sysfs, name);
102
103	if (stat(path, &st) < 0)
104		return -1;
105
106	file = fopen(path, "r");
107	if (!file)
108		return -EINVAL;
109
110	if (1 != fscanf(file, "%u", type))
111		ret = -1;
112
113	fclose(file);
114	return ret;
115}
116
117static struct perf_pmu *pmu_lookup(char *name)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118{
119	struct perf_pmu *pmu;
120	LIST_HEAD(format);
 
121	__u32 type;
122
123	/*
124	 * The pmu data we store & need consists of the pmu
125	 * type value and format definitions. Load both right
126	 * now.
127	 */
128	if (pmu_format(name, &format))
129		return NULL;
130
 
 
 
131	if (pmu_type(name, &type))
132		return NULL;
133
134	pmu = zalloc(sizeof(*pmu));
135	if (!pmu)
136		return NULL;
137
 
 
138	INIT_LIST_HEAD(&pmu->format);
 
139	list_splice(&format, &pmu->format);
 
140	pmu->name = strdup(name);
141	pmu->type = type;
 
142	return pmu;
143}
144
145static struct perf_pmu *pmu_find(char *name)
146{
147	struct perf_pmu *pmu;
148
149	list_for_each_entry(pmu, &pmus, list)
150		if (!strcmp(pmu->name, name))
151			return pmu;
152
153	return NULL;
154}
155
156struct perf_pmu *perf_pmu__find(char *name)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157{
158	struct perf_pmu *pmu;
159
160	/*
161	 * Once PMU is loaded it stays in the list,
162	 * so we keep us from multiple reading/parsing
163	 * the pmu format definitions.
164	 */
165	pmu = pmu_find(name);
166	if (pmu)
167		return pmu;
168
169	return pmu_lookup(name);
170}
171
172static struct perf_pmu__format*
173pmu_find_format(struct list_head *formats, char *name)
174{
175	struct perf_pmu__format *format;
176
177	list_for_each_entry(format, formats, list)
178		if (!strcmp(format->name, name))
179			return format;
180
181	return NULL;
182}
183
184/*
185 * Returns value based on the format definition (format parameter)
186 * and unformated value (value parameter).
187 *
188 * TODO maybe optimize a little ;)
189 */
190static __u64 pmu_format_value(unsigned long *format, __u64 value)
191{
192	unsigned long fbit, vbit;
193	__u64 v = 0;
194
195	for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
196
197		if (!test_bit(fbit, format))
198			continue;
199
200		if (!(value & (1llu << vbit++)))
201			continue;
202
203		v |= (1llu << fbit);
204	}
205
206	return v;
207}
208
209/*
210 * Setup one of config[12] attr members based on the
211 * user input data - temr parameter.
212 */
213static int pmu_config_term(struct list_head *formats,
214			   struct perf_event_attr *attr,
215			   struct parse_events__term *term)
216{
217	struct perf_pmu__format *format;
218	__u64 *vp;
219
220	/*
221	 * Support only for hardcoded and numnerial terms.
222	 * Hardcoded terms should be already in, so nothing
223	 * to be done for them.
224	 */
225	if (parse_events__is_hardcoded_term(term))
226		return 0;
227
228	if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
229		return -EINVAL;
230
231	format = pmu_find_format(formats, term->config);
232	if (!format)
233		return -EINVAL;
234
235	switch (format->value) {
236	case PERF_PMU_FORMAT_VALUE_CONFIG:
237		vp = &attr->config;
238		break;
239	case PERF_PMU_FORMAT_VALUE_CONFIG1:
240		vp = &attr->config1;
241		break;
242	case PERF_PMU_FORMAT_VALUE_CONFIG2:
243		vp = &attr->config2;
244		break;
245	default:
246		return -EINVAL;
247	}
248
249	/*
250	 * XXX If we ever decide to go with string values for
251	 * non-hardcoded terms, here's the place to translate
252	 * them into value.
253	 */
254	*vp |= pmu_format_value(format->bits, term->val.num);
255	return 0;
256}
257
258static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
259		      struct list_head *head_terms)
 
260{
261	struct parse_events__term *term;
262
263	list_for_each_entry(term, head_terms, list)
264		if (pmu_config_term(formats, attr, term))
265			return -EINVAL;
266
267	return 0;
268}
269
270/*
271 * Configures event's 'attr' parameter based on the:
272 * 1) users input - specified in terms parameter
273 * 2) pmu format definitions - specified by pmu parameter
274 */
275int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
276		     struct list_head *head_terms)
277{
278	attr->type = pmu->type;
279	return pmu_config(&pmu->format, attr, head_terms);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280}
281
282int perf_pmu__new_format(struct list_head *list, char *name,
283			 int config, unsigned long *bits)
284{
285	struct perf_pmu__format *format;
286
287	format = zalloc(sizeof(*format));
288	if (!format)
289		return -ENOMEM;
290
291	format->name = strdup(name);
292	format->value = config;
293	memcpy(format->bits, bits, sizeof(format->bits));
294
295	list_add_tail(&format->list, list);
296	return 0;
297}
298
299void perf_pmu__set_format(unsigned long *bits, long from, long to)
300{
301	long b;
302
303	if (!to)
304		to = from;
305
306	memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
307	for (b = from; b <= to; b++)
308		set_bit(b, bits);
309}
310
311/* Simulated format definitions. */
312static struct test_format {
313	const char *name;
314	const char *value;
315} test_formats[] = {
316	{ "krava01", "config:0-1,62-63\n", },
317	{ "krava02", "config:10-17\n", },
318	{ "krava03", "config:5\n", },
319	{ "krava11", "config1:0,2,4,6,8,20-28\n", },
320	{ "krava12", "config1:63\n", },
321	{ "krava13", "config1:45-47\n", },
322	{ "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
323	{ "krava22", "config2:8,18,48,58\n", },
324	{ "krava23", "config2:28-29,38\n", },
325};
326
327#define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
328
329/* Simulated users input. */
330static struct parse_events__term test_terms[] = {
331	{
332		.config    = (char *) "krava01",
333		.val.num   = 15,
334		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
335		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
336	},
337	{
338		.config    = (char *) "krava02",
339		.val.num   = 170,
340		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
341		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
342	},
343	{
344		.config    = (char *) "krava03",
345		.val.num   = 1,
346		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
347		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
348	},
349	{
350		.config    = (char *) "krava11",
351		.val.num   = 27,
352		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
353		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
354	},
355	{
356		.config    = (char *) "krava12",
357		.val.num   = 1,
358		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
359		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
360	},
361	{
362		.config    = (char *) "krava13",
363		.val.num   = 2,
364		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
365		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
366	},
367	{
368		.config    = (char *) "krava21",
369		.val.num   = 119,
370		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
371		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
372	},
373	{
374		.config    = (char *) "krava22",
375		.val.num   = 11,
376		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
377		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
378	},
379	{
380		.config    = (char *) "krava23",
381		.val.num   = 2,
382		.type_val  = PARSE_EVENTS__TERM_TYPE_NUM,
383		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
384	},
385};
386#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
387
388/*
389 * Prepare format directory data, exported by kernel
390 * at /sys/bus/event_source/devices/<dev>/format.
391 */
392static char *test_format_dir_get(void)
393{
394	static char dir[PATH_MAX];
395	unsigned int i;
396
397	snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
398	if (!mkdtemp(dir))
399		return NULL;
400
401	for (i = 0; i < TEST_FORMATS_CNT; i++) {
402		static char name[PATH_MAX];
403		struct test_format *format = &test_formats[i];
404		FILE *file;
405
406		snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
407
408		file = fopen(name, "w");
409		if (!file)
410			return NULL;
411
412		if (1 != fwrite(format->value, strlen(format->value), 1, file))
413			break;
414
415		fclose(file);
416	}
417
418	return dir;
419}
420
421/* Cleanup format directory. */
422static int test_format_dir_put(char *dir)
423{
424	char buf[PATH_MAX];
425	snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
426	if (system(buf))
427		return -1;
428
429	snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
430	return system(buf);
431}
432
433static struct list_head *test_terms_list(void)
434{
435	static LIST_HEAD(terms);
436	unsigned int i;
437
438	for (i = 0; i < TERMS_CNT; i++)
439		list_add_tail(&test_terms[i].list, &terms);
440
441	return &terms;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
442}
443
444#undef TERMS_CNT
445
446int perf_pmu__test(void)
447{
448	char *format = test_format_dir_get();
449	LIST_HEAD(formats);
450	struct list_head *terms = test_terms_list();
451	int ret;
452
453	if (!format)
454		return -EINVAL;
455
456	do {
457		struct perf_event_attr attr;
458
459		memset(&attr, 0, sizeof(attr));
460
461		ret = pmu_format_parse(format, &formats);
462		if (ret)
463			break;
464
465		ret = pmu_config(&formats, &attr, terms);
466		if (ret)
467			break;
468
469		ret = -EINVAL;
470
471		if (attr.config  != 0xc00000000002a823)
472			break;
473		if (attr.config1 != 0x8000400000000145)
474			break;
475		if (attr.config2 != 0x0400000020041d07)
476			break;
477
478		ret = 0;
479	} while (0);
480
481	test_format_dir_put(format);
482	return ret;
483}