diff options
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r-- | tools/perf/util/probe-event.c | 133 |
1 files changed, 118 insertions, 15 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index cd7fbda5e2a5..d14a4585bcaf 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -48,6 +48,9 @@ | |||
48 | 48 | ||
49 | /* If there is no space to write, returns -E2BIG. */ | 49 | /* If there is no space to write, returns -E2BIG. */ |
50 | static int e_snprintf(char *str, size_t size, const char *format, ...) | 50 | static int e_snprintf(char *str, size_t size, const char *format, ...) |
51 | __attribute__((format(printf, 3, 4))); | ||
52 | |||
53 | static int e_snprintf(char *str, size_t size, const char *format, ...) | ||
51 | { | 54 | { |
52 | int ret; | 55 | int ret; |
53 | va_list ap; | 56 | va_list ap; |
@@ -258,7 +261,7 @@ int synthesize_perf_probe_event(struct probe_point *pp) | |||
258 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, | 261 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, |
259 | offs, pp->retprobe ? "%return" : "", line); | 262 | offs, pp->retprobe ? "%return" : "", line); |
260 | else | 263 | else |
261 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->file, line); | 264 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); |
262 | if (ret <= 0) | 265 | if (ret <= 0) |
263 | goto error; | 266 | goto error; |
264 | len = ret; | 267 | len = ret; |
@@ -373,14 +376,32 @@ static void clear_probe_point(struct probe_point *pp) | |||
373 | free(pp->args); | 376 | free(pp->args); |
374 | for (i = 0; i < pp->found; i++) | 377 | for (i = 0; i < pp->found; i++) |
375 | free(pp->probes[i]); | 378 | free(pp->probes[i]); |
376 | memset(pp, 0, sizeof(pp)); | 379 | memset(pp, 0, sizeof(*pp)); |
380 | } | ||
381 | |||
382 | /* Show an event */ | ||
383 | static void show_perf_probe_event(const char *group, const char *event, | ||
384 | const char *place, struct probe_point *pp) | ||
385 | { | ||
386 | int i; | ||
387 | char buf[128]; | ||
388 | |||
389 | e_snprintf(buf, 128, "%s:%s", group, event); | ||
390 | printf(" %-40s (on %s", buf, place); | ||
391 | |||
392 | if (pp->nr_args > 0) { | ||
393 | printf(" with"); | ||
394 | for (i = 0; i < pp->nr_args; i++) | ||
395 | printf(" %s", pp->args[i]); | ||
396 | } | ||
397 | printf(")\n"); | ||
377 | } | 398 | } |
378 | 399 | ||
379 | /* List up current perf-probe events */ | 400 | /* List up current perf-probe events */ |
380 | void show_perf_probe_events(void) | 401 | void show_perf_probe_events(void) |
381 | { | 402 | { |
382 | unsigned int i; | 403 | unsigned int i; |
383 | int fd; | 404 | int fd, nr; |
384 | char *group, *event; | 405 | char *group, *event; |
385 | struct probe_point pp; | 406 | struct probe_point pp; |
386 | struct strlist *rawlist; | 407 | struct strlist *rawlist; |
@@ -393,8 +414,13 @@ void show_perf_probe_events(void) | |||
393 | for (i = 0; i < strlist__nr_entries(rawlist); i++) { | 414 | for (i = 0; i < strlist__nr_entries(rawlist); i++) { |
394 | ent = strlist__entry(rawlist, i); | 415 | ent = strlist__entry(rawlist, i); |
395 | parse_trace_kprobe_event(ent->s, &group, &event, &pp); | 416 | parse_trace_kprobe_event(ent->s, &group, &event, &pp); |
417 | /* Synthesize only event probe point */ | ||
418 | nr = pp.nr_args; | ||
419 | pp.nr_args = 0; | ||
396 | synthesize_perf_probe_event(&pp); | 420 | synthesize_perf_probe_event(&pp); |
397 | printf("[%s:%s]\t%s\n", group, event, pp.probes[0]); | 421 | pp.nr_args = nr; |
422 | /* Show an event */ | ||
423 | show_perf_probe_event(group, event, pp.probes[0], &pp); | ||
398 | free(group); | 424 | free(group); |
399 | free(event); | 425 | free(event); |
400 | clear_probe_point(&pp); | 426 | clear_probe_point(&pp); |
@@ -404,21 +430,28 @@ void show_perf_probe_events(void) | |||
404 | } | 430 | } |
405 | 431 | ||
406 | /* Get current perf-probe event names */ | 432 | /* Get current perf-probe event names */ |
407 | static struct strlist *get_perf_event_names(int fd) | 433 | static struct strlist *get_perf_event_names(int fd, bool include_group) |
408 | { | 434 | { |
409 | unsigned int i; | 435 | unsigned int i; |
410 | char *group, *event; | 436 | char *group, *event; |
437 | char buf[128]; | ||
411 | struct strlist *sl, *rawlist; | 438 | struct strlist *sl, *rawlist; |
412 | struct str_node *ent; | 439 | struct str_node *ent; |
413 | 440 | ||
414 | rawlist = get_trace_kprobe_event_rawlist(fd); | 441 | rawlist = get_trace_kprobe_event_rawlist(fd); |
415 | 442 | ||
416 | sl = strlist__new(false, NULL); | 443 | sl = strlist__new(true, NULL); |
417 | for (i = 0; i < strlist__nr_entries(rawlist); i++) { | 444 | for (i = 0; i < strlist__nr_entries(rawlist); i++) { |
418 | ent = strlist__entry(rawlist, i); | 445 | ent = strlist__entry(rawlist, i); |
419 | parse_trace_kprobe_event(ent->s, &group, &event, NULL); | 446 | parse_trace_kprobe_event(ent->s, &group, &event, NULL); |
420 | strlist__add(sl, event); | 447 | if (include_group) { |
448 | if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) | ||
449 | die("Failed to copy group:event name."); | ||
450 | strlist__add(sl, buf); | ||
451 | } else | ||
452 | strlist__add(sl, event); | ||
421 | free(group); | 453 | free(group); |
454 | free(event); | ||
422 | } | 455 | } |
423 | 456 | ||
424 | strlist__delete(rawlist); | 457 | strlist__delete(rawlist); |
@@ -426,24 +459,30 @@ static struct strlist *get_perf_event_names(int fd) | |||
426 | return sl; | 459 | return sl; |
427 | } | 460 | } |
428 | 461 | ||
429 | static int write_trace_kprobe_event(int fd, const char *buf) | 462 | static void write_trace_kprobe_event(int fd, const char *buf) |
430 | { | 463 | { |
431 | int ret; | 464 | int ret; |
432 | 465 | ||
466 | pr_debug("Writing event: %s\n", buf); | ||
433 | ret = write(fd, buf, strlen(buf)); | 467 | ret = write(fd, buf, strlen(buf)); |
434 | if (ret <= 0) | 468 | if (ret <= 0) |
435 | die("Failed to create event."); | 469 | die("Failed to write event: %s", strerror(errno)); |
436 | else | ||
437 | printf("Added new event: %s\n", buf); | ||
438 | |||
439 | return ret; | ||
440 | } | 470 | } |
441 | 471 | ||
442 | static void get_new_event_name(char *buf, size_t len, const char *base, | 472 | static void get_new_event_name(char *buf, size_t len, const char *base, |
443 | struct strlist *namelist) | 473 | struct strlist *namelist) |
444 | { | 474 | { |
445 | int i, ret; | 475 | int i, ret; |
446 | for (i = 0; i < MAX_EVENT_INDEX; i++) { | 476 | |
477 | /* Try no suffix */ | ||
478 | ret = e_snprintf(buf, len, "%s", base); | ||
479 | if (ret < 0) | ||
480 | die("snprintf() failed: %s", strerror(-ret)); | ||
481 | if (!strlist__has_entry(namelist, buf)) | ||
482 | return; | ||
483 | |||
484 | /* Try to add suffix */ | ||
485 | for (i = 1; i < MAX_EVENT_INDEX; i++) { | ||
447 | ret = e_snprintf(buf, len, "%s_%d", base, i); | 486 | ret = e_snprintf(buf, len, "%s_%d", base, i); |
448 | if (ret < 0) | 487 | if (ret < 0) |
449 | die("snprintf() failed: %s", strerror(-ret)); | 488 | die("snprintf() failed: %s", strerror(-ret)); |
@@ -464,7 +503,7 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes) | |||
464 | 503 | ||
465 | fd = open_kprobe_events(O_RDWR, O_APPEND); | 504 | fd = open_kprobe_events(O_RDWR, O_APPEND); |
466 | /* Get current event names */ | 505 | /* Get current event names */ |
467 | namelist = get_perf_event_names(fd); | 506 | namelist = get_perf_event_names(fd, false); |
468 | 507 | ||
469 | for (j = 0; j < nr_probes; j++) { | 508 | for (j = 0; j < nr_probes; j++) { |
470 | pp = probes + j; | 509 | pp = probes + j; |
@@ -476,9 +515,73 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes) | |||
476 | PERFPROBE_GROUP, event, | 515 | PERFPROBE_GROUP, event, |
477 | pp->probes[i]); | 516 | pp->probes[i]); |
478 | write_trace_kprobe_event(fd, buf); | 517 | write_trace_kprobe_event(fd, buf); |
518 | printf("Added new event:\n"); | ||
519 | /* Get the first parameter (probe-point) */ | ||
520 | sscanf(pp->probes[i], "%s", buf); | ||
521 | show_perf_probe_event(PERFPROBE_GROUP, event, | ||
522 | buf, pp); | ||
479 | /* Add added event name to namelist */ | 523 | /* Add added event name to namelist */ |
480 | strlist__add(namelist, event); | 524 | strlist__add(namelist, event); |
481 | } | 525 | } |
482 | } | 526 | } |
527 | /* Show how to use the event. */ | ||
528 | printf("\nYou can now use it on all perf tools, such as:\n\n"); | ||
529 | printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event); | ||
530 | |||
531 | strlist__delete(namelist); | ||
532 | close(fd); | ||
533 | } | ||
534 | |||
535 | static void del_trace_kprobe_event(int fd, const char *group, | ||
536 | const char *event, struct strlist *namelist) | ||
537 | { | ||
538 | char buf[128]; | ||
539 | |||
540 | if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) | ||
541 | die("Failed to copy event."); | ||
542 | if (!strlist__has_entry(namelist, buf)) { | ||
543 | pr_warning("Warning: event \"%s\" is not found.\n", buf); | ||
544 | return; | ||
545 | } | ||
546 | /* Convert from perf-probe event to trace-kprobe event */ | ||
547 | if (e_snprintf(buf, 128, "-:%s/%s", group, event) < 0) | ||
548 | die("Failed to copy event."); | ||
549 | |||
550 | write_trace_kprobe_event(fd, buf); | ||
551 | printf("Remove event: %s:%s\n", group, event); | ||
552 | } | ||
553 | |||
554 | void del_trace_kprobe_events(struct strlist *dellist) | ||
555 | { | ||
556 | int fd; | ||
557 | unsigned int i; | ||
558 | const char *group, *event; | ||
559 | char *p, *str; | ||
560 | struct str_node *ent; | ||
561 | struct strlist *namelist; | ||
562 | |||
563 | fd = open_kprobe_events(O_RDWR, O_APPEND); | ||
564 | /* Get current event names */ | ||
565 | namelist = get_perf_event_names(fd, true); | ||
566 | |||
567 | for (i = 0; i < strlist__nr_entries(dellist); i++) { | ||
568 | ent = strlist__entry(dellist, i); | ||
569 | str = strdup(ent->s); | ||
570 | if (!str) | ||
571 | die("Failed to copy event."); | ||
572 | p = strchr(str, ':'); | ||
573 | if (p) { | ||
574 | group = str; | ||
575 | *p = '\0'; | ||
576 | event = p + 1; | ||
577 | } else { | ||
578 | group = PERFPROBE_GROUP; | ||
579 | event = str; | ||
580 | } | ||
581 | del_trace_kprobe_event(fd, group, event, namelist); | ||
582 | free(str); | ||
583 | } | ||
584 | strlist__delete(namelist); | ||
483 | close(fd); | 585 | close(fd); |
484 | } | 586 | } |
587 | |||