From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932761AbcFOD3N (ORCPT ); Tue, 14 Jun 2016 23:29:13 -0400 Received: from mail.kernel.org ([198.145.29.136]:58658 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1161045AbcFOD3K (ORCPT ); Tue, 14 Jun 2016 23:29:10 -0400 From: Masami Hiramatsu To: Arnaldo Carvalho de Melo Cc: Masami Hiramatsu , linux-kernel@vger.kernel.org, Namhyung Kim , Peter Zijlstra , Ingo Molnar , Hemant Kumar , Ananth N Mavinakayanahalli , Brendan Gregg Subject: [PATCH perf/core v11 09/20] perf probe: Show all cached probes Date: Wed, 15 Jun 2016 12:29:04 +0900 Message-Id: <20160615032904.31330.1453.stgit@devbox> X-Mailer: git-send-email 2.1.0 In-Reply-To: <20160615032728.31330.45150.stgit@devbox> References: <20160615032728.31330.45150.stgit@devbox> 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 From: Masami Hiramatsu 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 Signed-off-by: Masami Hiramatsu --- Changes in v11: - Make build_id_cache__list_all() returns strlist directly. (no error code) - Harden build_id_cache__list_all() to check directory entries. Changes in v7: - Remove the top '/' from binary name if it is not a regular file. --- tools/perf/Documentation/perf-probe.txt | 8 ++ tools/perf/builtin-probe.c | 2 - tools/perf/util/build-id.c | 108 ++++++++++++++++++++++++++++++- tools/perf/util/build-id.h | 3 + tools/perf/util/probe-event.c | 3 + tools/perf/util/probe-file.c | 66 ++++++++++++++++++- 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 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 6d7ab431..53e380c0e 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 62b1473..0d6093c 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -165,8 +165,7 @@ retry: return NULL; } -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, @@ -176,6 +175,36 @@ 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; + size_t offs = 5; /* == strlen("../..") */ + + 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 > buf + offs)) { + *p = '\0'; + if (buf[offs + 1] == '[') + offs++; /* + * This is a DSO name, like [kernel.kallsyms]. + * Skip the first '/', since this is not the + * cache of a regular file. + */ + ret = strdup(buf + offs); /* 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"); @@ -387,6 +416,81 @@ void disable_buildid_cache(void) no_buildid_cache = true; } +static bool lsdir_bid_head_filter(const char *name __maybe_unused, + struct dirent *d __maybe_unused) +{ + return (strlen(d->d_name) == 2) && + isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]); +} + +static bool lsdir_bid_tail_filter(const char *name __maybe_unused, + struct dirent *d __maybe_unused) +{ + int i = 0; + while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3) + i++; + return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0'); +} + +struct strlist *build_id_cache__list_all(void) +{ + struct strlist *toplist, *linklist = NULL, *bidlist; + struct str_node *nd, *nd2; + char *topdir, *linkdir = NULL; + char sbuild_id[SBUILD_ID_SIZE]; + + /* Open the top-level directory */ + if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0) + return NULL; + + bidlist = strlist__new(NULL, NULL); + if (!bidlist) + goto out; + + toplist = lsdir(topdir, lsdir_bid_head_filter); + if (!toplist) { + pr_debug("Error in lsdir(%s): %d\n", topdir, errno); + /* If there is no buildid cache, return an empty list */ + if (errno == ENOENT) + goto out; + goto err_out; + } + + strlist__for_each(nd, toplist) { + if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0) + goto err_out; + /* Open the lower-level directory */ + linklist = lsdir(linkdir, lsdir_bid_tail_filter); + if (!linklist) { + pr_debug("Error in lsdir(%s): %d\n", linkdir, errno); + goto err_out; + } + strlist__for_each(nd2, linklist) { + if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s", + nd->s, nd2->s) != SBUILD_ID_SIZE - 1) + goto err_out; + if (strlist__add(bidlist, sbuild_id) < 0) + goto err_out; + } + strlist__delete(linklist); + zfree(&linkdir); + } + +out_free: + strlist__delete(toplist); +out: + free(topdir); + + return bidlist; + +err_out: + strlist__delete(linklist); + zfree(&linkdir); + strlist__delete(bidlist); + bidlist = NULL; + goto out_free; +} + char *build_id_cache__cachedir(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 d8c7f2f..b742e27 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); 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__cachedir(const char *sbuild_id, const char *name, bool is_kallsyms, bool is_vdso); +struct strlist *build_id_cache__list_all(void); 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 020c110..fbb101d 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2368,6 +2368,9 @@ int show_perf_probe_events(struct strfilter *filter) setup_pager(); + if (probe_conf.cache) + return probe_cache__show_all_caches(filter); + ret = init_probe_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 58a60b3..47e0e95 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) { 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 { @@ -394,8 +401,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) dir_name = build_id_cache__cachedir(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, 0644); @@ -673,3 +683,55 @@ 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->entries, node) { + 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 = strfilter__string(filter); + + pr_debug("list cache with filter: %s\n", buf); + free(buf); + + bidlist = build_id_cache__list_all(); + if (!bidlist) { + pr_debug("Failed to get buildids: %d\n", errno); + return -EINVAL; + } + strlist__for_each(nd, bidlist) { + pcache = probe_cache__new(nd->s); + if (!pcache) + continue; + if (!list_empty(&pcache->entries)) { + 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); + } + strlist__delete(bidlist); + + return 0; +} diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index 910aa74..0009b8a 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, 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