diff options
author | Tejun Heo <tj@kernel.org> | 2009-08-14 01:41:02 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2009-08-14 01:45:31 -0400 |
commit | 384be2b18a5f9475eab9ca2bdfa95cc1a04ef59c (patch) | |
tree | 04c93f391a1b65c8bf8d7ba8643c07d26c26590a /tools/perf/util/parse-events.c | |
parent | a76761b621bcd8336065c4fe3a74f046858bc34c (diff) | |
parent | 142d44b0dd6741a64a7bdbe029110e7c1dcf1d23 (diff) |
Merge branch 'percpu-for-linus' into percpu-for-next
Conflicts:
arch/sparc/kernel/smp_64.c
arch/x86/kernel/cpu/perf_counter.c
arch/x86/kernel/setup_percpu.c
drivers/cpufreq/cpufreq_ondemand.c
mm/percpu.c
Conflicts in core and arch percpu codes are mostly from commit
ed78e1e078dd44249f88b1dd8c76dafb39567161 which substituted many
num_possible_cpus() with nr_cpu_ids. As for-next branch has moved all
the first chunk allocators into mm/percpu.c, the changes are moved
from arch code to mm/percpu.c.
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r-- | tools/perf/util/parse-events.c | 465 |
1 files changed, 387 insertions, 78 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4d042f104cdc..044178408783 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include "parse-events.h" | 5 | #include "parse-events.h" |
6 | #include "exec_cmd.h" | 6 | #include "exec_cmd.h" |
7 | #include "string.h" | 7 | #include "string.h" |
8 | #include "cache.h" | ||
8 | 9 | ||
9 | extern char *strcasestr(const char *haystack, const char *needle); | 10 | extern char *strcasestr(const char *haystack, const char *needle); |
10 | 11 | ||
@@ -19,6 +20,8 @@ struct event_symbol { | |||
19 | char *alias; | 20 | char *alias; |
20 | }; | 21 | }; |
21 | 22 | ||
23 | char debugfs_path[MAXPATHLEN]; | ||
24 | |||
22 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x | 25 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x |
23 | #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x | 26 | #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x |
24 | 27 | ||
@@ -71,8 +74,8 @@ static char *sw_event_names[] = { | |||
71 | #define MAX_ALIASES 8 | 74 | #define MAX_ALIASES 8 |
72 | 75 | ||
73 | static char *hw_cache[][MAX_ALIASES] = { | 76 | static char *hw_cache[][MAX_ALIASES] = { |
74 | { "L1-d$", "l1-d", "l1d", "L1-data", }, | 77 | { "L1-dcache", "l1-d", "l1d", "L1-data", }, |
75 | { "L1-i$", "l1-i", "l1i", "L1-instruction", }, | 78 | { "L1-icache", "l1-i", "l1i", "L1-instruction", }, |
76 | { "LLC", "L2" }, | 79 | { "LLC", "L2" }, |
77 | { "dTLB", "d-tlb", "Data-TLB", }, | 80 | { "dTLB", "d-tlb", "Data-TLB", }, |
78 | { "iTLB", "i-tlb", "Instruction-TLB", }, | 81 | { "iTLB", "i-tlb", "Instruction-TLB", }, |
@@ -110,6 +113,104 @@ static unsigned long hw_cache_stat[C(MAX)] = { | |||
110 | [C(BPU)] = (CACHE_READ), | 113 | [C(BPU)] = (CACHE_READ), |
111 | }; | 114 | }; |
112 | 115 | ||
116 | #define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \ | ||
117 | while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ | ||
118 | if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path, \ | ||
119 | sys_dirent.d_name) && \ | ||
120 | (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ | ||
121 | (strcmp(sys_dirent.d_name, ".")) && \ | ||
122 | (strcmp(sys_dirent.d_name, ".."))) | ||
123 | |||
124 | static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) | ||
125 | { | ||
126 | char evt_path[MAXPATHLEN]; | ||
127 | int fd; | ||
128 | |||
129 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, | ||
130 | sys_dir->d_name, evt_dir->d_name); | ||
131 | fd = open(evt_path, O_RDONLY); | ||
132 | if (fd < 0) | ||
133 | return -EINVAL; | ||
134 | close(fd); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \ | ||
140 | while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ | ||
141 | if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \ | ||
142 | sys_dirent.d_name, evt_dirent.d_name) && \ | ||
143 | (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ | ||
144 | (strcmp(evt_dirent.d_name, ".")) && \ | ||
145 | (strcmp(evt_dirent.d_name, "..")) && \ | ||
146 | (!tp_event_has_id(&sys_dirent, &evt_dirent))) | ||
147 | |||
148 | #define MAX_EVENT_LENGTH 30 | ||
149 | |||
150 | int valid_debugfs_mount(const char *debugfs) | ||
151 | { | ||
152 | struct statfs st_fs; | ||
153 | |||
154 | if (statfs(debugfs, &st_fs) < 0) | ||
155 | return -ENOENT; | ||
156 | else if (st_fs.f_type != (long) DEBUGFS_MAGIC) | ||
157 | return -ENOENT; | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static char *tracepoint_id_to_name(u64 config) | ||
162 | { | ||
163 | static char tracepoint_name[2 * MAX_EVENT_LENGTH]; | ||
164 | DIR *sys_dir, *evt_dir; | ||
165 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | ||
166 | struct stat st; | ||
167 | char id_buf[4]; | ||
168 | int fd; | ||
169 | u64 id; | ||
170 | char evt_path[MAXPATHLEN]; | ||
171 | |||
172 | if (valid_debugfs_mount(debugfs_path)) | ||
173 | return "unkown"; | ||
174 | |||
175 | sys_dir = opendir(debugfs_path); | ||
176 | if (!sys_dir) | ||
177 | goto cleanup; | ||
178 | |||
179 | for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { | ||
180 | evt_dir = opendir(evt_path); | ||
181 | if (!evt_dir) | ||
182 | goto cleanup; | ||
183 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, | ||
184 | evt_path, st) { | ||
185 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", | ||
186 | debugfs_path, sys_dirent.d_name, | ||
187 | evt_dirent.d_name); | ||
188 | fd = open(evt_path, O_RDONLY); | ||
189 | if (fd < 0) | ||
190 | continue; | ||
191 | if (read(fd, id_buf, sizeof(id_buf)) < 0) { | ||
192 | close(fd); | ||
193 | continue; | ||
194 | } | ||
195 | close(fd); | ||
196 | id = atoll(id_buf); | ||
197 | if (id == config) { | ||
198 | closedir(evt_dir); | ||
199 | closedir(sys_dir); | ||
200 | snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH, | ||
201 | "%s:%s", sys_dirent.d_name, | ||
202 | evt_dirent.d_name); | ||
203 | return tracepoint_name; | ||
204 | } | ||
205 | } | ||
206 | closedir(evt_dir); | ||
207 | } | ||
208 | |||
209 | cleanup: | ||
210 | closedir(sys_dir); | ||
211 | return "unkown"; | ||
212 | } | ||
213 | |||
113 | static int is_cache_op_valid(u8 cache_type, u8 cache_op) | 214 | static int is_cache_op_valid(u8 cache_type, u8 cache_op) |
114 | { | 215 | { |
115 | if (hw_cache_stat[cache_type] & COP(cache_op)) | 216 | if (hw_cache_stat[cache_type] & COP(cache_op)) |
@@ -138,9 +239,15 @@ char *event_name(int counter) | |||
138 | { | 239 | { |
139 | u64 config = attrs[counter].config; | 240 | u64 config = attrs[counter].config; |
140 | int type = attrs[counter].type; | 241 | int type = attrs[counter].type; |
242 | |||
243 | return __event_name(type, config); | ||
244 | } | ||
245 | |||
246 | char *__event_name(int type, u64 config) | ||
247 | { | ||
141 | static char buf[32]; | 248 | static char buf[32]; |
142 | 249 | ||
143 | if (attrs[counter].type == PERF_TYPE_RAW) { | 250 | if (type == PERF_TYPE_RAW) { |
144 | sprintf(buf, "raw 0x%llx", config); | 251 | sprintf(buf, "raw 0x%llx", config); |
145 | return buf; | 252 | return buf; |
146 | } | 253 | } |
@@ -177,6 +284,9 @@ char *event_name(int counter) | |||
177 | return sw_event_names[config]; | 284 | return sw_event_names[config]; |
178 | return "unknown-software"; | 285 | return "unknown-software"; |
179 | 286 | ||
287 | case PERF_TYPE_TRACEPOINT: | ||
288 | return tracepoint_id_to_name(config); | ||
289 | |||
180 | default: | 290 | default: |
181 | break; | 291 | break; |
182 | } | 292 | } |
@@ -184,16 +294,20 @@ char *event_name(int counter) | |||
184 | return "unknown"; | 294 | return "unknown"; |
185 | } | 295 | } |
186 | 296 | ||
187 | static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) | 297 | static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size) |
188 | { | 298 | { |
189 | int i, j; | 299 | int i, j; |
300 | int n, longest = -1; | ||
190 | 301 | ||
191 | for (i = 0; i < size; i++) { | 302 | for (i = 0; i < size; i++) { |
192 | for (j = 0; j < MAX_ALIASES; j++) { | 303 | for (j = 0; j < MAX_ALIASES && names[i][j]; j++) { |
193 | if (!names[i][j]) | 304 | n = strlen(names[i][j]); |
194 | break; | 305 | if (n > longest && !strncasecmp(*str, names[i][j], n)) |
195 | if (strcasestr(str, names[i][j])) | 306 | longest = n; |
196 | return i; | 307 | } |
308 | if (longest > 0) { | ||
309 | *str += longest; | ||
310 | return i; | ||
197 | } | 311 | } |
198 | } | 312 | } |
199 | 313 | ||
@@ -201,30 +315,53 @@ static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) | |||
201 | } | 315 | } |
202 | 316 | ||
203 | static int | 317 | static int |
204 | parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) | 318 | parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) |
205 | { | 319 | { |
206 | int cache_type = -1, cache_op = 0, cache_result = 0; | 320 | const char *s = *str; |
321 | int cache_type = -1, cache_op = -1, cache_result = -1; | ||
207 | 322 | ||
208 | cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX); | 323 | cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX); |
209 | /* | 324 | /* |
210 | * No fallback - if we cannot get a clear cache type | 325 | * No fallback - if we cannot get a clear cache type |
211 | * then bail out: | 326 | * then bail out: |
212 | */ | 327 | */ |
213 | if (cache_type == -1) | 328 | if (cache_type == -1) |
214 | return -EINVAL; | 329 | return 0; |
330 | |||
331 | while ((cache_op == -1 || cache_result == -1) && *s == '-') { | ||
332 | ++s; | ||
333 | |||
334 | if (cache_op == -1) { | ||
335 | cache_op = parse_aliases(&s, hw_cache_op, | ||
336 | PERF_COUNT_HW_CACHE_OP_MAX); | ||
337 | if (cache_op >= 0) { | ||
338 | if (!is_cache_op_valid(cache_type, cache_op)) | ||
339 | return 0; | ||
340 | continue; | ||
341 | } | ||
342 | } | ||
343 | |||
344 | if (cache_result == -1) { | ||
345 | cache_result = parse_aliases(&s, hw_cache_result, | ||
346 | PERF_COUNT_HW_CACHE_RESULT_MAX); | ||
347 | if (cache_result >= 0) | ||
348 | continue; | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * Can't parse this as a cache op or result, so back up | ||
353 | * to the '-'. | ||
354 | */ | ||
355 | --s; | ||
356 | break; | ||
357 | } | ||
215 | 358 | ||
216 | cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX); | ||
217 | /* | 359 | /* |
218 | * Fall back to reads: | 360 | * Fall back to reads: |
219 | */ | 361 | */ |
220 | if (cache_op == -1) | 362 | if (cache_op == -1) |
221 | cache_op = PERF_COUNT_HW_CACHE_OP_READ; | 363 | cache_op = PERF_COUNT_HW_CACHE_OP_READ; |
222 | 364 | ||
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 | /* | 365 | /* |
229 | * Fall back to accesses: | 366 | * Fall back to accesses: |
230 | */ | 367 | */ |
@@ -234,93 +371,212 @@ parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) | |||
234 | attr->config = cache_type | (cache_op << 8) | (cache_result << 16); | 371 | attr->config = cache_type | (cache_op << 8) | (cache_result << 16); |
235 | attr->type = PERF_TYPE_HW_CACHE; | 372 | attr->type = PERF_TYPE_HW_CACHE; |
236 | 373 | ||
237 | return 0; | 374 | *str = s; |
375 | return 1; | ||
376 | } | ||
377 | |||
378 | static int parse_tracepoint_event(const char **strp, | ||
379 | struct perf_counter_attr *attr) | ||
380 | { | ||
381 | const char *evt_name; | ||
382 | char *flags; | ||
383 | char sys_name[MAX_EVENT_LENGTH]; | ||
384 | char id_buf[4]; | ||
385 | int fd; | ||
386 | unsigned int sys_length, evt_length; | ||
387 | u64 id; | ||
388 | char evt_path[MAXPATHLEN]; | ||
389 | |||
390 | if (valid_debugfs_mount(debugfs_path)) | ||
391 | return 0; | ||
392 | |||
393 | evt_name = strchr(*strp, ':'); | ||
394 | if (!evt_name) | ||
395 | return 0; | ||
396 | |||
397 | sys_length = evt_name - *strp; | ||
398 | if (sys_length >= MAX_EVENT_LENGTH) | ||
399 | return 0; | ||
400 | |||
401 | strncpy(sys_name, *strp, sys_length); | ||
402 | sys_name[sys_length] = '\0'; | ||
403 | evt_name = evt_name + 1; | ||
404 | |||
405 | flags = strchr(evt_name, ':'); | ||
406 | if (flags) { | ||
407 | *flags = '\0'; | ||
408 | flags++; | ||
409 | if (!strncmp(flags, "record", strlen(flags))) | ||
410 | attr->sample_type |= PERF_SAMPLE_RAW; | ||
411 | } | ||
412 | |||
413 | evt_length = strlen(evt_name); | ||
414 | if (evt_length >= MAX_EVENT_LENGTH) | ||
415 | return 0; | ||
416 | |||
417 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, | ||
418 | sys_name, evt_name); | ||
419 | fd = open(evt_path, O_RDONLY); | ||
420 | if (fd < 0) | ||
421 | return 0; | ||
422 | |||
423 | if (read(fd, id_buf, sizeof(id_buf)) < 0) { | ||
424 | close(fd); | ||
425 | return 0; | ||
426 | } | ||
427 | close(fd); | ||
428 | id = atoll(id_buf); | ||
429 | attr->config = id; | ||
430 | attr->type = PERF_TYPE_TRACEPOINT; | ||
431 | *strp = evt_name + evt_length; | ||
432 | return 1; | ||
238 | } | 433 | } |
239 | 434 | ||
240 | static int check_events(const char *str, unsigned int i) | 435 | static int check_events(const char *str, unsigned int i) |
241 | { | 436 | { |
242 | if (!strncmp(str, event_symbols[i].symbol, | 437 | int n; |
243 | strlen(event_symbols[i].symbol))) | ||
244 | return 1; | ||
245 | 438 | ||
246 | if (strlen(event_symbols[i].alias)) | 439 | n = strlen(event_symbols[i].symbol); |
247 | if (!strncmp(str, event_symbols[i].alias, | 440 | if (!strncmp(str, event_symbols[i].symbol, n)) |
248 | strlen(event_symbols[i].alias))) | 441 | return n; |
249 | return 1; | 442 | |
443 | n = strlen(event_symbols[i].alias); | ||
444 | if (n) | ||
445 | if (!strncmp(str, event_symbols[i].alias, n)) | ||
446 | return n; | ||
250 | return 0; | 447 | return 0; |
251 | } | 448 | } |
252 | 449 | ||
253 | /* | 450 | static int |
254 | * Each event can have multiple symbolic names. | 451 | parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) |
255 | * Symbolic names are (almost) exactly matched. | ||
256 | */ | ||
257 | static int parse_event_symbols(const char *str, struct perf_counter_attr *attr) | ||
258 | { | 452 | { |
259 | u64 config, id; | 453 | const char *str = *strp; |
260 | int type; | ||
261 | unsigned int i; | 454 | unsigned int i; |
262 | const char *sep, *pstr; | 455 | int n; |
263 | 456 | ||
264 | if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) { | 457 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { |
265 | attr->type = PERF_TYPE_RAW; | 458 | n = check_events(str, i); |
266 | attr->config = config; | 459 | if (n > 0) { |
460 | attr->type = event_symbols[i].type; | ||
461 | attr->config = event_symbols[i].config; | ||
462 | *strp = str + n; | ||
463 | return 1; | ||
464 | } | ||
465 | } | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static int parse_raw_event(const char **strp, struct perf_counter_attr *attr) | ||
470 | { | ||
471 | const char *str = *strp; | ||
472 | u64 config; | ||
473 | int n; | ||
267 | 474 | ||
475 | if (*str != 'r') | ||
268 | return 0; | 476 | return 0; |
477 | n = hex2u64(str + 1, &config); | ||
478 | if (n > 0) { | ||
479 | *strp = str + n + 1; | ||
480 | attr->type = PERF_TYPE_RAW; | ||
481 | attr->config = config; | ||
482 | return 1; | ||
269 | } | 483 | } |
484 | return 0; | ||
485 | } | ||
270 | 486 | ||
271 | pstr = str; | 487 | static int |
272 | sep = strchr(pstr, ':'); | 488 | parse_numeric_event(const char **strp, struct perf_counter_attr *attr) |
273 | if (sep) { | 489 | { |
274 | type = atoi(pstr); | 490 | const char *str = *strp; |
275 | pstr = sep + 1; | 491 | char *endp; |
276 | id = atoi(pstr); | 492 | unsigned long type; |
277 | sep = strchr(pstr, ':'); | 493 | u64 config; |
278 | if (sep) { | 494 | |
279 | pstr = sep + 1; | 495 | type = strtoul(str, &endp, 0); |
280 | if (strchr(pstr, 'k')) | 496 | if (endp > str && type < PERF_TYPE_MAX && *endp == ':') { |
281 | attr->exclude_user = 1; | 497 | str = endp + 1; |
282 | if (strchr(pstr, 'u')) | 498 | config = strtoul(str, &endp, 0); |
283 | attr->exclude_kernel = 1; | 499 | if (endp > str) { |
500 | attr->type = type; | ||
501 | attr->config = config; | ||
502 | *strp = endp; | ||
503 | return 1; | ||
284 | } | 504 | } |
285 | attr->type = type; | 505 | } |
286 | attr->config = id; | 506 | return 0; |
507 | } | ||
287 | 508 | ||
509 | static int | ||
510 | parse_event_modifier(const char **strp, struct perf_counter_attr *attr) | ||
511 | { | ||
512 | const char *str = *strp; | ||
513 | int eu = 1, ek = 1, eh = 1; | ||
514 | |||
515 | if (*str++ != ':') | ||
288 | return 0; | 516 | return 0; |
517 | while (*str) { | ||
518 | if (*str == 'u') | ||
519 | eu = 0; | ||
520 | else if (*str == 'k') | ||
521 | ek = 0; | ||
522 | else if (*str == 'h') | ||
523 | eh = 0; | ||
524 | else | ||
525 | break; | ||
526 | ++str; | ||
289 | } | 527 | } |
528 | if (str >= *strp + 2) { | ||
529 | *strp = str; | ||
530 | attr->exclude_user = eu; | ||
531 | attr->exclude_kernel = ek; | ||
532 | attr->exclude_hv = eh; | ||
533 | return 1; | ||
534 | } | ||
535 | return 0; | ||
536 | } | ||
290 | 537 | ||
291 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { | 538 | /* |
292 | if (check_events(str, i)) { | 539 | * Each event can have multiple symbolic names. |
293 | attr->type = event_symbols[i].type; | 540 | * Symbolic names are (almost) exactly matched. |
294 | attr->config = event_symbols[i].config; | 541 | */ |
542 | static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) | ||
543 | { | ||
544 | if (!(parse_tracepoint_event(str, attr) || | ||
545 | parse_raw_event(str, attr) || | ||
546 | parse_numeric_event(str, attr) || | ||
547 | parse_symbolic_event(str, attr) || | ||
548 | parse_generic_hw_event(str, attr))) | ||
549 | return 0; | ||
295 | 550 | ||
296 | return 0; | 551 | parse_event_modifier(str, attr); |
297 | } | ||
298 | } | ||
299 | 552 | ||
300 | return parse_generic_hw_symbols(str, attr); | 553 | return 1; |
301 | } | 554 | } |
302 | 555 | ||
303 | int parse_events(const struct option *opt, const char *str, int unset) | 556 | int parse_events(const struct option *opt __used, const char *str, int unset __used) |
304 | { | 557 | { |
305 | struct perf_counter_attr attr; | 558 | struct perf_counter_attr attr; |
306 | int ret; | ||
307 | 559 | ||
308 | memset(&attr, 0, sizeof(attr)); | 560 | for (;;) { |
309 | again: | 561 | if (nr_counters == MAX_COUNTERS) |
310 | if (nr_counters == MAX_COUNTERS) | 562 | return -1; |
311 | return -1; | ||
312 | 563 | ||
313 | ret = parse_event_symbols(str, &attr); | 564 | memset(&attr, 0, sizeof(attr)); |
314 | if (ret < 0) | 565 | if (!parse_event_symbols(&str, &attr)) |
315 | return ret; | 566 | return -1; |
316 | 567 | ||
317 | attrs[nr_counters] = attr; | 568 | if (!(*str == 0 || *str == ',' || isspace(*str))) |
318 | nr_counters++; | 569 | return -1; |
319 | 570 | ||
320 | str = strstr(str, ","); | 571 | attrs[nr_counters] = attr; |
321 | if (str) { | 572 | nr_counters++; |
322 | str++; | 573 | |
323 | goto again; | 574 | if (*str == 0) |
575 | break; | ||
576 | if (*str == ',') | ||
577 | ++str; | ||
578 | while (isspace(*str)) | ||
579 | ++str; | ||
324 | } | 580 | } |
325 | 581 | ||
326 | return 0; | 582 | return 0; |
@@ -335,12 +591,48 @@ static const char * const event_type_descriptors[] = { | |||
335 | }; | 591 | }; |
336 | 592 | ||
337 | /* | 593 | /* |
594 | * Print the events from <debugfs_mount_point>/tracing/events | ||
595 | */ | ||
596 | |||
597 | static void print_tracepoint_events(void) | ||
598 | { | ||
599 | DIR *sys_dir, *evt_dir; | ||
600 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | ||
601 | struct stat st; | ||
602 | char evt_path[MAXPATHLEN]; | ||
603 | |||
604 | if (valid_debugfs_mount(debugfs_path)) | ||
605 | return; | ||
606 | |||
607 | sys_dir = opendir(debugfs_path); | ||
608 | if (!sys_dir) | ||
609 | goto cleanup; | ||
610 | |||
611 | for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { | ||
612 | evt_dir = opendir(evt_path); | ||
613 | if (!evt_dir) | ||
614 | goto cleanup; | ||
615 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, | ||
616 | evt_path, st) { | ||
617 | snprintf(evt_path, MAXPATHLEN, "%s:%s", | ||
618 | sys_dirent.d_name, evt_dirent.d_name); | ||
619 | fprintf(stderr, " %-40s [%s]\n", evt_path, | ||
620 | event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); | ||
621 | } | ||
622 | closedir(evt_dir); | ||
623 | } | ||
624 | |||
625 | cleanup: | ||
626 | closedir(sys_dir); | ||
627 | } | ||
628 | |||
629 | /* | ||
338 | * Print the help text for the event symbols: | 630 | * Print the help text for the event symbols: |
339 | */ | 631 | */ |
340 | void print_events(void) | 632 | void print_events(void) |
341 | { | 633 | { |
342 | struct event_symbol *syms = event_symbols; | 634 | struct event_symbol *syms = event_symbols; |
343 | unsigned int i, type, prev_type = -1; | 635 | unsigned int i, type, op, prev_type = -1; |
344 | char name[40]; | 636 | char name[40]; |
345 | 637 | ||
346 | fprintf(stderr, "\n"); | 638 | fprintf(stderr, "\n"); |
@@ -348,7 +640,7 @@ void print_events(void) | |||
348 | 640 | ||
349 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { | 641 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { |
350 | type = syms->type + 1; | 642 | type = syms->type + 1; |
351 | if (type > ARRAY_SIZE(event_type_descriptors)) | 643 | if (type >= ARRAY_SIZE(event_type_descriptors)) |
352 | type = 0; | 644 | type = 0; |
353 | 645 | ||
354 | if (type != prev_type) | 646 | if (type != prev_type) |
@@ -365,9 +657,26 @@ void print_events(void) | |||
365 | } | 657 | } |
366 | 658 | ||
367 | fprintf(stderr, "\n"); | 659 | fprintf(stderr, "\n"); |
660 | for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { | ||
661 | for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { | ||
662 | /* skip invalid cache type */ | ||
663 | if (!is_cache_op_valid(type, op)) | ||
664 | continue; | ||
665 | |||
666 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { | ||
667 | fprintf(stderr, " %-40s [%s]\n", | ||
668 | event_cache_name(type, op, i), | ||
669 | event_type_descriptors[4]); | ||
670 | } | ||
671 | } | ||
672 | } | ||
673 | |||
674 | fprintf(stderr, "\n"); | ||
368 | fprintf(stderr, " %-40s [raw hardware event descriptor]\n", | 675 | fprintf(stderr, " %-40s [raw hardware event descriptor]\n", |
369 | "rNNN"); | 676 | "rNNN"); |
370 | fprintf(stderr, "\n"); | 677 | fprintf(stderr, "\n"); |
371 | 678 | ||
679 | print_tracepoint_events(); | ||
680 | |||
372 | exit(129); | 681 | exit(129); |
373 | } | 682 | } |