forked from luck/tmp_suning_uos_patched
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>
This commit is contained in:
parent
8d993d9690
commit
6430a94ead
|
@ -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
|
||||
-------
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 @@ int probe_cache__add_entry(struct probe_cache *pcache,
|
|||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user