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
25 static LIST_HEAD(events_list);
26 static LIST_HEAD(um_list);
27
28 static char const * filename;
29 static unsigned int line_nr;
30
31 static void delete_event(struct op_event * event);
32 static void read_events(char const * file);
33 static void read_unit_masks(char const * file);
34 static void free_unit_mask(struct op_unit_mask * um);
35
build_fn(const char * cpu_name,const char * fn)36 static 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
parse_error(char const * context)49 static 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
parse_int(char const * str)58 static 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
parse_hex(char const * str)68 static 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
parse_long_hex(char const * str)81 static 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
include_um(const char * start,const char * end)91 static 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 */
parse_um(struct op_unit_mask * um,char const * line)110 static 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 */
parse_um_entry(struct op_described_um * entry,char const * line)181 static 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
new_unit_mask(void)201 static 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
free_unit_mask(struct op_unit_mask * um)210 static 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 */
read_unit_masks(char const * file)220 static 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
254 next:
255 free(line);
256 line = op_get_line(fp);
257 ++line_nr;
258 }
259
260 fclose(fp);
261 }
262
263
parse_counter_mask(char const * str)264 static 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
try_find_um(char const * value)284 static 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
find_um(char const * value)298 static 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 */
merge_um(char * value)308 static 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" */
next_token(char const ** cp,char ** name,char ** value)348 static 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
include_events(char * value)391 static 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
new_event(void)406 static 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
free_event(struct op_event * event)415 static 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 */
read_events(char const * file)423 static 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 }
526 next:
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 */
check_unit_mask(struct op_unit_mask const * um,char const * cpu_name)537 static 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
arch_filter_events(op_cpu cpu_type)577 static 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
load_events_name(const char * cpu_name)590 static 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
load_events(op_cpu cpu_type)605 static 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
op_events(op_cpu cpu_type)627 struct 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
delete_unit_mask(struct op_unit_mask * unit)635 static 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
delete_event(struct op_event * event)651 static 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
op_free_events(void)663 void 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 */
find_event_any(u32 nr)678 static 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
find_event_um(u32 nr,u32 um)691 static 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
open_event_mapping_file(char const * cpu_name)709 static 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 */
get_mapping(u32 nr,FILE * fp)733 static 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 }
795 next:
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
find_mapping_for_event(u32 nr,op_cpu cpu_type)814 char 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
match_event(int i,struct op_event * event,unsigned um)847 static 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
find_event_by_name(char const * name,unsigned um,int um_valid)863 struct 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
op_find_event(op_cpu cpu_type,u32 nr,u32 um)886 struct 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
op_find_event_any(op_cpu cpu_type,u32 nr)897 struct 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
op_check_events(int ctr,u32 nr,u32 um,op_cpu cpu_type)904 int 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
op_default_event(op_cpu cpu_type,struct op_default_event_descr * descr)949 void 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