forked from Minki/linux
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:
parent
bc0622302f
commit
1f3736c9c8
@ -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.
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user