Commit ac20de6f authored by Zheng Yan's avatar Zheng Yan Committed by Ingo Molnar

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: default avatarZheng Yan <zheng.z.yan@intel.com>
[ Cleaned up the patch. ]
Signed-off-by: default avatarJiri Olsa <jolsa@redhat.com>
Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1339741902-8449-11-git-send-email-zheng.z.yan@intel.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 46010ab2
...@@ -11,6 +11,7 @@ ...@@ -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 { ...@@ -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) ...@@ -787,26 +788,38 @@ int parse_events_modifier(struct list_head *list, char *str)
return 0; return 0;
} }
int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) static int parse_events__scanner(const char *str, void *data)
{ {
struct parse_events_data__events data = {
.list = LIST_HEAD_INIT(data.list),
.idx = evlist->nr_entries,
};
YY_BUFFER_STATE buffer; YY_BUFFER_STATE buffer;
void *scanner;
int ret; int ret;
buffer = parse_events__scan_string(str); ret = parse_events_lex_init(&scanner);
if (ret)
return ret;
buffer = parse_events__scan_string(str, scanner);
#ifdef PARSER_DEBUG #ifdef PARSER_DEBUG
parse_events_debug = 1; parse_events_debug = 1;
#endif #endif
ret = parse_events_parse(&data); 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;
}
parse_events__flush_buffer(buffer); int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
parse_events__delete_buffer(buffer); {
parse_events_lex_destroy(); struct parse_events_data__events data = {
.list = LIST_HEAD_INIT(data.list),
.idx = evlist->nr_entries,
};
int ret;
ret = parse_events__scanner(str, &data);
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, ...@@ -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);
......
%option reentrant
%option bison-bridge
%option prefix="parse_events_" %option prefix="parse_events_"
%option stack %option stack
...@@ -8,7 +10,10 @@ ...@@ -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) ...@@ -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} ...@@ -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 | ...@@ -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); } ...@@ -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(); } ...@@ -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(); } ...@@ -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;
} }
%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 @@ ...@@ -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: '/' | ':' | ...@@ -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)
{ {
} }
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