diff options
author | Masami Hiramatsu <mhiramat@kernel.org> | 2016-07-12 06:05:18 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-07-13 22:09:07 -0400 |
commit | 42bba263eb58800b6239a0cb35ac17fd29379277 (patch) | |
tree | f0db0956443374d672e89f5c83f4ea1e39491557 /tools/perf | |
parent | 05bf2c8a2a819132b4a8f35d4315ff22e8e84a20 (diff) |
perf probe: Allow wildcard for cached events
Allo glob wildcard for reusing cached/SDT events. E.g.
# perf probe -x /usr/lib64/libc-2.20.so -a %sdt_libc:\*
This example adds probes for all SDT in libc.
Note that the SDTs must have been scanned by perf buildid-cache.
Committer note:
Using it to check what of those SDT probes would take place when doing
a cargo run (rust):
# trace --no-sys --event sdt_libc:* cargo run
0.000 sdt_libc:setjmp:(7f326b69c4d1))
28.423 sdt_libc:setjmp:(7f4b0a5364d1))
29.000 sdt_libc:setjmp:(7f4b0a5364d1))
88.597 sdt_libc:setjmp:(7fc01fd414d1))
89.220 sdt_libc:setjmp:(7fc01fd414d1))
95.501 sdt_libc:setjmp:(7f326b69c4d1))
Running `target/debug/hello_world`
97.110 sdt_libc:setjmp:(7f95e09234d1))
Hello, world!
#
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
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/146831791813.17065.17846564230840594888.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/util/probe-event.c | 107 | ||||
-rw-r--r-- | tools/perf/util/probe-file.c | 38 | ||||
-rw-r--r-- | tools/perf/util/probe-file.h | 3 |
3 files changed, 138 insertions, 10 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 85f25d41cf8d..7b96e687568e 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -1204,7 +1204,7 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev) | |||
1204 | ptr = strchr(*arg, ':'); | 1204 | ptr = strchr(*arg, ':'); |
1205 | if (ptr) { | 1205 | if (ptr) { |
1206 | *ptr = '\0'; | 1206 | *ptr = '\0'; |
1207 | if (!is_c_func_name(*arg)) | 1207 | if (!pev->sdt && !is_c_func_name(*arg)) |
1208 | goto ng_name; | 1208 | goto ng_name; |
1209 | pev->group = strdup(*arg); | 1209 | pev->group = strdup(*arg); |
1210 | if (!pev->group) | 1210 | if (!pev->group) |
@@ -1212,7 +1212,7 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev) | |||
1212 | *arg = ptr + 1; | 1212 | *arg = ptr + 1; |
1213 | } else | 1213 | } else |
1214 | pev->group = NULL; | 1214 | pev->group = NULL; |
1215 | if (!is_c_func_name(*arg)) { | 1215 | if (!pev->sdt && !is_c_func_name(*arg)) { |
1216 | ng_name: | 1216 | ng_name: |
1217 | semantic_error("%s is bad for event name -it must " | 1217 | semantic_error("%s is bad for event name -it must " |
1218 | "follow C symbol-naming rule.\n", *arg); | 1218 | "follow C symbol-naming rule.\n", *arg); |
@@ -1644,6 +1644,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev) | |||
1644 | ret = -ENOMEM; | 1644 | ret = -ENOMEM; |
1645 | goto out; | 1645 | goto out; |
1646 | } | 1646 | } |
1647 | tev->uprobes = (tp->module[0] == '/'); | ||
1647 | p++; | 1648 | p++; |
1648 | } else | 1649 | } else |
1649 | p = argv[1]; | 1650 | p = argv[1]; |
@@ -2518,7 +2519,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev, | |||
2518 | int ret; | 2519 | int ret; |
2519 | 2520 | ||
2520 | /* If probe_event or trace_event already have the name, reuse it */ | 2521 | /* If probe_event or trace_event already have the name, reuse it */ |
2521 | if (pev->event) | 2522 | if (pev->event && !pev->sdt) |
2522 | event = pev->event; | 2523 | event = pev->event; |
2523 | else if (tev->event) | 2524 | else if (tev->event) |
2524 | event = tev->event; | 2525 | event = tev->event; |
@@ -2531,7 +2532,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev, | |||
2531 | else | 2532 | else |
2532 | event = tev->point.realname; | 2533 | event = tev->point.realname; |
2533 | } | 2534 | } |
2534 | if (pev->group) | 2535 | if (pev->group && !pev->sdt) |
2535 | group = pev->group; | 2536 | group = pev->group; |
2536 | else if (tev->group) | 2537 | else if (tev->group) |
2537 | group = tev->group; | 2538 | group = tev->group; |
@@ -2894,6 +2895,100 @@ errout: | |||
2894 | 2895 | ||
2895 | bool __weak arch__prefers_symtab(void) { return false; } | 2896 | bool __weak arch__prefers_symtab(void) { return false; } |
2896 | 2897 | ||
2898 | /* Concatinate two arrays */ | ||
2899 | static void *memcat(void *a, size_t sz_a, void *b, size_t sz_b) | ||
2900 | { | ||
2901 | void *ret; | ||
2902 | |||
2903 | ret = malloc(sz_a + sz_b); | ||
2904 | if (ret) { | ||
2905 | memcpy(ret, a, sz_a); | ||
2906 | memcpy(ret + sz_a, b, sz_b); | ||
2907 | } | ||
2908 | return ret; | ||
2909 | } | ||
2910 | |||
2911 | static int | ||
2912 | concat_probe_trace_events(struct probe_trace_event **tevs, int *ntevs, | ||
2913 | struct probe_trace_event **tevs2, int ntevs2) | ||
2914 | { | ||
2915 | struct probe_trace_event *new_tevs; | ||
2916 | int ret = 0; | ||
2917 | |||
2918 | if (ntevs == 0) { | ||
2919 | *tevs = *tevs2; | ||
2920 | *ntevs = ntevs2; | ||
2921 | *tevs2 = NULL; | ||
2922 | return 0; | ||
2923 | } | ||
2924 | |||
2925 | if (*ntevs + ntevs2 > probe_conf.max_probes) | ||
2926 | ret = -E2BIG; | ||
2927 | else { | ||
2928 | /* Concatinate the array of probe_trace_event */ | ||
2929 | new_tevs = memcat(*tevs, (*ntevs) * sizeof(**tevs), | ||
2930 | *tevs2, ntevs2 * sizeof(**tevs2)); | ||
2931 | if (!new_tevs) | ||
2932 | ret = -ENOMEM; | ||
2933 | else { | ||
2934 | free(*tevs); | ||
2935 | *tevs = new_tevs; | ||
2936 | *ntevs += ntevs2; | ||
2937 | } | ||
2938 | } | ||
2939 | if (ret < 0) | ||
2940 | clear_probe_trace_events(*tevs2, ntevs2); | ||
2941 | zfree(tevs2); | ||
2942 | |||
2943 | return ret; | ||
2944 | } | ||
2945 | |||
2946 | /* | ||
2947 | * Try to find probe_trace_event from given probe caches. Return the number | ||
2948 | * of cached events found, if an error occurs return the error. | ||
2949 | */ | ||
2950 | static int find_cached_events(struct perf_probe_event *pev, | ||
2951 | struct probe_trace_event **tevs, | ||
2952 | const char *target) | ||
2953 | { | ||
2954 | struct probe_cache *cache; | ||
2955 | struct probe_cache_entry *entry; | ||
2956 | struct probe_trace_event *tmp_tevs = NULL; | ||
2957 | int ntevs = 0; | ||
2958 | int ret = 0; | ||
2959 | |||
2960 | cache = probe_cache__new(target); | ||
2961 | /* Return 0 ("not found") if the target has no probe cache. */ | ||
2962 | if (!cache) | ||
2963 | return 0; | ||
2964 | |||
2965 | for_each_probe_cache_entry(entry, cache) { | ||
2966 | /* Skip the cache entry which has no name */ | ||
2967 | if (!entry->pev.event || !entry->pev.group) | ||
2968 | continue; | ||
2969 | if ((!pev->group || strglobmatch(entry->pev.group, pev->group)) && | ||
2970 | strglobmatch(entry->pev.event, pev->event)) { | ||
2971 | ret = probe_cache_entry__get_event(entry, &tmp_tevs); | ||
2972 | if (ret > 0) | ||
2973 | ret = concat_probe_trace_events(tevs, &ntevs, | ||
2974 | &tmp_tevs, ret); | ||
2975 | if (ret < 0) | ||
2976 | break; | ||
2977 | } | ||
2978 | } | ||
2979 | probe_cache__delete(cache); | ||
2980 | if (ret < 0) { | ||
2981 | clear_probe_trace_events(*tevs, ntevs); | ||
2982 | zfree(tevs); | ||
2983 | } else { | ||
2984 | ret = ntevs; | ||
2985 | if (ntevs > 0 && target && target[0] == '/') | ||
2986 | pev->uprobes = true; | ||
2987 | } | ||
2988 | |||
2989 | return ret; | ||
2990 | } | ||
2991 | |||
2897 | static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, | 2992 | static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, |
2898 | struct probe_trace_event **tevs) | 2993 | struct probe_trace_event **tevs) |
2899 | { | 2994 | { |
@@ -2903,6 +2998,10 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, | |||
2903 | struct str_node *node; | 2998 | struct str_node *node; |
2904 | int ret, i; | 2999 | int ret, i; |
2905 | 3000 | ||
3001 | if (pev->sdt) | ||
3002 | /* For SDT/cached events, we use special search functions */ | ||
3003 | return find_cached_events(pev, tevs, pev->target); | ||
3004 | |||
2906 | cache = probe_cache__new(pev->target); | 3005 | cache = probe_cache__new(pev->target); |
2907 | if (!cache) | 3006 | if (!cache) |
2908 | return 0; | 3007 | return 0; |
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index abfb05cf135b..9aed9c332da6 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c | |||
@@ -362,13 +362,38 @@ probe_cache_entry__new(struct perf_probe_event *pev) | |||
362 | return entry; | 362 | return entry; |
363 | } | 363 | } |
364 | 364 | ||
365 | /* For the kernel probe caches, pass target = NULL */ | 365 | int probe_cache_entry__get_event(struct probe_cache_entry *entry, |
366 | struct probe_trace_event **tevs) | ||
367 | { | ||
368 | struct probe_trace_event *tev; | ||
369 | struct str_node *node; | ||
370 | int ret, i; | ||
371 | |||
372 | ret = strlist__nr_entries(entry->tevlist); | ||
373 | if (ret > probe_conf.max_probes) | ||
374 | return -E2BIG; | ||
375 | |||
376 | *tevs = zalloc(ret * sizeof(*tev)); | ||
377 | if (!*tevs) | ||
378 | return -ENOMEM; | ||
379 | |||
380 | i = 0; | ||
381 | strlist__for_each_entry(node, entry->tevlist) { | ||
382 | tev = &(*tevs)[i++]; | ||
383 | ret = parse_probe_trace_command(node->s, tev); | ||
384 | if (ret < 0) | ||
385 | break; | ||
386 | } | ||
387 | return i; | ||
388 | } | ||
389 | |||
390 | /* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */ | ||
366 | static int probe_cache__open(struct probe_cache *pcache, const char *target) | 391 | static int probe_cache__open(struct probe_cache *pcache, const char *target) |
367 | { | 392 | { |
368 | char cpath[PATH_MAX]; | 393 | char cpath[PATH_MAX]; |
369 | char sbuildid[SBUILD_ID_SIZE]; | 394 | char sbuildid[SBUILD_ID_SIZE]; |
370 | char *dir_name = NULL; | 395 | char *dir_name = NULL; |
371 | bool is_kallsyms = !target; | 396 | bool is_kallsyms = false; |
372 | int ret, fd; | 397 | int ret, fd; |
373 | 398 | ||
374 | if (target && build_id_cache__cached(target)) { | 399 | if (target && build_id_cache__cached(target)) { |
@@ -378,12 +403,13 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) | |||
378 | goto found; | 403 | goto found; |
379 | } | 404 | } |
380 | 405 | ||
381 | if (target) | 406 | if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) { |
382 | ret = filename__sprintf_build_id(target, sbuildid); | ||
383 | else { | ||
384 | target = DSO__NAME_KALLSYMS; | 407 | target = DSO__NAME_KALLSYMS; |
408 | is_kallsyms = true; | ||
385 | ret = sysfs__sprintf_build_id("/", sbuildid); | 409 | ret = sysfs__sprintf_build_id("/", sbuildid); |
386 | } | 410 | } else |
411 | ret = filename__sprintf_build_id(target, sbuildid); | ||
412 | |||
387 | if (ret < 0) { | 413 | if (ret < 0) { |
388 | pr_debug("Failed to get build-id from %s.\n", target); | 414 | pr_debug("Failed to get build-id from %s.\n", target); |
389 | return ret; | 415 | return ret; |
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index d513b346a70e..cafbe1d3f3bf 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h | |||
@@ -34,6 +34,9 @@ int probe_file__get_events(int fd, struct strfilter *filter, | |||
34 | struct strlist *plist); | 34 | struct strlist *plist); |
35 | int probe_file__del_strlist(int fd, struct strlist *namelist); | 35 | int probe_file__del_strlist(int fd, struct strlist *namelist); |
36 | 36 | ||
37 | int probe_cache_entry__get_event(struct probe_cache_entry *entry, | ||
38 | struct probe_trace_event **tevs); | ||
39 | |||
37 | struct probe_cache *probe_cache__new(const char *target); | 40 | struct probe_cache *probe_cache__new(const char *target); |
38 | int probe_cache__add_entry(struct probe_cache *pcache, | 41 | int probe_cache__add_entry(struct probe_cache *pcache, |
39 | struct perf_probe_event *pev, | 42 | struct perf_probe_event *pev, |