diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2016-07-01 04:03:26 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-07-01 10:34:57 -0400 |
commit | 1f3736c9c833e40ac4d3a8dc6d661e341df8a259 (patch) | |
tree | 25181ab3dfea97bc4986f2c4c49866e037a51873 /tools/perf | |
parent | bc0622302f344551050995491b7d14176f39c628 (diff) |
perf probe: Show all cached probes
perf probe --list shows all cached probes when --cache is given. Each
caches are shown with on which binary that probed. E.g.:
-----
# perf probe --cache vfs_read \$params
# perf probe --cache -x /lib64/libc-2.17.so getaddrinfo \$params
# perf probe --cache --list
[kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1):
vfs_read $params
/usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc):
getaddrinfo $params
-----
Note that $params requires debuginfo.
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
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/146736020674.27797.13488316780383460180.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Documentation/perf-probe.txt | 8 | ||||
-rw-r--r-- | tools/perf/builtin-probe.c | 2 | ||||
-rw-r--r-- | tools/perf/util/build-id.c | 108 | ||||
-rw-r--r-- | tools/perf/util/build-id.h | 3 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 3 | ||||
-rw-r--r-- | tools/perf/util/probe-file.c | 66 | ||||
-rw-r--r-- | tools/perf/util/probe-file.h | 1 |
7 files changed, 184 insertions, 7 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 947db6fe512c..5a70d45015ea 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
@@ -67,7 +67,10 @@ OPTIONS | |||
67 | 67 | ||
68 | -l:: | 68 | -l:: |
69 | --list[=[GROUP:]EVENT]:: | 69 | --list[=[GROUP:]EVENT]:: |
70 | List up current probe events. This can also accept filtering patterns of event names. | 70 | List up current probe events. This can also accept filtering patterns of |
71 | event names. | ||
72 | When this is used with --cache, perf shows all cached probes instead of | ||
73 | the live probes. | ||
71 | 74 | ||
72 | -L:: | 75 | -L:: |
73 | --line=:: | 76 | --line=:: |
@@ -110,8 +113,9 @@ OPTIONS | |||
110 | adding and removal operations. | 113 | adding and removal operations. |
111 | 114 | ||
112 | --cache:: | 115 | --cache:: |
113 | Cache the probes (with --add option). Any events which successfully added | 116 | (With --add) Cache the probes. Any events which successfully added |
114 | are also stored in the cache file. | 117 | are also stored in the cache file. |
118 | (With --list) Show cached probes. | ||
115 | 119 | ||
116 | --max-probes=NUM:: | 120 | --max-probes=NUM:: |
117 | Set the maximum number of probe points for an event. Default is 128. | 121 | Set the maximum number of probe points for an event. Default is 128. |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 34262329f405..0bb9084bf6cf 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -44,7 +44,7 @@ | |||
44 | 44 | ||
45 | #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" | 45 | #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" |
46 | #define DEFAULT_FUNC_FILTER "!_*" | 46 | #define DEFAULT_FUNC_FILTER "!_*" |
47 | #define DEFAULT_LIST_FILTER "*:*" | 47 | #define DEFAULT_LIST_FILTER "*" |
48 | 48 | ||
49 | /* Session management structure */ | 49 | /* Session management structure */ |
50 | static struct { | 50 | static struct { |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 62b147366d01..1c49620e98b2 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
@@ -165,8 +165,7 @@ retry: | |||
165 | return NULL; | 165 | return NULL; |
166 | } | 166 | } |
167 | 167 | ||
168 | static char *build_id_cache__linkname(const char *sbuild_id, char *bf, | 168 | char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size) |
169 | size_t size) | ||
170 | { | 169 | { |
171 | char *tmp = bf; | 170 | char *tmp = bf; |
172 | int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir, | 171 | int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir, |
@@ -176,6 +175,36 @@ static char *build_id_cache__linkname(const char *sbuild_id, char *bf, | |||
176 | return bf; | 175 | return bf; |
177 | } | 176 | } |
178 | 177 | ||
178 | char *build_id_cache__origname(const char *sbuild_id) | ||
179 | { | ||
180 | char *linkname; | ||
181 | char buf[PATH_MAX]; | ||
182 | char *ret = NULL, *p; | ||
183 | size_t offs = 5; /* == strlen("../..") */ | ||
184 | |||
185 | linkname = build_id_cache__linkname(sbuild_id, NULL, 0); | ||
186 | if (!linkname) | ||
187 | return NULL; | ||
188 | |||
189 | if (readlink(linkname, buf, PATH_MAX) < 0) | ||
190 | goto out; | ||
191 | /* The link should be "../..<origpath>/<sbuild_id>" */ | ||
192 | p = strrchr(buf, '/'); /* Cut off the "/<sbuild_id>" */ | ||
193 | if (p && (p > buf + offs)) { | ||
194 | *p = '\0'; | ||
195 | if (buf[offs + 1] == '[') | ||
196 | offs++; /* | ||
197 | * This is a DSO name, like [kernel.kallsyms]. | ||
198 | * Skip the first '/', since this is not the | ||
199 | * cache of a regular file. | ||
200 | */ | ||
201 | ret = strdup(buf + offs); /* Skip "../..[/]" */ | ||
202 | } | ||
203 | out: | ||
204 | free(linkname); | ||
205 | return ret; | ||
206 | } | ||
207 | |||
179 | static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso) | 208 | static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso) |
180 | { | 209 | { |
181 | return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf"); | 210 | return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf"); |
@@ -387,6 +416,81 @@ void disable_buildid_cache(void) | |||
387 | no_buildid_cache = true; | 416 | no_buildid_cache = true; |
388 | } | 417 | } |
389 | 418 | ||
419 | static bool lsdir_bid_head_filter(const char *name __maybe_unused, | ||
420 | struct dirent *d __maybe_unused) | ||
421 | { | ||
422 | return (strlen(d->d_name) == 2) && | ||
423 | isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]); | ||
424 | } | ||
425 | |||
426 | static bool lsdir_bid_tail_filter(const char *name __maybe_unused, | ||
427 | struct dirent *d __maybe_unused) | ||
428 | { | ||
429 | int i = 0; | ||
430 | while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3) | ||
431 | i++; | ||
432 | return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0'); | ||
433 | } | ||
434 | |||
435 | struct strlist *build_id_cache__list_all(void) | ||
436 | { | ||
437 | struct strlist *toplist, *linklist = NULL, *bidlist; | ||
438 | struct str_node *nd, *nd2; | ||
439 | char *topdir, *linkdir = NULL; | ||
440 | char sbuild_id[SBUILD_ID_SIZE]; | ||
441 | |||
442 | /* Open the top-level directory */ | ||
443 | if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0) | ||
444 | return NULL; | ||
445 | |||
446 | bidlist = strlist__new(NULL, NULL); | ||
447 | if (!bidlist) | ||
448 | goto out; | ||
449 | |||
450 | toplist = lsdir(topdir, lsdir_bid_head_filter); | ||
451 | if (!toplist) { | ||
452 | pr_debug("Error in lsdir(%s): %d\n", topdir, errno); | ||
453 | /* If there is no buildid cache, return an empty list */ | ||
454 | if (errno == ENOENT) | ||
455 | goto out; | ||
456 | goto err_out; | ||
457 | } | ||
458 | |||
459 | strlist__for_each_entry(nd, toplist) { | ||
460 | if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0) | ||
461 | goto err_out; | ||
462 | /* Open the lower-level directory */ | ||
463 | linklist = lsdir(linkdir, lsdir_bid_tail_filter); | ||
464 | if (!linklist) { | ||
465 | pr_debug("Error in lsdir(%s): %d\n", linkdir, errno); | ||
466 | goto err_out; | ||
467 | } | ||
468 | strlist__for_each_entry(nd2, linklist) { | ||
469 | if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s", | ||
470 | nd->s, nd2->s) != SBUILD_ID_SIZE - 1) | ||
471 | goto err_out; | ||
472 | if (strlist__add(bidlist, sbuild_id) < 0) | ||
473 | goto err_out; | ||
474 | } | ||
475 | strlist__delete(linklist); | ||
476 | zfree(&linkdir); | ||
477 | } | ||
478 | |||
479 | out_free: | ||
480 | strlist__delete(toplist); | ||
481 | out: | ||
482 | free(topdir); | ||
483 | |||
484 | return bidlist; | ||
485 | |||
486 | err_out: | ||
487 | strlist__delete(linklist); | ||
488 | zfree(&linkdir); | ||
489 | strlist__delete(bidlist); | ||
490 | bidlist = NULL; | ||
491 | goto out_free; | ||
492 | } | ||
493 | |||
390 | char *build_id_cache__cachedir(const char *sbuild_id, const char *name, | 494 | char *build_id_cache__cachedir(const char *sbuild_id, const char *name, |
391 | bool is_kallsyms, bool is_vdso) | 495 | bool is_kallsyms, bool is_vdso) |
392 | { | 496 | { |
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index d8c7f2fc6a87..b742e271ea2c 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h | |||
@@ -30,8 +30,11 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits); | |||
30 | int perf_session__write_buildid_table(struct perf_session *session, int fd); | 30 | int perf_session__write_buildid_table(struct perf_session *session, int fd); |
31 | int perf_session__cache_build_ids(struct perf_session *session); | 31 | int perf_session__cache_build_ids(struct perf_session *session); |
32 | 32 | ||
33 | char *build_id_cache__origname(const char *sbuild_id); | ||
34 | char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size); | ||
33 | char *build_id_cache__cachedir(const char *sbuild_id, const char *name, | 35 | char *build_id_cache__cachedir(const char *sbuild_id, const char *name, |
34 | bool is_kallsyms, bool is_vdso); | 36 | bool is_kallsyms, bool is_vdso); |
37 | struct strlist *build_id_cache__list_all(void); | ||
35 | int build_id_cache__list_build_ids(const char *pathname, | 38 | int build_id_cache__list_build_ids(const char *pathname, |
36 | struct strlist **result); | 39 | struct strlist **result); |
37 | bool build_id_cache__cached(const char *sbuild_id); | 40 | bool build_id_cache__cached(const char *sbuild_id); |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 47b6b8b7206e..f81b5dd7f1b1 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -2366,6 +2366,9 @@ int show_perf_probe_events(struct strfilter *filter) | |||
2366 | 2366 | ||
2367 | setup_pager(); | 2367 | setup_pager(); |
2368 | 2368 | ||
2369 | if (probe_conf.cache) | ||
2370 | return probe_cache__show_all_caches(filter); | ||
2371 | |||
2369 | ret = init_probe_symbol_maps(false); | 2372 | ret = init_probe_symbol_maps(false); |
2370 | if (ret < 0) | 2373 | if (ret < 0) |
2371 | return ret; | 2374 | return ret; |
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index a94ee478178d..156e3d883965 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c | |||
@@ -367,10 +367,17 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) | |||
367 | { | 367 | { |
368 | char cpath[PATH_MAX]; | 368 | char cpath[PATH_MAX]; |
369 | char sbuildid[SBUILD_ID_SIZE]; | 369 | char sbuildid[SBUILD_ID_SIZE]; |
370 | char *dir_name; | 370 | char *dir_name = NULL; |
371 | bool is_kallsyms = !target; | 371 | bool is_kallsyms = !target; |
372 | int ret, fd; | 372 | int ret, fd; |
373 | 373 | ||
374 | if (target && build_id_cache__cached(target)) { | ||
375 | /* This is a cached buildid */ | ||
376 | strncpy(sbuildid, target, SBUILD_ID_SIZE); | ||
377 | dir_name = build_id_cache__linkname(sbuildid, NULL, 0); | ||
378 | goto found; | ||
379 | } | ||
380 | |||
374 | if (target) | 381 | if (target) |
375 | ret = filename__sprintf_build_id(target, sbuildid); | 382 | ret = filename__sprintf_build_id(target, sbuildid); |
376 | else { | 383 | else { |
@@ -394,8 +401,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) | |||
394 | 401 | ||
395 | dir_name = build_id_cache__cachedir(sbuildid, target, is_kallsyms, | 402 | dir_name = build_id_cache__cachedir(sbuildid, target, is_kallsyms, |
396 | false); | 403 | false); |
397 | if (!dir_name) | 404 | found: |
405 | if (!dir_name) { | ||
406 | pr_debug("Failed to get cache from %s\n", target); | ||
398 | return -ENOMEM; | 407 | return -ENOMEM; |
408 | } | ||
399 | 409 | ||
400 | snprintf(cpath, PATH_MAX, "%s/probes", dir_name); | 410 | snprintf(cpath, PATH_MAX, "%s/probes", dir_name); |
401 | fd = open(cpath, O_CREAT | O_RDWR, 0644); | 411 | fd = open(cpath, O_CREAT | O_RDWR, 0644); |
@@ -673,3 +683,55 @@ int probe_cache__commit(struct probe_cache *pcache) | |||
673 | out: | 683 | out: |
674 | return ret; | 684 | return ret; |
675 | } | 685 | } |
686 | |||
687 | static int probe_cache__show_entries(struct probe_cache *pcache, | ||
688 | struct strfilter *filter) | ||
689 | { | ||
690 | struct probe_cache_entry *entry; | ||
691 | char buf[128], *ptr; | ||
692 | |||
693 | list_for_each_entry(entry, &pcache->entries, node) { | ||
694 | if (entry->pev.event) { | ||
695 | ptr = buf; | ||
696 | snprintf(buf, 128, "%s:%s", | ||
697 | entry->pev.group, entry->pev.event); | ||
698 | } else | ||
699 | ptr = entry->spev; | ||
700 | if (strfilter__compare(filter, ptr)) | ||
701 | printf("%s\n", entry->spev); | ||
702 | } | ||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | /* Show all cached probes */ | ||
707 | int probe_cache__show_all_caches(struct strfilter *filter) | ||
708 | { | ||
709 | struct probe_cache *pcache; | ||
710 | struct strlist *bidlist; | ||
711 | struct str_node *nd; | ||
712 | char *buf = strfilter__string(filter); | ||
713 | |||
714 | pr_debug("list cache with filter: %s\n", buf); | ||
715 | free(buf); | ||
716 | |||
717 | bidlist = build_id_cache__list_all(); | ||
718 | if (!bidlist) { | ||
719 | pr_debug("Failed to get buildids: %d\n", errno); | ||
720 | return -EINVAL; | ||
721 | } | ||
722 | strlist__for_each_entry(nd, bidlist) { | ||
723 | pcache = probe_cache__new(nd->s); | ||
724 | if (!pcache) | ||
725 | continue; | ||
726 | if (!list_empty(&pcache->entries)) { | ||
727 | buf = build_id_cache__origname(nd->s); | ||
728 | printf("%s (%s):\n", buf, nd->s); | ||
729 | free(buf); | ||
730 | probe_cache__show_entries(pcache, filter); | ||
731 | } | ||
732 | probe_cache__delete(pcache); | ||
733 | } | ||
734 | strlist__delete(bidlist); | ||
735 | |||
736 | return 0; | ||
737 | } | ||
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index 910aa74953e9..0009b8a65a5c 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h | |||
@@ -42,4 +42,5 @@ struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache, | |||
42 | struct perf_probe_event *pev); | 42 | struct perf_probe_event *pev); |
43 | struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache, | 43 | struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache, |
44 | const char *group, const char *event); | 44 | const char *group, const char *event); |
45 | int probe_cache__show_all_caches(struct strfilter *filter); | ||
45 | #endif | 46 | #endif |