Skip to content

Commit

Permalink
perf buildid-cache: Scan and import user SDT events to probe cache
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mhiramathitachi authored and acmel committed Jul 4, 2016
1 parent 8d993d9 commit 6430a94
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 3 deletions.
3 changes: 3 additions & 0 deletions tools/perf/Documentation/perf-buildid-cache.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
-------
Expand Down
30 changes: 30 additions & 0 deletions tools/perf/util/build-id.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "tool.h"
#include "header.h"
#include "vdso.h"
#include "probe-file.h"


static bool no_buildid_cache;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down
69 changes: 66 additions & 3 deletions tools/perf/util/probe-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions tools/perf/util/probe-file.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 6430a94

Please sign in to comment.