Skip to content

Commit

Permalink
perf/tool: Make the event parser re-entrant
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Zheng Yan authored and Ingo Molnar committed Jun 18, 2012
1 parent 46010ab commit ac20de6
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 64 deletions.
35 changes: 24 additions & 11 deletions tools/perf/util/parse-events.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "cache.h"
#include "header.h"
#include "debugfs.h"
#include "parse-events-bison.h"
#include "parse-events-flex.h"
#include "pmu.h"

Expand All @@ -26,7 +27,7 @@ struct event_symbol {
#ifdef PARSER_DEBUG
extern int parse_events_debug;
#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 CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
Expand Down Expand Up @@ -787,26 +788,38 @@ int parse_events_modifier(struct list_head *list, char *str)
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;
void *scanner;
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
parse_events_debug = 1;
#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);
parse_events__delete_buffer(buffer);
parse_events_lex_destroy();
int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
{
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) {
int entries = data.idx - evlist->nr_entries;
perf_evlist__splice_list_tail(evlist, &data.list, entries);
Expand Down
2 changes: 1 addition & 1 deletion tools/perf/util/parse-events.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
char *pmu , struct list_head *head_config);
void parse_events_update_lists(struct list_head *list_event,
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);

void print_events(const char *event_glob);
Expand Down
116 changes: 67 additions & 49 deletions tools/perf/util/parse-events.l
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

%option reentrant
%option bison-bridge
%option prefix="parse_events_"
%option stack

Expand All @@ -8,7 +10,10 @@
#include "parse-events-bison.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;

Expand All @@ -17,35 +22,48 @@ static int __value(char *str, int base, int token)
if (errno)
return PE_ERROR;

parse_events_lval.num = num;
yylval->num = num;
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;
}

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;
}

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;
}

Expand All @@ -61,79 +79,79 @@ modifier_event [ukhpGH]{1,8}
modifier_bp [rwx]

%%
cpu-cycles|cycles { return sym(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-backend|idle-cycles-backend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
instructions { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
cache-references { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
cache-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
branch-instructions|branches { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
branch-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
bus-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
ref-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
cpu-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
task-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
page-faults|faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
minor-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
major-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
context-switches|cs { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
cpu-migrations|migrations { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
alignment-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
emulation-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
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(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
instructions { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
cache-references { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
cache-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
branch-instructions|branches { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
branch-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
bus-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
ref-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
cpu-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
task-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
page-faults|faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
minor-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
major-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
context-switches|cs { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }

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(PE_NAME_CACHE_TYPE); }
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(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
* 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); }
name { return term(PARSE_EVENTS__TERM_TYPE_NAME); }
period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }

mem: { BEGIN(mem); return PE_PREFIX_MEM; }
r{num_raw_hex} { return raw(); }
{num_dec} { return value(10); }
{num_hex} { return value(16); }
r{num_raw_hex} { return raw(yyscanner); }
{num_dec} { return value(yyscanner, 10); }
{num_hex} { return value(yyscanner, 16); }

{modifier_event} { return str(PE_MODIFIER_EVENT); }
{name} { return str(PE_NAME); }
{modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); }
{name} { return str(yyscanner, PE_NAME); }
"/" { return '/'; }
- { return '-'; }
, { return ','; }
: { return ':'; }
= { return '='; }

<mem>{
{modifier_bp} { return str(PE_MODIFIER_BP); }
{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
: { return ':'; }
{num_dec} { return value(10); }
{num_hex} { return value(16); }
{num_dec} { return value(yyscanner, 10); }
{num_hex} { return value(yyscanner, 16); }
/*
* We need to separate 'mem:' scanner part, in order to get specific
* 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>
* 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,
* but anyway just to be sure get back to INIT state.
Expand All @@ -143,7 +161,7 @@ r{num_raw_hex} { return raw(); }

%%

int parse_events_wrap(void)
int parse_events_wrap(void *scanner __used)
{
return 1;
}
9 changes: 6 additions & 3 deletions tools/perf/util/parse-events.y
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@

%pure-parser
%name-prefix "parse_events_"
%parse-param {void *_data}
%parse-param {void *scanner}
%lex-param {void* scanner}

%{

Expand All @@ -11,8 +13,9 @@
#include "types.h"
#include "util.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) \
do { \
Expand Down Expand Up @@ -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)
{
}

0 comments on commit ac20de6

Please sign in to comment.