diff options
author | Masami Hiramatsu <mhiramat@kernel.org> | 2016-07-12 06:05:28 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-07-13 22:09:07 -0400 |
commit | 1de7b8bf728fd8d51b0cc644003d0694c6e0feef (patch) | |
tree | 785a66caa4604d1c2e3b9761a29c43f35a56a65c | |
parent | 42bba263eb58800b6239a0cb35ac17fd29379277 (diff) |
perf probe: Search SDT/cached event from all probe caches
Search SDT/cached event from all probe caches if user doesn't pass any
binary. With this, we don't have to specify target binary for SDT and
named cached events (which start with %).
E.g. without this, a target binary must be passed with -x.
# perf probe -x /usr/lib64/libc-2.20.so -a %sdt_libc:\*
With this change, we don't need it anymore.
# perf probe -a %sdt_libc:\*
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/146831792812.17065.2353705982669445313.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/util/probe-event.c | 105 |
1 files changed, 86 insertions, 19 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 7b96e687568e..c63e3b8704fe 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -2557,41 +2557,60 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev, | |||
2557 | return 0; | 2557 | return 0; |
2558 | } | 2558 | } |
2559 | 2559 | ||
2560 | static int __add_probe_trace_events(struct perf_probe_event *pev, | 2560 | static int __open_probe_file_and_namelist(bool uprobe, |
2561 | struct probe_trace_event *tevs, | 2561 | struct strlist **namelist) |
2562 | int ntevs, bool allow_suffix) | ||
2563 | { | 2562 | { |
2564 | int i, fd, ret; | 2563 | int fd; |
2565 | struct probe_trace_event *tev = NULL; | ||
2566 | struct probe_cache *cache = NULL; | ||
2567 | struct strlist *namelist; | ||
2568 | 2564 | ||
2569 | fd = probe_file__open(PF_FL_RW | (pev->uprobes ? PF_FL_UPROBE : 0)); | 2565 | fd = probe_file__open(PF_FL_RW | (uprobe ? PF_FL_UPROBE : 0)); |
2570 | if (fd < 0) | 2566 | if (fd < 0) |
2571 | return fd; | 2567 | return fd; |
2572 | 2568 | ||
2573 | /* Get current event names */ | 2569 | /* Get current event names */ |
2574 | namelist = probe_file__get_namelist(fd); | 2570 | *namelist = probe_file__get_namelist(fd); |
2575 | if (!namelist) { | 2571 | if (!(*namelist)) { |
2576 | pr_debug("Failed to get current event list.\n"); | 2572 | pr_debug("Failed to get current event list.\n"); |
2577 | ret = -ENOMEM; | 2573 | close(fd); |
2578 | goto close_out; | 2574 | return -ENOMEM; |
2579 | } | 2575 | } |
2576 | return fd; | ||
2577 | } | ||
2578 | |||
2579 | static int __add_probe_trace_events(struct perf_probe_event *pev, | ||
2580 | struct probe_trace_event *tevs, | ||
2581 | int ntevs, bool allow_suffix) | ||
2582 | { | ||
2583 | int i, fd[2] = {-1, -1}, up, ret; | ||
2584 | struct probe_trace_event *tev = NULL; | ||
2585 | struct probe_cache *cache = NULL; | ||
2586 | struct strlist *namelist[2] = {NULL, NULL}; | ||
2587 | |||
2588 | up = pev->uprobes ? 1 : 0; | ||
2589 | fd[up] = __open_probe_file_and_namelist(up, &namelist[up]); | ||
2590 | if (fd[up] < 0) | ||
2591 | return fd[up]; | ||
2580 | 2592 | ||
2581 | ret = 0; | 2593 | ret = 0; |
2582 | for (i = 0; i < ntevs; i++) { | 2594 | for (i = 0; i < ntevs; i++) { |
2583 | tev = &tevs[i]; | 2595 | tev = &tevs[i]; |
2596 | up = tev->uprobes ? 1 : 0; | ||
2597 | if (fd[up] == -1) { /* Open the kprobe/uprobe_events */ | ||
2598 | fd[up] = __open_probe_file_and_namelist(up, | ||
2599 | &namelist[up]); | ||
2600 | if (fd[up] < 0) | ||
2601 | goto close_out; | ||
2602 | } | ||
2584 | /* Skip if the symbol is out of .text or blacklisted */ | 2603 | /* Skip if the symbol is out of .text or blacklisted */ |
2585 | if (!tev->point.symbol && !pev->uprobes) | 2604 | if (!tev->point.symbol && !pev->uprobes) |
2586 | continue; | 2605 | continue; |
2587 | 2606 | ||
2588 | /* Set new name for tev (and update namelist) */ | 2607 | /* Set new name for tev (and update namelist) */ |
2589 | ret = probe_trace_event__set_name(tev, pev, namelist, | 2608 | ret = probe_trace_event__set_name(tev, pev, namelist[up], |
2590 | allow_suffix); | 2609 | allow_suffix); |
2591 | if (ret < 0) | 2610 | if (ret < 0) |
2592 | break; | 2611 | break; |
2593 | 2612 | ||
2594 | ret = probe_file__add_event(fd, tev); | 2613 | ret = probe_file__add_event(fd[up], tev); |
2595 | if (ret < 0) | 2614 | if (ret < 0) |
2596 | break; | 2615 | break; |
2597 | 2616 | ||
@@ -2614,9 +2633,12 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
2614 | probe_cache__delete(cache); | 2633 | probe_cache__delete(cache); |
2615 | } | 2634 | } |
2616 | 2635 | ||
2617 | strlist__delete(namelist); | ||
2618 | close_out: | 2636 | close_out: |
2619 | close(fd); | 2637 | for (up = 0; up < 2; up++) { |
2638 | strlist__delete(namelist[up]); | ||
2639 | if (fd[up] >= 0) | ||
2640 | close(fd[up]); | ||
2641 | } | ||
2620 | return ret; | 2642 | return ret; |
2621 | } | 2643 | } |
2622 | 2644 | ||
@@ -2989,6 +3011,48 @@ static int find_cached_events(struct perf_probe_event *pev, | |||
2989 | return ret; | 3011 | return ret; |
2990 | } | 3012 | } |
2991 | 3013 | ||
3014 | /* Try to find probe_trace_event from all probe caches */ | ||
3015 | static int find_cached_events_all(struct perf_probe_event *pev, | ||
3016 | struct probe_trace_event **tevs) | ||
3017 | { | ||
3018 | struct probe_trace_event *tmp_tevs = NULL; | ||
3019 | struct strlist *bidlist; | ||
3020 | struct str_node *nd; | ||
3021 | char *pathname; | ||
3022 | int ntevs = 0; | ||
3023 | int ret; | ||
3024 | |||
3025 | /* Get the buildid list of all valid caches */ | ||
3026 | bidlist = build_id_cache__list_all(true); | ||
3027 | if (!bidlist) { | ||
3028 | ret = -errno; | ||
3029 | pr_debug("Failed to get buildids: %d\n", ret); | ||
3030 | return ret; | ||
3031 | } | ||
3032 | |||
3033 | ret = 0; | ||
3034 | strlist__for_each_entry(nd, bidlist) { | ||
3035 | pathname = build_id_cache__origname(nd->s); | ||
3036 | ret = find_cached_events(pev, &tmp_tevs, pathname); | ||
3037 | /* In the case of cnt == 0, we just skip it */ | ||
3038 | if (ret > 0) | ||
3039 | ret = concat_probe_trace_events(tevs, &ntevs, | ||
3040 | &tmp_tevs, ret); | ||
3041 | free(pathname); | ||
3042 | if (ret < 0) | ||
3043 | break; | ||
3044 | } | ||
3045 | strlist__delete(bidlist); | ||
3046 | |||
3047 | if (ret < 0) { | ||
3048 | clear_probe_trace_events(*tevs, ntevs); | ||
3049 | zfree(tevs); | ||
3050 | } else | ||
3051 | ret = ntevs; | ||
3052 | |||
3053 | return ret; | ||
3054 | } | ||
3055 | |||
2992 | static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, | 3056 | static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, |
2993 | struct probe_trace_event **tevs) | 3057 | struct probe_trace_event **tevs) |
2994 | { | 3058 | { |
@@ -2998,10 +3062,13 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, | |||
2998 | struct str_node *node; | 3062 | struct str_node *node; |
2999 | int ret, i; | 3063 | int ret, i; |
3000 | 3064 | ||
3001 | if (pev->sdt) | 3065 | if (pev->sdt) { |
3002 | /* For SDT/cached events, we use special search functions */ | 3066 | /* For SDT/cached events, we use special search functions */ |
3003 | return find_cached_events(pev, tevs, pev->target); | 3067 | if (!pev->target) |
3004 | 3068 | return find_cached_events_all(pev, tevs); | |
3069 | else | ||
3070 | return find_cached_events(pev, tevs, pev->target); | ||
3071 | } | ||
3005 | cache = probe_cache__new(pev->target); | 3072 | cache = probe_cache__new(pev->target); |
3006 | if (!cache) | 3073 | if (!cache) |
3007 | return 0; | 3074 | return 0; |