op_events.c revision 5a4eb4eb367eccd4b976d1feae96cea96d2c50f2
1/**
2 * @file op_events.c
3 * Details of PMC profiling events
4 *
5 * You can have silliness here.
6 *
7 * @remark Copyright 2002 OProfile authors
8 * @remark Read the file COPYING
9 *
10 * @author John Levon
11 * @author Philippe Elie
12 */
13
14#include "op_events.h"
15#include "op_libiberty.h"
16#include "op_fileio.h"
17#include "op_string.h"
18#include "op_cpufreq.h"
19#include "op_hw_specific.h"
20
21#include <string.h>
22#include <stdlib.h>
23#include <stdio.h>
24
25static LIST_HEAD(events_list);
26static LIST_HEAD(um_list);
27
28static char const * filename;
29static unsigned int line_nr;
30
31static void delete_event(struct op_event * event);
32static void read_events(char const * file);
33static void read_unit_masks(char const * file);
34static void free_unit_mask(struct op_unit_mask * um);
35
36static char *build_fn(const char *cpu_name, const char *fn)
37{
38	char *s;
39	static const char *dir;
40	if (dir == NULL)
41		dir = getenv("OPROFILE_EVENTS_DIR");
42	if (dir == NULL)
43		dir = OP_DATADIR;
44	s = xmalloc(strlen(dir) + strlen(cpu_name) + strlen(fn) + 5);
45	sprintf(s, "%s/%s/%s", dir, cpu_name, fn);
46	return s;
47}
48
49static void parse_error(char const * context)
50{
51	fprintf(stderr, "oprofile: parse error in %s, line %u\n",
52		filename, line_nr);
53	fprintf(stderr, "%s\n", context);
54	exit(EXIT_FAILURE);
55}
56
57
58static int parse_int(char const * str)
59{
60	int value;
61	if (sscanf(str, "%d", &value) != 1)
62		parse_error("expected decimal value");
63
64	return value;
65}
66
67
68static int parse_hex(char const * str)
69{
70	int value;
71	/* 0x/0X to force the use of hexa notation for field intended to
72	   be in hexadecimal */
73	if (sscanf(str, "0x%x", &value) != 1 &&
74	    sscanf(str, "0X%x", &value) != 1)
75		parse_error("expected hexadecimal value");
76
77	return value;
78}
79
80
81static u64 parse_long_hex(char const * str)
82{
83	u64 value;
84	if (sscanf(str, "%Lx", &value) != 1)
85		parse_error("expected long hexadecimal value");
86
87	fflush(stderr);
88	return value;
89}
90
91static void include_um(const char *start, const char *end)
92{
93	char *s;
94	char cpu[end - start + 1];
95	int old_line_nr;
96	const char *old_filename;
97
98	strncpy(cpu, start, end - start);
99	cpu[end - start] = 0;
100	s = build_fn(cpu, "unit_masks");
101	old_line_nr = line_nr;
102	old_filename = filename;
103	read_unit_masks(s);
104	line_nr = old_line_nr;
105	filename = old_filename;
106	free(s);
107}
108
109/* name:MESI type:bitmask default:0x0f */
110static void parse_um(struct op_unit_mask * um, char const * line)
111{
112	int seen_name = 0;
113	int seen_type = 0;
114       	int seen_default = 0;
115	char const * valueend = line + 1;
116       	char const * tagend = line + 1;
117	char const * start = line;
118
119	while (*valueend) {
120		valueend = skip_nonws(valueend);
121
122		while (*tagend != ':' && *tagend)
123			++tagend;
124
125		if (valueend == tagend)
126			break;
127
128		if (!*tagend)
129			parse_error("parse_um() expected :value");
130
131		++tagend;
132
133		if (strisprefix(start, "include")) {
134			if (seen_name + seen_type + seen_default > 0)
135				parse_error("include must be on its own");
136			free_unit_mask(um);
137			include_um(tagend, valueend);
138			return;
139		}
140
141		if (strisprefix(start, "name")) {
142			if (seen_name)
143				parse_error("duplicate name: tag");
144			seen_name = 1;
145			um->name = op_xstrndup(tagend, valueend - tagend);
146		} else if (strisprefix(start, "type")) {
147			if (seen_type)
148				parse_error("duplicate type: tag");
149			seen_type = 1;
150			if (strisprefix(tagend, "mandatory")) {
151				um->unit_type_mask = utm_mandatory;
152			} else if (strisprefix(tagend, "bitmask")) {
153				um->unit_type_mask = utm_bitmask;
154			} else if (strisprefix(tagend, "exclusive")) {
155				um->unit_type_mask = utm_exclusive;
156			} else {
157				parse_error("invalid unit mask type");
158			}
159		} else if (strisprefix(start, "default")) {
160			if (seen_default)
161				parse_error("duplicate default: tag");
162			seen_default = 1;
163			um->default_mask = parse_hex(tagend);
164		} else {
165			parse_error("invalid unit mask tag");
166		}
167
168		valueend = skip_ws(valueend);
169		tagend = valueend;
170		start = valueend;
171	}
172
173	if (!um->name)
174		parse_error("Missing name for unit mask");
175	if (!seen_type)
176		parse_error("Missing type for unit mask");
177}
178
179
180/* \t0x08 (M)odified cache state */
181static void parse_um_entry(struct op_described_um * entry, char const * line)
182{
183	char const * c = line;
184
185	c = skip_ws(c);
186	entry->value = parse_hex(c);
187	c = skip_nonws(c);
188
189	if (!*c)
190		parse_error("invalid unit mask entry");
191
192	c = skip_ws(c);
193
194	if (!*c)
195		parse_error("invalid unit mask entry");
196
197	entry->desc = xstrdup(c);
198}
199
200
201static struct op_unit_mask * new_unit_mask(void)
202{
203	struct op_unit_mask * um = xmalloc(sizeof(struct op_unit_mask));
204	memset(um, '\0', sizeof(struct op_unit_mask));
205	list_add_tail(&um->um_next, &um_list);
206
207	return um;
208}
209
210static void free_unit_mask(struct op_unit_mask * um)
211{
212	list_del(&um->um_next);
213	free(um);
214}
215
216/*
217 * name:zero type:mandatory default:0x0
218 * \t0x0 No unit mask
219 */
220static void read_unit_masks(char const * file)
221{
222	struct op_unit_mask * um = NULL;
223	char * line;
224	FILE * fp = fopen(file, "r");
225
226	if (!fp) {
227		fprintf(stderr,
228			"oprofile: could not open unit mask description file %s\n", file);
229		exit(EXIT_FAILURE);
230	}
231
232	filename = file;
233	line_nr = 1;
234
235	line = op_get_line(fp);
236
237	while (line) {
238		if (empty_line(line) || comment_line(line))
239			goto next;
240
241		if (line[0] != '\t') {
242			um = new_unit_mask();
243			parse_um(um, line);
244		} else {
245			if (!um)
246				parse_error("no unit mask name line");
247			if (um->num >= MAX_UNIT_MASK)
248				parse_error("oprofile: maximum unit mask entries exceeded");
249
250			parse_um_entry(&um->um[um->num], line);
251			++(um->num);
252		}
253
254next:
255		free(line);
256		line = op_get_line(fp);
257		++line_nr;
258	}
259
260	fclose(fp);
261}
262
263
264static u32 parse_counter_mask(char const * str)
265{
266	u32 mask = 0;
267	char const * numstart = str;
268
269	while (*numstart) {
270		mask |= 1 << parse_int(numstart);
271
272		while (*numstart && *numstart != ',')
273			++numstart;
274		/* skip , unless we reach eos */
275		if (*numstart)
276			++numstart;
277
278		numstart = skip_ws(numstart);
279	}
280
281	return mask;
282}
283
284static struct op_unit_mask * try_find_um(char const * value)
285{
286	struct list_head * pos;
287
288	list_for_each(pos, &um_list) {
289		struct op_unit_mask * um = list_entry(pos, struct op_unit_mask, um_next);
290		if (strcmp(value, um->name) == 0) {
291			um->used = 1;
292			return um;
293		}
294	}
295	return NULL;
296}
297
298static struct op_unit_mask * find_um(char const * value)
299{
300	struct op_unit_mask * um = try_find_um(value);
301	if (um)
302		return um;
303	fprintf(stderr, "oprofile: could not find unit mask %s\n", value);
304	exit(EXIT_FAILURE);
305}
306
307/* um:a,b,c,d merge multiple unit masks */
308static struct op_unit_mask * merge_um(char * value)
309{
310	int num;
311	char *s;
312	struct op_unit_mask *new, *um;
313	enum unit_mask_type type = -1U;
314
315	um = try_find_um(value);
316	if (um)
317		return um;
318
319	new = new_unit_mask();
320	new->name = xstrdup(value);
321	new->used = 1;
322	num = 0;
323	while ((s = strsep(&value, ",")) != NULL) {
324		unsigned c;
325		um = find_um(s);
326		if (type == -1U)
327			type = um->unit_type_mask;
328		if (um->unit_type_mask != type)
329			parse_error("combined unit mask must be all the same types");
330		if (type != utm_bitmask && type != utm_exclusive)
331			parse_error("combined unit mask must be all bitmasks or exclusive");
332		new->default_mask |= um->default_mask;
333		new->num += um->num;
334		if (new->num > MAX_UNIT_MASK)
335			parse_error("too many members in combined unit mask");
336		for (c = 0; c < um->num; c++, num++) {
337			new->um[num] = um->um[c];
338			new->um[num].desc = xstrdup(new->um[num].desc);
339		}
340	}
341	if (type == -1U)
342		parse_error("Empty unit mask");
343	new->unit_type_mask = type;
344	return new;
345}
346
347/* parse either a "tag:value" or a ": trailing description string" */
348static int next_token(char const ** cp, char ** name, char ** value)
349{
350	size_t tag_len;
351	size_t val_len;
352	char const * c = *cp;
353	char const * end;
354	char const * colon;
355
356	c = skip_ws(c);
357	end = colon = c;
358	end = skip_nonws(end);
359
360	colon = strchr(colon, ':');
361
362	if (!colon) {
363		if (*c)
364			parse_error("next_token(): garbage at end of line");
365		return 0;
366	}
367
368	if (colon >= end)
369		parse_error("next_token() expected ':'");
370
371	tag_len = colon - c;
372	val_len = end - (colon + 1);
373
374	if (!tag_len) {
375		/* : trailing description */
376		end = skip_ws(end);
377		*name = xstrdup("desc");
378		*value = xstrdup(end);
379		end += strlen(end);
380	} else {
381		/* tag:value */
382		*name = op_xstrndup(c, tag_len);
383		*value = op_xstrndup(colon + 1, val_len);
384		end = skip_ws(end);
385	}
386
387	*cp = end;
388	return 1;
389}
390
391static void include_events (char *value)
392{
393	char * event_file;
394	const char *old_filename;
395	int old_line_nr;
396
397	event_file = build_fn(value, "events");
398	old_line_nr = line_nr;
399	old_filename = filename;
400	read_events(event_file);
401	line_nr = old_line_nr;
402	filename = old_filename;
403	free(event_file);
404}
405
406static struct op_event * new_event(void)
407{
408	struct op_event * event = xmalloc(sizeof(struct op_event));
409	memset(event, '\0', sizeof(struct op_event));
410	list_add_tail(&event->event_next, &events_list);
411
412	return event;
413}
414
415static void free_event(struct op_event * event)
416{
417	list_del(&event->event_next);
418	free(event);
419}
420
421/* event:0x00 counters:0 um:zero minimum:4096 name:ISSUES : Total issues */
422/* event:0x00 ext:xxxxxx um:zero minimum:4096 name:ISSUES : Total issues */
423static void read_events(char const * file)
424{
425	struct op_event * event = NULL;
426	char * line;
427	char * name;
428	char * value;
429	char const * c;
430	int seen_event, seen_counters, seen_um, seen_minimum, seen_name, seen_ext;
431	FILE * fp = fopen(file, "r");
432	int tags;
433
434	if (!fp) {
435		fprintf(stderr, "oprofile: could not open event description file %s\n", file);
436		exit(EXIT_FAILURE);
437	}
438
439	filename = file;
440	line_nr = 1;
441
442	line = op_get_line(fp);
443
444	while (line) {
445		if (empty_line(line) || comment_line(line))
446			goto next;
447
448		tags = 0;
449		seen_name = 0;
450		seen_event = 0;
451		seen_counters = 0;
452		seen_ext = 0;
453		seen_um = 0;
454		seen_minimum = 0;
455		event = new_event();
456		event->filter = -1;
457		event->ext = NULL;
458
459		c = line;
460		while (next_token(&c, &name, &value)) {
461			if (strcmp(name, "name") == 0) {
462				if (seen_name)
463					parse_error("duplicate name: tag");
464				seen_name = 1;
465				if (strchr(value, '/') != NULL)
466					parse_error("invalid event name");
467				if (strchr(value, '.') != NULL)
468					parse_error("invalid event name");
469				event->name = value;
470			} else if (strcmp(name, "event") == 0) {
471				if (seen_event)
472					parse_error("duplicate event: tag");
473				seen_event = 1;
474				event->val = parse_hex(value);
475				free(value);
476			} else if (strcmp(name, "counters") == 0) {
477				if (seen_counters)
478					parse_error("duplicate counters: tag");
479				seen_counters = 1;
480				if (!strcmp(value, "cpuid"))
481					event->counter_mask = arch_get_counter_mask();
482				else
483					event->counter_mask = parse_counter_mask(value);
484				free(value);
485			} else if (strcmp(name, "ext") == 0) {
486				if (seen_ext)
487					parse_error("duplicate ext: tag");
488				seen_ext = 1;
489				event->ext = value;
490			} else if (strcmp(name, "um") == 0) {
491				if (seen_um)
492					parse_error("duplicate um: tag");
493				seen_um = 1;
494				if (strchr(value, ','))
495					event->unit = merge_um(value);
496				else
497					event->unit = find_um(value);
498				free(value);
499			} else if (strcmp(name, "minimum") == 0) {
500				if (seen_minimum)
501					parse_error("duplicate minimum: tag");
502				seen_minimum = 1;
503				event->min_count = parse_int(value);
504				free(value);
505			} else if (strcmp(name, "desc") == 0) {
506				event->desc = value;
507			} else if (strcmp(name, "filter") == 0) {
508				event->filter = parse_int(value);
509				free(value);
510			} else if (strcmp(name, "include") == 0) {
511				if (tags > 0)
512					parse_error("tags before include:");
513				free_event(event);
514				include_events(value);
515				free(value);
516				c = skip_ws(c);
517				if (*c != '\0' && *c != '#')
518					parse_error("non whitespace after include:");
519			} else {
520				parse_error("unknown tag");
521			}
522			tags++;
523
524			free(name);
525		}
526next:
527		free(line);
528		line = op_get_line(fp);
529		++line_nr;
530	}
531
532	fclose(fp);
533}
534
535
536/* usefull for make check */
537static int check_unit_mask(struct op_unit_mask const * um,
538	char const * cpu_name)
539{
540	u32 i;
541	int err = 0;
542
543	if (!um->used) {
544		fprintf(stderr, "um %s is not used\n", um->name);
545		err = EXIT_FAILURE;
546	}
547
548	if (um->unit_type_mask == utm_mandatory && um->num != 1) {
549		fprintf(stderr, "mandatory um %s doesn't contain exactly one "
550			"entry (%s)\n", um->name, cpu_name);
551		err = EXIT_FAILURE;
552	} else if (um->unit_type_mask == utm_bitmask) {
553		u32 default_mask = um->default_mask;
554		for (i = 0; i < um->num; ++i)
555			default_mask &= ~um->um[i].value;
556
557		if (default_mask) {
558			fprintf(stderr, "um %s default mask is not valid "
559				"(%s)\n", um->name, cpu_name);
560			err = EXIT_FAILURE;
561		}
562	} else {
563		for (i = 0; i < um->num; ++i) {
564			if (um->default_mask == um->um[i].value)
565				break;
566		}
567
568		if (i == um->num) {
569			fprintf(stderr, "exclusive um %s default value is not "
570				"valid (%s)\n", um->name, cpu_name);
571			err = EXIT_FAILURE;
572		}
573	}
574	return err;
575}
576
577static void arch_filter_events(op_cpu cpu_type)
578{
579	struct list_head * pos, * pos2;
580	unsigned filter = arch_get_filter(cpu_type);
581	if (!filter)
582		return;
583	list_for_each_safe (pos, pos2, &events_list) {
584		struct op_event * event = list_entry(pos, struct op_event, event_next);
585		if (event->filter >= 0 && ((1U << event->filter) & filter))
586			delete_event(event);
587	}
588}
589
590static void load_events_name(const char *cpu_name)
591{
592	char * event_file;
593	char * um_file;
594
595	event_file = build_fn(cpu_name, "events");
596	um_file = build_fn(cpu_name, "unit_masks");
597
598	read_unit_masks(um_file);
599	read_events(event_file);
600
601	free(um_file);
602	free(event_file);
603}
604
605static void load_events(op_cpu cpu_type)
606{
607	const char * cpu_name = op_get_cpu_name(cpu_type);
608	struct list_head * pos;
609	int err = 0;
610
611	if (!list_empty(&events_list))
612		return;
613
614	load_events_name(cpu_name);
615
616	arch_filter_events(cpu_type);
617
618	/* sanity check: all unit mask must be used */
619	list_for_each(pos, &um_list) {
620		struct op_unit_mask * um = list_entry(pos, struct op_unit_mask, um_next);
621		err |= check_unit_mask(um, cpu_name);
622	}
623	if (err)
624		exit(err);
625}
626
627struct list_head * op_events(op_cpu cpu_type)
628{
629	load_events(cpu_type);
630	arch_filter_events(cpu_type);
631	return &events_list;
632}
633
634
635static void delete_unit_mask(struct op_unit_mask * unit)
636{
637	u32 cur;
638	for (cur = 0 ; cur < unit->num ; ++cur) {
639		if (unit->um[cur].desc)
640			free(unit->um[cur].desc);
641	}
642
643	if (unit->name)
644		free(unit->name);
645
646	list_del(&unit->um_next);
647	free(unit);
648}
649
650
651static void delete_event(struct op_event * event)
652{
653	if (event->name)
654		free(event->name);
655	if (event->desc)
656		free(event->desc);
657
658	list_del(&event->event_next);
659	free(event);
660}
661
662
663void op_free_events(void)
664{
665	struct list_head * pos, * pos2;
666	list_for_each_safe(pos, pos2, &events_list) {
667		struct op_event * event = list_entry(pos, struct op_event, event_next);
668		delete_event(event);
669	}
670
671	list_for_each_safe(pos, pos2, &um_list) {
672		struct op_unit_mask * unit = list_entry(pos, struct op_unit_mask, um_next);
673		delete_unit_mask(unit);
674	}
675}
676
677/* There can be actually multiple events here, so this is not quite correct */
678static struct op_event * find_event_any(u32 nr)
679{
680	struct list_head * pos;
681
682	list_for_each(pos, &events_list) {
683		struct op_event * event = list_entry(pos, struct op_event, event_next);
684		if (event->val == nr)
685			return event;
686	}
687
688	return NULL;
689}
690
691static struct op_event * find_event_um(u32 nr, u32 um)
692{
693	struct list_head * pos;
694	unsigned int i;
695
696	list_for_each(pos, &events_list) {
697		struct op_event * event = list_entry(pos, struct op_event, event_next);
698		if (event->val == nr) {
699			for (i = 0; i < event->unit->num; i++) {
700				if (event->unit->um[i].value == um)
701					return event;
702			}
703		}
704	}
705
706	return NULL;
707}
708
709static FILE * open_event_mapping_file(char const * cpu_name)
710{
711	char * ev_map_file;
712	char * dir;
713	dir = getenv("OPROFILE_EVENTS_DIR");
714	if (dir == NULL)
715		dir = OP_DATADIR;
716
717	ev_map_file = xmalloc(strlen(dir) + strlen("/") + strlen(cpu_name) +
718	                    strlen("/") + + strlen("event_mappings") + 1);
719	strcpy(ev_map_file, dir);
720	strcat(ev_map_file, "/");
721
722	strcat(ev_map_file, cpu_name);
723	strcat(ev_map_file, "/");
724	strcat(ev_map_file, "event_mappings");
725	filename = ev_map_file;
726	return (fopen(ev_map_file, "r"));
727}
728
729
730/**
731 *  This function is PPC64-specific.
732 */
733static char const * get_mapping(u32 nr, FILE * fp)
734{
735	char * line;
736	char * name;
737	char * value;
738	char const * c;
739	char * map = NULL;
740	int seen_event = 0, seen_mmcr0 = 0, seen_mmcr1 = 0, seen_mmcra = 0;
741	u32 mmcr0 = 0;
742	u64 mmcr1 = 0;
743	u32 mmcra = 0;
744	int event_found = 0;
745
746	line_nr = 1;
747	line = op_get_line(fp);
748	while (line && !event_found) {
749		if (empty_line(line) || comment_line(line))
750			goto next;
751
752		seen_event = 0;
753		seen_mmcr0 = 0;
754		seen_mmcr1 = 0;
755		seen_mmcra = 0;
756		mmcr0 = 0;
757		mmcr1 = 0;
758		mmcra = 0;
759
760		c = line;
761		while (next_token(&c, &name, &value)) {
762			if (strcmp(name, "event") == 0) {
763				u32 evt;
764				if (seen_event)
765					parse_error("duplicate event tag");
766				seen_event = 1;
767				evt = parse_hex(value);
768				if (evt == nr)
769					event_found = 1;
770				free(value);
771			} else if (strcmp(name, "mmcr0") == 0) {
772				if (seen_mmcr0)
773					parse_error("duplicate mmcr0 tag");
774				seen_mmcr0 = 1;
775				mmcr0 = parse_hex(value);
776				free(value);
777			} else if (strcmp(name, "mmcr1") == 0) {
778				if (seen_mmcr1)
779					parse_error("duplicate mmcr1: tag");
780				seen_mmcr1 = 1;
781				mmcr1 = parse_long_hex(value);
782				free(value);
783			} else if (strcmp(name, "mmcra") == 0) {
784				if (seen_mmcra)
785					parse_error("duplicate mmcra: tag");
786				seen_mmcra = 1;
787				mmcra = parse_hex(value);
788				free(value);
789			} else {
790				parse_error("unknown tag");
791			}
792
793			free(name);
794		}
795next:
796		free(line);
797		line = op_get_line(fp);
798		++line_nr;
799	}
800	if (event_found) {
801		if (!seen_mmcr0 || !seen_mmcr1 || !seen_mmcra) {
802			fprintf(stderr, "Error: Missing information in line %d of event mapping file %s\n", line_nr, filename);
803			exit(EXIT_FAILURE);
804		}
805		map = xmalloc(70);
806		snprintf(map, 70, "mmcr0:%u mmcr1:%Lu mmcra:%u",
807		         mmcr0, mmcr1, mmcra);
808	}
809
810	return map;
811}
812
813
814char const * find_mapping_for_event(u32 nr, op_cpu cpu_type)
815{
816	char const * cpu_name = op_get_cpu_name(cpu_type);
817	FILE * fp = open_event_mapping_file(cpu_name);
818	char const * map = NULL;
819	switch (cpu_type) {
820		case CPU_PPC64_PA6T:
821		case CPU_PPC64_970:
822		case CPU_PPC64_970MP:
823		case CPU_PPC64_POWER4:
824		case CPU_PPC64_POWER5:
825		case CPU_PPC64_POWER5p:
826		case CPU_PPC64_POWER5pp:
827		case CPU_PPC64_POWER6:
828		case CPU_PPC64_POWER7:
829		case CPU_PPC64_IBM_COMPAT_V1:
830			if (!fp) {
831				fprintf(stderr, "oprofile: could not open event mapping file %s\n", filename);
832				exit(EXIT_FAILURE);
833			} else {
834				map = get_mapping(nr, fp);
835			}
836			break;
837		default:
838			break;
839	}
840
841	if (fp)
842		fclose(fp);
843
844	return map;
845}
846
847static int match_event(int i, struct op_event *event, unsigned um)
848{
849	unsigned v = event->unit->um[i].value;
850
851	switch (event->unit->unit_type_mask) {
852	case utm_exclusive:
853	case utm_mandatory:
854		return v == um;
855
856	case utm_bitmask:
857		return (v & um) || (!v && v == 0);
858	}
859
860	abort();
861}
862
863struct op_event * find_event_by_name(char const * name, unsigned um, int um_valid)
864{
865	struct list_head * pos;
866
867	list_for_each(pos, &events_list) {
868		struct op_event * event = list_entry(pos, struct op_event, event_next);
869		if (strcmp(event->name, name) == 0) {
870			if (um_valid) {
871				unsigned i;
872
873				for (i = 0; i < event->unit->num; i++)
874					if (match_event(i, event, um))
875						return event;
876				continue;
877			}
878			return event;
879		}
880	}
881
882	return NULL;
883}
884
885
886struct op_event * op_find_event(op_cpu cpu_type, u32 nr, u32 um)
887{
888	struct op_event * event;
889
890	load_events(cpu_type);
891
892	event = find_event_um(nr, um);
893
894	return event;
895}
896
897struct op_event * op_find_event_any(op_cpu cpu_type, u32 nr)
898{
899	load_events(cpu_type);
900
901	return find_event_any(nr);
902}
903
904int op_check_events(int ctr, u32 nr, u32 um, op_cpu cpu_type)
905{
906	int ret = OP_INVALID_EVENT;
907	size_t i;
908	u32 ctr_mask = 1 << ctr;
909	struct list_head * pos;
910
911	load_events(cpu_type);
912
913	list_for_each(pos, &events_list) {
914		struct op_event * event = list_entry(pos, struct op_event, event_next);
915		if (event->val != nr)
916			continue;
917
918		ret = OP_OK_EVENT;
919
920		if ((event->counter_mask & ctr_mask) == 0)
921			ret |= OP_INVALID_COUNTER;
922
923		if (event->unit->unit_type_mask == utm_bitmask) {
924			for (i = 0; i < event->unit->num; ++i)
925				um &= ~(event->unit->um[i].value);
926
927			if (um)
928				ret |= OP_INVALID_UM;
929
930		} else {
931			for (i = 0; i < event->unit->num; ++i) {
932				if (event->unit->um[i].value == um)
933					break;
934			}
935
936			if (i == event->unit->num)
937				ret |= OP_INVALID_UM;
938
939		}
940
941		if (ret == OP_OK_EVENT)
942			return ret;
943	}
944
945	return ret;
946}
947
948
949void op_default_event(op_cpu cpu_type, struct op_default_event_descr * descr)
950{
951	descr->name = "";
952	descr->um = 0x0;
953	/* A fixed value of CPU cycles; this should ensure good
954	 * granulity even on faster CPUs, though it will generate more
955	 * interrupts.
956	 */
957	descr->count = 100000;
958
959	switch (cpu_type) {
960		case CPU_PPRO:
961		case CPU_PII:
962		case CPU_PIII:
963		case CPU_P6_MOBILE:
964		case CPU_CORE:
965		case CPU_CORE_2:
966		case CPU_ATHLON:
967		case CPU_HAMMER:
968		case CPU_FAMILY10:
969		case CPU_ARCH_PERFMON:
970		case CPU_FAMILY11H:
971 		case CPU_ATOM:
972 		case CPU_CORE_I7:
973			descr->name = "CPU_CLK_UNHALTED";
974			break;
975
976		case CPU_RTC:
977			descr->name = "RTC_INTERRUPTS";
978			descr->count = 1024;
979			break;
980
981		case CPU_P4:
982		case CPU_P4_HT2:
983			descr->name = "GLOBAL_POWER_EVENTS";
984			descr->um = 0x1;
985			break;
986
987		case CPU_IA64:
988		case CPU_IA64_1:
989		case CPU_IA64_2:
990			descr->count = 1000000;
991			descr->name = "CPU_CYCLES";
992			break;
993
994		case CPU_AXP_EV4:
995		case CPU_AXP_EV5:
996		case CPU_AXP_PCA56:
997		case CPU_AXP_EV6:
998		case CPU_AXP_EV67:
999			descr->name = "CYCLES";
1000			break;
1001
1002		// we could possibly use the CCNT
1003		case CPU_ARM_XSCALE1:
1004		case CPU_ARM_XSCALE2:
1005		case CPU_ARM_MPCORE:
1006		case CPU_ARM_V6:
1007		case CPU_ARM_V7:
1008		case CPU_AVR32:
1009			descr->name = "CPU_CYCLES";
1010			break;
1011
1012		case CPU_PPC64_PA6T:
1013		case CPU_PPC64_970:
1014		case CPU_PPC64_970MP:
1015		case CPU_PPC_7450:
1016		case CPU_PPC64_POWER4:
1017		case CPU_PPC64_POWER5:
1018		case CPU_PPC64_POWER6:
1019		case CPU_PPC64_POWER5p:
1020		case CPU_PPC64_POWER5pp:
1021		case CPU_PPC64_CELL:
1022		case CPU_PPC64_POWER7:
1023		case CPU_PPC64_IBM_COMPAT_V1:
1024			descr->name = "CYCLES";
1025			break;
1026
1027		case CPU_MIPS_20K:
1028			descr->name = "CYCLES";
1029			break;
1030
1031		case CPU_MIPS_24K:
1032			descr->name = "INSTRUCTIONS";
1033			break;
1034
1035		case CPU_MIPS_34K:
1036			descr->name = "INSTRUCTIONS";
1037			break;
1038
1039		case CPU_MIPS_5K:
1040		case CPU_MIPS_25K:
1041			descr->name = "CYCLES";
1042			break;
1043
1044		case CPU_MIPS_R10000:
1045		case CPU_MIPS_R12000:
1046			descr->name = "INSTRUCTIONS_GRADUATED";
1047			break;
1048
1049		case CPU_MIPS_RM7000:
1050		case CPU_MIPS_RM9000:
1051			descr->name = "INSTRUCTIONS_ISSUED";
1052			break;
1053
1054		case CPU_MIPS_SB1:
1055			descr->name = "INSN_SURVIVED_STAGE7";
1056			break;
1057
1058		case CPU_MIPS_VR5432:
1059		case CPU_MIPS_VR5500:
1060			descr->name = "INSTRUCTIONS_EXECUTED";
1061			break;
1062
1063		case CPU_PPC_E500:
1064		case CPU_PPC_E500_2:
1065		case CPU_PPC_E300:
1066			descr->name = "CPU_CLK";
1067			break;
1068
1069		// don't use default, if someone add a cpu he wants a compiler
1070		// warning if he forgets to handle it here.
1071		case CPU_TIMER_INT:
1072		case CPU_NO_GOOD:
1073		case MAX_CPU_TYPE:
1074			break;
1075	}
1076}
1077