summaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/parse-events.c23
-rw-r--r--tools/perf/util/parse-events.h10
-rw-r--r--tools/perf/util/parse-events.l23
-rw-r--r--tools/perf/util/parse-events.y49
4 files changed, 78 insertions, 27 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 629f7bd9fd59..2d36cadf35ec 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -946,10 +946,14 @@ do { \
return 0;
}
-int parse_events_add_breakpoint(struct list_head *list, int *idx,
- u64 addr, char *type, u64 len)
+int parse_events_add_breakpoint(struct parse_events_state *parse_state,
+ struct list_head *list,
+ u64 addr, char *type, u64 len,
+ struct list_head *head_config __maybe_unused)
{
struct perf_event_attr attr;
+ LIST_HEAD(config_terms);
+ const char *name;
memset(&attr, 0, sizeof(attr));
attr.bp_addr = addr;
@@ -970,8 +974,19 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
attr.type = PERF_TYPE_BREAKPOINT;
attr.sample_period = 1;
- return add_event(list, idx, &attr, /*name=*/NULL, /*mertic_id=*/NULL,
- /*config_terms=*/NULL);
+ if (head_config) {
+ if (config_attr(&attr, head_config, parse_state->error,
+ config_term_common))
+ return -EINVAL;
+
+ if (get_config_terms(head_config, &config_terms))
+ return -ENOMEM;
+ }
+
+ name = get_config_name(head_config);
+
+ return add_event(list, &parse_state->idx, &attr, name, /*mertic_id=*/NULL,
+ &config_terms);
}
static int check_type_val(struct parse_events_term *term,
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 2021fe145410..5fdc1f33f57e 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -185,8 +185,10 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name,
struct parse_events_state *parse_state,
struct list_head *head_config);
int parse_events__decode_legacy_cache(const char *name, int pmu_type, __u64 *config);
-int parse_events_add_breakpoint(struct list_head *list, int *idx,
- u64 addr, char *type, u64 len);
+int parse_events_add_breakpoint(struct parse_events_state *parse_state,
+ struct list_head *list,
+ u64 addr, char *type, u64 len,
+ struct list_head *head_config);
int parse_events_add_pmu(struct parse_events_state *parse_state,
struct list_head *list, char *name,
struct list_head *head_config,
@@ -226,6 +228,10 @@ void parse_events_error__handle(struct parse_events_error *err, int idx,
void parse_events_error__print(struct parse_events_error *err,
const char *event);
+static inline void parse_events_unused_value(const void *x __maybe_unused)
+{
+}
+
#ifdef HAVE_LIBELF_SUPPORT
/*
* If the probe point starts with '%',
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 6deb70c25984..7629af3d5c7c 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -190,11 +190,16 @@ 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() */
+/*
+ * If you add a modifier you need to update check_modifier().
+ * Also, the letters in modifier_event must not be in modifier_bp.
+ */
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)
+digit [0-9]
+non_digit [^0-9]
%%
@@ -304,8 +309,20 @@ r0x{num_raw_hex} { return str(yyscanner, PE_RAW); }
<mem>{
{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
-: { return ':'; }
-"/" { return '/'; }
+ /*
+ * The colon before memory access modifiers can get mixed up with the
+ * colon before event modifiers. Fortunately none of the option letters
+ * are the same, so trailing context can be used disambiguate the two
+ * cases.
+ */
+":"/{modifier_bp} { return str(yyscanner, PE_BP_COLON); }
+ /*
+ * The slash before memory length can get mixed up with the slash before
+ * config terms. Fortunately config terms do not start with a numeric
+ * digit, so trailing context can be used disambiguate the two cases.
+ */
+"/"/{digit} { return str(yyscanner, PE_BP_SLASH); }
+"/"/{non_digit} { BEGIN(config); return '/'; }
{num_dec} { return value(yyscanner, 10); }
{num_hex} { return value(yyscanner, 16); }
/*
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index f96afb0edd0c..0c3d086cc22a 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -59,7 +59,7 @@ static void free_list_evsel(struct list_head* list_evsel)
%token PE_EVENT_NAME
%token PE_RAW PE_NAME
%token PE_BPF_OBJECT PE_BPF_SOURCE
-%token PE_MODIFIER_EVENT PE_MODIFIER_BP
+%token PE_MODIFIER_EVENT PE_MODIFIER_BP PE_BP_COLON PE_BP_SLASH
%token PE_LEGACY_CACHE
%token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP
%token PE_ERROR
@@ -80,6 +80,8 @@ static void free_list_evsel(struct list_head* list_evsel)
%type <str> PE_LEGACY_CACHE
%type <str> PE_MODIFIER_EVENT
%type <str> PE_MODIFIER_BP
+%type <str> PE_BP_COLON
+%type <str> PE_BP_SLASH
%type <str> PE_EVENT_NAME
%type <str> PE_KERNEL_PMU_EVENT PE_PMU_EVENT_FAKE
%type <str> PE_DRV_CFG_TERM
@@ -275,7 +277,7 @@ event_def
event_def: event_pmu |
event_legacy_symbol |
event_legacy_cache sep_dc |
- event_legacy_mem |
+ event_legacy_mem sep_dc |
event_legacy_tracepoint sep_dc |
event_legacy_numeric sep_dc |
event_legacy_raw sep_dc |
@@ -503,16 +505,19 @@ PE_LEGACY_CACHE opt_event_config
}
event_legacy_mem:
-PE_PREFIX_MEM PE_VALUE '/' PE_VALUE ':' PE_MODIFIER_BP sep_dc
+PE_PREFIX_MEM PE_VALUE PE_BP_SLASH PE_VALUE PE_BP_COLON PE_MODIFIER_BP opt_event_config
{
- struct parse_events_state *parse_state = _parse_state;
struct list_head *list;
int err;
+ parse_events_unused_value(&$3);
+ parse_events_unused_value(&$5);
+
list = alloc_list();
ABORT_ON(!list);
- err = parse_events_add_breakpoint(list, &parse_state->idx,
- $2, $6, $4);
+ err = parse_events_add_breakpoint(_parse_state, list,
+ $2, $6, $4, $7);
+ parse_events_terms__delete($7);
free($6);
if (err) {
free(list);
@@ -521,31 +526,37 @@ PE_PREFIX_MEM PE_VALUE '/' PE_VALUE ':' PE_MODIFIER_BP sep_dc
$$ = list;
}
|
-PE_PREFIX_MEM PE_VALUE '/' PE_VALUE sep_dc
+PE_PREFIX_MEM PE_VALUE PE_BP_SLASH PE_VALUE opt_event_config
{
- struct parse_events_state *parse_state = _parse_state;
struct list_head *list;
+ int err;
+
+ parse_events_unused_value(&$3);
list = alloc_list();
ABORT_ON(!list);
- if (parse_events_add_breakpoint(list, &parse_state->idx,
- $2, NULL, $4)) {
+ err = parse_events_add_breakpoint(_parse_state, list,
+ $2, NULL, $4, $5);
+ parse_events_terms__delete($5);
+ if (err) {
free(list);
YYABORT;
}
$$ = list;
}
|
-PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
+PE_PREFIX_MEM PE_VALUE PE_BP_COLON PE_MODIFIER_BP opt_event_config
{
- struct parse_events_state *parse_state = _parse_state;
struct list_head *list;
int err;
+ parse_events_unused_value(&$3);
+
list = alloc_list();
ABORT_ON(!list);
- err = parse_events_add_breakpoint(list, &parse_state->idx,
- $2, $4, 0);
+ err = parse_events_add_breakpoint(_parse_state, list,
+ $2, $4, 0, $5);
+ parse_events_terms__delete($5);
free($4);
if (err) {
free(list);
@@ -554,15 +565,17 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
$$ = list;
}
|
-PE_PREFIX_MEM PE_VALUE sep_dc
+PE_PREFIX_MEM PE_VALUE opt_event_config
{
- struct parse_events_state *parse_state = _parse_state;
struct list_head *list;
+ int err;
list = alloc_list();
ABORT_ON(!list);
- if (parse_events_add_breakpoint(list, &parse_state->idx,
- $2, NULL, 0)) {
+ err = parse_events_add_breakpoint(_parse_state, list,
+ $2, NULL, 0, $3);
+ parse_events_terms__delete($3);
+ if (err) {
free(list);
YYABORT;
}