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:
Masami Hiramatsu 2016-07-01 17:04:10 +09:00 committed by Arnaldo Carvalho de Melo
parent 8d993d9690
commit 6430a94ead
4 changed files with 101 additions and 3 deletions

View file

@ -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);