Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752866AbcDZJEb (ORCPT ); Tue, 26 Apr 2016 05:04:31 -0400 Received: from mail.kernel.org ([198.145.29.136]:47379 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751735AbcDZJE2 (ORCPT ); Tue, 26 Apr 2016 05:04:28 -0400 From: Masami Hiramatsu To: Arnaldo Carvalho de Melo Cc: Masami Hiramatsu , linux-kernel@vger.kernel.org, Namhyung Kim , Peter Zijlstra , Ingo Molnar , Hemant Kumar , Ananth N Mavinakayanahalli Subject: [PATCH perf/core v4 14/19] perf buildid-cache: Scan and import user SDT events to probe cache Date: Tue, 26 Apr 2016 18:04:22 +0900 Message-Id: <20160426090422.11891.92396.stgit@devbox> X-Mailer: git-send-email 2.1.0 In-Reply-To: <20160426090200.11891.43944.stgit@devbox> References: <20160426090200.11891.43944.stgit@devbox> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6961 Lines: 223 From: Masami Hiramatsu perf buildid-cache --add 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_:=". 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 Signed-off-by: Masami Hiramatsu --- Changes in v4: - Fix a bug to copy correct group name to entries. - Fix to consolidate same-name entries. --- tools/perf/util/build-id.c | 27 +++++++++++++++-- tools/perf/util/probe-file.c | 67 ++++++++++++++++++++++++++++++++++++++++-- tools/perf/util/probe-file.h | 2 + 3 files changed, 90 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index a7da315..49a467b9 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; @@ -490,6 +491,23 @@ int build_id_cache__list_build_ids(const char *pathname, return ret; } +#ifdef HAVE_LIBELF_SUPPORT +static void build_id_cache__add_sdt_cache(const char *sbuild_id, + const char *realname) +{ + struct probe_cache *cache; + + cache = probe_cache__new(sbuild_id); + if (!cache) + return; + if (probe_cache__scan_sdt(cache, realname) >= 0) + probe_cache__commit(cache); + probe_cache__delete(cache); +} +#else +#define build_id_cache__add_sdt_cache(sbuild_id, realname) do { } while (0) +#endif + int build_id_cache__add_s(const char *sbuild_id, const char *name, bool is_kallsyms, bool is_vdso) { @@ -533,20 +551,23 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; } + /* Make a symbolic link */ if (!build_id_cache__linkname(sbuild_id, linkname, size)) goto out_free; + tmp = strrchr(linkname, '/'); *tmp = '\0'; - if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) goto out_free; - *tmp = '/'; tmp = dir_name + strlen(buildid_dir) - 5; memcpy(tmp, "../..", 5); - if (symlink(tmp, linkname) == 0) err = 0; + + /* Update SDT cache */ + build_id_cache__add_sdt_cache(sbuild_id, 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 46f006e..c10a647 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -428,9 +428,12 @@ 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); entry->spev = strdup(buf + 1); + if (buf[0] == '%') + entry->sdt = true; ret = parse_perf_probe_command(buf + 1, &entry->pev); if (!entry->spev || ret < 0) { probe_cache_entry__delete(entry); @@ -602,14 +605,72 @@ 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->list, &pcache->list); + } + 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) + 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 iovec iov[3]; + const char *prefix = entry->sdt ? "%" : "#"; int 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 ba7b6d3..55322f1 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h @@ -21,6 +21,7 @@ int probe_file__del_strlist(int fd, struct strlist *namelist); /* Cache of probe definitions */ struct probe_cache_entry { struct list_head list; + 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__delete(struct probe_cache *pcache); int probe_cache__remove_entries(struct probe_cache *pcache,