linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH perf/core v13 00/15] perf-probe --cache and SDT support
@ 2016-07-01  8:03 Masami Hiramatsu
  2016-07-01  8:03 ` [PATCH perf/core v13 01/15] perf probe: Use cache entry if possible Masami Hiramatsu
                   ` (15 more replies)
  0 siblings, 16 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:03 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

Hi,

Here is the 13th version of the patchset for probe-cache and 
initial SDT support.

Here is the previous v12: https://lkml.org/lkml/2016/6/24/147

In this version, I've removed the patch for perf-list to show
SDT events, since at this point we don't support SDT from
perf record. I also change perf-probe --cache --list to show
cached events on only valid (existing) binaries.

Thank you,

---

Hemant Kumar (1):
      perf/sdt: ELF support for SDT

Masami Hiramatsu (14):
      perf probe: Use cache entry if possible
      perf probe: Show all cached probes
      perf probe: Remove caches when --cache is given
      perf probe: Add group name support
      perf buildid-cache: Scan and import user SDT events to probe cache
      perf probe: Accept %sdt and %cached event name
      perf-probe: Make --list shows only available cached events
      perf: probe-cache: Add for_each_probe_cache_entry() wrapper
      perf probe: Allow wildcard for cached events
      perf probe: Search SDT/cached event from all probe caches
      perf probe: Support @BUILDID or @FILE suffix for SDT events
      perf probe: Support a special SDT probe format
      perf build: Add sdt feature detection
      perf-test: Add a test case for SDT event


 tools/perf/Documentation/perf-buildid-cache.txt |    3 
 tools/perf/Documentation/perf-probe.txt         |   30 +-
 tools/perf/Makefile.perf                        |    3 
 tools/perf/builtin-probe.c                      |   31 ++
 tools/perf/config/Makefile                      |   10 +
 tools/perf/tests/Build                          |    1 
 tools/perf/tests/builtin-test.c                 |    4 
 tools/perf/tests/make                           |    3 
 tools/perf/tests/sdt.c                          |  115 +++++++
 tools/perf/tests/tests.h                        |    1 
 tools/perf/util/build-id.c                      |  212 +++++++++++++
 tools/perf/util/build-id.h                      |    4 
 tools/perf/util/probe-event.c                   |  366 +++++++++++++++++++++--
 tools/perf/util/probe-event.h                   |    1 
 tools/perf/util/probe-file.c                    |  226 +++++++++++++-
 tools/perf/util/probe-file.h                    |   15 +
 tools/perf/util/symbol-elf.c                    |  252 ++++++++++++++++
 tools/perf/util/symbol.h                        |   22 +
 18 files changed, 1235 insertions(+), 64 deletions(-)
 create mode 100644 tools/perf/tests/sdt.c

--
Masami Hiramatsu

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 01/15] perf probe: Use cache entry if possible
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
@ 2016-07-01  8:03 ` Masami Hiramatsu
  2016-07-01 13:20   ` Arnaldo Carvalho de Melo
  2016-07-05 10:16   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  2016-07-01  8:03 ` [PATCH perf/core v13 02/15] perf probe: Show all cached probes Masami Hiramatsu
                   ` (14 subsequent siblings)
  15 siblings, 2 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:03 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

Before analyzing debuginfo, try to find a corresponding entry
from probe cache always. This does not depend on --cache,
the --cache enables to store/update cache, but looking up
the cache is always enabled.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v12:
  - Rename strlist__for_each to  strlist__for_each_entry.

 Changes in v6:
  - Remove fallback lookup routine by using function name
    as cached event name, because it should be done by following
    patch which supports %cached-event.
---
 tools/perf/util/probe-event.c |   65 ++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/probe-file.c  |   20 ++++++++++++-
 tools/perf/util/probe-file.h  |    5 +++
 3 files changed, 86 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 55f41d5..47b6b8b 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2474,17 +2474,24 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,
 	char buf[64];
 	int ret;
 
+	/* If probe_event or trace_event already have the name, reuse it */
 	if (pev->event)
 		event = pev->event;
-	else
+	else if (tev->event)
+		event = tev->event;
+	else {
+		/* Or generate new one from probe point */
 		if (pev->point.function &&
 			(strncmp(pev->point.function, "0x", 2) != 0) &&
 			!strisglob(pev->point.function))
 			event = pev->point.function;
 		else
 			event = tev->point.realname;
+	}
 	if (pev->group)
 		group = pev->group;
+	else if (tev->group)
+		group = tev->group;
 	else
 		group = PERFPROBE_GROUP;
 
@@ -2531,7 +2538,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 	for (i = 0; i < ntevs; i++) {
 		tev = &tevs[i];
 		/* Skip if the symbol is out of .text or blacklisted */
-		if (!tev->point.symbol)
+		if (!tev->point.symbol && !pev->uprobes)
 			continue;
 
 		/* Set new name for tev (and update namelist) */
@@ -2844,6 +2851,55 @@ errout:
 
 bool __weak arch__prefers_symtab(void) { return false; }
 
+static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
+					      struct probe_trace_event **tevs)
+{
+	struct probe_cache *cache;
+	struct probe_cache_entry *entry;
+	struct probe_trace_event *tev;
+	struct str_node *node;
+	int ret, i;
+
+	cache = probe_cache__new(pev->target);
+	if (!cache)
+		return 0;
+
+	entry = probe_cache__find(cache, pev);
+	if (!entry) {
+		ret = 0;
+		goto out;
+	}
+
+	ret = strlist__nr_entries(entry->tevlist);
+	if (ret > probe_conf.max_probes) {
+		pr_debug("Too many entries matched in the cache of %s\n",
+			 pev->target ? : "kernel");
+		ret = -E2BIG;
+		goto out;
+	}
+
+	*tevs = zalloc(ret * sizeof(*tev));
+	if (!*tevs) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	i = 0;
+	strlist__for_each_entry(node, entry->tevlist) {
+		tev = &(*tevs)[i++];
+		ret = parse_probe_trace_command(node->s, tev);
+		if (ret < 0)
+			goto out;
+		/* Set the uprobes attribute as same as original */
+		tev->uprobes = pev->uprobes;
+	}
+	ret = i;
+
+out:
+	probe_cache__delete(cache);
+	return ret;
+}
+
 static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 					 struct probe_trace_event **tevs)
 {
@@ -2866,6 +2922,11 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 	if (ret > 0)
 		return ret;
 
+	/* At first, we need to lookup cache entry */
+	ret = find_probe_trace_events_from_cache(pev, tevs);
+	if (ret > 0)
+		return ret;	/* Found in probe cache */
+
 	if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) {
 		ret = find_probe_trace_events_from_map(pev, tevs);
 		if (ret > 0)
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 1c12c1a..a94ee47 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -524,7 +524,7 @@ static bool streql(const char *a, const char *b)
 	return !strcmp(a, b);
 }
 
-static struct probe_cache_entry *
+struct probe_cache_entry *
 probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
 {
 	struct probe_cache_entry *entry = NULL;
@@ -548,6 +548,24 @@ found:
 	return entry;
 }
 
+struct probe_cache_entry *
+probe_cache__find_by_name(struct probe_cache *pcache,
+			  const char *group, const char *event)
+{
+	struct probe_cache_entry *entry = NULL;
+
+	list_for_each_entry(entry, &pcache->entries, node) {
+		/* Hit if same event name or same command-string */
+		if (streql(entry->pev.group, group) &&
+		    streql(entry->pev.event, event))
+			goto found;
+	}
+	entry = NULL;
+
+found:
+	return entry;
+}
+
 int probe_cache__add_entry(struct probe_cache *pcache,
 			   struct perf_probe_event *pev,
 			   struct probe_trace_event *tevs, int ntevs)
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index d872e3d..910aa74 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -38,5 +38,8 @@ int probe_cache__add_entry(struct probe_cache *pcache,
 int probe_cache__commit(struct probe_cache *pcache);
 void probe_cache__purge(struct probe_cache *pcache);
 void probe_cache__delete(struct probe_cache *pcache);
-
+struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
+					    struct perf_probe_event *pev);
+struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
+					const char *group, const char *event);
 #endif

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 02/15] perf probe: Show all cached probes
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
  2016-07-01  8:03 ` [PATCH perf/core v13 01/15] perf probe: Use cache entry if possible Masami Hiramatsu
@ 2016-07-01  8:03 ` Masami Hiramatsu
  2016-07-01 13:51   ` Arnaldo Carvalho de Melo
  2016-07-05 10:17   ` [tip:perf/core] perf probe: Show all cached probes tip-bot for Masami Hiramatsu
  2016-07-01  8:03 ` [PATCH perf/core v13 03/15] perf probe: Remove caches when --cache is given Masami Hiramatsu
                   ` (13 subsequent siblings)
  15 siblings, 2 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:03 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

perf probe --list shows all cached probes when --cache
is given. Each caches are shown with on which binary that
probed. e.g.
  -----
  # perf probe --cache vfs_read \$params
  # perf probe --cache -x /lib64/libc-2.17.so getaddrinfo \$params
  # perf probe --cache --list
  [kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1):
  vfs_read $params
  /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc):
  getaddrinfo $params
  -----
Note that $params requires debuginfo.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v12:
  - Rename strlist__for_each to strlist__for_each_entry.
 Changes in v11:
  - Make build_id_cache__list_all() returns strlist directly. (no error code)
  - Harden build_id_cache__list_all() to check directory entries.
 Changes in v7:
  - Remove the top '/' from binary name if it is not a regular file.
---
 tools/perf/Documentation/perf-probe.txt |    8 ++
 tools/perf/builtin-probe.c              |    2 -
 tools/perf/util/build-id.c              |  108 ++++++++++++++++++++++++++++++-
 tools/perf/util/build-id.h              |    3 +
 tools/perf/util/probe-event.c           |    3 +
 tools/perf/util/probe-file.c            |   66 ++++++++++++++++++-
 tools/perf/util/probe-file.h            |    1 
 7 files changed, 184 insertions(+), 7 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 947db6f..5a70d45 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -67,7 +67,10 @@ OPTIONS
 
 -l::
 --list[=[GROUP:]EVENT]::
-	List up current probe events. This can also accept filtering patterns of event names.
+	List up current probe events. This can also accept filtering patterns of
+	event names.
+	When this is used with --cache, perf shows all cached probes instead of
+	the live probes.
 
 -L::
 --line=::
@@ -110,8 +113,9 @@ OPTIONS
 	adding and removal operations.
 
 --cache::
-	Cache the probes (with --add option). Any events which successfully added
+	(With --add) Cache the probes. Any events which successfully added
 	are also stored in the cache file.
+	(With --list) Show cached probes.
 
 --max-probes=NUM::
 	Set the maximum number of probe points for an event. Default is 128.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 3426232..0bb9084 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -44,7 +44,7 @@
 
 #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
 #define DEFAULT_FUNC_FILTER "!_*"
-#define DEFAULT_LIST_FILTER "*:*"
+#define DEFAULT_LIST_FILTER "*"
 
 /* Session management structure */
 static struct {
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 62b1473..1c49620 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -165,8 +165,7 @@ retry:
 	return NULL;
 }
 
-static char *build_id_cache__linkname(const char *sbuild_id, char *bf,
-				      size_t size)
+char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size)
 {
 	char *tmp = bf;
 	int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
@@ -176,6 +175,36 @@ static char *build_id_cache__linkname(const char *sbuild_id, char *bf,
 	return bf;
 }
 
+char *build_id_cache__origname(const char *sbuild_id)
+{
+	char *linkname;
+	char buf[PATH_MAX];
+	char *ret = NULL, *p;
+	size_t offs = 5;	/* == strlen("../..") */
+
+	linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
+	if (!linkname)
+		return NULL;
+
+	if (readlink(linkname, buf, PATH_MAX) < 0)
+		goto out;
+	/* The link should be "../..<origpath>/<sbuild_id>" */
+	p = strrchr(buf, '/');	/* Cut off the "/<sbuild_id>" */
+	if (p && (p > buf + offs)) {
+		*p = '\0';
+		if (buf[offs + 1] == '[')
+			offs++;	/*
+				 * This is a DSO name, like [kernel.kallsyms].
+				 * Skip the first '/', since this is not the
+				 * cache of a regular file.
+				 */
+		ret = strdup(buf + offs);	/* Skip "../..[/]" */
+	}
+out:
+	free(linkname);
+	return ret;
+}
+
 static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
 {
 	return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
@@ -387,6 +416,81 @@ void disable_buildid_cache(void)
 	no_buildid_cache = true;
 }
 
+static bool lsdir_bid_head_filter(const char *name __maybe_unused,
+				  struct dirent *d __maybe_unused)
+{
+	return (strlen(d->d_name) == 2) &&
+		isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]);
+}
+
+static bool lsdir_bid_tail_filter(const char *name __maybe_unused,
+				  struct dirent *d __maybe_unused)
+{
+	int i = 0;
+	while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3)
+		i++;
+	return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0');
+}
+
+struct strlist *build_id_cache__list_all(void)
+{
+	struct strlist *toplist, *linklist = NULL, *bidlist;
+	struct str_node *nd, *nd2;
+	char *topdir, *linkdir = NULL;
+	char sbuild_id[SBUILD_ID_SIZE];
+
+	/* Open the top-level directory */
+	if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
+		return NULL;
+
+	bidlist = strlist__new(NULL, NULL);
+	if (!bidlist)
+		goto out;
+
+	toplist = lsdir(topdir, lsdir_bid_head_filter);
+	if (!toplist) {
+		pr_debug("Error in lsdir(%s): %d\n", topdir, errno);
+		/* If there is no buildid cache, return an empty list */
+		if (errno == ENOENT)
+			goto out;
+		goto err_out;
+	}
+
+	strlist__for_each_entry(nd, toplist) {
+		if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0)
+			goto err_out;
+		/* Open the lower-level directory */
+		linklist = lsdir(linkdir, lsdir_bid_tail_filter);
+		if (!linklist) {
+			pr_debug("Error in lsdir(%s): %d\n", linkdir, errno);
+			goto err_out;
+		}
+		strlist__for_each_entry(nd2, linklist) {
+			if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s",
+				     nd->s, nd2->s) != SBUILD_ID_SIZE - 1)
+				goto err_out;
+			if (strlist__add(bidlist, sbuild_id) < 0)
+				goto err_out;
+		}
+		strlist__delete(linklist);
+		zfree(&linkdir);
+	}
+
+out_free:
+	strlist__delete(toplist);
+out:
+	free(topdir);
+
+	return bidlist;
+
+err_out:
+	strlist__delete(linklist);
+	zfree(&linkdir);
+	strlist__delete(bidlist);
+	bidlist = NULL;
+	goto out_free;
+}
+
 char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
 			       bool is_kallsyms, bool is_vdso)
 {
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index d8c7f2f..b742e27 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -30,8 +30,11 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);
 int perf_session__write_buildid_table(struct perf_session *session, int fd);
 int perf_session__cache_build_ids(struct perf_session *session);
 
+char *build_id_cache__origname(const char *sbuild_id);
+char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
 char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
 			       bool is_kallsyms, bool is_vdso);
+struct strlist *build_id_cache__list_all(void);
 int build_id_cache__list_build_ids(const char *pathname,
 				   struct strlist **result);
 bool build_id_cache__cached(const char *sbuild_id);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 47b6b8b..f81b5dd 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2366,6 +2366,9 @@ int show_perf_probe_events(struct strfilter *filter)
 
 	setup_pager();
 
+	if (probe_conf.cache)
+		return probe_cache__show_all_caches(filter);
+
 	ret = init_probe_symbol_maps(false);
 	if (ret < 0)
 		return ret;
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index a94ee47..156e3d8 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -367,10 +367,17 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
 {
 	char cpath[PATH_MAX];
 	char sbuildid[SBUILD_ID_SIZE];
-	char *dir_name;
+	char *dir_name = NULL;
 	bool is_kallsyms = !target;
 	int ret, fd;
 
+	if (target && build_id_cache__cached(target)) {
+		/* This is a cached buildid */
+		strncpy(sbuildid, target, SBUILD_ID_SIZE);
+		dir_name = build_id_cache__linkname(sbuildid, NULL, 0);
+		goto found;
+	}
+
 	if (target)
 		ret = filename__sprintf_build_id(target, sbuildid);
 	else {
@@ -394,8 +401,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
 
 	dir_name = build_id_cache__cachedir(sbuildid, target, is_kallsyms,
 					    false);
-	if (!dir_name)
+found:
+	if (!dir_name) {
+		pr_debug("Failed to get cache from %s\n", target);
 		return -ENOMEM;
+	}
 
 	snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
 	fd = open(cpath, O_CREAT | O_RDWR, 0644);
@@ -673,3 +683,55 @@ int probe_cache__commit(struct probe_cache *pcache)
 out:
 	return ret;
 }
+
+static int probe_cache__show_entries(struct probe_cache *pcache,
+				     struct strfilter *filter)
+{
+	struct probe_cache_entry *entry;
+	char buf[128], *ptr;
+
+	list_for_each_entry(entry, &pcache->entries, node) {
+		if (entry->pev.event) {
+			ptr = buf;
+			snprintf(buf, 128, "%s:%s",
+				 entry->pev.group, entry->pev.event);
+		} else
+			ptr = entry->spev;
+		if (strfilter__compare(filter, ptr))
+			printf("%s\n", entry->spev);
+	}
+	return 0;
+}
+
+/* Show all cached probes */
+int probe_cache__show_all_caches(struct strfilter *filter)
+{
+	struct probe_cache *pcache;
+	struct strlist *bidlist;
+	struct str_node *nd;
+	char *buf = strfilter__string(filter);
+
+	pr_debug("list cache with filter: %s\n", buf);
+	free(buf);
+
+	bidlist = build_id_cache__list_all();
+	if (!bidlist) {
+		pr_debug("Failed to get buildids: %d\n", errno);
+		return -EINVAL;
+	}
+	strlist__for_each_entry(nd, bidlist) {
+		pcache = probe_cache__new(nd->s);
+		if (!pcache)
+			continue;
+		if (!list_empty(&pcache->entries)) {
+			buf = build_id_cache__origname(nd->s);
+			printf("%s (%s):\n", buf, nd->s);
+			free(buf);
+			probe_cache__show_entries(pcache, filter);
+		}
+		probe_cache__delete(pcache);
+	}
+	strlist__delete(bidlist);
+
+	return 0;
+}
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 910aa74..0009b8a 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -42,4 +42,5 @@ struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
 					    struct perf_probe_event *pev);
 struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
 					const char *group, const char *event);
+int probe_cache__show_all_caches(struct strfilter *filter);
 #endif

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 03/15] perf probe: Remove caches when --cache is given
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
  2016-07-01  8:03 ` [PATCH perf/core v13 01/15] perf probe: Use cache entry if possible Masami Hiramatsu
  2016-07-01  8:03 ` [PATCH perf/core v13 02/15] perf probe: Show all cached probes Masami Hiramatsu
@ 2016-07-01  8:03 ` Masami Hiramatsu
  2016-07-05 10:17   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  2016-07-01  8:03 ` [PATCH perf/core v13 04/15] perf/sdt: ELF support for SDT Masami Hiramatsu
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:03 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

perf-probe --del removes caches when --cache is given.
Note that the delete pattern is not same as normal events.

If you cached probes with event name, --del "eventname"
works as expected. However, if you skipped it, the cached
probes doesn't have actual event name. In that case
 --del "probe-desc" is required (wildcard is acceptable).
For example a cache entry has the probe-desc "vfs_read $params",
you can remove it with --del 'vfs_read*'.

  -----
  # perf probe --cache --list
  /[kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1):
  vfs_read $params
  /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc):
  getaddrinfo $params

  # perf probe --cache --del vfs_read\*
  Removed cached event: probe:vfs_read

  # perf probe --cache --list
  /[kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1):
  /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc):
  getaddrinfo $params
  -----

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v12:
  - Rename strlist__for_each to strlist__for_each_entry.
 Changes in v11:
  - Fix to check the result of purging cache entries.
  - Rename probe_cache__remove_entries to probe_cache__filter_purge.
 Changes in v9:
  - Fix to show which event is deleted (Thanks Hemant!)
 Changes in v4:
  - move del_perf_probe_caches() into builtin-probe.c since
    command-line related delete procedure is there now.
---
 tools/perf/Documentation/perf-probe.txt |    1 +
 tools/perf/builtin-probe.c              |   29 +++++++++++++++++++++++++
 tools/perf/util/probe-file.c            |   36 ++++++++++++++++++++++++-------
 tools/perf/util/probe-file.h            |    2 ++
 4 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 5a70d45..8d09173 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -116,6 +116,7 @@ OPTIONS
 	(With --add) Cache the probes. Any events which successfully added
 	are also stored in the cache file.
 	(With --list) Show cached probes.
+	(With --del) Remove cached probes.
 
 --max-probes=NUM::
 	Set the maximum number of probe points for an event. Default is 128.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 0bb9084..a1a5cd1 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -363,6 +363,32 @@ out_cleanup:
 	return ret;
 }
 
+static int del_perf_probe_caches(struct strfilter *filter)
+{
+	struct probe_cache *cache;
+	struct strlist *bidlist;
+	struct str_node *nd;
+	int ret;
+
+	bidlist = build_id_cache__list_all();
+	if (!bidlist) {
+		ret = -errno;
+		pr_debug("Failed to get buildids: %d\n", ret);
+		return ret ?: -ENOMEM;
+	}
+
+	strlist__for_each_entry(nd, bidlist) {
+		cache = probe_cache__new(nd->s);
+		if (!cache)
+			continue;
+		if (probe_cache__filter_purge(cache, filter) < 0 ||
+		    probe_cache__commit(cache) < 0)
+			pr_warning("Failed to remove entries for %s\n", nd->s);
+		probe_cache__delete(cache);
+	}
+	return 0;
+}
+
 static int perf_del_probe_events(struct strfilter *filter)
 {
 	int ret, ret2, ufd = -1, kfd = -1;
@@ -375,6 +401,9 @@ static int perf_del_probe_events(struct strfilter *filter)
 
 	pr_debug("Delete filter: \'%s\'\n", str);
 
+	if (probe_conf.cache)
+		return del_perf_probe_caches(filter);
+
 	/* Get current event names */
 	ret = probe_file__open_both(&kfd, &ufd, PF_FL_RW);
 	if (ret < 0)
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 156e3d8..6cb6ec0 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -684,20 +684,40 @@ out:
 	return ret;
 }
 
+static bool probe_cache_entry__compare(struct probe_cache_entry *entry,
+				       struct strfilter *filter)
+{
+	char buf[128], *ptr = entry->spev;
+
+	if (entry->pev.event) {
+		snprintf(buf, 128, "%s:%s", entry->pev.group, entry->pev.event);
+		ptr = buf;
+	}
+	return strfilter__compare(filter, ptr);
+}
+
+int probe_cache__filter_purge(struct probe_cache *pcache,
+			      struct strfilter *filter)
+{
+	struct probe_cache_entry *entry, *tmp;
+
+	list_for_each_entry_safe(entry, tmp, &pcache->entries, node) {
+		if (probe_cache_entry__compare(entry, filter)) {
+			pr_info("Removed cached event: %s\n", entry->spev);
+			list_del_init(&entry->node);
+			probe_cache_entry__delete(entry);
+		}
+	}
+	return 0;
+}
+
 static int probe_cache__show_entries(struct probe_cache *pcache,
 				     struct strfilter *filter)
 {
 	struct probe_cache_entry *entry;
-	char buf[128], *ptr;
 
 	list_for_each_entry(entry, &pcache->entries, node) {
-		if (entry->pev.event) {
-			ptr = buf;
-			snprintf(buf, 128, "%s:%s",
-				 entry->pev.group, entry->pev.event);
-		} else
-			ptr = entry->spev;
-		if (strfilter__compare(filter, ptr))
+		if (probe_cache_entry__compare(entry, filter))
 			printf("%s\n", entry->spev);
 	}
 	return 0;
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 0009b8a..0ed1fc5 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -38,6 +38,8 @@ int probe_cache__add_entry(struct probe_cache *pcache,
 int probe_cache__commit(struct probe_cache *pcache);
 void probe_cache__purge(struct probe_cache *pcache);
 void probe_cache__delete(struct probe_cache *pcache);
+int probe_cache__filter_purge(struct probe_cache *pcache,
+			      struct strfilter *filter);
 struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
 					    struct perf_probe_event *pev);
 struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 04/15] perf/sdt: ELF support for SDT
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (2 preceding siblings ...)
  2016-07-01  8:03 ` [PATCH perf/core v13 03/15] perf probe: Remove caches when --cache is given Masami Hiramatsu
@ 2016-07-01  8:03 ` Masami Hiramatsu
  2016-07-01 18:56   ` Arnaldo Carvalho de Melo
  2016-07-05 10:18   ` [tip:perf/core] perf sdt: " tip-bot for Hemant Kumar
  2016-07-01  8:04 ` [PATCH perf/core v13 05/15] perf probe: Add group name support Masami Hiramatsu
                   ` (11 subsequent siblings)
  15 siblings, 2 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:03 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

From: Hemant Kumar <hemant@linux.vnet.ibm.com>

This patch serves the initial support to identify and list SDT events in binaries.
When programs containing SDT markers are compiled, gcc with the help of assembler
directives identifies them and places them in the section ".note.stapsdt". To find
these markers from the binaries, one needs to traverse through this section and
parse the relevant details like the name, type and location of the marker. Also,
the original location could be skewed due to the effect of prelinking. If that is
the case, the locations need to be adjusted.

The functions in this patch open a given ELF, find out the SDT section, parse the
relevant details, adjust the location (if necessary) and populate them in a list.

A typical note entry in ".note.stapsdt" section is as follows :


                                 |--nhdr.n_namesz--|
                ------------------------------------
                |      nhdr      |     "stapsdt"   |
        -----   |----------------------------------|
         |      |  <location>       <base_address> |
         |      |  <semaphore>                     |
nhdr.n_descsize |  "provider_name"   "note_name"   |
         |      |   <args>                         |
        -----   |----------------------------------|
                |      nhdr      |     "stapsdt"   |
                |...

The above shows an excerpt from the section ".note.stapsdt".
'nhdr' is a structure which has the note name size (n_namesz), note
description size (n_desc_sz) and note type (n_type). So, in order to
parse the note note info, we need nhdr to tell us where to start from.
As can be seen from <sys/sdt.h>, the name of the SDT notes given is "stapsdt".
But this is not the identifier of the note.
After that, we go to description of the note to find out its location, the
address of the ".stapsdt.base" section and the semaphore address.
Then, we find the provider name and the SDT marker name and then follow the
arguments.

Signed-off-by: Hemant Kumar <hemant@linux.vnet.ibm.com>
Reviewed-by: Masami Hiramatsu <mhiramat@kernel.org>
Acked-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/util/symbol-elf.c |  252 ++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/symbol.h     |   22 ++++
 2 files changed, 274 insertions(+)

diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 87a297d..e74ce17 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1781,6 +1781,258 @@ void kcore_extract__delete(struct kcore_extract *kce)
 	unlink(kce->extract_filename);
 }
 
+/**
+ * populate_sdt_note : Parse raw data and identify SDT note
+ * @elf: elf of the opened file
+ * @data: raw data of a section with description offset applied
+ * @len: note description size
+ * @type: type of the note
+ * @sdt_notes: List to add the SDT note
+ *
+ * Responsible for parsing the @data in section .note.stapsdt in @elf and
+ * if its an SDT note, it appends to @sdt_notes list.
+ */
+static int populate_sdt_note(Elf **elf, const char *data, size_t len,
+			     struct list_head *sdt_notes)
+{
+	const char *provider, *name;
+	struct sdt_note *tmp = NULL;
+	GElf_Ehdr ehdr;
+	GElf_Addr base_off = 0;
+	GElf_Shdr shdr;
+	int ret = -EINVAL;
+
+	union {
+		Elf64_Addr a64[NR_ADDR];
+		Elf32_Addr a32[NR_ADDR];
+	} buf;
+
+	Elf_Data dst = {
+		.d_buf = &buf, .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
+		.d_size = gelf_fsize((*elf), ELF_T_ADDR, NR_ADDR, EV_CURRENT),
+		.d_off = 0, .d_align = 0
+	};
+	Elf_Data src = {
+		.d_buf = (void *) data, .d_type = ELF_T_ADDR,
+		.d_version = EV_CURRENT, .d_size = dst.d_size, .d_off = 0,
+		.d_align = 0
+	};
+
+	tmp = (struct sdt_note *)calloc(1, sizeof(struct sdt_note));
+	if (!tmp) {
+		ret = -ENOMEM;
+		goto out_err;
+	}
+
+	INIT_LIST_HEAD(&tmp->note_list);
+
+	if (len < dst.d_size + 3)
+		goto out_free_note;
+
+	/* Translation from file representation to memory representation */
+	if (gelf_xlatetom(*elf, &dst, &src,
+			  elf_getident(*elf, NULL)[EI_DATA]) == NULL) {
+		pr_err("gelf_xlatetom : %s\n", elf_errmsg(-1));
+		goto out_free_note;
+	}
+
+	/* Populate the fields of sdt_note */
+	provider = data + dst.d_size;
+
+	name = (const char *)memchr(provider, '\0', data + len - provider);
+	if (name++ == NULL)
+		goto out_free_note;
+
+	tmp->provider = strdup(provider);
+	if (!tmp->provider) {
+		ret = -ENOMEM;
+		goto out_free_note;
+	}
+	tmp->name = strdup(name);
+	if (!tmp->name) {
+		ret = -ENOMEM;
+		goto out_free_prov;
+	}
+
+	if (gelf_getclass(*elf) == ELFCLASS32) {
+		memcpy(&tmp->addr, &buf, 3 * sizeof(Elf32_Addr));
+		tmp->bit32 = true;
+	} else {
+		memcpy(&tmp->addr, &buf, 3 * sizeof(Elf64_Addr));
+		tmp->bit32 = false;
+	}
+
+	if (!gelf_getehdr(*elf, &ehdr)) {
+		pr_debug("%s : cannot get elf header.\n", __func__);
+		ret = -EBADF;
+		goto out_free_name;
+	}
+
+	/* Adjust the prelink effect :
+	 * Find out the .stapsdt.base section.
+	 * This scn will help us to handle prelinking (if present).
+	 * Compare the retrieved file offset of the base section with the
+	 * base address in the description of the SDT note. If its different,
+	 * then accordingly, adjust the note location.
+	 */
+	if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) {
+		base_off = shdr.sh_offset;
+		if (base_off) {
+			if (tmp->bit32)
+				tmp->addr.a32[0] = tmp->addr.a32[0] + base_off -
+					tmp->addr.a32[1];
+			else
+				tmp->addr.a64[0] = tmp->addr.a64[0] + base_off -
+					tmp->addr.a64[1];
+		}
+	}
+
+	list_add_tail(&tmp->note_list, sdt_notes);
+	return 0;
+
+out_free_name:
+	free(tmp->name);
+out_free_prov:
+	free(tmp->provider);
+out_free_note:
+	free(tmp);
+out_err:
+	return ret;
+}
+
+/**
+ * construct_sdt_notes_list : constructs a list of SDT notes
+ * @elf : elf to look into
+ * @sdt_notes : empty list_head
+ *
+ * Scans the sections in 'elf' for the section
+ * .note.stapsdt. It, then calls populate_sdt_note to find
+ * out the SDT events and populates the 'sdt_notes'.
+ */
+static int construct_sdt_notes_list(Elf *elf, struct list_head *sdt_notes)
+{
+	GElf_Ehdr ehdr;
+	Elf_Scn *scn = NULL;
+	Elf_Data *data;
+	GElf_Shdr shdr;
+	size_t shstrndx, next;
+	GElf_Nhdr nhdr;
+	size_t name_off, desc_off, offset;
+	int ret = 0;
+
+	if (gelf_getehdr(elf, &ehdr) == NULL) {
+		ret = -EBADF;
+		goto out_ret;
+	}
+	if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
+		ret = -EBADF;
+		goto out_ret;
+	}
+
+	/* Look for the required section */
+	scn = elf_section_by_name(elf, &ehdr, &shdr, SDT_NOTE_SCN, NULL);
+	if (!scn) {
+		ret = -ENOENT;
+		goto out_ret;
+	}
+
+	if ((shdr.sh_type != SHT_NOTE) || (shdr.sh_flags & SHF_ALLOC)) {
+		ret = -ENOENT;
+		goto out_ret;
+	}
+
+	data = elf_getdata(scn, NULL);
+
+	/* Get the SDT notes */
+	for (offset = 0; (next = gelf_getnote(data, offset, &nhdr, &name_off,
+					      &desc_off)) > 0; offset = next) {
+		if (nhdr.n_namesz == sizeof(SDT_NOTE_NAME) &&
+		    !memcmp(data->d_buf + name_off, SDT_NOTE_NAME,
+			    sizeof(SDT_NOTE_NAME))) {
+			/* Check the type of the note */
+			if (nhdr.n_type != SDT_NOTE_TYPE)
+				goto out_ret;
+
+			ret = populate_sdt_note(&elf, ((data->d_buf) + desc_off),
+						nhdr.n_descsz, sdt_notes);
+			if (ret < 0)
+				goto out_ret;
+		}
+	}
+	if (list_empty(sdt_notes))
+		ret = -ENOENT;
+
+out_ret:
+	return ret;
+}
+
+/**
+ * get_sdt_note_list : Wrapper to construct a list of sdt notes
+ * @head : empty list_head
+ * @target : file to find SDT notes from
+ *
+ * This opens the file, initializes
+ * the ELF and then calls construct_sdt_notes_list.
+ */
+int get_sdt_note_list(struct list_head *head, const char *target)
+{
+	Elf *elf;
+	int fd, ret;
+
+	fd = open(target, O_RDONLY);
+	if (fd < 0)
+		return -EBADF;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (!elf) {
+		ret = -EBADF;
+		goto out_close;
+	}
+	ret = construct_sdt_notes_list(elf, head);
+	elf_end(elf);
+out_close:
+	close(fd);
+	return ret;
+}
+
+/**
+ * cleanup_sdt_note_list : free the sdt notes' list
+ * @sdt_notes: sdt notes' list
+ *
+ * Free up the SDT notes in @sdt_notes.
+ * Returns the number of SDT notes free'd.
+ */
+int cleanup_sdt_note_list(struct list_head *sdt_notes)
+{
+	struct sdt_note *tmp, *pos;
+	int nr_free = 0;
+
+	list_for_each_entry_safe(pos, tmp, sdt_notes, note_list) {
+		list_del(&pos->note_list);
+		free(pos->name);
+		free(pos->provider);
+		free(pos);
+		nr_free++;
+	}
+	return nr_free;
+}
+
+/**
+ * sdt_notes__get_count: Counts the number of sdt events
+ * @start: list_head to sdt_notes list
+ *
+ * Returns the number of SDT notes in a list
+ */
+int sdt_notes__get_count(struct list_head *start)
+{
+	struct sdt_note *sdt_ptr;
+	int count = 0;
+
+	list_for_each_entry(sdt_ptr, start, note_list)
+		count++;
+	return count;
+}
+
 void symbol__elf_init(void)
 {
 	elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index b10d558..699f7cb 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -342,4 +342,26 @@ void arch__sym_update(struct symbol *s, GElf_Sym *sym);
 
 int arch__choose_best_symbol(struct symbol *syma, struct symbol *symb);
 
+/* structure containing an SDT note's info */
+struct sdt_note {
+	char *name;			/* name of the note*/
+	char *provider;			/* provider name */
+	bool bit32;			/* whether the location is 32 bits? */
+	union {				/* location, base and semaphore addrs */
+		Elf64_Addr a64[3];
+		Elf32_Addr a32[3];
+	} addr;
+	struct list_head note_list;	/* SDT notes' list */
+};
+
+int get_sdt_note_list(struct list_head *head, const char *target);
+int cleanup_sdt_note_list(struct list_head *sdt_notes);
+int sdt_notes__get_count(struct list_head *start);
+
+#define SDT_BASE_SCN ".stapsdt.base"
+#define SDT_NOTE_SCN  ".note.stapsdt"
+#define SDT_NOTE_TYPE 3
+#define SDT_NOTE_NAME "stapsdt"
+#define NR_ADDR 3
+
 #endif /* __PERF_SYMBOL */

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 05/15] perf probe: Add group name support
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (3 preceding siblings ...)
  2016-07-01  8:03 ` [PATCH perf/core v13 04/15] perf/sdt: ELF support for SDT Masami Hiramatsu
@ 2016-07-01  8:04 ` Masami Hiramatsu
  2016-07-05 10:19   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  2016-07-01  8:04 ` [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache Masami Hiramatsu
                   ` (10 subsequent siblings)
  15 siblings, 1 reply; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:04 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

Allow user to set group name for adding new event.
Note that user must ensure that the group name doesn't
conflict with existing group name carefully.
E.g. Existing group name can conflict with other events.
Especially, using the group name reserved for kernel
modules can hide kernel embedded events when loading
modules.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v4:
  - Update Documentation/perf-probe.txt too.
---
 tools/perf/Documentation/perf-probe.txt |   10 ++++++----
 tools/perf/util/probe-event.c           |   23 ++++++++++++++---------
 2 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 8d09173..7a258e9 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -143,16 +143,18 @@ PROBE SYNTAX
 Probe points are defined by following syntax.
 
     1) Define event based on function name
-     [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...]
+     [[GROUP:]EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...]
 
     2) Define event based on source file with line number
-     [EVENT=]SRC:ALN [ARG ...]
+     [[GROUP:]EVENT=]SRC:ALN [ARG ...]
 
     3) Define event based on source file with lazy pattern
-     [EVENT=]SRC;PTN [ARG ...]
+     [[GROUP:]EVENT=]SRC;PTN [ARG ...]
 
 
-'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'.
+'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. You can also specify a group name by 'GROUP', if omitted, set 'probe' is used for kprobe and 'probe_<bin>' is used for uprobe.
+Note that using existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide embedded events in the
+modules.
 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition.  In addition, '@SRC' specifies a source file which has that function.
 It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern.
 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT).
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index f81b5dd..0201f66 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1206,10 +1206,8 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 	bool file_spec = false;
 	/*
 	 * <Syntax>
-	 * perf probe [EVENT=]SRC[:LN|;PTN]
-	 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
-	 *
-	 * TODO:Group name support
+	 * perf probe [GRP:][EVENT=]SRC[:LN|;PTN]
+	 * perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
 	 */
 	if (!arg)
 		return -EINVAL;
@@ -1218,11 +1216,19 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 	if (ptr && *ptr == '=') {	/* Event name */
 		*ptr = '\0';
 		tmp = ptr + 1;
-		if (strchr(arg, ':')) {
-			semantic_error("Group name is not supported yet.\n");
-			return -ENOTSUP;
-		}
+		ptr = strchr(arg, ':');
+		if (ptr) {
+			*ptr = '\0';
+			if (!is_c_func_name(arg))
+				goto not_fname;
+			pev->group = strdup(arg);
+			if (!pev->group)
+				return -ENOMEM;
+			arg = ptr + 1;
+		} else
+			pev->group = NULL;
 		if (!is_c_func_name(arg)) {
+not_fname:
 			semantic_error("%s is bad for event name -it must "
 				       "follow C symbol-naming rule.\n", arg);
 			return -EINVAL;
@@ -1230,7 +1236,6 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 		pev->event = strdup(arg);
 		if (pev->event == NULL)
 			return -ENOMEM;
-		pev->group = NULL;
 		arg = tmp;
 	}
 

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (4 preceding siblings ...)
  2016-07-01  8:04 ` [PATCH perf/core v13 05/15] perf probe: Add group name support Masami Hiramatsu
@ 2016-07-01  8:04 ` Masami Hiramatsu
  2016-07-01 18:22   ` Arnaldo Carvalho de Melo
  2016-07-05 10:19   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  2016-07-01  8:04 ` [PATCH perf/core v13 07/15] perf probe: Accept %sdt and %cached event name Masami Hiramatsu
                   ` (9 subsequent siblings)
  15 siblings, 2 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:04 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

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 <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v11:
  - Warn if SDT scanning/updating are failed.
 Changes in v10:
  - Update Documentation/perf-buildid-cache.txt too.
 Changes in v4:
  - Fix a bug to copy correct group name to entries.
  - Fix to consolidate same-name entries.
---
 tools/perf/Documentation/perf-buildid-cache.txt |    3 +
 tools/perf/util/build-id.c                      |   30 ++++++++++
 tools/perf/util/probe-file.c                    |   69 ++++++++++++++++++++++-
 tools/perf/util/probe-file.h                    |    2 +
 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 dd07b55..058064d 100644
--- a/tools/perf/Documentation/perf-buildid-cache.txt
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -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
 -------
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 1c49620..e1a1640 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;
@@ -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)
 {
@@ -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);
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 6cb6ec0..5b563b2 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)
 		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);
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 0ed1fc5..ddf5ae2 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -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;
@@ -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);

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 07/15] perf probe: Accept %sdt and %cached event name
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (5 preceding siblings ...)
  2016-07-01  8:04 ` [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache Masami Hiramatsu
@ 2016-07-01  8:04 ` Masami Hiramatsu
  2016-07-01  8:04 ` [PATCH perf/core v13 08/15] perf-probe: Make --list shows only available cached events Masami Hiramatsu
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:04 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

To improbe usability, support %[PROVIDER:]SDTEVENT format to
add new probes on SDT and cached events.

e.g.
  ----
  # perf probe -x /lib/libc-2.17.so  %lll_lock_wait_private
  Added new event:
    sdt_libc:lll_lock_wait_private (on %lll_lock_wait_private in
  /usr/lib/libc-2.17.so)

  You can now use it in all perf tools, such as:

          perf record -e sdt_libc:lll_lock_wait_private -aR sleep 1

  # perf probe -l | more
    sdt_libc:lll_lock_wait_private (on __lll_lock_wait_private+21
   in /usr/lib/libc-2.17.so)
  ----

Note that this is not only for SDT events, but also normal
events with event-name.

e.g. define "myevent" on cache (-n doesn't add the real probe)
  ----
  # perf probe -x ./perf --cache -n --add 'myevent=dso__load $params'
  ----
  Reuse the "myevent" from cache as below.
  ----
  # perf probe -x ./perf %myevent
  ----

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v10:
  - Update Documentation/perf-probe.txt to add a link about SDT.
 Changes in v7:
  - Fix a bug to return an error if no SDT/cached events found in cache.
---
 tools/perf/Documentation/perf-probe.txt |    9 +++
 tools/perf/util/probe-event.c           |   82 ++++++++++++++++++++++---------
 tools/perf/util/probe-event.h           |    1 
 tools/perf/util/probe-file.c            |    9 +++
 4 files changed, 76 insertions(+), 25 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 7a258e9..39e3870 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -151,6 +151,8 @@ Probe points are defined by following syntax.
     3) Define event based on source file with lazy pattern
      [[GROUP:]EVENT=]SRC;PTN [ARG ...]
 
+    4) Pre-defined SDT events or cached event with name
+     %[PROVIDER:]SDTEVENT
 
 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. You can also specify a group name by 'GROUP', if omitted, set 'probe' is used for kprobe and 'probe_<bin>' is used for uprobe.
 Note that using existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide embedded events in the
@@ -158,6 +160,11 @@ modules.
 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition.  In addition, '@SRC' specifies a source file which has that function.
 It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern.
 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT).
+'SDTEVENT' and 'PROVIDER' is the pre-defined event name which is defined by user SDT (Statically Defined Tracing) or the pre-cached probes with event name.
+Note that before using the SDT event, the target binary (on which SDT events are defined) must be scanned by linkperf:perf-buildid-cache[1] to make SDT events as cached events.
+
+For details of the SDT, see below.
+https://sourceware.org/gdb/onlinedocs/gdb/Static-Probe-Points.html
 
 PROBE ARGUMENT
 --------------
@@ -237,4 +244,4 @@ Add probes at malloc() function on libc
 
 SEE ALSO
 --------
-linkperf:perf-trace[1], linkperf:perf-record[1]
+linkperf:perf-trace[1], linkperf:perf-record[1], linkperf:perf-buildid-cache[1]
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 0201f66..7f79a83 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1197,6 +1197,34 @@ err:
 	return err;
 }
 
+static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev)
+{
+	char *ptr;
+
+	ptr = strchr(*arg, ':');
+	if (ptr) {
+		*ptr = '\0';
+		if (!is_c_func_name(*arg))
+			goto ng_name;
+		pev->group = strdup(*arg);
+		if (!pev->group)
+			return -ENOMEM;
+		*arg = ptr + 1;
+	} else
+		pev->group = NULL;
+	if (!is_c_func_name(*arg)) {
+ng_name:
+		semantic_error("%s is bad for event name -it must "
+			       "follow C symbol-naming rule.\n", *arg);
+		return -EINVAL;
+	}
+	pev->event = strdup(*arg);
+	if (pev->event == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
 /* Parse probepoint definition. */
 static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 {
@@ -1204,38 +1232,43 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 	char *ptr, *tmp;
 	char c, nc = 0;
 	bool file_spec = false;
+	int ret;
+
 	/*
 	 * <Syntax>
 	 * perf probe [GRP:][EVENT=]SRC[:LN|;PTN]
 	 * perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
+	 * perf probe %[GRP:]SDT_EVENT
 	 */
 	if (!arg)
 		return -EINVAL;
 
+	if (arg[0] == '%') {
+		pev->sdt = true;
+		arg++;
+	}
+
 	ptr = strpbrk(arg, ";=@+%");
-	if (ptr && *ptr == '=') {	/* Event name */
-		*ptr = '\0';
-		tmp = ptr + 1;
-		ptr = strchr(arg, ':');
+	if (pev->sdt) {
 		if (ptr) {
-			*ptr = '\0';
-			if (!is_c_func_name(arg))
-				goto not_fname;
-			pev->group = strdup(arg);
-			if (!pev->group)
-				return -ENOMEM;
-			arg = ptr + 1;
-		} else
-			pev->group = NULL;
-		if (!is_c_func_name(arg)) {
-not_fname:
-			semantic_error("%s is bad for event name -it must "
-				       "follow C symbol-naming rule.\n", arg);
+			semantic_error("%s must contain only an SDT event name.\n", arg);
 			return -EINVAL;
 		}
-		pev->event = strdup(arg);
-		if (pev->event == NULL)
-			return -ENOMEM;
+		ret = parse_perf_probe_event_name(&arg, pev);
+		if (ret == 0) {
+			if (asprintf(&pev->point.function, "%%%s", pev->event) < 0)
+				ret = -errno;
+		}
+		return ret;
+	}
+
+	if (ptr && *ptr == '=') {	/* Event name */
+		*ptr = '\0';
+		tmp = ptr + 1;
+		ret = parse_perf_probe_event_name(&arg, pev);
+		if (ret < 0)
+			return ret;
+
 		arg = tmp;
 	}
 
@@ -2874,7 +2907,8 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
 
 	entry = probe_cache__find(cache, pev);
 	if (!entry) {
-		ret = 0;
+		/* SDT must be in the cache */
+		ret = pev->sdt ? -ENOENT : 0;
 		goto out;
 	}
 
@@ -2913,7 +2947,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 {
 	int ret;
 
-	if (!pev->group) {
+	if (!pev->group && !pev->sdt) {
 		/* Set group name if not given */
 		if (!pev->uprobes) {
 			pev->group = strdup(PERFPROBE_GROUP);
@@ -2932,8 +2966,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 
 	/* At first, we need to lookup cache entry */
 	ret = find_probe_trace_events_from_cache(pev, tevs);
-	if (ret > 0)
-		return ret;	/* Found in probe cache */
+	if (ret > 0 || pev->sdt)	/* SDT can be found only in the cache */
+		return ret == 0 ? -ENOENT : ret; /* Found in probe cache */
 
 	if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) {
 		ret = find_probe_trace_events_from_map(pev, tevs);
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 432b690..e18ea9f 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -85,6 +85,7 @@ struct perf_probe_event {
 	char			*group;	/* Group name */
 	struct perf_probe_point	point;	/* Probe point */
 	int			nargs;	/* Number of arguments */
+	bool			sdt;	/* SDT/cached event flag */
 	bool			uprobes;	/* Uprobe event flag */
 	char			*target;	/* Target binary */
 	struct perf_probe_arg	*args;	/* Arguments */
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 5b563b2..b642d06 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -547,6 +547,15 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
 		return NULL;
 
 	list_for_each_entry(entry, &pcache->entries, node) {
+		if (pev->sdt) {
+			if (entry->pev.event &&
+			    streql(entry->pev.event, pev->event) &&
+			    (!pev->group ||
+			     streql(entry->pev.group, pev->group)))
+				goto found;
+
+			continue;
+		}
 		/* Hit if same event name or same command-string */
 		if ((pev->event &&
 		     (streql(entry->pev.group, pev->group) &&

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 08/15] perf-probe: Make --list shows only available cached events
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (6 preceding siblings ...)
  2016-07-01  8:04 ` [PATCH perf/core v13 07/15] perf probe: Accept %sdt and %cached event name Masami Hiramatsu
@ 2016-07-01  8:04 ` Masami Hiramatsu
  2016-07-01  8:04 ` [PATCH perf/core v13 09/15] perf: probe-cache: Add for_each_probe_cache_entry() wrapper Masami Hiramatsu
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:04 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

Make "perf probe --cache --list" shows only available cached events
by checking build-id validity.

E.g. without this patch:
  ----
  $ ./perf probe --cache --add oldevent=cmd_probe
  $ make #(to update ./perf)
  $ ./perf probe --cache --add newevent=cmd_probe
  $ ./perf probe --cache --list
  /home/mhiramat/ksrc/linux/tools/perf/perf (061e90539bac69
  probe_perf:newevent=cmd_probe
  /home/mhiramat/ksrc/linux/tools/perf/perf (c2e44d614e33e1
  probe_perf:oldevent=cmd_probe
  ----
It shows both of old and new events but user can not use old one.
With this;
  ----
  $ ./perf probe --cache -l
  /home/mhiramat/ksrc/linux/tools/perf/perf (061e90539bac69
  probe_perf:newevent=cmd_probe
  ----
This show only new event which is on the existing binary.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v13:
  - Instead of the perf-list, apply this change for perf-probe --list
    because of avoiding to confuse user.
 Changes in v7:
  - Validate build-id via sysfs if it is for kallsyms,
 Changes in v4:
  - Rename a parameter 'valid' to 'validonly' :)
---
 tools/perf/builtin-probe.c   |    2 +-
 tools/perf/util/build-id.c   |   33 ++++++++++++++++++++++++++++++++-
 tools/perf/util/build-id.h   |    2 +-
 tools/perf/util/probe-file.c |    2 +-
 4 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index a1a5cd1..de75af5 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -370,7 +370,7 @@ static int del_perf_probe_caches(struct strfilter *filter)
 	struct str_node *nd;
 	int ret;
 
-	bidlist = build_id_cache__list_all();
+	bidlist = build_id_cache__list_all(false);
 	if (!bidlist) {
 		ret = -errno;
 		pr_debug("Failed to get buildids: %d\n", ret);
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index e1a1640..8e86a83 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -206,6 +206,31 @@ out:
 	return ret;
 }
 
+/* Check if the given build_id cache is valid on current running system */
+static bool build_id_cache__valid_id(char *sbuild_id)
+{
+	char real_sbuild_id[SBUILD_ID_SIZE] = "";
+	char *pathname;
+	int ret = 0;
+	bool result = false;
+
+	pathname = build_id_cache__origname(sbuild_id);
+	if (!pathname)
+		return false;
+
+	if (!strcmp(pathname, DSO__NAME_KALLSYMS))
+		ret = sysfs__sprintf_build_id("/", real_sbuild_id);
+	else if (pathname[0] == '/')
+		ret = filename__sprintf_build_id(pathname, real_sbuild_id);
+	else
+		ret = -EINVAL;	/* Should we support other special DSO cache? */
+	if (ret >= 0)
+		result = (strcmp(sbuild_id, real_sbuild_id) == 0);
+	free(pathname);
+
+	return result;
+}
+
 static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
 {
 	return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
@@ -433,13 +458,17 @@ static bool lsdir_bid_tail_filter(const char *name __maybe_unused,
 	return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0');
 }
 
-struct strlist *build_id_cache__list_all(void)
+struct strlist *build_id_cache__list_all(bool validonly)
 {
 	struct strlist *toplist, *linklist = NULL, *bidlist;
 	struct str_node *nd, *nd2;
 	char *topdir, *linkdir = NULL;
 	char sbuild_id[SBUILD_ID_SIZE];
 
+	/* for filename__ functions */
+	if (validonly)
+		symbol__init(NULL);
+
 	/* Open the top-level directory */
 	if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
 		return NULL;
@@ -470,6 +499,8 @@ struct strlist *build_id_cache__list_all(void)
 			if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s",
 				     nd->s, nd2->s) != SBUILD_ID_SIZE - 1)
 				goto err_out;
+			if (validonly && !build_id_cache__valid_id(sbuild_id))
+				continue;
 			if (strlist__add(bidlist, sbuild_id) < 0)
 				goto err_out;
 		}
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index b742e27..64e740f 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -34,7 +34,7 @@ char *build_id_cache__origname(const char *sbuild_id);
 char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
 char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
 			       bool is_kallsyms, bool is_vdso);
-struct strlist *build_id_cache__list_all(void);
+struct strlist *build_id_cache__list_all(bool validonly);
 int build_id_cache__list_build_ids(const char *pathname,
 				   struct strlist **result);
 bool build_id_cache__cached(const char *sbuild_id);
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index b642d06..b062545 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -806,7 +806,7 @@ int probe_cache__show_all_caches(struct strfilter *filter)
 	pr_debug("list cache with filter: %s\n", buf);
 	free(buf);
 
-	bidlist = build_id_cache__list_all();
+	bidlist = build_id_cache__list_all(true);
 	if (!bidlist) {
 		pr_debug("Failed to get buildids: %d\n", errno);
 		return -EINVAL;

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 09/15] perf: probe-cache: Add for_each_probe_cache_entry() wrapper
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (7 preceding siblings ...)
  2016-07-01  8:04 ` [PATCH perf/core v13 08/15] perf-probe: Make --list shows only available cached events Masami Hiramatsu
@ 2016-07-01  8:04 ` Masami Hiramatsu
  2016-07-01  8:04 ` [PATCH perf/core v13 10/15] perf probe: Allow wildcard for cached events Masami Hiramatsu
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:04 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

Add for_each_probe_cache_entry() wrapper macro
for hiding list in probe_cache.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v10:
  - Splitted from "perf probe: Allow wildcard for cached events"
---
 tools/perf/util/probe-file.c |    8 ++++----
 tools/perf/util/probe-file.h |    2 ++
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index b062545..9152ad2 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -546,7 +546,7 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
 	if (!cmd)
 		return NULL;
 
-	list_for_each_entry(entry, &pcache->entries, node) {
+	for_each_probe_cache_entry(entry, pcache) {
 		if (pev->sdt) {
 			if (entry->pev.event &&
 			    streql(entry->pev.event, pev->event) &&
@@ -576,7 +576,7 @@ probe_cache__find_by_name(struct probe_cache *pcache,
 {
 	struct probe_cache_entry *entry = NULL;
 
-	list_for_each_entry(entry, &pcache->entries, node) {
+	for_each_probe_cache_entry(entry, pcache) {
 		/* Hit if same event name or same command-string */
 		if (streql(entry->pev.group, group) &&
 		    streql(entry->pev.event, event))
@@ -746,7 +746,7 @@ int probe_cache__commit(struct probe_cache *pcache)
 	if (ret < 0)
 		goto out;
 
-	list_for_each_entry(entry, &pcache->entries, node) {
+	for_each_probe_cache_entry(entry, pcache) {
 		ret = probe_cache_entry__write(entry, pcache->fd);
 		pr_debug("Cache committed: %d\n", ret);
 		if (ret < 0)
@@ -788,7 +788,7 @@ static int probe_cache__show_entries(struct probe_cache *pcache,
 {
 	struct probe_cache_entry *entry;
 
-	list_for_each_entry(entry, &pcache->entries, node) {
+	for_each_probe_cache_entry(entry, pcache) {
 		if (probe_cache_entry__compare(entry, filter))
 			printf("%s\n", entry->spev);
 	}
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index ddf5ae2..d513b34 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -21,6 +21,8 @@ struct probe_cache {
 
 #define PF_FL_UPROBE	1
 #define PF_FL_RW	2
+#define for_each_probe_cache_entry(entry, pcache) \
+	list_for_each_entry(entry, &pcache->entries, node)
 
 int probe_file__open(int flag);
 int probe_file__open_both(int *kfd, int *ufd, int flag);

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 10/15] perf probe: Allow wildcard for cached events
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (8 preceding siblings ...)
  2016-07-01  8:04 ` [PATCH perf/core v13 09/15] perf: probe-cache: Add for_each_probe_cache_entry() wrapper Masami Hiramatsu
@ 2016-07-01  8:04 ` Masami Hiramatsu
  2016-07-01  8:04 ` [PATCH perf/core v13 11/15] perf probe: Search SDT/cached event from all probe caches Masami Hiramatsu
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:04 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

Allo glob wildcard for reusing cached/SDT events. E.g.

  # perf probe -x /usr/lib64/libc-2.20.so -a %sdt_libc:\*

This example adds probes for all SDT in libc.
Note that the SDTs must have been scanned by perf buildid-cache.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v12:
  - Rename strlist__for_each to strlist__for_each_entry.
 Changes in v10:
  - Split off bugfix, adding interface, and target search patches.
  - Do not export clear_probe_trace_events().
 Changes in v7:
  - Continue to search caches if a build-id cache has no probe cache.
  - Make probe_cache__open() to accept DSO__NAME_KALLSYMS for kernel.
  - Fix to add probes correctly when a wildcard matchs both of
    uprobes and kprobes.
 Changes in v5.1:
  - Fix a SEGV bug when a group name is omitted. (Thanks Hemant!)
---
 tools/perf/util/probe-event.c |  107 +++++++++++++++++++++++++++++++++++++++--
 tools/perf/util/probe-file.c  |   38 ++++++++++++---
 tools/perf/util/probe-file.h  |    3 +
 3 files changed, 138 insertions(+), 10 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 7f79a83..2fb828f 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1204,7 +1204,7 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev)
 	ptr = strchr(*arg, ':');
 	if (ptr) {
 		*ptr = '\0';
-		if (!is_c_func_name(*arg))
+		if (!pev->sdt && !is_c_func_name(*arg))
 			goto ng_name;
 		pev->group = strdup(*arg);
 		if (!pev->group)
@@ -1212,7 +1212,7 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev)
 		*arg = ptr + 1;
 	} else
 		pev->group = NULL;
-	if (!is_c_func_name(*arg)) {
+	if (!pev->sdt && !is_c_func_name(*arg)) {
 ng_name:
 		semantic_error("%s is bad for event name -it must "
 			       "follow C symbol-naming rule.\n", *arg);
@@ -1642,6 +1642,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev)
 			ret = -ENOMEM;
 			goto out;
 		}
+		tev->uprobes = (tp->module[0] == '/');
 		p++;
 	} else
 		p = argv[1];
@@ -2516,7 +2517,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,
 	int ret;
 
 	/* If probe_event or trace_event already have the name, reuse it */
-	if (pev->event)
+	if (pev->event && !pev->sdt)
 		event = pev->event;
 	else if (tev->event)
 		event = tev->event;
@@ -2529,7 +2530,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,
 		else
 			event = tev->point.realname;
 	}
-	if (pev->group)
+	if (pev->group && !pev->sdt)
 		group = pev->group;
 	else if (tev->group)
 		group = tev->group;
@@ -2892,6 +2893,100 @@ errout:
 
 bool __weak arch__prefers_symtab(void) { return false; }
 
+/* Concatinate two arrays */
+static void *memcat(void *a, size_t sz_a, void *b, size_t sz_b)
+{
+	void *ret;
+
+	ret = malloc(sz_a + sz_b);
+	if (ret) {
+		memcpy(ret, a, sz_a);
+		memcpy(ret + sz_a, b, sz_b);
+	}
+	return ret;
+}
+
+static int
+concat_probe_trace_events(struct probe_trace_event **tevs, int *ntevs,
+			  struct probe_trace_event **tevs2, int ntevs2)
+{
+	struct probe_trace_event *new_tevs;
+	int ret = 0;
+
+	if (ntevs == 0) {
+		*tevs = *tevs2;
+		*ntevs = ntevs2;
+		*tevs2 = NULL;
+		return 0;
+	}
+
+	if (*ntevs + ntevs2 > probe_conf.max_probes)
+		ret = -E2BIG;
+	else {
+		/* Concatinate the array of probe_trace_event */
+		new_tevs = memcat(*tevs, (*ntevs) * sizeof(**tevs),
+				  *tevs2, ntevs2 * sizeof(**tevs2));
+		if (!new_tevs)
+			ret = -ENOMEM;
+		else {
+			free(*tevs);
+			*tevs = new_tevs;
+			*ntevs += ntevs2;
+		}
+	}
+	if (ret < 0)
+		clear_probe_trace_events(*tevs2, ntevs2);
+	zfree(tevs2);
+
+	return ret;
+}
+
+/*
+ * Try to find probe_trace_event from given probe caches. Return the number
+ * of cached events found, if an error occurs return the error.
+ */
+static int find_cached_events(struct perf_probe_event *pev,
+			      struct probe_trace_event **tevs,
+			      const char *target)
+{
+	struct probe_cache *cache;
+	struct probe_cache_entry *entry;
+	struct probe_trace_event *tmp_tevs = NULL;
+	int ntevs = 0;
+	int ret = 0;
+
+	cache = probe_cache__new(target);
+	/* Return 0 ("not found") if the target has no probe cache. */
+	if (!cache)
+		return 0;
+
+	for_each_probe_cache_entry(entry, cache) {
+		/* Skip the cache entry which has no name */
+		if (!entry->pev.event || !entry->pev.group)
+			continue;
+		if ((!pev->group || strglobmatch(entry->pev.group, pev->group)) &&
+		    strglobmatch(entry->pev.event, pev->event)) {
+			ret = probe_cache_entry__get_event(entry, &tmp_tevs);
+			if (ret > 0)
+				ret = concat_probe_trace_events(tevs, &ntevs,
+								&tmp_tevs, ret);
+			if (ret < 0)
+				break;
+		}
+	}
+	probe_cache__delete(cache);
+	if (ret < 0) {
+		clear_probe_trace_events(*tevs, ntevs);
+		zfree(tevs);
+	} else {
+		ret = ntevs;
+		if (ntevs > 0 && target && target[0] == '/')
+			pev->uprobes = true;
+	}
+
+	return ret;
+}
+
 static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
 					      struct probe_trace_event **tevs)
 {
@@ -2901,6 +2996,10 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
 	struct str_node *node;
 	int ret, i;
 
+	if (pev->sdt)
+		/* For SDT/cached events, we use special search functions */
+		return find_cached_events(pev, tevs, pev->target);
+
 	cache = probe_cache__new(pev->target);
 	if (!cache)
 		return 0;
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 9152ad2..78a84f5 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -362,13 +362,38 @@ probe_cache_entry__new(struct perf_probe_event *pev)
 	return entry;
 }
 
-/* For the kernel probe caches, pass target = NULL */
+int probe_cache_entry__get_event(struct probe_cache_entry *entry,
+				 struct probe_trace_event **tevs)
+{
+	struct probe_trace_event *tev;
+	struct str_node *node;
+	int ret, i;
+
+	ret = strlist__nr_entries(entry->tevlist);
+	if (ret > probe_conf.max_probes)
+		return -E2BIG;
+
+	*tevs = zalloc(ret * sizeof(*tev));
+	if (!*tevs)
+		return -ENOMEM;
+
+	i = 0;
+	strlist__for_each_entry(node, entry->tevlist) {
+		tev = &(*tevs)[i++];
+		ret = parse_probe_trace_command(node->s, tev);
+		if (ret < 0)
+			break;
+	}
+	return i;
+}
+
+/* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */
 static int probe_cache__open(struct probe_cache *pcache, const char *target)
 {
 	char cpath[PATH_MAX];
 	char sbuildid[SBUILD_ID_SIZE];
 	char *dir_name = NULL;
-	bool is_kallsyms = !target;
+	bool is_kallsyms = false;
 	int ret, fd;
 
 	if (target && build_id_cache__cached(target)) {
@@ -378,12 +403,13 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
 		goto found;
 	}
 
-	if (target)
-		ret = filename__sprintf_build_id(target, sbuildid);
-	else {
+	if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) {
 		target = DSO__NAME_KALLSYMS;
+		is_kallsyms = true;
 		ret = sysfs__sprintf_build_id("/", sbuildid);
-	}
+	} else
+		ret = filename__sprintf_build_id(target, sbuildid);
+
 	if (ret < 0) {
 		pr_debug("Failed to get build-id from %s.\n", target);
 		return ret;
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index d513b34..cafbe1d 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -34,6 +34,9 @@ int probe_file__get_events(int fd, struct strfilter *filter,
 				  struct strlist *plist);
 int probe_file__del_strlist(int fd, struct strlist *namelist);
 
+int probe_cache_entry__get_event(struct probe_cache_entry *entry,
+				 struct probe_trace_event **tevs);
+
 struct probe_cache *probe_cache__new(const char *target);
 int probe_cache__add_entry(struct probe_cache *pcache,
 			   struct perf_probe_event *pev,

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 11/15] perf probe: Search SDT/cached event from all probe caches
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (9 preceding siblings ...)
  2016-07-01  8:04 ` [PATCH perf/core v13 10/15] perf probe: Allow wildcard for cached events Masami Hiramatsu
@ 2016-07-01  8:04 ` Masami Hiramatsu
  2016-07-01  8:05 ` [PATCH perf/core v13 12/15] perf probe: Support @BUILDID or @FILE suffix for SDT events Masami Hiramatsu
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:04 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

Search SDT/cached event from all probe caches if user doesn't
pass any binary. With this, we don't have to specify target
binary for SDT and named cached events (which start with %).

E.g. without this, a target binary must be passed with -x.

 # perf probe -x /usr/lib64/libc-2.20.so -a %sdt_libc:\*

With this change, we don't need it anymore.

 # perf probe -a %sdt_libc:\*

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v12:
  - Rename strlist__for_each to strlist__for_each_entry.
 Changes from v10:
  - Splitted from "perf probe: Allow wildcard for cached events"
---
 tools/perf/util/probe-event.c |  105 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 86 insertions(+), 19 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 2fb828f..8816643 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2555,41 +2555,60 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,
 	return 0;
 }
 
-static int __add_probe_trace_events(struct perf_probe_event *pev,
-				     struct probe_trace_event *tevs,
-				     int ntevs, bool allow_suffix)
+static int __open_probe_file_and_namelist(bool uprobe,
+					  struct strlist **namelist)
 {
-	int i, fd, ret;
-	struct probe_trace_event *tev = NULL;
-	struct probe_cache *cache = NULL;
-	struct strlist *namelist;
+	int fd;
 
-	fd = probe_file__open(PF_FL_RW | (pev->uprobes ? PF_FL_UPROBE : 0));
+	fd = probe_file__open(PF_FL_RW | (uprobe ? PF_FL_UPROBE : 0));
 	if (fd < 0)
 		return fd;
 
 	/* Get current event names */
-	namelist = probe_file__get_namelist(fd);
-	if (!namelist) {
+	*namelist = probe_file__get_namelist(fd);
+	if (!(*namelist)) {
 		pr_debug("Failed to get current event list.\n");
-		ret = -ENOMEM;
-		goto close_out;
+		close(fd);
+		return -ENOMEM;
 	}
+	return fd;
+}
+
+static int __add_probe_trace_events(struct perf_probe_event *pev,
+				     struct probe_trace_event *tevs,
+				     int ntevs, bool allow_suffix)
+{
+	int i, fd[2] = {-1, -1}, up, ret;
+	struct probe_trace_event *tev = NULL;
+	struct probe_cache *cache = NULL;
+	struct strlist *namelist[2] = {NULL, NULL};
+
+	up = pev->uprobes ? 1 : 0;
+	fd[up] = __open_probe_file_and_namelist(up, &namelist[up]);
+	if (fd[up] < 0)
+		return fd[up];
 
 	ret = 0;
 	for (i = 0; i < ntevs; i++) {
 		tev = &tevs[i];
+		up = tev->uprobes ? 1 : 0;
+		if (fd[up] == -1) {	/* Open the kprobe/uprobe_events */
+			fd[up] = __open_probe_file_and_namelist(up,
+								&namelist[up]);
+			if (fd[up] < 0)
+				goto close_out;
+		}
 		/* Skip if the symbol is out of .text or blacklisted */
 		if (!tev->point.symbol && !pev->uprobes)
 			continue;
 
 		/* Set new name for tev (and update namelist) */
-		ret = probe_trace_event__set_name(tev, pev, namelist,
+		ret = probe_trace_event__set_name(tev, pev, namelist[up],
 						  allow_suffix);
 		if (ret < 0)
 			break;
 
-		ret = probe_file__add_event(fd, tev);
+		ret = probe_file__add_event(fd[up], tev);
 		if (ret < 0)
 			break;
 
@@ -2612,9 +2631,12 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 		probe_cache__delete(cache);
 	}
 
-	strlist__delete(namelist);
 close_out:
-	close(fd);
+	for (up = 0; up < 2; up++) {
+		strlist__delete(namelist[up]);
+		if (fd[up] >= 0)
+			close(fd[up]);
+	}
 	return ret;
 }
 
@@ -2987,6 +3009,48 @@ static int find_cached_events(struct perf_probe_event *pev,
 	return ret;
 }
 
+/* Try to find probe_trace_event from all probe caches */
+static int find_cached_events_all(struct perf_probe_event *pev,
+				   struct probe_trace_event **tevs)
+{
+	struct probe_trace_event *tmp_tevs = NULL;
+	struct strlist *bidlist;
+	struct str_node *nd;
+	char *pathname;
+	int ntevs = 0;
+	int ret;
+
+	/* Get the buildid list of all valid caches */
+	bidlist = build_id_cache__list_all(true);
+	if (!bidlist) {
+		ret = -errno;
+		pr_debug("Failed to get buildids: %d\n", ret);
+		return ret;
+	}
+
+	ret = 0;
+	strlist__for_each_entry(nd, bidlist) {
+		pathname = build_id_cache__origname(nd->s);
+		ret = find_cached_events(pev, &tmp_tevs, pathname);
+		/* In the case of cnt == 0, we just skip it */
+		if (ret > 0)
+			ret = concat_probe_trace_events(tevs, &ntevs,
+							&tmp_tevs, ret);
+		free(pathname);
+		if (ret < 0)
+			break;
+	}
+	strlist__delete(bidlist);
+
+	if (ret < 0) {
+		clear_probe_trace_events(*tevs, ntevs);
+		zfree(tevs);
+	} else
+		ret = ntevs;
+
+	return ret;
+}
+
 static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
 					      struct probe_trace_event **tevs)
 {
@@ -2996,10 +3060,13 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
 	struct str_node *node;
 	int ret, i;
 
-	if (pev->sdt)
+	if (pev->sdt) {
 		/* For SDT/cached events, we use special search functions */
-		return find_cached_events(pev, tevs, pev->target);
-
+		if (!pev->target)
+			return find_cached_events_all(pev, tevs);
+		else
+			return find_cached_events(pev, tevs, pev->target);
+	}
 	cache = probe_cache__new(pev->target);
 	if (!cache)
 		return 0;

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 12/15] perf probe: Support @BUILDID or @FILE suffix for SDT events
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (10 preceding siblings ...)
  2016-07-01  8:04 ` [PATCH perf/core v13 11/15] perf probe: Search SDT/cached event from all probe caches Masami Hiramatsu
@ 2016-07-01  8:05 ` Masami Hiramatsu
  2016-07-01  8:05 ` [PATCH perf/core v13 13/15] perf probe: Support a special SDT probe format Masami Hiramatsu
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:05 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

Support @BUILDID or @FILE suffix for SDT events. This allows
perf to add probes on SDTs/pre-cached events on given FILE
or the file which has given BUILDID (also, this complements
BUILDID.)
For example, both gcc and libstdc++ has same SDTs as below.
If you would like to add a probe on sdt_libstdcxx:catch on gcc,
you can do as below.

  ----
  # perf list sdt | tail -n 6
    sdt_libstdcxx:catch@/usr/bin/gcc(0cc207fc4b27)     [SDT event]
    sdt_libstdcxx:catch@/usr/lib64/libstdc++.so.6.0.20(91c7a88fdf49)
    sdt_libstdcxx:rethrow@/usr/bin/gcc(0cc207fc4b27)   [SDT event]
    sdt_libstdcxx:rethrow@/usr/lib64/libstdc++.so.6.0.20(91c7a88fdf49)
    sdt_libstdcxx:throw@/usr/bin/gcc(0cc207fc4b27)     [SDT event]
    sdt_libstdcxx:throw@/usr/lib64/libstdc++.so.6.0.20(91c7a88fdf49)
  # perf probe -a %sdt_libstdcxx:catch@0cc
  Added new event:
    sdt_libstdcxx:catch  (on %catch in /usr/bin/gcc)

  You can now use it in all perf tools, such as:

  	perf record -e sdt_libstdcxx:catch -aR sleep 1
  ----

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v12:
  - Rename strlist__for_each to strlist__for_each_entry.
---
 tools/perf/util/build-id.c    |   43 +++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/build-id.h    |    1 +
 tools/perf/util/probe-event.c |   17 ++++++++++++++--
 3 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 8e86a83..e59003e 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -523,6 +523,49 @@ err_out:
 	goto out_free;
 }
 
+static bool str_is_build_id(const char *maybe_sbuild_id, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++) {
+		if (!isxdigit(maybe_sbuild_id[i]))
+			return false;
+	}
+	return true;
+}
+
+/* Return the valid complete build-id */
+char *build_id_cache__complement(const char *incomplete_sbuild_id)
+{
+	struct strlist *bidlist;
+	struct str_node *nd, *cand = NULL;
+	char *sbuild_id = NULL;
+	size_t len = strlen(incomplete_sbuild_id);
+
+	if (len >= SBUILD_ID_SIZE ||
+	    !str_is_build_id(incomplete_sbuild_id, len))
+		return NULL;
+
+	bidlist = build_id_cache__list_all(true);
+	if (!bidlist)
+		return NULL;
+
+	strlist__for_each_entry(nd, bidlist) {
+		if (strncmp(nd->s, incomplete_sbuild_id, len) != 0)
+			continue;
+		if (cand) {	/* Error: There are more than 2 candidates. */
+			cand = NULL;
+			break;
+		}
+		cand = nd;
+	}
+	if (cand)
+		sbuild_id = strdup(cand->s);
+	strlist__delete(bidlist);
+
+	return sbuild_id;
+}
+
 char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
 			       bool is_kallsyms, bool is_vdso)
 {
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 64e740f..d279906 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -35,6 +35,7 @@ char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
 char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
 			       bool is_kallsyms, bool is_vdso);
 struct strlist *build_id_cache__list_all(bool validonly);
+char *build_id_cache__complement(const char *incomplete_sbuild_id);
 int build_id_cache__list_build_ids(const char *pathname,
 				   struct strlist **result);
 bool build_id_cache__cached(const char *sbuild_id);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 8816643..b38548c 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1251,8 +1251,21 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 	ptr = strpbrk(arg, ";=@+%");
 	if (pev->sdt) {
 		if (ptr) {
-			semantic_error("%s must contain only an SDT event name.\n", arg);
-			return -EINVAL;
+			if (*ptr != '@') {
+				semantic_error("%s must be an SDT name.\n",
+					       arg);
+				return -EINVAL;
+			}
+			/* This must be a target file name or build id */
+			tmp = build_id_cache__complement(ptr + 1);
+			if (tmp) {
+				pev->target = build_id_cache__origname(tmp);
+				free(tmp);
+			} else
+				pev->target = strdup(ptr + 1);
+			if (!pev->target)
+				return -ENOMEM;
+			*ptr = '\0';
 		}
 		ret = parse_perf_probe_event_name(&arg, pev);
 		if (ret == 0) {

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 13/15] perf probe: Support a special SDT probe format
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (11 preceding siblings ...)
  2016-07-01  8:05 ` [PATCH perf/core v13 12/15] perf probe: Support @BUILDID or @FILE suffix for SDT events Masami Hiramatsu
@ 2016-07-01  8:05 ` Masami Hiramatsu
  2016-07-01  8:05 ` [PATCH perf/core v13 14/15] perf build: Add sdt feature detection Masami Hiramatsu
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:05 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

Support a special SDT probe format which can omit the '%' prefix
only if the SDT group name starts with "sdt_". So, for example
both of "%sdt_libc:setjump" and "sdt_libc:setjump" are acceptable
for perf probe --add.

E.g. without this:
  ----
  # perf probe -a sdt_libc:setjmp
  Semantic error :There is non-digit char in line number.
  ...
  ----
With this:
  ----
  # perf probe -a sdt_libc:setjmp
  Added new event:
    sdt_libc:setjmp      (on %setjmp in /usr/lib64/libc-2.20.so)

  You can now use it in all perf tools, such as:

  	perf record -e sdt_libc:setjmp -aR sleep 1
  ----

Suggested-by: Brendan Gregg <brendan.d.gregg@gmail.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 tools/perf/Documentation/perf-probe.txt |    4 +++-
 tools/perf/util/probe-event.c           |   12 ++++++++++--
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 39e3870..736da44 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -152,7 +152,9 @@ Probe points are defined by following syntax.
      [[GROUP:]EVENT=]SRC;PTN [ARG ...]
 
     4) Pre-defined SDT events or cached event with name
-     %[PROVIDER:]SDTEVENT
+     %[sdt_PROVIDER:]SDTEVENT
+     or,
+     sdt_PROVIDER:SDTEVENT
 
 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. You can also specify a group name by 'GROUP', if omitted, set 'probe' is used for kprobe and 'probe_<bin>' is used for uprobe.
 Note that using existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide embedded events in the
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index b38548c..8b4fb63 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1243,9 +1243,17 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 	if (!arg)
 		return -EINVAL;
 
-	if (arg[0] == '%') {
+	/*
+	 * If the probe point starts with '%',
+	 * or starts with "sdt_" and has a ':' but no '=',
+	 * then it should be a SDT/cached probe point.
+	 */
+	if (arg[0] == '%' ||
+	    (!strncmp(arg, "sdt_", 4) &&
+	     !!strchr(arg, ':') && !strchr(arg, '='))) {
 		pev->sdt = true;
-		arg++;
+		if (arg[0] == '%')
+			arg++;
 	}
 
 	ptr = strpbrk(arg, ";=@+%");

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 14/15] perf build: Add sdt feature detection
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (12 preceding siblings ...)
  2016-07-01  8:05 ` [PATCH perf/core v13 13/15] perf probe: Support a special SDT probe format Masami Hiramatsu
@ 2016-07-01  8:05 ` Masami Hiramatsu
  2016-07-01  8:05 ` [PATCH perf/core v13 15/15] perf-test: Add a test case for SDT event Masami Hiramatsu
  2016-07-01 13:19 ` [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Arnaldo Carvalho de Melo
  15 siblings, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:05 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

This checks whether sys/sdt.h is available or not,
which is required for DTRACE_PROBE().
We can disable this feature by passing NO_SDT=1 when
building.
This flag will be used for SDT test case and further
SDT events in perftools.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 tools/perf/Makefile.perf   |    3 +++
 tools/perf/config/Makefile |   10 ++++++++++
 tools/perf/tests/make      |    3 ++-
 3 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 57c8f98..6bc7767 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -60,7 +60,8 @@ FEATURE_TESTS_BASIC :=			\
 	zlib				\
 	lzma				\
 	get_cpuid			\
-	bpf
+	bpf				\
+	sdt
 
 # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
 # of all feature tests
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index 3d88f09..82d357f 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -43,7 +43,8 @@ FILES=					\
 	test-zlib.bin			\
 	test-lzma.bin			\
 	test-bpf.bin			\
-	test-get_cpuid.bin
+	test-get_cpuid.bin		\
+	test-sdt.bin
 
 FILES := $(addprefix $(OUTPUT),$(FILES))
 
@@ -205,6 +206,9 @@ $(OUTPUT)test-get_cpuid.bin:
 $(OUTPUT)test-bpf.bin:
 	$(BUILD)
 
+$(OUTPUT)test-sdt.bin:
+	$(BUILD)
+
 -include $(OUTPUT)*.d
 
 ###############################
diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c
index a282e8c..f538c5f 100644
--- a/tools/build/feature/test-all.c
+++ b/tools/build/feature/test-all.c
@@ -137,6 +137,10 @@
 # include "test-libcrypto.c"
 #undef main
 
+#define main main_test_sdt
+# include "test-sdt.c"
+#undef main
+
 int main(int argc, char *argv[])
 {
 	main_test_libpython();
@@ -168,6 +172,7 @@ int main(int argc, char *argv[])
 	main_test_get_cpuid();
 	main_test_bpf();
 	main_test_libcrypto();
+	main_test_sdt();
 
 	return 0;
 }
diff --git a/tools/build/feature/test-sdt.c b/tools/build/feature/test-sdt.c
new file mode 100644
index 0000000..e4531a6
--- /dev/null
+++ b/tools/build/feature/test-sdt.c
@@ -0,0 +1,7 @@
+#include <sys/sdt.h>
+
+int main(void)
+{
+	DTRACE_PROBE(provider, name);
+	return 0;
+}
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index d0a2cb1..458eaf5 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -81,6 +81,9 @@ include ../scripts/utilities.mak
 #
 # Define NO_LIBBPF if you do not want BPF support
 #
+# Define NO_SDT if you do not want to define SDT event in perf tools,
+# note that it doesn't disable SDT scanning support.
+#
 # Define FEATURES_DUMP to provide features detection dump file
 # and bypass the feature detection
 
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index bf1a0a0..b87c91c 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -345,6 +345,16 @@ ifndef NO_LIBELF
   endif # NO_LIBBPF
 endif # NO_LIBELF
 
+ifndef NO_SDT
+  ifneq ($(feature-sdt), 1)
+    msg := $(warning No sys/sdt.h found, no SDT events are defined, please install systemtap-sdt-devel or systemtap-sdt-dev);
+    NO_SDT := 1;
+  else
+    CFLAGS += -DHAVE_SDT_EVENT
+    $(call detected,CONFIG_SDT_EVENT)
+  endif
+endif
+
 ifdef PERF_HAVE_JITDUMP
   ifndef NO_DWARF
     $(call detected,CONFIG_JITDUMP)
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 51966d9..143f4d5 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -82,6 +82,7 @@ make_no_auxtrace    := NO_AUXTRACE=1
 make_no_libbpf	    := NO_LIBBPF=1
 make_no_libcrypto   := NO_LIBCRYPTO=1
 make_with_babeltrace:= LIBBABELTRACE=1
+make_no_sdt	    := NO_SDT=1
 make_tags           := tags
 make_cscope         := cscope
 make_help           := help
@@ -105,7 +106,7 @@ make_minimal        := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
 make_minimal        += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
 make_minimal        += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
 make_minimal        += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1
-make_minimal        += NO_LIBCRYPTO=1
+make_minimal        += NO_LIBCRYPTO=1 NO_SDT=1
 
 # $(run) contains all available tests
 run := make_pure

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH perf/core v13 15/15] perf-test: Add a test case for SDT event
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (13 preceding siblings ...)
  2016-07-01  8:05 ` [PATCH perf/core v13 14/15] perf build: Add sdt feature detection Masami Hiramatsu
@ 2016-07-01  8:05 ` Masami Hiramatsu
  2016-07-01 13:19 ` [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Arnaldo Carvalho de Melo
  15 siblings, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-01  8:05 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

Add a basic test case for SDT event support.
This test scans an SDT event in perftools and
check whether the SDT event is correctly stored
into the buildid cache.
Here is an example:
  ----
  $ perf test sdt -v
  47: Test SDT event probing                                   :
  --- start ---
  test child forked, pid 20732
  Found 72 SDTs in /home/mhiramat/ksrc/linux/tools/perf/perf
  Writing cache: %sdt_perf:test_target=test_target
  Cache committed: 0
  symbol:test_target file:(null) line:0 offset:0 return:0 lazy:(null)
  test child finished with 0
  ---- end ----
  Test SDT event probing: Ok
  ----

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 tools/perf/tests/Build          |    1 
 tools/perf/tests/builtin-test.c |    4 +
 tools/perf/tests/sdt.c          |  115 +++++++++++++++++++++++++++++++++++++++
 tools/perf/tests/tests.h        |    1 
 4 files changed, 121 insertions(+)
 create mode 100644 tools/perf/tests/sdt.c

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 66a2898..4158422 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -39,6 +39,7 @@ perf-y += stat.o
 perf-y += event_update.o
 perf-y += event-times.o
 perf-y += backward-ring-buffer.o
+perf-y += sdt.o
 
 $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
 	$(call rule_mkdir)
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 07c14e9..74ed9f5 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -218,6 +218,10 @@ static struct test generic_tests[] = {
 		.func = test__cpu_map_print,
 	},
 	{
+		.desc = "Test SDT event probing",
+		.func = test__sdt_event,
+	},
+	{
 		.func = NULL,
 	},
 };
diff --git a/tools/perf/tests/sdt.c b/tools/perf/tests/sdt.c
new file mode 100644
index 0000000..f59d210
--- /dev/null
+++ b/tools/perf/tests/sdt.c
@@ -0,0 +1,115 @@
+#include <stdio.h>
+#include <sys/epoll.h>
+#include <util/util.h>
+#include <util/evlist.h>
+#include <linux/filter.h>
+#include "tests.h"
+#include "debug.h"
+#include "probe-file.h"
+#include "build-id.h"
+
+/* To test SDT event, we need libelf support to scan elf binary */
+#if defined(HAVE_SDT_EVENT) && defined(HAVE_LIBELF_SUPPORT)
+
+#include <sys/sdt.h>
+
+static int target_function(void)
+{
+	DTRACE_PROBE(perf, test_target);
+	return TEST_OK;
+}
+
+/* Copied from builtin-buildid-cache.c */
+static int build_id_cache__add_file(const char *filename)
+{
+	char sbuild_id[SBUILD_ID_SIZE];
+	u8 build_id[BUILD_ID_SIZE];
+	int err;
+
+	err = filename__read_build_id(filename, &build_id, sizeof(build_id));
+	if (err < 0) {
+		pr_debug("Failed to read build id of %s\n", filename);
+		return err;
+	}
+
+	build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
+	err = build_id_cache__add_s(sbuild_id, filename, false, false);
+	if (err < 0)
+		pr_debug("Failed to add build id cache of %s\n", filename);
+	return err;
+}
+
+static char *get_self_path(void)
+{
+	char *buf = calloc(PATH_MAX, sizeof(char));
+
+	if (buf && readlink("/proc/self/exe", buf, PATH_MAX) < 0) {
+		pr_debug("Failed to get correct path of perf\n");
+		free(buf);
+		return NULL;
+	}
+	return buf;
+}
+
+static int search_cached_probe(const char *target,
+			       const char *group, const char *event)
+{
+	struct probe_cache *cache = probe_cache__new(target);
+	int ret = 0;
+
+	if (!cache) {
+		pr_debug("Failed to open probe cache of %s\n", target);
+		return -EINVAL;
+	}
+
+	if (!probe_cache__find_by_name(cache, group, event)) {
+		pr_debug("Failed to find %s:%s in the cache\n", group, event);
+		ret = -ENOENT;
+	}
+	probe_cache__delete(cache);
+
+	return ret;
+}
+
+int test__sdt_event(int subtests __maybe_unused)
+{
+	int ret = TEST_FAIL;
+	char __tempdir[] = "./test-buildid-XXXXXX";
+	char *tempdir = NULL, *myself = get_self_path();
+
+	if (myself == NULL || mkdtemp(__tempdir) == NULL) {
+		pr_debug("Failed to make a tempdir for build-id cache\n");
+		goto error;
+	}
+	/* Note that buildid_dir must be an absolute path */
+	tempdir = realpath(__tempdir, NULL);
+
+	/* At first, scan itself */
+	set_buildid_dir(tempdir);
+	if (build_id_cache__add_file(myself) < 0)
+		goto error_rmdir;
+
+	/* Open a cache and make sure the SDT is stored */
+	if (search_cached_probe(myself, "sdt_perf", "test_target") < 0)
+		goto error_rmdir;
+
+	/* TBD: probing on the SDT event and collect logs */
+
+	/* Call the target and get an event */
+	ret = target_function();
+
+error_rmdir:
+	/* Cleanup temporary buildid dir */
+	rm_rf(tempdir);
+error:
+	free(tempdir);
+	free(myself);
+	return ret;
+}
+#else
+int test__sdt_event(int subtests __maybe_unused)
+{
+	pr_debug("Skip SDT event test because SDT support is not compiled\n");
+	return TEST_SKIP;
+}
+#endif
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 52f9695..a0288f8 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -88,6 +88,7 @@ int test__event_update(int subtest);
 int test__event_times(int subtest);
 int test__backward_ring_buffer(int subtest);
 int test__cpu_map_print(int subtest);
+int test__sdt_event(int subtest);
 
 #if defined(__arm__) || defined(__aarch64__)
 #ifdef HAVE_DWARF_UNWIND_SUPPORT

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH perf/core v13 00/15] perf-probe --cache and SDT support
  2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
                   ` (14 preceding siblings ...)
  2016-07-01  8:05 ` [PATCH perf/core v13 15/15] perf-test: Add a test case for SDT event Masami Hiramatsu
@ 2016-07-01 13:19 ` Arnaldo Carvalho de Melo
  15 siblings, 0 replies; 32+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-07-01 13:19 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: linux-kernel, Namhyung Kim, Peter Zijlstra, Ingo Molnar,
	Hemant Kumar, Ananth N Mavinakayanahalli, Brendan Gregg

Em Fri, Jul 01, 2016 at 05:03:01PM +0900, Masami Hiramatsu escreveu:
> Hi,
> 
> Here is the 13th version of the patchset for probe-cache and 
> initial SDT support.
> 
> Here is the previous v12: https://lkml.org/lkml/2016/6/24/147

As a suggestion for next time, please keep the history here, inline,
i.e. the text for v11, v10, etc.
 
> In this version, I've removed the patch for perf-list to show
> SDT events, since at this point we don't support SDT from
> perf record. I also change perf-probe --cache --list to show
> cached events on only valid (existing) binaries.
> 
> Thank you,
> 
> ---
> 
> Hemant Kumar (1):
>       perf/sdt: ELF support for SDT
> 
> Masami Hiramatsu (14):
>       perf probe: Use cache entry if possible
>       perf probe: Show all cached probes
>       perf probe: Remove caches when --cache is given
>       perf probe: Add group name support
>       perf buildid-cache: Scan and import user SDT events to probe cache
>       perf probe: Accept %sdt and %cached event name
>       perf-probe: Make --list shows only available cached events
>       perf: probe-cache: Add for_each_probe_cache_entry() wrapper
>       perf probe: Allow wildcard for cached events
>       perf probe: Search SDT/cached event from all probe caches
>       perf probe: Support @BUILDID or @FILE suffix for SDT events
>       perf probe: Support a special SDT probe format
>       perf build: Add sdt feature detection
>       perf-test: Add a test case for SDT event
> 
> 
>  tools/perf/Documentation/perf-buildid-cache.txt |    3 
>  tools/perf/Documentation/perf-probe.txt         |   30 +-
>  tools/perf/Makefile.perf                        |    3 
>  tools/perf/builtin-probe.c                      |   31 ++
>  tools/perf/config/Makefile                      |   10 +
>  tools/perf/tests/Build                          |    1 
>  tools/perf/tests/builtin-test.c                 |    4 
>  tools/perf/tests/make                           |    3 
>  tools/perf/tests/sdt.c                          |  115 +++++++
>  tools/perf/tests/tests.h                        |    1 
>  tools/perf/util/build-id.c                      |  212 +++++++++++++
>  tools/perf/util/build-id.h                      |    4 
>  tools/perf/util/probe-event.c                   |  366 +++++++++++++++++++++--
>  tools/perf/util/probe-event.h                   |    1 
>  tools/perf/util/probe-file.c                    |  226 +++++++++++++-
>  tools/perf/util/probe-file.h                    |   15 +
>  tools/perf/util/symbol-elf.c                    |  252 ++++++++++++++++
>  tools/perf/util/symbol.h                        |   22 +
>  18 files changed, 1235 insertions(+), 64 deletions(-)
>  create mode 100644 tools/perf/tests/sdt.c
> 
> --
> Masami Hiramatsu

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH perf/core v13 01/15] perf probe: Use cache entry if possible
  2016-07-01  8:03 ` [PATCH perf/core v13 01/15] perf probe: Use cache entry if possible Masami Hiramatsu
@ 2016-07-01 13:20   ` Arnaldo Carvalho de Melo
  2016-07-05 10:16   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  1 sibling, 0 replies; 32+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-07-01 13:20 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: linux-kernel, Namhyung Kim, Peter Zijlstra, Ingo Molnar,
	Hemant Kumar, Ananth N Mavinakayanahalli, Brendan Gregg

Em Fri, Jul 01, 2016 at 05:03:12PM +0900, Masami Hiramatsu escreveu:
> From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> 
> Before analyzing debuginfo, try to find a corresponding entry
> from probe cache always. This does not depend on --cache,
> the --cache enables to store/update cache, but looking up
> the cache is always enabled.
> 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> ---
>  Changes in v12:
>   - Rename strlist__for_each to  strlist__for_each_entry.
> 
>  Changes in v6:
>   - Remove fallback lookup routine by using function name
>     as cached event name, because it should be done by following
>     patch which supports %cached-event.

cool, keeping the entries for changes for this specific patch helps in
swapping back into my brain the history of this patch, helping in
re-re-re-re-reviewing 8-)

> ---
>  tools/perf/util/probe-event.c |   65 ++++++++++++++++++++++++++++++++++++++++-
>  tools/perf/util/probe-file.c  |   20 ++++++++++++-
>  tools/perf/util/probe-file.h  |    5 +++
>  3 files changed, 86 insertions(+), 4 deletions(-)
> 
> diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> index 55f41d5..47b6b8b 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -2474,17 +2474,24 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,
>  	char buf[64];
>  	int ret;
>  
> +	/* If probe_event or trace_event already have the name, reuse it */
>  	if (pev->event)
>  		event = pev->event;
> -	else
> +	else if (tev->event)
> +		event = tev->event;
> +	else {
> +		/* Or generate new one from probe point */
>  		if (pev->point.function &&
>  			(strncmp(pev->point.function, "0x", 2) != 0) &&
>  			!strisglob(pev->point.function))
>  			event = pev->point.function;
>  		else
>  			event = tev->point.realname;
> +	}
>  	if (pev->group)
>  		group = pev->group;
> +	else if (tev->group)
> +		group = tev->group;
>  	else
>  		group = PERFPROBE_GROUP;
>  
> @@ -2531,7 +2538,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
>  	for (i = 0; i < ntevs; i++) {
>  		tev = &tevs[i];
>  		/* Skip if the symbol is out of .text or blacklisted */
> -		if (!tev->point.symbol)
> +		if (!tev->point.symbol && !pev->uprobes)
>  			continue;
>  
>  		/* Set new name for tev (and update namelist) */
> @@ -2844,6 +2851,55 @@ errout:
>  
>  bool __weak arch__prefers_symtab(void) { return false; }
>  
> +static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
> +					      struct probe_trace_event **tevs)
> +{
> +	struct probe_cache *cache;
> +	struct probe_cache_entry *entry;
> +	struct probe_trace_event *tev;
> +	struct str_node *node;
> +	int ret, i;
> +
> +	cache = probe_cache__new(pev->target);
> +	if (!cache)
> +		return 0;
> +
> +	entry = probe_cache__find(cache, pev);
> +	if (!entry) {
> +		ret = 0;
> +		goto out;
> +	}
> +
> +	ret = strlist__nr_entries(entry->tevlist);
> +	if (ret > probe_conf.max_probes) {
> +		pr_debug("Too many entries matched in the cache of %s\n",
> +			 pev->target ? : "kernel");
> +		ret = -E2BIG;
> +		goto out;
> +	}
> +
> +	*tevs = zalloc(ret * sizeof(*tev));
> +	if (!*tevs) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	i = 0;
> +	strlist__for_each_entry(node, entry->tevlist) {
> +		tev = &(*tevs)[i++];
> +		ret = parse_probe_trace_command(node->s, tev);
> +		if (ret < 0)
> +			goto out;
> +		/* Set the uprobes attribute as same as original */
> +		tev->uprobes = pev->uprobes;
> +	}
> +	ret = i;
> +
> +out:
> +	probe_cache__delete(cache);
> +	return ret;
> +}
> +
>  static int convert_to_probe_trace_events(struct perf_probe_event *pev,
>  					 struct probe_trace_event **tevs)
>  {
> @@ -2866,6 +2922,11 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
>  	if (ret > 0)
>  		return ret;
>  
> +	/* At first, we need to lookup cache entry */
> +	ret = find_probe_trace_events_from_cache(pev, tevs);
> +	if (ret > 0)
> +		return ret;	/* Found in probe cache */
> +
>  	if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) {
>  		ret = find_probe_trace_events_from_map(pev, tevs);
>  		if (ret > 0)
> diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
> index 1c12c1a..a94ee47 100644
> --- a/tools/perf/util/probe-file.c
> +++ b/tools/perf/util/probe-file.c
> @@ -524,7 +524,7 @@ static bool streql(const char *a, const char *b)
>  	return !strcmp(a, b);
>  }
>  
> -static struct probe_cache_entry *
> +struct probe_cache_entry *
>  probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
>  {
>  	struct probe_cache_entry *entry = NULL;
> @@ -548,6 +548,24 @@ found:
>  	return entry;
>  }
>  
> +struct probe_cache_entry *
> +probe_cache__find_by_name(struct probe_cache *pcache,
> +			  const char *group, const char *event)
> +{
> +	struct probe_cache_entry *entry = NULL;
> +
> +	list_for_each_entry(entry, &pcache->entries, node) {
> +		/* Hit if same event name or same command-string */
> +		if (streql(entry->pev.group, group) &&
> +		    streql(entry->pev.event, event))
> +			goto found;
> +	}
> +	entry = NULL;
> +
> +found:
> +	return entry;
> +}
> +
>  int probe_cache__add_entry(struct probe_cache *pcache,
>  			   struct perf_probe_event *pev,
>  			   struct probe_trace_event *tevs, int ntevs)
> diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
> index d872e3d..910aa74 100644
> --- a/tools/perf/util/probe-file.h
> +++ b/tools/perf/util/probe-file.h
> @@ -38,5 +38,8 @@ int probe_cache__add_entry(struct probe_cache *pcache,
>  int probe_cache__commit(struct probe_cache *pcache);
>  void probe_cache__purge(struct probe_cache *pcache);
>  void probe_cache__delete(struct probe_cache *pcache);
> -
> +struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
> +					    struct perf_probe_event *pev);
> +struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
> +					const char *group, const char *event);
>  #endif

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH perf/core v13 02/15] perf probe: Show all cached probes
  2016-07-01  8:03 ` [PATCH perf/core v13 02/15] perf probe: Show all cached probes Masami Hiramatsu
@ 2016-07-01 13:51   ` Arnaldo Carvalho de Melo
  2016-07-04  2:03     ` Masami Hiramatsu
  2016-07-05 10:17   ` [tip:perf/core] perf probe: Show all cached probes tip-bot for Masami Hiramatsu
  1 sibling, 1 reply; 32+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-07-01 13:51 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: linux-kernel, Namhyung Kim, Peter Zijlstra, Ingo Molnar,
	Hemant Kumar, Ananth N Mavinakayanahalli, Brendan Gregg

Em Fri, Jul 01, 2016 at 05:03:26PM +0900, Masami Hiramatsu escreveu:
> From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> 
> perf probe --list shows all cached probes when --cache
> is given. Each caches are shown with on which binary that
> probed. e.g.
>   -----
>   # perf probe --cache vfs_read \$params

This one works:

# perf probe --cache vfs_read \$params
Added new event:
  probe:vfs_read       (on vfs_read with $params)

You can now use it in all perf tools, such as:

	perf record -e probe:vfs_read -aR sleep 1

#

>   # perf probe --cache -x /lib64/libc-2.17.so getaddrinfo \$params

But this one doesn't and provides a funny message:

[root@jouet perf]# perf probe --cache -x /lib64/libc-2.23.so getaddrinfo \$params
Failed to write event: Invalid argument
Please upgrade your kernel to at least 3.14 to have access to feature $params
  Error: Failed to add events.
[root@jouet perf]#

[root@jouet perf]# uname -a
Linux jouet 4.5.7-300.fc24.x86_64 #1 SMP Wed Jun 8 18:12:45 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
[root@jouet perf]# cat /etc/fedora-release 
Fedora release 24 (Twenty Four)
[root@jouet perf]# 

- Arnaldo

>   # perf probe --cache --list
>   [kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1):
>   vfs_read $params
>   /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc):
>   getaddrinfo $params
>   -----
> Note that $params requires debuginfo.
> 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> ---
>  Changes in v12:
>   - Rename strlist__for_each to strlist__for_each_entry.
>  Changes in v11:
>   - Make build_id_cache__list_all() returns strlist directly. (no error code)
>   - Harden build_id_cache__list_all() to check directory entries.
>  Changes in v7:
>   - Remove the top '/' from binary name if it is not a regular file.
> ---
>  tools/perf/Documentation/perf-probe.txt |    8 ++
>  tools/perf/builtin-probe.c              |    2 -
>  tools/perf/util/build-id.c              |  108 ++++++++++++++++++++++++++++++-
>  tools/perf/util/build-id.h              |    3 +
>  tools/perf/util/probe-event.c           |    3 +
>  tools/perf/util/probe-file.c            |   66 ++++++++++++++++++-
>  tools/perf/util/probe-file.h            |    1 
>  7 files changed, 184 insertions(+), 7 deletions(-)
> 
> diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
> index 947db6f..5a70d45 100644
> --- a/tools/perf/Documentation/perf-probe.txt
> +++ b/tools/perf/Documentation/perf-probe.txt
> @@ -67,7 +67,10 @@ OPTIONS
>  
>  -l::
>  --list[=[GROUP:]EVENT]::
> -	List up current probe events. This can also accept filtering patterns of event names.
> +	List up current probe events. This can also accept filtering patterns of
> +	event names.
> +	When this is used with --cache, perf shows all cached probes instead of
> +	the live probes.
>  
>  -L::
>  --line=::
> @@ -110,8 +113,9 @@ OPTIONS
>  	adding and removal operations.
>  
>  --cache::
> -	Cache the probes (with --add option). Any events which successfully added
> +	(With --add) Cache the probes. Any events which successfully added
>  	are also stored in the cache file.
> +	(With --list) Show cached probes.
>  
>  --max-probes=NUM::
>  	Set the maximum number of probe points for an event. Default is 128.
> diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
> index 3426232..0bb9084 100644
> --- a/tools/perf/builtin-probe.c
> +++ b/tools/perf/builtin-probe.c
> @@ -44,7 +44,7 @@
>  
>  #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
>  #define DEFAULT_FUNC_FILTER "!_*"
> -#define DEFAULT_LIST_FILTER "*:*"
> +#define DEFAULT_LIST_FILTER "*"
>  
>  /* Session management structure */
>  static struct {
> diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> index 62b1473..1c49620 100644
> --- a/tools/perf/util/build-id.c
> +++ b/tools/perf/util/build-id.c
> @@ -165,8 +165,7 @@ retry:
>  	return NULL;
>  }
>  
> -static char *build_id_cache__linkname(const char *sbuild_id, char *bf,
> -				      size_t size)
> +char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size)
>  {
>  	char *tmp = bf;
>  	int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
> @@ -176,6 +175,36 @@ static char *build_id_cache__linkname(const char *sbuild_id, char *bf,
>  	return bf;
>  }
>  
> +char *build_id_cache__origname(const char *sbuild_id)
> +{
> +	char *linkname;
> +	char buf[PATH_MAX];
> +	char *ret = NULL, *p;
> +	size_t offs = 5;	/* == strlen("../..") */
> +
> +	linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
> +	if (!linkname)
> +		return NULL;
> +
> +	if (readlink(linkname, buf, PATH_MAX) < 0)
> +		goto out;
> +	/* The link should be "../..<origpath>/<sbuild_id>" */
> +	p = strrchr(buf, '/');	/* Cut off the "/<sbuild_id>" */
> +	if (p && (p > buf + offs)) {
> +		*p = '\0';
> +		if (buf[offs + 1] == '[')
> +			offs++;	/*
> +				 * This is a DSO name, like [kernel.kallsyms].
> +				 * Skip the first '/', since this is not the
> +				 * cache of a regular file.
> +				 */
> +		ret = strdup(buf + offs);	/* Skip "../..[/]" */
> +	}
> +out:
> +	free(linkname);
> +	return ret;
> +}
> +
>  static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
>  {
>  	return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
> @@ -387,6 +416,81 @@ void disable_buildid_cache(void)
>  	no_buildid_cache = true;
>  }
>  
> +static bool lsdir_bid_head_filter(const char *name __maybe_unused,
> +				  struct dirent *d __maybe_unused)
> +{
> +	return (strlen(d->d_name) == 2) &&
> +		isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]);
> +}
> +
> +static bool lsdir_bid_tail_filter(const char *name __maybe_unused,
> +				  struct dirent *d __maybe_unused)
> +{
> +	int i = 0;
> +	while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3)
> +		i++;
> +	return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0');
> +}
> +
> +struct strlist *build_id_cache__list_all(void)
> +{
> +	struct strlist *toplist, *linklist = NULL, *bidlist;
> +	struct str_node *nd, *nd2;
> +	char *topdir, *linkdir = NULL;
> +	char sbuild_id[SBUILD_ID_SIZE];
> +
> +	/* Open the top-level directory */
> +	if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
> +		return NULL;
> +
> +	bidlist = strlist__new(NULL, NULL);
> +	if (!bidlist)
> +		goto out;
> +
> +	toplist = lsdir(topdir, lsdir_bid_head_filter);
> +	if (!toplist) {
> +		pr_debug("Error in lsdir(%s): %d\n", topdir, errno);
> +		/* If there is no buildid cache, return an empty list */
> +		if (errno == ENOENT)
> +			goto out;
> +		goto err_out;
> +	}
> +
> +	strlist__for_each_entry(nd, toplist) {
> +		if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0)
> +			goto err_out;
> +		/* Open the lower-level directory */
> +		linklist = lsdir(linkdir, lsdir_bid_tail_filter);
> +		if (!linklist) {
> +			pr_debug("Error in lsdir(%s): %d\n", linkdir, errno);
> +			goto err_out;
> +		}
> +		strlist__for_each_entry(nd2, linklist) {
> +			if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s",
> +				     nd->s, nd2->s) != SBUILD_ID_SIZE - 1)
> +				goto err_out;
> +			if (strlist__add(bidlist, sbuild_id) < 0)
> +				goto err_out;
> +		}
> +		strlist__delete(linklist);
> +		zfree(&linkdir);
> +	}
> +
> +out_free:
> +	strlist__delete(toplist);
> +out:
> +	free(topdir);
> +
> +	return bidlist;
> +
> +err_out:
> +	strlist__delete(linklist);
> +	zfree(&linkdir);
> +	strlist__delete(bidlist);
> +	bidlist = NULL;
> +	goto out_free;
> +}
> +
>  char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
>  			       bool is_kallsyms, bool is_vdso)
>  {
> diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
> index d8c7f2f..b742e27 100644
> --- a/tools/perf/util/build-id.h
> +++ b/tools/perf/util/build-id.h
> @@ -30,8 +30,11 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);
>  int perf_session__write_buildid_table(struct perf_session *session, int fd);
>  int perf_session__cache_build_ids(struct perf_session *session);
>  
> +char *build_id_cache__origname(const char *sbuild_id);
> +char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
>  char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
>  			       bool is_kallsyms, bool is_vdso);
> +struct strlist *build_id_cache__list_all(void);
>  int build_id_cache__list_build_ids(const char *pathname,
>  				   struct strlist **result);
>  bool build_id_cache__cached(const char *sbuild_id);
> diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> index 47b6b8b..f81b5dd 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -2366,6 +2366,9 @@ int show_perf_probe_events(struct strfilter *filter)
>  
>  	setup_pager();
>  
> +	if (probe_conf.cache)
> +		return probe_cache__show_all_caches(filter);
> +
>  	ret = init_probe_symbol_maps(false);
>  	if (ret < 0)
>  		return ret;
> diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
> index a94ee47..156e3d8 100644
> --- a/tools/perf/util/probe-file.c
> +++ b/tools/perf/util/probe-file.c
> @@ -367,10 +367,17 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
>  {
>  	char cpath[PATH_MAX];
>  	char sbuildid[SBUILD_ID_SIZE];
> -	char *dir_name;
> +	char *dir_name = NULL;
>  	bool is_kallsyms = !target;
>  	int ret, fd;
>  
> +	if (target && build_id_cache__cached(target)) {
> +		/* This is a cached buildid */
> +		strncpy(sbuildid, target, SBUILD_ID_SIZE);
> +		dir_name = build_id_cache__linkname(sbuildid, NULL, 0);
> +		goto found;
> +	}
> +
>  	if (target)
>  		ret = filename__sprintf_build_id(target, sbuildid);
>  	else {
> @@ -394,8 +401,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
>  
>  	dir_name = build_id_cache__cachedir(sbuildid, target, is_kallsyms,
>  					    false);
> -	if (!dir_name)
> +found:
> +	if (!dir_name) {
> +		pr_debug("Failed to get cache from %s\n", target);
>  		return -ENOMEM;
> +	}
>  
>  	snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
>  	fd = open(cpath, O_CREAT | O_RDWR, 0644);
> @@ -673,3 +683,55 @@ int probe_cache__commit(struct probe_cache *pcache)
>  out:
>  	return ret;
>  }
> +
> +static int probe_cache__show_entries(struct probe_cache *pcache,
> +				     struct strfilter *filter)
> +{
> +	struct probe_cache_entry *entry;
> +	char buf[128], *ptr;
> +
> +	list_for_each_entry(entry, &pcache->entries, node) {
> +		if (entry->pev.event) {
> +			ptr = buf;
> +			snprintf(buf, 128, "%s:%s",
> +				 entry->pev.group, entry->pev.event);
> +		} else
> +			ptr = entry->spev;
> +		if (strfilter__compare(filter, ptr))
> +			printf("%s\n", entry->spev);
> +	}
> +	return 0;
> +}
> +
> +/* Show all cached probes */
> +int probe_cache__show_all_caches(struct strfilter *filter)
> +{
> +	struct probe_cache *pcache;
> +	struct strlist *bidlist;
> +	struct str_node *nd;
> +	char *buf = strfilter__string(filter);
> +
> +	pr_debug("list cache with filter: %s\n", buf);
> +	free(buf);
> +
> +	bidlist = build_id_cache__list_all();
> +	if (!bidlist) {
> +		pr_debug("Failed to get buildids: %d\n", errno);
> +		return -EINVAL;
> +	}
> +	strlist__for_each_entry(nd, bidlist) {
> +		pcache = probe_cache__new(nd->s);
> +		if (!pcache)
> +			continue;
> +		if (!list_empty(&pcache->entries)) {
> +			buf = build_id_cache__origname(nd->s);
> +			printf("%s (%s):\n", buf, nd->s);
> +			free(buf);
> +			probe_cache__show_entries(pcache, filter);
> +		}
> +		probe_cache__delete(pcache);
> +	}
> +	strlist__delete(bidlist);
> +
> +	return 0;
> +}
> diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
> index 910aa74..0009b8a 100644
> --- a/tools/perf/util/probe-file.h
> +++ b/tools/perf/util/probe-file.h
> @@ -42,4 +42,5 @@ struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
>  					    struct perf_probe_event *pev);
>  struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
>  					const char *group, const char *event);
> +int probe_cache__show_all_caches(struct strfilter *filter);
>  #endif

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache
  2016-07-01  8:04 ` [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache Masami Hiramatsu
@ 2016-07-01 18:22   ` Arnaldo Carvalho de Melo
  2016-07-04  2:15     ` Masami Hiramatsu
  2016-07-05  2:08     ` Masami Hiramatsu
  2016-07-05 10:19   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  1 sibling, 2 replies; 32+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-07-01 18:22 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: linux-kernel, Namhyung Kim, Peter Zijlstra, Ingo Molnar,
	Hemant Kumar, Ananth N Mavinakayanahalli, Brendan Gregg

Em Fri, Jul 01, 2016 at 05:04:10PM +0900, Masami Hiramatsu escreveu:
> From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> 
> 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

Why not remove the need for that build-cache --add? I.e. go straight to:

  perf probe -x /usr/lib/libc-2.17.so -a sdt_libc:memory_heap_new=memory_heap_new

And all the various steps above be done automagically?

It may well be interesting to have it available as separate steps, as above,
but requiring this cumbersome sequence to performed all the time when it seems
possible to do automatically seems user unfriendly.

I am tentatively applying this and testing.

- Arnaldo

>   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 "%".

Is this still the case?

[root@jouet perf]# perf probe --cache --list
/usr/lib64/libc-2.23.so (88686319c72f1a9d9cd514af519aa5602880bab2):
sdt_libc:setjmp=setjmp
sdt_libc:longjmp=longjmp
sdt_libc:longjmp_target=longjmp_target
sdt_libc:memory_arena_reuse_free_list=memory_arena_reuse_free_list
sdt_libc:memory_heap_new=memory_heap_new
sdt_libc:memory_sbrk_less=memory_sbrk_less
sdt_libc:memory_arena_reuse_wait=memory_arena_reuse_wait
sdt_libc:memory_arena_reuse=memory_arena_reuse
sdt_libc:memory_arena_new=memory_arena_new
sdt_libc:memory_arena_retry=memory_arena_retry
sdt_libc:memory_heap_free=memory_heap_free
sdt_libc:memory_heap_less=memory_heap_less
sdt_libc:memory_heap_more=memory_heap_more
sdt_libc:memory_sbrk_more=memory_sbrk_more
sdt_libc:memory_malloc_retry=memory_malloc_retry
sdt_libc:memory_mallopt_free_dyn_thresholds=memory_mallopt_free_dyn_thresholds
sdt_libc:memory_realloc_retry=memory_realloc_retry
sdt_libc:memory_memalign_retry=memory_memalign_retry
sdt_libc:memory_calloc_retry=memory_calloc_retry
sdt_libc:memory_mallopt=memory_mallopt
sdt_libc:memory_mallopt_mxfast=memory_mallopt_mxfast
sdt_libc:memory_mallopt_arena_max=memory_mallopt_arena_max
sdt_libc:memory_mallopt_arena_test=memory_mallopt_arena_test
sdt_libc:memory_mallopt_mmap_max=memory_mallopt_mmap_max
sdt_libc:memory_mallopt_mmap_threshold=memory_mallopt_mmap_threshold
sdt_libc:memory_mallopt_top_pad=memory_mallopt_top_pad
sdt_libc:memory_mallopt_trim_threshold=memory_mallopt_trim_threshold
sdt_libc:memory_mallopt_perturb=memory_mallopt_perturb
sdt_libc:memory_mallopt_check_action=memory_mallopt_check_action
sdt_libc:lll_lock_wait_private=lll_lock_wait_private
[root@jouet perf]# 


 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> ---
>  Changes in v11:
>   - Warn if SDT scanning/updating are failed.
>  Changes in v10:
>   - Update Documentation/perf-buildid-cache.txt too.
>  Changes in v4:
>   - Fix a bug to copy correct group name to entries.
>   - Fix to consolidate same-name entries.
> ---
>  tools/perf/Documentation/perf-buildid-cache.txt |    3 +
>  tools/perf/util/build-id.c                      |   30 ++++++++++
>  tools/perf/util/probe-file.c                    |   69 ++++++++++++++++++++++-
>  tools/perf/util/probe-file.h                    |    2 +
>  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 dd07b55..058064d 100644
> --- a/tools/perf/Documentation/perf-buildid-cache.txt
> +++ b/tools/perf/Documentation/perf-buildid-cache.txt
> @@ -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
>  -------
> diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> index 1c49620..e1a1640 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;
> @@ -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)
>  {
> @@ -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);
> diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
> index 6cb6ec0..5b563b2 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)
>  		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);
> diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
> index 0ed1fc5..ddf5ae2 100644
> --- a/tools/perf/util/probe-file.h
> +++ b/tools/perf/util/probe-file.h
> @@ -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;
> @@ -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);

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH perf/core v13 04/15] perf/sdt: ELF support for SDT
  2016-07-01  8:03 ` [PATCH perf/core v13 04/15] perf/sdt: ELF support for SDT Masami Hiramatsu
@ 2016-07-01 18:56   ` Arnaldo Carvalho de Melo
  2016-07-04  5:25     ` Masami Hiramatsu
  2016-07-05 10:18   ` [tip:perf/core] perf sdt: " tip-bot for Hemant Kumar
  1 sibling, 1 reply; 32+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-07-01 18:56 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: linux-kernel, Namhyung Kim, Peter Zijlstra, Ingo Molnar,
	Hemant Kumar, Ananth N Mavinakayanahalli, Brendan Gregg

Em Fri, Jul 01, 2016 at 05:03:46PM +0900, Masami Hiramatsu escreveu:
> From: Hemant Kumar <hemant@linux.vnet.ibm.com>
> 
> This patch serves the initial support to identify and list SDT events in binaries.
> When programs containing SDT markers are compiled, gcc with the help of assembler
> directives identifies them and places them in the section ".note.stapsdt". To find
> these markers from the binaries, one needs to traverse through this section and
> parse the relevant details like the name, type and location of the marker. Also,
> the original location could be skewed due to the effect of prelinking. If that is
> the case, the locations need to be adjusted.
> 
> The functions in this patch open a given ELF, find out the SDT section, parse the
> relevant details, adjust the location (if necessary) and populate them in a list.

Breaks the build on older systems:


[root@jouet perf]# dm
centos:5: FAIL
  CC       /tmp/build/perf/util/symbol-elf.o
cc1: warnings being treated as errors
util/symbol-elf.c: In function 'construct_sdt_notes_list':
util/symbol-elf.c:1927: warning: implicit declaration of function 'elf_getshdrstrndx'
util/symbol-elf.c:1927: warning: nested extern declaration of 'elf_getshdrstrndx'
mv: cannot stat `/tmp/build/perf/util/.symbol-elf.o.tmp': No such file or directory
make[3]: *** [/tmp/build/perf/util/symbol-elf.o] Error 1
make[3]: *** Waiting for unfinished jobs....
make[2]: *** [util] Error 2
make[1]: *** [/tmp/build/perf/libperf-in.o] Error 2
make: *** [install-bin] Error 2
make: Leaving directory `/git/linux/tools/perf'
centos:6: Ok
centos:7: Ok
debian:experimental: Ok
debian:7: Ok
debian:8: Ok
fedora:21: Ok
fedora:22: Ok
fedora:23: Ok
fedora:24: Ok
opensuse:13.2: Ok
opensuse:42.1: Ok
ubuntu:14.04.4: Ok
ubuntu:15.10: Ok
ubuntu:16.04: Ok
ubuntu:12.04.5: Ok

---------

Needs a feature detection test, I will try to contribute that.

- Arnaldo

 
> A typical note entry in ".note.stapsdt" section is as follows :
> 
> 
>                                  |--nhdr.n_namesz--|
>                 ------------------------------------
>                 |      nhdr      |     "stapsdt"   |
>         -----   |----------------------------------|
>          |      |  <location>       <base_address> |
>          |      |  <semaphore>                     |
> nhdr.n_descsize |  "provider_name"   "note_name"   |
>          |      |   <args>                         |
>         -----   |----------------------------------|
>                 |      nhdr      |     "stapsdt"   |
>                 |...
> 
> The above shows an excerpt from the section ".note.stapsdt".
> 'nhdr' is a structure which has the note name size (n_namesz), note
> description size (n_desc_sz) and note type (n_type). So, in order to
> parse the note note info, we need nhdr to tell us where to start from.
> As can be seen from <sys/sdt.h>, the name of the SDT notes given is "stapsdt".
> But this is not the identifier of the note.
> After that, we go to description of the note to find out its location, the
> address of the ".stapsdt.base" section and the semaphore address.
> Then, we find the provider name and the SDT marker name and then follow the
> arguments.
> 
> Signed-off-by: Hemant Kumar <hemant@linux.vnet.ibm.com>
> Reviewed-by: Masami Hiramatsu <mhiramat@kernel.org>
> Acked-by: Namhyung Kim <namhyung@kernel.org>
> ---
>  tools/perf/util/symbol-elf.c |  252 ++++++++++++++++++++++++++++++++++++++++++
>  tools/perf/util/symbol.h     |   22 ++++
>  2 files changed, 274 insertions(+)
> 
> diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
> index 87a297d..e74ce17 100644
> --- a/tools/perf/util/symbol-elf.c
> +++ b/tools/perf/util/symbol-elf.c
> @@ -1781,6 +1781,258 @@ void kcore_extract__delete(struct kcore_extract *kce)
>  	unlink(kce->extract_filename);
>  }
>  
> +/**
> + * populate_sdt_note : Parse raw data and identify SDT note
> + * @elf: elf of the opened file
> + * @data: raw data of a section with description offset applied
> + * @len: note description size
> + * @type: type of the note
> + * @sdt_notes: List to add the SDT note
> + *
> + * Responsible for parsing the @data in section .note.stapsdt in @elf and
> + * if its an SDT note, it appends to @sdt_notes list.
> + */
> +static int populate_sdt_note(Elf **elf, const char *data, size_t len,
> +			     struct list_head *sdt_notes)
> +{
> +	const char *provider, *name;
> +	struct sdt_note *tmp = NULL;
> +	GElf_Ehdr ehdr;
> +	GElf_Addr base_off = 0;
> +	GElf_Shdr shdr;
> +	int ret = -EINVAL;
> +
> +	union {
> +		Elf64_Addr a64[NR_ADDR];
> +		Elf32_Addr a32[NR_ADDR];
> +	} buf;
> +
> +	Elf_Data dst = {
> +		.d_buf = &buf, .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
> +		.d_size = gelf_fsize((*elf), ELF_T_ADDR, NR_ADDR, EV_CURRENT),
> +		.d_off = 0, .d_align = 0
> +	};
> +	Elf_Data src = {
> +		.d_buf = (void *) data, .d_type = ELF_T_ADDR,
> +		.d_version = EV_CURRENT, .d_size = dst.d_size, .d_off = 0,
> +		.d_align = 0
> +	};
> +
> +	tmp = (struct sdt_note *)calloc(1, sizeof(struct sdt_note));
> +	if (!tmp) {
> +		ret = -ENOMEM;
> +		goto out_err;
> +	}
> +
> +	INIT_LIST_HEAD(&tmp->note_list);
> +
> +	if (len < dst.d_size + 3)
> +		goto out_free_note;
> +
> +	/* Translation from file representation to memory representation */
> +	if (gelf_xlatetom(*elf, &dst, &src,
> +			  elf_getident(*elf, NULL)[EI_DATA]) == NULL) {
> +		pr_err("gelf_xlatetom : %s\n", elf_errmsg(-1));
> +		goto out_free_note;
> +	}
> +
> +	/* Populate the fields of sdt_note */
> +	provider = data + dst.d_size;
> +
> +	name = (const char *)memchr(provider, '\0', data + len - provider);
> +	if (name++ == NULL)
> +		goto out_free_note;
> +
> +	tmp->provider = strdup(provider);
> +	if (!tmp->provider) {
> +		ret = -ENOMEM;
> +		goto out_free_note;
> +	}
> +	tmp->name = strdup(name);
> +	if (!tmp->name) {
> +		ret = -ENOMEM;
> +		goto out_free_prov;
> +	}
> +
> +	if (gelf_getclass(*elf) == ELFCLASS32) {
> +		memcpy(&tmp->addr, &buf, 3 * sizeof(Elf32_Addr));
> +		tmp->bit32 = true;
> +	} else {
> +		memcpy(&tmp->addr, &buf, 3 * sizeof(Elf64_Addr));
> +		tmp->bit32 = false;
> +	}
> +
> +	if (!gelf_getehdr(*elf, &ehdr)) {
> +		pr_debug("%s : cannot get elf header.\n", __func__);
> +		ret = -EBADF;
> +		goto out_free_name;
> +	}
> +
> +	/* Adjust the prelink effect :
> +	 * Find out the .stapsdt.base section.
> +	 * This scn will help us to handle prelinking (if present).
> +	 * Compare the retrieved file offset of the base section with the
> +	 * base address in the description of the SDT note. If its different,
> +	 * then accordingly, adjust the note location.
> +	 */
> +	if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) {
> +		base_off = shdr.sh_offset;
> +		if (base_off) {
> +			if (tmp->bit32)
> +				tmp->addr.a32[0] = tmp->addr.a32[0] + base_off -
> +					tmp->addr.a32[1];
> +			else
> +				tmp->addr.a64[0] = tmp->addr.a64[0] + base_off -
> +					tmp->addr.a64[1];
> +		}
> +	}
> +
> +	list_add_tail(&tmp->note_list, sdt_notes);
> +	return 0;
> +
> +out_free_name:
> +	free(tmp->name);
> +out_free_prov:
> +	free(tmp->provider);
> +out_free_note:
> +	free(tmp);
> +out_err:
> +	return ret;
> +}
> +
> +/**
> + * construct_sdt_notes_list : constructs a list of SDT notes
> + * @elf : elf to look into
> + * @sdt_notes : empty list_head
> + *
> + * Scans the sections in 'elf' for the section
> + * .note.stapsdt. It, then calls populate_sdt_note to find
> + * out the SDT events and populates the 'sdt_notes'.
> + */
> +static int construct_sdt_notes_list(Elf *elf, struct list_head *sdt_notes)
> +{
> +	GElf_Ehdr ehdr;
> +	Elf_Scn *scn = NULL;
> +	Elf_Data *data;
> +	GElf_Shdr shdr;
> +	size_t shstrndx, next;
> +	GElf_Nhdr nhdr;
> +	size_t name_off, desc_off, offset;
> +	int ret = 0;
> +
> +	if (gelf_getehdr(elf, &ehdr) == NULL) {
> +		ret = -EBADF;
> +		goto out_ret;
> +	}
> +	if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
> +		ret = -EBADF;
> +		goto out_ret;
> +	}
> +
> +	/* Look for the required section */
> +	scn = elf_section_by_name(elf, &ehdr, &shdr, SDT_NOTE_SCN, NULL);
> +	if (!scn) {
> +		ret = -ENOENT;
> +		goto out_ret;
> +	}
> +
> +	if ((shdr.sh_type != SHT_NOTE) || (shdr.sh_flags & SHF_ALLOC)) {
> +		ret = -ENOENT;
> +		goto out_ret;
> +	}
> +
> +	data = elf_getdata(scn, NULL);
> +
> +	/* Get the SDT notes */
> +	for (offset = 0; (next = gelf_getnote(data, offset, &nhdr, &name_off,
> +					      &desc_off)) > 0; offset = next) {
> +		if (nhdr.n_namesz == sizeof(SDT_NOTE_NAME) &&
> +		    !memcmp(data->d_buf + name_off, SDT_NOTE_NAME,
> +			    sizeof(SDT_NOTE_NAME))) {
> +			/* Check the type of the note */
> +			if (nhdr.n_type != SDT_NOTE_TYPE)
> +				goto out_ret;
> +
> +			ret = populate_sdt_note(&elf, ((data->d_buf) + desc_off),
> +						nhdr.n_descsz, sdt_notes);
> +			if (ret < 0)
> +				goto out_ret;
> +		}
> +	}
> +	if (list_empty(sdt_notes))
> +		ret = -ENOENT;
> +
> +out_ret:
> +	return ret;
> +}
> +
> +/**
> + * get_sdt_note_list : Wrapper to construct a list of sdt notes
> + * @head : empty list_head
> + * @target : file to find SDT notes from
> + *
> + * This opens the file, initializes
> + * the ELF and then calls construct_sdt_notes_list.
> + */
> +int get_sdt_note_list(struct list_head *head, const char *target)
> +{
> +	Elf *elf;
> +	int fd, ret;
> +
> +	fd = open(target, O_RDONLY);
> +	if (fd < 0)
> +		return -EBADF;
> +
> +	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
> +	if (!elf) {
> +		ret = -EBADF;
> +		goto out_close;
> +	}
> +	ret = construct_sdt_notes_list(elf, head);
> +	elf_end(elf);
> +out_close:
> +	close(fd);
> +	return ret;
> +}
> +
> +/**
> + * cleanup_sdt_note_list : free the sdt notes' list
> + * @sdt_notes: sdt notes' list
> + *
> + * Free up the SDT notes in @sdt_notes.
> + * Returns the number of SDT notes free'd.
> + */
> +int cleanup_sdt_note_list(struct list_head *sdt_notes)
> +{
> +	struct sdt_note *tmp, *pos;
> +	int nr_free = 0;
> +
> +	list_for_each_entry_safe(pos, tmp, sdt_notes, note_list) {
> +		list_del(&pos->note_list);
> +		free(pos->name);
> +		free(pos->provider);
> +		free(pos);
> +		nr_free++;
> +	}
> +	return nr_free;
> +}
> +
> +/**
> + * sdt_notes__get_count: Counts the number of sdt events
> + * @start: list_head to sdt_notes list
> + *
> + * Returns the number of SDT notes in a list
> + */
> +int sdt_notes__get_count(struct list_head *start)
> +{
> +	struct sdt_note *sdt_ptr;
> +	int count = 0;
> +
> +	list_for_each_entry(sdt_ptr, start, note_list)
> +		count++;
> +	return count;
> +}
> +
>  void symbol__elf_init(void)
>  {
>  	elf_version(EV_CURRENT);
> diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
> index b10d558..699f7cb 100644
> --- a/tools/perf/util/symbol.h
> +++ b/tools/perf/util/symbol.h
> @@ -342,4 +342,26 @@ void arch__sym_update(struct symbol *s, GElf_Sym *sym);
>  
>  int arch__choose_best_symbol(struct symbol *syma, struct symbol *symb);
>  
> +/* structure containing an SDT note's info */
> +struct sdt_note {
> +	char *name;			/* name of the note*/
> +	char *provider;			/* provider name */
> +	bool bit32;			/* whether the location is 32 bits? */
> +	union {				/* location, base and semaphore addrs */
> +		Elf64_Addr a64[3];
> +		Elf32_Addr a32[3];
> +	} addr;
> +	struct list_head note_list;	/* SDT notes' list */
> +};
> +
> +int get_sdt_note_list(struct list_head *head, const char *target);
> +int cleanup_sdt_note_list(struct list_head *sdt_notes);
> +int sdt_notes__get_count(struct list_head *start);
> +
> +#define SDT_BASE_SCN ".stapsdt.base"
> +#define SDT_NOTE_SCN  ".note.stapsdt"
> +#define SDT_NOTE_TYPE 3
> +#define SDT_NOTE_NAME "stapsdt"
> +#define NR_ADDR 3
> +
>  #endif /* __PERF_SYMBOL */

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH perf/core v13 02/15] perf probe: Show all cached probes
  2016-07-01 13:51   ` Arnaldo Carvalho de Melo
@ 2016-07-04  2:03     ` Masami Hiramatsu
  2016-07-04  2:06       ` [PATCH perf/core] [BUGFIX] perf-probe: Fix to show correct error message for $vars and $params Masami Hiramatsu
  0 siblings, 1 reply; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-04  2:03 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: linux-kernel, Namhyung Kim, Peter Zijlstra, Ingo Molnar,
	Hemant Kumar, Ananth N Mavinakayanahalli, Brendan Gregg

On Fri, 1 Jul 2016 10:51:04 -0300
Arnaldo Carvalho de Melo <acme@kernel.org> wrote:

> Em Fri, Jul 01, 2016 at 05:03:26PM +0900, Masami Hiramatsu escreveu:
> > From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > 
> > perf probe --list shows all cached probes when --cache
> > is given. Each caches are shown with on which binary that
> > probed. e.g.
> >   -----
> >   # perf probe --cache vfs_read \$params
> 
> This one works:
> 
> # perf probe --cache vfs_read \$params
> Added new event:
>   probe:vfs_read       (on vfs_read with $params)
> 
> You can now use it in all perf tools, such as:
> 
> 	perf record -e probe:vfs_read -aR sleep 1
> 
> #
> 
> >   # perf probe --cache -x /lib64/libc-2.17.so getaddrinfo \$params
> 
> But this one doesn't and provides a funny message:
> 
> [root@jouet perf]# perf probe --cache -x /lib64/libc-2.23.so getaddrinfo \$params
> Failed to write event: Invalid argument
> Please upgrade your kernel to at least 3.14 to have access to feature $params
>   Error: Failed to add events.

Ah, OK, $params requires debuginfo. It this error message is not correct.
I'll send a fix soon.

Thanks!!


-- 
Masami Hiramatsu <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH perf/core] [BUGFIX] perf-probe: Fix to show correct error message for $vars and $params
  2016-07-04  2:03     ` Masami Hiramatsu
@ 2016-07-04  2:06       ` Masami Hiramatsu
  0 siblings, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-04  2:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, linux-kernel, Namhyung Kim, Peter Zijlstra,
	Ingo Molnar, Hemant Kumar, Ananth N Mavinakayanahalli,
	Brendan Gregg

Fix to show correct error messages for $vars and $params because
those special variables requires debug information to find the
real variables or function parameters.

E.g. without this fix;
  ----
  # perf probe -x /lib64/libc-2.23.so getaddrinfo \$params
  Failed to write event: Invalid argument
  Please upgrade your kernel to at least 3.14 to have access to feature $params
    Error: Failed to add events.
  ----
Perf ends up with an error, but the message is not correct.
With this fix, perf shows correct error message as below.
  ----
  # perf probe -x /lib64/libc-2.23.so getaddrinfo \$params
  The /usr/lib64/libc-2.23.so file has no debug information.
  Rebuild with -g, or install an appropriate debuginfo package.
    Error: Failed to add events.
  ----

Reported-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 tools/perf/util/probe-event.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 55f41d5..dcc906b 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1542,7 +1542,9 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
 		return true;
 
 	for (i = 0; i < pev->nargs; i++)
-		if (is_c_varname(pev->args[i].var))
+		if (is_c_varname(pev->args[i].var) ||
+		    !strcmp(pev->args[i].var, "$params") ||
+		    !strcmp(pev->args[i].var, "$vars"))
 			return true;
 
 	return false;

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache
  2016-07-01 18:22   ` Arnaldo Carvalho de Melo
@ 2016-07-04  2:15     ` Masami Hiramatsu
  2016-07-05  2:08     ` Masami Hiramatsu
  1 sibling, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-04  2:15 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: linux-kernel, Namhyung Kim, Peter Zijlstra, Ingo Molnar,
	Hemant Kumar, Ananth N Mavinakayanahalli, Brendan Gregg

On Fri, 1 Jul 2016 15:22:01 -0300
Arnaldo Carvalho de Melo <acme@kernel.org> wrote:

> Em Fri, Jul 01, 2016 at 05:04:10PM +0900, Masami Hiramatsu escreveu:
> > From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > 
> > 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
> 
> Why not remove the need for that build-cache --add? I.e. go straight to:
> 
>   perf probe -x /usr/lib/libc-2.17.so -a sdt_libc:memory_heap_new=memory_heap_new
> 
> And all the various steps above be done automagically?

Yes, I can add that.

> It may well be interesting to have it available as separate steps, as above,
> but requiring this cumbersome sequence to performed all the time when it seems
> possible to do automatically seems user unfriendly.

Agreed. In 11/15 added a feature to search SDT without -x, but
usually uprobes requires -x, using -x is also natural.

> 
> I am tentatively applying this and testing.

Thank you!

> 
> - Arnaldo
> 
> >   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 "%".
> 
> Is this still the case?
> 
> [root@jouet perf]# perf probe --cache --list
> /usr/lib64/libc-2.23.so (88686319c72f1a9d9cd514af519aa5602880bab2):
> sdt_libc:setjmp=setjmp
> sdt_libc:longjmp=longjmp
> sdt_libc:longjmp_target=longjmp_target
> sdt_libc:memory_arena_reuse_free_list=memory_arena_reuse_free_list
> sdt_libc:memory_heap_new=memory_heap_new
> sdt_libc:memory_sbrk_less=memory_sbrk_less
> sdt_libc:memory_arena_reuse_wait=memory_arena_reuse_wait
> sdt_libc:memory_arena_reuse=memory_arena_reuse
> sdt_libc:memory_arena_new=memory_arena_new
> sdt_libc:memory_arena_retry=memory_arena_retry
> sdt_libc:memory_heap_free=memory_heap_free
> sdt_libc:memory_heap_less=memory_heap_less
> sdt_libc:memory_heap_more=memory_heap_more
> sdt_libc:memory_sbrk_more=memory_sbrk_more
> sdt_libc:memory_malloc_retry=memory_malloc_retry
> sdt_libc:memory_mallopt_free_dyn_thresholds=memory_mallopt_free_dyn_thresholds
> sdt_libc:memory_realloc_retry=memory_realloc_retry
> sdt_libc:memory_memalign_retry=memory_memalign_retry
> sdt_libc:memory_calloc_retry=memory_calloc_retry
> sdt_libc:memory_mallopt=memory_mallopt
> sdt_libc:memory_mallopt_mxfast=memory_mallopt_mxfast
> sdt_libc:memory_mallopt_arena_max=memory_mallopt_arena_max
> sdt_libc:memory_mallopt_arena_test=memory_mallopt_arena_test
> sdt_libc:memory_mallopt_mmap_max=memory_mallopt_mmap_max
> sdt_libc:memory_mallopt_mmap_threshold=memory_mallopt_mmap_threshold
> sdt_libc:memory_mallopt_top_pad=memory_mallopt_top_pad
> sdt_libc:memory_mallopt_trim_threshold=memory_mallopt_trim_threshold
> sdt_libc:memory_mallopt_perturb=memory_mallopt_perturb
> sdt_libc:memory_mallopt_check_action=memory_mallopt_check_action
> sdt_libc:lll_lock_wait_private=lll_lock_wait_private
> [root@jouet perf]# 
> 
> 
>  
> > Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> > ---
> >  Changes in v11:
> >   - Warn if SDT scanning/updating are failed.
> >  Changes in v10:
> >   - Update Documentation/perf-buildid-cache.txt too.
> >  Changes in v4:
> >   - Fix a bug to copy correct group name to entries.
> >   - Fix to consolidate same-name entries.
> > ---
> >  tools/perf/Documentation/perf-buildid-cache.txt |    3 +
> >  tools/perf/util/build-id.c                      |   30 ++++++++++
> >  tools/perf/util/probe-file.c                    |   69 ++++++++++++++++++++++-
> >  tools/perf/util/probe-file.h                    |    2 +
> >  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 dd07b55..058064d 100644
> > --- a/tools/perf/Documentation/perf-buildid-cache.txt
> > +++ b/tools/perf/Documentation/perf-buildid-cache.txt
> > @@ -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
> >  -------
> > diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> > index 1c49620..e1a1640 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;
> > @@ -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)
> >  {
> > @@ -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);
> > diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
> > index 6cb6ec0..5b563b2 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)
> >  		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);
> > diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
> > index 0ed1fc5..ddf5ae2 100644
> > --- a/tools/perf/util/probe-file.h
> > +++ b/tools/perf/util/probe-file.h
> > @@ -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;
> > @@ -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);


-- 
Masami Hiramatsu <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH perf/core v13 04/15] perf/sdt: ELF support for SDT
  2016-07-01 18:56   ` Arnaldo Carvalho de Melo
@ 2016-07-04  5:25     ` Masami Hiramatsu
  0 siblings, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-04  5:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: linux-kernel, Namhyung Kim, Peter Zijlstra, Ingo Molnar,
	Hemant Kumar, Ananth N Mavinakayanahalli, Brendan Gregg

On Fri, 1 Jul 2016 15:56:49 -0300
Arnaldo Carvalho de Melo <acme@kernel.org> wrote:

> Em Fri, Jul 01, 2016 at 05:03:46PM +0900, Masami Hiramatsu escreveu:
> > From: Hemant Kumar <hemant@linux.vnet.ibm.com>
> > 
> > This patch serves the initial support to identify and list SDT events in binaries.
> > When programs containing SDT markers are compiled, gcc with the help of assembler
> > directives identifies them and places them in the section ".note.stapsdt". To find
> > these markers from the binaries, one needs to traverse through this section and
> > parse the relevant details like the name, type and location of the marker. Also,
> > the original location could be skewed due to the effect of prelinking. If that is
> > the case, the locations need to be adjusted.
> > 
> > The functions in this patch open a given ELF, find out the SDT section, parse the
> > relevant details, adjust the location (if necessary) and populate them in a list.
> 
> Breaks the build on older systems:
> 
> 
> [root@jouet perf]# dm
> centos:5: FAIL
>   CC       /tmp/build/perf/util/symbol-elf.o
> cc1: warnings being treated as errors
> util/symbol-elf.c: In function 'construct_sdt_notes_list':
> util/symbol-elf.c:1927: warning: implicit declaration of function 'elf_getshdrstrndx'
> util/symbol-elf.c:1927: warning: nested extern declaration of 'elf_getshdrstrndx'
> mv: cannot stat `/tmp/build/perf/util/.symbol-elf.o.tmp': No such file or directory
> make[3]: *** [/tmp/build/perf/util/symbol-elf.o] Error 1
> make[3]: *** Waiting for unfinished jobs....
> make[2]: *** [util] Error 2
> make[1]: *** [/tmp/build/perf/libperf-in.o] Error 2
> make: *** [install-bin] Error 2
> make: Leaving directory `/git/linux/tools/perf'
> centos:6: Ok
> centos:7: Ok
> debian:experimental: Ok
> debian:7: Ok
> debian:8: Ok
> fedora:21: Ok
> fedora:22: Ok
> fedora:23: Ok
> fedora:24: Ok
> opensuse:13.2: Ok
> opensuse:42.1: Ok
> ubuntu:14.04.4: Ok
> ubuntu:15.10: Ok
> ubuntu:16.04: Ok
> ubuntu:12.04.5: Ok
> 
> ---------

OK, that API is newer one. We have to check wheter it is supported by libelf.

> 
> Needs a feature detection test, I will try to contribute that.

Thanks!

> 
> - Arnaldo
> 
>  
> > A typical note entry in ".note.stapsdt" section is as follows :
> > 
> > 
> >                                  |--nhdr.n_namesz--|
> >                 ------------------------------------
> >                 |      nhdr      |     "stapsdt"   |
> >         -----   |----------------------------------|
> >          |      |  <location>       <base_address> |
> >          |      |  <semaphore>                     |
> > nhdr.n_descsize |  "provider_name"   "note_name"   |
> >          |      |   <args>                         |
> >         -----   |----------------------------------|
> >                 |      nhdr      |     "stapsdt"   |
> >                 |...
> > 
> > The above shows an excerpt from the section ".note.stapsdt".
> > 'nhdr' is a structure which has the note name size (n_namesz), note
> > description size (n_desc_sz) and note type (n_type). So, in order to
> > parse the note note info, we need nhdr to tell us where to start from.
> > As can be seen from <sys/sdt.h>, the name of the SDT notes given is "stapsdt".
> > But this is not the identifier of the note.
> > After that, we go to description of the note to find out its location, the
> > address of the ".stapsdt.base" section and the semaphore address.
> > Then, we find the provider name and the SDT marker name and then follow the
> > arguments.
> > 
> > Signed-off-by: Hemant Kumar <hemant@linux.vnet.ibm.com>
> > Reviewed-by: Masami Hiramatsu <mhiramat@kernel.org>
> > Acked-by: Namhyung Kim <namhyung@kernel.org>
> > ---
> >  tools/perf/util/symbol-elf.c |  252 ++++++++++++++++++++++++++++++++++++++++++
> >  tools/perf/util/symbol.h     |   22 ++++
> >  2 files changed, 274 insertions(+)
> > 
> > diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
> > index 87a297d..e74ce17 100644
> > --- a/tools/perf/util/symbol-elf.c
> > +++ b/tools/perf/util/symbol-elf.c
> > @@ -1781,6 +1781,258 @@ void kcore_extract__delete(struct kcore_extract *kce)
> >  	unlink(kce->extract_filename);
> >  }
> >  
> > +/**
> > + * populate_sdt_note : Parse raw data and identify SDT note
> > + * @elf: elf of the opened file
> > + * @data: raw data of a section with description offset applied
> > + * @len: note description size
> > + * @type: type of the note
> > + * @sdt_notes: List to add the SDT note
> > + *
> > + * Responsible for parsing the @data in section .note.stapsdt in @elf and
> > + * if its an SDT note, it appends to @sdt_notes list.
> > + */
> > +static int populate_sdt_note(Elf **elf, const char *data, size_t len,
> > +			     struct list_head *sdt_notes)
> > +{
> > +	const char *provider, *name;
> > +	struct sdt_note *tmp = NULL;
> > +	GElf_Ehdr ehdr;
> > +	GElf_Addr base_off = 0;
> > +	GElf_Shdr shdr;
> > +	int ret = -EINVAL;
> > +
> > +	union {
> > +		Elf64_Addr a64[NR_ADDR];
> > +		Elf32_Addr a32[NR_ADDR];
> > +	} buf;
> > +
> > +	Elf_Data dst = {
> > +		.d_buf = &buf, .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
> > +		.d_size = gelf_fsize((*elf), ELF_T_ADDR, NR_ADDR, EV_CURRENT),
> > +		.d_off = 0, .d_align = 0
> > +	};
> > +	Elf_Data src = {
> > +		.d_buf = (void *) data, .d_type = ELF_T_ADDR,
> > +		.d_version = EV_CURRENT, .d_size = dst.d_size, .d_off = 0,
> > +		.d_align = 0
> > +	};
> > +
> > +	tmp = (struct sdt_note *)calloc(1, sizeof(struct sdt_note));
> > +	if (!tmp) {
> > +		ret = -ENOMEM;
> > +		goto out_err;
> > +	}
> > +
> > +	INIT_LIST_HEAD(&tmp->note_list);
> > +
> > +	if (len < dst.d_size + 3)
> > +		goto out_free_note;
> > +
> > +	/* Translation from file representation to memory representation */
> > +	if (gelf_xlatetom(*elf, &dst, &src,
> > +			  elf_getident(*elf, NULL)[EI_DATA]) == NULL) {
> > +		pr_err("gelf_xlatetom : %s\n", elf_errmsg(-1));
> > +		goto out_free_note;
> > +	}
> > +
> > +	/* Populate the fields of sdt_note */
> > +	provider = data + dst.d_size;
> > +
> > +	name = (const char *)memchr(provider, '\0', data + len - provider);
> > +	if (name++ == NULL)
> > +		goto out_free_note;
> > +
> > +	tmp->provider = strdup(provider);
> > +	if (!tmp->provider) {
> > +		ret = -ENOMEM;
> > +		goto out_free_note;
> > +	}
> > +	tmp->name = strdup(name);
> > +	if (!tmp->name) {
> > +		ret = -ENOMEM;
> > +		goto out_free_prov;
> > +	}
> > +
> > +	if (gelf_getclass(*elf) == ELFCLASS32) {
> > +		memcpy(&tmp->addr, &buf, 3 * sizeof(Elf32_Addr));
> > +		tmp->bit32 = true;
> > +	} else {
> > +		memcpy(&tmp->addr, &buf, 3 * sizeof(Elf64_Addr));
> > +		tmp->bit32 = false;
> > +	}
> > +
> > +	if (!gelf_getehdr(*elf, &ehdr)) {
> > +		pr_debug("%s : cannot get elf header.\n", __func__);
> > +		ret = -EBADF;
> > +		goto out_free_name;
> > +	}
> > +
> > +	/* Adjust the prelink effect :
> > +	 * Find out the .stapsdt.base section.
> > +	 * This scn will help us to handle prelinking (if present).
> > +	 * Compare the retrieved file offset of the base section with the
> > +	 * base address in the description of the SDT note. If its different,
> > +	 * then accordingly, adjust the note location.
> > +	 */
> > +	if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) {
> > +		base_off = shdr.sh_offset;
> > +		if (base_off) {
> > +			if (tmp->bit32)
> > +				tmp->addr.a32[0] = tmp->addr.a32[0] + base_off -
> > +					tmp->addr.a32[1];
> > +			else
> > +				tmp->addr.a64[0] = tmp->addr.a64[0] + base_off -
> > +					tmp->addr.a64[1];
> > +		}
> > +	}
> > +
> > +	list_add_tail(&tmp->note_list, sdt_notes);
> > +	return 0;
> > +
> > +out_free_name:
> > +	free(tmp->name);
> > +out_free_prov:
> > +	free(tmp->provider);
> > +out_free_note:
> > +	free(tmp);
> > +out_err:
> > +	return ret;
> > +}
> > +
> > +/**
> > + * construct_sdt_notes_list : constructs a list of SDT notes
> > + * @elf : elf to look into
> > + * @sdt_notes : empty list_head
> > + *
> > + * Scans the sections in 'elf' for the section
> > + * .note.stapsdt. It, then calls populate_sdt_note to find
> > + * out the SDT events and populates the 'sdt_notes'.
> > + */
> > +static int construct_sdt_notes_list(Elf *elf, struct list_head *sdt_notes)
> > +{
> > +	GElf_Ehdr ehdr;
> > +	Elf_Scn *scn = NULL;
> > +	Elf_Data *data;
> > +	GElf_Shdr shdr;
> > +	size_t shstrndx, next;
> > +	GElf_Nhdr nhdr;
> > +	size_t name_off, desc_off, offset;
> > +	int ret = 0;
> > +
> > +	if (gelf_getehdr(elf, &ehdr) == NULL) {
> > +		ret = -EBADF;
> > +		goto out_ret;
> > +	}
> > +	if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
> > +		ret = -EBADF;
> > +		goto out_ret;
> > +	}
> > +
> > +	/* Look for the required section */
> > +	scn = elf_section_by_name(elf, &ehdr, &shdr, SDT_NOTE_SCN, NULL);
> > +	if (!scn) {
> > +		ret = -ENOENT;
> > +		goto out_ret;
> > +	}
> > +
> > +	if ((shdr.sh_type != SHT_NOTE) || (shdr.sh_flags & SHF_ALLOC)) {
> > +		ret = -ENOENT;
> > +		goto out_ret;
> > +	}
> > +
> > +	data = elf_getdata(scn, NULL);
> > +
> > +	/* Get the SDT notes */
> > +	for (offset = 0; (next = gelf_getnote(data, offset, &nhdr, &name_off,
> > +					      &desc_off)) > 0; offset = next) {
> > +		if (nhdr.n_namesz == sizeof(SDT_NOTE_NAME) &&
> > +		    !memcmp(data->d_buf + name_off, SDT_NOTE_NAME,
> > +			    sizeof(SDT_NOTE_NAME))) {
> > +			/* Check the type of the note */
> > +			if (nhdr.n_type != SDT_NOTE_TYPE)
> > +				goto out_ret;
> > +
> > +			ret = populate_sdt_note(&elf, ((data->d_buf) + desc_off),
> > +						nhdr.n_descsz, sdt_notes);
> > +			if (ret < 0)
> > +				goto out_ret;
> > +		}
> > +	}
> > +	if (list_empty(sdt_notes))
> > +		ret = -ENOENT;
> > +
> > +out_ret:
> > +	return ret;
> > +}
> > +
> > +/**
> > + * get_sdt_note_list : Wrapper to construct a list of sdt notes
> > + * @head : empty list_head
> > + * @target : file to find SDT notes from
> > + *
> > + * This opens the file, initializes
> > + * the ELF and then calls construct_sdt_notes_list.
> > + */
> > +int get_sdt_note_list(struct list_head *head, const char *target)
> > +{
> > +	Elf *elf;
> > +	int fd, ret;
> > +
> > +	fd = open(target, O_RDONLY);
> > +	if (fd < 0)
> > +		return -EBADF;
> > +
> > +	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
> > +	if (!elf) {
> > +		ret = -EBADF;
> > +		goto out_close;
> > +	}
> > +	ret = construct_sdt_notes_list(elf, head);
> > +	elf_end(elf);
> > +out_close:
> > +	close(fd);
> > +	return ret;
> > +}
> > +
> > +/**
> > + * cleanup_sdt_note_list : free the sdt notes' list
> > + * @sdt_notes: sdt notes' list
> > + *
> > + * Free up the SDT notes in @sdt_notes.
> > + * Returns the number of SDT notes free'd.
> > + */
> > +int cleanup_sdt_note_list(struct list_head *sdt_notes)
> > +{
> > +	struct sdt_note *tmp, *pos;
> > +	int nr_free = 0;
> > +
> > +	list_for_each_entry_safe(pos, tmp, sdt_notes, note_list) {
> > +		list_del(&pos->note_list);
> > +		free(pos->name);
> > +		free(pos->provider);
> > +		free(pos);
> > +		nr_free++;
> > +	}
> > +	return nr_free;
> > +}
> > +
> > +/**
> > + * sdt_notes__get_count: Counts the number of sdt events
> > + * @start: list_head to sdt_notes list
> > + *
> > + * Returns the number of SDT notes in a list
> > + */
> > +int sdt_notes__get_count(struct list_head *start)
> > +{
> > +	struct sdt_note *sdt_ptr;
> > +	int count = 0;
> > +
> > +	list_for_each_entry(sdt_ptr, start, note_list)
> > +		count++;
> > +	return count;
> > +}
> > +
> >  void symbol__elf_init(void)
> >  {
> >  	elf_version(EV_CURRENT);
> > diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
> > index b10d558..699f7cb 100644
> > --- a/tools/perf/util/symbol.h
> > +++ b/tools/perf/util/symbol.h
> > @@ -342,4 +342,26 @@ void arch__sym_update(struct symbol *s, GElf_Sym *sym);
> >  
> >  int arch__choose_best_symbol(struct symbol *syma, struct symbol *symb);
> >  
> > +/* structure containing an SDT note's info */
> > +struct sdt_note {
> > +	char *name;			/* name of the note*/
> > +	char *provider;			/* provider name */
> > +	bool bit32;			/* whether the location is 32 bits? */
> > +	union {				/* location, base and semaphore addrs */
> > +		Elf64_Addr a64[3];
> > +		Elf32_Addr a32[3];
> > +	} addr;
> > +	struct list_head note_list;	/* SDT notes' list */
> > +};
> > +
> > +int get_sdt_note_list(struct list_head *head, const char *target);
> > +int cleanup_sdt_note_list(struct list_head *sdt_notes);
> > +int sdt_notes__get_count(struct list_head *start);
> > +
> > +#define SDT_BASE_SCN ".stapsdt.base"
> > +#define SDT_NOTE_SCN  ".note.stapsdt"
> > +#define SDT_NOTE_TYPE 3
> > +#define SDT_NOTE_NAME "stapsdt"
> > +#define NR_ADDR 3
> > +
> >  #endif /* __PERF_SYMBOL */


-- 
Masami Hiramatsu <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache
  2016-07-01 18:22   ` Arnaldo Carvalho de Melo
  2016-07-04  2:15     ` Masami Hiramatsu
@ 2016-07-05  2:08     ` Masami Hiramatsu
  1 sibling, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2016-07-05  2:08 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: linux-kernel, Namhyung Kim, Peter Zijlstra, Ingo Molnar,
	Hemant Kumar, Ananth N Mavinakayanahalli, Brendan Gregg

On Fri, 1 Jul 2016 15:22:01 -0300
Arnaldo Carvalho de Melo <acme@kernel.org> wrote:

> Em Fri, Jul 01, 2016 at 05:04:10PM +0900, Masami Hiramatsu escreveu:
> > From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > 
> > 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
> 
> Why not remove the need for that build-cache --add? I.e. go straight to:
> 
>   perf probe -x /usr/lib/libc-2.17.so -a sdt_libc:memory_heap_new=memory_heap_new
> 
> And all the various steps above be done automagically?

Ah, this has been done :) Yes, you can do that already.

See commit dd975497ad ("perf probe: Introduce perf_cache interfaces")
which introduces probe cache and it automatically add the target
binary to the buildid-cache.

Thank you,


-- 
Masami Hiramatsu <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [tip:perf/core] perf probe: Use cache entry if possible
  2016-07-01  8:03 ` [PATCH perf/core v13 01/15] perf probe: Use cache entry if possible Masami Hiramatsu
  2016-07-01 13:20   ` Arnaldo Carvalho de Melo
@ 2016-07-05 10:16   ` tip-bot for Masami Hiramatsu
  1 sibling, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2016-07-05 10:16 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: peterz, mingo, linux-kernel, brendan.d.gregg, hpa, ananth,
	masami.hiramatsu.pt, acme, namhyung, mhiramat, hemant, tglx

Commit-ID:  bc0622302f344551050995491b7d14176f39c628
Gitweb:     http://git.kernel.org/tip/bc0622302f344551050995491b7d14176f39c628
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Fri, 1 Jul 2016 17:03:12 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 1 Jul 2016 11:34:57 -0300

perf probe: Use cache entry if possible

Before analyzing debuginfo, try to find a corresponding entry from probe
cache always. This does not depend on --cache, the --cache enables to
store/update cache, but looking up the cache is always enabled.

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/146736019226.27797.16366402884098398857.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-event.c | 65 +++++++++++++++++++++++++++++++++++++++++--
 tools/perf/util/probe-file.c  | 20 ++++++++++++-
 tools/perf/util/probe-file.h  |  5 +++-
 3 files changed, 86 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 55f41d5..47b6b8b 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2474,17 +2474,24 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,
 	char buf[64];
 	int ret;
 
+	/* If probe_event or trace_event already have the name, reuse it */
 	if (pev->event)
 		event = pev->event;
-	else
+	else if (tev->event)
+		event = tev->event;
+	else {
+		/* Or generate new one from probe point */
 		if (pev->point.function &&
 			(strncmp(pev->point.function, "0x", 2) != 0) &&
 			!strisglob(pev->point.function))
 			event = pev->point.function;
 		else
 			event = tev->point.realname;
+	}
 	if (pev->group)
 		group = pev->group;
+	else if (tev->group)
+		group = tev->group;
 	else
 		group = PERFPROBE_GROUP;
 
@@ -2531,7 +2538,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 	for (i = 0; i < ntevs; i++) {
 		tev = &tevs[i];
 		/* Skip if the symbol is out of .text or blacklisted */
-		if (!tev->point.symbol)
+		if (!tev->point.symbol && !pev->uprobes)
 			continue;
 
 		/* Set new name for tev (and update namelist) */
@@ -2844,6 +2851,55 @@ errout:
 
 bool __weak arch__prefers_symtab(void) { return false; }
 
+static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
+					      struct probe_trace_event **tevs)
+{
+	struct probe_cache *cache;
+	struct probe_cache_entry *entry;
+	struct probe_trace_event *tev;
+	struct str_node *node;
+	int ret, i;
+
+	cache = probe_cache__new(pev->target);
+	if (!cache)
+		return 0;
+
+	entry = probe_cache__find(cache, pev);
+	if (!entry) {
+		ret = 0;
+		goto out;
+	}
+
+	ret = strlist__nr_entries(entry->tevlist);
+	if (ret > probe_conf.max_probes) {
+		pr_debug("Too many entries matched in the cache of %s\n",
+			 pev->target ? : "kernel");
+		ret = -E2BIG;
+		goto out;
+	}
+
+	*tevs = zalloc(ret * sizeof(*tev));
+	if (!*tevs) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	i = 0;
+	strlist__for_each_entry(node, entry->tevlist) {
+		tev = &(*tevs)[i++];
+		ret = parse_probe_trace_command(node->s, tev);
+		if (ret < 0)
+			goto out;
+		/* Set the uprobes attribute as same as original */
+		tev->uprobes = pev->uprobes;
+	}
+	ret = i;
+
+out:
+	probe_cache__delete(cache);
+	return ret;
+}
+
 static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 					 struct probe_trace_event **tevs)
 {
@@ -2866,6 +2922,11 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 	if (ret > 0)
 		return ret;
 
+	/* At first, we need to lookup cache entry */
+	ret = find_probe_trace_events_from_cache(pev, tevs);
+	if (ret > 0)
+		return ret;	/* Found in probe cache */
+
 	if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) {
 		ret = find_probe_trace_events_from_map(pev, tevs);
 		if (ret > 0)
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 1c12c1a..a94ee47 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -524,7 +524,7 @@ static bool streql(const char *a, const char *b)
 	return !strcmp(a, b);
 }
 
-static struct probe_cache_entry *
+struct probe_cache_entry *
 probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
 {
 	struct probe_cache_entry *entry = NULL;
@@ -548,6 +548,24 @@ found:
 	return entry;
 }
 
+struct probe_cache_entry *
+probe_cache__find_by_name(struct probe_cache *pcache,
+			  const char *group, const char *event)
+{
+	struct probe_cache_entry *entry = NULL;
+
+	list_for_each_entry(entry, &pcache->entries, node) {
+		/* Hit if same event name or same command-string */
+		if (streql(entry->pev.group, group) &&
+		    streql(entry->pev.event, event))
+			goto found;
+	}
+	entry = NULL;
+
+found:
+	return entry;
+}
+
 int probe_cache__add_entry(struct probe_cache *pcache,
 			   struct perf_probe_event *pev,
 			   struct probe_trace_event *tevs, int ntevs)
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index d872e3d..910aa74 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -38,5 +38,8 @@ int probe_cache__add_entry(struct probe_cache *pcache,
 int probe_cache__commit(struct probe_cache *pcache);
 void probe_cache__purge(struct probe_cache *pcache);
 void probe_cache__delete(struct probe_cache *pcache);
-
+struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
+					    struct perf_probe_event *pev);
+struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
+					const char *group, const char *event);
 #endif

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [tip:perf/core] perf probe: Show all cached probes
  2016-07-01  8:03 ` [PATCH perf/core v13 02/15] perf probe: Show all cached probes Masami Hiramatsu
  2016-07-01 13:51   ` Arnaldo Carvalho de Melo
@ 2016-07-05 10:17   ` tip-bot for Masami Hiramatsu
  1 sibling, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2016-07-05 10:17 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: mingo, acme, brendan.d.gregg, hemant, linux-kernel, namhyung,
	hpa, peterz, tglx, ananth, mhiramat, masami.hiramatsu.pt

Commit-ID:  1f3736c9c833e40ac4d3a8dc6d661e341df8a259
Gitweb:     http://git.kernel.org/tip/1f3736c9c833e40ac4d3a8dc6d661e341df8a259
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Fri, 1 Jul 2016 17:03:26 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 1 Jul 2016 11:34:57 -0300

perf probe: Show all cached probes

perf probe --list shows all cached probes when --cache is given. Each
caches are shown with on which binary that probed. E.g.:

  -----
  # perf probe --cache vfs_read \$params
  # perf probe --cache -x /lib64/libc-2.17.so getaddrinfo \$params
  # perf probe --cache --list
  [kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1):
  vfs_read $params
  /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc):
  getaddrinfo $params
  -----

Note that $params requires debuginfo.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.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/146736020674.27797.13488316780383460180.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/Documentation/perf-probe.txt |   8 ++-
 tools/perf/builtin-probe.c              |   2 +-
 tools/perf/util/build-id.c              | 108 +++++++++++++++++++++++++++++++-
 tools/perf/util/build-id.h              |   3 +
 tools/perf/util/probe-event.c           |   3 +
 tools/perf/util/probe-file.c            |  66 ++++++++++++++++++-
 tools/perf/util/probe-file.h            |   1 +
 7 files changed, 184 insertions(+), 7 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 947db6f..5a70d45 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -67,7 +67,10 @@ OPTIONS
 
 -l::
 --list[=[GROUP:]EVENT]::
-	List up current probe events. This can also accept filtering patterns of event names.
+	List up current probe events. This can also accept filtering patterns of
+	event names.
+	When this is used with --cache, perf shows all cached probes instead of
+	the live probes.
 
 -L::
 --line=::
@@ -110,8 +113,9 @@ OPTIONS
 	adding and removal operations.
 
 --cache::
-	Cache the probes (with --add option). Any events which successfully added
+	(With --add) Cache the probes. Any events which successfully added
 	are also stored in the cache file.
+	(With --list) Show cached probes.
 
 --max-probes=NUM::
 	Set the maximum number of probe points for an event. Default is 128.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 3426232..0bb9084 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -44,7 +44,7 @@
 
 #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
 #define DEFAULT_FUNC_FILTER "!_*"
-#define DEFAULT_LIST_FILTER "*:*"
+#define DEFAULT_LIST_FILTER "*"
 
 /* Session management structure */
 static struct {
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 62b1473..1c49620 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -165,8 +165,7 @@ retry:
 	return NULL;
 }
 
-static char *build_id_cache__linkname(const char *sbuild_id, char *bf,
-				      size_t size)
+char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size)
 {
 	char *tmp = bf;
 	int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
@@ -176,6 +175,36 @@ static char *build_id_cache__linkname(const char *sbuild_id, char *bf,
 	return bf;
 }
 
+char *build_id_cache__origname(const char *sbuild_id)
+{
+	char *linkname;
+	char buf[PATH_MAX];
+	char *ret = NULL, *p;
+	size_t offs = 5;	/* == strlen("../..") */
+
+	linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
+	if (!linkname)
+		return NULL;
+
+	if (readlink(linkname, buf, PATH_MAX) < 0)
+		goto out;
+	/* The link should be "../..<origpath>/<sbuild_id>" */
+	p = strrchr(buf, '/');	/* Cut off the "/<sbuild_id>" */
+	if (p && (p > buf + offs)) {
+		*p = '\0';
+		if (buf[offs + 1] == '[')
+			offs++;	/*
+				 * This is a DSO name, like [kernel.kallsyms].
+				 * Skip the first '/', since this is not the
+				 * cache of a regular file.
+				 */
+		ret = strdup(buf + offs);	/* Skip "../..[/]" */
+	}
+out:
+	free(linkname);
+	return ret;
+}
+
 static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
 {
 	return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
@@ -387,6 +416,81 @@ void disable_buildid_cache(void)
 	no_buildid_cache = true;
 }
 
+static bool lsdir_bid_head_filter(const char *name __maybe_unused,
+				  struct dirent *d __maybe_unused)
+{
+	return (strlen(d->d_name) == 2) &&
+		isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]);
+}
+
+static bool lsdir_bid_tail_filter(const char *name __maybe_unused,
+				  struct dirent *d __maybe_unused)
+{
+	int i = 0;
+	while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3)
+		i++;
+	return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0');
+}
+
+struct strlist *build_id_cache__list_all(void)
+{
+	struct strlist *toplist, *linklist = NULL, *bidlist;
+	struct str_node *nd, *nd2;
+	char *topdir, *linkdir = NULL;
+	char sbuild_id[SBUILD_ID_SIZE];
+
+	/* Open the top-level directory */
+	if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
+		return NULL;
+
+	bidlist = strlist__new(NULL, NULL);
+	if (!bidlist)
+		goto out;
+
+	toplist = lsdir(topdir, lsdir_bid_head_filter);
+	if (!toplist) {
+		pr_debug("Error in lsdir(%s): %d\n", topdir, errno);
+		/* If there is no buildid cache, return an empty list */
+		if (errno == ENOENT)
+			goto out;
+		goto err_out;
+	}
+
+	strlist__for_each_entry(nd, toplist) {
+		if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0)
+			goto err_out;
+		/* Open the lower-level directory */
+		linklist = lsdir(linkdir, lsdir_bid_tail_filter);
+		if (!linklist) {
+			pr_debug("Error in lsdir(%s): %d\n", linkdir, errno);
+			goto err_out;
+		}
+		strlist__for_each_entry(nd2, linklist) {
+			if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s",
+				     nd->s, nd2->s) != SBUILD_ID_SIZE - 1)
+				goto err_out;
+			if (strlist__add(bidlist, sbuild_id) < 0)
+				goto err_out;
+		}
+		strlist__delete(linklist);
+		zfree(&linkdir);
+	}
+
+out_free:
+	strlist__delete(toplist);
+out:
+	free(topdir);
+
+	return bidlist;
+
+err_out:
+	strlist__delete(linklist);
+	zfree(&linkdir);
+	strlist__delete(bidlist);
+	bidlist = NULL;
+	goto out_free;
+}
+
 char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
 			       bool is_kallsyms, bool is_vdso)
 {
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index d8c7f2f..b742e27 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -30,8 +30,11 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);
 int perf_session__write_buildid_table(struct perf_session *session, int fd);
 int perf_session__cache_build_ids(struct perf_session *session);
 
+char *build_id_cache__origname(const char *sbuild_id);
+char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
 char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
 			       bool is_kallsyms, bool is_vdso);
+struct strlist *build_id_cache__list_all(void);
 int build_id_cache__list_build_ids(const char *pathname,
 				   struct strlist **result);
 bool build_id_cache__cached(const char *sbuild_id);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 47b6b8b..f81b5dd 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2366,6 +2366,9 @@ int show_perf_probe_events(struct strfilter *filter)
 
 	setup_pager();
 
+	if (probe_conf.cache)
+		return probe_cache__show_all_caches(filter);
+
 	ret = init_probe_symbol_maps(false);
 	if (ret < 0)
 		return ret;
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index a94ee47..156e3d8 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -367,10 +367,17 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
 {
 	char cpath[PATH_MAX];
 	char sbuildid[SBUILD_ID_SIZE];
-	char *dir_name;
+	char *dir_name = NULL;
 	bool is_kallsyms = !target;
 	int ret, fd;
 
+	if (target && build_id_cache__cached(target)) {
+		/* This is a cached buildid */
+		strncpy(sbuildid, target, SBUILD_ID_SIZE);
+		dir_name = build_id_cache__linkname(sbuildid, NULL, 0);
+		goto found;
+	}
+
 	if (target)
 		ret = filename__sprintf_build_id(target, sbuildid);
 	else {
@@ -394,8 +401,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
 
 	dir_name = build_id_cache__cachedir(sbuildid, target, is_kallsyms,
 					    false);
-	if (!dir_name)
+found:
+	if (!dir_name) {
+		pr_debug("Failed to get cache from %s\n", target);
 		return -ENOMEM;
+	}
 
 	snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
 	fd = open(cpath, O_CREAT | O_RDWR, 0644);
@@ -673,3 +683,55 @@ int probe_cache__commit(struct probe_cache *pcache)
 out:
 	return ret;
 }
+
+static int probe_cache__show_entries(struct probe_cache *pcache,
+				     struct strfilter *filter)
+{
+	struct probe_cache_entry *entry;
+	char buf[128], *ptr;
+
+	list_for_each_entry(entry, &pcache->entries, node) {
+		if (entry->pev.event) {
+			ptr = buf;
+			snprintf(buf, 128, "%s:%s",
+				 entry->pev.group, entry->pev.event);
+		} else
+			ptr = entry->spev;
+		if (strfilter__compare(filter, ptr))
+			printf("%s\n", entry->spev);
+	}
+	return 0;
+}
+
+/* Show all cached probes */
+int probe_cache__show_all_caches(struct strfilter *filter)
+{
+	struct probe_cache *pcache;
+	struct strlist *bidlist;
+	struct str_node *nd;
+	char *buf = strfilter__string(filter);
+
+	pr_debug("list cache with filter: %s\n", buf);
+	free(buf);
+
+	bidlist = build_id_cache__list_all();
+	if (!bidlist) {
+		pr_debug("Failed to get buildids: %d\n", errno);
+		return -EINVAL;
+	}
+	strlist__for_each_entry(nd, bidlist) {
+		pcache = probe_cache__new(nd->s);
+		if (!pcache)
+			continue;
+		if (!list_empty(&pcache->entries)) {
+			buf = build_id_cache__origname(nd->s);
+			printf("%s (%s):\n", buf, nd->s);
+			free(buf);
+			probe_cache__show_entries(pcache, filter);
+		}
+		probe_cache__delete(pcache);
+	}
+	strlist__delete(bidlist);
+
+	return 0;
+}
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 910aa74..0009b8a 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -42,4 +42,5 @@ struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
 					    struct perf_probe_event *pev);
 struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
 					const char *group, const char *event);
+int probe_cache__show_all_caches(struct strfilter *filter);
 #endif

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [tip:perf/core] perf probe: Remove caches when --cache is given
  2016-07-01  8:03 ` [PATCH perf/core v13 03/15] perf probe: Remove caches when --cache is given Masami Hiramatsu
@ 2016-07-05 10:17   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2016-07-05 10:17 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: namhyung, hpa, brendan.d.gregg, hemant, ananth, acme, tglx,
	mingo, mhiramat, linux-kernel, masami.hiramatsu.pt, peterz

Commit-ID:  4a0f65c102ec3a718b4a0b90981232b6cb019477
Gitweb:     http://git.kernel.org/tip/4a0f65c102ec3a718b4a0b90981232b6cb019477
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Fri, 1 Jul 2016 17:03:36 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 1 Jul 2016 11:34:57 -0300

perf probe: Remove caches when --cache is given

'perf probe --del' removes caches when '--cache' is given.  Note that
the delete pattern is not the same as for normal events.

If you cached probes with event name, --del "eventname" works as
expected. However, if you skipped it, the cached probes doesn't have
actual event name. In that case --del "probe-desc" is required (wildcard
is acceptable).  For example a cache entry has the probe-desc "vfs_read
$params", you can remove it with --del 'vfs_read*'.

  -----
  # perf probe --cache --list
  /[kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1):
  vfs_read $params
  /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc):
  getaddrinfo $params

  # perf probe --cache --del vfs_read\*
  Removed cached event: probe:vfs_read

  # perf probe --cache --list
  /[kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1):
  /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc):
  getaddrinfo $params
  -----

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.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/146736021651.27797.10250879847070772920.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/Documentation/perf-probe.txt |  1 +
 tools/perf/builtin-probe.c              | 29 ++++++++++++++++++++++++++
 tools/perf/util/probe-file.c            | 36 +++++++++++++++++++++++++--------
 tools/perf/util/probe-file.h            |  2 ++
 4 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 5a70d45..8d09173 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -116,6 +116,7 @@ OPTIONS
 	(With --add) Cache the probes. Any events which successfully added
 	are also stored in the cache file.
 	(With --list) Show cached probes.
+	(With --del) Remove cached probes.
 
 --max-probes=NUM::
 	Set the maximum number of probe points for an event. Default is 128.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 0bb9084..a1a5cd1 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -363,6 +363,32 @@ out_cleanup:
 	return ret;
 }
 
+static int del_perf_probe_caches(struct strfilter *filter)
+{
+	struct probe_cache *cache;
+	struct strlist *bidlist;
+	struct str_node *nd;
+	int ret;
+
+	bidlist = build_id_cache__list_all();
+	if (!bidlist) {
+		ret = -errno;
+		pr_debug("Failed to get buildids: %d\n", ret);
+		return ret ?: -ENOMEM;
+	}
+
+	strlist__for_each_entry(nd, bidlist) {
+		cache = probe_cache__new(nd->s);
+		if (!cache)
+			continue;
+		if (probe_cache__filter_purge(cache, filter) < 0 ||
+		    probe_cache__commit(cache) < 0)
+			pr_warning("Failed to remove entries for %s\n", nd->s);
+		probe_cache__delete(cache);
+	}
+	return 0;
+}
+
 static int perf_del_probe_events(struct strfilter *filter)
 {
 	int ret, ret2, ufd = -1, kfd = -1;
@@ -375,6 +401,9 @@ static int perf_del_probe_events(struct strfilter *filter)
 
 	pr_debug("Delete filter: \'%s\'\n", str);
 
+	if (probe_conf.cache)
+		return del_perf_probe_caches(filter);
+
 	/* Get current event names */
 	ret = probe_file__open_both(&kfd, &ufd, PF_FL_RW);
 	if (ret < 0)
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 156e3d8..6cb6ec0 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -684,20 +684,40 @@ out:
 	return ret;
 }
 
+static bool probe_cache_entry__compare(struct probe_cache_entry *entry,
+				       struct strfilter *filter)
+{
+	char buf[128], *ptr = entry->spev;
+
+	if (entry->pev.event) {
+		snprintf(buf, 128, "%s:%s", entry->pev.group, entry->pev.event);
+		ptr = buf;
+	}
+	return strfilter__compare(filter, ptr);
+}
+
+int probe_cache__filter_purge(struct probe_cache *pcache,
+			      struct strfilter *filter)
+{
+	struct probe_cache_entry *entry, *tmp;
+
+	list_for_each_entry_safe(entry, tmp, &pcache->entries, node) {
+		if (probe_cache_entry__compare(entry, filter)) {
+			pr_info("Removed cached event: %s\n", entry->spev);
+			list_del_init(&entry->node);
+			probe_cache_entry__delete(entry);
+		}
+	}
+	return 0;
+}
+
 static int probe_cache__show_entries(struct probe_cache *pcache,
 				     struct strfilter *filter)
 {
 	struct probe_cache_entry *entry;
-	char buf[128], *ptr;
 
 	list_for_each_entry(entry, &pcache->entries, node) {
-		if (entry->pev.event) {
-			ptr = buf;
-			snprintf(buf, 128, "%s:%s",
-				 entry->pev.group, entry->pev.event);
-		} else
-			ptr = entry->spev;
-		if (strfilter__compare(filter, ptr))
+		if (probe_cache_entry__compare(entry, filter))
 			printf("%s\n", entry->spev);
 	}
 	return 0;
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 0009b8a..0ed1fc5 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -38,6 +38,8 @@ int probe_cache__add_entry(struct probe_cache *pcache,
 int probe_cache__commit(struct probe_cache *pcache);
 void probe_cache__purge(struct probe_cache *pcache);
 void probe_cache__delete(struct probe_cache *pcache);
+int probe_cache__filter_purge(struct probe_cache *pcache,
+			      struct strfilter *filter);
 struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
 					    struct perf_probe_event *pev);
 struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [tip:perf/core] perf sdt: ELF support for SDT
  2016-07-01  8:03 ` [PATCH perf/core v13 04/15] perf/sdt: ELF support for SDT Masami Hiramatsu
  2016-07-01 18:56   ` Arnaldo Carvalho de Melo
@ 2016-07-05 10:18   ` tip-bot for Hemant Kumar
  1 sibling, 0 replies; 32+ messages in thread
From: tip-bot for Hemant Kumar @ 2016-07-05 10:18 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: namhyung, tglx, mhiramat, peterz, hpa, ananth, brendan.d.gregg,
	linux-kernel, acme, mingo, hemant

Commit-ID:  060fa0c7a3e0bb4f1426ee79dfd38e2a4c80067a
Gitweb:     http://git.kernel.org/tip/060fa0c7a3e0bb4f1426ee79dfd38e2a4c80067a
Author:     Hemant Kumar <hemant@linux.vnet.ibm.com>
AuthorDate: Fri, 1 Jul 2016 17:03:46 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 4 Jul 2016 19:38:59 -0300

perf sdt: ELF support for SDT

This patch serves the initial support to identify and list SDT events in
binaries.  When programs containing SDT markers are compiled, gcc with
the help of assembler directives identifies them and places them in the
section ".note.stapsdt".

To find these markers from the binaries, one needs to traverse through
this section and parse the relevant details like the name, type and
location of the marker. Also, the original location could be skewed due
to the effect of prelinking. If that is the case, the locations need to
be adjusted.

The functions in this patch open a given ELF, find out the SDT section,
parse the relevant details, adjust the location (if necessary) and
populate them in a list.

A typical note entry in ".note.stapsdt" section is as follows :

                                 |--nhdr.n_namesz--|
                ------------------------------------
                |      nhdr      |     "stapsdt"   |
        -----   |----------------------------------|
         |      |  <location>       <base_address> |
         |      |  <semaphore>                     |
nhdr.n_descsize |  "provider_name"   "note_name"   |
         |      |   <args>                         |
        -----   |----------------------------------|
                |      nhdr      |     "stapsdt"   |
                |...

The above shows an excerpt from the section ".note.stapsdt".  'nhdr' is
a structure which has the note name size (n_namesz), note description
size (n_desc_sz) and note type (n_type).

So, in order to parse the note note info, we need nhdr to tell us where
to start from.  As can be seen from <sys/sdt.h>, the name of the SDT
notes given is "stapsdt".  But this is not the identifier of the note.

After that, we go to description of the note to find out its location, the
address of the ".stapsdt.base" section and the semaphore address.
Then, we find the provider name and the SDT marker name and then follow the
arguments.

Signed-off-by: Hemant Kumar <hemant@linux.vnet.ibm.com>
Reviewed-by: Masami Hiramatsu <mhiramat@kernel.org>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/146736022628.27797.1201368329092908163.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/symbol-elf.c | 252 +++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/symbol.h     |  22 ++++
 2 files changed, 274 insertions(+)

diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index b222552c..6f15b92 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1789,6 +1789,258 @@ void kcore_extract__delete(struct kcore_extract *kce)
 	unlink(kce->extract_filename);
 }
 
+/**
+ * populate_sdt_note : Parse raw data and identify SDT note
+ * @elf: elf of the opened file
+ * @data: raw data of a section with description offset applied
+ * @len: note description size
+ * @type: type of the note
+ * @sdt_notes: List to add the SDT note
+ *
+ * Responsible for parsing the @data in section .note.stapsdt in @elf and
+ * if its an SDT note, it appends to @sdt_notes list.
+ */
+static int populate_sdt_note(Elf **elf, const char *data, size_t len,
+			     struct list_head *sdt_notes)
+{
+	const char *provider, *name;
+	struct sdt_note *tmp = NULL;
+	GElf_Ehdr ehdr;
+	GElf_Addr base_off = 0;
+	GElf_Shdr shdr;
+	int ret = -EINVAL;
+
+	union {
+		Elf64_Addr a64[NR_ADDR];
+		Elf32_Addr a32[NR_ADDR];
+	} buf;
+
+	Elf_Data dst = {
+		.d_buf = &buf, .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
+		.d_size = gelf_fsize((*elf), ELF_T_ADDR, NR_ADDR, EV_CURRENT),
+		.d_off = 0, .d_align = 0
+	};
+	Elf_Data src = {
+		.d_buf = (void *) data, .d_type = ELF_T_ADDR,
+		.d_version = EV_CURRENT, .d_size = dst.d_size, .d_off = 0,
+		.d_align = 0
+	};
+
+	tmp = (struct sdt_note *)calloc(1, sizeof(struct sdt_note));
+	if (!tmp) {
+		ret = -ENOMEM;
+		goto out_err;
+	}
+
+	INIT_LIST_HEAD(&tmp->note_list);
+
+	if (len < dst.d_size + 3)
+		goto out_free_note;
+
+	/* Translation from file representation to memory representation */
+	if (gelf_xlatetom(*elf, &dst, &src,
+			  elf_getident(*elf, NULL)[EI_DATA]) == NULL) {
+		pr_err("gelf_xlatetom : %s\n", elf_errmsg(-1));
+		goto out_free_note;
+	}
+
+	/* Populate the fields of sdt_note */
+	provider = data + dst.d_size;
+
+	name = (const char *)memchr(provider, '\0', data + len - provider);
+	if (name++ == NULL)
+		goto out_free_note;
+
+	tmp->provider = strdup(provider);
+	if (!tmp->provider) {
+		ret = -ENOMEM;
+		goto out_free_note;
+	}
+	tmp->name = strdup(name);
+	if (!tmp->name) {
+		ret = -ENOMEM;
+		goto out_free_prov;
+	}
+
+	if (gelf_getclass(*elf) == ELFCLASS32) {
+		memcpy(&tmp->addr, &buf, 3 * sizeof(Elf32_Addr));
+		tmp->bit32 = true;
+	} else {
+		memcpy(&tmp->addr, &buf, 3 * sizeof(Elf64_Addr));
+		tmp->bit32 = false;
+	}
+
+	if (!gelf_getehdr(*elf, &ehdr)) {
+		pr_debug("%s : cannot get elf header.\n", __func__);
+		ret = -EBADF;
+		goto out_free_name;
+	}
+
+	/* Adjust the prelink effect :
+	 * Find out the .stapsdt.base section.
+	 * This scn will help us to handle prelinking (if present).
+	 * Compare the retrieved file offset of the base section with the
+	 * base address in the description of the SDT note. If its different,
+	 * then accordingly, adjust the note location.
+	 */
+	if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) {
+		base_off = shdr.sh_offset;
+		if (base_off) {
+			if (tmp->bit32)
+				tmp->addr.a32[0] = tmp->addr.a32[0] + base_off -
+					tmp->addr.a32[1];
+			else
+				tmp->addr.a64[0] = tmp->addr.a64[0] + base_off -
+					tmp->addr.a64[1];
+		}
+	}
+
+	list_add_tail(&tmp->note_list, sdt_notes);
+	return 0;
+
+out_free_name:
+	free(tmp->name);
+out_free_prov:
+	free(tmp->provider);
+out_free_note:
+	free(tmp);
+out_err:
+	return ret;
+}
+
+/**
+ * construct_sdt_notes_list : constructs a list of SDT notes
+ * @elf : elf to look into
+ * @sdt_notes : empty list_head
+ *
+ * Scans the sections in 'elf' for the section
+ * .note.stapsdt. It, then calls populate_sdt_note to find
+ * out the SDT events and populates the 'sdt_notes'.
+ */
+static int construct_sdt_notes_list(Elf *elf, struct list_head *sdt_notes)
+{
+	GElf_Ehdr ehdr;
+	Elf_Scn *scn = NULL;
+	Elf_Data *data;
+	GElf_Shdr shdr;
+	size_t shstrndx, next;
+	GElf_Nhdr nhdr;
+	size_t name_off, desc_off, offset;
+	int ret = 0;
+
+	if (gelf_getehdr(elf, &ehdr) == NULL) {
+		ret = -EBADF;
+		goto out_ret;
+	}
+	if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
+		ret = -EBADF;
+		goto out_ret;
+	}
+
+	/* Look for the required section */
+	scn = elf_section_by_name(elf, &ehdr, &shdr, SDT_NOTE_SCN, NULL);
+	if (!scn) {
+		ret = -ENOENT;
+		goto out_ret;
+	}
+
+	if ((shdr.sh_type != SHT_NOTE) || (shdr.sh_flags & SHF_ALLOC)) {
+		ret = -ENOENT;
+		goto out_ret;
+	}
+
+	data = elf_getdata(scn, NULL);
+
+	/* Get the SDT notes */
+	for (offset = 0; (next = gelf_getnote(data, offset, &nhdr, &name_off,
+					      &desc_off)) > 0; offset = next) {
+		if (nhdr.n_namesz == sizeof(SDT_NOTE_NAME) &&
+		    !memcmp(data->d_buf + name_off, SDT_NOTE_NAME,
+			    sizeof(SDT_NOTE_NAME))) {
+			/* Check the type of the note */
+			if (nhdr.n_type != SDT_NOTE_TYPE)
+				goto out_ret;
+
+			ret = populate_sdt_note(&elf, ((data->d_buf) + desc_off),
+						nhdr.n_descsz, sdt_notes);
+			if (ret < 0)
+				goto out_ret;
+		}
+	}
+	if (list_empty(sdt_notes))
+		ret = -ENOENT;
+
+out_ret:
+	return ret;
+}
+
+/**
+ * get_sdt_note_list : Wrapper to construct a list of sdt notes
+ * @head : empty list_head
+ * @target : file to find SDT notes from
+ *
+ * This opens the file, initializes
+ * the ELF and then calls construct_sdt_notes_list.
+ */
+int get_sdt_note_list(struct list_head *head, const char *target)
+{
+	Elf *elf;
+	int fd, ret;
+
+	fd = open(target, O_RDONLY);
+	if (fd < 0)
+		return -EBADF;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (!elf) {
+		ret = -EBADF;
+		goto out_close;
+	}
+	ret = construct_sdt_notes_list(elf, head);
+	elf_end(elf);
+out_close:
+	close(fd);
+	return ret;
+}
+
+/**
+ * cleanup_sdt_note_list : free the sdt notes' list
+ * @sdt_notes: sdt notes' list
+ *
+ * Free up the SDT notes in @sdt_notes.
+ * Returns the number of SDT notes free'd.
+ */
+int cleanup_sdt_note_list(struct list_head *sdt_notes)
+{
+	struct sdt_note *tmp, *pos;
+	int nr_free = 0;
+
+	list_for_each_entry_safe(pos, tmp, sdt_notes, note_list) {
+		list_del(&pos->note_list);
+		free(pos->name);
+		free(pos->provider);
+		free(pos);
+		nr_free++;
+	}
+	return nr_free;
+}
+
+/**
+ * sdt_notes__get_count: Counts the number of sdt events
+ * @start: list_head to sdt_notes list
+ *
+ * Returns the number of SDT notes in a list
+ */
+int sdt_notes__get_count(struct list_head *start)
+{
+	struct sdt_note *sdt_ptr;
+	int count = 0;
+
+	list_for_each_entry(sdt_ptr, start, note_list)
+		count++;
+	return count;
+}
+
 void symbol__elf_init(void)
 {
 	elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index b10d558..699f7cb 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -342,4 +342,26 @@ void arch__sym_update(struct symbol *s, GElf_Sym *sym);
 
 int arch__choose_best_symbol(struct symbol *syma, struct symbol *symb);
 
+/* structure containing an SDT note's info */
+struct sdt_note {
+	char *name;			/* name of the note*/
+	char *provider;			/* provider name */
+	bool bit32;			/* whether the location is 32 bits? */
+	union {				/* location, base and semaphore addrs */
+		Elf64_Addr a64[3];
+		Elf32_Addr a32[3];
+	} addr;
+	struct list_head note_list;	/* SDT notes' list */
+};
+
+int get_sdt_note_list(struct list_head *head, const char *target);
+int cleanup_sdt_note_list(struct list_head *sdt_notes);
+int sdt_notes__get_count(struct list_head *start);
+
+#define SDT_BASE_SCN ".stapsdt.base"
+#define SDT_NOTE_SCN  ".note.stapsdt"
+#define SDT_NOTE_TYPE 3
+#define SDT_NOTE_NAME "stapsdt"
+#define NR_ADDR 3
+
 #endif /* __PERF_SYMBOL */

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [tip:perf/core] perf probe: Add group name support
  2016-07-01  8:04 ` [PATCH perf/core v13 05/15] perf probe: Add group name support Masami Hiramatsu
@ 2016-07-05 10:19   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2016-07-05 10:19 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: tglx, peterz, acme, ananth, linux-kernel, hpa, namhyung, hemant,
	masami.hiramatsu.pt, mingo, mhiramat, brendan.d.gregg

Commit-ID:  8d993d96901f55d26e083390aae80fd02cbff7aa
Gitweb:     http://git.kernel.org/tip/8d993d96901f55d26e083390aae80fd02cbff7aa
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Fri, 1 Jul 2016 17:04:01 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 4 Jul 2016 19:39:00 -0300

perf probe: Add group name support

Allow user to set group name for adding new event.  Note that user must
ensure that the group name doesn't conflict with existing group name
carefully.

E.g. Existing group name can conflict with other events.  Especially,
using the group name reserved for kernel modules can hide kernel
embedded events when loading modules.

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/146736024091.27797.9471545190066268995.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/Documentation/perf-probe.txt | 10 ++++++----
 tools/perf/util/probe-event.c           | 23 ++++++++++++++---------
 2 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 8d09173..7a258e9 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -143,16 +143,18 @@ PROBE SYNTAX
 Probe points are defined by following syntax.
 
     1) Define event based on function name
-     [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...]
+     [[GROUP:]EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...]
 
     2) Define event based on source file with line number
-     [EVENT=]SRC:ALN [ARG ...]
+     [[GROUP:]EVENT=]SRC:ALN [ARG ...]
 
     3) Define event based on source file with lazy pattern
-     [EVENT=]SRC;PTN [ARG ...]
+     [[GROUP:]EVENT=]SRC;PTN [ARG ...]
 
 
-'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'.
+'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. You can also specify a group name by 'GROUP', if omitted, set 'probe' is used for kprobe and 'probe_<bin>' is used for uprobe.
+Note that using existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide embedded events in the
+modules.
 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition.  In addition, '@SRC' specifies a source file which has that function.
 It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern.
 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT).
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index f81b5dd..0201f66 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1206,10 +1206,8 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 	bool file_spec = false;
 	/*
 	 * <Syntax>
-	 * perf probe [EVENT=]SRC[:LN|;PTN]
-	 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
-	 *
-	 * TODO:Group name support
+	 * perf probe [GRP:][EVENT=]SRC[:LN|;PTN]
+	 * perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
 	 */
 	if (!arg)
 		return -EINVAL;
@@ -1218,11 +1216,19 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 	if (ptr && *ptr == '=') {	/* Event name */
 		*ptr = '\0';
 		tmp = ptr + 1;
-		if (strchr(arg, ':')) {
-			semantic_error("Group name is not supported yet.\n");
-			return -ENOTSUP;
-		}
+		ptr = strchr(arg, ':');
+		if (ptr) {
+			*ptr = '\0';
+			if (!is_c_func_name(arg))
+				goto not_fname;
+			pev->group = strdup(arg);
+			if (!pev->group)
+				return -ENOMEM;
+			arg = ptr + 1;
+		} else
+			pev->group = NULL;
 		if (!is_c_func_name(arg)) {
+not_fname:
 			semantic_error("%s is bad for event name -it must "
 				       "follow C symbol-naming rule.\n", arg);
 			return -EINVAL;
@@ -1230,7 +1236,6 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 		pev->event = strdup(arg);
 		if (pev->event == NULL)
 			return -ENOMEM;
-		pev->group = NULL;
 		arg = tmp;
 	}
 

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [tip:perf/core] perf buildid-cache: Scan and import user SDT events to probe cache
  2016-07-01  8:04 ` [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache Masami Hiramatsu
  2016-07-01 18:22   ` Arnaldo Carvalho de Melo
@ 2016-07-05 10:19   ` tip-bot for Masami Hiramatsu
  1 sibling, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2016-07-05 10:19 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: peterz, masami.hiramatsu.pt, linux-kernel, mhiramat, namhyung,
	tglx, hemant, brendan.d.gregg, hpa, acme, mingo, ananth

Commit-ID:  6430a94ead2a4c8f350441351a735303eb6d1c8a
Gitweb:     http://git.kernel.org/tip/6430a94ead2a4c8f350441351a735303eb6d1c8a
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Fri, 1 Jul 2016 17:04:10 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 4 Jul 2016 19:39:00 -0300

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>
---
 tools/perf/Documentation/perf-buildid-cache.txt |  3 ++
 tools/perf/util/build-id.c                      | 30 +++++++++++
 tools/perf/util/probe-file.c                    | 69 +++++++++++++++++++++++--
 tools/perf/util/probe-file.h                    |  2 +
 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 dd07b55..058064d 100644
--- a/tools/perf/Documentation/perf-buildid-cache.txt
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -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
 -------
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 1c49620..e1a1640 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;
@@ -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)
 {
@@ -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);
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 6cb6ec0..5b563b2 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)
 		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);
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 0ed1fc5..ddf5ae2 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -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;
@@ -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);

^ permalink raw reply related	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2016-07-05 10:20 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-01  8:03 [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Masami Hiramatsu
2016-07-01  8:03 ` [PATCH perf/core v13 01/15] perf probe: Use cache entry if possible Masami Hiramatsu
2016-07-01 13:20   ` Arnaldo Carvalho de Melo
2016-07-05 10:16   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2016-07-01  8:03 ` [PATCH perf/core v13 02/15] perf probe: Show all cached probes Masami Hiramatsu
2016-07-01 13:51   ` Arnaldo Carvalho de Melo
2016-07-04  2:03     ` Masami Hiramatsu
2016-07-04  2:06       ` [PATCH perf/core] [BUGFIX] perf-probe: Fix to show correct error message for $vars and $params Masami Hiramatsu
2016-07-05 10:17   ` [tip:perf/core] perf probe: Show all cached probes tip-bot for Masami Hiramatsu
2016-07-01  8:03 ` [PATCH perf/core v13 03/15] perf probe: Remove caches when --cache is given Masami Hiramatsu
2016-07-05 10:17   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2016-07-01  8:03 ` [PATCH perf/core v13 04/15] perf/sdt: ELF support for SDT Masami Hiramatsu
2016-07-01 18:56   ` Arnaldo Carvalho de Melo
2016-07-04  5:25     ` Masami Hiramatsu
2016-07-05 10:18   ` [tip:perf/core] perf sdt: " tip-bot for Hemant Kumar
2016-07-01  8:04 ` [PATCH perf/core v13 05/15] perf probe: Add group name support Masami Hiramatsu
2016-07-05 10:19   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2016-07-01  8:04 ` [PATCH perf/core v13 06/15] perf buildid-cache: Scan and import user SDT events to probe cache Masami Hiramatsu
2016-07-01 18:22   ` Arnaldo Carvalho de Melo
2016-07-04  2:15     ` Masami Hiramatsu
2016-07-05  2:08     ` Masami Hiramatsu
2016-07-05 10:19   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2016-07-01  8:04 ` [PATCH perf/core v13 07/15] perf probe: Accept %sdt and %cached event name Masami Hiramatsu
2016-07-01  8:04 ` [PATCH perf/core v13 08/15] perf-probe: Make --list shows only available cached events Masami Hiramatsu
2016-07-01  8:04 ` [PATCH perf/core v13 09/15] perf: probe-cache: Add for_each_probe_cache_entry() wrapper Masami Hiramatsu
2016-07-01  8:04 ` [PATCH perf/core v13 10/15] perf probe: Allow wildcard for cached events Masami Hiramatsu
2016-07-01  8:04 ` [PATCH perf/core v13 11/15] perf probe: Search SDT/cached event from all probe caches Masami Hiramatsu
2016-07-01  8:05 ` [PATCH perf/core v13 12/15] perf probe: Support @BUILDID or @FILE suffix for SDT events Masami Hiramatsu
2016-07-01  8:05 ` [PATCH perf/core v13 13/15] perf probe: Support a special SDT probe format Masami Hiramatsu
2016-07-01  8:05 ` [PATCH perf/core v13 14/15] perf build: Add sdt feature detection Masami Hiramatsu
2016-07-01  8:05 ` [PATCH perf/core v13 15/15] perf-test: Add a test case for SDT event Masami Hiramatsu
2016-07-01 13:19 ` [PATCH perf/core v13 00/15] perf-probe --cache and SDT support Arnaldo Carvalho de Melo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).