From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754424AbbGOJT0 (ORCPT ); Wed, 15 Jul 2015 05:19:26 -0400 Received: from mail4.hitachi.co.jp ([133.145.228.5]:50171 "EHLO mail4.hitachi.co.jp" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754403AbbGOJTY (ORCPT ); Wed, 15 Jul 2015 05:19:24 -0400 Subject: [RFC PATCH perf/core v2 11/16] perf probe: Show all cached probes From: Masami Hiramatsu To: Arnaldo Carvalho de Melo Cc: Peter Zijlstra , linux-kernel@vger.kernel.org, Adrian Hunter , Ingo Molnar , Paul Mackerras , Jiri Olsa , Namhyung Kim , Borislav Petkov , Hemant Kumar Date: Wed, 15 Jul 2015 18:15:09 +0900 Message-ID: <20150715091509.8915.81216.stgit@localhost.localdomain> In-Reply-To: <20150715091352.8915.87480.stgit@localhost.localdomain> References: <20150715091352.8915.87480.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- Changes in v2: - Fix to ignore if build-id list is failed to get with -ENOENT, since this can happen when ~/.debug is not initialized. - Do not show binary name if there is no cached entries. - Update perf-probe.txt too. --- tools/perf/Documentation/perf-probe.txt | 8 ++- tools/perf/builtin-probe.c | 2 - tools/perf/util/build-id.c | 79 ++++++++++++++++++++++++++++++- tools/perf/util/build-id.h | 3 + tools/perf/util/probe-event.c | 3 + tools/perf/util/probe-file.c | 65 +++++++++++++++++++++++++- tools/perf/util/probe-file.h | 1 7 files changed, 154 insertions(+), 7 deletions(-) diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 947db6f..5a70d45 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -67,7 +67,10 @@ OPTIONS -l:: --list[=[GROUP:]EVENT]:: - List up current probe events. This can also accept filtering patterns of event names. + List up current probe events. This can also accept filtering patterns of + event names. + When this is used with --cache, perf shows all cached probes instead of + the live probes. -L:: --line=:: @@ -110,8 +113,9 @@ OPTIONS adding and removal operations. --cache:: - Cache the probes (with --add option). Any events which successfully added + (With --add) Cache the probes. Any events which successfully added are also stored in the cache file. + (With --list) Show cached probes. --max-probes=NUM:: 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 5ac8a79..5d0c246 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -44,7 +44,7 @@ #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" #define DEFAULT_FUNC_FILTER "!_*" -#define DEFAULT_LIST_FILTER "*:*" +#define DEFAULT_LIST_FILTER "*" /* Session management structure */ static struct { diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 169639e..63123c1 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -144,8 +144,7 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...) return ret; } -static char *build_id_cache__linkname(const char *sbuild_id, char *bf, - size_t size) +char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size) { char *tmp = bf; int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir, @@ -155,6 +154,29 @@ static char *build_id_cache__linkname(const char *sbuild_id, char *bf, return bf; } +char *build_id_cache__origname(const char *sbuild_id) +{ + char *linkname; + char buf[PATH_MAX]; + char *ret = NULL, *p; + + linkname = build_id_cache__linkname(sbuild_id, NULL, 0); + if (!linkname) + return NULL; + + if (readlink(linkname, buf, PATH_MAX) < 0) + goto out; + /* The link should be "../../" */ + p = strrchr(buf, '/'); /* Cut off the "/" */ + if (p) { + *p = '\0'; + ret = strdup(buf + 5); /* Skip "../.." */ + } +out: + free(linkname); + return ret; +} + static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso) { return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf"); @@ -313,6 +335,59 @@ void disable_buildid_cache(void) no_buildid_cache = true; } +int build_id_cache__list_all(struct strlist **result) +{ + struct strlist *toplist, *list, *bidlist; + struct str_node *nd, *nd2; + char *topdir, *linkdir; + char sbuild_id[SBUILD_ID_SIZE]; + int ret = 0; + + /* Open the top-level directory */ + if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0) + return -errno; + toplist = lsdir(topdir, lsdir_no_dot_filter); + if (!toplist) { + pr_debug("Failed to opendir %s\n", topdir); + ret = -errno; + goto out; + } + bidlist = strlist__new(true, NULL); + strlist__for_each(nd, toplist) { + if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0) { + ret = -errno; + goto out; + } + /* Open the lower-level directory */ + list = lsdir(linkdir, lsdir_no_dot_filter); + if (!list) { + pr_debug("Failed to open %s: %d\n", linkdir, -errno); + goto next; + } + strlist__for_each(nd2, list) { + ret = snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s", + nd->s, nd2->s); + if (ret != SBUILD_ID_SIZE - 1) { + pr_debug("%s/%s is not buildid cache\n", + nd->s, nd2->s); + continue; + } + strlist__add(bidlist, sbuild_id); + } + strlist__delete(list); +next: + free(linkdir); + } + + *result = bidlist; +out: + if (toplist) + strlist__delete(toplist); + free(topdir); + + return ret; +} + char *build_id_cache__dirname_from_path(const char *sbuild_id, const char *name, bool is_kallsyms, bool is_vdso) { diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index a1f428d..2d5c61c 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h @@ -27,8 +27,11 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits); int perf_session__write_buildid_table(struct perf_session *session, int fd); int perf_session__cache_build_ids(struct perf_session *session); +char *build_id_cache__origname(const char *sbuild_id); +char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size); char *build_id_cache__dirname_from_path(const char *sbuild_id, const char *name, bool is_kallsyms, bool is_vdso); +int build_id_cache__list_all(struct strlist **result); int build_id_cache__list_build_ids(const char *pathname, struct strlist **result); 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 c71b16b..23b577b 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2210,6 +2210,9 @@ int show_perf_probe_events(struct strfilter *filter) setup_pager(); + if (probe_conf.cache) + return probe_cache__show_all_caches(filter); + ret = init_symbol_maps(false); if (ret < 0) return ret; diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 984f690..da69ff7 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -340,10 +340,17 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) { char cpath[PATH_MAX]; char sbuildid[SBUILD_ID_SIZE]; - char *dir_name; + char *dir_name = NULL; bool is_kallsyms = !target; int ret, fd; + if (target && build_id_cache__cached(target)) { + /* This is a cached buildid */ + strncpy(sbuildid, target, SBUILD_ID_SIZE); + dir_name = build_id_cache__linkname(sbuildid, NULL, 0); + goto found; + } + if (target) ret = filename__sprintf_build_id(target, sbuildid); else { @@ -367,8 +374,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) dir_name = build_id_cache__dirname_from_path(sbuildid, target, is_kallsyms, false); - if (!dir_name) +found: + if (!dir_name) { + pr_debug("Failed to get cache from %s\n", target); return -ENOMEM; + } snprintf(cpath, PATH_MAX, "%s/probes", dir_name); fd = open(cpath, O_CREAT | O_RDWR | O_APPEND, 0644); @@ -616,3 +626,54 @@ int probe_cache__commit(struct probe_cache *pcache) out: return ret; } + +static int probe_cache__show_entries(struct probe_cache *pcache, + struct strfilter *filter) +{ + struct probe_cache_entry *entry; + char buf[128], *ptr; + + list_for_each_entry(entry, &pcache->list, list) { + if (entry->pev.event) { + ptr = buf; + snprintf(buf, 128, "%s:%s", entry->pev.group, entry->pev.event); + } else + ptr = entry->spev; + if (strfilter__compare(filter, ptr)) + printf("%s\n", entry->spev); + } + return 0; +} + +/* Show all cached probes */ +int probe_cache__show_all_caches(struct strfilter *filter) +{ + struct probe_cache *pcache; + struct strlist *bidlist; + struct str_node *nd; + char *buf; + int ret; + + buf = strfilter__string(filter); + pr_debug("list cache with filter: %s\n", buf); + free(buf); + + ret = build_id_cache__list_all(&bidlist); + if (ret < 0) { + pr_debug("Failed to get buildids: %d\n", ret); + return ret == -ENOENT ? 0 : ret; + } + strlist__for_each(nd, bidlist) { + pcache = probe_cache__new(nd->s); + if (!pcache) + continue; + if (!list_empty(&pcache->list)) { + buf = build_id_cache__origname(nd->s); + printf("%s (%s):\n", buf, nd->s); + free(buf); + probe_cache__show_entries(pcache, filter); + } + probe_cache__delete(pcache); + } + return 0; +} diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index 833e061..26dc4f7 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h @@ -38,4 +38,5 @@ struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev); struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache, const char *group, const char *event); +int probe_cache__show_all_caches(struct strfilter *filter); #endif