diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-stat.c | 8 | ||||
-rw-r--r-- | tools/perf/util/header.c | 48 | ||||
-rw-r--r-- | tools/perf/util/include/linux/bitops.h | 2 | ||||
-rw-r--r-- | tools/perf/util/parse-events-test.c | 122 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 71 | ||||
-rw-r--r-- | tools/perf/util/parse-events.h | 15 | ||||
-rw-r--r-- | tools/perf/util/parse-events.l | 129 | ||||
-rw-r--r-- | tools/perf/util/parse-events.y | 71 | ||||
-rw-r--r-- | tools/perf/util/pmu.c | 166 | ||||
-rw-r--r-- | tools/perf/util/pmu.h | 11 | ||||
-rw-r--r-- | tools/perf/util/session.c | 10 | ||||
-rw-r--r-- | tools/perf/util/session.h | 1 |
12 files changed, 558 insertions, 96 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 875bf2675326..861f0aec77ae 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -1179,6 +1179,12 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
1179 | fprintf(stderr, "cannot use both --output and --log-fd\n"); | 1179 | fprintf(stderr, "cannot use both --output and --log-fd\n"); |
1180 | usage_with_options(stat_usage, options); | 1180 | usage_with_options(stat_usage, options); |
1181 | } | 1181 | } |
1182 | |||
1183 | if (output_fd < 0) { | ||
1184 | fprintf(stderr, "argument to --log-fd must be a > 0\n"); | ||
1185 | usage_with_options(stat_usage, options); | ||
1186 | } | ||
1187 | |||
1182 | if (!output) { | 1188 | if (!output) { |
1183 | struct timespec tm; | 1189 | struct timespec tm; |
1184 | mode = append_file ? "a" : "w"; | 1190 | mode = append_file ? "a" : "w"; |
@@ -1190,7 +1196,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
1190 | } | 1196 | } |
1191 | clock_gettime(CLOCK_REALTIME, &tm); | 1197 | clock_gettime(CLOCK_REALTIME, &tm); |
1192 | fprintf(output, "# started on %s\n", ctime(&tm.tv_sec)); | 1198 | fprintf(output, "# started on %s\n", ctime(&tm.tv_sec)); |
1193 | } else if (output_fd != 2) { | 1199 | } else if (output_fd > 0) { |
1194 | mode = append_file ? "a" : "w"; | 1200 | mode = append_file ? "a" : "w"; |
1195 | output = fdopen(output_fd, mode); | 1201 | output = fdopen(output_fd, mode); |
1196 | if (!output) { | 1202 | if (!output) { |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 07c8f3792954..a5e2015319ee 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1942,7 +1942,6 @@ int perf_file_header__read(struct perf_file_header *header, | |||
1942 | else | 1942 | else |
1943 | return -1; | 1943 | return -1; |
1944 | } else if (ph->needs_swap) { | 1944 | } else if (ph->needs_swap) { |
1945 | unsigned int i; | ||
1946 | /* | 1945 | /* |
1947 | * feature bitmap is declared as an array of unsigned longs -- | 1946 | * feature bitmap is declared as an array of unsigned longs -- |
1948 | * not good since its size can differ between the host that | 1947 | * not good since its size can differ between the host that |
@@ -1958,14 +1957,17 @@ int perf_file_header__read(struct perf_file_header *header, | |||
1958 | * file), punt and fallback to the original behavior -- | 1957 | * file), punt and fallback to the original behavior -- |
1959 | * clearing all feature bits and setting buildid. | 1958 | * clearing all feature bits and setting buildid. |
1960 | */ | 1959 | */ |
1961 | for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i) | 1960 | mem_bswap_64(&header->adds_features, |
1962 | header->adds_features[i] = bswap_64(header->adds_features[i]); | 1961 | BITS_TO_U64(HEADER_FEAT_BITS)); |
1963 | 1962 | ||
1964 | if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { | 1963 | if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { |
1965 | for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i) { | 1964 | /* unswap as u64 */ |
1966 | header->adds_features[i] = bswap_64(header->adds_features[i]); | 1965 | mem_bswap_64(&header->adds_features, |
1967 | header->adds_features[i] = bswap_32(header->adds_features[i]); | 1966 | BITS_TO_U64(HEADER_FEAT_BITS)); |
1968 | } | 1967 | |
1968 | /* unswap as u32 */ | ||
1969 | mem_bswap_32(&header->adds_features, | ||
1970 | BITS_TO_U32(HEADER_FEAT_BITS)); | ||
1969 | } | 1971 | } |
1970 | 1972 | ||
1971 | if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { | 1973 | if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { |
@@ -2091,6 +2093,35 @@ static int read_attr(int fd, struct perf_header *ph, | |||
2091 | return ret <= 0 ? -1 : 0; | 2093 | return ret <= 0 ? -1 : 0; |
2092 | } | 2094 | } |
2093 | 2095 | ||
2096 | static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel) | ||
2097 | { | ||
2098 | struct event_format *event = trace_find_event(evsel->attr.config); | ||
2099 | char bf[128]; | ||
2100 | |||
2101 | if (event == NULL) | ||
2102 | return -1; | ||
2103 | |||
2104 | snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name); | ||
2105 | evsel->name = strdup(bf); | ||
2106 | if (event->name == NULL) | ||
2107 | return -1; | ||
2108 | |||
2109 | return 0; | ||
2110 | } | ||
2111 | |||
2112 | static int perf_evlist__set_tracepoint_names(struct perf_evlist *evlist) | ||
2113 | { | ||
2114 | struct perf_evsel *pos; | ||
2115 | |||
2116 | list_for_each_entry(pos, &evlist->entries, node) { | ||
2117 | if (pos->attr.type == PERF_TYPE_TRACEPOINT && | ||
2118 | perf_evsel__set_tracepoint_name(pos)) | ||
2119 | return -1; | ||
2120 | } | ||
2121 | |||
2122 | return 0; | ||
2123 | } | ||
2124 | |||
2094 | int perf_session__read_header(struct perf_session *session, int fd) | 2125 | int perf_session__read_header(struct perf_session *session, int fd) |
2095 | { | 2126 | { |
2096 | struct perf_header *header = &session->header; | 2127 | struct perf_header *header = &session->header; |
@@ -2172,6 +2203,9 @@ int perf_session__read_header(struct perf_session *session, int fd) | |||
2172 | 2203 | ||
2173 | lseek(fd, header->data_offset, SEEK_SET); | 2204 | lseek(fd, header->data_offset, SEEK_SET); |
2174 | 2205 | ||
2206 | if (perf_evlist__set_tracepoint_names(session->evlist)) | ||
2207 | goto out_delete_evlist; | ||
2208 | |||
2175 | header->frozen = 1; | 2209 | header->frozen = 1; |
2176 | return 0; | 2210 | return 0; |
2177 | out_errno: | 2211 | out_errno: |
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h index f1584833bd22..587a230d2075 100644 --- a/tools/perf/util/include/linux/bitops.h +++ b/tools/perf/util/include/linux/bitops.h | |||
@@ -8,6 +8,8 @@ | |||
8 | #define BITS_PER_LONG __WORDSIZE | 8 | #define BITS_PER_LONG __WORDSIZE |
9 | #define BITS_PER_BYTE 8 | 9 | #define BITS_PER_BYTE 8 |
10 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) | 10 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) |
11 | #define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) | ||
12 | #define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) | ||
11 | 13 | ||
12 | #define for_each_set_bit(bit, addr, size) \ | 14 | #define for_each_set_bit(bit, addr, size) \ |
13 | for ((bit) = find_first_bit((addr), (size)); \ | 15 | for ((bit) = find_first_bit((addr), (size)); \ |
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c index d0cf7c1ed068..229af6da33a2 100644 --- a/tools/perf/util/parse-events-test.c +++ b/tools/perf/util/parse-events-test.c | |||
@@ -430,6 +430,49 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist) | |||
430 | return 0; | 430 | return 0; |
431 | } | 431 | } |
432 | 432 | ||
433 | static int test__checkterms_simple(struct list_head *terms) | ||
434 | { | ||
435 | struct parse_events__term *term; | ||
436 | |||
437 | /* config=10 */ | ||
438 | term = list_entry(terms->next, struct parse_events__term, list); | ||
439 | TEST_ASSERT_VAL("wrong type term", | ||
440 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG); | ||
441 | TEST_ASSERT_VAL("wrong type val", | ||
442 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
443 | TEST_ASSERT_VAL("wrong val", term->val.num == 10); | ||
444 | TEST_ASSERT_VAL("wrong config", !term->config); | ||
445 | |||
446 | /* config1 */ | ||
447 | term = list_entry(term->list.next, struct parse_events__term, list); | ||
448 | TEST_ASSERT_VAL("wrong type term", | ||
449 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1); | ||
450 | TEST_ASSERT_VAL("wrong type val", | ||
451 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
452 | TEST_ASSERT_VAL("wrong val", term->val.num == 1); | ||
453 | TEST_ASSERT_VAL("wrong config", !term->config); | ||
454 | |||
455 | /* config2=3 */ | ||
456 | term = list_entry(term->list.next, struct parse_events__term, list); | ||
457 | TEST_ASSERT_VAL("wrong type term", | ||
458 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2); | ||
459 | TEST_ASSERT_VAL("wrong type val", | ||
460 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
461 | TEST_ASSERT_VAL("wrong val", term->val.num == 3); | ||
462 | TEST_ASSERT_VAL("wrong config", !term->config); | ||
463 | |||
464 | /* umask=1*/ | ||
465 | term = list_entry(term->list.next, struct parse_events__term, list); | ||
466 | TEST_ASSERT_VAL("wrong type term", | ||
467 | term->type_term == PARSE_EVENTS__TERM_TYPE_USER); | ||
468 | TEST_ASSERT_VAL("wrong type val", | ||
469 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
470 | TEST_ASSERT_VAL("wrong val", term->val.num == 1); | ||
471 | TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "umask")); | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
433 | struct test__event_st { | 476 | struct test__event_st { |
434 | const char *name; | 477 | const char *name; |
435 | __u32 type; | 478 | __u32 type; |
@@ -559,7 +602,23 @@ static struct test__event_st test__events_pmu[] = { | |||
559 | #define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \ | 602 | #define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \ |
560 | sizeof(struct test__event_st)) | 603 | sizeof(struct test__event_st)) |
561 | 604 | ||
562 | static int test(struct test__event_st *e) | 605 | struct test__term { |
606 | const char *str; | ||
607 | __u32 type; | ||
608 | int (*check)(struct list_head *terms); | ||
609 | }; | ||
610 | |||
611 | static struct test__term test__terms[] = { | ||
612 | [0] = { | ||
613 | .str = "config=10,config1,config2=3,umask=1", | ||
614 | .check = test__checkterms_simple, | ||
615 | }, | ||
616 | }; | ||
617 | |||
618 | #define TEST__TERMS_CNT (sizeof(test__terms) / \ | ||
619 | sizeof(struct test__term)) | ||
620 | |||
621 | static int test_event(struct test__event_st *e) | ||
563 | { | 622 | { |
564 | struct perf_evlist *evlist; | 623 | struct perf_evlist *evlist; |
565 | int ret; | 624 | int ret; |
@@ -590,7 +649,48 @@ static int test_events(struct test__event_st *events, unsigned cnt) | |||
590 | struct test__event_st *e = &events[i]; | 649 | struct test__event_st *e = &events[i]; |
591 | 650 | ||
592 | pr_debug("running test %d '%s'\n", i, e->name); | 651 | pr_debug("running test %d '%s'\n", i, e->name); |
593 | ret = test(e); | 652 | ret = test_event(e); |
653 | if (ret) | ||
654 | break; | ||
655 | } | ||
656 | |||
657 | return ret; | ||
658 | } | ||
659 | |||
660 | static int test_term(struct test__term *t) | ||
661 | { | ||
662 | struct list_head *terms; | ||
663 | int ret; | ||
664 | |||
665 | terms = malloc(sizeof(*terms)); | ||
666 | if (!terms) | ||
667 | return -ENOMEM; | ||
668 | |||
669 | INIT_LIST_HEAD(terms); | ||
670 | |||
671 | ret = parse_events_terms(terms, t->str); | ||
672 | if (ret) { | ||
673 | pr_debug("failed to parse terms '%s', err %d\n", | ||
674 | t->str , ret); | ||
675 | return ret; | ||
676 | } | ||
677 | |||
678 | ret = t->check(terms); | ||
679 | parse_events__free_terms(terms); | ||
680 | |||
681 | return ret; | ||
682 | } | ||
683 | |||
684 | static int test_terms(struct test__term *terms, unsigned cnt) | ||
685 | { | ||
686 | int ret = 0; | ||
687 | unsigned i; | ||
688 | |||
689 | for (i = 0; i < cnt; i++) { | ||
690 | struct test__term *t = &terms[i]; | ||
691 | |||
692 | pr_debug("running test %d '%s'\n", i, t->str); | ||
693 | ret = test_term(t); | ||
594 | if (ret) | 694 | if (ret) |
595 | break; | 695 | break; |
596 | } | 696 | } |
@@ -617,9 +717,21 @@ int parse_events__test(void) | |||
617 | { | 717 | { |
618 | int ret; | 718 | int ret; |
619 | 719 | ||
620 | ret = test_events(test__events, TEST__EVENTS_CNT); | 720 | do { |
621 | if (!ret && test_pmu()) | 721 | ret = test_events(test__events, TEST__EVENTS_CNT); |
622 | ret = test_events(test__events_pmu, TEST__EVENTS_PMU_CNT); | 722 | if (ret) |
723 | break; | ||
724 | |||
725 | if (test_pmu()) { | ||
726 | ret = test_events(test__events_pmu, | ||
727 | TEST__EVENTS_PMU_CNT); | ||
728 | if (ret) | ||
729 | break; | ||
730 | } | ||
731 | |||
732 | ret = test_terms(test__terms, TEST__TERMS_CNT); | ||
733 | |||
734 | } while (0); | ||
623 | 735 | ||
624 | return ret; | 736 | return ret; |
625 | } | 737 | } |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index eacf932a36a0..0cc27da30ddb 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include "cache.h" | 11 | #include "cache.h" |
12 | #include "header.h" | 12 | #include "header.h" |
13 | #include "debugfs.h" | 13 | #include "debugfs.h" |
14 | #include "parse-events-bison.h" | ||
15 | #define YY_EXTRA_TYPE int | ||
14 | #include "parse-events-flex.h" | 16 | #include "parse-events-flex.h" |
15 | #include "pmu.h" | 17 | #include "pmu.h" |
16 | 18 | ||
@@ -26,7 +28,7 @@ struct event_symbol { | |||
26 | #ifdef PARSER_DEBUG | 28 | #ifdef PARSER_DEBUG |
27 | extern int parse_events_debug; | 29 | extern int parse_events_debug; |
28 | #endif | 30 | #endif |
29 | int parse_events_parse(struct list_head *list, int *idx); | 31 | int parse_events_parse(void *data, void *scanner); |
30 | 32 | ||
31 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x | 33 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x |
32 | #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x | 34 | #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x |
@@ -529,6 +531,9 @@ int parse_events_add_pmu(struct list_head **list, int *idx, | |||
529 | 531 | ||
530 | memset(&attr, 0, sizeof(attr)); | 532 | memset(&attr, 0, sizeof(attr)); |
531 | 533 | ||
534 | if (perf_pmu__check_alias(pmu, head_config)) | ||
535 | return -EINVAL; | ||
536 | |||
532 | /* | 537 | /* |
533 | * Configure hardcoded terms first, no need to check | 538 | * Configure hardcoded terms first, no need to check |
534 | * return value when called with fail == 0 ;) | 539 | * return value when called with fail == 0 ;) |
@@ -617,27 +622,62 @@ int parse_events_modifier(struct list_head *list, char *str) | |||
617 | return 0; | 622 | return 0; |
618 | } | 623 | } |
619 | 624 | ||
620 | int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) | 625 | static int parse_events__scanner(const char *str, void *data, int start_token) |
621 | { | 626 | { |
622 | LIST_HEAD(list); | ||
623 | LIST_HEAD(list_tmp); | ||
624 | YY_BUFFER_STATE buffer; | 627 | YY_BUFFER_STATE buffer; |
625 | int ret, idx = evlist->nr_entries; | 628 | void *scanner; |
629 | int ret; | ||
630 | |||
631 | ret = parse_events_lex_init_extra(start_token, &scanner); | ||
632 | if (ret) | ||
633 | return ret; | ||
626 | 634 | ||
627 | buffer = parse_events__scan_string(str); | 635 | buffer = parse_events__scan_string(str, scanner); |
628 | 636 | ||
629 | #ifdef PARSER_DEBUG | 637 | #ifdef PARSER_DEBUG |
630 | parse_events_debug = 1; | 638 | parse_events_debug = 1; |
631 | #endif | 639 | #endif |
632 | ret = parse_events_parse(&list, &idx); | 640 | ret = parse_events_parse(data, scanner); |
641 | |||
642 | parse_events__flush_buffer(buffer, scanner); | ||
643 | parse_events__delete_buffer(buffer, scanner); | ||
644 | parse_events_lex_destroy(scanner); | ||
645 | return ret; | ||
646 | } | ||
647 | |||
648 | /* | ||
649 | * parse event config string, return a list of event terms. | ||
650 | */ | ||
651 | int parse_events_terms(struct list_head *terms, const char *str) | ||
652 | { | ||
653 | struct parse_events_data__terms data = { | ||
654 | .terms = NULL, | ||
655 | }; | ||
656 | int ret; | ||
657 | |||
658 | ret = parse_events__scanner(str, &data, PE_START_TERMS); | ||
659 | if (!ret) { | ||
660 | list_splice(data.terms, terms); | ||
661 | free(data.terms); | ||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | parse_events__free_terms(data.terms); | ||
666 | return ret; | ||
667 | } | ||
633 | 668 | ||
634 | parse_events__flush_buffer(buffer); | 669 | int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) |
635 | parse_events__delete_buffer(buffer); | 670 | { |
636 | parse_events_lex_destroy(); | 671 | struct parse_events_data__events data = { |
672 | .list = LIST_HEAD_INIT(data.list), | ||
673 | .idx = evlist->nr_entries, | ||
674 | }; | ||
675 | int ret; | ||
637 | 676 | ||
677 | ret = parse_events__scanner(str, &data, PE_START_EVENTS); | ||
638 | if (!ret) { | 678 | if (!ret) { |
639 | int entries = idx - evlist->nr_entries; | 679 | int entries = data.idx - evlist->nr_entries; |
640 | perf_evlist__splice_list_tail(evlist, &list, entries); | 680 | perf_evlist__splice_list_tail(evlist, &data.list, entries); |
641 | return 0; | 681 | return 0; |
642 | } | 682 | } |
643 | 683 | ||
@@ -937,6 +977,13 @@ int parse_events__term_str(struct parse_events__term **term, | |||
937 | config, str, 0); | 977 | config, str, 0); |
938 | } | 978 | } |
939 | 979 | ||
980 | int parse_events__term_clone(struct parse_events__term **new, | ||
981 | struct parse_events__term *term) | ||
982 | { | ||
983 | return new_term(new, term->type_val, term->type_term, term->config, | ||
984 | term->val.str, term->val.num); | ||
985 | } | ||
986 | |||
940 | void parse_events__free_terms(struct list_head *terms) | 987 | void parse_events__free_terms(struct list_head *terms) |
941 | { | 988 | { |
942 | struct parse_events__term *term, *h; | 989 | struct parse_events__term *term, *h; |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 1784f06e3a6a..ee9c218a193c 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -31,6 +31,7 @@ extern int parse_events_option(const struct option *opt, const char *str, | |||
31 | int unset); | 31 | int unset); |
32 | extern int parse_events(struct perf_evlist *evlist, const char *str, | 32 | extern int parse_events(struct perf_evlist *evlist, const char *str, |
33 | int unset); | 33 | int unset); |
34 | extern int parse_events_terms(struct list_head *terms, const char *str); | ||
34 | extern int parse_filter(const struct option *opt, const char *str, int unset); | 35 | extern int parse_filter(const struct option *opt, const char *str, int unset); |
35 | 36 | ||
36 | #define EVENTS_HELP_MAX (128*1024) | 37 | #define EVENTS_HELP_MAX (128*1024) |
@@ -61,11 +62,22 @@ struct parse_events__term { | |||
61 | struct list_head list; | 62 | struct list_head list; |
62 | }; | 63 | }; |
63 | 64 | ||
65 | struct parse_events_data__events { | ||
66 | struct list_head list; | ||
67 | int idx; | ||
68 | }; | ||
69 | |||
70 | struct parse_events_data__terms { | ||
71 | struct list_head *terms; | ||
72 | }; | ||
73 | |||
64 | int parse_events__is_hardcoded_term(struct parse_events__term *term); | 74 | int parse_events__is_hardcoded_term(struct parse_events__term *term); |
65 | int parse_events__term_num(struct parse_events__term **_term, | 75 | int parse_events__term_num(struct parse_events__term **_term, |
66 | int type_term, char *config, long num); | 76 | int type_term, char *config, long num); |
67 | int parse_events__term_str(struct parse_events__term **_term, | 77 | int parse_events__term_str(struct parse_events__term **_term, |
68 | int type_term, char *config, char *str); | 78 | int type_term, char *config, char *str); |
79 | int parse_events__term_clone(struct parse_events__term **new, | ||
80 | struct parse_events__term *term); | ||
69 | void parse_events__free_terms(struct list_head *terms); | 81 | void parse_events__free_terms(struct list_head *terms); |
70 | int parse_events_modifier(struct list_head *list, char *str); | 82 | int parse_events_modifier(struct list_head *list, char *str); |
71 | int parse_events_add_tracepoint(struct list_head **list, int *idx, | 83 | int parse_events_add_tracepoint(struct list_head **list, int *idx, |
@@ -81,8 +93,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx, | |||
81 | char *pmu , struct list_head *head_config); | 93 | char *pmu , struct list_head *head_config); |
82 | void parse_events_update_lists(struct list_head *list_event, | 94 | void parse_events_update_lists(struct list_head *list_event, |
83 | struct list_head *list_all); | 95 | struct list_head *list_all); |
84 | void parse_events_error(struct list_head *list_all, | 96 | void parse_events_error(void *data, void *scanner, char const *msg); |
85 | int *idx, char const *msg); | ||
86 | int parse_events__test(void); | 97 | int parse_events__test(void); |
87 | 98 | ||
88 | void print_events(const char *event_glob); | 99 | void print_events(const char *event_glob); |
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 618a8e788399..488362e14133 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
@@ -1,4 +1,6 @@ | |||
1 | 1 | ||
2 | %option reentrant | ||
3 | %option bison-bridge | ||
2 | %option prefix="parse_events_" | 4 | %option prefix="parse_events_" |
3 | %option stack | 5 | %option stack |
4 | 6 | ||
@@ -8,7 +10,10 @@ | |||
8 | #include "parse-events-bison.h" | 10 | #include "parse-events-bison.h" |
9 | #include "parse-events.h" | 11 | #include "parse-events.h" |
10 | 12 | ||
11 | static int __value(char *str, int base, int token) | 13 | char *parse_events_get_text(yyscan_t yyscanner); |
14 | YYSTYPE *parse_events_get_lval(yyscan_t yyscanner); | ||
15 | |||
16 | static int __value(YYSTYPE *yylval, char *str, int base, int token) | ||
12 | { | 17 | { |
13 | long num; | 18 | long num; |
14 | 19 | ||
@@ -17,35 +22,48 @@ static int __value(char *str, int base, int token) | |||
17 | if (errno) | 22 | if (errno) |
18 | return PE_ERROR; | 23 | return PE_ERROR; |
19 | 24 | ||
20 | parse_events_lval.num = num; | 25 | yylval->num = num; |
21 | return token; | 26 | return token; |
22 | } | 27 | } |
23 | 28 | ||
24 | static int value(int base) | 29 | static int value(yyscan_t scanner, int base) |
25 | { | 30 | { |
26 | return __value(parse_events_text, base, PE_VALUE); | 31 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
32 | char *text = parse_events_get_text(scanner); | ||
33 | |||
34 | return __value(yylval, text, base, PE_VALUE); | ||
27 | } | 35 | } |
28 | 36 | ||
29 | static int raw(void) | 37 | static int raw(yyscan_t scanner) |
30 | { | 38 | { |
31 | return __value(parse_events_text + 1, 16, PE_RAW); | 39 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
40 | char *text = parse_events_get_text(scanner); | ||
41 | |||
42 | return __value(yylval, text + 1, 16, PE_RAW); | ||
32 | } | 43 | } |
33 | 44 | ||
34 | static int str(int token) | 45 | static int str(yyscan_t scanner, int token) |
35 | { | 46 | { |
36 | parse_events_lval.str = strdup(parse_events_text); | 47 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
48 | char *text = parse_events_get_text(scanner); | ||
49 | |||
50 | yylval->str = strdup(text); | ||
37 | return token; | 51 | return token; |
38 | } | 52 | } |
39 | 53 | ||
40 | static int sym(int type, int config) | 54 | static int sym(yyscan_t scanner, int type, int config) |
41 | { | 55 | { |
42 | parse_events_lval.num = (type << 16) + config; | 56 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
57 | |||
58 | yylval->num = (type << 16) + config; | ||
43 | return PE_VALUE_SYM; | 59 | return PE_VALUE_SYM; |
44 | } | 60 | } |
45 | 61 | ||
46 | static int term(int type) | 62 | static int term(yyscan_t scanner, int type) |
47 | { | 63 | { |
48 | parse_events_lval.num = type; | 64 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
65 | |||
66 | yylval->num = type; | ||
49 | return PE_TERM; | 67 | return PE_TERM; |
50 | } | 68 | } |
51 | 69 | ||
@@ -61,25 +79,38 @@ modifier_event [ukhpGH]{1,8} | |||
61 | modifier_bp [rwx] | 79 | modifier_bp [rwx] |
62 | 80 | ||
63 | %% | 81 | %% |
64 | cpu-cycles|cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } | 82 | |
65 | stalled-cycles-frontend|idle-cycles-frontend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } | 83 | %{ |
66 | stalled-cycles-backend|idle-cycles-backend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } | 84 | { |
67 | instructions { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); } | 85 | int start_token; |
68 | cache-references { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); } | 86 | |
69 | cache-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); } | 87 | start_token = (int) parse_events_get_extra(yyscanner); |
70 | branch-instructions|branches { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); } | 88 | if (start_token) { |
71 | branch-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); } | 89 | parse_events_set_extra(NULL, yyscanner); |
72 | bus-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); } | 90 | return start_token; |
73 | ref-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); } | 91 | } |
74 | cpu-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); } | 92 | } |
75 | task-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); } | 93 | %} |
76 | page-faults|faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); } | 94 | |
77 | minor-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); } | 95 | cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } |
78 | major-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); } | 96 | stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } |
79 | context-switches|cs { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); } | 97 | stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } |
80 | cpu-migrations|migrations { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); } | 98 | instructions { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); } |
81 | alignment-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } | 99 | cache-references { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); } |
82 | emulation-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } | 100 | cache-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); } |
101 | branch-instructions|branches { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); } | ||
102 | branch-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); } | ||
103 | bus-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); } | ||
104 | ref-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); } | ||
105 | cpu-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); } | ||
106 | task-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); } | ||
107 | page-faults|faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); } | ||
108 | minor-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); } | ||
109 | major-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); } | ||
110 | context-switches|cs { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); } | ||
111 | cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); } | ||
112 | alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } | ||
113 | emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } | ||
83 | 114 | ||
84 | L1-dcache|l1-d|l1d|L1-data | | 115 | L1-dcache|l1-d|l1d|L1-data | |
85 | L1-icache|l1-i|l1i|L1-instruction | | 116 | L1-icache|l1-i|l1i|L1-instruction | |
@@ -87,14 +118,14 @@ LLC|L2 | | |||
87 | dTLB|d-tlb|Data-TLB | | 118 | dTLB|d-tlb|Data-TLB | |
88 | iTLB|i-tlb|Instruction-TLB | | 119 | iTLB|i-tlb|Instruction-TLB | |
89 | branch|branches|bpu|btb|bpc | | 120 | branch|branches|bpu|btb|bpc | |
90 | node { return str(PE_NAME_CACHE_TYPE); } | 121 | node { return str(yyscanner, PE_NAME_CACHE_TYPE); } |
91 | 122 | ||
92 | load|loads|read | | 123 | load|loads|read | |
93 | store|stores|write | | 124 | store|stores|write | |
94 | prefetch|prefetches | | 125 | prefetch|prefetches | |
95 | speculative-read|speculative-load | | 126 | speculative-read|speculative-load | |
96 | refs|Reference|ops|access | | 127 | refs|Reference|ops|access | |
97 | misses|miss { return str(PE_NAME_CACHE_OP_RESULT); } | 128 | misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); } |
98 | 129 | ||
99 | /* | 130 | /* |
100 | * These are event config hardcoded term names to be specified | 131 | * These are event config hardcoded term names to be specified |
@@ -102,20 +133,20 @@ misses|miss { return str(PE_NAME_CACHE_OP_RESULT); } | |||
102 | * so we can put them here directly. In case the we have a conflict | 133 | * so we can put them here directly. In case the we have a conflict |
103 | * in future, this needs to go into '//' condition block. | 134 | * in future, this needs to go into '//' condition block. |
104 | */ | 135 | */ |
105 | config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); } | 136 | config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); } |
106 | config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); } | 137 | config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); } |
107 | config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); } | 138 | config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); } |
108 | name { return term(PARSE_EVENTS__TERM_TYPE_NAME); } | 139 | name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); } |
109 | period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } | 140 | period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } |
110 | branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } | 141 | branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } |
111 | 142 | ||
112 | mem: { BEGIN(mem); return PE_PREFIX_MEM; } | 143 | mem: { BEGIN(mem); return PE_PREFIX_MEM; } |
113 | r{num_raw_hex} { return raw(); } | 144 | r{num_raw_hex} { return raw(yyscanner); } |
114 | {num_dec} { return value(10); } | 145 | {num_dec} { return value(yyscanner, 10); } |
115 | {num_hex} { return value(16); } | 146 | {num_hex} { return value(yyscanner, 16); } |
116 | 147 | ||
117 | {modifier_event} { return str(PE_MODIFIER_EVENT); } | 148 | {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } |
118 | {name} { return str(PE_NAME); } | 149 | {name} { return str(yyscanner, PE_NAME); } |
119 | "/" { return '/'; } | 150 | "/" { return '/'; } |
120 | - { return '-'; } | 151 | - { return '-'; } |
121 | , { return ','; } | 152 | , { return ','; } |
@@ -123,17 +154,17 @@ r{num_raw_hex} { return raw(); } | |||
123 | = { return '='; } | 154 | = { return '='; } |
124 | 155 | ||
125 | <mem>{ | 156 | <mem>{ |
126 | {modifier_bp} { return str(PE_MODIFIER_BP); } | 157 | {modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); } |
127 | : { return ':'; } | 158 | : { return ':'; } |
128 | {num_dec} { return value(10); } | 159 | {num_dec} { return value(yyscanner, 10); } |
129 | {num_hex} { return value(16); } | 160 | {num_hex} { return value(yyscanner, 16); } |
130 | /* | 161 | /* |
131 | * We need to separate 'mem:' scanner part, in order to get specific | 162 | * We need to separate 'mem:' scanner part, in order to get specific |
132 | * modifier bits parsed out. Otherwise we would need to handle PE_NAME | 163 | * modifier bits parsed out. Otherwise we would need to handle PE_NAME |
133 | * and we'd need to parse it manually. During the escape from <mem> | 164 | * and we'd need to parse it manually. During the escape from <mem> |
134 | * state we need to put the escaping char back, so we dont miss it. | 165 | * state we need to put the escaping char back, so we dont miss it. |
135 | */ | 166 | */ |
136 | . { unput(*parse_events_text); BEGIN(INITIAL); } | 167 | . { unput(*yytext); BEGIN(INITIAL); } |
137 | /* | 168 | /* |
138 | * We destroy the scanner after reaching EOF, | 169 | * We destroy the scanner after reaching EOF, |
139 | * but anyway just to be sure get back to INIT state. | 170 | * but anyway just to be sure get back to INIT state. |
@@ -143,7 +174,7 @@ r{num_raw_hex} { return raw(); } | |||
143 | 174 | ||
144 | %% | 175 | %% |
145 | 176 | ||
146 | int parse_events_wrap(void) | 177 | int parse_events_wrap(void *scanner __used) |
147 | { | 178 | { |
148 | return 1; | 179 | return 1; |
149 | } | 180 | } |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 362cc59332ae..9525c455d27f 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
@@ -1,7 +1,8 @@ | |||
1 | 1 | %pure-parser | |
2 | %name-prefix "parse_events_" | 2 | %name-prefix "parse_events_" |
3 | %parse-param {struct list_head *list_all} | 3 | %parse-param {void *_data} |
4 | %parse-param {int *idx} | 4 | %parse-param {void *scanner} |
5 | %lex-param {void* scanner} | ||
5 | 6 | ||
6 | %{ | 7 | %{ |
7 | 8 | ||
@@ -12,8 +13,9 @@ | |||
12 | #include "types.h" | 13 | #include "types.h" |
13 | #include "util.h" | 14 | #include "util.h" |
14 | #include "parse-events.h" | 15 | #include "parse-events.h" |
16 | #include "parse-events-bison.h" | ||
15 | 17 | ||
16 | extern int parse_events_lex (void); | 18 | extern int parse_events_lex (YYSTYPE* lvalp, void* scanner); |
17 | 19 | ||
18 | #define ABORT_ON(val) \ | 20 | #define ABORT_ON(val) \ |
19 | do { \ | 21 | do { \ |
@@ -23,6 +25,7 @@ do { \ | |||
23 | 25 | ||
24 | %} | 26 | %} |
25 | 27 | ||
28 | %token PE_START_EVENTS PE_START_TERMS | ||
26 | %token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM | 29 | %token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM |
27 | %token PE_NAME | 30 | %token PE_NAME |
28 | %token PE_MODIFIER_EVENT PE_MODIFIER_BP | 31 | %token PE_MODIFIER_EVENT PE_MODIFIER_BP |
@@ -58,24 +61,33 @@ do { \ | |||
58 | } | 61 | } |
59 | %% | 62 | %% |
60 | 63 | ||
64 | start: | ||
65 | PE_START_EVENTS events | ||
66 | | | ||
67 | PE_START_TERMS terms | ||
68 | |||
61 | events: | 69 | events: |
62 | events ',' event | event | 70 | events ',' event | event |
63 | 71 | ||
64 | event: | 72 | event: |
65 | event_def PE_MODIFIER_EVENT | 73 | event_def PE_MODIFIER_EVENT |
66 | { | 74 | { |
75 | struct parse_events_data__events *data = _data; | ||
76 | |||
67 | /* | 77 | /* |
68 | * Apply modifier on all events added by single event definition | 78 | * Apply modifier on all events added by single event definition |
69 | * (there could be more events added for multiple tracepoint | 79 | * (there could be more events added for multiple tracepoint |
70 | * definitions via '*?'. | 80 | * definitions via '*?'. |
71 | */ | 81 | */ |
72 | ABORT_ON(parse_events_modifier($1, $2)); | 82 | ABORT_ON(parse_events_modifier($1, $2)); |
73 | parse_events_update_lists($1, list_all); | 83 | parse_events_update_lists($1, &data->list); |
74 | } | 84 | } |
75 | | | 85 | | |
76 | event_def | 86 | event_def |
77 | { | 87 | { |
78 | parse_events_update_lists($1, list_all); | 88 | struct parse_events_data__events *data = _data; |
89 | |||
90 | parse_events_update_lists($1, &data->list); | ||
79 | } | 91 | } |
80 | 92 | ||
81 | event_def: event_pmu | | 93 | event_def: event_pmu | |
@@ -89,9 +101,10 @@ event_def: event_pmu | | |||
89 | event_pmu: | 101 | event_pmu: |
90 | PE_NAME '/' event_config '/' | 102 | PE_NAME '/' event_config '/' |
91 | { | 103 | { |
104 | struct parse_events_data__events *data = _data; | ||
92 | struct list_head *list = NULL; | 105 | struct list_head *list = NULL; |
93 | 106 | ||
94 | ABORT_ON(parse_events_add_pmu(&list, idx, $1, $3)); | 107 | ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); |
95 | parse_events__free_terms($3); | 108 | parse_events__free_terms($3); |
96 | $$ = list; | 109 | $$ = list; |
97 | } | 110 | } |
@@ -99,94 +112,115 @@ PE_NAME '/' event_config '/' | |||
99 | event_legacy_symbol: | 112 | event_legacy_symbol: |
100 | PE_VALUE_SYM '/' event_config '/' | 113 | PE_VALUE_SYM '/' event_config '/' |
101 | { | 114 | { |
115 | struct parse_events_data__events *data = _data; | ||
102 | struct list_head *list = NULL; | 116 | struct list_head *list = NULL; |
103 | int type = $1 >> 16; | 117 | int type = $1 >> 16; |
104 | int config = $1 & 255; | 118 | int config = $1 & 255; |
105 | 119 | ||
106 | ABORT_ON(parse_events_add_numeric(&list, idx, type, config, $3)); | 120 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, |
121 | type, config, $3)); | ||
107 | parse_events__free_terms($3); | 122 | parse_events__free_terms($3); |
108 | $$ = list; | 123 | $$ = list; |
109 | } | 124 | } |
110 | | | 125 | | |
111 | PE_VALUE_SYM sep_slash_dc | 126 | PE_VALUE_SYM sep_slash_dc |
112 | { | 127 | { |
128 | struct parse_events_data__events *data = _data; | ||
113 | struct list_head *list = NULL; | 129 | struct list_head *list = NULL; |
114 | int type = $1 >> 16; | 130 | int type = $1 >> 16; |
115 | int config = $1 & 255; | 131 | int config = $1 & 255; |
116 | 132 | ||
117 | ABORT_ON(parse_events_add_numeric(&list, idx, type, config, NULL)); | 133 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, |
134 | type, config, NULL)); | ||
118 | $$ = list; | 135 | $$ = list; |
119 | } | 136 | } |
120 | 137 | ||
121 | event_legacy_cache: | 138 | event_legacy_cache: |
122 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT | 139 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT |
123 | { | 140 | { |
141 | struct parse_events_data__events *data = _data; | ||
124 | struct list_head *list = NULL; | 142 | struct list_head *list = NULL; |
125 | 143 | ||
126 | ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, $5)); | 144 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); |
127 | $$ = list; | 145 | $$ = list; |
128 | } | 146 | } |
129 | | | 147 | | |
130 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT | 148 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT |
131 | { | 149 | { |
150 | struct parse_events_data__events *data = _data; | ||
132 | struct list_head *list = NULL; | 151 | struct list_head *list = NULL; |
133 | 152 | ||
134 | ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, NULL)); | 153 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); |
135 | $$ = list; | 154 | $$ = list; |
136 | } | 155 | } |
137 | | | 156 | | |
138 | PE_NAME_CACHE_TYPE | 157 | PE_NAME_CACHE_TYPE |
139 | { | 158 | { |
159 | struct parse_events_data__events *data = _data; | ||
140 | struct list_head *list = NULL; | 160 | struct list_head *list = NULL; |
141 | 161 | ||
142 | ABORT_ON(parse_events_add_cache(&list, idx, $1, NULL, NULL)); | 162 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); |
143 | $$ = list; | 163 | $$ = list; |
144 | } | 164 | } |
145 | 165 | ||
146 | event_legacy_mem: | 166 | event_legacy_mem: |
147 | PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc | 167 | PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc |
148 | { | 168 | { |
169 | struct parse_events_data__events *data = _data; | ||
149 | struct list_head *list = NULL; | 170 | struct list_head *list = NULL; |
150 | 171 | ||
151 | ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, $4)); | 172 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, |
173 | (void *) $2, $4)); | ||
152 | $$ = list; | 174 | $$ = list; |
153 | } | 175 | } |
154 | | | 176 | | |
155 | PE_PREFIX_MEM PE_VALUE sep_dc | 177 | PE_PREFIX_MEM PE_VALUE sep_dc |
156 | { | 178 | { |
179 | struct parse_events_data__events *data = _data; | ||
157 | struct list_head *list = NULL; | 180 | struct list_head *list = NULL; |
158 | 181 | ||
159 | ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, NULL)); | 182 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, |
183 | (void *) $2, NULL)); | ||
160 | $$ = list; | 184 | $$ = list; |
161 | } | 185 | } |
162 | 186 | ||
163 | event_legacy_tracepoint: | 187 | event_legacy_tracepoint: |
164 | PE_NAME ':' PE_NAME | 188 | PE_NAME ':' PE_NAME |
165 | { | 189 | { |
190 | struct parse_events_data__events *data = _data; | ||
166 | struct list_head *list = NULL; | 191 | struct list_head *list = NULL; |
167 | 192 | ||
168 | ABORT_ON(parse_events_add_tracepoint(&list, idx, $1, $3)); | 193 | ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); |
169 | $$ = list; | 194 | $$ = list; |
170 | } | 195 | } |
171 | 196 | ||
172 | event_legacy_numeric: | 197 | event_legacy_numeric: |
173 | PE_VALUE ':' PE_VALUE | 198 | PE_VALUE ':' PE_VALUE |
174 | { | 199 | { |
200 | struct parse_events_data__events *data = _data; | ||
175 | struct list_head *list = NULL; | 201 | struct list_head *list = NULL; |
176 | 202 | ||
177 | ABORT_ON(parse_events_add_numeric(&list, idx, $1, $3, NULL)); | 203 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, $1, $3, NULL)); |
178 | $$ = list; | 204 | $$ = list; |
179 | } | 205 | } |
180 | 206 | ||
181 | event_legacy_raw: | 207 | event_legacy_raw: |
182 | PE_RAW | 208 | PE_RAW |
183 | { | 209 | { |
210 | struct parse_events_data__events *data = _data; | ||
184 | struct list_head *list = NULL; | 211 | struct list_head *list = NULL; |
185 | 212 | ||
186 | ABORT_ON(parse_events_add_numeric(&list, idx, PERF_TYPE_RAW, $1, NULL)); | 213 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, |
214 | PERF_TYPE_RAW, $1, NULL)); | ||
187 | $$ = list; | 215 | $$ = list; |
188 | } | 216 | } |
189 | 217 | ||
218 | terms: event_config | ||
219 | { | ||
220 | struct parse_events_data__terms *data = _data; | ||
221 | data->terms = $1; | ||
222 | } | ||
223 | |||
190 | event_config: | 224 | event_config: |
191 | event_config ',' event_term | 225 | event_config ',' event_term |
192 | { | 226 | { |
@@ -267,8 +301,7 @@ sep_slash_dc: '/' | ':' | | |||
267 | 301 | ||
268 | %% | 302 | %% |
269 | 303 | ||
270 | void parse_events_error(struct list_head *list_all __used, | 304 | void parse_events_error(void *data __used, void *scanner __used, |
271 | int *idx __used, | ||
272 | char const *msg __used) | 305 | char const *msg __used) |
273 | { | 306 | { |
274 | } | 307 | } |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index a119a5371699..74d0948ec368 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -80,6 +80,114 @@ static int pmu_format(char *name, struct list_head *format) | |||
80 | return 0; | 80 | return 0; |
81 | } | 81 | } |
82 | 82 | ||
83 | static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) | ||
84 | { | ||
85 | struct perf_pmu__alias *alias; | ||
86 | char buf[256]; | ||
87 | int ret; | ||
88 | |||
89 | ret = fread(buf, 1, sizeof(buf), file); | ||
90 | if (ret == 0) | ||
91 | return -EINVAL; | ||
92 | buf[ret] = 0; | ||
93 | |||
94 | alias = malloc(sizeof(*alias)); | ||
95 | if (!alias) | ||
96 | return -ENOMEM; | ||
97 | |||
98 | INIT_LIST_HEAD(&alias->terms); | ||
99 | ret = parse_events_terms(&alias->terms, buf); | ||
100 | if (ret) { | ||
101 | free(alias); | ||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | alias->name = strdup(name); | ||
106 | list_add_tail(&alias->list, list); | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * Process all the sysfs attributes located under the directory | ||
112 | * specified in 'dir' parameter. | ||
113 | */ | ||
114 | static int pmu_aliases_parse(char *dir, struct list_head *head) | ||
115 | { | ||
116 | struct dirent *evt_ent; | ||
117 | DIR *event_dir; | ||
118 | int ret = 0; | ||
119 | |||
120 | event_dir = opendir(dir); | ||
121 | if (!event_dir) | ||
122 | return -EINVAL; | ||
123 | |||
124 | while (!ret && (evt_ent = readdir(event_dir))) { | ||
125 | char path[PATH_MAX]; | ||
126 | char *name = evt_ent->d_name; | ||
127 | FILE *file; | ||
128 | |||
129 | if (!strcmp(name, ".") || !strcmp(name, "..")) | ||
130 | continue; | ||
131 | |||
132 | snprintf(path, PATH_MAX, "%s/%s", dir, name); | ||
133 | |||
134 | ret = -EINVAL; | ||
135 | file = fopen(path, "r"); | ||
136 | if (!file) | ||
137 | break; | ||
138 | ret = perf_pmu__new_alias(head, name, file); | ||
139 | fclose(file); | ||
140 | } | ||
141 | |||
142 | closedir(event_dir); | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * Reading the pmu event aliases definition, which should be located at: | ||
148 | * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. | ||
149 | */ | ||
150 | static int pmu_aliases(char *name, struct list_head *head) | ||
151 | { | ||
152 | struct stat st; | ||
153 | char path[PATH_MAX]; | ||
154 | const char *sysfs; | ||
155 | |||
156 | sysfs = sysfs_find_mountpoint(); | ||
157 | if (!sysfs) | ||
158 | return -1; | ||
159 | |||
160 | snprintf(path, PATH_MAX, | ||
161 | "%s/bus/event_source/devices/%s/events", sysfs, name); | ||
162 | |||
163 | if (stat(path, &st) < 0) | ||
164 | return -1; | ||
165 | |||
166 | if (pmu_aliases_parse(path, head)) | ||
167 | return -1; | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int pmu_alias_terms(struct perf_pmu__alias *alias, | ||
173 | struct list_head *terms) | ||
174 | { | ||
175 | struct parse_events__term *term, *clone; | ||
176 | LIST_HEAD(list); | ||
177 | int ret; | ||
178 | |||
179 | list_for_each_entry(term, &alias->terms, list) { | ||
180 | ret = parse_events__term_clone(&clone, term); | ||
181 | if (ret) { | ||
182 | parse_events__free_terms(&list); | ||
183 | return ret; | ||
184 | } | ||
185 | list_add_tail(&clone->list, &list); | ||
186 | } | ||
187 | list_splice(&list, terms); | ||
188 | return 0; | ||
189 | } | ||
190 | |||
83 | /* | 191 | /* |
84 | * Reading/parsing the default pmu type value, which should be | 192 | * Reading/parsing the default pmu type value, which should be |
85 | * located at: | 193 | * located at: |
@@ -118,6 +226,7 @@ static struct perf_pmu *pmu_lookup(char *name) | |||
118 | { | 226 | { |
119 | struct perf_pmu *pmu; | 227 | struct perf_pmu *pmu; |
120 | LIST_HEAD(format); | 228 | LIST_HEAD(format); |
229 | LIST_HEAD(aliases); | ||
121 | __u32 type; | 230 | __u32 type; |
122 | 231 | ||
123 | /* | 232 | /* |
@@ -135,8 +244,12 @@ static struct perf_pmu *pmu_lookup(char *name) | |||
135 | if (!pmu) | 244 | if (!pmu) |
136 | return NULL; | 245 | return NULL; |
137 | 246 | ||
247 | pmu_aliases(name, &aliases); | ||
248 | |||
138 | INIT_LIST_HEAD(&pmu->format); | 249 | INIT_LIST_HEAD(&pmu->format); |
250 | INIT_LIST_HEAD(&pmu->aliases); | ||
139 | list_splice(&format, &pmu->format); | 251 | list_splice(&format, &pmu->format); |
252 | list_splice(&aliases, &pmu->aliases); | ||
140 | pmu->name = strdup(name); | 253 | pmu->name = strdup(name); |
141 | pmu->type = type; | 254 | pmu->type = type; |
142 | return pmu; | 255 | return pmu; |
@@ -279,6 +392,59 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | |||
279 | return pmu_config(&pmu->format, attr, head_terms); | 392 | return pmu_config(&pmu->format, attr, head_terms); |
280 | } | 393 | } |
281 | 394 | ||
395 | static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, | ||
396 | struct parse_events__term *term) | ||
397 | { | ||
398 | struct perf_pmu__alias *alias; | ||
399 | char *name; | ||
400 | |||
401 | if (parse_events__is_hardcoded_term(term)) | ||
402 | return NULL; | ||
403 | |||
404 | if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { | ||
405 | if (term->val.num != 1) | ||
406 | return NULL; | ||
407 | if (pmu_find_format(&pmu->format, term->config)) | ||
408 | return NULL; | ||
409 | name = term->config; | ||
410 | } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { | ||
411 | if (strcasecmp(term->config, "event")) | ||
412 | return NULL; | ||
413 | name = term->val.str; | ||
414 | } else { | ||
415 | return NULL; | ||
416 | } | ||
417 | |||
418 | list_for_each_entry(alias, &pmu->aliases, list) { | ||
419 | if (!strcasecmp(alias->name, name)) | ||
420 | return alias; | ||
421 | } | ||
422 | return NULL; | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * Find alias in the terms list and replace it with the terms | ||
427 | * defined for the alias | ||
428 | */ | ||
429 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) | ||
430 | { | ||
431 | struct parse_events__term *term, *h; | ||
432 | struct perf_pmu__alias *alias; | ||
433 | int ret; | ||
434 | |||
435 | list_for_each_entry_safe(term, h, head_terms, list) { | ||
436 | alias = pmu_find_alias(pmu, term); | ||
437 | if (!alias) | ||
438 | continue; | ||
439 | ret = pmu_alias_terms(alias, &term->list); | ||
440 | if (ret) | ||
441 | return ret; | ||
442 | list_del(&term->list); | ||
443 | free(term); | ||
444 | } | ||
445 | return 0; | ||
446 | } | ||
447 | |||
282 | int perf_pmu__new_format(struct list_head *list, char *name, | 448 | int perf_pmu__new_format(struct list_head *list, char *name, |
283 | int config, unsigned long *bits) | 449 | int config, unsigned long *bits) |
284 | { | 450 | { |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 68c0db965e1f..535f2c5258ab 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -19,17 +19,26 @@ struct perf_pmu__format { | |||
19 | struct list_head list; | 19 | struct list_head list; |
20 | }; | 20 | }; |
21 | 21 | ||
22 | struct perf_pmu__alias { | ||
23 | char *name; | ||
24 | struct list_head terms; | ||
25 | struct list_head list; | ||
26 | }; | ||
27 | |||
22 | struct perf_pmu { | 28 | struct perf_pmu { |
23 | char *name; | 29 | char *name; |
24 | __u32 type; | 30 | __u32 type; |
25 | struct list_head format; | 31 | struct list_head format; |
32 | struct list_head aliases; | ||
26 | struct list_head list; | 33 | struct list_head list; |
27 | }; | 34 | }; |
28 | 35 | ||
29 | struct perf_pmu *perf_pmu__find(char *name); | 36 | struct perf_pmu *perf_pmu__find(char *name); |
30 | int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | 37 | int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, |
31 | struct list_head *head_terms); | 38 | struct list_head *head_terms); |
32 | 39 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); | |
40 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, | ||
41 | struct list_head *head_terms); | ||
33 | int perf_pmu_wrap(void); | 42 | int perf_pmu_wrap(void); |
34 | void perf_pmu_error(struct list_head *list, char *name, char const *msg); | 43 | void perf_pmu_error(struct list_head *list, char *name, char const *msg); |
35 | 44 | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index febc0aeb3c66..6b305fbcc986 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -441,6 +441,16 @@ static void perf_tool__fill_defaults(struct perf_tool *tool) | |||
441 | tool->finished_round = process_finished_round_stub; | 441 | tool->finished_round = process_finished_round_stub; |
442 | } | 442 | } |
443 | } | 443 | } |
444 | |||
445 | void mem_bswap_32(void *src, int byte_size) | ||
446 | { | ||
447 | u32 *m = src; | ||
448 | while (byte_size > 0) { | ||
449 | *m = bswap_32(*m); | ||
450 | byte_size -= sizeof(u32); | ||
451 | ++m; | ||
452 | } | ||
453 | } | ||
444 | 454 | ||
445 | void mem_bswap_64(void *src, int byte_size) | 455 | void mem_bswap_64(void *src, int byte_size) |
446 | { | 456 | { |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 877d78186f2c..c71a1a7b05ed 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -80,6 +80,7 @@ struct branch_info *machine__resolve_bstack(struct machine *self, | |||
80 | bool perf_session__has_traces(struct perf_session *self, const char *msg); | 80 | bool perf_session__has_traces(struct perf_session *self, const char *msg); |
81 | 81 | ||
82 | void mem_bswap_64(void *src, int byte_size); | 82 | void mem_bswap_64(void *src, int byte_size); |
83 | void mem_bswap_32(void *src, int byte_size); | ||
83 | void perf_event__attr_swap(struct perf_event_attr *attr); | 84 | void perf_event__attr_swap(struct perf_event_attr *attr); |
84 | 85 | ||
85 | int perf_session__create_kernel_maps(struct perf_session *self); | 86 | int perf_session__create_kernel_maps(struct perf_session *self); |