perf probe: Show all cached probes
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Fri, 1 Jul 2016 08:03:26 +0000 (17:03 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 1 Jul 2016 14:34:57 +0000 (11:34 -0300)
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>
tools/perf/Documentation/perf-probe.txt
tools/perf/builtin-probe.c
tools/perf/util/build-id.c
tools/perf/util/build-id.h
tools/perf/util/probe-event.c
tools/perf/util/probe-file.c
tools/perf/util/probe-file.h

index 947db6fe512c81990b4bfa519f885f76af55d554..5a70d45015eac669c88451bde3355d23cd106585 100644 (file)
@@ -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.
index 34262329f4056d660438d4b7315415ae61de8397..0bb9084bf6cfd38a962aa326331f12ba04bc2339 100644 (file)
@@ -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 {
index 62b147366d017107675f4881cc06fa410aa572d0..1c49620e98b2e315cd4cbe0680dfaabb281e0b12 100644 (file)
@@ -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 "../..<origpath>/<sbuild_id>" */
+       p = strrchr(buf, '/');  /* Cut off the "/<sbuild_id>" */
+       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_entry(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_entry(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)
 {
index d8c7f2fc6a878bddec7fd8bc7c971b0190ffd8d6..b742e271ea2cee40dcefaa24b2627cea3c0b2fad 100644 (file)
@@ -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);
index 47b6b8b7206e276e652bab63885ba6989deb1793..f81b5dd7f1b175ebf718ae3c6df52a52a490afe4 100644 (file)
@@ -2366,6 +2366,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;
index a94ee478178d1ef53f852acc3cd7304ce60905ed..156e3d88396513aabc8bf61e5649dea117db81bb 100644 (file)
@@ -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_entry(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;
+}
index 910aa74953e9c7a743b1d8200b7a16413513001c..0009b8a65a5cc301f60df82f6ad8d878329f9899 100644 (file)
@@ -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