Commit 8f707d84 authored by Jiri Olsa's avatar Jiri Olsa Committed by Arnaldo Carvalho de Melo

perf tools: Add config options support for event parsing

Adding a new rule to the event grammar to be able to specify
values of additional attributes of symbolic event.

The new syntax for event symbolic definition is:

event_legacy_symbol:  PE_NAME_SYM '/' event_config '/' |
                      PE_NAME_SYM sep_slash_dc

event_config:         event_config ',' event_term | event_term

event_term:           PE_NAME '=' PE_NAME |
                      PE_NAME '=' PE_VALUE
                      PE_NAME

sep_slash_dc: '/' | ':' |

At the moment the config options are hardcoded to be used for legacy
symbol events to define several perf_event_attr fields. It is:

  'config'   to define perf_event_attr::config
  'config1'  to define perf_event_attr::config1
  'config2'  to define perf_event_attr::config2
  'period'   to define perf_event_attr::sample_period

Legacy events could be now specified as:
  cycles/period=100000/

If term is specified without the value assignment, then 1 is
assigned by default.
Acked-by: default avatarPeter Zijlstra <peterz@infradead.org>
Signed-off-by: default avatarJiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/n/tip-mgkavww9790jbt2jdkooyv4q@git.kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 89812fc8
...@@ -677,6 +677,24 @@ static int test__checkevent_symbolic_name(struct perf_evlist *evlist) ...@@ -677,6 +677,24 @@ static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
return 0; return 0;
} }
static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
{
struct perf_evsel *evsel = list_entry(evlist->entries.next,
struct perf_evsel, node);
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
TEST_ASSERT_VAL("wrong config",
PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
TEST_ASSERT_VAL("wrong period",
100000 == evsel->attr.sample_period);
TEST_ASSERT_VAL("wrong config1",
0 == evsel->attr.config1);
TEST_ASSERT_VAL("wrong config2",
1 == evsel->attr.config2);
return 0;
}
static int test__checkevent_symbolic_alias(struct perf_evlist *evlist) static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
{ {
struct perf_evsel *evsel = list_entry(evlist->entries.next, struct perf_evsel *evsel = list_entry(evlist->entries.next,
...@@ -883,6 +901,10 @@ static struct test__event_st { ...@@ -883,6 +901,10 @@ static struct test__event_st {
.name = "instructions", .name = "instructions",
.check = test__checkevent_symbolic_name, .check = test__checkevent_symbolic_name,
}, },
{
.name = "cycles/period=100000,config2/",
.check = test__checkevent_symbolic_name_config,
},
{ {
.name = "faults", .name = "faults",
.check = test__checkevent_symbolic_alias, .check = test__checkevent_symbolic_alias,
......
This diff is collapsed.
...@@ -41,14 +41,15 @@ ...@@ -41,14 +41,15 @@
PE_VALUE = 258, PE_VALUE = 258,
PE_VALUE_SYM = 259, PE_VALUE_SYM = 259,
PE_RAW = 260, PE_RAW = 260,
PE_NAME = 261, PE_TERM = 261,
PE_MODIFIER_EVENT = 262, PE_NAME = 262,
PE_MODIFIER_BP = 263, PE_MODIFIER_EVENT = 263,
PE_NAME_CACHE_TYPE = 264, PE_MODIFIER_BP = 264,
PE_NAME_CACHE_OP_RESULT = 265, PE_NAME_CACHE_TYPE = 265,
PE_PREFIX_MEM = 266, PE_NAME_CACHE_OP_RESULT = 266,
PE_PREFIX_RAW = 267, PE_PREFIX_MEM = 267,
PE_ERROR = 268 PE_PREFIX_RAW = 268,
PE_ERROR = 269
}; };
#endif #endif
...@@ -59,15 +60,17 @@ typedef union YYSTYPE ...@@ -59,15 +60,17 @@ typedef union YYSTYPE
{ {
/* Line 1685 of yacc.c */ /* Line 1685 of yacc.c */
#line 42 "util/parse-events.y" #line 45 "util/parse-events.y"
char *str; char *str;
unsigned long num; unsigned long num;
struct list_head *head;
struct parse_events__term *term;
/* Line 1685 of yacc.c */ /* Line 1685 of yacc.c */
#line 71 "util/parse-events-bison.h" #line 74 "util/parse-events-bison.h"
} YYSTYPE; } YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define yystype YYSTYPE /* obsolescent; will be withdrawn */
......
This diff is collapsed.
...@@ -308,7 +308,7 @@ extern int parse_events_lex (void); ...@@ -308,7 +308,7 @@ extern int parse_events_lex (void);
#undef YY_DECL #undef YY_DECL
#endif #endif
#line 102 "util/parse-events.l" #line 121 "util/parse-events.l"
#line 315 "util/parse-events-flex.h" #line 315 "util/parse-events-flex.h"
......
...@@ -588,15 +588,60 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx, ...@@ -588,15 +588,60 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
return add_event(list, idx, &attr, name); return add_event(list, idx, &attr, name);
} }
int static int config_term(struct perf_event_attr *attr,
parse_events_add_numeric(struct list_head *list, int *idx, struct parse_events__term *term)
unsigned long type, unsigned long config) {
switch (term->type) {
case PARSE_EVENTS__TERM_TYPE_CONFIG:
attr->config = term->val.num;
break;
case PARSE_EVENTS__TERM_TYPE_CONFIG1:
attr->config1 = term->val.num;
break;
case PARSE_EVENTS__TERM_TYPE_CONFIG2:
attr->config2 = term->val.num;
break;
case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
attr->sample_period = term->val.num;
break;
case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
/*
* TODO uncomment when the field is available
* attr->branch_sample_type = term->val.num;
*/
break;
default:
return -EINVAL;
}
return 0;
}
static int config_attr(struct perf_event_attr *attr,
struct list_head *head, int fail)
{
struct parse_events__term *term;
list_for_each_entry(term, head, list)
if (config_term(attr, term) && fail)
return -EINVAL;
return 0;
}
int parse_events_add_numeric(struct list_head *list, int *idx,
unsigned long type, unsigned long config,
struct list_head *head_config)
{ {
struct perf_event_attr attr; struct perf_event_attr attr;
memset(&attr, 0, sizeof(attr)); memset(&attr, 0, sizeof(attr));
attr.type = type; attr.type = type;
attr.config = config; attr.config = config;
if (head_config &&
config_attr(&attr, head_config, 1))
return -EINVAL;
return add_event(list, idx, &attr, return add_event(list, idx, &attr,
(char *) __event_name(type, config)); (char *) __event_name(type, config));
} }
...@@ -923,3 +968,51 @@ void print_events(const char *event_glob) ...@@ -923,3 +968,51 @@ void print_events(const char *event_glob)
print_tracepoint_events(NULL, NULL); print_tracepoint_events(NULL, NULL);
} }
int parse_events__is_hardcoded_term(struct parse_events__term *term)
{
return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX;
}
int parse_events__new_term(struct parse_events__term **_term, int type,
char *config, char *str, long num)
{
struct parse_events__term *term;
term = zalloc(sizeof(*term));
if (!term)
return -ENOMEM;
INIT_LIST_HEAD(&term->list);
term->type = type;
term->config = config;
switch (type) {
case PARSE_EVENTS__TERM_TYPE_CONFIG:
case PARSE_EVENTS__TERM_TYPE_CONFIG1:
case PARSE_EVENTS__TERM_TYPE_CONFIG2:
case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
case PARSE_EVENTS__TERM_TYPE_NUM:
term->val.num = num;
break;
case PARSE_EVENTS__TERM_TYPE_STR:
term->val.str = str;
break;
default:
return -EINVAL;
}
*_term = term;
return 0;
}
void parse_events__free_terms(struct list_head *terms)
{
struct parse_events__term *term, *h;
list_for_each_entry_safe(term, h, terms, list)
free(term);
free(terms);
}
...@@ -33,6 +33,34 @@ extern int parse_filter(const struct option *opt, const char *str, int unset); ...@@ -33,6 +33,34 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
#define EVENTS_HELP_MAX (128*1024) #define EVENTS_HELP_MAX (128*1024)
enum {
PARSE_EVENTS__TERM_TYPE_CONFIG,
PARSE_EVENTS__TERM_TYPE_CONFIG1,
PARSE_EVENTS__TERM_TYPE_CONFIG2,
PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
PARSE_EVENTS__TERM_TYPE_NUM,
PARSE_EVENTS__TERM_TYPE_STR,
PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX =
PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
};
struct parse_events__term {
char *config;
union {
char *str;
long num;
} val;
int type;
struct list_head list;
};
int parse_events__is_hardcoded_term(struct parse_events__term *term);
int parse_events__new_term(struct parse_events__term **term, int type,
char *config, char *str, long num);
void parse_events__free_terms(struct list_head *terms);
int parse_events_modifier(struct list_head *list __used, char *str __used); int parse_events_modifier(struct list_head *list __used, char *str __used);
int parse_events_add_tracepoint(struct list_head *list, int *idx, int parse_events_add_tracepoint(struct list_head *list, int *idx,
char *sys, char *event); char *sys, char *event);
...@@ -40,7 +68,8 @@ int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config, ...@@ -40,7 +68,8 @@ int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config,
unsigned long config1, unsigned long config2, unsigned long config1, unsigned long config2,
char *mod); char *mod);
int parse_events_add_numeric(struct list_head *list, int *idx, int parse_events_add_numeric(struct list_head *list, int *idx,
unsigned long type, unsigned long config); unsigned long type, unsigned long config,
struct list_head *head_config);
int parse_events_add_cache(struct list_head *list, int *idx, int parse_events_add_cache(struct list_head *list, int *idx,
char *type, char *op_result1, char *op_result2); char *type, char *op_result1, char *op_result2);
int parse_events_add_breakpoint(struct list_head *list, int *idx, int parse_events_add_breakpoint(struct list_head *list, int *idx,
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <errno.h> #include <errno.h>
#include "../perf.h" #include "../perf.h"
#include "parse-events-bison.h" #include "parse-events-bison.h"
#include "parse-events.h"
static int __value(char *str, int base, int token) static int __value(char *str, int base, int token)
{ {
...@@ -41,6 +42,12 @@ static int sym(int type, int config) ...@@ -41,6 +42,12 @@ static int sym(int type, int config)
return PE_VALUE_SYM; return PE_VALUE_SYM;
} }
static int term(int type)
{
parse_events_lval.num = type;
return PE_TERM;
}
%} %}
num_dec [0-9]+ num_dec [0-9]+
...@@ -85,6 +92,18 @@ speculative-read|speculative-load | ...@@ -85,6 +92,18 @@ speculative-read|speculative-load |
refs|Reference|ops|access | refs|Reference|ops|access |
misses|miss { return str(PE_NAME_CACHE_OP_RESULT); } misses|miss { return str(PE_NAME_CACHE_OP_RESULT); }
/*
* These are event config hardcoded term names to be specified
* within xxx/.../ syntax. So far we dont clash with other names,
* so we can put them here directly. In case the we have a conflict
* in future, this needs to go into '//' condition block.
*/
config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
mem: { return PE_PREFIX_MEM; } mem: { return PE_PREFIX_MEM; }
r{num_raw_hex} { return raw(); } r{num_raw_hex} { return raw(); }
{num_dec} { return value(10); } {num_dec} { return value(10); }
......
...@@ -23,7 +23,7 @@ do { \ ...@@ -23,7 +23,7 @@ do { \
%} %}
%token PE_VALUE PE_VALUE_SYM PE_RAW %token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM
%token PE_NAME %token PE_NAME
%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_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
...@@ -32,16 +32,21 @@ do { \ ...@@ -32,16 +32,21 @@ do { \
%type <num> PE_VALUE %type <num> PE_VALUE
%type <num> PE_VALUE_SYM %type <num> PE_VALUE_SYM
%type <num> PE_RAW %type <num> PE_RAW
%type <num> PE_TERM
%type <str> PE_NAME %type <str> PE_NAME
%type <str> PE_NAME_CACHE_TYPE %type <str> PE_NAME_CACHE_TYPE
%type <str> PE_NAME_CACHE_OP_RESULT %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 <head> event_config
%type <term> event_term
%union %union
{ {
char *str; char *str;
unsigned long num; unsigned long num;
struct list_head *head;
struct parse_events__term *term;
} }
%% %%
...@@ -56,7 +61,7 @@ event_def PE_MODIFIER_EVENT ...@@ -56,7 +61,7 @@ event_def PE_MODIFIER_EVENT
| |
event_def event_def
event_def: event_legacy_symbol sep_dc | event_def: event_legacy_symbol |
event_legacy_cache sep_dc | event_legacy_cache sep_dc |
event_legacy_mem | event_legacy_mem |
event_legacy_tracepoint sep_dc | event_legacy_tracepoint sep_dc |
...@@ -64,12 +69,21 @@ event_def: event_legacy_symbol sep_dc | ...@@ -64,12 +69,21 @@ event_def: event_legacy_symbol sep_dc |
event_legacy_raw sep_dc event_legacy_raw sep_dc
event_legacy_symbol: event_legacy_symbol:
PE_VALUE_SYM PE_VALUE_SYM '/' event_config '/'
{ {
int type = $1 >> 16; int type = $1 >> 16;
int config = $1 & 255; int config = $1 & 255;
ABORT_ON(parse_events_add_numeric(list, idx, type, config)); ABORT_ON(parse_events_add_numeric(list, idx, type, config, $3));
parse_events__free_terms($3);
}
|
PE_VALUE_SYM sep_slash_dc
{
int type = $1 >> 16;
int config = $1 & 255;
ABORT_ON(parse_events_add_numeric(list, idx, type, config, NULL));
} }
event_legacy_cache: event_legacy_cache:
...@@ -108,17 +122,85 @@ PE_NAME ':' PE_NAME ...@@ -108,17 +122,85 @@ PE_NAME ':' PE_NAME
event_legacy_numeric: event_legacy_numeric:
PE_VALUE ':' PE_VALUE PE_VALUE ':' PE_VALUE
{ {
ABORT_ON(parse_events_add_numeric(list, idx, $1, $3)); ABORT_ON(parse_events_add_numeric(list, idx, $1, $3, NULL));
} }
event_legacy_raw: event_legacy_raw:
PE_RAW PE_RAW
{ {
ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, $1)); ABORT_ON(parse_events_add_numeric(list, idx, PERF_TYPE_RAW, $1, NULL));
}
event_config:
event_config ',' event_term
{
struct list_head *head = $1;
struct parse_events__term *term = $3;
ABORT_ON(!head);
list_add_tail(&term->list, head);
$$ = $1;
}
|
event_term
{
struct list_head *head = malloc(sizeof(*head));
struct parse_events__term *term = $1;
ABORT_ON(!head);
INIT_LIST_HEAD(head);
list_add_tail(&term->list, head);
$$ = head;
}
event_term:
PE_NAME '=' PE_NAME
{
struct parse_events__term *term;
ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR,
$1, $3, 0));
$$ = term;
}
|
PE_NAME '=' PE_VALUE
{
struct parse_events__term *term;
ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
$1, NULL, $3));
$$ = term;
}
|
PE_NAME
{
struct parse_events__term *term;
ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
$1, NULL, 1));
$$ = term;
}
|
PE_TERM '=' PE_VALUE
{
struct parse_events__term *term;
ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, $3));
$$ = term;
}
|
PE_TERM
{
struct parse_events__term *term;
ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, 1));
$$ = term;
} }
sep_dc: ':' | sep_dc: ':' |
sep_slash_dc: '/' | ':' |
%% %%
void parse_events_error(struct list_head *list __used, int *idx __used, void parse_events_error(struct list_head *list __used, int *idx __used,
......
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