diff options
Diffstat (limited to 'tools/perf/util/parse-events.c')
| -rw-r--r-- | tools/perf/util/parse-events.c | 114 |
1 files changed, 87 insertions, 27 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 5b3a0ef4e232..fac7d59309b8 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -23,8 +23,10 @@ struct event_symbol { | |||
| 23 | const char *alias; | 23 | const char *alias; |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | int parse_events_parse(struct list_head *list, struct list_head *list_tmp, | 26 | #ifdef PARSER_DEBUG |
| 27 | int *idx); | 27 | extern int parse_events_debug; |
| 28 | #endif | ||
| 29 | int parse_events_parse(struct list_head *list, int *idx); | ||
| 28 | 30 | ||
| 29 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x | 31 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x |
| 30 | #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x | 32 | #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x |
| @@ -355,20 +357,30 @@ const char *__event_name(int type, u64 config) | |||
| 355 | return "unknown"; | 357 | return "unknown"; |
| 356 | } | 358 | } |
| 357 | 359 | ||
| 358 | static int add_event(struct list_head *list, int *idx, | 360 | static int add_event(struct list_head **_list, int *idx, |
| 359 | struct perf_event_attr *attr, char *name) | 361 | struct perf_event_attr *attr, char *name) |
| 360 | { | 362 | { |
| 361 | struct perf_evsel *evsel; | 363 | struct perf_evsel *evsel; |
| 364 | struct list_head *list = *_list; | ||
| 365 | |||
| 366 | if (!list) { | ||
| 367 | list = malloc(sizeof(*list)); | ||
| 368 | if (!list) | ||
| 369 | return -ENOMEM; | ||
| 370 | INIT_LIST_HEAD(list); | ||
| 371 | } | ||
| 362 | 372 | ||
| 363 | event_attr_init(attr); | 373 | event_attr_init(attr); |
| 364 | 374 | ||
| 365 | evsel = perf_evsel__new(attr, (*idx)++); | 375 | evsel = perf_evsel__new(attr, (*idx)++); |
| 366 | if (!evsel) | 376 | if (!evsel) { |
| 377 | free(list); | ||
| 367 | return -ENOMEM; | 378 | return -ENOMEM; |
| 368 | 379 | } | |
| 369 | list_add_tail(&evsel->node, list); | ||
| 370 | 380 | ||
| 371 | evsel->name = strdup(name); | 381 | evsel->name = strdup(name); |
| 382 | list_add_tail(&evsel->node, list); | ||
| 383 | *_list = list; | ||
| 372 | return 0; | 384 | return 0; |
| 373 | } | 385 | } |
| 374 | 386 | ||
| @@ -390,7 +402,7 @@ static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size) | |||
| 390 | return -1; | 402 | return -1; |
| 391 | } | 403 | } |
| 392 | 404 | ||
| 393 | int parse_events_add_cache(struct list_head *list, int *idx, | 405 | int parse_events_add_cache(struct list_head **list, int *idx, |
| 394 | char *type, char *op_result1, char *op_result2) | 406 | char *type, char *op_result1, char *op_result2) |
| 395 | { | 407 | { |
| 396 | struct perf_event_attr attr; | 408 | struct perf_event_attr attr; |
| @@ -451,7 +463,7 @@ int parse_events_add_cache(struct list_head *list, int *idx, | |||
| 451 | return add_event(list, idx, &attr, name); | 463 | return add_event(list, idx, &attr, name); |
| 452 | } | 464 | } |
| 453 | 465 | ||
| 454 | static int add_tracepoint(struct list_head *list, int *idx, | 466 | static int add_tracepoint(struct list_head **list, int *idx, |
| 455 | char *sys_name, char *evt_name) | 467 | char *sys_name, char *evt_name) |
| 456 | { | 468 | { |
| 457 | struct perf_event_attr attr; | 469 | struct perf_event_attr attr; |
| @@ -488,7 +500,7 @@ static int add_tracepoint(struct list_head *list, int *idx, | |||
| 488 | return add_event(list, idx, &attr, name); | 500 | return add_event(list, idx, &attr, name); |
| 489 | } | 501 | } |
| 490 | 502 | ||
| 491 | static int add_tracepoint_multi(struct list_head *list, int *idx, | 503 | static int add_tracepoint_multi(struct list_head **list, int *idx, |
| 492 | char *sys_name, char *evt_name) | 504 | char *sys_name, char *evt_name) |
| 493 | { | 505 | { |
| 494 | char evt_path[MAXPATHLEN]; | 506 | char evt_path[MAXPATHLEN]; |
| @@ -519,7 +531,7 @@ static int add_tracepoint_multi(struct list_head *list, int *idx, | |||
| 519 | return ret; | 531 | return ret; |
| 520 | } | 532 | } |
| 521 | 533 | ||
| 522 | int parse_events_add_tracepoint(struct list_head *list, int *idx, | 534 | int parse_events_add_tracepoint(struct list_head **list, int *idx, |
| 523 | char *sys, char *event) | 535 | char *sys, char *event) |
| 524 | { | 536 | { |
| 525 | int ret; | 537 | int ret; |
| @@ -563,7 +575,7 @@ parse_breakpoint_type(const char *type, struct perf_event_attr *attr) | |||
| 563 | return 0; | 575 | return 0; |
| 564 | } | 576 | } |
| 565 | 577 | ||
| 566 | int parse_events_add_breakpoint(struct list_head *list, int *idx, | 578 | int parse_events_add_breakpoint(struct list_head **list, int *idx, |
| 567 | void *ptr, char *type) | 579 | void *ptr, char *type) |
| 568 | { | 580 | { |
| 569 | struct perf_event_attr attr; | 581 | struct perf_event_attr attr; |
| @@ -593,17 +605,27 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx, | |||
| 593 | static int config_term(struct perf_event_attr *attr, | 605 | static int config_term(struct perf_event_attr *attr, |
| 594 | struct parse_events__term *term) | 606 | struct parse_events__term *term) |
| 595 | { | 607 | { |
| 596 | switch (term->type) { | 608 | #define CHECK_TYPE_VAL(type) \ |
| 609 | do { \ | ||
| 610 | if (PARSE_EVENTS__TERM_TYPE_ ## type != term->type_val) \ | ||
| 611 | return -EINVAL; \ | ||
| 612 | } while (0) | ||
| 613 | |||
| 614 | switch (term->type_term) { | ||
| 597 | case PARSE_EVENTS__TERM_TYPE_CONFIG: | 615 | case PARSE_EVENTS__TERM_TYPE_CONFIG: |
| 616 | CHECK_TYPE_VAL(NUM); | ||
| 598 | attr->config = term->val.num; | 617 | attr->config = term->val.num; |
| 599 | break; | 618 | break; |
| 600 | case PARSE_EVENTS__TERM_TYPE_CONFIG1: | 619 | case PARSE_EVENTS__TERM_TYPE_CONFIG1: |
| 620 | CHECK_TYPE_VAL(NUM); | ||
| 601 | attr->config1 = term->val.num; | 621 | attr->config1 = term->val.num; |
| 602 | break; | 622 | break; |
| 603 | case PARSE_EVENTS__TERM_TYPE_CONFIG2: | 623 | case PARSE_EVENTS__TERM_TYPE_CONFIG2: |
| 624 | CHECK_TYPE_VAL(NUM); | ||
| 604 | attr->config2 = term->val.num; | 625 | attr->config2 = term->val.num; |
| 605 | break; | 626 | break; |
| 606 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: | 627 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: |
| 628 | CHECK_TYPE_VAL(NUM); | ||
| 607 | attr->sample_period = term->val.num; | 629 | attr->sample_period = term->val.num; |
| 608 | break; | 630 | break; |
| 609 | case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: | 631 | case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: |
| @@ -612,10 +634,15 @@ static int config_term(struct perf_event_attr *attr, | |||
| 612 | * attr->branch_sample_type = term->val.num; | 634 | * attr->branch_sample_type = term->val.num; |
| 613 | */ | 635 | */ |
| 614 | break; | 636 | break; |
| 637 | case PARSE_EVENTS__TERM_TYPE_NAME: | ||
| 638 | CHECK_TYPE_VAL(STR); | ||
| 639 | break; | ||
| 615 | default: | 640 | default: |
| 616 | return -EINVAL; | 641 | return -EINVAL; |
| 617 | } | 642 | } |
| 643 | |||
| 618 | return 0; | 644 | return 0; |
| 645 | #undef CHECK_TYPE_VAL | ||
| 619 | } | 646 | } |
| 620 | 647 | ||
| 621 | static int config_attr(struct perf_event_attr *attr, | 648 | static int config_attr(struct perf_event_attr *attr, |
| @@ -630,7 +657,7 @@ static int config_attr(struct perf_event_attr *attr, | |||
| 630 | return 0; | 657 | return 0; |
| 631 | } | 658 | } |
| 632 | 659 | ||
| 633 | int parse_events_add_numeric(struct list_head *list, int *idx, | 660 | int parse_events_add_numeric(struct list_head **list, int *idx, |
| 634 | unsigned long type, unsigned long config, | 661 | unsigned long type, unsigned long config, |
| 635 | struct list_head *head_config) | 662 | struct list_head *head_config) |
| 636 | { | 663 | { |
| @@ -648,7 +675,24 @@ int parse_events_add_numeric(struct list_head *list, int *idx, | |||
| 648 | (char *) __event_name(type, config)); | 675 | (char *) __event_name(type, config)); |
| 649 | } | 676 | } |
| 650 | 677 | ||
| 651 | int parse_events_add_pmu(struct list_head *list, int *idx, | 678 | static int parse_events__is_name_term(struct parse_events__term *term) |
| 679 | { | ||
| 680 | return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; | ||
| 681 | } | ||
| 682 | |||
| 683 | static char *pmu_event_name(struct perf_event_attr *attr, | ||
| 684 | struct list_head *head_terms) | ||
| 685 | { | ||
| 686 | struct parse_events__term *term; | ||
| 687 | |||
| 688 | list_for_each_entry(term, head_terms, list) | ||
| 689 | if (parse_events__is_name_term(term)) | ||
| 690 | return term->val.str; | ||
| 691 | |||
| 692 | return (char *) __event_name(PERF_TYPE_RAW, attr->config); | ||
| 693 | } | ||
| 694 | |||
| 695 | int parse_events_add_pmu(struct list_head **list, int *idx, | ||
| 652 | char *name, struct list_head *head_config) | 696 | char *name, struct list_head *head_config) |
| 653 | { | 697 | { |
| 654 | struct perf_event_attr attr; | 698 | struct perf_event_attr attr; |
| @@ -669,7 +713,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx, | |||
| 669 | if (perf_pmu__config(pmu, &attr, head_config)) | 713 | if (perf_pmu__config(pmu, &attr, head_config)) |
| 670 | return -EINVAL; | 714 | return -EINVAL; |
| 671 | 715 | ||
| 672 | return add_event(list, idx, &attr, (char *) "pmu"); | 716 | return add_event(list, idx, &attr, |
| 717 | pmu_event_name(&attr, head_config)); | ||
| 673 | } | 718 | } |
| 674 | 719 | ||
| 675 | void parse_events_update_lists(struct list_head *list_event, | 720 | void parse_events_update_lists(struct list_head *list_event, |
| @@ -681,7 +726,7 @@ void parse_events_update_lists(struct list_head *list_event, | |||
| 681 | * list, for next event definition. | 726 | * list, for next event definition. |
| 682 | */ | 727 | */ |
| 683 | list_splice_tail(list_event, list_all); | 728 | list_splice_tail(list_event, list_all); |
| 684 | INIT_LIST_HEAD(list_event); | 729 | free(list_event); |
| 685 | } | 730 | } |
| 686 | 731 | ||
| 687 | int parse_events_modifier(struct list_head *list, char *str) | 732 | int parse_events_modifier(struct list_head *list, char *str) |
| @@ -756,10 +801,14 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) | |||
| 756 | 801 | ||
| 757 | buffer = parse_events__scan_string(str); | 802 | buffer = parse_events__scan_string(str); |
| 758 | 803 | ||
| 759 | ret = parse_events_parse(&list, &list_tmp, &idx); | 804 | #ifdef PARSER_DEBUG |
| 805 | parse_events_debug = 1; | ||
| 806 | #endif | ||
| 807 | ret = parse_events_parse(&list, &idx); | ||
| 760 | 808 | ||
| 761 | parse_events__flush_buffer(buffer); | 809 | parse_events__flush_buffer(buffer); |
| 762 | parse_events__delete_buffer(buffer); | 810 | parse_events__delete_buffer(buffer); |
| 811 | parse_events_lex_destroy(); | ||
| 763 | 812 | ||
| 764 | if (!ret) { | 813 | if (!ret) { |
| 765 | int entries = idx - evlist->nr_entries; | 814 | int entries = idx - evlist->nr_entries; |
| @@ -1015,11 +1064,12 @@ void print_events(const char *event_glob) | |||
| 1015 | 1064 | ||
| 1016 | int parse_events__is_hardcoded_term(struct parse_events__term *term) | 1065 | int parse_events__is_hardcoded_term(struct parse_events__term *term) |
| 1017 | { | 1066 | { |
| 1018 | return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX; | 1067 | return term->type_term != PARSE_EVENTS__TERM_TYPE_USER; |
| 1019 | } | 1068 | } |
| 1020 | 1069 | ||
| 1021 | int parse_events__new_term(struct parse_events__term **_term, int type, | 1070 | static int new_term(struct parse_events__term **_term, int type_val, |
| 1022 | char *config, char *str, long num) | 1071 | int type_term, char *config, |
| 1072 | char *str, long num) | ||
| 1023 | { | 1073 | { |
| 1024 | struct parse_events__term *term; | 1074 | struct parse_events__term *term; |
| 1025 | 1075 | ||
| @@ -1028,15 +1078,11 @@ int parse_events__new_term(struct parse_events__term **_term, int type, | |||
| 1028 | return -ENOMEM; | 1078 | return -ENOMEM; |
| 1029 | 1079 | ||
| 1030 | INIT_LIST_HEAD(&term->list); | 1080 | INIT_LIST_HEAD(&term->list); |
| 1031 | term->type = type; | 1081 | term->type_val = type_val; |
| 1082 | term->type_term = type_term; | ||
| 1032 | term->config = config; | 1083 | term->config = config; |
| 1033 | 1084 | ||
| 1034 | switch (type) { | 1085 | switch (type_val) { |
| 1035 | case PARSE_EVENTS__TERM_TYPE_CONFIG: | ||
| 1036 | case PARSE_EVENTS__TERM_TYPE_CONFIG1: | ||
| 1037 | case PARSE_EVENTS__TERM_TYPE_CONFIG2: | ||
| 1038 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: | ||
| 1039 | case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: | ||
| 1040 | case PARSE_EVENTS__TERM_TYPE_NUM: | 1086 | case PARSE_EVENTS__TERM_TYPE_NUM: |
| 1041 | term->val.num = num; | 1087 | term->val.num = num; |
| 1042 | break; | 1088 | break; |
| @@ -1051,6 +1097,20 @@ int parse_events__new_term(struct parse_events__term **_term, int type, | |||
| 1051 | return 0; | 1097 | return 0; |
| 1052 | } | 1098 | } |
| 1053 | 1099 | ||
| 1100 | int parse_events__term_num(struct parse_events__term **term, | ||
| 1101 | int type_term, char *config, long num) | ||
| 1102 | { | ||
| 1103 | return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, | ||
| 1104 | config, NULL, num); | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | int parse_events__term_str(struct parse_events__term **term, | ||
| 1108 | int type_term, char *config, char *str) | ||
| 1109 | { | ||
| 1110 | return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, | ||
| 1111 | config, str, 0); | ||
| 1112 | } | ||
| 1113 | |||
| 1054 | void parse_events__free_terms(struct list_head *terms) | 1114 | void parse_events__free_terms(struct list_head *terms) |
| 1055 | { | 1115 | { |
| 1056 | struct parse_events__term *term, *h; | 1116 | struct parse_events__term *term, *h; |
