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>
This commit is contained in:
Masami Hiramatsu 2016-07-01 17:03:26 +09:00 committed by Arnaldo Carvalho de Melo
parent bc0622302f
commit 1f3736c9c8
7 changed files with 184 additions and 7 deletions

View File

@ -67,7 +67,10 @@ OPTIONS
-l:: -l::
--list[=[GROUP:]EVENT]:: --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:: -L::
--line=:: --line=::
@ -110,8 +113,9 @@ OPTIONS
adding and removal operations. adding and removal operations.
--cache:: --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. are also stored in the cache file.
(With --list) Show cached probes.
--max-probes=NUM:: --max-probes=NUM::
Set the maximum number of probe points for an event. Default is 128. Set the maximum number of probe points for an event. Default is 128.

View File

@ -44,7 +44,7 @@
#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
#define DEFAULT_FUNC_FILTER "!_*" #define DEFAULT_FUNC_FILTER "!_*"
#define DEFAULT_LIST_FILTER "*:*" #define DEFAULT_LIST_FILTER "*"
/* Session management structure */ /* Session management structure */
static struct { static struct {

View File

@ -165,8 +165,7 @@ retry:
return NULL; return NULL;
} }
static char *build_id_cache__linkname(const char *sbuild_id, char *bf, char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size)
size_t size)
{ {
char *tmp = bf; char *tmp = bf;
int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir, 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; 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) static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
{ {
return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf"); return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
@ -387,6 +416,81 @@ void disable_buildid_cache(void)
no_buildid_cache = true; 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, char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
bool is_kallsyms, bool is_vdso) bool is_kallsyms, bool is_vdso)
{ {

View 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__write_buildid_table(struct perf_session *session, int fd);
int perf_session__cache_build_ids(struct perf_session *session); 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, char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
bool is_kallsyms, bool is_vdso); bool is_kallsyms, bool is_vdso);
struct strlist *build_id_cache__list_all(void);
int build_id_cache__list_build_ids(const char *pathname, int build_id_cache__list_build_ids(const char *pathname,
struct strlist **result); struct strlist **result);
bool build_id_cache__cached(const char *sbuild_id); bool build_id_cache__cached(const char *sbuild_id);

View File

@ -2366,6 +2366,9 @@ int show_perf_probe_events(struct strfilter *filter)
setup_pager(); setup_pager();
if (probe_conf.cache)
return probe_cache__show_all_caches(filter);
ret = init_probe_symbol_maps(false); ret = init_probe_symbol_maps(false);
if (ret < 0) if (ret < 0)
return ret; return ret;

View File

@ -367,10 +367,17 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
{ {
char cpath[PATH_MAX]; char cpath[PATH_MAX];
char sbuildid[SBUILD_ID_SIZE]; char sbuildid[SBUILD_ID_SIZE];
char *dir_name; char *dir_name = NULL;
bool is_kallsyms = !target; bool is_kallsyms = !target;
int ret, fd; 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) if (target)
ret = filename__sprintf_build_id(target, sbuildid); ret = filename__sprintf_build_id(target, sbuildid);
else { 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, dir_name = build_id_cache__cachedir(sbuildid, target, is_kallsyms,
false); false);
if (!dir_name) found:
if (!dir_name) {
pr_debug("Failed to get cache from %s\n", target);
return -ENOMEM; return -ENOMEM;
}
snprintf(cpath, PATH_MAX, "%s/probes", dir_name); snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
fd = open(cpath, O_CREAT | O_RDWR, 0644); fd = open(cpath, O_CREAT | O_RDWR, 0644);
@ -673,3 +683,55 @@ int probe_cache__commit(struct probe_cache *pcache)
out: out:
return ret; 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;
}

View File

@ -42,4 +42,5 @@ struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
struct perf_probe_event *pev); struct perf_probe_event *pev);
struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache, struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
const char *group, const char *event); const char *group, const char *event);
int probe_cache__show_all_caches(struct strfilter *filter);
#endif #endif