perf tools: Fix term parsing for raw syntax
authorJiri Olsa <jolsa@kernel.org>
Sun, 26 Jul 2020 07:52:44 +0000 (09:52 +0200)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 30 Jul 2020 10:01:48 +0000 (07:01 -0300)
Jin Yao reported issue with possible conflict between raw events and
term values in pmu event syntax.

Currently following syntax is resolved as raw event with 0xead value:

  uncore_imc_free_running/read/

instead of using 'read' term from uncore_imc_free_running pmu, because
'read' is correct raw event syntax with 0xead value.

To solve this issue we do following:

  - check existing terms during rXXXX syntax processing
    and make them priority in case of conflict

  - allow pmu/r0x1234/ syntax to be able to specify conflicting
    raw event (implemented in previous patch)

Also add automated tests for this and perf_pmu__parse_cleanup call to
parse_events_terms, so the test gets properly cleaned up.

Fixes: 3a6c51e4d66c ("perf parser: Add support to specify rXXX event with pmu")
Reported-by: Jin Yao <yao.jin@linux.intel.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Jin Yao <yao.jin@linux.intel.com>
Acked-by: Ian Rogers <irogers@google.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Michael Petlan <mpetlan@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Link: http://lore.kernel.org/lkml/20200726075244.1191481-2-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/tests/parse-events.c
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/parse-events.l

index 5aaddcb..7f9f87a 100644 (file)
@@ -631,6 +631,34 @@ static int test__checkterms_simple(struct list_head *terms)
        TEST_ASSERT_VAL("wrong val", term->val.num == 1);
        TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "umask"));
 
+       /*
+        * read
+        *
+        * The perf_pmu__test_parse_init injects 'read' term into
+        * perf_pmu_events_list, so 'read' is evaluated as read term
+        * and not as raw event with 'ead' hex value.
+        */
+       term = list_entry(term->list.next, struct parse_events_term, list);
+       TEST_ASSERT_VAL("wrong type term",
+                       term->type_term == PARSE_EVENTS__TERM_TYPE_USER);
+       TEST_ASSERT_VAL("wrong type val",
+                       term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
+       TEST_ASSERT_VAL("wrong val", term->val.num == 1);
+       TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "read"));
+
+       /*
+        * r0xead
+        *
+        * To be still able to pass 'ead' value with 'r' syntax,
+        * we added support to parse 'r0xHEX' event.
+        */
+       term = list_entry(term->list.next, struct parse_events_term, list);
+       TEST_ASSERT_VAL("wrong type term",
+                       term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG);
+       TEST_ASSERT_VAL("wrong type val",
+                       term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
+       TEST_ASSERT_VAL("wrong val", term->val.num == 0xead);
+       TEST_ASSERT_VAL("wrong config", !term->config);
        return 0;
 }
 
@@ -1781,7 +1809,7 @@ struct terms_test {
 
 static struct terms_test test__terms[] = {
        [0] = {
-               .str   = "config=10,config1,config2=3,umask=1",
+               .str   = "config=10,config1,config2=3,umask=1,read,r0xead",
                .check = test__checkterms_simple,
        },
 };
@@ -1841,6 +1869,13 @@ static int test_term(struct terms_test *t)
 
        INIT_LIST_HEAD(&terms);
 
+       /*
+        * The perf_pmu__test_parse_init prepares perf_pmu_events_list
+        * which gets freed in parse_events_terms.
+        */
+       if (perf_pmu__test_parse_init())
+               return -1;
+
        ret = parse_events_terms(&terms, t->str);
        if (ret) {
                pr_debug("failed to parse terms '%s', err %d\n",
index e88e4c7..9f7260e 100644 (file)
@@ -2019,6 +2019,32 @@ err:
        perf_pmu__parse_cleanup();
 }
 
+/*
+ * This function injects special term in
+ * perf_pmu_events_list so the test code
+ * can check on this functionality.
+ */
+int perf_pmu__test_parse_init(void)
+{
+       struct perf_pmu_event_symbol *list;
+
+       list = malloc(sizeof(*list) * 1);
+       if (!list)
+               return -ENOMEM;
+
+       list->type   = PMU_EVENT_SYMBOL;
+       list->symbol = strdup("read");
+
+       if (!list->symbol) {
+               free(list);
+               return -ENOMEM;
+       }
+
+       perf_pmu_events_list = list;
+       perf_pmu_events_list_num = 1;
+       return 0;
+}
+
 enum perf_pmu_event_symbol_type
 perf_pmu__parse_check(const char *name)
 {
@@ -2080,6 +2106,8 @@ int parse_events_terms(struct list_head *terms, const char *str)
        int ret;
 
        ret = parse_events__scanner(str, &parse_state);
+       perf_pmu__parse_cleanup();
+
        if (!ret) {
                list_splice(parse_state.terms, terms);
                zfree(&parse_state.terms);
index f001009..00cde7d 100644 (file)
@@ -261,4 +261,6 @@ static inline bool is_sdt_event(char *str __maybe_unused)
 }
 #endif /* HAVE_LIBELF_SUPPORT */
 
+int perf_pmu__test_parse_init(void);
+
 #endif /* __PERF_PARSE_EVENTS_H */
index 44c85fe..3ca5fd2 100644 (file)
@@ -41,14 +41,6 @@ static int value(yyscan_t scanner, int base)
        return __value(yylval, text, base, PE_VALUE);
 }
 
-static int raw(yyscan_t scanner)
-{
-       YYSTYPE *yylval = parse_events_get_lval(scanner);
-       char *text = parse_events_get_text(scanner);
-
-       return __value(yylval, text + 1, 16, PE_RAW);
-}
-
 static int str(yyscan_t scanner, int token)
 {
        YYSTYPE *yylval = parse_events_get_lval(scanner);
@@ -72,6 +64,17 @@ static int str(yyscan_t scanner, int token)
        return token;
 }
 
+static int raw(yyscan_t scanner)
+{
+       YYSTYPE *yylval = parse_events_get_lval(scanner);
+       char *text = parse_events_get_text(scanner);
+
+       if (perf_pmu__parse_check(text) == PMU_EVENT_SYMBOL)
+               return str(scanner, PE_NAME);
+
+       return __value(yylval, text + 1, 16, PE_RAW);
+}
+
 static bool isbpf_suffix(char *text)
 {
        int len = strlen(text);