diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2016-07-01 11:04:10 +0300 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-07-05 01:39:00 +0300 |
commit | 6430a94ead2a4c8f350441351a735303eb6d1c8a (patch) | |
tree | ab1b6fc072549f519d8a15dca3c39a8ed0cad8ca /tools | |
parent | 8d993d96901f55d26e083390aae80fd02cbff7aa (diff) | |
download | linux-6430a94ead2a4c8f350441351a735303eb6d1c8a.tar.xz |
perf buildid-cache: Scan and import user SDT events to probe cache
perf buildid-cache --add <binary> scans given binary and add
the SDT events to probe cache. "sdt_" prefix is appended for
all SDT providers to avoid event-name clash with other pre-defined
events. It is possible to use the cached SDT events as other cached
events, via perf probe --add "sdt_<provider>:<event>=<event>".
e.g.
----
# perf buildid-cache --add /lib/libc-2.17.so
# perf probe --cache --list | head -n 5
/usr/lib/libc-2.17.so (a6fb821bdf53660eb2c29f778757aef294d3d392):
sdt_libc:setjmp=setjmp
sdt_libc:longjmp=longjmp
sdt_libc:longjmp_target=longjmp_target
sdt_libc:memory_heap_new=memory_heap_new
# perf probe -x /usr/lib/libc-2.17.so \
-a sdt_libc:memory_heap_new=memory_heap_new
Added new event:
sdt_libc:memory_heap_new (on memory_heap_new
in /usr/lib/libc-2.17.so)
You can now use it in all perf tools, such as:
perf record -e sdt_libc:memory_heap_new -aR sleep 1
# perf probe -l
sdt_libc:memory_heap_new (on new_heap+183 in /usr/lib/libc-2.17.so)
----
Note that SDT event entries in probe-cache file is somewhat different
from normal cached events. Normal one starts with "#", but SDTs are
starting with "%".
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.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/146736025058.27797.13043265488541434502.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/Documentation/perf-buildid-cache.txt | 3 | ||||
-rw-r--r-- | tools/perf/util/build-id.c | 30 | ||||
-rw-r--r-- | tools/perf/util/probe-file.c | 69 | ||||
-rw-r--r-- | tools/perf/util/probe-file.h | 2 |
4 files changed, 101 insertions, 3 deletions
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt index dd07b55f58d8..058064db39d2 100644 --- a/tools/perf/Documentation/perf-buildid-cache.txt +++ b/tools/perf/Documentation/perf-buildid-cache.txt @@ -15,6 +15,9 @@ DESCRIPTION This command manages the build-id cache. It can add, remove, update and purge files to/from the cache. In the future it should as well set upper limits for the space used by the cache, etc. +This also scans the target binary for SDT (Statically Defined Tracing) and +record it along with the buildid-cache, which will be used by perf-probe. +For more details, see linkperf:perf-probe[1]. OPTIONS ------- diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 1c49620e98b2..e1a16408da9c 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -17,6 +17,7 @@ #include "tool.h" #include "header.h" #include "vdso.h" +#include "probe-file.h" static bool no_buildid_cache; @@ -532,6 +533,30 @@ int build_id_cache__list_build_ids(const char *pathname, return ret; } +#ifdef HAVE_LIBELF_SUPPORT +static int build_id_cache__add_sdt_cache(const char *sbuild_id, + const char *realname) +{ + struct probe_cache *cache; + int ret; + + cache = probe_cache__new(sbuild_id); + if (!cache) + return -1; + + ret = probe_cache__scan_sdt(cache, realname); + if (ret >= 0) { + pr_debug("Found %d SDTs in %s\n", ret, realname); + if (probe_cache__commit(cache) < 0) + ret = -1; + } + probe_cache__delete(cache); + return ret; +} +#else +#define build_id_cache__add_sdt_cache(sbuild_id, realname) (0) +#endif + int build_id_cache__add_s(const char *sbuild_id, const char *name, bool is_kallsyms, bool is_vdso) { @@ -589,6 +614,11 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, if (symlink(tmp, linkname) == 0) err = 0; + + /* Update SDT cache : error is just warned */ + if (build_id_cache__add_sdt_cache(sbuild_id, realname) < 0) + pr_debug("Failed to update/scan SDT cache for %s\n", realname); + out_free: if (!is_kallsyms) free(realname); diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 6cb6ec03c1fe..5b563b2e8b1d 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -434,12 +434,15 @@ static int probe_cache__load(struct probe_cache *pcache) p = strchr(buf, '\n'); if (p) *p = '\0'; - if (buf[0] == '#') { /* #perf_probe_event */ + /* #perf_probe_event or %sdt_event */ + if (buf[0] == '#' || buf[0] == '%') { entry = probe_cache_entry__new(NULL); if (!entry) { ret = -ENOMEM; goto out; } + if (buf[0] == '%') + entry->sdt = true; entry->spev = strdup(buf + 1); if (entry->spev) ret = parse_perf_probe_command(buf + 1, @@ -621,19 +624,79 @@ out_err: return ret; } +static unsigned long long sdt_note__get_addr(struct sdt_note *note) +{ + return note->bit32 ? (unsigned long long)note->addr.a32[0] + : (unsigned long long)note->addr.a64[0]; +} + +int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname) +{ + struct probe_cache_entry *entry = NULL; + struct list_head sdtlist; + struct sdt_note *note; + char *buf; + char sdtgrp[64]; + int ret; + + INIT_LIST_HEAD(&sdtlist); + ret = get_sdt_note_list(&sdtlist, pathname); + if (ret < 0) { + pr_debug("Failed to get sdt note: %d\n", ret); + return ret; + } + list_for_each_entry(note, &sdtlist, note_list) { + ret = snprintf(sdtgrp, 64, "sdt_%s", note->provider); + if (ret < 0) + break; + /* Try to find same-name entry */ + entry = probe_cache__find_by_name(pcache, sdtgrp, note->name); + if (!entry) { + entry = probe_cache_entry__new(NULL); + if (!entry) { + ret = -ENOMEM; + break; + } + entry->sdt = true; + ret = asprintf(&entry->spev, "%s:%s=%s", sdtgrp, + note->name, note->name); + if (ret < 0) + break; + entry->pev.event = strdup(note->name); + entry->pev.group = strdup(sdtgrp); + list_add_tail(&entry->node, &pcache->entries); + } + ret = asprintf(&buf, "p:%s/%s %s:0x%llx", + sdtgrp, note->name, pathname, + sdt_note__get_addr(note)); + if (ret < 0) + break; + strlist__add(entry->tevlist, buf); + free(buf); + entry = NULL; + } + if (entry) { + list_del_init(&entry->node); + probe_cache_entry__delete(entry); + } + cleanup_sdt_note_list(&sdtlist); + return ret; +} + static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd) { struct str_node *snode; struct stat st; struct iovec iov[3]; + const char *prefix = entry->sdt ? "%" : "#"; int ret; /* Save stat for rollback */ ret = fstat(fd, &st); if (ret < 0) return ret; - pr_debug("Writing cache: #%s\n", entry->spev); - iov[0].iov_base = (void *)"#"; iov[0].iov_len = 1; + pr_debug("Writing cache: %s%s\n", prefix, entry->spev); + iov[0].iov_base = (void *)prefix; iov[0].iov_len = 1; iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev); iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1; ret = writev(fd, iov, 3); diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index 0ed1fc563b77..ddf5ae212c2f 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h @@ -8,6 +8,7 @@ /* Cache of probe definitions */ struct probe_cache_entry { struct list_head node; + bool sdt; struct perf_probe_event pev; char *spev; struct strlist *tevlist; @@ -35,6 +36,7 @@ struct probe_cache *probe_cache__new(const char *target); int probe_cache__add_entry(struct probe_cache *pcache, struct perf_probe_event *pev, struct probe_trace_event *tevs, int ntevs); +int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname); int probe_cache__commit(struct probe_cache *pcache); void probe_cache__purge(struct probe_cache *pcache); void probe_cache__delete(struct probe_cache *pcache); |