aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2016-07-01 04:04:10 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-07-04 18:39:00 -0400
commit6430a94ead2a4c8f350441351a735303eb6d1c8a (patch)
treeab1b6fc072549f519d8a15dca3c39a8ed0cad8ca
parent8d993d96901f55d26e083390aae80fd02cbff7aa (diff)
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>
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt3
-rw-r--r--tools/perf/util/build-id.c30
-rw-r--r--tools/perf/util/probe-file.c69
-rw-r--r--tools/perf/util/probe-file.h2
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
15This command manages the build-id cache. It can add, remove, update and purge 15This command manages the build-id cache. It can add, remove, update and purge
16files to/from the cache. In the future it should as well set upper limits for 16files to/from the cache. In the future it should as well set upper limits for
17the space used by the cache, etc. 17the space used by the cache, etc.
18This also scans the target binary for SDT (Statically Defined Tracing) and
19record it along with the buildid-cache, which will be used by perf-probe.
20For more details, see linkperf:perf-probe[1].
18 21
19OPTIONS 22OPTIONS
20------- 23-------
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 @@
17#include "tool.h" 17#include "tool.h"
18#include "header.h" 18#include "header.h"
19#include "vdso.h" 19#include "vdso.h"
20#include "probe-file.h"
20 21
21 22
22static bool no_buildid_cache; 23static bool no_buildid_cache;
@@ -532,6 +533,30 @@ int build_id_cache__list_build_ids(const char *pathname,
532 return ret; 533 return ret;
533} 534}
534 535
536#ifdef HAVE_LIBELF_SUPPORT
537static int build_id_cache__add_sdt_cache(const char *sbuild_id,
538 const char *realname)
539{
540 struct probe_cache *cache;
541 int ret;
542
543 cache = probe_cache__new(sbuild_id);
544 if (!cache)
545 return -1;
546
547 ret = probe_cache__scan_sdt(cache, realname);
548 if (ret >= 0) {
549 pr_debug("Found %d SDTs in %s\n", ret, realname);
550 if (probe_cache__commit(cache) < 0)
551 ret = -1;
552 }
553 probe_cache__delete(cache);
554 return ret;
555}
556#else
557#define build_id_cache__add_sdt_cache(sbuild_id, realname) (0)
558#endif
559
535int build_id_cache__add_s(const char *sbuild_id, const char *name, 560int build_id_cache__add_s(const char *sbuild_id, const char *name,
536 bool is_kallsyms, bool is_vdso) 561 bool is_kallsyms, bool is_vdso)
537{ 562{
@@ -589,6 +614,11 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
589 614
590 if (symlink(tmp, linkname) == 0) 615 if (symlink(tmp, linkname) == 0)
591 err = 0; 616 err = 0;
617
618 /* Update SDT cache : error is just warned */
619 if (build_id_cache__add_sdt_cache(sbuild_id, realname) < 0)
620 pr_debug("Failed to update/scan SDT cache for %s\n", realname);
621
592out_free: 622out_free:
593 if (!is_kallsyms) 623 if (!is_kallsyms)
594 free(realname); 624 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)
434 p = strchr(buf, '\n'); 434 p = strchr(buf, '\n');
435 if (p) 435 if (p)
436 *p = '\0'; 436 *p = '\0';
437 if (buf[0] == '#') { /* #perf_probe_event */ 437 /* #perf_probe_event or %sdt_event */
438 if (buf[0] == '#' || buf[0] == '%') {
438 entry = probe_cache_entry__new(NULL); 439 entry = probe_cache_entry__new(NULL);
439 if (!entry) { 440 if (!entry) {
440 ret = -ENOMEM; 441 ret = -ENOMEM;
441 goto out; 442 goto out;
442 } 443 }
444 if (buf[0] == '%')
445 entry->sdt = true;
443 entry->spev = strdup(buf + 1); 446 entry->spev = strdup(buf + 1);
444 if (entry->spev) 447 if (entry->spev)
445 ret = parse_perf_probe_command(buf + 1, 448 ret = parse_perf_probe_command(buf + 1,
@@ -621,19 +624,79 @@ out_err:
621 return ret; 624 return ret;
622} 625}
623 626
627static unsigned long long sdt_note__get_addr(struct sdt_note *note)
628{
629 return note->bit32 ? (unsigned long long)note->addr.a32[0]
630 : (unsigned long long)note->addr.a64[0];
631}
632
633int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
634{
635 struct probe_cache_entry *entry = NULL;
636 struct list_head sdtlist;
637 struct sdt_note *note;
638 char *buf;
639 char sdtgrp[64];
640 int ret;
641
642 INIT_LIST_HEAD(&sdtlist);
643 ret = get_sdt_note_list(&sdtlist, pathname);
644 if (ret < 0) {
645 pr_debug("Failed to get sdt note: %d\n", ret);
646 return ret;
647 }
648 list_for_each_entry(note, &sdtlist, note_list) {
649 ret = snprintf(sdtgrp, 64, "sdt_%s", note->provider);
650 if (ret < 0)
651 break;
652 /* Try to find same-name entry */
653 entry = probe_cache__find_by_name(pcache, sdtgrp, note->name);
654 if (!entry) {
655 entry = probe_cache_entry__new(NULL);
656 if (!entry) {
657 ret = -ENOMEM;
658 break;
659 }
660 entry->sdt = true;
661 ret = asprintf(&entry->spev, "%s:%s=%s", sdtgrp,
662 note->name, note->name);
663 if (ret < 0)
664 break;
665 entry->pev.event = strdup(note->name);
666 entry->pev.group = strdup(sdtgrp);
667 list_add_tail(&entry->node, &pcache->entries);
668 }
669 ret = asprintf(&buf, "p:%s/%s %s:0x%llx",
670 sdtgrp, note->name, pathname,
671 sdt_note__get_addr(note));
672 if (ret < 0)
673 break;
674 strlist__add(entry->tevlist, buf);
675 free(buf);
676 entry = NULL;
677 }
678 if (entry) {
679 list_del_init(&entry->node);
680 probe_cache_entry__delete(entry);
681 }
682 cleanup_sdt_note_list(&sdtlist);
683 return ret;
684}
685
624static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd) 686static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd)
625{ 687{
626 struct str_node *snode; 688 struct str_node *snode;
627 struct stat st; 689 struct stat st;
628 struct iovec iov[3]; 690 struct iovec iov[3];
691 const char *prefix = entry->sdt ? "%" : "#";
629 int ret; 692 int ret;
630 /* Save stat for rollback */ 693 /* Save stat for rollback */
631 ret = fstat(fd, &st); 694 ret = fstat(fd, &st);
632 if (ret < 0) 695 if (ret < 0)
633 return ret; 696 return ret;
634 697
635 pr_debug("Writing cache: #%s\n", entry->spev); 698 pr_debug("Writing cache: %s%s\n", prefix, entry->spev);
636 iov[0].iov_base = (void *)"#"; iov[0].iov_len = 1; 699 iov[0].iov_base = (void *)prefix; iov[0].iov_len = 1;
637 iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev); 700 iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev);
638 iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1; 701 iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1;
639 ret = writev(fd, iov, 3); 702 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 @@
8/* Cache of probe definitions */ 8/* Cache of probe definitions */
9struct probe_cache_entry { 9struct probe_cache_entry {
10 struct list_head node; 10 struct list_head node;
11 bool sdt;
11 struct perf_probe_event pev; 12 struct perf_probe_event pev;
12 char *spev; 13 char *spev;
13 struct strlist *tevlist; 14 struct strlist *tevlist;
@@ -35,6 +36,7 @@ struct probe_cache *probe_cache__new(const char *target);
35int probe_cache__add_entry(struct probe_cache *pcache, 36int probe_cache__add_entry(struct probe_cache *pcache,
36 struct perf_probe_event *pev, 37 struct perf_probe_event *pev,
37 struct probe_trace_event *tevs, int ntevs); 38 struct probe_trace_event *tevs, int ntevs);
39int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname);
38int probe_cache__commit(struct probe_cache *pcache); 40int probe_cache__commit(struct probe_cache *pcache);
39void probe_cache__purge(struct probe_cache *pcache); 41void probe_cache__purge(struct probe_cache *pcache);
40void probe_cache__delete(struct probe_cache *pcache); 42void probe_cache__delete(struct probe_cache *pcache);