Commit 70c90e4a authored by Ian Rogers's avatar Ian Rogers Committed by Arnaldo Carvalho de Melo

perf parse-events: Avoid scanning PMUs before parsing

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: default avatarIan Rogers <irogers@google.com>
Tested-by: default avatarKan Liang <kan.liang@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ahmad Yasin <ahmad.yasin@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
Cc: Caleb Biggers <caleb.biggers@intel.com>
Cc: Edward Baker <edward.baker@intel.com>
Cc: Florian Fischer <florian.fischer@muhq.space>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Kang Minchul <tegongkang@gmail.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Perry Taylor <perry.taylor@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Samantha Alt <samantha.alt@intel.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Sumanth Korikkar <sumanthk@linux.ibm.com>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Tiezhu Yang <yangtiezhu@loongson.cn>
Cc: Weilin Wang <weilin.wang@intel.com>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Cc: Yang Jihong <yangjihong1@huawei.com>
Link: https://lore.kernel.org/r/20230502223851.2234828-19-irogers@google.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 442eeb77
...@@ -676,11 +676,11 @@ static int test__checkterms_simple(struct list_head *terms) ...@@ -676,11 +676,11 @@ static int test__checkterms_simple(struct list_head *terms)
*/ */
term = list_entry(term->list.next, struct parse_events_term, list); term = list_entry(term->list.next, struct parse_events_term, list);
TEST_ASSERT_VAL("wrong type term", 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", TEST_ASSERT_VAL("wrong type val",
term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); term->type_val == PARSE_EVENTS__TERM_TYPE_STR);
TEST_ASSERT_VAL("wrong val", term->val.num == 1); TEST_ASSERT_VAL("wrong val", !strcmp(term->val.str, "read"));
TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "read")); TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "raw"));
/* /*
* r0xead * r0xead
...@@ -690,11 +690,11 @@ static int test__checkterms_simple(struct list_head *terms) ...@@ -690,11 +690,11 @@ static int test__checkterms_simple(struct list_head *terms)
*/ */
term = list_entry(term->list.next, struct parse_events_term, list); term = list_entry(term->list.next, struct parse_events_term, list);
TEST_ASSERT_VAL("wrong type term", 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", TEST_ASSERT_VAL("wrong type val",
term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); term->type_val == PARSE_EVENTS__TERM_TYPE_STR);
TEST_ASSERT_VAL("wrong val", term->val.num == 0xead); TEST_ASSERT_VAL("wrong val", !strcmp(term->val.str, "r0xead"));
TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "config")); TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "raw"));
return TEST_OK; return TEST_OK;
} }
...@@ -2104,7 +2104,6 @@ static int test_event_fake_pmu(const char *str) ...@@ -2104,7 +2104,6 @@ static int test_event_fake_pmu(const char *str)
return -ENOMEM; return -ENOMEM;
parse_events_error__init(&err); parse_events_error__init(&err);
perf_pmu__test_parse_init();
ret = __parse_events(evlist, str, &err, &perf_pmu__fake, /*warn_if_reordered=*/true); ret = __parse_events(evlist, str, &err, &perf_pmu__fake, /*warn_if_reordered=*/true);
if (ret) { if (ret) {
pr_debug("failed to parse event '%s', err %d, str '%s'\n", pr_debug("failed to parse event '%s', err %d, str '%s'\n",
...@@ -2158,13 +2157,6 @@ static int test_term(const struct terms_test *t) ...@@ -2158,13 +2157,6 @@ static int test_term(const struct terms_test *t)
INIT_LIST_HEAD(&terms); 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); ret = parse_events_terms(&terms, t->str);
if (ret) { if (ret) {
pr_debug("failed to parse terms '%s', err %d\n", pr_debug("failed to parse terms '%s', err %d\n",
......
...@@ -776,15 +776,6 @@ static int check_parse_id(const char *id, struct parse_events_error *error, ...@@ -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, '@')) for (cur = strchr(dup, '@') ; cur; cur = strchr(++cur, '@'))
*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); ret = __parse_events(evlist, dup, error, fake_pmu, /*warn_if_reordered=*/true);
free(dup); free(dup);
......
This diff is collapsed.
...@@ -41,14 +41,6 @@ int parse_events_terms(struct list_head *terms, const char *str); ...@@ -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 parse_filter(const struct option *opt, const char *str, int unset);
int exclude_perf(const struct option *opt, const char *arg, 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 { enum {
PARSE_EVENTS__TERM_TYPE_NUM, PARSE_EVENTS__TERM_TYPE_NUM,
PARSE_EVENTS__TERM_TYPE_STR, PARSE_EVENTS__TERM_TYPE_STR,
...@@ -78,6 +70,7 @@ enum { ...@@ -78,6 +70,7 @@ enum {
PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT, PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT,
PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE, PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE,
PARSE_EVENTS__TERM_TYPE_METRIC_ID, PARSE_EVENTS__TERM_TYPE_METRIC_ID,
PARSE_EVENTS__TERM_TYPE_RAW,
__PARSE_EVENTS__TERM_TYPE_NR, __PARSE_EVENTS__TERM_TYPE_NR,
}; };
...@@ -174,8 +167,7 @@ int parse_events_add_numeric(struct parse_events_state *parse_state, ...@@ -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, int parse_events_add_tool(struct parse_events_state *parse_state,
struct list_head *list, struct list_head *list,
int tool_event); int tool_event);
int parse_events_add_cache(struct list_head *list, int *idx, int parse_events_add_cache(struct list_head *list, int *idx, const char *name,
char *type, char *op_result1, char *op_result2,
struct parse_events_error *error, struct parse_events_error *error,
struct list_head *head_config, struct list_head *head_config,
struct parse_events_state *parse_state); struct parse_events_state *parse_state);
...@@ -198,8 +190,6 @@ int parse_events_multi_pmu_add(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, int parse_events_copy_term_list(struct list_head *old,
struct list_head **new); 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__set_leader(char *name, struct list_head *list);
void parse_events_update_lists(struct list_head *list_event, void parse_events_update_lists(struct list_head *list_event,
struct list_head *list_all); struct list_head *list_all);
...@@ -241,8 +231,6 @@ static inline bool is_sdt_event(char *str __maybe_unused) ...@@ -241,8 +231,6 @@ static inline bool is_sdt_event(char *str __maybe_unused)
} }
#endif /* HAVE_LIBELF_SUPPORT */ #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 evsel *parse_events__add_event_hybrid(struct list_head *list, int *idx,
struct perf_event_attr *attr, struct perf_event_attr *attr,
const char *name, const char *name,
......
...@@ -63,17 +63,6 @@ static int str(yyscan_t scanner, int token) ...@@ -63,17 +63,6 @@ static int str(yyscan_t scanner, int token)
return 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) static bool isbpf_suffix(char *text)
{ {
int len = strlen(text); int len = strlen(text);
...@@ -131,35 +120,6 @@ do { \ ...@@ -131,35 +120,6 @@ do { \
yyless(0); \ yyless(0); \
} while (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) static int sym(yyscan_t scanner, int type, int config)
{ {
YYSTYPE *yylval = parse_events_get_lval(scanner); YYSTYPE *yylval = parse_events_get_lval(scanner);
...@@ -211,13 +171,15 @@ bpf_source [^,{}]+\.c[a-zA-Z0-9._]* ...@@ -211,13 +171,15 @@ bpf_source [^,{}]+\.c[a-zA-Z0-9._]*
num_dec [0-9]+ num_dec [0-9]+
num_hex 0x[a-fA-F0-9]+ num_hex 0x[a-fA-F0-9]+
num_raw_hex [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_tag [\'][a-zA-Z_*?\[\]][a-zA-Z0-9_*?\-,\.\[\]:=]*[\']
name_minus [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_*?\.:]+)? drv_cfg_term [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)?
/* If you add a modifier you need to update check_modifier() */ /* If you add a modifier you need to update check_modifier() */
modifier_event [ukhpPGHSDIWeb]+ modifier_event [ukhpPGHSDIWeb]+
modifier_bp [rwx]{1,3} 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); } ...@@ -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-output { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT); }
aux-sample-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE); } aux-sample-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE); }
metric-id { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_METRIC_ID); } metric-id { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_METRIC_ID); }
r{num_raw_hex} { return raw(yyscanner); } r{num_raw_hex} { return str(yyscanner, PE_RAW); }
r0x{num_raw_hex} { return raw(yyscanner); } r0x{num_raw_hex} { return str(yyscanner, PE_RAW); }
, { return ','; } , { return ','; }
"/" { BEGIN(INITIAL); return '/'; } "/" { BEGIN(INITIAL); return '/'; }
{name_minus} { return str(yyscanner, PE_NAME); } {name_minus} { return str(yyscanner, PE_NAME); }
...@@ -359,47 +321,20 @@ system_time { return tool(yyscanner, PERF_TOOL_SYSTEM_TIME); } ...@@ -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); } 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); } cgroup-switches { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CGROUP_SWITCHES); }
/* {lc_type} { return str(yyscanner, PE_LEGACY_CACHE); }
* We have to handle the kernel PMU event cycles-ct/cycles-t/mem-loads/mem-stores separately. {lc_type}-{lc_op_result} { return str(yyscanner, PE_LEGACY_CACHE); }
* Because the prefix cycles is mixed up with cpu-cycles. {lc_type}-{lc_op_result}-{lc_op_result} { return str(yyscanner, PE_LEGACY_CACHE); }
* 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); }
mem: { BEGIN(mem); return PE_PREFIX_MEM; } 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_dec} { return value(yyscanner, 10); }
{num_hex} { return value(yyscanner, 16); } {num_hex} { return value(yyscanner, 16); }
{modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); }
{bpf_object} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_OBJECT); } {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); } {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); } {name_tag} { return str(yyscanner, PE_NAME); }
"/" { BEGIN(config); return '/'; } "/" { BEGIN(config); return '/'; }
- { return '-'; }
, { BEGIN(event); return ','; } , { BEGIN(event); return ','; }
: { return ':'; } : { return ':'; }
"{" { BEGIN(event); return '{'; } "{" { BEGIN(event); return '{'; }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define YYDEBUG 1 #define YYDEBUG 1
#include <errno.h>
#include <fnmatch.h> #include <fnmatch.h>
#include <stdio.h> #include <stdio.h>
#include <linux/compiler.h> #include <linux/compiler.h>
...@@ -52,36 +53,35 @@ static void free_list_evsel(struct list_head* list_evsel) ...@@ -52,36 +53,35 @@ static void free_list_evsel(struct list_head* list_evsel)
%} %}
%token PE_START_EVENTS PE_START_TERMS %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_VALUE_SYM_TOOL
%token PE_EVENT_NAME %token PE_EVENT_NAME
%token PE_NAME %token PE_RAW PE_NAME
%token PE_BPF_OBJECT PE_BPF_SOURCE %token PE_BPF_OBJECT PE_BPF_SOURCE
%token PE_MODIFIER_EVENT PE_MODIFIER_BP %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_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP
%token PE_ERROR %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_ARRAY_ALL PE_ARRAY_RANGE
%token PE_DRV_CFG_TERM %token PE_DRV_CFG_TERM
%type <num> PE_VALUE %type <num> PE_VALUE
%type <num> PE_VALUE_SYM_HW %type <num> PE_VALUE_SYM_HW
%type <num> PE_VALUE_SYM_SW %type <num> PE_VALUE_SYM_SW
%type <num> PE_VALUE_SYM_TOOL %type <num> PE_VALUE_SYM_TOOL
%type <num> PE_RAW
%type <num> PE_TERM %type <num> PE_TERM
%type <num> value_sym %type <num> value_sym
%type <str> PE_RAW
%type <str> PE_NAME %type <str> PE_NAME
%type <str> PE_BPF_OBJECT %type <str> PE_BPF_OBJECT
%type <str> PE_BPF_SOURCE %type <str> PE_BPF_SOURCE
%type <str> PE_NAME_CACHE_TYPE %type <str> PE_LEGACY_CACHE
%type <str> PE_NAME_CACHE_OP_RESULT
%type <str> PE_MODIFIER_EVENT %type <str> PE_MODIFIER_EVENT
%type <str> PE_MODIFIER_BP %type <str> PE_MODIFIER_BP
%type <str> PE_EVENT_NAME %type <str> PE_EVENT_NAME
%type <str> PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_PMU_EVENT_SUF2 PE_KERNEL_PMU_EVENT PE_PMU_EVENT_FAKE %type <str> PE_KERNEL_PMU_EVENT PE_PMU_EVENT_FAKE
%type <str> PE_DRV_CFG_TERM %type <str> PE_DRV_CFG_TERM
%type <str> event_pmu_name %type <str> name_or_raw
%destructor { free ($$); } <str> %destructor { free ($$); } <str>
%type <term> event_term %type <term> event_term
%destructor { parse_events_term__delete ($$); } <term> %destructor { parse_events_term__delete ($$); } <term>
...@@ -273,11 +273,8 @@ event_def: event_pmu | ...@@ -273,11 +273,8 @@ event_def: event_pmu |
event_legacy_raw sep_dc | event_legacy_raw sep_dc |
event_bpf_file event_bpf_file
event_pmu_name:
PE_NAME | PE_PMU_EVENT_PRE
event_pmu: event_pmu:
event_pmu_name opt_pmu_config PE_NAME opt_pmu_config
{ {
struct parse_events_state *parse_state = _parse_state; struct parse_events_state *parse_state = _parse_state;
struct parse_events_error *error = parse_state->error; struct parse_events_error *error = parse_state->error;
...@@ -303,10 +300,12 @@ event_pmu_name opt_pmu_config ...@@ -303,10 +300,12 @@ event_pmu_name opt_pmu_config
list = alloc_list(); list = alloc_list();
if (!list) if (!list)
CLEANUP_YYABORT; 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)) { if (parse_events_add_pmu(_parse_state, list, $1, $2, /*auto_merge_stats=*/false)) {
struct perf_pmu *pmu = NULL; struct perf_pmu *pmu = NULL;
int ok = 0; int ok = 0;
/* Failure to add, try wildcard expansion of $1 as a PMU name. */
if (asprintf(&pattern, "%s*", $1) < 0) if (asprintf(&pattern, "%s*", $1) < 0)
CLEANUP_YYABORT; CLEANUP_YYABORT;
...@@ -329,6 +328,12 @@ event_pmu_name opt_pmu_config ...@@ -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) if (!ok)
CLEANUP_YYABORT; CLEANUP_YYABORT;
} }
...@@ -352,41 +357,27 @@ PE_KERNEL_PMU_EVENT sep_dc ...@@ -352,41 +357,27 @@ PE_KERNEL_PMU_EVENT sep_dc
$$ = list; $$ = list;
} }
| |
PE_KERNEL_PMU_EVENT opt_pmu_config PE_NAME sep_dc
{ {
struct list_head *list; struct list_head *list;
int err; int err;
/* frees $2 */ err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list);
err = parse_events_multi_pmu_add(_parse_state, $1, $2, &list);
free($1); free($1);
if (err < 0) if (err < 0)
YYABORT; YYABORT;
$$ = list; $$ = list;
} }
| |
PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF '-' PE_PMU_EVENT_SUF2 sep_dc PE_KERNEL_PMU_EVENT opt_pmu_config
{
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
{ {
struct list_head *list; 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($1);
free($3); if (err < 0)
if (parse_events_multi_pmu_add(_parse_state, pmu_name, NULL, &list) < 0)
YYABORT; YYABORT;
$$ = list; $$ = list;
} }
...@@ -476,7 +467,7 @@ PE_VALUE_SYM_TOOL sep_slash_slash_dc ...@@ -476,7 +467,7 @@ PE_VALUE_SYM_TOOL sep_slash_slash_dc
} }
event_legacy_cache: 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_state *parse_state = _parse_state;
struct parse_events_error *error = parse_state->error; 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 ...@@ -485,51 +476,8 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT opt_e
list = alloc_list(); list = alloc_list();
ABORT_ON(!list); ABORT_ON(!list);
err = parse_events_add_cache(list, &parse_state->idx, $1, $3, $5, error, $6, err = parse_events_add_cache(list, &parse_state->idx, $1, error, $2, parse_state);
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;
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); parse_events_terms__delete($2);
free($1); free($1);
if (err) { if (err) {
...@@ -633,17 +581,6 @@ tracepoint_name opt_event_config ...@@ -633,17 +581,6 @@ tracepoint_name opt_event_config
} }
tracepoint_name: 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 PE_NAME ':' PE_NAME
{ {
struct tracepoint_name tracepoint = {$1, $3}; struct tracepoint_name tracepoint = {$1, $3};
...@@ -673,10 +610,15 @@ PE_RAW opt_event_config ...@@ -673,10 +610,15 @@ PE_RAW opt_event_config
{ {
struct list_head *list; struct list_head *list;
int err; int err;
u64 num;
list = alloc_list(); list = alloc_list();
ABORT_ON(!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); parse_events_terms__delete($2);
if (err) { if (err) {
free(list); free(list);
...@@ -781,17 +723,22 @@ event_term ...@@ -781,17 +723,22 @@ event_term
$$ = head; $$ = head;
} }
name_or_raw: PE_RAW | PE_NAME
event_term: event_term:
PE_RAW PE_RAW
{ {
struct parse_events_term *term; struct parse_events_term *term;
ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_CONFIG, if (parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_RAW,
NULL, $1, false, &@1, NULL)); strdup("raw"), $1, &@1, &@1)) {
free($1);
YYABORT;
}
$$ = term; $$ = term;
} }
| |
PE_NAME '=' PE_NAME name_or_raw '=' PE_NAME
{ {
struct parse_events_term *term; struct parse_events_term *term;
...@@ -804,7 +751,7 @@ PE_NAME '=' PE_NAME ...@@ -804,7 +751,7 @@ PE_NAME '=' PE_NAME
$$ = term; $$ = term;
} }
| |
PE_NAME '=' PE_VALUE name_or_raw '=' PE_VALUE
{ {
struct parse_events_term *term; struct parse_events_term *term;
...@@ -816,7 +763,7 @@ PE_NAME '=' PE_VALUE ...@@ -816,7 +763,7 @@ PE_NAME '=' PE_VALUE
$$ = term; $$ = term;
} }
| |
PE_NAME '=' PE_VALUE_SYM_HW name_or_raw '=' PE_VALUE_SYM_HW
{ {
struct parse_events_term *term; struct parse_events_term *term;
int config = $3 & 255; int config = $3 & 255;
...@@ -876,7 +823,7 @@ PE_TERM ...@@ -876,7 +823,7 @@ PE_TERM
$$ = term; $$ = term;
} }
| |
PE_NAME array '=' PE_NAME name_or_raw array '=' PE_NAME
{ {
struct parse_events_term *term; struct parse_events_term *term;
...@@ -891,7 +838,7 @@ PE_NAME array '=' PE_NAME ...@@ -891,7 +838,7 @@ PE_NAME array '=' PE_NAME
$$ = term; $$ = term;
} }
| |
PE_NAME array '=' PE_VALUE name_or_raw array '=' PE_VALUE
{ {
struct parse_events_term *term; struct parse_events_term *term;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment