Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf tools: Add term support for parse_events_error

Allowing event's term processing to report back error, like:

$ perf record -e 'cpu/even=0x1/' ls
event syntax error: 'cpu/even=0x1/'
\___ unknown term

valid terms: pc,any,inv,edge,cmask,event,in_tx,ldlat,umask,in_tx_cp,offcore_rsp,config,config1,config2,name,period,branch_type

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1429729824-13932-7-git-send-email-jolsa@kernel.org
[ Renamed 'error' variables to 'err', not to clash with util.h error() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Jiri Olsa and committed by
Arnaldo Carvalho de Melo
e64b020b cecf3a2e

+62 -10
+2 -1
tools/perf/tests/pmu.c
··· 152 152 if (ret) 153 153 break; 154 154 155 - ret = perf_pmu__config_terms(&formats, &attr, terms, false); 155 + ret = perf_pmu__config_terms(&formats, &attr, terms, 156 + false, NULL); 156 157 if (ret) 157 158 break; 158 159
+1 -1
tools/perf/util/parse-events.c
··· 675 675 if (config_attr(&attr, head_config)) 676 676 return -EINVAL; 677 677 678 - if (perf_pmu__config(pmu, &attr, head_config)) 678 + if (perf_pmu__config(pmu, &attr, head_config, data->error)) 679 679 return -EINVAL; 680 680 681 681 evsel = __add_event(list, &data->idx, &attr,
+4
tools/perf/util/parse-events.l
··· 174 174 } 175 175 176 176 <config>{ 177 + /* 178 + * Please update formats_error_string any time 179 + * new static term is added. 180 + */ 177 181 config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); } 178 182 config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); } 179 183 config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
+51 -6
tools/perf/util/pmu.c
··· 579 579 return -1; 580 580 } 581 581 582 + static char *formats_error_string(struct list_head *formats) 583 + { 584 + struct perf_pmu_format *format; 585 + char *err, *str; 586 + static const char *static_terms = "config,config1,config2,name,period,branch_type\n"; 587 + unsigned i = 0; 588 + 589 + if (!asprintf(&str, "valid terms:")) 590 + return NULL; 591 + 592 + /* sysfs exported terms */ 593 + list_for_each_entry(format, formats, list) { 594 + char c = i++ ? ',' : ' '; 595 + 596 + err = str; 597 + if (!asprintf(&str, "%s%c%s", err, c, format->name)) 598 + goto fail; 599 + free(err); 600 + } 601 + 602 + /* static terms */ 603 + err = str; 604 + if (!asprintf(&str, "%s,%s", err, static_terms)) 605 + goto fail; 606 + 607 + free(err); 608 + return str; 609 + fail: 610 + free(err); 611 + return NULL; 612 + } 613 + 582 614 /* 583 615 * Setup one of config[12] attr members based on the 584 616 * user input data - term parameter. ··· 619 587 struct perf_event_attr *attr, 620 588 struct parse_events_term *term, 621 589 struct list_head *head_terms, 622 - bool zero) 590 + bool zero, struct parse_events_error *err) 623 591 { 624 592 struct perf_pmu_format *format; 625 593 __u64 *vp; ··· 643 611 if (!format) { 644 612 if (verbose) 645 613 printf("Invalid event/parameter '%s'\n", term->config); 614 + if (err) { 615 + err->idx = term->err_term; 616 + err->str = strdup("unknown term"); 617 + err->help = formats_error_string(formats); 618 + } 646 619 return -EINVAL; 647 620 } 648 621 ··· 673 636 val = term->val.num; 674 637 else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 675 638 if (strcmp(term->val.str, "?")) { 676 - if (verbose) 639 + if (verbose) { 677 640 pr_info("Invalid sysfs entry %s=%s\n", 678 641 term->config, term->val.str); 642 + } 643 + if (err) { 644 + err->idx = term->err_val; 645 + err->str = strdup("expected numeric value"); 646 + } 679 647 return -EINVAL; 680 648 } 681 649 ··· 696 654 int perf_pmu__config_terms(struct list_head *formats, 697 655 struct perf_event_attr *attr, 698 656 struct list_head *head_terms, 699 - bool zero) 657 + bool zero, struct parse_events_error *err) 700 658 { 701 659 struct parse_events_term *term; 702 660 703 661 list_for_each_entry(term, head_terms, list) { 704 - if (pmu_config_term(formats, attr, term, head_terms, zero)) 662 + if (pmu_config_term(formats, attr, term, head_terms, 663 + zero, err)) 705 664 return -EINVAL; 706 665 } 707 666 ··· 715 672 * 2) pmu format definitions - specified by pmu parameter 716 673 */ 717 674 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 718 - struct list_head *head_terms) 675 + struct list_head *head_terms, 676 + struct parse_events_error *err) 719 677 { 720 678 bool zero = !!pmu->default_config; 721 679 722 680 attr->type = pmu->type; 723 - return perf_pmu__config_terms(&pmu->format, attr, head_terms, zero); 681 + return perf_pmu__config_terms(&pmu->format, attr, head_terms, 682 + zero, err); 724 683 } 725 684 726 685 static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
+4 -2
tools/perf/util/pmu.h
··· 4 4 #include <linux/bitmap.h> 5 5 #include <linux/perf_event.h> 6 6 #include <stdbool.h> 7 + #include "parse-events.h" 7 8 8 9 enum { 9 10 PERF_PMU_FORMAT_VALUE_CONFIG, ··· 48 47 49 48 struct perf_pmu *perf_pmu__find(const char *name); 50 49 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 51 - struct list_head *head_terms); 50 + struct list_head *head_terms, 51 + struct parse_events_error *error); 52 52 int perf_pmu__config_terms(struct list_head *formats, 53 53 struct perf_event_attr *attr, 54 54 struct list_head *head_terms, 55 - bool zero); 55 + bool zero, struct parse_events_error *error); 56 56 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 57 57 struct perf_pmu_info *info); 58 58 struct list_head *perf_pmu__alias(struct perf_pmu *pmu,