aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2009-06-30 23:04:34 -0400
committerIngo Molnar <mingo@elte.hu>2009-07-01 04:23:17 -0400
commit61c45981ddbd718136d49464f00d2f11938aaa6e (patch)
treee8a89bd386ce1bbe5160d554c778894d76015f20
parent0a456fc58fb8ef3c53d18297ab5cd5d2a70d146b (diff)
perf_counter tools: Rework event string parsing/syntax
This reworks the parser for event descriptors to make it more consistent in what it accepts. It is now structured as a recursive descent parser for the following grammar: events ::= event ( ("," | space) space* event )* event ::= ( raw_event | numeric_event | symbolic_event | generic_hw_event ) [ event_modifier ] raw_event ::= "r" hex_number numeric_event ::= number ":" number number ::= decimal_number | "0x" hex_number | "0" octal_number symbolic_event ::= string_from_event_symbols_array generic_hw_event::= cache_type ( "-" ( cache_op | cache_result ) )* event_modifier ::= ":" ( "u" | "k" | "h" )+ with the extra restriction that you can have at most one cache_op and at most one cache_result. We pass the current string pointer by reference (i.e. as a const char **) to the various parsing functions so that they can advance the pointer to indicate how much they consumed. They return 0 if they didn't recognize the thing at the pointer or 1 if they did (and advance the pointer past it). This also fixes parse_aliases to take the longest matching alias from the table, not the first one. Otherwise "l1-data" would match the "l1-d" alias and the "ata" would not be consumed. This allows event modifiers indicating what processor modes to count in to be applied to any event, not just numeric events, and adds a ":h" modifier to indicate counting in hypervisor mode. Specifying ":u" now sets both exclude_kernel and exclude_hv, and so on. Multiple modes can be specified, e.g. ":uk" will count in user or hypervisor mode (i.e. only exclude_kernel will be set). Signed-off-by: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <19018.53826.843815.189847@cargo.ozlabs.ibm.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--tools/perf/util/parse-events.c232
1 files changed, 160 insertions, 72 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 4d042f104cdc..e6b83a3311a5 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -184,16 +184,20 @@ char *event_name(int counter)
184 return "unknown"; 184 return "unknown";
185} 185}
186 186
187static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) 187static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size)
188{ 188{
189 int i, j; 189 int i, j;
190 int n, longest = -1;
190 191
191 for (i = 0; i < size; i++) { 192 for (i = 0; i < size; i++) {
192 for (j = 0; j < MAX_ALIASES; j++) { 193 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
193 if (!names[i][j]) 194 n = strlen(names[i][j]);
194 break; 195 if (n > longest && !strncasecmp(*str, names[i][j], n))
195 if (strcasestr(str, names[i][j])) 196 longest = n;
196 return i; 197 }
198 if (longest > 0) {
199 *str += longest;
200 return i;
197 } 201 }
198 } 202 }
199 203
@@ -201,30 +205,53 @@ static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size)
201} 205}
202 206
203static int 207static int
204parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) 208parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
205{ 209{
206 int cache_type = -1, cache_op = 0, cache_result = 0; 210 const char *s = *str;
211 int cache_type = -1, cache_op = -1, cache_result = -1;
207 212
208 cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX); 213 cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
209 /* 214 /*
210 * No fallback - if we cannot get a clear cache type 215 * No fallback - if we cannot get a clear cache type
211 * then bail out: 216 * then bail out:
212 */ 217 */
213 if (cache_type == -1) 218 if (cache_type == -1)
214 return -EINVAL; 219 return 0;
220
221 while ((cache_op == -1 || cache_result == -1) && *s == '-') {
222 ++s;
223
224 if (cache_op == -1) {
225 cache_op = parse_aliases(&s, hw_cache_op,
226 PERF_COUNT_HW_CACHE_OP_MAX);
227 if (cache_op >= 0) {
228 if (!is_cache_op_valid(cache_type, cache_op))
229 return 0;
230 continue;
231 }
232 }
233
234 if (cache_result == -1) {
235 cache_result = parse_aliases(&s, hw_cache_result,
236 PERF_COUNT_HW_CACHE_RESULT_MAX);
237 if (cache_result >= 0)
238 continue;
239 }
240
241 /*
242 * Can't parse this as a cache op or result, so back up
243 * to the '-'.
244 */
245 --s;
246 break;
247 }
215 248
216 cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
217 /* 249 /*
218 * Fall back to reads: 250 * Fall back to reads:
219 */ 251 */
220 if (cache_op == -1) 252 if (cache_op == -1)
221 cache_op = PERF_COUNT_HW_CACHE_OP_READ; 253 cache_op = PERF_COUNT_HW_CACHE_OP_READ;
222 254
223 if (!is_cache_op_valid(cache_type, cache_op))
224 return -EINVAL;
225
226 cache_result = parse_aliases(str, hw_cache_result,
227 PERF_COUNT_HW_CACHE_RESULT_MAX);
228 /* 255 /*
229 * Fall back to accesses: 256 * Fall back to accesses:
230 */ 257 */
@@ -234,93 +261,154 @@ parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
234 attr->config = cache_type | (cache_op << 8) | (cache_result << 16); 261 attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
235 attr->type = PERF_TYPE_HW_CACHE; 262 attr->type = PERF_TYPE_HW_CACHE;
236 263
237 return 0; 264 *str = s;
265 return 1;
238} 266}
239 267
240static int check_events(const char *str, unsigned int i) 268static int check_events(const char *str, unsigned int i)
241{ 269{
242 if (!strncmp(str, event_symbols[i].symbol, 270 int n;
243 strlen(event_symbols[i].symbol)))
244 return 1;
245 271
246 if (strlen(event_symbols[i].alias)) 272 n = strlen(event_symbols[i].symbol);
247 if (!strncmp(str, event_symbols[i].alias, 273 if (!strncmp(str, event_symbols[i].symbol, n))
248 strlen(event_symbols[i].alias))) 274 return n;
249 return 1; 275
276 n = strlen(event_symbols[i].alias);
277 if (n)
278 if (!strncmp(str, event_symbols[i].alias, n))
279 return n;
250 return 0; 280 return 0;
251} 281}
252 282
253/* 283static int
254 * Each event can have multiple symbolic names. 284parse_symbolic_event(const char **strp, struct perf_counter_attr *attr)
255 * Symbolic names are (almost) exactly matched.
256 */
257static int parse_event_symbols(const char *str, struct perf_counter_attr *attr)
258{ 285{
259 u64 config, id; 286 const char *str = *strp;
260 int type;
261 unsigned int i; 287 unsigned int i;
262 const char *sep, *pstr; 288 int n;
263 289
264 if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) { 290 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
265 attr->type = PERF_TYPE_RAW; 291 n = check_events(str, i);
266 attr->config = config; 292 if (n > 0) {
293 attr->type = event_symbols[i].type;
294 attr->config = event_symbols[i].config;
295 *strp = str + n;
296 return 1;
297 }
298 }
299 return 0;
300}
301
302static int parse_raw_event(const char **strp, struct perf_counter_attr *attr)
303{
304 const char *str = *strp;
305 u64 config;
306 int n;
267 307
308 if (*str != 'r')
268 return 0; 309 return 0;
310 n = hex2u64(str + 1, &config);
311 if (n > 0) {
312 *strp = str + n + 1;
313 attr->type = PERF_TYPE_RAW;
314 attr->config = config;
315 return 1;
269 } 316 }
317 return 0;
318}
270 319
271 pstr = str; 320static int
272 sep = strchr(pstr, ':'); 321parse_numeric_event(const char **strp, struct perf_counter_attr *attr)
273 if (sep) { 322{
274 type = atoi(pstr); 323 const char *str = *strp;
275 pstr = sep + 1; 324 char *endp;
276 id = atoi(pstr); 325 unsigned long type;
277 sep = strchr(pstr, ':'); 326 u64 config;
278 if (sep) { 327
279 pstr = sep + 1; 328 type = strtoul(str, &endp, 0);
280 if (strchr(pstr, 'k')) 329 if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
281 attr->exclude_user = 1; 330 str = endp + 1;
282 if (strchr(pstr, 'u')) 331 config = strtoul(str, &endp, 0);
283 attr->exclude_kernel = 1; 332 if (endp > str) {
333 attr->type = type;
334 attr->config = config;
335 *strp = endp;
336 return 1;
284 } 337 }
285 attr->type = type; 338 }
286 attr->config = id; 339 return 0;
340}
341
342static int
343parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
344{
345 const char *str = *strp;
346 int eu = 1, ek = 1, eh = 1;
287 347
348 if (*str++ != ':')
288 return 0; 349 return 0;
350 while (*str) {
351 if (*str == 'u')
352 eu = 0;
353 else if (*str == 'k')
354 ek = 0;
355 else if (*str == 'h')
356 eh = 0;
357 else
358 break;
359 ++str;
289 } 360 }
361 if (str >= *strp + 2) {
362 *strp = str;
363 attr->exclude_user = eu;
364 attr->exclude_kernel = ek;
365 attr->exclude_hv = eh;
366 return 1;
367 }
368 return 0;
369}
290 370
291 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { 371/*
292 if (check_events(str, i)) { 372 * Each event can have multiple symbolic names.
293 attr->type = event_symbols[i].type; 373 * Symbolic names are (almost) exactly matched.
294 attr->config = event_symbols[i].config; 374 */
375static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
376{
377 if (!(parse_raw_event(str, attr) ||
378 parse_numeric_event(str, attr) ||
379 parse_symbolic_event(str, attr) ||
380 parse_generic_hw_event(str, attr)))
381 return 0;
295 382
296 return 0; 383 parse_event_modifier(str, attr);
297 }
298 }
299 384
300 return parse_generic_hw_symbols(str, attr); 385 return 1;
301} 386}
302 387
303int parse_events(const struct option *opt, const char *str, int unset) 388int parse_events(const struct option *opt, const char *str, int unset)
304{ 389{
305 struct perf_counter_attr attr; 390 struct perf_counter_attr attr;
306 int ret;
307 391
308 memset(&attr, 0, sizeof(attr)); 392 for (;;) {
309again: 393 if (nr_counters == MAX_COUNTERS)
310 if (nr_counters == MAX_COUNTERS) 394 return -1;
311 return -1; 395
396 memset(&attr, 0, sizeof(attr));
397 if (!parse_event_symbols(&str, &attr))
398 return -1;
312 399
313 ret = parse_event_symbols(str, &attr); 400 if (!(*str == 0 || *str == ',' || isspace(*str)))
314 if (ret < 0) 401 return -1;
315 return ret;
316 402
317 attrs[nr_counters] = attr; 403 attrs[nr_counters] = attr;
318 nr_counters++; 404 nr_counters++;
319 405
320 str = strstr(str, ","); 406 if (*str == 0)
321 if (str) { 407 break;
322 str++; 408 if (*str == ',')
323 goto again; 409 ++str;
410 while (isspace(*str))
411 ++str;
324 } 412 }
325 413
326 return 0; 414 return 0;