Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754021AbbHOLuv (ORCPT ); Sat, 15 Aug 2015 07:50:51 -0400 Received: from mail7.hitachi.co.jp ([133.145.228.42]:45270 "EHLO mail7.hitachi.co.jp" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750943AbbHOLsH (ORCPT ); Sat, 15 Aug 2015 07:48:07 -0400 X-AuditID: 85900ec0-9ebcbb9000001a57-36-55cf26a154e2 Subject: [RFC PATCH perf/core v3 13/17] perf buildid-cache: Scan and import user SDT events to probe cache From: Masami Hiramatsu To: Arnaldo Carvalho de Melo Cc: Peter Zijlstra , linux-kernel@vger.kernel.org, Adrian Hunter , Ingo Molnar , Paul Mackerras , Jiri Olsa , Namhyung Kim , Borislav Petkov , Hemant Kumar Date: Sat, 15 Aug 2015 20:43:21 +0900 Message-ID: <20150815114321.13642.66453.stgit@localhost.localdomain> In-Reply-To: <20150815114252.13642.62690.stgit@localhost.localdomain> References: <20150815114252.13642.62690.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit X-Brightmail-Tracker: AAAAAA== Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7080 Lines: 226 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 --- Changes in v3: - Use sdt_ prefix for group name - Use HAVE_LIBELF_SUPPORT instead of CONFIG_LIBELF --- 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 b68f5f0..31eb8d9 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; @@ -432,6 +433,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) { @@ -470,20 +488,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 5ee892f..7e2b4f8 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -403,9 +403,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); @@ -577,14 +580,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; + entry = probe_cache__find_by_name(pcache, sdtgrp, note->name); + if (entry) /* We've already scanned */ + continue; + + 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(note->provider); + 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); + list_add_tail(&entry->list, &pcache->list); + 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 391fde0..9a9b0c5 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h @@ -18,6 +18,7 @@ int probe_file__del_events(int fd, struct strfilter *filter); /* Cache of probe definitions */ struct probe_cache_entry { struct list_head list; + bool sdt; struct perf_probe_event pev; char *spev; struct strlist *tevlist; @@ -32,6 +33,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, -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/