diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /tools/perf/util/parse-events.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r-- | tools/perf/util/parse-events.c | 388 |
1 files changed, 258 insertions, 130 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4af5bd59cfd1..41982c373faf 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -1,6 +1,8 @@ | |||
1 | #include "../../../include/linux/hw_breakpoint.h" | 1 | #include "../../../include/linux/hw_breakpoint.h" |
2 | #include "util.h" | 2 | #include "util.h" |
3 | #include "../perf.h" | 3 | #include "../perf.h" |
4 | #include "evlist.h" | ||
5 | #include "evsel.h" | ||
4 | #include "parse-options.h" | 6 | #include "parse-options.h" |
5 | #include "parse-events.h" | 7 | #include "parse-events.h" |
6 | #include "exec_cmd.h" | 8 | #include "exec_cmd.h" |
@@ -10,11 +12,6 @@ | |||
10 | #include "header.h" | 12 | #include "header.h" |
11 | #include "debugfs.h" | 13 | #include "debugfs.h" |
12 | 14 | ||
13 | int nr_counters; | ||
14 | |||
15 | struct perf_event_attr attrs[MAX_COUNTERS]; | ||
16 | char *filters[MAX_COUNTERS]; | ||
17 | |||
18 | struct event_symbol { | 15 | struct event_symbol { |
19 | u8 type; | 16 | u8 type; |
20 | u64 config; | 17 | u64 config; |
@@ -34,34 +31,36 @@ char debugfs_path[MAXPATHLEN]; | |||
34 | #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x | 31 | #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x |
35 | 32 | ||
36 | static struct event_symbol event_symbols[] = { | 33 | static struct event_symbol event_symbols[] = { |
37 | { CHW(CPU_CYCLES), "cpu-cycles", "cycles" }, | 34 | { CHW(CPU_CYCLES), "cpu-cycles", "cycles" }, |
38 | { CHW(INSTRUCTIONS), "instructions", "" }, | 35 | { CHW(STALLED_CYCLES_FRONTEND), "stalled-cycles-frontend", "idle-cycles-frontend" }, |
39 | { CHW(CACHE_REFERENCES), "cache-references", "" }, | 36 | { CHW(STALLED_CYCLES_BACKEND), "stalled-cycles-backend", "idle-cycles-backend" }, |
40 | { CHW(CACHE_MISSES), "cache-misses", "" }, | 37 | { CHW(INSTRUCTIONS), "instructions", "" }, |
41 | { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, | 38 | { CHW(CACHE_REFERENCES), "cache-references", "" }, |
42 | { CHW(BRANCH_MISSES), "branch-misses", "" }, | 39 | { CHW(CACHE_MISSES), "cache-misses", "" }, |
43 | { CHW(BUS_CYCLES), "bus-cycles", "" }, | 40 | { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, |
44 | 41 | { CHW(BRANCH_MISSES), "branch-misses", "" }, | |
45 | { CSW(CPU_CLOCK), "cpu-clock", "" }, | 42 | { CHW(BUS_CYCLES), "bus-cycles", "" }, |
46 | { CSW(TASK_CLOCK), "task-clock", "" }, | 43 | |
47 | { CSW(PAGE_FAULTS), "page-faults", "faults" }, | 44 | { CSW(CPU_CLOCK), "cpu-clock", "" }, |
48 | { CSW(PAGE_FAULTS_MIN), "minor-faults", "" }, | 45 | { CSW(TASK_CLOCK), "task-clock", "" }, |
49 | { CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, | 46 | { CSW(PAGE_FAULTS), "page-faults", "faults" }, |
50 | { CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, | 47 | { CSW(PAGE_FAULTS_MIN), "minor-faults", "" }, |
51 | { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, | 48 | { CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, |
52 | { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" }, | 49 | { CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, |
53 | { CSW(EMULATION_FAULTS), "emulation-faults", "" }, | 50 | { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, |
51 | { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" }, | ||
52 | { CSW(EMULATION_FAULTS), "emulation-faults", "" }, | ||
54 | }; | 53 | }; |
55 | 54 | ||
56 | #define __PERF_EVENT_FIELD(config, name) \ | 55 | #define __PERF_EVENT_FIELD(config, name) \ |
57 | ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT) | 56 | ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT) |
58 | 57 | ||
59 | #define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW) | 58 | #define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW) |
60 | #define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG) | 59 | #define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG) |
61 | #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) | 60 | #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) |
62 | #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) | 61 | #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) |
63 | 62 | ||
64 | static const char *hw_event_names[] = { | 63 | static const char *hw_event_names[PERF_COUNT_HW_MAX] = { |
65 | "cycles", | 64 | "cycles", |
66 | "instructions", | 65 | "instructions", |
67 | "cache-references", | 66 | "cache-references", |
@@ -69,11 +68,13 @@ static const char *hw_event_names[] = { | |||
69 | "branches", | 68 | "branches", |
70 | "branch-misses", | 69 | "branch-misses", |
71 | "bus-cycles", | 70 | "bus-cycles", |
71 | "stalled-cycles-frontend", | ||
72 | "stalled-cycles-backend", | ||
72 | }; | 73 | }; |
73 | 74 | ||
74 | static const char *sw_event_names[] = { | 75 | static const char *sw_event_names[PERF_COUNT_SW_MAX] = { |
75 | "cpu-clock-msecs", | 76 | "cpu-clock", |
76 | "task-clock-msecs", | 77 | "task-clock", |
77 | "page-faults", | 78 | "page-faults", |
78 | "context-switches", | 79 | "context-switches", |
79 | "CPU-migrations", | 80 | "CPU-migrations", |
@@ -266,10 +267,35 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result) | |||
266 | return name; | 267 | return name; |
267 | } | 268 | } |
268 | 269 | ||
269 | const char *event_name(int counter) | 270 | const char *event_type(int type) |
270 | { | 271 | { |
271 | u64 config = attrs[counter].config; | 272 | switch (type) { |
272 | int type = attrs[counter].type; | 273 | case PERF_TYPE_HARDWARE: |
274 | return "hardware"; | ||
275 | |||
276 | case PERF_TYPE_SOFTWARE: | ||
277 | return "software"; | ||
278 | |||
279 | case PERF_TYPE_TRACEPOINT: | ||
280 | return "tracepoint"; | ||
281 | |||
282 | case PERF_TYPE_HW_CACHE: | ||
283 | return "hardware-cache"; | ||
284 | |||
285 | default: | ||
286 | break; | ||
287 | } | ||
288 | |||
289 | return "unknown"; | ||
290 | } | ||
291 | |||
292 | const char *event_name(struct perf_evsel *evsel) | ||
293 | { | ||
294 | u64 config = evsel->attr.config; | ||
295 | int type = evsel->attr.type; | ||
296 | |||
297 | if (evsel->name) | ||
298 | return evsel->name; | ||
273 | 299 | ||
274 | return __event_name(type, config); | 300 | return __event_name(type, config); |
275 | } | 301 | } |
@@ -279,13 +305,13 @@ const char *__event_name(int type, u64 config) | |||
279 | static char buf[32]; | 305 | static char buf[32]; |
280 | 306 | ||
281 | if (type == PERF_TYPE_RAW) { | 307 | if (type == PERF_TYPE_RAW) { |
282 | sprintf(buf, "raw 0x%llx", config); | 308 | sprintf(buf, "raw 0x%" PRIx64, config); |
283 | return buf; | 309 | return buf; |
284 | } | 310 | } |
285 | 311 | ||
286 | switch (type) { | 312 | switch (type) { |
287 | case PERF_TYPE_HARDWARE: | 313 | case PERF_TYPE_HARDWARE: |
288 | if (config < PERF_COUNT_HW_MAX) | 314 | if (config < PERF_COUNT_HW_MAX && hw_event_names[config]) |
289 | return hw_event_names[config]; | 315 | return hw_event_names[config]; |
290 | return "unknown-hardware"; | 316 | return "unknown-hardware"; |
291 | 317 | ||
@@ -311,7 +337,7 @@ const char *__event_name(int type, u64 config) | |||
311 | } | 337 | } |
312 | 338 | ||
313 | case PERF_TYPE_SOFTWARE: | 339 | case PERF_TYPE_SOFTWARE: |
314 | if (config < PERF_COUNT_SW_MAX) | 340 | if (config < PERF_COUNT_SW_MAX && sw_event_names[config]) |
315 | return sw_event_names[config]; | 341 | return sw_event_names[config]; |
316 | return "unknown-software"; | 342 | return "unknown-software"; |
317 | 343 | ||
@@ -434,7 +460,7 @@ parse_single_tracepoint_event(char *sys_name, | |||
434 | id = atoll(id_buf); | 460 | id = atoll(id_buf); |
435 | attr->config = id; | 461 | attr->config = id; |
436 | attr->type = PERF_TYPE_TRACEPOINT; | 462 | attr->type = PERF_TYPE_TRACEPOINT; |
437 | *strp = evt_name + evt_length; | 463 | *strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */ |
438 | 464 | ||
439 | attr->sample_type |= PERF_SAMPLE_RAW; | 465 | attr->sample_type |= PERF_SAMPLE_RAW; |
440 | attr->sample_type |= PERF_SAMPLE_TIME; | 466 | attr->sample_type |= PERF_SAMPLE_TIME; |
@@ -449,8 +475,8 @@ parse_single_tracepoint_event(char *sys_name, | |||
449 | /* sys + ':' + event + ':' + flags*/ | 475 | /* sys + ':' + event + ':' + flags*/ |
450 | #define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) | 476 | #define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) |
451 | static enum event_result | 477 | static enum event_result |
452 | parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, | 478 | parse_multiple_tracepoint_event(const struct option *opt, char *sys_name, |
453 | char *flags) | 479 | const char *evt_exp, char *flags) |
454 | { | 480 | { |
455 | char evt_path[MAXPATHLEN]; | 481 | char evt_path[MAXPATHLEN]; |
456 | struct dirent *evt_ent; | 482 | struct dirent *evt_ent; |
@@ -483,19 +509,19 @@ parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, | |||
483 | if (len < 0) | 509 | if (len < 0) |
484 | return EVT_FAILED; | 510 | return EVT_FAILED; |
485 | 511 | ||
486 | if (parse_events(NULL, event_opt, 0)) | 512 | if (parse_events(opt, event_opt, 0)) |
487 | return EVT_FAILED; | 513 | return EVT_FAILED; |
488 | } | 514 | } |
489 | 515 | ||
490 | return EVT_HANDLED_ALL; | 516 | return EVT_HANDLED_ALL; |
491 | } | 517 | } |
492 | 518 | ||
493 | 519 | static enum event_result | |
494 | static enum event_result parse_tracepoint_event(const char **strp, | 520 | parse_tracepoint_event(const struct option *opt, const char **strp, |
495 | struct perf_event_attr *attr) | 521 | struct perf_event_attr *attr) |
496 | { | 522 | { |
497 | const char *evt_name; | 523 | const char *evt_name; |
498 | char *flags; | 524 | char *flags = NULL, *comma_loc; |
499 | char sys_name[MAX_EVENT_LENGTH]; | 525 | char sys_name[MAX_EVENT_LENGTH]; |
500 | unsigned int sys_length, evt_length; | 526 | unsigned int sys_length, evt_length; |
501 | 527 | ||
@@ -514,6 +540,11 @@ static enum event_result parse_tracepoint_event(const char **strp, | |||
514 | sys_name[sys_length] = '\0'; | 540 | sys_name[sys_length] = '\0'; |
515 | evt_name = evt_name + 1; | 541 | evt_name = evt_name + 1; |
516 | 542 | ||
543 | comma_loc = strchr(evt_name, ','); | ||
544 | if (comma_loc) { | ||
545 | /* take the event name up to the comma */ | ||
546 | evt_name = strndup(evt_name, comma_loc - evt_name); | ||
547 | } | ||
517 | flags = strchr(evt_name, ':'); | 548 | flags = strchr(evt_name, ':'); |
518 | if (flags) { | 549 | if (flags) { |
519 | /* split it out: */ | 550 | /* split it out: */ |
@@ -524,14 +555,14 @@ static enum event_result parse_tracepoint_event(const char **strp, | |||
524 | evt_length = strlen(evt_name); | 555 | evt_length = strlen(evt_name); |
525 | if (evt_length >= MAX_EVENT_LENGTH) | 556 | if (evt_length >= MAX_EVENT_LENGTH) |
526 | return EVT_FAILED; | 557 | return EVT_FAILED; |
527 | |||
528 | if (strpbrk(evt_name, "*?")) { | 558 | if (strpbrk(evt_name, "*?")) { |
529 | *strp = evt_name + evt_length; | 559 | *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */ |
530 | return parse_multiple_tracepoint_event(sys_name, evt_name, | 560 | return parse_multiple_tracepoint_event(opt, sys_name, evt_name, |
531 | flags); | 561 | flags); |
532 | } else | 562 | } else { |
533 | return parse_single_tracepoint_event(sys_name, evt_name, | 563 | return parse_single_tracepoint_event(sys_name, evt_name, |
534 | evt_length, attr, strp); | 564 | evt_length, attr, strp); |
565 | } | ||
535 | } | 566 | } |
536 | 567 | ||
537 | static enum event_result | 568 | static enum event_result |
@@ -621,13 +652,15 @@ static int check_events(const char *str, unsigned int i) | |||
621 | int n; | 652 | int n; |
622 | 653 | ||
623 | n = strlen(event_symbols[i].symbol); | 654 | n = strlen(event_symbols[i].symbol); |
624 | if (!strncmp(str, event_symbols[i].symbol, n)) | 655 | if (!strncasecmp(str, event_symbols[i].symbol, n)) |
625 | return n; | 656 | return n; |
626 | 657 | ||
627 | n = strlen(event_symbols[i].alias); | 658 | n = strlen(event_symbols[i].alias); |
628 | if (n) | 659 | if (n) { |
629 | if (!strncmp(str, event_symbols[i].alias, n)) | 660 | if (!strncasecmp(str, event_symbols[i].alias, n)) |
630 | return n; | 661 | return n; |
662 | } | ||
663 | |||
631 | return 0; | 664 | return 0; |
632 | } | 665 | } |
633 | 666 | ||
@@ -691,15 +724,22 @@ parse_numeric_event(const char **strp, struct perf_event_attr *attr) | |||
691 | return EVT_FAILED; | 724 | return EVT_FAILED; |
692 | } | 725 | } |
693 | 726 | ||
694 | static enum event_result | 727 | static int |
695 | parse_event_modifier(const char **strp, struct perf_event_attr *attr) | 728 | parse_event_modifier(const char **strp, struct perf_event_attr *attr) |
696 | { | 729 | { |
697 | const char *str = *strp; | 730 | const char *str = *strp; |
698 | int exclude = 0; | 731 | int exclude = 0; |
699 | int eu = 0, ek = 0, eh = 0, precise = 0; | 732 | int eu = 0, ek = 0, eh = 0, precise = 0; |
700 | 733 | ||
701 | if (*str++ != ':') | 734 | if (!*str) |
702 | return 0; | 735 | return 0; |
736 | |||
737 | if (*str == ',') | ||
738 | return 0; | ||
739 | |||
740 | if (*str++ != ':') | ||
741 | return -1; | ||
742 | |||
703 | while (*str) { | 743 | while (*str) { |
704 | if (*str == 'u') { | 744 | if (*str == 'u') { |
705 | if (!exclude) | 745 | if (!exclude) |
@@ -720,14 +760,16 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr) | |||
720 | 760 | ||
721 | ++str; | 761 | ++str; |
722 | } | 762 | } |
723 | if (str >= *strp + 2) { | 763 | if (str < *strp + 2) |
724 | *strp = str; | 764 | return -1; |
725 | attr->exclude_user = eu; | 765 | |
726 | attr->exclude_kernel = ek; | 766 | *strp = str; |
727 | attr->exclude_hv = eh; | 767 | |
728 | attr->precise_ip = precise; | 768 | attr->exclude_user = eu; |
729 | return 1; | 769 | attr->exclude_kernel = ek; |
730 | } | 770 | attr->exclude_hv = eh; |
771 | attr->precise_ip = precise; | ||
772 | |||
731 | return 0; | 773 | return 0; |
732 | } | 774 | } |
733 | 775 | ||
@@ -736,11 +778,12 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr) | |||
736 | * Symbolic names are (almost) exactly matched. | 778 | * Symbolic names are (almost) exactly matched. |
737 | */ | 779 | */ |
738 | static enum event_result | 780 | static enum event_result |
739 | parse_event_symbols(const char **str, struct perf_event_attr *attr) | 781 | parse_event_symbols(const struct option *opt, const char **str, |
782 | struct perf_event_attr *attr) | ||
740 | { | 783 | { |
741 | enum event_result ret; | 784 | enum event_result ret; |
742 | 785 | ||
743 | ret = parse_tracepoint_event(str, attr); | 786 | ret = parse_tracepoint_event(opt, str, attr); |
744 | if (ret != EVT_FAILED) | 787 | if (ret != EVT_FAILED) |
745 | goto modifier; | 788 | goto modifier; |
746 | 789 | ||
@@ -769,52 +812,27 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr) | |||
769 | return EVT_FAILED; | 812 | return EVT_FAILED; |
770 | 813 | ||
771 | modifier: | 814 | modifier: |
772 | parse_event_modifier(str, attr); | 815 | if (parse_event_modifier(str, attr) < 0) { |
773 | 816 | fprintf(stderr, "invalid event modifier: '%s'\n", *str); | |
774 | return ret; | 817 | fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n"); |
775 | } | ||
776 | |||
777 | static int store_event_type(const char *orgname) | ||
778 | { | ||
779 | char filename[PATH_MAX], *c; | ||
780 | FILE *file; | ||
781 | int id, n; | ||
782 | 818 | ||
783 | sprintf(filename, "%s/", debugfs_path); | 819 | return EVT_FAILED; |
784 | strncat(filename, orgname, strlen(orgname)); | ||
785 | strcat(filename, "/id"); | ||
786 | |||
787 | c = strchr(filename, ':'); | ||
788 | if (c) | ||
789 | *c = '/'; | ||
790 | |||
791 | file = fopen(filename, "r"); | ||
792 | if (!file) | ||
793 | return 0; | ||
794 | n = fscanf(file, "%i", &id); | ||
795 | fclose(file); | ||
796 | if (n < 1) { | ||
797 | pr_err("cannot store event ID\n"); | ||
798 | return -EINVAL; | ||
799 | } | 820 | } |
800 | return perf_header__push_event(id, orgname); | 821 | |
822 | return ret; | ||
801 | } | 823 | } |
802 | 824 | ||
803 | int parse_events(const struct option *opt __used, const char *str, int unset __used) | 825 | int parse_events(const struct option *opt, const char *str, int unset __used) |
804 | { | 826 | { |
827 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; | ||
805 | struct perf_event_attr attr; | 828 | struct perf_event_attr attr; |
806 | enum event_result ret; | 829 | enum event_result ret; |
807 | 830 | const char *ostr; | |
808 | if (strchr(str, ':')) | ||
809 | if (store_event_type(str) < 0) | ||
810 | return -1; | ||
811 | 831 | ||
812 | for (;;) { | 832 | for (;;) { |
813 | if (nr_counters == MAX_COUNTERS) | 833 | ostr = str; |
814 | return -1; | ||
815 | |||
816 | memset(&attr, 0, sizeof(attr)); | 834 | memset(&attr, 0, sizeof(attr)); |
817 | ret = parse_event_symbols(&str, &attr); | 835 | ret = parse_event_symbols(opt, &str, &attr); |
818 | if (ret == EVT_FAILED) | 836 | if (ret == EVT_FAILED) |
819 | return -1; | 837 | return -1; |
820 | 838 | ||
@@ -822,8 +840,16 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u | |||
822 | return -1; | 840 | return -1; |
823 | 841 | ||
824 | if (ret != EVT_HANDLED_ALL) { | 842 | if (ret != EVT_HANDLED_ALL) { |
825 | attrs[nr_counters] = attr; | 843 | struct perf_evsel *evsel; |
826 | nr_counters++; | 844 | evsel = perf_evsel__new(&attr, evlist->nr_entries); |
845 | if (evsel == NULL) | ||
846 | return -1; | ||
847 | perf_evlist__add(evlist, evsel); | ||
848 | |||
849 | evsel->name = calloc(str - ostr + 1, 1); | ||
850 | if (!evsel->name) | ||
851 | return -1; | ||
852 | strncpy(evsel->name, ostr, str - ostr); | ||
827 | } | 853 | } |
828 | 854 | ||
829 | if (*str == 0) | 855 | if (*str == 0) |
@@ -837,24 +863,26 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u | |||
837 | return 0; | 863 | return 0; |
838 | } | 864 | } |
839 | 865 | ||
840 | int parse_filter(const struct option *opt __used, const char *str, | 866 | int parse_filter(const struct option *opt, const char *str, |
841 | int unset __used) | 867 | int unset __used) |
842 | { | 868 | { |
843 | int i = nr_counters - 1; | 869 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; |
844 | int len = strlen(str); | 870 | struct perf_evsel *last = NULL; |
871 | |||
872 | if (evlist->nr_entries > 0) | ||
873 | last = list_entry(evlist->entries.prev, struct perf_evsel, node); | ||
845 | 874 | ||
846 | if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) { | 875 | if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { |
847 | fprintf(stderr, | 876 | fprintf(stderr, |
848 | "-F option should follow a -e tracepoint option\n"); | 877 | "-F option should follow a -e tracepoint option\n"); |
849 | return -1; | 878 | return -1; |
850 | } | 879 | } |
851 | 880 | ||
852 | filters[i] = malloc(len + 1); | 881 | last->filter = strdup(str); |
853 | if (!filters[i]) { | 882 | if (last->filter == NULL) { |
854 | fprintf(stderr, "not enough memory to hold filter string\n"); | 883 | fprintf(stderr, "not enough memory to hold filter string\n"); |
855 | return -1; | 884 | return -1; |
856 | } | 885 | } |
857 | strcpy(filters[i], str); | ||
858 | 886 | ||
859 | return 0; | 887 | return 0; |
860 | } | 888 | } |
@@ -872,7 +900,7 @@ static const char * const event_type_descriptors[] = { | |||
872 | * Print the events from <debugfs_mount_point>/tracing/events | 900 | * Print the events from <debugfs_mount_point>/tracing/events |
873 | */ | 901 | */ |
874 | 902 | ||
875 | static void print_tracepoint_events(void) | 903 | void print_tracepoint_events(const char *subsys_glob, const char *event_glob) |
876 | { | 904 | { |
877 | DIR *sys_dir, *evt_dir; | 905 | DIR *sys_dir, *evt_dir; |
878 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | 906 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; |
@@ -887,6 +915,9 @@ static void print_tracepoint_events(void) | |||
887 | return; | 915 | return; |
888 | 916 | ||
889 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { | 917 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { |
918 | if (subsys_glob != NULL && | ||
919 | !strglobmatch(sys_dirent.d_name, subsys_glob)) | ||
920 | continue; | ||
890 | 921 | ||
891 | snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, | 922 | snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, |
892 | sys_dirent.d_name); | 923 | sys_dirent.d_name); |
@@ -895,9 +926,13 @@ static void print_tracepoint_events(void) | |||
895 | continue; | 926 | continue; |
896 | 927 | ||
897 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { | 928 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { |
929 | if (event_glob != NULL && | ||
930 | !strglobmatch(evt_dirent.d_name, event_glob)) | ||
931 | continue; | ||
932 | |||
898 | snprintf(evt_path, MAXPATHLEN, "%s:%s", | 933 | snprintf(evt_path, MAXPATHLEN, "%s:%s", |
899 | sys_dirent.d_name, evt_dirent.d_name); | 934 | sys_dirent.d_name, evt_dirent.d_name); |
900 | printf(" %-42s [%s]\n", evt_path, | 935 | printf(" %-50s [%s]\n", evt_path, |
901 | event_type_descriptors[PERF_TYPE_TRACEPOINT]); | 936 | event_type_descriptors[PERF_TYPE_TRACEPOINT]); |
902 | } | 937 | } |
903 | closedir(evt_dir); | 938 | closedir(evt_dir); |
@@ -906,34 +941,71 @@ static void print_tracepoint_events(void) | |||
906 | } | 941 | } |
907 | 942 | ||
908 | /* | 943 | /* |
909 | * Print the help text for the event symbols: | 944 | * Check whether event is in <debugfs_mount_point>/tracing/events |
910 | */ | 945 | */ |
911 | void print_events(void) | 946 | |
947 | int is_valid_tracepoint(const char *event_string) | ||
912 | { | 948 | { |
913 | struct event_symbol *syms = event_symbols; | 949 | DIR *sys_dir, *evt_dir; |
914 | unsigned int i, type, op, prev_type = -1; | 950 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; |
915 | char name[40]; | 951 | char evt_path[MAXPATHLEN]; |
952 | char dir_path[MAXPATHLEN]; | ||
916 | 953 | ||
917 | printf("\n"); | 954 | if (debugfs_valid_mountpoint(debugfs_path)) |
918 | printf("List of pre-defined events (to be used in -e):\n"); | 955 | return 0; |
919 | 956 | ||
920 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { | 957 | sys_dir = opendir(debugfs_path); |
921 | type = syms->type; | 958 | if (!sys_dir) |
959 | return 0; | ||
922 | 960 | ||
923 | if (type != prev_type) | 961 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { |
924 | printf("\n"); | 962 | |
963 | snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, | ||
964 | sys_dirent.d_name); | ||
965 | evt_dir = opendir(dir_path); | ||
966 | if (!evt_dir) | ||
967 | continue; | ||
968 | |||
969 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { | ||
970 | snprintf(evt_path, MAXPATHLEN, "%s:%s", | ||
971 | sys_dirent.d_name, evt_dirent.d_name); | ||
972 | if (!strcmp(evt_path, event_string)) { | ||
973 | closedir(evt_dir); | ||
974 | closedir(sys_dir); | ||
975 | return 1; | ||
976 | } | ||
977 | } | ||
978 | closedir(evt_dir); | ||
979 | } | ||
980 | closedir(sys_dir); | ||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | void print_events_type(u8 type) | ||
985 | { | ||
986 | struct event_symbol *syms = event_symbols; | ||
987 | unsigned int i; | ||
988 | char name[64]; | ||
989 | |||
990 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { | ||
991 | if (type != syms->type) | ||
992 | continue; | ||
925 | 993 | ||
926 | if (strlen(syms->alias)) | 994 | if (strlen(syms->alias)) |
927 | sprintf(name, "%s OR %s", syms->symbol, syms->alias); | 995 | snprintf(name, sizeof(name), "%s OR %s", |
996 | syms->symbol, syms->alias); | ||
928 | else | 997 | else |
929 | strcpy(name, syms->symbol); | 998 | snprintf(name, sizeof(name), "%s", syms->symbol); |
930 | printf(" %-42s [%s]\n", name, | ||
931 | event_type_descriptors[type]); | ||
932 | 999 | ||
933 | prev_type = type; | 1000 | printf(" %-50s [%s]\n", name, |
1001 | event_type_descriptors[type]); | ||
934 | } | 1002 | } |
1003 | } | ||
1004 | |||
1005 | int print_hwcache_events(const char *event_glob) | ||
1006 | { | ||
1007 | unsigned int type, op, i, printed = 0; | ||
935 | 1008 | ||
936 | printf("\n"); | ||
937 | for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { | 1009 | for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { |
938 | for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { | 1010 | for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { |
939 | /* skip invalid cache type */ | 1011 | /* skip invalid cache type */ |
@@ -941,25 +1013,81 @@ void print_events(void) | |||
941 | continue; | 1013 | continue; |
942 | 1014 | ||
943 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { | 1015 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { |
944 | printf(" %-42s [%s]\n", | 1016 | char *name = event_cache_name(type, op, i); |
945 | event_cache_name(type, op, i), | 1017 | |
1018 | if (event_glob != NULL && !strglobmatch(name, event_glob)) | ||
1019 | continue; | ||
1020 | |||
1021 | printf(" %-50s [%s]\n", name, | ||
946 | event_type_descriptors[PERF_TYPE_HW_CACHE]); | 1022 | event_type_descriptors[PERF_TYPE_HW_CACHE]); |
1023 | ++printed; | ||
947 | } | 1024 | } |
948 | } | 1025 | } |
949 | } | 1026 | } |
950 | 1027 | ||
1028 | return printed; | ||
1029 | } | ||
1030 | |||
1031 | #define MAX_NAME_LEN 100 | ||
1032 | |||
1033 | /* | ||
1034 | * Print the help text for the event symbols: | ||
1035 | */ | ||
1036 | void print_events(const char *event_glob) | ||
1037 | { | ||
1038 | unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0; | ||
1039 | struct event_symbol *syms = event_symbols; | ||
1040 | char name[MAX_NAME_LEN]; | ||
1041 | |||
1042 | printf("\n"); | ||
1043 | printf("List of pre-defined events (to be used in -e):\n"); | ||
1044 | |||
1045 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { | ||
1046 | type = syms->type; | ||
1047 | |||
1048 | if (type != prev_type && printed) { | ||
1049 | printf("\n"); | ||
1050 | printed = 0; | ||
1051 | ntypes_printed++; | ||
1052 | } | ||
1053 | |||
1054 | if (event_glob != NULL && | ||
1055 | !(strglobmatch(syms->symbol, event_glob) || | ||
1056 | (syms->alias && strglobmatch(syms->alias, event_glob)))) | ||
1057 | continue; | ||
1058 | |||
1059 | if (strlen(syms->alias)) | ||
1060 | snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); | ||
1061 | else | ||
1062 | strncpy(name, syms->symbol, MAX_NAME_LEN); | ||
1063 | printf(" %-50s [%s]\n", name, | ||
1064 | event_type_descriptors[type]); | ||
1065 | |||
1066 | prev_type = type; | ||
1067 | ++printed; | ||
1068 | } | ||
1069 | |||
1070 | if (ntypes_printed) { | ||
1071 | printed = 0; | ||
1072 | printf("\n"); | ||
1073 | } | ||
1074 | print_hwcache_events(event_glob); | ||
1075 | |||
1076 | if (event_glob != NULL) | ||
1077 | return; | ||
1078 | |||
951 | printf("\n"); | 1079 | printf("\n"); |
952 | printf(" %-42s [%s]\n", | 1080 | printf(" %-50s [%s]\n", |
953 | "rNNN (see 'perf list --help' on how to encode it)", | 1081 | "rNNN (see 'perf list --help' on how to encode it)", |
954 | event_type_descriptors[PERF_TYPE_RAW]); | 1082 | event_type_descriptors[PERF_TYPE_RAW]); |
955 | printf("\n"); | 1083 | printf("\n"); |
956 | 1084 | ||
957 | printf(" %-42s [%s]\n", | 1085 | printf(" %-50s [%s]\n", |
958 | "mem:<addr>[:access]", | 1086 | "mem:<addr>[:access]", |
959 | event_type_descriptors[PERF_TYPE_BREAKPOINT]); | 1087 | event_type_descriptors[PERF_TYPE_BREAKPOINT]); |
960 | printf("\n"); | 1088 | printf("\n"); |
961 | 1089 | ||
962 | print_tracepoint_events(); | 1090 | print_tracepoint_events(NULL, NULL); |
963 | 1091 | ||
964 | exit(129); | 1092 | exit(129); |
965 | } | 1093 | } |