]>
Commit | Line | Data |
---|---|---|
89812fc8 | 1 | |
ac20de6f ZY |
2 | %option reentrant |
3 | %option bison-bridge | |
89812fc8 | 4 | %option prefix="parse_events_" |
08d2f762 | 5 | %option stack |
6297d423 JO |
6 | %option bison-locations |
7 | %option yylineno | |
b6af53b7 | 8 | %option reject |
89812fc8 JO |
9 | |
10 | %{ | |
11 | #include <errno.h> | |
29479bfe JO |
12 | #include <sys/types.h> |
13 | #include <sys/stat.h> | |
14 | #include <unistd.h> | |
89812fc8 | 15 | #include "../perf.h" |
8f707d84 | 16 | #include "parse-events.h" |
e571e029 | 17 | #include "parse-events-bison.h" |
89812fc8 | 18 | |
ac20de6f ZY |
19 | char *parse_events_get_text(yyscan_t yyscanner); |
20 | YYSTYPE *parse_events_get_lval(yyscan_t yyscanner); | |
21 | ||
22 | static int __value(YYSTYPE *yylval, char *str, int base, int token) | |
89812fc8 | 23 | { |
b527bab5 | 24 | u64 num; |
89812fc8 JO |
25 | |
26 | errno = 0; | |
b527bab5 | 27 | num = strtoull(str, NULL, base); |
89812fc8 JO |
28 | if (errno) |
29 | return PE_ERROR; | |
30 | ||
ac20de6f | 31 | yylval->num = num; |
89812fc8 JO |
32 | return token; |
33 | } | |
34 | ||
ac20de6f | 35 | static int value(yyscan_t scanner, int base) |
89812fc8 | 36 | { |
ac20de6f ZY |
37 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
38 | char *text = parse_events_get_text(scanner); | |
39 | ||
40 | return __value(yylval, text, base, PE_VALUE); | |
89812fc8 JO |
41 | } |
42 | ||
ac20de6f | 43 | static int raw(yyscan_t scanner) |
89812fc8 | 44 | { |
ac20de6f ZY |
45 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
46 | char *text = parse_events_get_text(scanner); | |
47 | ||
48 | return __value(yylval, text + 1, 16, PE_RAW); | |
89812fc8 JO |
49 | } |
50 | ||
ac20de6f | 51 | static int str(yyscan_t scanner, int token) |
89812fc8 | 52 | { |
ac20de6f ZY |
53 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
54 | char *text = parse_events_get_text(scanner); | |
55 | ||
56 | yylval->str = strdup(text); | |
89812fc8 JO |
57 | return token; |
58 | } | |
59 | ||
29479bfe | 60 | static bool isbpf_suffix(char *text) |
77d0871c | 61 | { |
77d0871c AK |
62 | int len = strlen(text); |
63 | ||
64 | if (len < 2) | |
65 | return false; | |
66 | if ((text[len - 1] == 'c' || text[len - 1] == 'o') && | |
67 | text[len - 2] == '.') | |
68 | return true; | |
69 | if (len > 4 && !strcmp(text + len - 4, ".obj")) | |
70 | return true; | |
71 | return false; | |
72 | } | |
73 | ||
29479bfe JO |
74 | static bool isbpf(yyscan_t scanner) |
75 | { | |
76 | char *text = parse_events_get_text(scanner); | |
77 | struct stat st; | |
78 | ||
79 | if (!isbpf_suffix(text)) | |
80 | return false; | |
81 | ||
82 | return stat(text, &st) == 0; | |
83 | } | |
84 | ||
dd60fba7 MP |
85 | /* |
86 | * This function is called when the parser gets two kind of input: | |
87 | * | |
88 | * @cfg1 or @cfg2=config | |
89 | * | |
90 | * The leading '@' is stripped off before 'cfg1' and 'cfg2=config' are given to | |
91 | * bison. In the latter case it is necessary to keep the string intact so that | |
92 | * the PMU kernel driver can determine what configurable is associated to | |
93 | * 'config'. | |
94 | */ | |
95 | static int drv_str(yyscan_t scanner, int token) | |
96 | { | |
97 | YYSTYPE *yylval = parse_events_get_lval(scanner); | |
98 | char *text = parse_events_get_text(scanner); | |
99 | ||
100 | /* Strip off the '@' */ | |
101 | yylval->str = strdup(text + 1); | |
102 | return token; | |
103 | } | |
104 | ||
6297d423 JO |
105 | #define REWIND(__alloc) \ |
106 | do { \ | |
107 | YYSTYPE *__yylval = parse_events_get_lval(yyscanner); \ | |
108 | char *text = parse_events_get_text(yyscanner); \ | |
109 | \ | |
110 | if (__alloc) \ | |
111 | __yylval->str = strdup(text); \ | |
112 | \ | |
113 | yycolumn -= strlen(text); \ | |
114 | yyless(0); \ | |
115 | } while (0) | |
116 | ||
ba32a451 KL |
117 | static int pmu_str_check(yyscan_t scanner) |
118 | { | |
119 | YYSTYPE *yylval = parse_events_get_lval(scanner); | |
120 | char *text = parse_events_get_text(scanner); | |
121 | ||
122 | yylval->str = strdup(text); | |
123 | switch (perf_pmu__parse_check(text)) { | |
124 | case PMU_EVENT_SYMBOL_PREFIX: | |
125 | return PE_PMU_EVENT_PRE; | |
126 | case PMU_EVENT_SYMBOL_SUFFIX: | |
127 | return PE_PMU_EVENT_SUF; | |
128 | case PMU_EVENT_SYMBOL: | |
129 | return PE_KERNEL_PMU_EVENT; | |
130 | default: | |
131 | return PE_NAME; | |
132 | } | |
133 | } | |
134 | ||
ac20de6f | 135 | static int sym(yyscan_t scanner, int type, int config) |
89812fc8 | 136 | { |
ac20de6f ZY |
137 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
138 | ||
139 | yylval->num = (type << 16) + config; | |
cf3506dc | 140 | return type == PERF_TYPE_HARDWARE ? PE_VALUE_SYM_HW : PE_VALUE_SYM_SW; |
89812fc8 JO |
141 | } |
142 | ||
ac20de6f | 143 | static int term(yyscan_t scanner, int type) |
8f707d84 | 144 | { |
ac20de6f ZY |
145 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
146 | ||
147 | yylval->num = type; | |
8f707d84 JO |
148 | return PE_TERM; |
149 | } | |
150 | ||
6297d423 JO |
151 | #define YY_USER_ACTION \ |
152 | do { \ | |
153 | yylloc->last_column = yylloc->first_column; \ | |
154 | yylloc->first_column = yycolumn; \ | |
155 | yycolumn += yyleng; \ | |
156 | } while (0); | |
157 | ||
9445464b JO |
158 | #define USER_REJECT \ |
159 | yycolumn -= yyleng; \ | |
160 | REJECT | |
161 | ||
89812fc8 JO |
162 | %} |
163 | ||
08d2f762 | 164 | %x mem |
ac2ba9f3 RR |
165 | %s config |
166 | %x event | |
e571e029 | 167 | %x array |
ac2ba9f3 RR |
168 | |
169 | group [^,{}/]*[{][^}]*[}][^,{}/]* | |
170 | event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* | |
171 | event [^,{}/]+ | |
77d0871c AK |
172 | bpf_object [^,{}]+\.(o|bpf)[a-zA-Z0-9._]* |
173 | bpf_source [^,{}]+\.c[a-zA-Z0-9._]* | |
08d2f762 | 174 | |
89812fc8 JO |
175 | num_dec [0-9]+ |
176 | num_hex 0x[a-fA-F0-9]+ | |
177 | num_raw_hex [a-fA-F0-9]+ | |
5b021ddf | 178 | name [a-zA-Z_*?][a-zA-Z0-9_*?.]* |
a34f3be7 | 179 | name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.:]* |
dd60fba7 | 180 | drv_cfg_term [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)? |
e9a7c414 | 181 | /* If you add a modifier you need to update check_modifier() */ |
7f94af7a | 182 | modifier_event [ukhpPGHSDI]+ |
7582732f | 183 | modifier_bp [rwx]{1,3} |
89812fc8 JO |
184 | |
185 | %% | |
90e2b22d JO |
186 | |
187 | %{ | |
188 | { | |
189 | int start_token; | |
190 | ||
ac2ba9f3 RR |
191 | start_token = parse_events_get_extra(yyscanner); |
192 | ||
193 | if (start_token == PE_START_TERMS) | |
194 | BEGIN(config); | |
195 | else if (start_token == PE_START_EVENTS) | |
196 | BEGIN(event); | |
197 | ||
90e2b22d JO |
198 | if (start_token) { |
199 | parse_events_set_extra(NULL, yyscanner); | |
6297d423 JO |
200 | /* |
201 | * The flex parser does not init locations variable | |
202 | * via the scan_string interface, so we need do the | |
203 | * init in here. | |
204 | */ | |
205 | yycolumn = 0; | |
90e2b22d JO |
206 | return start_token; |
207 | } | |
208 | } | |
209 | %} | |
210 | ||
ac2ba9f3 RR |
211 | <event>{ |
212 | ||
213 | {group} { | |
6297d423 JO |
214 | BEGIN(INITIAL); |
215 | REWIND(0); | |
ac2ba9f3 RR |
216 | } |
217 | ||
218 | {event_pmu} | | |
84c86ca1 | 219 | {bpf_object} | |
d509db04 | 220 | {bpf_source} | |
ac2ba9f3 | 221 | {event} { |
6297d423 JO |
222 | BEGIN(INITIAL); |
223 | REWIND(1); | |
ac2ba9f3 RR |
224 | return PE_EVENT_NAME; |
225 | } | |
226 | ||
ac2ba9f3 | 227 | <<EOF>> { |
6297d423 JO |
228 | BEGIN(INITIAL); |
229 | REWIND(0); | |
ac2ba9f3 RR |
230 | } |
231 | ||
232 | } | |
233 | ||
e571e029 WN |
234 | <array>{ |
235 | "]" { BEGIN(config); return ']'; } | |
236 | {num_dec} { return value(yyscanner, 10); } | |
237 | {num_hex} { return value(yyscanner, 16); } | |
238 | , { return ','; } | |
239 | "\.\.\." { return PE_ARRAY_RANGE; } | |
240 | } | |
241 | ||
82004223 | 242 | <config>{ |
e64b020b | 243 | /* |
17cb5f84 | 244 | * Please update config_term_names when new static term is added. |
e64b020b | 245 | */ |
82004223 JO |
246 | config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); } |
247 | config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); } | |
248 | config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); } | |
249 | name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); } | |
250 | period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } | |
09af2a55 | 251 | freq { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ); } |
82004223 | 252 | branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } |
32067712 | 253 | time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); } |
d457c963 KL |
254 | call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); } |
255 | stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); } | |
792d48b4 | 256 | max-stack { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_STACK); } |
374ce938 WN |
257 | inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } |
258 | no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } | |
626a6b78 WN |
259 | overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); } |
260 | no-overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOOVERWRITE); } | |
82004223 JO |
261 | , { return ','; } |
262 | "/" { BEGIN(INITIAL); return '/'; } | |
263 | {name_minus} { return str(yyscanner, PE_NAME); } | |
e571e029 WN |
264 | \[all\] { return PE_ARRAY_ALL; } |
265 | "[" { BEGIN(array); return '['; } | |
dd60fba7 | 266 | @{drv_cfg_term} { return drv_str(yyscanner, PE_DRV_CFG_TERM); } |
82004223 JO |
267 | } |
268 | ||
269 | <mem>{ | |
270 | {modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); } | |
271 | : { return ':'; } | |
3741eb9f | 272 | "/" { return '/'; } |
82004223 JO |
273 | {num_dec} { return value(yyscanner, 10); } |
274 | {num_hex} { return value(yyscanner, 16); } | |
275 | /* | |
276 | * We need to separate 'mem:' scanner part, in order to get specific | |
277 | * modifier bits parsed out. Otherwise we would need to handle PE_NAME | |
278 | * and we'd need to parse it manually. During the escape from <mem> | |
279 | * state we need to put the escaping char back, so we dont miss it. | |
280 | */ | |
281 | . { unput(*yytext); BEGIN(INITIAL); } | |
282 | /* | |
283 | * We destroy the scanner after reaching EOF, | |
284 | * but anyway just to be sure get back to INIT state. | |
285 | */ | |
286 | <<EOF>> { BEGIN(INITIAL); } | |
287 | } | |
288 | ||
ac20de6f ZY |
289 | cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } |
290 | stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } | |
291 | stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } | |
292 | instructions { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); } | |
293 | cache-references { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); } | |
294 | cache-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); } | |
295 | branch-instructions|branches { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); } | |
296 | branch-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); } | |
297 | bus-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); } | |
298 | ref-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); } | |
299 | cpu-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); } | |
300 | task-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); } | |
301 | page-faults|faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); } | |
302 | minor-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); } | |
303 | major-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); } | |
304 | context-switches|cs { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); } | |
305 | cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); } | |
306 | alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } | |
307 | emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } | |
d22d1a2a | 308 | dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); } |
03e0a7df | 309 | bpf-output { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_BPF_OUTPUT); } |
89812fc8 | 310 | |
ba32a451 KL |
311 | /* |
312 | * We have to handle the kernel PMU event cycles-ct/cycles-t/mem-loads/mem-stores separately. | |
313 | * Because the prefix cycles is mixed up with cpu-cycles. | |
314 | * loads and stores are mixed up with cache event | |
315 | */ | |
316 | cycles-ct { return str(yyscanner, PE_KERNEL_PMU_EVENT); } | |
317 | cycles-t { return str(yyscanner, PE_KERNEL_PMU_EVENT); } | |
318 | mem-loads { return str(yyscanner, PE_KERNEL_PMU_EVENT); } | |
319 | mem-stores { return str(yyscanner, PE_KERNEL_PMU_EVENT); } | |
44b1e60a | 320 | topdown-[a-z-]+ { return str(yyscanner, PE_KERNEL_PMU_EVENT); } |
ba32a451 | 321 | |
89812fc8 JO |
322 | L1-dcache|l1-d|l1d|L1-data | |
323 | L1-icache|l1-i|l1i|L1-instruction | | |
324 | LLC|L2 | | |
325 | dTLB|d-tlb|Data-TLB | | |
326 | iTLB|i-tlb|Instruction-TLB | | |
327 | branch|branches|bpu|btb|bpc | | |
ac20de6f | 328 | node { return str(yyscanner, PE_NAME_CACHE_TYPE); } |
89812fc8 JO |
329 | |
330 | load|loads|read | | |
331 | store|stores|write | | |
332 | prefetch|prefetches | | |
333 | speculative-read|speculative-load | | |
334 | refs|Reference|ops|access | | |
ac20de6f | 335 | misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); } |
89812fc8 | 336 | |
08d2f762 | 337 | mem: { BEGIN(mem); return PE_PREFIX_MEM; } |
ac20de6f ZY |
338 | r{num_raw_hex} { return raw(yyscanner); } |
339 | {num_dec} { return value(yyscanner, 10); } | |
340 | {num_hex} { return value(yyscanner, 16); } | |
89812fc8 | 341 | |
ac20de6f | 342 | {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } |
a271bfaf JO |
343 | {bpf_object} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_OBJECT); } |
344 | {bpf_source} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_SOURCE); } | |
ba32a451 | 345 | {name} { return pmu_str_check(yyscanner); } |
ac2ba9f3 | 346 | "/" { BEGIN(config); return '/'; } |
89812fc8 | 347 | - { return '-'; } |
ac2ba9f3 | 348 | , { BEGIN(event); return ','; } |
89812fc8 | 349 | : { return ':'; } |
ac2ba9f3 | 350 | "{" { BEGIN(event); return '{'; } |
89efb029 | 351 | "}" { return '}'; } |
89812fc8 | 352 | = { return '='; } |
8c5f0a84 | 353 | \n { } |
82004223 | 354 | . { } |
08d2f762 | 355 | |
89812fc8 JO |
356 | %% |
357 | ||
1d037ca1 | 358 | int parse_events_wrap(void *scanner __maybe_unused) |
89812fc8 JO |
359 | { |
360 | return 1; | |
361 | } |