diff options
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r-- | tools/perf/util/parse-events.c | 431 |
1 files changed, 354 insertions, 77 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4d042f104cdc..7bdad8df22a6 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include "parse-events.h" | 5 | #include "parse-events.h" |
6 | #include "exec_cmd.h" | 6 | #include "exec_cmd.h" |
7 | #include "string.h" | 7 | #include "string.h" |
8 | #include "cache.h" | ||
8 | 9 | ||
9 | extern char *strcasestr(const char *haystack, const char *needle); | 10 | extern char *strcasestr(const char *haystack, const char *needle); |
10 | 11 | ||
@@ -19,6 +20,8 @@ struct event_symbol { | |||
19 | char *alias; | 20 | char *alias; |
20 | }; | 21 | }; |
21 | 22 | ||
23 | char debugfs_path[MAXPATHLEN]; | ||
24 | |||
22 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x | 25 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x |
23 | #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x | 26 | #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x |
24 | 27 | ||
@@ -71,8 +74,8 @@ static char *sw_event_names[] = { | |||
71 | #define MAX_ALIASES 8 | 74 | #define MAX_ALIASES 8 |
72 | 75 | ||
73 | static char *hw_cache[][MAX_ALIASES] = { | 76 | static char *hw_cache[][MAX_ALIASES] = { |
74 | { "L1-d$", "l1-d", "l1d", "L1-data", }, | 77 | { "L1-dcache", "l1-d", "l1d", "L1-data", }, |
75 | { "L1-i$", "l1-i", "l1i", "L1-instruction", }, | 78 | { "L1-icache", "l1-i", "l1i", "L1-instruction", }, |
76 | { "LLC", "L2" }, | 79 | { "LLC", "L2" }, |
77 | { "dTLB", "d-tlb", "Data-TLB", }, | 80 | { "dTLB", "d-tlb", "Data-TLB", }, |
78 | { "iTLB", "i-tlb", "Instruction-TLB", }, | 81 | { "iTLB", "i-tlb", "Instruction-TLB", }, |
@@ -110,6 +113,88 @@ static unsigned long hw_cache_stat[C(MAX)] = { | |||
110 | [C(BPU)] = (CACHE_READ), | 113 | [C(BPU)] = (CACHE_READ), |
111 | }; | 114 | }; |
112 | 115 | ||
116 | #define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \ | ||
117 | while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ | ||
118 | if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path, \ | ||
119 | sys_dirent.d_name) && \ | ||
120 | (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ | ||
121 | (strcmp(sys_dirent.d_name, ".")) && \ | ||
122 | (strcmp(sys_dirent.d_name, ".."))) | ||
123 | |||
124 | #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \ | ||
125 | while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ | ||
126 | if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \ | ||
127 | sys_dirent.d_name, evt_dirent.d_name) && \ | ||
128 | (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ | ||
129 | (strcmp(evt_dirent.d_name, ".")) && \ | ||
130 | (strcmp(evt_dirent.d_name, ".."))) | ||
131 | |||
132 | #define MAX_EVENT_LENGTH 30 | ||
133 | |||
134 | int valid_debugfs_mount(const char *debugfs) | ||
135 | { | ||
136 | struct statfs st_fs; | ||
137 | |||
138 | if (statfs(debugfs, &st_fs) < 0) | ||
139 | return -ENOENT; | ||
140 | else if (st_fs.f_type != (long) DEBUGFS_MAGIC) | ||
141 | return -ENOENT; | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static char *tracepoint_id_to_name(u64 config) | ||
146 | { | ||
147 | static char tracepoint_name[2 * MAX_EVENT_LENGTH]; | ||
148 | DIR *sys_dir, *evt_dir; | ||
149 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | ||
150 | struct stat st; | ||
151 | char id_buf[4]; | ||
152 | int fd; | ||
153 | u64 id; | ||
154 | char evt_path[MAXPATHLEN]; | ||
155 | |||
156 | if (valid_debugfs_mount(debugfs_path)) | ||
157 | return "unkown"; | ||
158 | |||
159 | sys_dir = opendir(debugfs_path); | ||
160 | if (!sys_dir) | ||
161 | goto cleanup; | ||
162 | |||
163 | for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { | ||
164 | evt_dir = opendir(evt_path); | ||
165 | if (!evt_dir) | ||
166 | goto cleanup; | ||
167 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, | ||
168 | evt_path, st) { | ||
169 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", | ||
170 | debugfs_path, sys_dirent.d_name, | ||
171 | evt_dirent.d_name); | ||
172 | fd = open(evt_path, O_RDONLY); | ||
173 | if (fd < 0) | ||
174 | continue; | ||
175 | if (read(fd, id_buf, sizeof(id_buf)) < 0) { | ||
176 | close(fd); | ||
177 | continue; | ||
178 | } | ||
179 | close(fd); | ||
180 | id = atoll(id_buf); | ||
181 | if (id == config) { | ||
182 | closedir(evt_dir); | ||
183 | closedir(sys_dir); | ||
184 | snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH, | ||
185 | "%s:%s", sys_dirent.d_name, | ||
186 | evt_dirent.d_name); | ||
187 | return tracepoint_name; | ||
188 | } | ||
189 | } | ||
190 | closedir(evt_dir); | ||
191 | } | ||
192 | |||
193 | cleanup: | ||
194 | closedir(sys_dir); | ||
195 | return "unkown"; | ||
196 | } | ||
197 | |||
113 | static int is_cache_op_valid(u8 cache_type, u8 cache_op) | 198 | static int is_cache_op_valid(u8 cache_type, u8 cache_op) |
114 | { | 199 | { |
115 | if (hw_cache_stat[cache_type] & COP(cache_op)) | 200 | if (hw_cache_stat[cache_type] & COP(cache_op)) |
@@ -177,6 +262,9 @@ char *event_name(int counter) | |||
177 | return sw_event_names[config]; | 262 | return sw_event_names[config]; |
178 | return "unknown-software"; | 263 | return "unknown-software"; |
179 | 264 | ||
265 | case PERF_TYPE_TRACEPOINT: | ||
266 | return tracepoint_id_to_name(config); | ||
267 | |||
180 | default: | 268 | default: |
181 | break; | 269 | break; |
182 | } | 270 | } |
@@ -184,16 +272,20 @@ char *event_name(int counter) | |||
184 | return "unknown"; | 272 | return "unknown"; |
185 | } | 273 | } |
186 | 274 | ||
187 | static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) | 275 | static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size) |
188 | { | 276 | { |
189 | int i, j; | 277 | int i, j; |
278 | int n, longest = -1; | ||
190 | 279 | ||
191 | for (i = 0; i < size; i++) { | 280 | for (i = 0; i < size; i++) { |
192 | for (j = 0; j < MAX_ALIASES; j++) { | 281 | for (j = 0; j < MAX_ALIASES && names[i][j]; j++) { |
193 | if (!names[i][j]) | 282 | n = strlen(names[i][j]); |
194 | break; | 283 | if (n > longest && !strncasecmp(*str, names[i][j], n)) |
195 | if (strcasestr(str, names[i][j])) | 284 | longest = n; |
196 | return i; | 285 | } |
286 | if (longest > 0) { | ||
287 | *str += longest; | ||
288 | return i; | ||
197 | } | 289 | } |
198 | } | 290 | } |
199 | 291 | ||
@@ -201,30 +293,53 @@ static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) | |||
201 | } | 293 | } |
202 | 294 | ||
203 | static int | 295 | static int |
204 | parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) | 296 | parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) |
205 | { | 297 | { |
206 | int cache_type = -1, cache_op = 0, cache_result = 0; | 298 | const char *s = *str; |
299 | int cache_type = -1, cache_op = -1, cache_result = -1; | ||
207 | 300 | ||
208 | cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX); | 301 | cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX); |
209 | /* | 302 | /* |
210 | * No fallback - if we cannot get a clear cache type | 303 | * No fallback - if we cannot get a clear cache type |
211 | * then bail out: | 304 | * then bail out: |
212 | */ | 305 | */ |
213 | if (cache_type == -1) | 306 | if (cache_type == -1) |
214 | return -EINVAL; | 307 | return 0; |
308 | |||
309 | while ((cache_op == -1 || cache_result == -1) && *s == '-') { | ||
310 | ++s; | ||
311 | |||
312 | if (cache_op == -1) { | ||
313 | cache_op = parse_aliases(&s, hw_cache_op, | ||
314 | PERF_COUNT_HW_CACHE_OP_MAX); | ||
315 | if (cache_op >= 0) { | ||
316 | if (!is_cache_op_valid(cache_type, cache_op)) | ||
317 | return 0; | ||
318 | continue; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | if (cache_result == -1) { | ||
323 | cache_result = parse_aliases(&s, hw_cache_result, | ||
324 | PERF_COUNT_HW_CACHE_RESULT_MAX); | ||
325 | if (cache_result >= 0) | ||
326 | continue; | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * Can't parse this as a cache op or result, so back up | ||
331 | * to the '-'. | ||
332 | */ | ||
333 | --s; | ||
334 | break; | ||
335 | } | ||
215 | 336 | ||
216 | cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX); | ||
217 | /* | 337 | /* |
218 | * Fall back to reads: | 338 | * Fall back to reads: |
219 | */ | 339 | */ |
220 | if (cache_op == -1) | 340 | if (cache_op == -1) |
221 | cache_op = PERF_COUNT_HW_CACHE_OP_READ; | 341 | cache_op = PERF_COUNT_HW_CACHE_OP_READ; |
222 | 342 | ||
223 | if (!is_cache_op_valid(cache_type, cache_op)) | ||
224 | return -EINVAL; | ||
225 | |||
226 | cache_result = parse_aliases(str, hw_cache_result, | ||
227 | PERF_COUNT_HW_CACHE_RESULT_MAX); | ||
228 | /* | 343 | /* |
229 | * Fall back to accesses: | 344 | * Fall back to accesses: |
230 | */ | 345 | */ |
@@ -234,93 +349,202 @@ parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) | |||
234 | attr->config = cache_type | (cache_op << 8) | (cache_result << 16); | 349 | attr->config = cache_type | (cache_op << 8) | (cache_result << 16); |
235 | attr->type = PERF_TYPE_HW_CACHE; | 350 | attr->type = PERF_TYPE_HW_CACHE; |
236 | 351 | ||
237 | return 0; | 352 | *str = s; |
353 | return 1; | ||
354 | } | ||
355 | |||
356 | static int parse_tracepoint_event(const char **strp, | ||
357 | struct perf_counter_attr *attr) | ||
358 | { | ||
359 | const char *evt_name; | ||
360 | char sys_name[MAX_EVENT_LENGTH]; | ||
361 | char id_buf[4]; | ||
362 | int fd; | ||
363 | unsigned int sys_length, evt_length; | ||
364 | u64 id; | ||
365 | char evt_path[MAXPATHLEN]; | ||
366 | |||
367 | if (valid_debugfs_mount(debugfs_path)) | ||
368 | return 0; | ||
369 | |||
370 | evt_name = strchr(*strp, ':'); | ||
371 | if (!evt_name) | ||
372 | return 0; | ||
373 | |||
374 | sys_length = evt_name - *strp; | ||
375 | if (sys_length >= MAX_EVENT_LENGTH) | ||
376 | return 0; | ||
377 | |||
378 | strncpy(sys_name, *strp, sys_length); | ||
379 | sys_name[sys_length] = '\0'; | ||
380 | evt_name = evt_name + 1; | ||
381 | evt_length = strlen(evt_name); | ||
382 | if (evt_length >= MAX_EVENT_LENGTH) | ||
383 | return 0; | ||
384 | |||
385 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, | ||
386 | sys_name, evt_name); | ||
387 | fd = open(evt_path, O_RDONLY); | ||
388 | if (fd < 0) | ||
389 | return 0; | ||
390 | |||
391 | if (read(fd, id_buf, sizeof(id_buf)) < 0) { | ||
392 | close(fd); | ||
393 | return 0; | ||
394 | } | ||
395 | close(fd); | ||
396 | id = atoll(id_buf); | ||
397 | attr->config = id; | ||
398 | attr->type = PERF_TYPE_TRACEPOINT; | ||
399 | *strp = evt_name + evt_length; | ||
400 | return 1; | ||
238 | } | 401 | } |
239 | 402 | ||
240 | static int check_events(const char *str, unsigned int i) | 403 | static int check_events(const char *str, unsigned int i) |
241 | { | 404 | { |
242 | if (!strncmp(str, event_symbols[i].symbol, | 405 | int n; |
243 | strlen(event_symbols[i].symbol))) | ||
244 | return 1; | ||
245 | 406 | ||
246 | if (strlen(event_symbols[i].alias)) | 407 | n = strlen(event_symbols[i].symbol); |
247 | if (!strncmp(str, event_symbols[i].alias, | 408 | if (!strncmp(str, event_symbols[i].symbol, n)) |
248 | strlen(event_symbols[i].alias))) | 409 | return n; |
249 | return 1; | 410 | |
411 | n = strlen(event_symbols[i].alias); | ||
412 | if (n) | ||
413 | if (!strncmp(str, event_symbols[i].alias, n)) | ||
414 | return n; | ||
250 | return 0; | 415 | return 0; |
251 | } | 416 | } |
252 | 417 | ||
253 | /* | 418 | static int |
254 | * Each event can have multiple symbolic names. | 419 | parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) |
255 | * Symbolic names are (almost) exactly matched. | ||
256 | */ | ||
257 | static int parse_event_symbols(const char *str, struct perf_counter_attr *attr) | ||
258 | { | 420 | { |
259 | u64 config, id; | 421 | const char *str = *strp; |
260 | int type; | ||
261 | unsigned int i; | 422 | unsigned int i; |
262 | const char *sep, *pstr; | 423 | int n; |
263 | 424 | ||
264 | if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) { | 425 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { |
265 | attr->type = PERF_TYPE_RAW; | 426 | n = check_events(str, i); |
266 | attr->config = config; | 427 | if (n > 0) { |
428 | attr->type = event_symbols[i].type; | ||
429 | attr->config = event_symbols[i].config; | ||
430 | *strp = str + n; | ||
431 | return 1; | ||
432 | } | ||
433 | } | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static int parse_raw_event(const char **strp, struct perf_counter_attr *attr) | ||
438 | { | ||
439 | const char *str = *strp; | ||
440 | u64 config; | ||
441 | int n; | ||
267 | 442 | ||
443 | if (*str != 'r') | ||
268 | return 0; | 444 | return 0; |
445 | n = hex2u64(str + 1, &config); | ||
446 | if (n > 0) { | ||
447 | *strp = str + n + 1; | ||
448 | attr->type = PERF_TYPE_RAW; | ||
449 | attr->config = config; | ||
450 | return 1; | ||
269 | } | 451 | } |
452 | return 0; | ||
453 | } | ||
270 | 454 | ||
271 | pstr = str; | 455 | static int |
272 | sep = strchr(pstr, ':'); | 456 | parse_numeric_event(const char **strp, struct perf_counter_attr *attr) |
273 | if (sep) { | 457 | { |
274 | type = atoi(pstr); | 458 | const char *str = *strp; |
275 | pstr = sep + 1; | 459 | char *endp; |
276 | id = atoi(pstr); | 460 | unsigned long type; |
277 | sep = strchr(pstr, ':'); | 461 | u64 config; |
278 | if (sep) { | 462 | |
279 | pstr = sep + 1; | 463 | type = strtoul(str, &endp, 0); |
280 | if (strchr(pstr, 'k')) | 464 | if (endp > str && type < PERF_TYPE_MAX && *endp == ':') { |
281 | attr->exclude_user = 1; | 465 | str = endp + 1; |
282 | if (strchr(pstr, 'u')) | 466 | config = strtoul(str, &endp, 0); |
283 | attr->exclude_kernel = 1; | 467 | if (endp > str) { |
468 | attr->type = type; | ||
469 | attr->config = config; | ||
470 | *strp = endp; | ||
471 | return 1; | ||
284 | } | 472 | } |
285 | attr->type = type; | 473 | } |
286 | attr->config = id; | 474 | return 0; |
475 | } | ||
287 | 476 | ||
477 | static int | ||
478 | parse_event_modifier(const char **strp, struct perf_counter_attr *attr) | ||
479 | { | ||
480 | const char *str = *strp; | ||
481 | int eu = 1, ek = 1, eh = 1; | ||
482 | |||
483 | if (*str++ != ':') | ||
288 | return 0; | 484 | return 0; |
485 | while (*str) { | ||
486 | if (*str == 'u') | ||
487 | eu = 0; | ||
488 | else if (*str == 'k') | ||
489 | ek = 0; | ||
490 | else if (*str == 'h') | ||
491 | eh = 0; | ||
492 | else | ||
493 | break; | ||
494 | ++str; | ||
495 | } | ||
496 | if (str >= *strp + 2) { | ||
497 | *strp = str; | ||
498 | attr->exclude_user = eu; | ||
499 | attr->exclude_kernel = ek; | ||
500 | attr->exclude_hv = eh; | ||
501 | return 1; | ||
289 | } | 502 | } |
503 | return 0; | ||
504 | } | ||
290 | 505 | ||
291 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { | 506 | /* |
292 | if (check_events(str, i)) { | 507 | * Each event can have multiple symbolic names. |
293 | attr->type = event_symbols[i].type; | 508 | * Symbolic names are (almost) exactly matched. |
294 | attr->config = event_symbols[i].config; | 509 | */ |
510 | static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) | ||
511 | { | ||
512 | if (!(parse_tracepoint_event(str, attr) || | ||
513 | parse_raw_event(str, attr) || | ||
514 | parse_numeric_event(str, attr) || | ||
515 | parse_symbolic_event(str, attr) || | ||
516 | parse_generic_hw_event(str, attr))) | ||
517 | return 0; | ||
295 | 518 | ||
296 | return 0; | 519 | parse_event_modifier(str, attr); |
297 | } | ||
298 | } | ||
299 | 520 | ||
300 | return parse_generic_hw_symbols(str, attr); | 521 | return 1; |
301 | } | 522 | } |
302 | 523 | ||
303 | int parse_events(const struct option *opt, const char *str, int unset) | 524 | int parse_events(const struct option *opt __used, const char *str, int unset __used) |
304 | { | 525 | { |
305 | struct perf_counter_attr attr; | 526 | struct perf_counter_attr attr; |
306 | int ret; | ||
307 | 527 | ||
308 | memset(&attr, 0, sizeof(attr)); | 528 | for (;;) { |
309 | again: | 529 | if (nr_counters == MAX_COUNTERS) |
310 | if (nr_counters == MAX_COUNTERS) | 530 | return -1; |
311 | return -1; | 531 | |
532 | memset(&attr, 0, sizeof(attr)); | ||
533 | if (!parse_event_symbols(&str, &attr)) | ||
534 | return -1; | ||
312 | 535 | ||
313 | ret = parse_event_symbols(str, &attr); | 536 | if (!(*str == 0 || *str == ',' || isspace(*str))) |
314 | if (ret < 0) | 537 | return -1; |
315 | return ret; | ||
316 | 538 | ||
317 | attrs[nr_counters] = attr; | 539 | attrs[nr_counters] = attr; |
318 | nr_counters++; | 540 | nr_counters++; |
319 | 541 | ||
320 | str = strstr(str, ","); | 542 | if (*str == 0) |
321 | if (str) { | 543 | break; |
322 | str++; | 544 | if (*str == ',') |
323 | goto again; | 545 | ++str; |
546 | while (isspace(*str)) | ||
547 | ++str; | ||
324 | } | 548 | } |
325 | 549 | ||
326 | return 0; | 550 | return 0; |
@@ -335,12 +559,48 @@ static const char * const event_type_descriptors[] = { | |||
335 | }; | 559 | }; |
336 | 560 | ||
337 | /* | 561 | /* |
562 | * Print the events from <debugfs_mount_point>/tracing/events | ||
563 | */ | ||
564 | |||
565 | static void print_tracepoint_events(void) | ||
566 | { | ||
567 | DIR *sys_dir, *evt_dir; | ||
568 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | ||
569 | struct stat st; | ||
570 | char evt_path[MAXPATHLEN]; | ||
571 | |||
572 | if (valid_debugfs_mount(debugfs_path)) | ||
573 | return; | ||
574 | |||
575 | sys_dir = opendir(debugfs_path); | ||
576 | if (!sys_dir) | ||
577 | goto cleanup; | ||
578 | |||
579 | for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { | ||
580 | evt_dir = opendir(evt_path); | ||
581 | if (!evt_dir) | ||
582 | goto cleanup; | ||
583 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, | ||
584 | evt_path, st) { | ||
585 | snprintf(evt_path, MAXPATHLEN, "%s:%s", | ||
586 | sys_dirent.d_name, evt_dirent.d_name); | ||
587 | fprintf(stderr, " %-40s [%s]\n", evt_path, | ||
588 | event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); | ||
589 | } | ||
590 | closedir(evt_dir); | ||
591 | } | ||
592 | |||
593 | cleanup: | ||
594 | closedir(sys_dir); | ||
595 | } | ||
596 | |||
597 | /* | ||
338 | * Print the help text for the event symbols: | 598 | * Print the help text for the event symbols: |
339 | */ | 599 | */ |
340 | void print_events(void) | 600 | void print_events(void) |
341 | { | 601 | { |
342 | struct event_symbol *syms = event_symbols; | 602 | struct event_symbol *syms = event_symbols; |
343 | unsigned int i, type, prev_type = -1; | 603 | unsigned int i, type, op, prev_type = -1; |
344 | char name[40]; | 604 | char name[40]; |
345 | 605 | ||
346 | fprintf(stderr, "\n"); | 606 | fprintf(stderr, "\n"); |
@@ -348,7 +608,7 @@ void print_events(void) | |||
348 | 608 | ||
349 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { | 609 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { |
350 | type = syms->type + 1; | 610 | type = syms->type + 1; |
351 | if (type > ARRAY_SIZE(event_type_descriptors)) | 611 | if (type >= ARRAY_SIZE(event_type_descriptors)) |
352 | type = 0; | 612 | type = 0; |
353 | 613 | ||
354 | if (type != prev_type) | 614 | if (type != prev_type) |
@@ -365,9 +625,26 @@ void print_events(void) | |||
365 | } | 625 | } |
366 | 626 | ||
367 | fprintf(stderr, "\n"); | 627 | fprintf(stderr, "\n"); |
628 | for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { | ||
629 | for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { | ||
630 | /* skip invalid cache type */ | ||
631 | if (!is_cache_op_valid(type, op)) | ||
632 | continue; | ||
633 | |||
634 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { | ||
635 | fprintf(stderr, " %-40s [%s]\n", | ||
636 | event_cache_name(type, op, i), | ||
637 | event_type_descriptors[4]); | ||
638 | } | ||
639 | } | ||
640 | } | ||
641 | |||
642 | fprintf(stderr, "\n"); | ||
368 | fprintf(stderr, " %-40s [raw hardware event descriptor]\n", | 643 | fprintf(stderr, " %-40s [raw hardware event descriptor]\n", |
369 | "rNNN"); | 644 | "rNNN"); |
370 | fprintf(stderr, "\n"); | 645 | fprintf(stderr, "\n"); |
371 | 646 | ||
647 | print_tracepoint_events(); | ||
648 | |||
372 | exit(129); | 649 | exit(129); |
373 | } | 650 | } |