perf/tool: Make the event parser re-entrant
Make the event parser reentrant by creating separate scanner for each parsing. The scanner is passed to the bison as and argument to the lexer. Signed-off-by: Zheng Yan <zheng.z.yan@intel.com> [ Cleaned up the patch. ] Signed-off-by: Jiri Olsa <jolsa@redhat.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1339741902-8449-11-git-send-email-zheng.z.yan@intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
46010ab260
commit
ac20de6fff
4 changed files with 100 additions and 66 deletions
|
@ -11,6 +11,7 @@
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "header.h"
|
#include "header.h"
|
||||||
#include "debugfs.h"
|
#include "debugfs.h"
|
||||||
|
#include "parse-events-bison.h"
|
||||||
#include "parse-events-flex.h"
|
#include "parse-events-flex.h"
|
||||||
#include "pmu.h"
|
#include "pmu.h"
|
||||||
|
|
||||||
|
@ -26,7 +27,7 @@ struct event_symbol {
|
||||||
#ifdef PARSER_DEBUG
|
#ifdef PARSER_DEBUG
|
||||||
extern int parse_events_debug;
|
extern int parse_events_debug;
|
||||||
#endif
|
#endif
|
||||||
int parse_events_parse(void *data);
|
int parse_events_parse(void *data, void *scanner);
|
||||||
|
|
||||||
#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
|
#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
|
||||||
#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
|
#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
|
||||||
|
@ -787,26 +788,38 @@ int parse_events_modifier(struct list_head *list, char *str)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parse_events__scanner(const char *str, void *data)
|
||||||
|
{
|
||||||
|
YY_BUFFER_STATE buffer;
|
||||||
|
void *scanner;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = parse_events_lex_init(&scanner);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
buffer = parse_events__scan_string(str, scanner);
|
||||||
|
|
||||||
|
#ifdef PARSER_DEBUG
|
||||||
|
parse_events_debug = 1;
|
||||||
|
#endif
|
||||||
|
ret = parse_events_parse(data, scanner);
|
||||||
|
|
||||||
|
parse_events__flush_buffer(buffer, scanner);
|
||||||
|
parse_events__delete_buffer(buffer, scanner);
|
||||||
|
parse_events_lex_destroy(scanner);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
|
int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
|
||||||
{
|
{
|
||||||
struct parse_events_data__events data = {
|
struct parse_events_data__events data = {
|
||||||
.list = LIST_HEAD_INIT(data.list),
|
.list = LIST_HEAD_INIT(data.list),
|
||||||
.idx = evlist->nr_entries,
|
.idx = evlist->nr_entries,
|
||||||
};
|
};
|
||||||
YY_BUFFER_STATE buffer;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
buffer = parse_events__scan_string(str);
|
ret = parse_events__scanner(str, &data);
|
||||||
|
|
||||||
#ifdef PARSER_DEBUG
|
|
||||||
parse_events_debug = 1;
|
|
||||||
#endif
|
|
||||||
ret = parse_events_parse(&data);
|
|
||||||
|
|
||||||
parse_events__flush_buffer(buffer);
|
|
||||||
parse_events__delete_buffer(buffer);
|
|
||||||
parse_events_lex_destroy();
|
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
int entries = data.idx - evlist->nr_entries;
|
int entries = data.idx - evlist->nr_entries;
|
||||||
perf_evlist__splice_list_tail(evlist, &data.list, entries);
|
perf_evlist__splice_list_tail(evlist, &data.list, entries);
|
||||||
|
|
|
@ -88,7 +88,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
|
||||||
char *pmu , struct list_head *head_config);
|
char *pmu , struct list_head *head_config);
|
||||||
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);
|
||||||
void parse_events_error(void *data, char const *msg);
|
void parse_events_error(void *data, void *scanner, char const *msg);
|
||||||
int parse_events__test(void);
|
int parse_events__test(void);
|
||||||
|
|
||||||
void print_events(const char *event_glob);
|
void print_events(const char *event_glob);
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
|
||||||
|
%option reentrant
|
||||||
|
%option bison-bridge
|
||||||
%option prefix="parse_events_"
|
%option prefix="parse_events_"
|
||||||
%option stack
|
%option stack
|
||||||
|
|
||||||
|
@ -8,7 +10,10 @@
|
||||||
#include "parse-events-bison.h"
|
#include "parse-events-bison.h"
|
||||||
#include "parse-events.h"
|
#include "parse-events.h"
|
||||||
|
|
||||||
static int __value(char *str, int base, int token)
|
char *parse_events_get_text(yyscan_t yyscanner);
|
||||||
|
YYSTYPE *parse_events_get_lval(yyscan_t yyscanner);
|
||||||
|
|
||||||
|
static int __value(YYSTYPE *yylval, char *str, int base, int token)
|
||||||
{
|
{
|
||||||
long num;
|
long num;
|
||||||
|
|
||||||
|
@ -17,35 +22,48 @@ static int __value(char *str, int base, int token)
|
||||||
if (errno)
|
if (errno)
|
||||||
return PE_ERROR;
|
return PE_ERROR;
|
||||||
|
|
||||||
parse_events_lval.num = num;
|
yylval->num = num;
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int value(int base)
|
static int value(yyscan_t scanner, int base)
|
||||||
{
|
{
|
||||||
return __value(parse_events_text, base, PE_VALUE);
|
YYSTYPE *yylval = parse_events_get_lval(scanner);
|
||||||
|
char *text = parse_events_get_text(scanner);
|
||||||
|
|
||||||
|
return __value(yylval, text, base, PE_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int raw(void)
|
static int raw(yyscan_t scanner)
|
||||||
{
|
{
|
||||||
return __value(parse_events_text + 1, 16, PE_RAW);
|
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(int token)
|
static int str(yyscan_t scanner, int token)
|
||||||
{
|
{
|
||||||
parse_events_lval.str = strdup(parse_events_text);
|
YYSTYPE *yylval = parse_events_get_lval(scanner);
|
||||||
|
char *text = parse_events_get_text(scanner);
|
||||||
|
|
||||||
|
yylval->str = strdup(text);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sym(int type, int config)
|
static int sym(yyscan_t scanner, int type, int config)
|
||||||
{
|
{
|
||||||
parse_events_lval.num = (type << 16) + config;
|
YYSTYPE *yylval = parse_events_get_lval(scanner);
|
||||||
|
|
||||||
|
yylval->num = (type << 16) + config;
|
||||||
return PE_VALUE_SYM;
|
return PE_VALUE_SYM;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int term(int type)
|
static int term(yyscan_t scanner, int type)
|
||||||
{
|
{
|
||||||
parse_events_lval.num = type;
|
YYSTYPE *yylval = parse_events_get_lval(scanner);
|
||||||
|
|
||||||
|
yylval->num = type;
|
||||||
return PE_TERM;
|
return PE_TERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,25 +79,25 @@ modifier_event [ukhpGH]{1,8}
|
||||||
modifier_bp [rwx]
|
modifier_bp [rwx]
|
||||||
|
|
||||||
%%
|
%%
|
||||||
cpu-cycles|cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
|
cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
|
||||||
stalled-cycles-frontend|idle-cycles-frontend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
|
stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
|
||||||
stalled-cycles-backend|idle-cycles-backend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
|
stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
|
||||||
instructions { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
|
instructions { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
|
||||||
cache-references { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
|
cache-references { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
|
||||||
cache-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
|
cache-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
|
||||||
branch-instructions|branches { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
|
branch-instructions|branches { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
|
||||||
branch-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
|
branch-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
|
||||||
bus-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
|
bus-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
|
||||||
ref-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
|
ref-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
|
||||||
cpu-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
|
cpu-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
|
||||||
task-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
|
task-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
|
||||||
page-faults|faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
|
page-faults|faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
|
||||||
minor-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
|
minor-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
|
||||||
major-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
|
major-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
|
||||||
context-switches|cs { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
|
context-switches|cs { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
|
||||||
cpu-migrations|migrations { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
|
cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
|
||||||
alignment-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
|
alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
|
||||||
emulation-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
|
emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
|
||||||
|
|
||||||
L1-dcache|l1-d|l1d|L1-data |
|
L1-dcache|l1-d|l1d|L1-data |
|
||||||
L1-icache|l1-i|l1i|L1-instruction |
|
L1-icache|l1-i|l1i|L1-instruction |
|
||||||
|
@ -87,14 +105,14 @@ LLC|L2 |
|
||||||
dTLB|d-tlb|Data-TLB |
|
dTLB|d-tlb|Data-TLB |
|
||||||
iTLB|i-tlb|Instruction-TLB |
|
iTLB|i-tlb|Instruction-TLB |
|
||||||
branch|branches|bpu|btb|bpc |
|
branch|branches|bpu|btb|bpc |
|
||||||
node { return str(PE_NAME_CACHE_TYPE); }
|
node { return str(yyscanner, PE_NAME_CACHE_TYPE); }
|
||||||
|
|
||||||
load|loads|read |
|
load|loads|read |
|
||||||
store|stores|write |
|
store|stores|write |
|
||||||
prefetch|prefetches |
|
prefetch|prefetches |
|
||||||
speculative-read|speculative-load |
|
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(yyscanner, PE_NAME_CACHE_OP_RESULT); }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These are event config hardcoded term names to be specified
|
* These are event config hardcoded term names to be specified
|
||||||
|
@ -102,20 +120,20 @@ misses|miss { return str(PE_NAME_CACHE_OP_RESULT); }
|
||||||
* so we can put them here directly. In case the we have a conflict
|
* so we can put them here directly. In case the we have a conflict
|
||||||
* in future, this needs to go into '//' condition block.
|
* in future, this needs to go into '//' condition block.
|
||||||
*/
|
*/
|
||||||
config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
|
config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
|
||||||
config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
|
config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
|
||||||
config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
|
config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
|
||||||
name { return term(PARSE_EVENTS__TERM_TYPE_NAME); }
|
name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
|
||||||
period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
|
period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
|
||||||
branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
|
branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
|
||||||
|
|
||||||
mem: { BEGIN(mem); return PE_PREFIX_MEM; }
|
mem: { BEGIN(mem); return PE_PREFIX_MEM; }
|
||||||
r{num_raw_hex} { return raw(); }
|
r{num_raw_hex} { return raw(yyscanner); }
|
||||||
{num_dec} { return value(10); }
|
{num_dec} { return value(yyscanner, 10); }
|
||||||
{num_hex} { return value(16); }
|
{num_hex} { return value(yyscanner, 16); }
|
||||||
|
|
||||||
{modifier_event} { return str(PE_MODIFIER_EVENT); }
|
{modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); }
|
||||||
{name} { return str(PE_NAME); }
|
{name} { return str(yyscanner, PE_NAME); }
|
||||||
"/" { return '/'; }
|
"/" { return '/'; }
|
||||||
- { return '-'; }
|
- { return '-'; }
|
||||||
, { return ','; }
|
, { return ','; }
|
||||||
|
@ -123,17 +141,17 @@ r{num_raw_hex} { return raw(); }
|
||||||
= { return '='; }
|
= { return '='; }
|
||||||
|
|
||||||
<mem>{
|
<mem>{
|
||||||
{modifier_bp} { return str(PE_MODIFIER_BP); }
|
{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
|
||||||
: { return ':'; }
|
: { return ':'; }
|
||||||
{num_dec} { return value(10); }
|
{num_dec} { return value(yyscanner, 10); }
|
||||||
{num_hex} { return value(16); }
|
{num_hex} { return value(yyscanner, 16); }
|
||||||
/*
|
/*
|
||||||
* We need to separate 'mem:' scanner part, in order to get specific
|
* We need to separate 'mem:' scanner part, in order to get specific
|
||||||
* modifier bits parsed out. Otherwise we would need to handle PE_NAME
|
* modifier bits parsed out. Otherwise we would need to handle PE_NAME
|
||||||
* and we'd need to parse it manually. During the escape from <mem>
|
* and we'd need to parse it manually. During the escape from <mem>
|
||||||
* state we need to put the escaping char back, so we dont miss it.
|
* state we need to put the escaping char back, so we dont miss it.
|
||||||
*/
|
*/
|
||||||
. { unput(*parse_events_text); BEGIN(INITIAL); }
|
. { unput(*yytext); BEGIN(INITIAL); }
|
||||||
/*
|
/*
|
||||||
* We destroy the scanner after reaching EOF,
|
* We destroy the scanner after reaching EOF,
|
||||||
* but anyway just to be sure get back to INIT state.
|
* but anyway just to be sure get back to INIT state.
|
||||||
|
@ -143,7 +161,7 @@ r{num_raw_hex} { return raw(); }
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
int parse_events_wrap(void)
|
int parse_events_wrap(void *scanner __used)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
%pure-parser
|
||||||
%name-prefix "parse_events_"
|
%name-prefix "parse_events_"
|
||||||
%parse-param {void *_data}
|
%parse-param {void *_data}
|
||||||
|
%parse-param {void *scanner}
|
||||||
|
%lex-param {void* scanner}
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
|
||||||
|
@ -11,8 +13,9 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "parse-events.h"
|
#include "parse-events.h"
|
||||||
|
#include "parse-events-bison.h"
|
||||||
|
|
||||||
extern int parse_events_lex (void);
|
extern int parse_events_lex (YYSTYPE* lvalp, void* scanner);
|
||||||
|
|
||||||
#define ABORT_ON(val) \
|
#define ABORT_ON(val) \
|
||||||
do { \
|
do { \
|
||||||
|
@ -286,7 +289,7 @@ sep_slash_dc: '/' | ':' |
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
void parse_events_error(void *data __used,
|
void parse_events_error(void *data __used, void *scanner __used,
|
||||||
char const *msg __used)
|
char const *msg __used)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue