Received: by 2002:a05:6358:9144:b0:117:f937:c515 with SMTP id r4csp1157090rwr; Thu, 27 Apr 2023 13:13:47 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ5PxdOJkprFmCawTdhHTk5kex5FZqSe02IT0rMepVFfmJgCmrcPpQ7p0t7y8KlXY78mqcWA X-Received: by 2002:a17:902:7489:b0:1a6:8f8c:fa1a with SMTP id h9-20020a170902748900b001a68f8cfa1amr2914230pll.16.1682626427472; Thu, 27 Apr 2023 13:13:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1682626427; cv=none; d=google.com; s=arc-20160816; b=ekqpo5jga2p4w4nw2+R7yrd2xYzFpusVLH+w2+kT+ZMLLQcVg+N2XHbQzzJAK7+tB9 /4Qb2yn4H/DL2mn/2to4/V8JqfAkvXbj76WuR5FqEFgVbUSTBvAZsLebA2gSwGCT1r2g q7Bc+IwSMVU8b5F7gSdjmfMIn+a2GYU4Di89WboyJfTI3+u87nrY1X9v9FOqbST6rwMv VNUvuMFlJgvXIf8R+lEZLX3QobLZRPVYqGNu+M4hgr2fbkBptRcGQmUPajdBGz34NaZE wh7jNmCob5XQHt0aXsVdDL2uqTD2Ldu80K6y0HvZsvXpZLxyRu2gVrA8e1pXMn5BUOqe C/ng== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:in-reply-to:from :references:to:content-language:subject:user-agent:mime-version:date :message-id:dkim-signature; bh=pHk1/JIClgNo3bGOR04LwsQCIxka3oGttNqbIc+WHWo=; b=B8XIJDfxAOAcTVlHkmlhAvf7YIsOr9C2LicnKJn3iGJpxlIv3iQ4vLtXQXpoeXgSHm LyyETH7/xjkpLSkQr3OwmMT6AXBCJ+AZsRVEzPm1rzthLuyDTbz34y5eYT0TB1lnf/qX jqBuSMgxiC0bSnSyWY0hIU87T8uWUK79ZCMJ0bTomN2VnPkgs3hbcGOokC21mUgl2O6c qKTf9Tuvi+XLk4LCEawgbY/5/u5B6XfrQbso3jtlo9UIkmbCvX0Qcds0ky3IFjXLftyq y/YwU5DSF0siirpU5wdOtOQzbM1GiWMzHMqm6KjoaNQmmQfpDjf0onkjPGb51pVrW+3r OpIQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b="El6/Wv+J"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id f16-20020a63f110000000b00518db33cf17si19102607pgi.552.2023.04.27.13.13.33; Thu, 27 Apr 2023 13:13:47 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b="El6/Wv+J"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344097AbjD0UG6 (ORCPT + 99 others); Thu, 27 Apr 2023 16:06:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45514 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233562AbjD0UG4 (ORCPT ); Thu, 27 Apr 2023 16:06:56 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 634B22D74; Thu, 27 Apr 2023 13:06:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1682626012; x=1714162012; h=message-id:date:mime-version:subject:to:references:from: in-reply-to:content-transfer-encoding; bh=CDgM0oQaOwgyslFaAllN6MQH6fUqXXSt++hEgQmcgME=; b=El6/Wv+JzTb8EAfpL/PWmiVZaXVao6JNYwBTaxJKFejR4kvMMa2q7xsG dvfXk4maz0sj86C+PgeSnWDlnN7dGAgUIJ1h3ji6lMkdNzs440WSwQt36 jIfKZ1tncTbHMpaI9nKJsrznvk3/xcd3gUKNfNlRX+ahfomRjf0RGB5aD +ArPdBcdqLzszrCo0o5BJ2lfa/5n+WLkzl5pGl30vJixUqRtmWoOUXbGi zCTmUvXg8PYKjmxTgUlQavaVh0Pa+Wf1sgIv3QjK3ei1EmiQv+Grw7Pr6 gcoU1XXhOgYutyako9zIpyF0hxlWfAZMdo+Xglk7shDbDmFmXd/F6yk8n w==; X-IronPort-AV: E=McAfee;i="6600,9927,10693"; a="350445933" X-IronPort-AV: E=Sophos;i="5.99,232,1677571200"; d="scan'208";a="350445933" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Apr 2023 13:06:51 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10693"; a="818695708" X-IronPort-AV: E=Sophos;i="5.99,232,1677571200"; d="scan'208";a="818695708" Received: from linux.intel.com ([10.54.29.200]) by orsmga004.jf.intel.com with ESMTP; 27 Apr 2023 13:06:50 -0700 Received: from [10.209.41.222] (kliang2-mobl1.ccr.corp.intel.com [10.209.41.222]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by linux.intel.com (Postfix) with ESMTPS id D4973580377; Thu, 27 Apr 2023 13:06:46 -0700 (PDT) Message-ID: Date: Thu, 27 Apr 2023 16:06:45 -0400 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Thunderbird/102.10.0 Subject: Re: [PATCH v1 15/40] perf parse-events: Avoid scanning PMUs before parsing Content-Language: en-US To: Ian Rogers , Arnaldo Carvalho de Melo , Ahmad Yasin , Peter Zijlstra , Ingo Molnar , Stephane Eranian , Andi Kleen , Perry Taylor , Samantha Alt , Caleb Biggers , Weilin Wang , Edward Baker , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Adrian Hunter , Florian Fischer , Rob Herring , Zhengjun Xing , John Garry , Kajol Jain , Sumanth Korikkar , Thomas Richter , Tiezhu Yang , Ravi Bangoria , Leo Yan , Yang Jihong , James Clark , Suzuki Poulouse , Kang Minchul , Athira Rajeev , linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org References: <20230426070050.1315519-1-irogers@google.com> <20230426070050.1315519-16-irogers@google.com> From: "Liang, Kan" In-Reply-To: <20230426070050.1315519-16-irogers@google.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-5.9 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,NICE_REPLY_A,RCVD_IN_DNSWL_MED, SPF_HELO_NONE,SPF_NONE,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 2023-04-26 3:00 a.m., Ian Rogers wrote: > The event parser needs to handle two special cases: > 1) legacy events like L1-dcache-load-miss. These event names don't > appear in json or sysfs, and lookup tables are used for the config > value. > 2) raw events where 'r0xead' is the same as 'read' unless the PMU has > an event called 'read' in which case the event has priority. > > The previous parser to handle these cases would scan all PMUs for > components of event names. These components would then be used to > classify in the lexer whether the token should be part of a legacy > event, a raw event or an event. The grammar would handle legacy event > tokens or recombining the tokens back into a regular event name. The > code wasn't PMU specific and had issues around events like AMD's > branch-brs that would fail to parse as it expects brs to be a suffix > on a legacy event style name: > > $ perf stat -e branch-brs true > event syntax error: 'branch-brs' > \___ parser error > > This change removes processing all PMUs by using the lexer in the form > of a regular expression matcher. The lexer will return the token for > the longest matched sequence of characters, and in the event of a tie > the first. The legacy events are a fixed number of regular > expressions, and by matching these before a name token its possible to > generate an accurate legacy event token with everything else matching > as a name. Because of the lexer change the handling of hyphens in the > grammar can be removed as hyphens just become a part of the name. > > To handle raw events and terms the parser is changed to defer trying > to evaluate whether something is a raw event until the PMU is known in > the grammar. Once the PMU is known, the events of the PMU can be > scanned for the 'read' style problem. A new term type is added for > these raw terms, used to enable deferring the evaluation. > > While this change is large, it has stats of: > 170 insertions(+), 436 deletions(-) > the bulk of the change is deleting the old approach. It isn't possible > to break apart the code added due to the dependencies on how the parts > of the parsing work. > > Signed-off-by: Ian Rogers Run the test on Cascade Lake and Alder Lake. It looks good. Tested-by: Kan Liang Thanks, Kan > --- > tools/perf/tests/parse-events.c | 24 +-- > tools/perf/tests/pmu-events.c | 9 - > tools/perf/util/parse-events.c | 329 ++++++++++---------------------- > tools/perf/util/parse-events.h | 16 +- > tools/perf/util/parse-events.l | 85 +-------- > tools/perf/util/parse-events.y | 143 +++++--------- > 6 files changed, 170 insertions(+), 436 deletions(-) > > diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c > index 177464793aa8..6eadb8a47dbf 100644 > --- a/tools/perf/tests/parse-events.c > +++ b/tools/perf/tests/parse-events.c > @@ -664,11 +664,11 @@ static int test__checkterms_simple(struct list_head *terms) > */ > 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); > + term->type_term == PARSE_EVENTS__TERM_TYPE_RAW); > 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")); > + term->type_val == PARSE_EVENTS__TERM_TYPE_STR); > + TEST_ASSERT_VAL("wrong val", !strcmp(term->val.str, "read")); > + TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "raw")); > > /* > * r0xead > @@ -678,11 +678,11 @@ static int test__checkterms_simple(struct list_head *terms) > */ > 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); > + term->type_term == PARSE_EVENTS__TERM_TYPE_RAW); > 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", !strcmp(term->config, "config")); > + term->type_val == PARSE_EVENTS__TERM_TYPE_STR); > + TEST_ASSERT_VAL("wrong val", !strcmp(term->val.str, "r0xead")); > + TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "raw")); > return TEST_OK; > } > > @@ -2090,7 +2090,6 @@ static int test_event_fake_pmu(const char *str) > return -ENOMEM; > > parse_events_error__init(&err); > - perf_pmu__test_parse_init(); > ret = __parse_events(evlist, str, &err, &perf_pmu__fake, /*warn_if_reordered=*/true); > if (ret) { > pr_debug("failed to parse event '%s', err %d, str '%s'\n", > @@ -2144,13 +2143,6 @@ static int test_term(const 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", > diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c > index 1dff863b9711..a2cde61b1c77 100644 > --- a/tools/perf/tests/pmu-events.c > +++ b/tools/perf/tests/pmu-events.c > @@ -776,15 +776,6 @@ static int check_parse_id(const char *id, struct parse_events_error *error, > for (cur = strchr(dup, '@') ; cur; cur = strchr(++cur, '@')) > *cur = '/'; > > - if (fake_pmu) { > - /* > - * Every call to __parse_events will try to initialize the PMU > - * state from sysfs and then clean it up at the end. Reset the > - * PMU events to the test state so that we don't pick up > - * erroneous prefixes and suffixes. > - */ > - perf_pmu__test_parse_init(); > - } > ret = __parse_events(evlist, dup, error, fake_pmu, /*warn_if_reordered=*/true); > free(dup); > > diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c > index 4ba01577618e..e416e653cf74 100644 > --- a/tools/perf/util/parse-events.c > +++ b/tools/perf/util/parse-events.c > @@ -34,11 +34,6 @@ > > #define MAX_NAME_LEN 100 > > -struct perf_pmu_event_symbol { > - char *symbol; > - enum perf_pmu_event_symbol_type type; > -}; > - > #ifdef PARSER_DEBUG > extern int parse_events_debug; > #endif > @@ -49,15 +44,6 @@ static int parse_events__with_hybrid_pmu(struct parse_events_state *parse_state, > const char *str, char *pmu_name, > struct list_head *list); > > -static struct perf_pmu_event_symbol *perf_pmu_events_list; > -/* > - * The variable indicates the number of supported pmu event symbols. > - * 0 means not initialized and ready to init > - * -1 means failed to init, don't try anymore > - * >0 is the number of supported pmu event symbols > - */ > -static int perf_pmu_events_list_num; > - > struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = { > [PERF_COUNT_HW_CPU_CYCLES] = { > .symbol = "cpu-cycles", > @@ -236,6 +222,57 @@ static char *get_config_name(struct list_head *head_terms) > return get_config_str(head_terms, PARSE_EVENTS__TERM_TYPE_NAME); > } > > +/** > + * fix_raw - For each raw term see if there is an event (aka alias) in pmu that > + * matches the raw's string value. If the string value matches an > + * event then change the term to be an event, if not then change it to > + * be a config term. For example, "read" may be an event of the PMU or > + * a raw hex encoding of 0xead. The fix-up is done late so the PMU of > + * the event can be determined and we don't need to scan all PMUs > + * ahead-of-time. > + * @config_terms: the list of terms that may contain a raw term. > + * @pmu: the PMU to scan for events from. > + */ > +static void fix_raw(struct list_head *config_terms, struct perf_pmu *pmu) > +{ > + struct parse_events_term *term; > + > + list_for_each_entry(term, config_terms, list) { > + struct perf_pmu_alias *alias; > + bool matched = false; > + > + if (term->type_term != PARSE_EVENTS__TERM_TYPE_RAW) > + continue; > + > + list_for_each_entry(alias, &pmu->aliases, list) { > + if (!strcmp(alias->name, term->val.str)) { > + free(term->config); > + term->config = term->val.str; > + term->type_val = PARSE_EVENTS__TERM_TYPE_NUM; > + term->type_term = PARSE_EVENTS__TERM_TYPE_USER; > + term->val.num = 1; > + term->no_value = true; > + matched = true; > + break; > + } > + } > + if (!matched) { > + u64 num; > + > + free(term->config); > + term->config=strdup("config"); > + errno = 0; > + num = strtoull(term->val.str + 1, NULL, 16); > + assert(errno == 0); > + free(term->val.str); > + term->type_val = PARSE_EVENTS__TERM_TYPE_NUM; > + term->type_term = PARSE_EVENTS__TERM_TYPE_CONFIG; > + term->val.num = num; > + term->no_value = false; > + } > + } > +} > + > static struct evsel * > __add_event(struct list_head *list, int *idx, > struct perf_event_attr *attr, > @@ -328,18 +365,27 @@ static int add_event_tool(struct list_head *list, int *idx, > return 0; > } > > -static int parse_aliases(char *str, const char *const names[][EVSEL__MAX_ALIASES], int size) > +/** > + * parse_aliases - search names for entries beginning or equalling str ignoring > + * case. If mutliple entries in names match str then the longest > + * is chosen. > + * @str: The needle to look for. > + * @names: The haystack to search. > + * @size: The size of the haystack. > + * @longest: Out argument giving the length of the matching entry. > + */ > +static int parse_aliases(const char *str, const char *const names[][EVSEL__MAX_ALIASES], int size, > + int *longest) > { > - int i, j; > - int n, longest = -1; > + *longest = -1; > + for (int i = 0; i < size; i++) { > + for (int j = 0; j < EVSEL__MAX_ALIASES && names[i][j]; j++) { > + int n = strlen(names[i][j]); > > - for (i = 0; i < size; i++) { > - for (j = 0; j < EVSEL__MAX_ALIASES && names[i][j]; j++) { > - n = strlen(names[i][j]); > - if (n > longest && !strncasecmp(str, names[i][j], n)) > - longest = n; > + if (n > *longest && !strncasecmp(str, names[i][j], n)) > + *longest = n; > } > - if (longest > 0) > + if (*longest > 0) > return i; > } > > @@ -357,52 +403,58 @@ static int config_attr(struct perf_event_attr *attr, > struct parse_events_error *err, > config_term_func_t config_term); > > -int parse_events_add_cache(struct list_head *list, int *idx, > - char *type, char *op_result1, char *op_result2, > +int parse_events_add_cache(struct list_head *list, int *idx, const char *name, > struct parse_events_error *err, > struct list_head *head_config, > struct parse_events_state *parse_state) > { > struct perf_event_attr attr; > LIST_HEAD(config_terms); > - char name[MAX_NAME_LEN]; > const char *config_name, *metric_id; > int cache_type = -1, cache_op = -1, cache_result = -1; > - char *op_result[2] = { op_result1, op_result2 }; > - int i, n, ret; > + int ret, len; > + const char *name_end = &name[strlen(name) + 1]; > bool hybrid; > + const char *str = name; > > /* > - * No fallback - if we cannot get a clear cache type > - * then bail out: > + * Search str for the legacy cache event name composed of 1, 2 or 3 > + * hyphen separated sections. The first section is the cache type while > + * the others are the optional op and optional result. To make life hard > + * the names in the table also contain hyphens and the longest name > + * should always be selected. > */ > - cache_type = parse_aliases(type, evsel__hw_cache, PERF_COUNT_HW_CACHE_MAX); > + cache_type = parse_aliases(str, evsel__hw_cache, PERF_COUNT_HW_CACHE_MAX, &len); > if (cache_type == -1) > return -EINVAL; > + str += len + 1; > > config_name = get_config_name(head_config); > - n = snprintf(name, MAX_NAME_LEN, "%s", type); > - > - for (i = 0; (i < 2) && (op_result[i]); i++) { > - char *str = op_result[i]; > - > - n += snprintf(name + n, MAX_NAME_LEN - n, "-%s", str); > - > - if (cache_op == -1) { > + if (str < name_end) { > + cache_op = parse_aliases(str, evsel__hw_cache_op, > + PERF_COUNT_HW_CACHE_OP_MAX, &len); > + if (cache_op >= 0) { > + if (!evsel__is_cache_op_valid(cache_type, cache_op)) > + return -EINVAL; > + str += len + 1; > + } else { > + cache_result = parse_aliases(str, evsel__hw_cache_result, > + PERF_COUNT_HW_CACHE_RESULT_MAX, &len); > + if (cache_result >= 0) > + str += len + 1; > + } > + } > + if (str < name_end) { > + if (cache_op < 0) { > cache_op = parse_aliases(str, evsel__hw_cache_op, > - PERF_COUNT_HW_CACHE_OP_MAX); > + PERF_COUNT_HW_CACHE_OP_MAX, &len); > if (cache_op >= 0) { > if (!evsel__is_cache_op_valid(cache_type, cache_op)) > return -EINVAL; > - continue; > } > - } > - > - if (cache_result == -1) { > + } else if (cache_result < 0) { > cache_result = parse_aliases(str, evsel__hw_cache_result, > - PERF_COUNT_HW_CACHE_RESULT_MAX); > - if (cache_result >= 0) > - continue; > + PERF_COUNT_HW_CACHE_RESULT_MAX, &len); > } > } > > @@ -968,6 +1020,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = { > [PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT] = "aux-output", > [PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE] = "aux-sample-size", > [PARSE_EVENTS__TERM_TYPE_METRIC_ID] = "metric-id", > + [PARSE_EVENTS__TERM_TYPE_RAW] = "raw", > }; > > static bool config_term_shrinked; > @@ -1089,6 +1142,9 @@ do { \ > case PARSE_EVENTS__TERM_TYPE_METRIC_ID: > CHECK_TYPE_VAL(STR); > break; > + case PARSE_EVENTS__TERM_TYPE_RAW: > + CHECK_TYPE_VAL(STR); > + break; > case PARSE_EVENTS__TERM_TYPE_MAX_STACK: > CHECK_TYPE_VAL(NUM); > break; > @@ -1485,6 +1541,8 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, > parse_events_error__handle(err, 0, err_str, NULL); > return -EINVAL; > } > + if (head_config) > + fix_raw(head_config, pmu); > > if (pmu->default_config) { > memcpy(&attr, pmu->default_config, > @@ -1875,180 +1933,6 @@ int parse_events_name(struct list_head *list, const char *name) > return 0; > } > > -static int > -comp_pmu(const void *p1, const void *p2) > -{ > - struct perf_pmu_event_symbol *pmu1 = (struct perf_pmu_event_symbol *) p1; > - struct perf_pmu_event_symbol *pmu2 = (struct perf_pmu_event_symbol *) p2; > - > - return strcasecmp(pmu1->symbol, pmu2->symbol); > -} > - > -static void perf_pmu__parse_cleanup(void) > -{ > - if (perf_pmu_events_list_num > 0) { > - struct perf_pmu_event_symbol *p; > - int i; > - > - for (i = 0; i < perf_pmu_events_list_num; i++) { > - p = perf_pmu_events_list + i; > - zfree(&p->symbol); > - } > - zfree(&perf_pmu_events_list); > - perf_pmu_events_list_num = 0; > - } > -} > - > -#define SET_SYMBOL(str, stype) \ > -do { \ > - p->symbol = str; \ > - if (!p->symbol) \ > - goto err; \ > - p->type = stype; \ > -} while (0) > - > -/* > - * Read the pmu events list from sysfs > - * Save it into perf_pmu_events_list > - */ > -static void perf_pmu__parse_init(void) > -{ > - > - struct perf_pmu *pmu = NULL; > - struct perf_pmu_alias *alias; > - int len = 0; > - > - pmu = NULL; > - while ((pmu = perf_pmu__scan(pmu)) != NULL) { > - list_for_each_entry(alias, &pmu->aliases, list) { > - char *tmp = strchr(alias->name, '-'); > - > - if (tmp) { > - char *tmp2 = NULL; > - > - tmp2 = strchr(tmp + 1, '-'); > - len++; > - if (tmp2) > - len++; > - } > - > - len++; > - } > - } > - > - if (len == 0) { > - perf_pmu_events_list_num = -1; > - return; > - } > - perf_pmu_events_list = malloc(sizeof(struct perf_pmu_event_symbol) * len); > - if (!perf_pmu_events_list) > - return; > - perf_pmu_events_list_num = len; > - > - len = 0; > - pmu = NULL; > - while ((pmu = perf_pmu__scan(pmu)) != NULL) { > - list_for_each_entry(alias, &pmu->aliases, list) { > - struct perf_pmu_event_symbol *p = perf_pmu_events_list + len; > - char *tmp = strchr(alias->name, '-'); > - char *tmp2 = NULL; > - > - if (tmp) > - tmp2 = strchr(tmp + 1, '-'); > - if (tmp2) { > - SET_SYMBOL(strndup(alias->name, tmp - alias->name), > - PMU_EVENT_SYMBOL_PREFIX); > - p++; > - tmp++; > - SET_SYMBOL(strndup(tmp, tmp2 - tmp), PMU_EVENT_SYMBOL_SUFFIX); > - p++; > - SET_SYMBOL(strdup(++tmp2), PMU_EVENT_SYMBOL_SUFFIX2); > - len += 3; > - } else if (tmp) { > - SET_SYMBOL(strndup(alias->name, tmp - alias->name), > - PMU_EVENT_SYMBOL_PREFIX); > - p++; > - SET_SYMBOL(strdup(++tmp), PMU_EVENT_SYMBOL_SUFFIX); > - len += 2; > - } else { > - SET_SYMBOL(strdup(alias->name), PMU_EVENT_SYMBOL); > - len++; > - } > - } > - } > - qsort(perf_pmu_events_list, len, > - sizeof(struct perf_pmu_event_symbol), comp_pmu); > - > - return; > -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, *tmp, symbols[] = { > - {(char *)"read", PMU_EVENT_SYMBOL}, > - {(char *)"event", PMU_EVENT_SYMBOL_PREFIX}, > - {(char *)"two", PMU_EVENT_SYMBOL_SUFFIX}, > - {(char *)"hyphen", PMU_EVENT_SYMBOL_SUFFIX}, > - {(char *)"hyph", PMU_EVENT_SYMBOL_SUFFIX2}, > - }; > - unsigned long i, j; > - > - tmp = list = malloc(sizeof(*list) * ARRAY_SIZE(symbols)); > - if (!list) > - return -ENOMEM; > - > - for (i = 0; i < ARRAY_SIZE(symbols); i++, tmp++) { > - tmp->type = symbols[i].type; > - tmp->symbol = strdup(symbols[i].symbol); > - if (!tmp->symbol) > - goto err_free; > - } > - > - perf_pmu_events_list = list; > - perf_pmu_events_list_num = ARRAY_SIZE(symbols); > - > - qsort(perf_pmu_events_list, ARRAY_SIZE(symbols), > - sizeof(struct perf_pmu_event_symbol), comp_pmu); > - return 0; > - > -err_free: > - for (j = 0, tmp = list; j < i; j++, tmp++) > - zfree(&tmp->symbol); > - free(list); > - return -ENOMEM; > -} > - > -enum perf_pmu_event_symbol_type > -perf_pmu__parse_check(const char *name) > -{ > - struct perf_pmu_event_symbol p, *r; > - > - /* scan kernel pmu events from sysfs if needed */ > - if (perf_pmu_events_list_num == 0) > - perf_pmu__parse_init(); > - /* > - * name "cpu" could be prefix of cpu-cycles or cpu// events. > - * cpu-cycles has been handled by hardcode. > - * So it must be cpu// events, not kernel pmu event. > - */ > - if ((perf_pmu_events_list_num <= 0) || !strcmp(name, "cpu")) > - return PMU_EVENT_SYMBOL_ERR; > - > - p.symbol = strdup(name); > - r = bsearch(&p, perf_pmu_events_list, > - (size_t) perf_pmu_events_list_num, > - sizeof(struct perf_pmu_event_symbol), comp_pmu); > - zfree(&p.symbol); > - return r ? r->type : PMU_EVENT_SYMBOL_ERR; > -} > - > static int parse_events__scanner(const char *str, > struct parse_events_state *parse_state) > { > @@ -2086,7 +1970,6 @@ 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); > @@ -2111,7 +1994,6 @@ static int parse_events__with_hybrid_pmu(struct parse_events_state *parse_state, > int ret; > > ret = parse_events__scanner(str, &ps); > - perf_pmu__parse_cleanup(); > > if (!ret) { > if (!list_empty(&ps.list)) { > @@ -2267,7 +2149,6 @@ int __parse_events(struct evlist *evlist, const char *str, > int ret; > > ret = parse_events__scanner(str, &parse_state); > - perf_pmu__parse_cleanup(); > > if (!ret && list_empty(&parse_state.list)) { > WARN_ONCE(true, "WARNING: event parser found nothing\n"); > diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h > index 86ad4438a2aa..f638542c8638 100644 > --- a/tools/perf/util/parse-events.h > +++ b/tools/perf/util/parse-events.h > @@ -41,14 +41,6 @@ int parse_events_terms(struct list_head *terms, const char *str); > int parse_filter(const struct option *opt, const char *str, int unset); > int exclude_perf(const struct option *opt, const char *arg, int unset); > > -enum perf_pmu_event_symbol_type { > - PMU_EVENT_SYMBOL_ERR, /* not a PMU EVENT */ > - PMU_EVENT_SYMBOL, /* normal style PMU event */ > - PMU_EVENT_SYMBOL_PREFIX, /* prefix of pre-suf style event */ > - PMU_EVENT_SYMBOL_SUFFIX, /* suffix of pre-suf style event */ > - PMU_EVENT_SYMBOL_SUFFIX2, /* suffix of pre-suf2 style event */ > -}; > - > enum { > PARSE_EVENTS__TERM_TYPE_NUM, > PARSE_EVENTS__TERM_TYPE_STR, > @@ -78,6 +70,7 @@ enum { > PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT, > PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE, > PARSE_EVENTS__TERM_TYPE_METRIC_ID, > + PARSE_EVENTS__TERM_TYPE_RAW, > __PARSE_EVENTS__TERM_TYPE_NR, > }; > > @@ -174,8 +167,7 @@ int parse_events_add_numeric(struct parse_events_state *parse_state, > int parse_events_add_tool(struct parse_events_state *parse_state, > struct list_head *list, > int tool_event); > -int parse_events_add_cache(struct list_head *list, int *idx, > - char *type, char *op_result1, char *op_result2, > +int parse_events_add_cache(struct list_head *list, int *idx, const char *name, > struct parse_events_error *error, > struct list_head *head_config, > struct parse_events_state *parse_state); > @@ -198,8 +190,6 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, > int parse_events_copy_term_list(struct list_head *old, > struct list_head **new); > > -enum perf_pmu_event_symbol_type > -perf_pmu__parse_check(const char *name); > void parse_events__set_leader(char *name, struct list_head *list); > void parse_events_update_lists(struct list_head *list_event, > struct list_head *list_all); > @@ -241,8 +231,6 @@ static inline bool is_sdt_event(char *str __maybe_unused) > } > #endif /* HAVE_LIBELF_SUPPORT */ > > -int perf_pmu__test_parse_init(void); > - > struct evsel *parse_events__add_event_hybrid(struct list_head *list, int *idx, > struct perf_event_attr *attr, > const char *name, > diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l > index 51fe0a9fb3de..4b35c099189a 100644 > --- a/tools/perf/util/parse-events.l > +++ b/tools/perf/util/parse-events.l > @@ -63,17 +63,6 @@ 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); > @@ -131,35 +120,6 @@ do { \ > yyless(0); \ > } while (0) > > -static int pmu_str_check(yyscan_t scanner, struct parse_events_state *parse_state) > -{ > - YYSTYPE *yylval = parse_events_get_lval(scanner); > - char *text = parse_events_get_text(scanner); > - > - yylval->str = strdup(text); > - > - /* > - * If we're not testing then parse check determines the PMU event type > - * which if it isn't a PMU returns PE_NAME. When testing the result of > - * parse check can't be trusted so we return PE_PMU_EVENT_FAKE unless > - * an '!' is present in which case the text can't be a PMU name. > - */ > - switch (perf_pmu__parse_check(text)) { > - case PMU_EVENT_SYMBOL_PREFIX: > - return PE_PMU_EVENT_PRE; > - case PMU_EVENT_SYMBOL_SUFFIX: > - return PE_PMU_EVENT_SUF; > - case PMU_EVENT_SYMBOL_SUFFIX2: > - return PE_PMU_EVENT_SUF2; > - case PMU_EVENT_SYMBOL: > - return parse_state->fake_pmu > - ? PE_PMU_EVENT_FAKE : PE_KERNEL_PMU_EVENT; > - default: > - return parse_state->fake_pmu && !strchr(text,'!') > - ? PE_PMU_EVENT_FAKE : PE_NAME; > - } > -} > - > static int sym(yyscan_t scanner, int type, int config) > { > YYSTYPE *yylval = parse_events_get_lval(scanner); > @@ -211,13 +171,15 @@ bpf_source [^,{}]+\.c[a-zA-Z0-9._]* > num_dec [0-9]+ > num_hex 0x[a-fA-F0-9]+ > num_raw_hex [a-fA-F0-9]+ > -name [a-zA-Z_*?\[\]][a-zA-Z0-9_*?.\[\]!]* > +name [a-zA-Z_*?\[\]][a-zA-Z0-9_*?.\[\]!\-]* > name_tag [\'][a-zA-Z_*?\[\]][a-zA-Z0-9_*?\-,\.\[\]:=]*[\'] > name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.:]* > drv_cfg_term [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)? > /* If you add a modifier you need to update check_modifier() */ > modifier_event [ukhpPGHSDIWeb]+ > modifier_bp [rwx]{1,3} > +lc_type (L1-dcache|l1-d|l1d|L1-data|L1-icache|l1-i|l1i|L1-instruction|LLC|L2|dTLB|d-tlb|Data-TLB|iTLB|i-tlb|Instruction-TLB|branch|branches|bpu|btb|bpc|node) > +lc_op_result (load|loads|read|store|stores|write|prefetch|prefetches|speculative-read|speculative-load|refs|Reference|ops|access|misses|miss) > > %% > > @@ -303,8 +265,8 @@ percore { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_PERCORE); } > aux-output { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT); } > aux-sample-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE); } > metric-id { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_METRIC_ID); } > -r{num_raw_hex} { return raw(yyscanner); } > -r0x{num_raw_hex} { return raw(yyscanner); } > +r{num_raw_hex} { return str(yyscanner, PE_RAW); } > +r0x{num_raw_hex} { return str(yyscanner, PE_RAW); } > , { return ','; } > "/" { BEGIN(INITIAL); return '/'; } > {name_minus} { return str(yyscanner, PE_NAME); } > @@ -359,47 +321,20 @@ system_time { return tool(yyscanner, PERF_TOOL_SYSTEM_TIME); } > bpf-output { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_BPF_OUTPUT); } > cgroup-switches { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CGROUP_SWITCHES); } > > - /* > - * We have to handle the kernel PMU event cycles-ct/cycles-t/mem-loads/mem-stores separately. > - * Because the prefix cycles is mixed up with cpu-cycles. > - * loads and stores are mixed up with cache event > - */ > -cycles-ct | > -cycles-t | > -mem-loads | > -mem-loads-aux | > -mem-stores | > -topdown-[a-z-]+ | > -tx-capacity-[a-z-]+ | > -el-capacity-[a-z-]+ { return str(yyscanner, PE_KERNEL_PMU_EVENT); } > - > -L1-dcache|l1-d|l1d|L1-data | > -L1-icache|l1-i|l1i|L1-instruction | > -LLC|L2 | > -dTLB|d-tlb|Data-TLB | > -iTLB|i-tlb|Instruction-TLB | > -branch|branches|bpu|btb|bpc | > -node { return str(yyscanner, PE_NAME_CACHE_TYPE); } > - > -load|loads|read | > -store|stores|write | > -prefetch|prefetches | > -speculative-read|speculative-load | > -refs|Reference|ops|access | > -misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); } > - > +{lc_type} { return str(yyscanner, PE_LEGACY_CACHE); } > +{lc_type}-{lc_op_result} { return str(yyscanner, PE_LEGACY_CACHE); } > +{lc_type}-{lc_op_result}-{lc_op_result} { return str(yyscanner, PE_LEGACY_CACHE); } > mem: { BEGIN(mem); return PE_PREFIX_MEM; } > -r{num_raw_hex} { return raw(yyscanner); } > +r{num_raw_hex} { return str(yyscanner, PE_RAW); } > {num_dec} { return value(yyscanner, 10); } > {num_hex} { return value(yyscanner, 16); } > > {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } > {bpf_object} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_OBJECT); } > {bpf_source} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_SOURCE); } > -{name} { return pmu_str_check(yyscanner, _parse_state); } > +{name} { return str(yyscanner, PE_NAME); } > {name_tag} { return str(yyscanner, PE_NAME); } > "/" { BEGIN(config); return '/'; } > -- { return '-'; } > , { BEGIN(event); return ','; } > : { return ':'; } > "{" { BEGIN(event); return '{'; } > diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y > index 4488443e506e..e7072b5601c5 100644 > --- a/tools/perf/util/parse-events.y > +++ b/tools/perf/util/parse-events.y > @@ -8,6 +8,7 @@ > > #define YYDEBUG 1 > > +#include > #include > #include > #include > @@ -52,36 +53,35 @@ static void free_list_evsel(struct list_head* list_evsel) > %} > > %token PE_START_EVENTS PE_START_TERMS > -%token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM > +%token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_TERM > %token PE_VALUE_SYM_TOOL > %token PE_EVENT_NAME > -%token PE_NAME > +%token PE_RAW PE_NAME > %token PE_BPF_OBJECT PE_BPF_SOURCE > %token PE_MODIFIER_EVENT PE_MODIFIER_BP > -%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT > +%token PE_LEGACY_CACHE > %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP > %token PE_ERROR > -%token PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_PMU_EVENT_SUF2 PE_KERNEL_PMU_EVENT PE_PMU_EVENT_FAKE > +%token PE_KERNEL_PMU_EVENT PE_PMU_EVENT_FAKE > %token PE_ARRAY_ALL PE_ARRAY_RANGE > %token PE_DRV_CFG_TERM > %type PE_VALUE > %type PE_VALUE_SYM_HW > %type PE_VALUE_SYM_SW > %type PE_VALUE_SYM_TOOL > -%type PE_RAW > %type PE_TERM > %type value_sym > +%type PE_RAW > %type PE_NAME > %type PE_BPF_OBJECT > %type PE_BPF_SOURCE > -%type PE_NAME_CACHE_TYPE > -%type PE_NAME_CACHE_OP_RESULT > +%type PE_LEGACY_CACHE > %type PE_MODIFIER_EVENT > %type PE_MODIFIER_BP > %type PE_EVENT_NAME > -%type PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_PMU_EVENT_SUF2 PE_KERNEL_PMU_EVENT PE_PMU_EVENT_FAKE > +%type PE_KERNEL_PMU_EVENT PE_PMU_EVENT_FAKE > %type PE_DRV_CFG_TERM > -%type event_pmu_name > +%type name_or_raw > %destructor { free ($$); } > %type event_term > %destructor { parse_events_term__delete ($$); } > @@ -273,11 +273,8 @@ event_def: event_pmu | > event_legacy_raw sep_dc | > event_bpf_file > > -event_pmu_name: > -PE_NAME | PE_PMU_EVENT_PRE > - > event_pmu: > -event_pmu_name opt_pmu_config > +PE_NAME opt_pmu_config > { > struct parse_events_state *parse_state = _parse_state; > struct parse_events_error *error = parse_state->error; > @@ -303,10 +300,12 @@ event_pmu_name opt_pmu_config > list = alloc_list(); > if (!list) > CLEANUP_YYABORT; > + /* Attempt to add to list assuming $1 is a PMU name. */ > if (parse_events_add_pmu(_parse_state, list, $1, $2, /*auto_merge_stats=*/false)) { > struct perf_pmu *pmu = NULL; > int ok = 0; > > + /* Failure to add, try wildcard expansion of $1 as a PMU name. */ > if (asprintf(&pattern, "%s*", $1) < 0) > CLEANUP_YYABORT; > > @@ -329,6 +328,12 @@ event_pmu_name opt_pmu_config > } > } > > + if (!ok) { > + /* Failure to add, assume $1 is an event name. */ > + zfree(&list); > + ok = !parse_events_multi_pmu_add(_parse_state, $1, $2, &list); > + $2 = NULL; > + } > if (!ok) > CLEANUP_YYABORT; > } > @@ -352,41 +357,27 @@ PE_KERNEL_PMU_EVENT sep_dc > $$ = list; > } > | > -PE_KERNEL_PMU_EVENT opt_pmu_config > +PE_NAME sep_dc > { > struct list_head *list; > int err; > > - /* frees $2 */ > - err = parse_events_multi_pmu_add(_parse_state, $1, $2, &list); > + err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list); > free($1); > if (err < 0) > YYABORT; > $$ = list; > } > | > -PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF '-' PE_PMU_EVENT_SUF2 sep_dc > -{ > - struct list_head *list; > - char pmu_name[128]; > - snprintf(pmu_name, sizeof(pmu_name), "%s-%s-%s", $1, $3, $5); > - free($1); > - free($3); > - free($5); > - if (parse_events_multi_pmu_add(_parse_state, pmu_name, NULL, &list) < 0) > - YYABORT; > - $$ = list; > -} > -| > -PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc > +PE_KERNEL_PMU_EVENT opt_pmu_config > { > struct list_head *list; > - char pmu_name[128]; > + int err; > > - snprintf(pmu_name, sizeof(pmu_name), "%s-%s", $1, $3); > + /* frees $2 */ > + err = parse_events_multi_pmu_add(_parse_state, $1, $2, &list); > free($1); > - free($3); > - if (parse_events_multi_pmu_add(_parse_state, pmu_name, NULL, &list) < 0) > + if (err < 0) > YYABORT; > $$ = list; > } > @@ -476,7 +467,7 @@ PE_VALUE_SYM_TOOL sep_slash_slash_dc > } > > event_legacy_cache: > -PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT opt_event_config > +PE_LEGACY_CACHE opt_event_config > { > struct parse_events_state *parse_state = _parse_state; > struct parse_events_error *error = parse_state->error; > @@ -485,51 +476,8 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT opt_e > > list = alloc_list(); > ABORT_ON(!list); > - err = parse_events_add_cache(list, &parse_state->idx, $1, $3, $5, error, $6, > - parse_state); > - parse_events_terms__delete($6); > - free($1); > - free($3); > - free($5); > - if (err) { > - free_list_evsel(list); > - YYABORT; > - } > - $$ = list; > -} > -| > -PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT opt_event_config > -{ > - struct parse_events_state *parse_state = _parse_state; > - struct parse_events_error *error = parse_state->error; > - struct list_head *list; > - int err; > + err = parse_events_add_cache(list, &parse_state->idx, $1, error, $2, parse_state); > > - list = alloc_list(); > - ABORT_ON(!list); > - err = parse_events_add_cache(list, &parse_state->idx, $1, $3, NULL, error, $4, > - parse_state); > - parse_events_terms__delete($4); > - free($1); > - free($3); > - if (err) { > - free_list_evsel(list); > - YYABORT; > - } > - $$ = list; > -} > -| > -PE_NAME_CACHE_TYPE opt_event_config > -{ > - struct parse_events_state *parse_state = _parse_state; > - struct parse_events_error *error = parse_state->error; > - struct list_head *list; > - int err; > - > - list = alloc_list(); > - ABORT_ON(!list); > - err = parse_events_add_cache(list, &parse_state->idx, $1, NULL, NULL, error, $2, > - parse_state); > parse_events_terms__delete($2); > free($1); > if (err) { > @@ -633,17 +581,6 @@ tracepoint_name opt_event_config > } > > tracepoint_name: > -PE_NAME '-' PE_NAME ':' PE_NAME > -{ > - struct tracepoint_name tracepoint; > - > - ABORT_ON(asprintf(&tracepoint.sys, "%s-%s", $1, $3) < 0); > - tracepoint.event = $5; > - free($1); > - free($3); > - $$ = tracepoint; > -} > -| > PE_NAME ':' PE_NAME > { > struct tracepoint_name tracepoint = {$1, $3}; > @@ -673,10 +610,15 @@ PE_RAW opt_event_config > { > struct list_head *list; > int err; > + u64 num; > > list = alloc_list(); > ABORT_ON(!list); > - err = parse_events_add_numeric(_parse_state, list, PERF_TYPE_RAW, $1, $2); > + errno = 0; > + num = strtoull($1 + 1, NULL, 16); > + ABORT_ON(errno); > + free($1); > + err = parse_events_add_numeric(_parse_state, list, PERF_TYPE_RAW, num, $2); > parse_events_terms__delete($2); > if (err) { > free(list); > @@ -781,17 +723,22 @@ event_term > $$ = head; > } > > +name_or_raw: PE_RAW | PE_NAME > + > event_term: > PE_RAW > { > struct parse_events_term *term; > > - ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_CONFIG, > - NULL, $1, false, &@1, NULL)); > + if (parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_RAW, > + strdup("raw"), $1, &@1, &@1)) { > + free($1); > + YYABORT; > + } > $$ = term; > } > | > -PE_NAME '=' PE_NAME > +name_or_raw '=' PE_NAME > { > struct parse_events_term *term; > > @@ -804,7 +751,7 @@ PE_NAME '=' PE_NAME > $$ = term; > } > | > -PE_NAME '=' PE_VALUE > +name_or_raw '=' PE_VALUE > { > struct parse_events_term *term; > > @@ -816,7 +763,7 @@ PE_NAME '=' PE_VALUE > $$ = term; > } > | > -PE_NAME '=' PE_VALUE_SYM_HW > +name_or_raw '=' PE_VALUE_SYM_HW > { > struct parse_events_term *term; > int config = $3 & 255; > @@ -876,7 +823,7 @@ PE_TERM > $$ = term; > } > | > -PE_NAME array '=' PE_NAME > +name_or_raw array '=' PE_NAME > { > struct parse_events_term *term; > > @@ -891,7 +838,7 @@ PE_NAME array '=' PE_NAME > $$ = term; > } > | > -PE_NAME array '=' PE_VALUE > +name_or_raw array '=' PE_VALUE > { > struct parse_events_term *term; >