blob: 4546dda20af20e5790d55758c0d299f7c7b2bc32 [file] [log] [blame]
The Android Open Source Project10e23ee2009-03-03 19:30:30 -08001/**
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"
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070019#include "op_hw_specific.h"
The Android Open Source Project10e23ee2009-03-03 19:30:30 -080020
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
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070031static 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
The Android Open Source Project10e23ee2009-03-03 19:30:30 -080049static 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
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070091static 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}
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800108
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
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700133 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
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800141 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 }
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700172
173 if (!um->name)
174 parse_error("Missing name for unit mask");
175 if (!seen_type)
176 parse_error("Missing type for unit mask");
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800177}
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
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700210static void free_unit_mask(struct op_unit_mask * um)
211{
212 list_del(&um->um_next);
213 free(um);
214}
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800215
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
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700284static struct op_unit_mask * try_find_um(char const * value)
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800285{
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);
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700290 if (strcmp(value, um->name) == 0) {
291 um->used = 1;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800292 return um;
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700293 }
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800294 }
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700295 return NULL;
296}
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800297
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700298static 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;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800303 fprintf(stderr, "oprofile: could not find unit mask %s\n", value);
304 exit(EXIT_FAILURE);
305}
306
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700307/* 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}
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800346
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
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700391static 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}
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800405
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
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700415static void free_event(struct op_event * event)
416{
417 list_del(&event->event_next);
418 free(event);
419}
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800420
421/* event:0x00 counters:0 um:zero minimum:4096 name:ISSUES : Total issues */
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700422/* event:0x00 ext:xxxxxx um:zero minimum:4096 name:ISSUES : Total issues */
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800423static 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;
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700430 int seen_event, seen_counters, seen_um, seen_minimum, seen_name, seen_ext;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800431 FILE * fp = fopen(file, "r");
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700432 int tags;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800433
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
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700448 tags = 0;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800449 seen_name = 0;
450 seen_event = 0;
451 seen_counters = 0;
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700452 seen_ext = 0;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800453 seen_um = 0;
454 seen_minimum = 0;
455 event = new_event();
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700456 event->filter = -1;
457 event->ext = NULL;
458
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800459 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;
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700480 if (!strcmp(value, "cpuid"))
481 event->counter_mask = arch_get_counter_mask();
482 else
483 event->counter_mask = parse_counter_mask(value);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800484 free(value);
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700485 } else if (strcmp(name, "ext") == 0) {
486 if (seen_ext)
487 parse_error("duplicate ext: tag");
488 seen_ext = 1;
489 event->ext = value;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800490 } else if (strcmp(name, "um") == 0) {
491 if (seen_um)
492 parse_error("duplicate um: tag");
493 seen_um = 1;
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700494 if (strchr(value, ','))
495 event->unit = merge_um(value);
496 else
497 event->unit = find_um(value);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800498 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;
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700507 } 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:");
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800519 } else {
520 parse_error("unknown tag");
521 }
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700522 tags++;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800523
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 */
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700537static int check_unit_mask(struct op_unit_mask const * um,
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800538 char const * cpu_name)
539{
540 u32 i;
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700541 int err = 0;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800542
543 if (!um->used) {
544 fprintf(stderr, "um %s is not used\n", um->name);
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700545 err = EXIT_FAILURE;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800546 }
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);
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700551 err = EXIT_FAILURE;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800552 } 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);
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700560 err = EXIT_FAILURE;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800561 }
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);
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700571 err = EXIT_FAILURE;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800572 }
573 }
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700574 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 }
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800588}
589
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700590static 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}
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800604
605static void load_events(op_cpu cpu_type)
606{
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700607 const char * cpu_name = op_get_cpu_name(cpu_type);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800608 struct list_head * pos;
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700609 int err = 0;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800610
611 if (!list_empty(&events_list))
612 return;
613
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700614 load_events_name(cpu_name);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800615
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700616 arch_filter_events(cpu_type);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800617
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);
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700621 err |= check_unit_mask(um, cpu_name);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800622 }
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700623 if (err)
624 exit(err);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800625}
626
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800627struct list_head * op_events(op_cpu cpu_type)
628{
629 load_events(cpu_type);
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700630 arch_filter_events(cpu_type);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800631 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
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700677/* There can be actually multiple events here, so this is not quite correct */
678static struct op_event * find_event_any(u32 nr)
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800679{
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
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700691static struct op_event * find_event_um(u32 nr, u32 um)
692{
693 struct list_head * pos;
694 unsigned int i;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800695
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700696 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)
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800710{
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 */
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700733static char const * get_mapping(u32 nr, FILE * fp)
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800734{
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:
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700828 case CPU_PPC64_POWER7:
829 case CPU_PPC64_IBM_COMPAT_V1:
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800830 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
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700847static int match_event(int i, struct op_event *event, unsigned um)
848{
849 unsigned v = event->unit->um[i].value;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800850
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700851 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)
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800864{
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);
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700869 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 }
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800878 return event;
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700879 }
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800880 }
881
882 return NULL;
883}
884
885
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700886struct op_event * op_find_event(op_cpu cpu_type, u32 nr, u32 um)
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800887{
888 struct op_event * event;
889
890 load_events(cpu_type);
891
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700892 event = find_event_um(nr, um);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800893
894 return event;
895}
896
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700897struct 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}
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800903
904int op_check_events(int ctr, u32 nr, u32 um, op_cpu cpu_type)
905{
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700906 int ret = OP_INVALID_EVENT;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800907 size_t i;
908 u32 ctr_mask = 1 << ctr;
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700909 struct list_head * pos;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800910
911 load_events(cpu_type);
912
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700913 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;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800917
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700918 ret = OP_OK_EVENT;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800919
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700920 if ((event->counter_mask & ctr_mask) == 0)
921 ret |= OP_INVALID_COUNTER;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800922
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700923 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;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800938
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800939 }
940
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700941 if (ret == OP_OK_EVENT)
942 return ret;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800943 }
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:
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700969 case CPU_ARCH_PERFMON:
970 case CPU_FAMILY11H:
971 case CPU_ATOM:
972 case CPU_CORE_I7:
Ben Cheng5bbbe462010-09-02 21:48:01 -0700973 case CPU_NEHALEM:
Jeff Brown7a33c862011-02-02 14:00:44 -0800974 case CPU_WESTMERE:
Ben Cheng5bbbe462010-09-02 21:48:01 -0700975 case CPU_MIPS_LOONGSON2:
Jeff Brown7a33c862011-02-02 14:00:44 -0800976 case CPU_FAMILY12H:
977 case CPU_FAMILY14H:
978 case CPU_FAMILY15H:
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800979 descr->name = "CPU_CLK_UNHALTED";
980 break;
981
982 case CPU_RTC:
983 descr->name = "RTC_INTERRUPTS";
984 descr->count = 1024;
985 break;
986
987 case CPU_P4:
988 case CPU_P4_HT2:
989 descr->name = "GLOBAL_POWER_EVENTS";
990 descr->um = 0x1;
991 break;
992
993 case CPU_IA64:
994 case CPU_IA64_1:
995 case CPU_IA64_2:
996 descr->count = 1000000;
997 descr->name = "CPU_CYCLES";
998 break;
999
1000 case CPU_AXP_EV4:
1001 case CPU_AXP_EV5:
1002 case CPU_AXP_PCA56:
1003 case CPU_AXP_EV6:
1004 case CPU_AXP_EV67:
1005 descr->name = "CYCLES";
1006 break;
1007
1008 // we could possibly use the CCNT
1009 case CPU_ARM_XSCALE1:
1010 case CPU_ARM_XSCALE2:
1011 case CPU_ARM_MPCORE:
1012 case CPU_ARM_V6:
Ben Cheng5a4eb4e2009-09-14 16:00:41 -07001013 case CPU_ARM_V7:
Ben Cheng5bbbe462010-09-02 21:48:01 -07001014 case CPU_ARM_V7_CA9:
The Android Open Source Project10e23ee2009-03-03 19:30:30 -08001015 case CPU_AVR32:
1016 descr->name = "CPU_CYCLES";
1017 break;
1018
1019 case CPU_PPC64_PA6T:
1020 case CPU_PPC64_970:
1021 case CPU_PPC64_970MP:
1022 case CPU_PPC_7450:
1023 case CPU_PPC64_POWER4:
1024 case CPU_PPC64_POWER5:
1025 case CPU_PPC64_POWER6:
1026 case CPU_PPC64_POWER5p:
1027 case CPU_PPC64_POWER5pp:
1028 case CPU_PPC64_CELL:
Ben Cheng5a4eb4e2009-09-14 16:00:41 -07001029 case CPU_PPC64_POWER7:
1030 case CPU_PPC64_IBM_COMPAT_V1:
The Android Open Source Project10e23ee2009-03-03 19:30:30 -08001031 descr->name = "CYCLES";
1032 break;
1033
1034 case CPU_MIPS_20K:
1035 descr->name = "CYCLES";
1036 break;
1037
1038 case CPU_MIPS_24K:
The Android Open Source Project10e23ee2009-03-03 19:30:30 -08001039 case CPU_MIPS_34K:
Ben Cheng5bbbe462010-09-02 21:48:01 -07001040 case CPU_MIPS_74K:
1041 case CPU_MIPS_1004K:
The Android Open Source Project10e23ee2009-03-03 19:30:30 -08001042 descr->name = "INSTRUCTIONS";
1043 break;
1044
1045 case CPU_MIPS_5K:
1046 case CPU_MIPS_25K:
1047 descr->name = "CYCLES";
1048 break;
1049
1050 case CPU_MIPS_R10000:
1051 case CPU_MIPS_R12000:
1052 descr->name = "INSTRUCTIONS_GRADUATED";
1053 break;
1054
1055 case CPU_MIPS_RM7000:
1056 case CPU_MIPS_RM9000:
1057 descr->name = "INSTRUCTIONS_ISSUED";
1058 break;
1059
1060 case CPU_MIPS_SB1:
1061 descr->name = "INSN_SURVIVED_STAGE7";
1062 break;
1063
1064 case CPU_MIPS_VR5432:
1065 case CPU_MIPS_VR5500:
1066 descr->name = "INSTRUCTIONS_EXECUTED";
1067 break;
1068
1069 case CPU_PPC_E500:
1070 case CPU_PPC_E500_2:
1071 case CPU_PPC_E300:
1072 descr->name = "CPU_CLK";
1073 break;
1074
1075 // don't use default, if someone add a cpu he wants a compiler
1076 // warning if he forgets to handle it here.
1077 case CPU_TIMER_INT:
1078 case CPU_NO_GOOD:
1079 case MAX_CPU_TYPE:
1080 break;
1081 }
1082}