Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1389465 > unrolled thread

[PATCH perf/core v5 00/15] perf-probe --cache and SDT support

Started byMasami Hiramatsu <mhiramat@kernel.org>
First post2016-04-27 20:40 +0200
Last post2016-04-29 16:00 +0200
Articles 20 on this page of 28 — 4 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH perf/core v5 00/15] perf-probe --cache and SDT support Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-27 20:40 +0200
    [PATCH perf/core v5 07/15] perf probe: Remove caches when --cache is given Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-27 20:40 +0200
    [PATCH perf/core v5 03/15] perf-buildid-cache: Use lsdir for looking up buildid caches Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-27 20:40 +0200
    [PATCH perf/core v5 15/15] perf probe: Support @BUILDID or @FILE suffix for SDT events Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-27 20:40 +0200
    [PATCH perf/core v5 13/15] perf-list: Skip SDTs placed in invalid binaries Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-27 20:40 +0200
    [PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-27 20:40 +0200
      Re: [PATCH perf/core v5 02/15] perf-buildid-cache: Use  path/to/bin/buildid/elf instead of path/to/bin/buildid Arnaldo Carvalho de Melo <acme@kernel.org> - 2016-04-27 23:20 +0200
        Re: [PATCH perf/core v5 02/15] perf-buildid-cache: Use  path/to/bin/buildid/elf instead of path/to/bin/buildid Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-28 04:00 +0200
      Re: [PATCH perf/core v5 02/15] perf-buildid-cache: Use  path/to/bin/buildid/elf instead of path/to/bin/buildid Arnaldo Carvalho de Melo <acme@kernel.org> - 2016-04-27 23:30 +0200
        Re: [PATCH perf/core v5 02/15] perf-buildid-cache: Use  path/to/bin/buildid/elf instead of path/to/bin/buildid Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-28 04:00 +0200
      Re: [PATCH perf/core v5 02/15] perf-buildid-cache: Use  path/to/bin/buildid/elf instead of path/to/bin/buildid Namhyung Kim <namhyung@kernel.org> - 2016-04-28 03:30 +0200
        Re: [PATCH perf/core v5 02/15] perf-buildid-cache: Use  path/to/bin/buildid/elf instead of path/to/bin/buildid Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-29 01:00 +0200
    [PATCH perf/core v5 04/15] perf probe: Add --cache option to cache the probe definitions Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-27 20:40 +0200
      Re: [PATCH perf/core v5 04/15] perf probe: Add --cache option to  cache the probe definitions Namhyung Kim <namhyung@kernel.org> - 2016-04-28 04:20 +0200
        Re: [PATCH perf/core v5 04/15] perf probe: Add --cache option to  cache the probe definitions Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-29 01:20 +0200
      Re: [PATCH perf/core v5 04/15] perf probe: Add --cache option to  cache the probe definitions Namhyung Kim <namhyung@kernel.org> - 2016-04-28 04:40 +0200
        Re: [PATCH perf/core v5 04/15] perf probe: Add --cache option to  cache the probe definitions Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-29 01:10 +0200
    [PATCH perf/core v5 14/15] perf probe: Allow wildcard for cached events Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-27 20:40 +0200
      Re: [PATCH perf/core v5 14/15] perf probe: Allow wildcard for  cached events Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-27 20:50 +0200
        [PATCH perf/core v5.1 14/15] perf probe: Allow wildcard for cached events Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-27 21:20 +0200
          Re: [PATCH perf/core v5.1 14/15] perf probe: Allow wildcard for cached  events Hemant Kumar <hemant@linux.vnet.ibm.com> - 2016-04-27 22:40 +0200
    [PATCH perf/core v5 12/15] perf-list: Show SDT and pre-cached events Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-27 20:40 +0200
      Re: [PATCH perf/core v5 12/15] perf-list: Show SDT and pre-cached  events Hemant Kumar <hemant@linux.vnet.ibm.com> - 2016-04-27 22:50 +0200
    [PATCH perf/core v5 11/15] perf probe: Accept %sdt and %cached event name Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-27 20:40 +0200
      Re: [PATCH perf/core v5 11/15] perf probe: Accept %sdt and %cached  event name Namhyung Kim <namhyung@kernel.org> - 2016-04-28 07:30 +0200
        Re: [PATCH perf/core v5 11/15] perf probe: Accept %sdt and %cached  event name Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-29 02:20 +0200
    [PATCH perf/core v5 09/15] perf probe: Add group name support Masami Hiramatsu <mhiramat@kernel.org> - 2016-04-27 20:40 +0200
    Re: [PATCH perf/core v5 00/15] perf-probe --cache and SDT support Hemant Kumar <hemant@linux.vnet.ibm.com> - 2016-04-29 16:00 +0200

Page 1 of 2  [1] 2  Next page →


#1389465 — [PATCH perf/core v5 00/15] perf-probe --cache and SDT support

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-27 20:40 +0200
Subject[PATCH perf/core v5 00/15] perf-probe --cache and SDT support
Message-ID<rsCxs-5Ye-11@gated-at.bofh.it>
Hi,

Here is the 5th version of the patchset for probe-cache and 
initial SDT support which are going to be perf-cache finally.

The previous version is here; https://lkml.org/lkml/2016/4/26/179

This version fixes a build bug on "make build-test", removed
accepted patches, and fold buildid-cache style change and backward
compatibility patches.
IOW, just a cleanup version :)

TODOs are here, but I think it should involve kernel-side change
to complete.
 - (perf record) Support SDT event recording directly
 - (perf record) Support @FILE/@BUILDID suffix to record specific SDTs.
 - (perf record) Try to unregister SDT events after record.
 - (ftrace) Support multiple SDTs on single event.

Thank you,

---

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

Masami Hiramatsu (14):
      perf probe: Use strbuf for making strings
      perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
      perf-buildid-cache: Use lsdir for looking up buildid caches
      perf probe: Add --cache option to cache the probe definitions
      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-list: Show SDT and pre-cached events
      perf-list: Skip SDTs placed in invalid binaries
      perf probe: Allow wildcard for cached events
      perf probe: Support @BUILDID or @FILE suffix for SDT events


 tools/perf/Documentation/perf-probe.txt |   24 +
 tools/perf/builtin-list.c               |    4 
 tools/perf/builtin-probe.c              |   30 +
 tools/perf/util/build-id.c              |  278 ++++++++++---
 tools/perf/util/build-id.h              |    6 
 tools/perf/util/dso.h                   |    5 
 tools/perf/util/parse-events.c          |   83 ++++
 tools/perf/util/parse-events.h          |    2 
 tools/perf/util/probe-event.c           |  684 ++++++++++++++++++++++---------
 tools/perf/util/probe-event.h           |    9 
 tools/perf/util/probe-file.c            |  492 ++++++++++++++++++++++
 tools/perf/util/probe-file.h            |   41 ++
 tools/perf/util/probe-finder.c          |   14 -
 tools/perf/util/symbol-elf.c            |  252 +++++++++++
 tools/perf/util/symbol.c                |   15 -
 tools/perf/util/symbol.h                |   22 +
 16 files changed, 1689 insertions(+), 272 deletions(-)

--
Masami Hiramatsu

[toc] | [next] | [standalone]


#1389466 — [PATCH perf/core v5 07/15] perf probe: Remove caches when --cache is given

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-27 20:40 +0200
Subject[PATCH perf/core v5 07/15] perf probe: Remove caches when --cache is given
Message-ID<rsCxs-5Ye-25@gated-at.bofh.it>
In reply to#1389465
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 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 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              |   27 +++++++++++++++++++++++++
 tools/perf/util/probe-file.c            |   33 +++++++++++++++++++++++--------
 tools/perf/util/probe-file.h            |    2 ++
 4 files changed, 55 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 53e380c0e..8f61525 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -363,6 +363,30 @@ 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;
+
+	ret = build_id_cache__list_all(&bidlist);
+	if (ret < 0) {
+		pr_debug("Failed to get buildids: %d\n", ret);
+		return ret;
+	}
+
+	strlist__for_each(nd, bidlist) {
+		cache = probe_cache__new(nd->s);
+		if (!cache)
+			continue;
+		probe_cache__remove_entries(cache, filter);
+		probe_cache__commit(cache);
+		probe_cache__delete(cache);
+	}
+	return 0;
+}
+
 static int perf_del_probe_events(struct strfilter *filter)
 {
 	int ret, ret2, ufd = -1, kfd = -1;
@@ -375,6 +399,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 72d58e7..46f006e 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -396,7 +396,6 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
 			return ret;
 		}
 	}
-
 	dir_name = build_id_cache__dirname_from_path(sbuildid, target,
 						     is_kallsyms, false);
 found:
@@ -652,19 +651,37 @@ 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__remove_entries(struct probe_cache *pcache,
+				struct strfilter *filter)
+{
+	struct probe_cache_entry *entry, *tmp;
+
+	list_for_each_entry_safe(entry, tmp, &pcache->list, list) {
+		if (probe_cache_entry__compare(entry, filter))
+			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->list, list) {
-		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 ac70446..e6fd9b9 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -37,6 +37,8 @@ int probe_cache__add_entry(struct probe_cache *pcache,
 			   struct probe_trace_event *tevs, int ntevs);
 int probe_cache__commit(struct probe_cache *pcache);
 void probe_cache__delete(struct probe_cache *pcache);
+int probe_cache__remove_entries(struct probe_cache *pcache,
+				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,

[toc] | [prev] | [next] | [standalone]


#1389469 — [PATCH perf/core v5 03/15] perf-buildid-cache: Use lsdir for looking up buildid caches

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-27 20:40 +0200
Subject[PATCH perf/core v5 03/15] perf-buildid-cache: Use lsdir for looking up buildid caches
Message-ID<rsCxs-5Ye-35@gated-at.bofh.it>
In reply to#1389465
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

Use new lsdir() for looking up buildid caches. This changes
logic a bit to ignore all dot files, since the build-id
cache must not start with dot.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 tools/perf/util/build-id.c |   30 +++++-------------------------
 1 file changed, 5 insertions(+), 25 deletions(-)

diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index b035483..848e05f 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -400,38 +400,18 @@ int build_id_cache__list_build_ids(const char *pathname,
 {
 	struct strlist *list;
 	char *dir_name;
-	DIR *dir;
-	struct dirent *d;
 	int ret = 0;
 
-	list = strlist__new(NULL, NULL);
 	dir_name = build_id_cache__dirname_from_path(pathname, false, false,
 						     NULL);
-	if (!list || !dir_name) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	if (!dir_name)
+		return -ENOMEM;
 
-	/* List up all dirents */
-	dir = opendir(dir_name);
-	if (!dir) {
+	list = lsdir(dir_name, lsdir_no_dot_filter);
+	if (!list)
 		ret = -errno;
-		goto out;
-	}
-
-	while ((d = readdir(dir)) != NULL) {
-		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
-			continue;
-		strlist__add(list, d->d_name);
-	}
-	closedir(dir);
-
-out:
+	*result = list;
 	free(dir_name);
-	if (ret)
-		strlist__delete(list);
-	else
-		*result = list;
 
 	return ret;
 }

[toc] | [prev] | [next] | [standalone]


#1389470 — [PATCH perf/core v5 15/15] perf probe: Support @BUILDID or @FILE suffix for SDT events

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-27 20:40 +0200
Subject[PATCH perf/core v5 15/15] perf probe: Support @BUILDID or @FILE suffix for SDT events
Message-ID<rsCxt-5Ye-37@gated-at.bofh.it>
In reply to#1389465
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>
---
 tools/perf/util/build-id.c    |   40 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/build-id.h    |    1 +
 tools/perf/util/probe-event.c |   17 +++++++++++++++--
 3 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index c849253..4fec09e 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -472,6 +472,46 @@ out:
 	return ret;
 }
 
+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 *list;
+	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) ||
+	    build_id_cache__list_all(&list, true) < 0)
+		return NULL;
+
+	strlist__for_each(nd, list) {
+		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(list);
+
+	return sbuild_id;
+}
+
 char *build_id_cache__dirname_from_path(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 5e29cfc..cafab5e 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -33,6 +33,7 @@ char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
 char *build_id_cache__dirname_from_path(const char *sbuild_id, const char *name,
 					bool is_kallsyms, bool is_vdso);
 int build_id_cache__list_all(struct strlist **result, 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 9ca8392..29dc153 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1253,8 +1253,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 contain only an SDT event 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;
+			pev->uprobes = 1;
+			*ptr = '\0';
 		}
 		ret = parse_perf_probe_event_name(&arg, pev);
 		if (ret == 0) {

[toc] | [prev] | [next] | [standalone]


#1389472 — [PATCH perf/core v5 13/15] perf-list: Skip SDTs placed in invalid binaries

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-27 20:40 +0200
Subject[PATCH perf/core v5 13/15] perf-list: Skip SDTs placed in invalid binaries
Message-ID<rsCxt-5Ye-41@gated-at.bofh.it>
In reply to#1389465
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

Skip SDTs placed in invalid (non-exist, or older version)
binaries. Note that perf-probe --cache --list and
perf-probe --cache --del still handle all the caches
including invalid binaries.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v4:
  - Rename a parameter 'valid' to 'validonly' :)
---
 tools/perf/builtin-probe.c     |    2 +-
 tools/perf/util/build-id.c     |   27 ++++++++++++++++++++++++++-
 tools/perf/util/build-id.h     |    2 +-
 tools/perf/util/parse-events.c |    2 +-
 tools/perf/util/probe-file.c   |    2 +-
 5 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 8f61525..4a86aea 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;
 
-	ret = build_id_cache__list_all(&bidlist);
+	ret = build_id_cache__list_all(&bidlist, false);
 	if (ret < 0) {
 		pr_debug("Failed to get buildids: %d\n", ret);
 		return ret;
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 49a467b9..c849253 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -184,6 +184,25 @@ out:
 	return ret;
 }
 
+static bool build_id_cache__valid_id(char *sbuild_id)
+{
+	char real_sbuild_id[SBUILD_ID_SIZE] = "";
+	char *pathname;
+	bool ret;
+
+	pathname = build_id_cache__origname(sbuild_id);
+	if (!pathname)
+		return false;
+
+	if (filename__sprintf_build_id(pathname, real_sbuild_id) < 0)
+		ret = false;
+	else
+		ret = (strcmp(sbuild_id, real_sbuild_id) == 0);
+	free(pathname);
+
+	return ret;
+}
+
 static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
 {
 	return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
@@ -394,7 +413,7 @@ void disable_buildid_cache(void)
 	no_buildid_cache = true;
 }
 
-int build_id_cache__list_all(struct strlist **result)
+int build_id_cache__list_all(struct strlist **result, bool validonly)
 {
 	struct strlist *toplist, *list, *bidlist;
 	struct str_node *nd, *nd2;
@@ -402,6 +421,10 @@ int build_id_cache__list_all(struct strlist **result)
 	char sbuild_id[SBUILD_ID_SIZE];
 	int ret = 0;
 
+	/* for filename__ functions */
+	if (validonly)
+		symbol__init(NULL);
+
 	/* Open the top-level directory */
 	if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
 		return -errno;
@@ -431,6 +454,8 @@ int build_id_cache__list_all(struct strlist **result)
 					nd->s, nd2->s);
 				continue;
 			}
+			if (validonly && !build_id_cache__valid_id(sbuild_id))
+				continue;
 			strlist__add(bidlist, sbuild_id);
 		}
 		strlist__delete(list);
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 2c98a39..5e29cfc 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -32,7 +32,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__dirname_from_path(const char *sbuild_id, const char *name,
 					bool is_kallsyms, bool is_vdso);
-int build_id_cache__list_all(struct strlist **result);
+int build_id_cache__list_all(struct strlist **result, 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/parse-events.c b/tools/perf/util/parse-events.c
index f9c8b7b..53d52a3 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1994,7 +1994,7 @@ void print_sdt_events(const char *subsys_glob, const char *event_glob,
 		pr_debug("Failed to allocate new strlist for SDT\n");
 		return;
 	}
-	ret = build_id_cache__list_all(&bidlist);
+	ret = build_id_cache__list_all(&bidlist, true);
 	if (ret < 0) {
 		pr_debug("Failed to get buildids: %d\n", ret);
 		return;
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index ee560dd..2437b48 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -770,7 +770,7 @@ int probe_cache__show_all_caches(struct strfilter *filter)
 	pr_debug("list cache with filter: %s\n", buf);
 	free(buf);
 
-	ret = build_id_cache__list_all(&bidlist);
+	ret = build_id_cache__list_all(&bidlist, false);
 	if (ret < 0) {
 		pr_debug("Failed to get buildids: %d\n", ret);
 		return ret == -ENOENT ? 0 : ret;

[toc] | [prev] | [next] | [standalone]


#1389473 — [PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-27 20:40 +0200
Subject[PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
Message-ID<rsCxt-5Ye-51@gated-at.bofh.it>
In reply to#1389465
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

Use path/to/bin/buildid/elf instead of path/to/bin/buildid
to store corresponding elf binary.
This also stores vdso in buildid/vdso, kallsyms in buildid/kallsyms.

Note that the existing caches are not updated until user adds
or updates the cache. Anyway, if there is the old style build-id
cache it falls back to use it. (IOW, it is backward compatible)

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v5:
  - Support old style buildid caches.
---
 tools/perf/util/build-id.c |   80 ++++++++++++++++++++++++++++++++++----------
 tools/perf/util/dso.h      |    5 +++
 tools/perf/util/symbol.c   |   15 ++++++--
 3 files changed, 76 insertions(+), 24 deletions(-)

diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index b6ecf87..b035483 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -144,7 +144,8 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...)
 	return ret;
 }
 
-static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
+static 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,
@@ -154,15 +155,45 @@ static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
 	return bf;
 }
 
+static bool __is_regular_file(const char *pathname)
+{
+	struct stat sb;
+	return stat(pathname, &sb) == 0 && S_ISREG(sb.st_mode);
+}
+
+static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
+{
+	return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
+}
+
 char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
 {
-	char build_id_hex[SBUILD_ID_SIZE];
+	bool is_kallsyms = dso__is_kallsyms((struct dso *)dso);
+	bool is_vdso = dso__is_vdso((struct dso *)dso);
+	char sbuild_id[SBUILD_ID_SIZE];
+	char *linkname;
+	bool alloc = (bf == NULL);
+	int ret;
 
 	if (!dso->has_build_id)
 		return NULL;
 
-	build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex);
-	return build_id__filename(build_id_hex, bf, size);
+	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
+	linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
+	if (!linkname)
+		return NULL;
+
+	/* Check if old style build_id cache */
+	if (__is_regular_file(linkname))
+		ret = asnprintf(&bf, size, "%s", linkname);
+	else
+		ret = asnprintf(&bf, size, "%s/%s", linkname,
+			 build_id_cache__basename(is_kallsyms, is_vdso));
+	if (ret < 0 || (!alloc && size < (unsigned int)ret))
+		bf = NULL;
+	free(linkname);
+
+	return bf;
 }
 
 bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
@@ -341,7 +372,8 @@ void disable_buildid_cache(void)
 }
 
 static char *build_id_cache__dirname_from_path(const char *name,
-					       bool is_kallsyms, bool is_vdso)
+					       bool is_kallsyms, bool is_vdso,
+					       const char *sbuild_id)
 {
 	char *realname = (char *)name, *filename;
 	bool slash = is_kallsyms || is_vdso;
@@ -352,8 +384,9 @@ static char *build_id_cache__dirname_from_path(const char *name,
 			return NULL;
 	}
 
-	if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "",
-		     is_vdso ? DSO__NAME_VDSO : realname) < 0)
+	if (asprintf(&filename, "%s%s%s%s%s", buildid_dir, slash ? "/" : "",
+		     is_vdso ? DSO__NAME_VDSO : realname,
+		     sbuild_id ? "/" : "", sbuild_id ?: "") < 0)
 		filename = NULL;
 
 	if (!slash)
@@ -372,7 +405,8 @@ int build_id_cache__list_build_ids(const char *pathname,
 	int ret = 0;
 
 	list = strlist__new(NULL, NULL);
-	dir_name = build_id_cache__dirname_from_path(pathname, false, false);
+	dir_name = build_id_cache__dirname_from_path(pathname, false, false,
+						     NULL);
 	if (!list || !dir_name) {
 		ret = -ENOMEM;
 		goto out;
@@ -407,7 +441,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
 {
 	const size_t size = PATH_MAX;
 	char *realname = NULL, *filename = NULL, *dir_name = NULL,
-	     *linkname = zalloc(size), *targetname, *tmp;
+	     *linkname = zalloc(size), *tmp;
 	int err = -1;
 
 	if (!is_kallsyms) {
@@ -416,14 +450,22 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
 			goto out_free;
 	}
 
-	dir_name = build_id_cache__dirname_from_path(name, is_kallsyms, is_vdso);
+	dir_name = build_id_cache__dirname_from_path(name, is_kallsyms,
+						     is_vdso, sbuild_id);
 	if (!dir_name)
 		goto out_free;
 
+	/* Remove old style build-id cache */
+	if (__is_regular_file(dir_name))
+		if (unlink(dir_name))
+			goto out_free;
+
 	if (mkdir_p(dir_name, 0755))
 		goto out_free;
 
-	if (asprintf(&filename, "%s/%s", dir_name, sbuild_id) < 0) {
+	/* Save the allocated buildid dirname */
+	if (asprintf(&filename, "%s/%s", dir_name,
+		     build_id_cache__basename(is_kallsyms, is_vdso)) < 0) {
 		filename = NULL;
 		goto out_free;
 	}
@@ -437,7 +479,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
 			goto out_free;
 	}
 
-	if (!build_id__filename(sbuild_id, linkname, size))
+	if (!build_id_cache__linkname(sbuild_id, linkname, size))
 		goto out_free;
 	tmp = strrchr(linkname, '/');
 	*tmp = '\0';
@@ -446,10 +488,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
 		goto out_free;
 
 	*tmp = '/';
-	targetname = filename + strlen(buildid_dir) - 5;
-	memcpy(targetname, "../..", 5);
+	tmp = dir_name + strlen(buildid_dir) - 5;
+	memcpy(tmp, "../..", 5);
 
-	if (symlink(targetname, linkname) == 0)
+	if (symlink(tmp, linkname) == 0)
 		err = 0;
 out_free:
 	if (!is_kallsyms)
@@ -474,7 +516,7 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
 bool build_id_cache__cached(const char *sbuild_id)
 {
 	bool ret = false;
-	char *filename = build_id__filename(sbuild_id, NULL, 0);
+	char *filename = build_id_cache__linkname(sbuild_id, NULL, 0);
 
 	if (filename && !access(filename, F_OK))
 		ret = true;
@@ -493,7 +535,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
 	if (filename == NULL || linkname == NULL)
 		goto out_free;
 
-	if (!build_id__filename(sbuild_id, linkname, size))
+	if (!build_id_cache__linkname(sbuild_id, linkname, size))
 		goto out_free;
 
 	if (access(linkname, F_OK))
@@ -511,7 +553,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
 	tmp = strrchr(linkname, '/') + 1;
 	snprintf(tmp, size - (tmp - linkname), "%s", filename);
 
-	if (unlink(linkname))
+	if (rm_rf(linkname))
 		goto out_free;
 
 	err = 0;
@@ -523,7 +565,7 @@ out_free:
 
 static int dso__cache_build_id(struct dso *dso, struct machine *machine)
 {
-	bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
+	bool is_kallsyms = dso__is_kallsyms(dso);
 	bool is_vdso = dso__is_vdso(dso);
 	const char *name = dso->long_name;
 	char nm[PATH_MAX];
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 0953280..76d79d0 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -349,6 +349,11 @@ static inline bool dso__is_kcore(struct dso *dso)
 	       dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE;
 }
 
+static inline bool dso__is_kallsyms(struct dso *dso)
+{
+	return dso->kernel && dso->long_name[0] != '/';
+}
+
 void dso__free_a2l(struct dso *dso);
 
 enum dso_type dso__type(struct dso *dso, struct machine *machine);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 415c4f6..9463c7d 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1685,13 +1685,18 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
 	if (!find_matching_kcore(map, path, sizeof(path)))
 		return strdup(path);
 
-	scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
+	scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s/kallsyms",
 		  buildid_dir, sbuild_id);
-
+	/* Try old style kallsyms cache */
 	if (access(path, F_OK)) {
-		pr_err("No kallsyms or vmlinux with build-id %s was found\n",
-		       sbuild_id);
-		return NULL;
+		scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
+			  buildid_dir, sbuild_id);
+
+		if (access(path, F_OK)) {
+			pr_err("No kallsyms or vmlinux with build-id %s was found\n",
+			       sbuild_id);
+			return NULL;
+		}
 	}
 
 	return strdup(path);

[toc] | [prev] | [next] | [standalone]


#1389587 — Re: [PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid

FromArnaldo Carvalho de Melo <acme@kernel.org>
Date2016-04-27 23:20 +0200
SubjectRe: [PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
Message-ID<rsF2h-8fU-3@gated-at.bofh.it>
In reply to#1389473
Em Thu, Apr 28, 2016 at 03:37:23AM +0900, Masami Hiramatsu escreveu:
> From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> 
> Use path/to/bin/buildid/elf instead of path/to/bin/buildid
> to store corresponding elf binary.
> This also stores vdso in buildid/vdso, kallsyms in buildid/kallsyms.
> 
> Note that the existing caches are not updated until user adds
> or updates the cache. Anyway, if there is the old style build-id
> cache it falls back to use it. (IOW, it is backward compatible)

I reworded this to:

"If there is old style build-id cache content, i.e. links to
path/to/bin/buildid/aa/bbccdd, it will still be accessible, IOW, this is
backard compatible."

This part "existing caches are not updated until the user updates de
cache" sounds confusing.

Anyway, applied.

- Arnaldo

[toc] | [prev] | [next] | [standalone]


#1389764 — Re: [PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-28 04:00 +0200
SubjectRe: [PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
Message-ID<rsJpg-35w-5@gated-at.bofh.it>
In reply to#1389587
On Wed, 27 Apr 2016 18:12:32 -0300
Arnaldo Carvalho de Melo <acme@kernel.org> wrote:

> Em Thu, Apr 28, 2016 at 03:37:23AM +0900, Masami Hiramatsu escreveu:
> > From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > 
> > Use path/to/bin/buildid/elf instead of path/to/bin/buildid
> > to store corresponding elf binary.
> > This also stores vdso in buildid/vdso, kallsyms in buildid/kallsyms.
> > 
> > Note that the existing caches are not updated until user adds
> > or updates the cache. Anyway, if there is the old style build-id
> > cache it falls back to use it. (IOW, it is backward compatible)
> 
> I reworded this to:
> 
> "If there is old style build-id cache content, i.e. links to
> path/to/bin/buildid/aa/bbccdd, it will still be accessible, IOW, this is
> backard compatible."
> 
> This part "existing caches are not updated until the user updates de
> cache" sounds confusing.

Ah, I see. Thank you!

> 
> Anyway, applied.
> 
> - Arnaldo


-- 
Masami Hiramatsu <mhiramat@kernel.org>

[toc] | [prev] | [next] | [standalone]


#1389598 — Re: [PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid

FromArnaldo Carvalho de Melo <acme@kernel.org>
Date2016-04-27 23:30 +0200
SubjectRe: [PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
Message-ID<rsFbZ-8m2-15@gated-at.bofh.it>
In reply to#1389473
Em Thu, Apr 28, 2016 at 03:37:23AM +0900, Masami Hiramatsu escreveu:
> From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> 
> Use path/to/bin/buildid/elf instead of path/to/bin/buildid
> to store corresponding elf binary.
> This also stores vdso in buildid/vdso, kallsyms in buildid/kallsyms.
> 
> Note that the existing caches are not updated until user adds
> or updates the cache. Anyway, if there is the old style build-id
> cache it falls back to use it. (IOW, it is backward compatible)
> 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> ---
>  Changes in v5:
>   - Support old style buildid caches.

> +	/* Remove old style build-id cache */
> +	if (__is_regular_file(dir_name))
> +		if (unlink(dir_name))
> +			goto out_free;

Shouldn't this just fail and require the user to use --force/-f or purge
first?

- Arnaldo

>  	if (mkdir_p(dir_name, 0755))
>  		goto out_free;
>  
> -	if (asprintf(&filename, "%s/%s", dir_name, sbuild_id) < 0) {
> +	/* Save the allocated buildid dirname */
> +	if (asprintf(&filename, "%s/%s", dir_name,
> +		     build_id_cache__basename(is_kallsyms, is_vdso)) < 0) {
>  		filename = NULL;
>  		goto out_free;
>  	}
> @@ -437,7 +479,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
>  			goto out_free;
>  	}
>  
> -	if (!build_id__filename(sbuild_id, linkname, size))
> +	if (!build_id_cache__linkname(sbuild_id, linkname, size))
>  		goto out_free;
>  	tmp = strrchr(linkname, '/');
>  	*tmp = '\0';
> @@ -446,10 +488,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
>  		goto out_free;
>  
>  	*tmp = '/';
> -	targetname = filename + strlen(buildid_dir) - 5;
> -	memcpy(targetname, "../..", 5);
> +	tmp = dir_name + strlen(buildid_dir) - 5;
> +	memcpy(tmp, "../..", 5);
>  
> -	if (symlink(targetname, linkname) == 0)
> +	if (symlink(tmp, linkname) == 0)
>  		err = 0;
>  out_free:
>  	if (!is_kallsyms)
> @@ -474,7 +516,7 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
>  bool build_id_cache__cached(const char *sbuild_id)
>  {
>  	bool ret = false;
> -	char *filename = build_id__filename(sbuild_id, NULL, 0);
> +	char *filename = build_id_cache__linkname(sbuild_id, NULL, 0);
>  
>  	if (filename && !access(filename, F_OK))
>  		ret = true;
> @@ -493,7 +535,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
>  	if (filename == NULL || linkname == NULL)
>  		goto out_free;
>  
> -	if (!build_id__filename(sbuild_id, linkname, size))
> +	if (!build_id_cache__linkname(sbuild_id, linkname, size))
>  		goto out_free;
>  
>  	if (access(linkname, F_OK))
> @@ -511,7 +553,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
>  	tmp = strrchr(linkname, '/') + 1;
>  	snprintf(tmp, size - (tmp - linkname), "%s", filename);
>  
> -	if (unlink(linkname))
> +	if (rm_rf(linkname))
>  		goto out_free;
>  
>  	err = 0;
> @@ -523,7 +565,7 @@ out_free:
>  
>  static int dso__cache_build_id(struct dso *dso, struct machine *machine)
>  {
> -	bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
> +	bool is_kallsyms = dso__is_kallsyms(dso);
>  	bool is_vdso = dso__is_vdso(dso);
>  	const char *name = dso->long_name;
>  	char nm[PATH_MAX];
> diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
> index 0953280..76d79d0 100644
> --- a/tools/perf/util/dso.h
> +++ b/tools/perf/util/dso.h
> @@ -349,6 +349,11 @@ static inline bool dso__is_kcore(struct dso *dso)
>  	       dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE;
>  }
>  
> +static inline bool dso__is_kallsyms(struct dso *dso)
> +{
> +	return dso->kernel && dso->long_name[0] != '/';
> +}
> +
>  void dso__free_a2l(struct dso *dso);
>  
>  enum dso_type dso__type(struct dso *dso, struct machine *machine);
> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> index 415c4f6..9463c7d 100644
> --- a/tools/perf/util/symbol.c
> +++ b/tools/perf/util/symbol.c
> @@ -1685,13 +1685,18 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
>  	if (!find_matching_kcore(map, path, sizeof(path)))
>  		return strdup(path);
>  
> -	scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
> +	scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s/kallsyms",
>  		  buildid_dir, sbuild_id);
> -
> +	/* Try old style kallsyms cache */
>  	if (access(path, F_OK)) {
> -		pr_err("No kallsyms or vmlinux with build-id %s was found\n",
> -		       sbuild_id);
> -		return NULL;
> +		scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
> +			  buildid_dir, sbuild_id);
> +
> +		if (access(path, F_OK)) {
> +			pr_err("No kallsyms or vmlinux with build-id %s was found\n",
> +			       sbuild_id);
> +			return NULL;
> +		}
>  	}
>  
>  	return strdup(path);

[toc] | [prev] | [next] | [standalone]


#1389765 — Re: [PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-28 04:00 +0200
SubjectRe: [PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
Message-ID<rsJpg-35w-3@gated-at.bofh.it>
In reply to#1389598
On Wed, 27 Apr 2016 18:23:50 -0300
Arnaldo Carvalho de Melo <acme@kernel.org> wrote:

> Em Thu, Apr 28, 2016 at 03:37:23AM +0900, Masami Hiramatsu escreveu:
> > From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > 
> > Use path/to/bin/buildid/elf instead of path/to/bin/buildid
> > to store corresponding elf binary.
> > This also stores vdso in buildid/vdso, kallsyms in buildid/kallsyms.
> > 
> > Note that the existing caches are not updated until user adds
> > or updates the cache. Anyway, if there is the old style build-id
> > cache it falls back to use it. (IOW, it is backward compatible)
> > 
> > Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> > ---
> >  Changes in v5:
> >   - Support old style buildid caches.
> 
> > +	/* Remove old style build-id cache */
> > +	if (__is_regular_file(dir_name))
> > +		if (unlink(dir_name))
> > +			goto out_free;
> 
> Shouldn't this just fail and require the user to use --force/-f or purge
> first?

No, I don't think so, because the old style build-id is useless for
probe-cache in anyway, and after applying this patch, perf can use
new one seemlessly. So let just renew it :)

Thank you,

-- 
Masami Hiramatsu <mhiramat@kernel.org>

[toc] | [prev] | [next] | [standalone]


#1389740 — Re: [PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid

FromNamhyung Kim <namhyung@kernel.org>
Date2016-04-28 03:30 +0200
SubjectRe: [PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
Message-ID<rsIWe-2QW-7@gated-at.bofh.it>
In reply to#1389473
Hi Masami,

On Thu, Apr 28, 2016 at 03:37:23AM +0900, Masami Hiramatsu wrote:
> From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> 
> Use path/to/bin/buildid/elf instead of path/to/bin/buildid
> to store corresponding elf binary.
> This also stores vdso in buildid/vdso, kallsyms in buildid/kallsyms.
> 
> Note that the existing caches are not updated until user adds
> or updates the cache. Anyway, if there is the old style build-id
> cache it falls back to use it. (IOW, it is backward compatible)
> 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> ---
>  Changes in v5:
>   - Support old style buildid caches.
> ---
>  tools/perf/util/build-id.c |   80 ++++++++++++++++++++++++++++++++++----------
>  tools/perf/util/dso.h      |    5 +++
>  tools/perf/util/symbol.c   |   15 ++++++--
>  3 files changed, 76 insertions(+), 24 deletions(-)
> 
> diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> index b6ecf87..b035483 100644
> --- a/tools/perf/util/build-id.c
> +++ b/tools/perf/util/build-id.c
> @@ -144,7 +144,8 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...)
>  	return ret;
>  }
>  
> -static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
> +static 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,
> @@ -154,15 +155,45 @@ static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
>  	return bf;
>  }
>  
> +static bool __is_regular_file(const char *pathname)
> +{
> +	struct stat sb;
> +	return stat(pathname, &sb) == 0 && S_ISREG(sb.st_mode);
> +}

It looks like that the is_regular_file() is already in the
util/util.c

Thanks,
Namhyung


> +
> +static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
> +{
> +	return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
> +}
> +
>  char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
>  {
> -	char build_id_hex[SBUILD_ID_SIZE];
> +	bool is_kallsyms = dso__is_kallsyms((struct dso *)dso);
> +	bool is_vdso = dso__is_vdso((struct dso *)dso);
> +	char sbuild_id[SBUILD_ID_SIZE];
> +	char *linkname;
> +	bool alloc = (bf == NULL);
> +	int ret;
>  
>  	if (!dso->has_build_id)
>  		return NULL;
>  
> -	build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex);
> -	return build_id__filename(build_id_hex, bf, size);
> +	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
> +	linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
> +	if (!linkname)
> +		return NULL;
> +
> +	/* Check if old style build_id cache */
> +	if (__is_regular_file(linkname))
> +		ret = asnprintf(&bf, size, "%s", linkname);
> +	else
> +		ret = asnprintf(&bf, size, "%s/%s", linkname,
> +			 build_id_cache__basename(is_kallsyms, is_vdso));
> +	if (ret < 0 || (!alloc && size < (unsigned int)ret))
> +		bf = NULL;
> +	free(linkname);
> +
> +	return bf;
>  }
>  
>  bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
> @@ -341,7 +372,8 @@ void disable_buildid_cache(void)
>  }
>  
>  static char *build_id_cache__dirname_from_path(const char *name,
> -					       bool is_kallsyms, bool is_vdso)
> +					       bool is_kallsyms, bool is_vdso,
> +					       const char *sbuild_id)
>  {
>  	char *realname = (char *)name, *filename;
>  	bool slash = is_kallsyms || is_vdso;
> @@ -352,8 +384,9 @@ static char *build_id_cache__dirname_from_path(const char *name,
>  			return NULL;
>  	}
>  
> -	if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "",
> -		     is_vdso ? DSO__NAME_VDSO : realname) < 0)
> +	if (asprintf(&filename, "%s%s%s%s%s", buildid_dir, slash ? "/" : "",
> +		     is_vdso ? DSO__NAME_VDSO : realname,
> +		     sbuild_id ? "/" : "", sbuild_id ?: "") < 0)
>  		filename = NULL;
>  
>  	if (!slash)
> @@ -372,7 +405,8 @@ int build_id_cache__list_build_ids(const char *pathname,
>  	int ret = 0;
>  
>  	list = strlist__new(NULL, NULL);
> -	dir_name = build_id_cache__dirname_from_path(pathname, false, false);
> +	dir_name = build_id_cache__dirname_from_path(pathname, false, false,
> +						     NULL);
>  	if (!list || !dir_name) {
>  		ret = -ENOMEM;
>  		goto out;
> @@ -407,7 +441,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
>  {
>  	const size_t size = PATH_MAX;
>  	char *realname = NULL, *filename = NULL, *dir_name = NULL,
> -	     *linkname = zalloc(size), *targetname, *tmp;
> +	     *linkname = zalloc(size), *tmp;
>  	int err = -1;
>  
>  	if (!is_kallsyms) {
> @@ -416,14 +450,22 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
>  			goto out_free;
>  	}
>  
> -	dir_name = build_id_cache__dirname_from_path(name, is_kallsyms, is_vdso);
> +	dir_name = build_id_cache__dirname_from_path(name, is_kallsyms,
> +						     is_vdso, sbuild_id);
>  	if (!dir_name)
>  		goto out_free;
>  
> +	/* Remove old style build-id cache */
> +	if (__is_regular_file(dir_name))
> +		if (unlink(dir_name))
> +			goto out_free;
> +
>  	if (mkdir_p(dir_name, 0755))
>  		goto out_free;
>  
> -	if (asprintf(&filename, "%s/%s", dir_name, sbuild_id) < 0) {
> +	/* Save the allocated buildid dirname */
> +	if (asprintf(&filename, "%s/%s", dir_name,
> +		     build_id_cache__basename(is_kallsyms, is_vdso)) < 0) {
>  		filename = NULL;
>  		goto out_free;
>  	}
> @@ -437,7 +479,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
>  			goto out_free;
>  	}
>  
> -	if (!build_id__filename(sbuild_id, linkname, size))
> +	if (!build_id_cache__linkname(sbuild_id, linkname, size))
>  		goto out_free;
>  	tmp = strrchr(linkname, '/');
>  	*tmp = '\0';
> @@ -446,10 +488,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
>  		goto out_free;
>  
>  	*tmp = '/';
> -	targetname = filename + strlen(buildid_dir) - 5;
> -	memcpy(targetname, "../..", 5);
> +	tmp = dir_name + strlen(buildid_dir) - 5;
> +	memcpy(tmp, "../..", 5);
>  
> -	if (symlink(targetname, linkname) == 0)
> +	if (symlink(tmp, linkname) == 0)
>  		err = 0;
>  out_free:
>  	if (!is_kallsyms)
> @@ -474,7 +516,7 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
>  bool build_id_cache__cached(const char *sbuild_id)
>  {
>  	bool ret = false;
> -	char *filename = build_id__filename(sbuild_id, NULL, 0);
> +	char *filename = build_id_cache__linkname(sbuild_id, NULL, 0);
>  
>  	if (filename && !access(filename, F_OK))
>  		ret = true;
> @@ -493,7 +535,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
>  	if (filename == NULL || linkname == NULL)
>  		goto out_free;
>  
> -	if (!build_id__filename(sbuild_id, linkname, size))
> +	if (!build_id_cache__linkname(sbuild_id, linkname, size))
>  		goto out_free;
>  
>  	if (access(linkname, F_OK))
> @@ -511,7 +553,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
>  	tmp = strrchr(linkname, '/') + 1;
>  	snprintf(tmp, size - (tmp - linkname), "%s", filename);
>  
> -	if (unlink(linkname))
> +	if (rm_rf(linkname))
>  		goto out_free;
>  
>  	err = 0;
> @@ -523,7 +565,7 @@ out_free:
>  
>  static int dso__cache_build_id(struct dso *dso, struct machine *machine)
>  {
> -	bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
> +	bool is_kallsyms = dso__is_kallsyms(dso);
>  	bool is_vdso = dso__is_vdso(dso);
>  	const char *name = dso->long_name;
>  	char nm[PATH_MAX];
> diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
> index 0953280..76d79d0 100644
> --- a/tools/perf/util/dso.h
> +++ b/tools/perf/util/dso.h
> @@ -349,6 +349,11 @@ static inline bool dso__is_kcore(struct dso *dso)
>  	       dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE;
>  }
>  
> +static inline bool dso__is_kallsyms(struct dso *dso)
> +{
> +	return dso->kernel && dso->long_name[0] != '/';
> +}
> +
>  void dso__free_a2l(struct dso *dso);
>  
>  enum dso_type dso__type(struct dso *dso, struct machine *machine);
> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> index 415c4f6..9463c7d 100644
> --- a/tools/perf/util/symbol.c
> +++ b/tools/perf/util/symbol.c
> @@ -1685,13 +1685,18 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
>  	if (!find_matching_kcore(map, path, sizeof(path)))
>  		return strdup(path);
>  
> -	scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
> +	scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s/kallsyms",
>  		  buildid_dir, sbuild_id);
> -
> +	/* Try old style kallsyms cache */
>  	if (access(path, F_OK)) {
> -		pr_err("No kallsyms or vmlinux with build-id %s was found\n",
> -		       sbuild_id);
> -		return NULL;
> +		scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
> +			  buildid_dir, sbuild_id);
> +
> +		if (access(path, F_OK)) {
> +			pr_err("No kallsyms or vmlinux with build-id %s was found\n",
> +			       sbuild_id);
> +			return NULL;
> +		}
>  	}
>  
>  	return strdup(path);
> 

[toc] | [prev] | [next] | [standalone]


#1390608 — Re: [PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-29 01:00 +0200
SubjectRe: [PATCH perf/core v5 02/15] perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
Message-ID<rt34C-3xI-11@gated-at.bofh.it>
In reply to#1389740
On Thu, 28 Apr 2016 10:22:23 +0900
Namhyung Kim <namhyung@kernel.org> wrote:

> Hi Masami,
> 
> On Thu, Apr 28, 2016 at 03:37:23AM +0900, Masami Hiramatsu wrote:
> > From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > 
> > Use path/to/bin/buildid/elf instead of path/to/bin/buildid
> > to store corresponding elf binary.
> > This also stores vdso in buildid/vdso, kallsyms in buildid/kallsyms.
> > 
> > Note that the existing caches are not updated until user adds
> > or updates the cache. Anyway, if there is the old style build-id
> > cache it falls back to use it. (IOW, it is backward compatible)
> > 
> > Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> > ---
> >  Changes in v5:
> >   - Support old style buildid caches.
> > ---
> >  tools/perf/util/build-id.c |   80 ++++++++++++++++++++++++++++++++++----------
> >  tools/perf/util/dso.h      |    5 +++
> >  tools/perf/util/symbol.c   |   15 ++++++--
> >  3 files changed, 76 insertions(+), 24 deletions(-)
> > 
> > diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> > index b6ecf87..b035483 100644
> > --- a/tools/perf/util/build-id.c
> > +++ b/tools/perf/util/build-id.c
> > @@ -144,7 +144,8 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...)
> >  	return ret;
> >  }
> >  
> > -static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
> > +static 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,
> > @@ -154,15 +155,45 @@ static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
> >  	return bf;
> >  }
> >  
> > +static bool __is_regular_file(const char *pathname)
> > +{
> > +	struct stat sb;
> > +	return stat(pathname, &sb) == 0 && S_ISREG(sb.st_mode);
> > +}
> 
> It looks like that the is_regular_file() is already in the
> util/util.c

Nice catch!!
OK, it should be used.

Thanks!

-- 
Masami Hiramatsu <mhiramat@kernel.org>

[toc] | [prev] | [next] | [standalone]


#1389474 — [PATCH perf/core v5 04/15] perf probe: Add --cache option to cache the probe definitions

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-27 20:40 +0200
Subject[PATCH perf/core v5 04/15] perf probe: Add --cache option to cache the probe definitions
Message-ID<rsCxt-5Ye-49@gated-at.bofh.it>
In reply to#1389465
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

Add --cache option to cache the probe definitions. This
just saves the result of the dwarf analysis to probe cache.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v5:
  - Move probe_cache* definitions. (code cleanup)

 Changes in v4:
  - Remove cache saving failure message.
---
 tools/perf/Documentation/perf-probe.txt |    4 
 tools/perf/builtin-probe.c              |    1 
 tools/perf/util/build-id.c              |   13 +
 tools/perf/util/build-id.h              |    2 
 tools/perf/util/probe-event.c           |  126 +++++++++++--
 tools/perf/util/probe-event.h           |    5 +
 tools/perf/util/probe-file.c            |  299 +++++++++++++++++++++++++++++++
 tools/perf/util/probe-file.h            |   19 ++
 8 files changed, 441 insertions(+), 28 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 3a8a9ba..947db6f 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -109,6 +109,10 @@ OPTIONS
 	Dry run. With this option, --add and --del doesn't execute actual
 	adding and removal operations.
 
+--cache::
+	Cache the probes (with --add option). Any events which successfully added
+	are also stored in the cache file.
+
 --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 9af859b..6d7ab431 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -512,6 +512,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 		    "Enable symbol demangling"),
 	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
 		    "Enable kernel symbol demangling"),
+	OPT_BOOLEAN(0, "cache", &probe_conf.cache, "Manipulate probe cache"),
 	OPT_END()
 	};
 	int ret;
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 848e05f..588ff01 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -371,9 +371,8 @@ void disable_buildid_cache(void)
 	no_buildid_cache = true;
 }
 
-static char *build_id_cache__dirname_from_path(const char *name,
-					       bool is_kallsyms, bool is_vdso,
-					       const char *sbuild_id)
+char *build_id_cache__dirname_from_path(const char *sbuild_id, const char *name,
+					bool is_kallsyms, bool is_vdso)
 {
 	char *realname = (char *)name, *filename;
 	bool slash = is_kallsyms || is_vdso;
@@ -402,8 +401,8 @@ int build_id_cache__list_build_ids(const char *pathname,
 	char *dir_name;
 	int ret = 0;
 
-	dir_name = build_id_cache__dirname_from_path(pathname, false, false,
-						     NULL);
+	dir_name = build_id_cache__dirname_from_path(NULL, pathname,
+						     false, false);
 	if (!dir_name)
 		return -ENOMEM;
 
@@ -430,8 +429,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
 			goto out_free;
 	}
 
-	dir_name = build_id_cache__dirname_from_path(name, is_kallsyms,
-						     is_vdso, sbuild_id);
+	dir_name = build_id_cache__dirname_from_path(sbuild_id, name,
+						     is_kallsyms, is_vdso);
 	if (!dir_name)
 		goto out_free;
 
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 64af3e2..1841524 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -28,6 +28,8 @@ 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__dirname_from_path(const char *sbuild_id, const char *name,
+					bool is_kallsyms, bool is_vdso);
 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 85d82f4..dc0265e 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -67,7 +67,6 @@ int e_snprintf(char *str, size_t size, const char *format, ...)
 	return ret;
 }
 
-static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
 static struct machine *host_machine;
 
 /* Initialize symbol maps and path of vmlinux/modules */
@@ -1703,7 +1702,7 @@ char *synthesize_perf_probe_arg(struct perf_probe_arg *pa)
 }
 
 /* Compose only probe point (not argument) */
-static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
+char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 {
 	struct strbuf buf;
 	char *tmp;
@@ -1734,30 +1733,36 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 	return strbuf_detach(&buf, NULL);
 }
 
-#if 0
 char *synthesize_perf_probe_command(struct perf_probe_event *pev)
 {
-	char *buf;
-	int i, len, ret;
+	struct strbuf buf;
+	char *tmp;
+	int i;
 
-	buf = synthesize_perf_probe_point(&pev->point);
-	if (!buf)
-		return NULL;
+	strbuf_init(&buf, 64);
+	if (pev->event)
+		strbuf_addf(&buf, "%s:%s=", pev->group ?: PERFPROBE_GROUP,
+			    pev->event);
+
+	tmp = synthesize_perf_probe_point(&pev->point);
+	if (!tmp)
+		goto out;
+	strbuf_addstr(&buf, tmp);
+	free(tmp);
 
-	len = strlen(buf);
 	for (i = 0; i < pev->nargs; i++) {
-		ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
-				 pev->args[i].name);
-		if (ret <= 0) {
-			free(buf);
-			return NULL;
-		}
-		len += ret;
+		tmp = synthesize_perf_probe_arg(pev->args + i);
+		if (!tmp)
+			goto out;
+		strbuf_addf(&buf, " %s", tmp);
+		free(tmp);
 	}
 
-	return buf;
+	tmp = strbuf_detach(&buf, NULL);
+out:
+	strbuf_release(&buf);
+	return tmp;
 }
-#endif
 
 static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
 					    struct strbuf *buf, int depth)
@@ -2000,6 +2005,79 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
 	memset(pev, 0, sizeof(*pev));
 }
 
+#define strdup_or_goto(str, label)	\
+({ char *__p = NULL; if (str && !(__p = strdup(str))) goto label; __p; })
+
+static int perf_probe_point__copy(struct perf_probe_point *dst,
+				  struct perf_probe_point *src)
+{
+	dst->file = strdup_or_goto(src->file, out_err);
+	dst->function = strdup_or_goto(src->function, out_err);
+	dst->lazy_line = strdup_or_goto(src->lazy_line, out_err);
+	dst->line = src->line;
+	dst->retprobe = src->retprobe;
+	dst->offset = src->offset;
+	return 0;
+
+out_err:
+	clear_perf_probe_point(dst);
+	return -ENOMEM;
+}
+
+static int perf_probe_arg__copy(struct perf_probe_arg *dst,
+				struct perf_probe_arg *src)
+{
+	struct perf_probe_arg_field *field, **ppfield;
+
+	dst->name = strdup_or_goto(src->name, out_err);
+	dst->var = strdup_or_goto(src->var, out_err);
+	dst->type = strdup_or_goto(src->type, out_err);
+
+	field = src->field;
+	ppfield = &(dst->field);
+	while (field) {
+		*ppfield = zalloc(sizeof(*field));
+		if (!*ppfield)
+			goto out_err;
+		(*ppfield)->name = strdup_or_goto(field->name, out_err);
+		(*ppfield)->index = field->index;
+		(*ppfield)->ref = field->ref;
+		field = field->next;
+		ppfield = &((*ppfield)->next);
+	}
+	return 0;
+out_err:
+	return -ENOMEM;
+}
+
+int perf_probe_event__copy(struct perf_probe_event *dst,
+			   struct perf_probe_event *src)
+{
+	int i;
+
+	dst->event = strdup_or_goto(src->event, out_err);
+	dst->group = strdup_or_goto(src->group, out_err);
+	dst->target = strdup_or_goto(src->target, out_err);
+	dst->uprobes = src->uprobes;
+
+	if (perf_probe_point__copy(&dst->point, &src->point) < 0)
+		goto out_err;
+
+	dst->args = zalloc(sizeof(struct perf_probe_arg) * src->nargs);
+	if (!dst->args)
+		goto out_err;
+	dst->nargs = src->nargs;
+
+	for (i = 0; i < src->nargs; i++)
+		if (perf_probe_arg__copy(&dst->args[i], &src->args[i]) < 0)
+			goto out_err;
+	return 0;
+
+out_err:
+	clear_perf_probe_event(dst);
+	return -ENOMEM;
+}
+
 void clear_probe_trace_event(struct probe_trace_event *tev)
 {
 	struct probe_trace_arg_ref *ref, *next;
@@ -2403,6 +2481,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 {
 	int i, fd, ret;
 	struct probe_trace_event *tev = NULL;
+	struct probe_cache *cache = NULL;
 	struct strlist *namelist;
 
 	fd = probe_file__open(PF_FL_RW | (pev->uprobes ? PF_FL_UPROBE : 0));
@@ -2444,6 +2523,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 	}
 	if (ret == -EINVAL && pev->uprobes)
 		warn_uprobe_event_compat(tev);
+	if (ret == 0 && probe_conf.cache) {
+		cache = probe_cache__new(pev->target);
+		if (cache) {
+			probe_cache__add_entry(cache, pev, tevs, ntevs);
+			probe_cache__commit(cache);
+			probe_cache__delete(cache);
+		}
+	}
 
 	strlist__delete(namelist);
 close_out:
@@ -2472,9 +2559,6 @@ static int find_probe_functions(struct map *map, char *name,
 	return found;
 }
 
-#define strdup_or_goto(str, label)	\
-	({ char *__p = strdup(str); if (!__p) goto label; __p; })
-
 void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused,
 				struct probe_trace_event *tev __maybe_unused,
 				struct map *map __maybe_unused) { }
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index e220962..c451223 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -12,6 +12,7 @@ struct probe_conf {
 	bool	show_location_range;
 	bool	force_add;
 	bool	no_inlines;
+	bool	cache;
 	int	max_probes;
 };
 extern struct probe_conf probe_conf;
@@ -121,6 +122,10 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev);
 char *synthesize_perf_probe_command(struct perf_probe_event *pev);
 char *synthesize_probe_trace_command(struct probe_trace_event *tev);
 char *synthesize_perf_probe_arg(struct perf_probe_arg *pa);
+char *synthesize_perf_probe_point(struct perf_probe_point *pp);
+
+int perf_probe_event__copy(struct perf_probe_event *dst,
+			   struct perf_probe_event *src);
 
 /* Check the perf_probe_event needs debuginfo */
 bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 3fe6214..bb849c9 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -14,6 +14,7 @@
  * GNU General Public License for more details.
  *
  */
+#include <sys/uio.h>
 #include "util.h"
 #include "event.h"
 #include "strlist.h"
@@ -324,3 +325,301 @@ int probe_file__del_events(int fd, struct strfilter *filter)
 
 	return ret;
 }
+
+static void probe_cache_entry__delete(struct probe_cache_entry *node)
+{
+	if (!list_empty(&node->list))
+		list_del(&node->list);
+	if (node->tevlist)
+		strlist__delete(node->tevlist);
+	clear_perf_probe_event(&node->pev);
+	free(node->spev);
+	free(node);
+}
+
+static struct probe_cache_entry *
+probe_cache_entry__new(struct perf_probe_event *pev)
+{
+	struct probe_cache_entry *ret = zalloc(sizeof(*ret));
+
+	if (ret) {
+		INIT_LIST_HEAD(&ret->list);
+		ret->tevlist = strlist__new(NULL, NULL);
+		if (!ret->tevlist)
+			zfree(&ret);
+		if (ret && pev) {
+			ret->spev = synthesize_perf_probe_command(pev);
+			if (!ret->spev ||
+			    perf_probe_event__copy(&ret->pev, pev) < 0) {
+				probe_cache_entry__delete(ret);
+				return NULL;
+			}
+		}
+	}
+
+	return ret;
+}
+
+/* For the kernel probe caches, pass target = NULL */
+static int probe_cache__open(struct probe_cache *pcache, const char *target)
+{
+	char cpath[PATH_MAX];
+	char sbuildid[SBUILD_ID_SIZE];
+	char *dir_name;
+	bool is_kallsyms = !target;
+	int ret, fd;
+
+	if (target)
+		ret = filename__sprintf_build_id(target, sbuildid);
+	else {
+		target = "[kernel.kallsyms]";
+		ret = sysfs__sprintf_build_id("/", sbuildid);
+	}
+	if (ret < 0) {
+		pr_debug("Failed to get build-id from %s.\n", target ?: "kernel");
+		return ret;
+	}
+
+	/* If we have no buildid cache, make it */
+	if (!build_id_cache__cached(sbuildid)) {
+		ret = build_id_cache__add_s(sbuildid, target,
+					    is_kallsyms, NULL);
+		if (ret < 0) {
+			pr_debug("Failed to add build-id cache: %s\n", target);
+			return ret;
+		}
+	}
+
+	dir_name = build_id_cache__dirname_from_path(sbuildid, target,
+						     is_kallsyms, false);
+	if (!dir_name)
+		return -ENOMEM;
+
+	snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
+	fd = open(cpath, O_CREAT | O_RDWR | O_APPEND, 0644);
+	if (fd < 0)
+		pr_debug("Failed to open cache(%d): %s\n", fd, cpath);
+	free(dir_name);
+	pcache->fd = fd;
+
+	return fd;
+}
+
+static int probe_cache__load(struct probe_cache *pcache)
+{
+	struct probe_cache_entry *entry = NULL;
+	char buf[MAX_CMDLEN], *p;
+	int ret = 0;
+	FILE *fp;
+
+	fp = fdopen(dup(pcache->fd), "r");
+	while (!feof(fp)) {
+		if (!fgets(buf, MAX_CMDLEN, fp))
+			break;
+		p = strchr(buf, '\n');
+		if (p)
+			*p = '\0';
+		if (buf[0] == '#') {	/* #perf_probe_event */
+			entry = probe_cache_entry__new(NULL);
+			entry->spev = strdup(buf + 1);
+			ret = parse_perf_probe_command(buf + 1, &entry->pev);
+			if (!entry->spev || ret < 0) {
+				probe_cache_entry__delete(entry);
+				goto out;
+			}
+			list_add_tail(&entry->list, &pcache->list);
+		} else {	/* trace_probe_event */
+			if (!entry) {
+				ret = -EINVAL;
+				goto out;
+			}
+			strlist__add(entry->tevlist, buf);
+		}
+	}
+out:
+	fclose(fp);
+	return ret;
+}
+
+static struct probe_cache *probe_cache__alloc(void)
+{
+	struct probe_cache *ret = zalloc(sizeof(*ret));
+
+	if (ret) {
+		INIT_LIST_HEAD(&ret->list);
+		ret->fd = -EINVAL;
+	}
+	return ret;
+}
+
+void probe_cache__delete(struct probe_cache *pcache)
+{
+	struct probe_cache_entry *entry;
+
+	if (!pcache)
+		return;
+
+	while (!list_empty(&pcache->list)) {
+		entry = list_first_entry(&pcache->list, typeof(*entry), list);
+		probe_cache_entry__delete(entry);
+	}
+	if (pcache->fd > 0)
+		close(pcache->fd);
+	free(pcache);
+}
+
+struct probe_cache *probe_cache__new(const char *target)
+{
+	struct probe_cache *pcache = probe_cache__alloc();
+	int ret;
+
+	if (!pcache)
+		return NULL;
+
+	ret = probe_cache__open(pcache, target);
+	if (ret < 0) {
+		pr_debug("Cache open error: %d\n", ret);
+		goto out_err;
+	}
+
+	ret = probe_cache__load(pcache);
+	if (ret < 0) {
+		pr_debug("Cache read error: %d\n", ret);
+		goto out_err;
+	}
+
+	return pcache;
+
+out_err:
+	probe_cache__delete(pcache);
+	return NULL;
+}
+
+static bool streql(const char *a, const char *b)
+{
+	if (a == b)
+		return true;
+
+	if (!a || !b)
+		return false;
+
+	return !strcmp(a, b);
+}
+
+static struct probe_cache_entry *
+probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
+{
+	struct probe_cache_entry *entry = NULL;
+	char *cmd = NULL;
+
+	cmd = synthesize_perf_probe_command(pev);
+	if (!cmd)
+		return NULL;
+
+	list_for_each_entry(entry, &pcache->list, list) {
+		/* Hit if same event name or same command-string */
+		if ((pev->event &&
+		     (streql(entry->pev.group, pev->group) &&
+		      streql(entry->pev.event, pev->event))) ||
+		    (!strcmp(entry->spev, cmd)))
+			goto found;
+	}
+	entry = NULL;
+
+found:
+	free(cmd);
+	return entry;
+}
+
+int probe_cache__add_entry(struct probe_cache *pcache,
+			   struct perf_probe_event *pev,
+			   struct probe_trace_event *tevs, int ntevs)
+{
+	struct probe_cache_entry *entry = NULL;
+	char *command;
+	int i, ret = 0;
+
+	if (!pcache || !pev || !tevs || ntevs <= 0) {
+		ret = -EINVAL;
+		goto out_err;
+	}
+
+	/* Remove old cache entry */
+	entry = probe_cache__find(pcache, pev);
+	if (entry)
+		probe_cache_entry__delete(entry);
+
+	ret = -ENOMEM;
+	entry = probe_cache_entry__new(pev);
+	if (!entry)
+		goto out_err;
+
+	for (i = 0; i < ntevs; i++) {
+		if (!tevs[i].point.symbol)
+			continue;
+
+		command = synthesize_probe_trace_command(&tevs[i]);
+		if (!command)
+			goto out_err;
+		strlist__add(entry->tevlist, command);
+		free(command);
+	}
+	list_add_tail(&entry->list, &pcache->list);
+	pr_debug("Added probe cache: %d\n", ntevs);
+	return 0;
+
+out_err:
+	pr_debug("Failed to add probe caches\n");
+	if (entry)
+		probe_cache_entry__delete(entry);
+	return ret;
+}
+
+static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd)
+{
+	struct str_node *snode;
+	struct iovec iov[3];
+	int ret;
+
+	pr_debug("Writing cache: #%s\n", entry->spev);
+	iov[0].iov_base = (void *)"#"; 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);
+	if (ret < 0)
+		return ret;
+
+	strlist__for_each(snode, entry->tevlist) {
+		iov[0].iov_base = (void *)snode->s;
+		iov[0].iov_len = strlen(snode->s);
+		iov[1].iov_base = (void *)"\n"; iov[1].iov_len = 1;
+		ret = writev(fd, iov, 2);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+int probe_cache__commit(struct probe_cache *pcache)
+{
+	struct probe_cache_entry *entry;
+	int ret = 0;
+
+	/* TBD: if we do not update existing entries, skip it */
+	ret = lseek(pcache->fd, 0, SEEK_SET);
+	if (ret < 0)
+		goto out;
+
+	ret = ftruncate(pcache->fd, 0);
+	if (ret < 0)
+		goto out;
+
+	list_for_each_entry(entry, &pcache->list, list) {
+		ret = probe_cache_entry__write(entry, pcache->fd);
+		pr_debug("Cache committed: %d\n", ret);
+		if (ret < 0)
+			break;
+	}
+out:
+	return ret;
+}
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 18ac9cf..d2b8791d 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -5,6 +5,19 @@
 #include "strfilter.h"
 #include "probe-event.h"
 
+/* Cache of probe definitions */
+struct probe_cache_entry {
+	struct list_head	list;
+	struct perf_probe_event pev;
+	char			*spev;
+	struct strlist		*tevlist;
+};
+
+struct probe_cache {
+	int	fd;
+	struct list_head list;
+};
+
 #define PF_FL_UPROBE	1
 #define PF_FL_RW	2
 
@@ -18,5 +31,11 @@ int probe_file__get_events(int fd, struct strfilter *filter,
 				  struct strlist *plist);
 int probe_file__del_strlist(int fd, struct strlist *namelist);
 
+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__commit(struct probe_cache *pcache);
+void probe_cache__delete(struct probe_cache *pcache);
 
 #endif

[toc] | [prev] | [next] | [standalone]


#1389768 — Re: [PATCH perf/core v5 04/15] perf probe: Add --cache option to cache the probe definitions

FromNamhyung Kim <namhyung@kernel.org>
Date2016-04-28 04:20 +0200
SubjectRe: [PATCH perf/core v5 04/15] perf probe: Add --cache option to cache the probe definitions
Message-ID<rsJIB-3C4-1@gated-at.bofh.it>
In reply to#1389474
On Thu, Apr 28, 2016 at 03:37:42AM +0900, Masami Hiramatsu wrote:
> From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> 
> Add --cache option to cache the probe definitions. This
> just saves the result of the dwarf analysis to probe cache.
> 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> ---
>  Changes in v5:
>   - Move probe_cache* definitions. (code cleanup)
> 
>  Changes in v4:
>   - Remove cache saving failure message.
> ---

[snip]
> +static int probe_cache__load(struct probe_cache *pcache)
> +{
> +	struct probe_cache_entry *entry = NULL;
> +	char buf[MAX_CMDLEN], *p;
> +	int ret = 0;
> +	FILE *fp;
> +
> +	fp = fdopen(dup(pcache->fd), "r");
> +	while (!feof(fp)) {
> +		if (!fgets(buf, MAX_CMDLEN, fp))
> +			break;
> +		p = strchr(buf, '\n');
> +		if (p)
> +			*p = '\0';
> +		if (buf[0] == '#') {	/* #perf_probe_event */
> +			entry = probe_cache_entry__new(NULL);

The probe_cache_entry__new() can fail.

Thanks,
Namhyung


> +			entry->spev = strdup(buf + 1);
> +			ret = parse_perf_probe_command(buf + 1, &entry->pev);
> +			if (!entry->spev || ret < 0) {
> +				probe_cache_entry__delete(entry);
> +				goto out;
> +			}
> +			list_add_tail(&entry->list, &pcache->list);
> +		} else {	/* trace_probe_event */
> +			if (!entry) {
> +				ret = -EINVAL;
> +				goto out;
> +			}
> +			strlist__add(entry->tevlist, buf);
> +		}
> +	}
> +out:
> +	fclose(fp);
> +	return ret;
> +}

[toc] | [prev] | [next] | [standalone]


#1390614 — Re: [PATCH perf/core v5 04/15] perf probe: Add --cache option to cache the probe definitions

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-29 01:20 +0200
SubjectRe: [PATCH perf/core v5 04/15] perf probe: Add --cache option to cache the probe definitions
Message-ID<rt3nX-3WT-1@gated-at.bofh.it>
In reply to#1389768
On Thu, 28 Apr 2016 11:12:19 +0900
Namhyung Kim <namhyung@kernel.org> wrote:

> On Thu, Apr 28, 2016 at 03:37:42AM +0900, Masami Hiramatsu wrote:
> > From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > 
> > Add --cache option to cache the probe definitions. This
> > just saves the result of the dwarf analysis to probe cache.
> > 
> > Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> > ---
> >  Changes in v5:
> >   - Move probe_cache* definitions. (code cleanup)
> > 
> >  Changes in v4:
> >   - Remove cache saving failure message.
> > ---
> 
> [snip]
> > +static int probe_cache__load(struct probe_cache *pcache)
> > +{
> > +	struct probe_cache_entry *entry = NULL;
> > +	char buf[MAX_CMDLEN], *p;
> > +	int ret = 0;
> > +	FILE *fp;
> > +
> > +	fp = fdopen(dup(pcache->fd), "r");
> > +	while (!feof(fp)) {
> > +		if (!fgets(buf, MAX_CMDLEN, fp))
> > +			break;
> > +		p = strchr(buf, '\n');
> > +		if (p)
> > +			*p = '\0';
> > +		if (buf[0] == '#') {	/* #perf_probe_event */
> > +			entry = probe_cache_entry__new(NULL);
> 
> The probe_cache_entry__new() can fail.

Good catch!

> 
> Thanks,
> Namhyung
> 
> 
> > +			entry->spev = strdup(buf + 1);

Moreover, if this strdup fail, this goes to return but retvalue is 0...

I'll fix this too.

Thank you!

-- 
Masami Hiramatsu <mhiramat@kernel.org>

[toc] | [prev] | [next] | [standalone]


#1389773 — Re: [PATCH perf/core v5 04/15] perf probe: Add --cache option to cache the probe definitions

FromNamhyung Kim <namhyung@kernel.org>
Date2016-04-28 04:40 +0200
SubjectRe: [PATCH perf/core v5 04/15] perf probe: Add --cache option to cache the probe definitions
Message-ID<rsK1X-3Ld-5@gated-at.bofh.it>
In reply to#1389474
On Thu, Apr 28, 2016 at 03:37:42AM +0900, Masami Hiramatsu wrote:
> From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> 
> Add --cache option to cache the probe definitions. This
> just saves the result of the dwarf analysis to probe cache.
> 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> ---
>  Changes in v5:
>   - Move probe_cache* definitions. (code cleanup)
> 
>  Changes in v4:
>   - Remove cache saving failure message.
> ---

[SNIP]
> +/* For the kernel probe caches, pass target = NULL */
> +static int probe_cache__open(struct probe_cache *pcache, const char *target)
> +{
> +	char cpath[PATH_MAX];
> +	char sbuildid[SBUILD_ID_SIZE];
> +	char *dir_name;
> +	bool is_kallsyms = !target;
> +	int ret, fd;
> +
> +	if (target)
> +		ret = filename__sprintf_build_id(target, sbuildid);
> +	else {
> +		target = "[kernel.kallsyms]";
> +		ret = sysfs__sprintf_build_id("/", sbuildid);
> +	}
> +	if (ret < 0) {
> +		pr_debug("Failed to get build-id from %s.\n", target ?: "kernel");
> +		return ret;
> +	}
> +
> +	/* If we have no buildid cache, make it */
> +	if (!build_id_cache__cached(sbuildid)) {
> +		ret = build_id_cache__add_s(sbuildid, target,
> +					    is_kallsyms, NULL);
> +		if (ret < 0) {
> +			pr_debug("Failed to add build-id cache: %s\n", target);
> +			return ret;
> +		}
> +	}
> +
> +	dir_name = build_id_cache__dirname_from_path(sbuildid, target,
> +						     is_kallsyms, false);
> +	if (!dir_name)
> +		return -ENOMEM;
> +
> +	snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
> +	fd = open(cpath, O_CREAT | O_RDWR | O_APPEND, 0644);
> +	if (fd < 0)
> +		pr_debug("Failed to open cache(%d): %s\n", fd, cpath);
> +	free(dir_name);
> +	pcache->fd = fd;
> +
> +	return fd;
> +}

[SNIP]
> +
> +int probe_cache__commit(struct probe_cache *pcache)
> +{
> +	struct probe_cache_entry *entry;
> +	int ret = 0;
> +
> +	/* TBD: if we do not update existing entries, skip it */
> +	ret = lseek(pcache->fd, 0, SEEK_SET);
> +	if (ret < 0)
> +		goto out;
> +
> +	ret = ftruncate(pcache->fd, 0);
> +	if (ret < 0)
> +		goto out;

What is this doing?  Does it truncate old contents on write?  Opening
with O_APPEND looks strange to me..

Thanks,
Namhyung


> +
> +	list_for_each_entry(entry, &pcache->list, list) {
> +		ret = probe_cache_entry__write(entry, pcache->fd);
> +		pr_debug("Cache committed: %d\n", ret);
> +		if (ret < 0)
> +			break;
> +	}
> +out:
> +	return ret;
> +}
> diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
> index 18ac9cf..d2b8791d 100644
> --- a/tools/perf/util/probe-file.h
> +++ b/tools/perf/util/probe-file.h
> @@ -5,6 +5,19 @@
>  #include "strfilter.h"
>  #include "probe-event.h"
>  
> +/* Cache of probe definitions */
> +struct probe_cache_entry {
> +	struct list_head	list;
> +	struct perf_probe_event pev;
> +	char			*spev;
> +	struct strlist		*tevlist;
> +};
> +
> +struct probe_cache {
> +	int	fd;
> +	struct list_head list;
> +};
> +
>  #define PF_FL_UPROBE	1
>  #define PF_FL_RW	2
>  
> @@ -18,5 +31,11 @@ int probe_file__get_events(int fd, struct strfilter *filter,
>  				  struct strlist *plist);
>  int probe_file__del_strlist(int fd, struct strlist *namelist);
>  
> +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__commit(struct probe_cache *pcache);
> +void probe_cache__delete(struct probe_cache *pcache);
>  
>  #endif
> 

[toc] | [prev] | [next] | [standalone]


#1390611 — Re: [PATCH perf/core v5 04/15] perf probe: Add --cache option to cache the probe definitions

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-29 01:10 +0200
SubjectRe: [PATCH perf/core v5 04/15] perf probe: Add --cache option to cache the probe definitions
Message-ID<rt3eh-3Ta-11@gated-at.bofh.it>
In reply to#1389773
On Thu, 28 Apr 2016 11:32:18 +0900
Namhyung Kim <namhyung@kernel.org> wrote:

> On Thu, Apr 28, 2016 at 03:37:42AM +0900, Masami Hiramatsu wrote:
> > From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > 
> > Add --cache option to cache the probe definitions. This
> > just saves the result of the dwarf analysis to probe cache.
> > 
> > Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> > ---
> >  Changes in v5:
> >   - Move probe_cache* definitions. (code cleanup)
> > 
> >  Changes in v4:
> >   - Remove cache saving failure message.
> > ---
> 
> [SNIP]
> > +/* For the kernel probe caches, pass target = NULL */
> > +static int probe_cache__open(struct probe_cache *pcache, const char *target)
> > +{
> > +	char cpath[PATH_MAX];
> > +	char sbuildid[SBUILD_ID_SIZE];
> > +	char *dir_name;
> > +	bool is_kallsyms = !target;
> > +	int ret, fd;
> > +
> > +	if (target)
> > +		ret = filename__sprintf_build_id(target, sbuildid);
> > +	else {
> > +		target = "[kernel.kallsyms]";
> > +		ret = sysfs__sprintf_build_id("/", sbuildid);
> > +	}
> > +	if (ret < 0) {
> > +		pr_debug("Failed to get build-id from %s.\n", target ?: "kernel");
> > +		return ret;
> > +	}
> > +
> > +	/* If we have no buildid cache, make it */
> > +	if (!build_id_cache__cached(sbuildid)) {
> > +		ret = build_id_cache__add_s(sbuildid, target,
> > +					    is_kallsyms, NULL);
> > +		if (ret < 0) {
> > +			pr_debug("Failed to add build-id cache: %s\n", target);
> > +			return ret;
> > +		}
> > +	}
> > +
> > +	dir_name = build_id_cache__dirname_from_path(sbuildid, target,
> > +						     is_kallsyms, false);
> > +	if (!dir_name)
> > +		return -ENOMEM;
> > +
> > +	snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
> > +	fd = open(cpath, O_CREAT | O_RDWR | O_APPEND, 0644);
> > +	if (fd < 0)
> > +		pr_debug("Failed to open cache(%d): %s\n", fd, cpath);
> > +	free(dir_name);
> > +	pcache->fd = fd;
> > +
> > +	return fd;
> > +}
> 
> [SNIP]
> > +
> > +int probe_cache__commit(struct probe_cache *pcache)
> > +{
> > +	struct probe_cache_entry *entry;
> > +	int ret = 0;
> > +
> > +	/* TBD: if we do not update existing entries, skip it */
> > +	ret = lseek(pcache->fd, 0, SEEK_SET);
> > +	if (ret < 0)
> > +		goto out;
> > +
> > +	ret = ftruncate(pcache->fd, 0);
> > +	if (ret < 0)
> > +		goto out;
> 
> What is this doing?  Does it truncate old contents on write?  Opening
> with O_APPEND looks strange to me..

Ah, right. I forget the reason why :(, but I guess it maybe because just
changing the design while coding.
I'll remove O_APPEND flag then.

Thank you!

-- 
Masami Hiramatsu <mhiramat@kernel.org>

[toc] | [prev] | [next] | [standalone]


#1389475 — [PATCH perf/core v5 14/15] perf probe: Allow wildcard for cached events

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-27 20:40 +0200
Subject[PATCH perf/core v5 14/15] perf probe: Allow wildcard for cached events
Message-ID<rsCxu-5Ye-61@gated-at.bofh.it>
In reply to#1389465
Allo glob wildcard for reusing cached/SDT events. This also
automatically find the target binaries, e.g.

  # perf probe -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>
---
 tools/perf/util/probe-event.c |  153 ++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/probe-event.h |    1 
 tools/perf/util/probe-file.c  |   33 ++++++++-
 tools/perf/util/probe-file.h  |    5 +
 4 files changed, 183 insertions(+), 9 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 1a9ea2b..9ca8392 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -236,7 +236,7 @@ static void clear_perf_probe_point(struct perf_probe_point *pp)
 	free(pp->lazy_line);
 }
 
-static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
+void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
 {
 	int i;
 
@@ -1206,7 +1206,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)
@@ -1214,7 +1214,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);
@@ -1640,6 +1640,11 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev)
 	p = strchr(argv[1], ':');
 	if (p) {
 		tp->module = strndup(argv[1], p - argv[1]);
+		if (!tp->module) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		tev->uprobes = (tp->module[0] == '/');
 		p++;
 	} else
 		p = argv[1];
@@ -2485,7 +2490,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;
@@ -2498,7 +2503,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;
@@ -2860,6 +2865,137 @@ 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 */
+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);
+	if (!cache)
+		return -ENOENT;
+
+	for_each_probe_cache_entry(entry, cache) {
+		/* Skip the cache entry which has no name */
+		if (!entry->pev.event || !entry->pev.group)
+			continue;
+		if (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 (target[0] == '/')
+			pev->uprobes = true;
+	}
+
+	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 */
+	ret = build_id_cache__list_all(&bidlist, true);
+	if (ret < 0) {
+		pr_debug("Failed to get buildids: %d\n", ret);
+		return ret;
+	}
+
+	ret = 0;
+	strlist__for_each(nd, bidlist) {
+		pathname = build_id_cache__origname(nd->s);
+		ret = find_cached_events(pev, &tmp_tevs, pathname);
+		if (ret > 0)
+			ret = concat_probe_trace_events(tevs, &ntevs,
+							&tmp_tevs, ret);
+		/* In the case of cnt == 0, we just skip it */
+		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)
 {
@@ -2869,6 +3005,13 @@ 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 */
+		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;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 2a23efe..39b5a35 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -134,6 +134,7 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
 /* Release event contents */
 void clear_perf_probe_event(struct perf_probe_event *pev);
 void clear_probe_trace_event(struct probe_trace_event *tev);
+void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs);
 
 /* Command string to line-range */
 int parse_line_range_desc(const char *cmd, struct line_range *lr);
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 2437b48..896d645 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -360,6 +360,31 @@ probe_cache_entry__new(struct perf_probe_event *pev)
 	return ret;
 }
 
+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(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 */
 static int probe_cache__open(struct probe_cache *pcache, const char *target)
 {
@@ -528,7 +553,7 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
 	if (!cmd)
 		return NULL;
 
-	list_for_each_entry(entry, &pcache->list, list) {
+	for_each_probe_cache_entry(entry, pcache) {
 		if (pev->sdt) {
 			if (entry->pev.event &&
 			    streql(entry->pev.event, pev->event) &&
@@ -558,7 +583,7 @@ probe_cache__find_by_name(struct probe_cache *pcache,
 {
 	struct probe_cache_entry *entry = NULL;
 
-	list_for_each_entry(entry, &pcache->list, list) {
+	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))
@@ -711,7 +736,7 @@ int probe_cache__commit(struct probe_cache *pcache)
 	if (ret < 0)
 		goto out;
 
-	list_for_each_entry(entry, &pcache->list, list) {
+	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)
@@ -750,7 +775,7 @@ static int probe_cache__show_entries(struct probe_cache *pcache,
 {
 	struct probe_cache_entry *entry;
 
-	list_for_each_entry(entry, &pcache->list, list) {
+	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 ce98162..0faf083 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->list, list)
 
 /* probe-file.c depends on libelf */
 #ifdef HAVE_LIBELF_SUPPORT
@@ -34,6 +36,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,

[toc] | [prev] | [next] | [standalone]


#1389483 — Re: [PATCH perf/core v5 14/15] perf probe: Allow wildcard for cached events

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-27 20:50 +0200
SubjectRe: [PATCH perf/core v5 14/15] perf probe: Allow wildcard for cached events
Message-ID<rsCH9-61V-23@gated-at.bofh.it>
In reply to#1389475
Oops, I missed to fix the SEGV bug. 
I'll fix it and resend as 5.1.

Thanks,

On Thu, 28 Apr 2016 03:39:17 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> Allo glob wildcard for reusing cached/SDT events. This also
> automatically find the target binaries, e.g.
> 
>   # perf probe -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>
> ---
>  tools/perf/util/probe-event.c |  153 ++++++++++++++++++++++++++++++++++++++++-
>  tools/perf/util/probe-event.h |    1 
>  tools/perf/util/probe-file.c  |   33 ++++++++-
>  tools/perf/util/probe-file.h  |    5 +
>  4 files changed, 183 insertions(+), 9 deletions(-)
> 
> diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> index 1a9ea2b..9ca8392 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -236,7 +236,7 @@ static void clear_perf_probe_point(struct perf_probe_point *pp)
>  	free(pp->lazy_line);
>  }
>  
> -static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
> +void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
>  {
>  	int i;
>  
> @@ -1206,7 +1206,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)
> @@ -1214,7 +1214,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);
> @@ -1640,6 +1640,11 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev)
>  	p = strchr(argv[1], ':');
>  	if (p) {
>  		tp->module = strndup(argv[1], p - argv[1]);
> +		if (!tp->module) {
> +			ret = -ENOMEM;
> +			goto out;
> +		}
> +		tev->uprobes = (tp->module[0] == '/');
>  		p++;
>  	} else
>  		p = argv[1];
> @@ -2485,7 +2490,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;
> @@ -2498,7 +2503,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;
> @@ -2860,6 +2865,137 @@ 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 */
> +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);
> +	if (!cache)
> +		return -ENOENT;
> +
> +	for_each_probe_cache_entry(entry, cache) {
> +		/* Skip the cache entry which has no name */
> +		if (!entry->pev.event || !entry->pev.group)
> +			continue;
> +		if (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 (target[0] == '/')
> +			pev->uprobes = true;
> +	}
> +
> +	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 */
> +	ret = build_id_cache__list_all(&bidlist, true);
> +	if (ret < 0) {
> +		pr_debug("Failed to get buildids: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = 0;
> +	strlist__for_each(nd, bidlist) {
> +		pathname = build_id_cache__origname(nd->s);
> +		ret = find_cached_events(pev, &tmp_tevs, pathname);
> +		if (ret > 0)
> +			ret = concat_probe_trace_events(tevs, &ntevs,
> +							&tmp_tevs, ret);
> +		/* In the case of cnt == 0, we just skip it */
> +		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)
>  {
> @@ -2869,6 +3005,13 @@ 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 */
> +		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;
> diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
> index 2a23efe..39b5a35 100644
> --- a/tools/perf/util/probe-event.h
> +++ b/tools/perf/util/probe-event.h
> @@ -134,6 +134,7 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
>  /* Release event contents */
>  void clear_perf_probe_event(struct perf_probe_event *pev);
>  void clear_probe_trace_event(struct probe_trace_event *tev);
> +void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs);
>  
>  /* Command string to line-range */
>  int parse_line_range_desc(const char *cmd, struct line_range *lr);
> diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
> index 2437b48..896d645 100644
> --- a/tools/perf/util/probe-file.c
> +++ b/tools/perf/util/probe-file.c
> @@ -360,6 +360,31 @@ probe_cache_entry__new(struct perf_probe_event *pev)
>  	return ret;
>  }
>  
> +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(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 */
>  static int probe_cache__open(struct probe_cache *pcache, const char *target)
>  {
> @@ -528,7 +553,7 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
>  	if (!cmd)
>  		return NULL;
>  
> -	list_for_each_entry(entry, &pcache->list, list) {
> +	for_each_probe_cache_entry(entry, pcache) {
>  		if (pev->sdt) {
>  			if (entry->pev.event &&
>  			    streql(entry->pev.event, pev->event) &&
> @@ -558,7 +583,7 @@ probe_cache__find_by_name(struct probe_cache *pcache,
>  {
>  	struct probe_cache_entry *entry = NULL;
>  
> -	list_for_each_entry(entry, &pcache->list, list) {
> +	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))
> @@ -711,7 +736,7 @@ int probe_cache__commit(struct probe_cache *pcache)
>  	if (ret < 0)
>  		goto out;
>  
> -	list_for_each_entry(entry, &pcache->list, list) {
> +	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)
> @@ -750,7 +775,7 @@ static int probe_cache__show_entries(struct probe_cache *pcache,
>  {
>  	struct probe_cache_entry *entry;
>  
> -	list_for_each_entry(entry, &pcache->list, list) {
> +	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 ce98162..0faf083 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->list, list)
>  
>  /* probe-file.c depends on libelf */
>  #ifdef HAVE_LIBELF_SUPPORT
> @@ -34,6 +36,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,
> 


-- 
Masami Hiramatsu <mhiramat@kernel.org>

[toc] | [prev] | [next] | [standalone]


#1389511 — [PATCH perf/core v5.1 14/15] perf probe: Allow wildcard for cached events

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-04-27 21:20 +0200
Subject[PATCH perf/core v5.1 14/15] perf probe: Allow wildcard for cached events
Message-ID<rsDa9-6Ba-7@gated-at.bofh.it>
In reply to#1389483
Allo glob wildcard for reusing cached/SDT events. This also
automatically find the target binaries, e.g.

  # perf probe -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 v5.1:
  - Fix a SEGV bug when a group name is omitted. (Thanks Hemant!)
---
 tools/perf/util/probe-event.c |  153 ++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/probe-event.h |    1 
 tools/perf/util/probe-file.c  |   33 ++++++++-
 tools/perf/util/probe-file.h  |    5 +
 4 files changed, 183 insertions(+), 9 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 1a9ea2b..11752d2 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -236,7 +236,7 @@ static void clear_perf_probe_point(struct perf_probe_point *pp)
 	free(pp->lazy_line);
 }
 
-static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
+void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
 {
 	int i;
 
@@ -1206,7 +1206,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)
@@ -1214,7 +1214,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);
@@ -1640,6 +1640,11 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev)
 	p = strchr(argv[1], ':');
 	if (p) {
 		tp->module = strndup(argv[1], p - argv[1]);
+		if (!tp->module) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		tev->uprobes = (tp->module[0] == '/');
 		p++;
 	} else
 		p = argv[1];
@@ -2485,7 +2490,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;
@@ -2498,7 +2503,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;
@@ -2860,6 +2865,137 @@ 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 */
+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);
+	if (!cache)
+		return -ENOENT;
+
+	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 (target[0] == '/')
+			pev->uprobes = true;
+	}
+
+	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 */
+	ret = build_id_cache__list_all(&bidlist, true);
+	if (ret < 0) {
+		pr_debug("Failed to get buildids: %d\n", ret);
+		return ret;
+	}
+
+	ret = 0;
+	strlist__for_each(nd, bidlist) {
+		pathname = build_id_cache__origname(nd->s);
+		ret = find_cached_events(pev, &tmp_tevs, pathname);
+		if (ret > 0)
+			ret = concat_probe_trace_events(tevs, &ntevs,
+							&tmp_tevs, ret);
+		/* In the case of cnt == 0, we just skip it */
+		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)
 {
@@ -2869,6 +3005,13 @@ 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 */
+		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;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 2a23efe..39b5a35 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -134,6 +134,7 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
 /* Release event contents */
 void clear_perf_probe_event(struct perf_probe_event *pev);
 void clear_probe_trace_event(struct probe_trace_event *tev);
+void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs);
 
 /* Command string to line-range */
 int parse_line_range_desc(const char *cmd, struct line_range *lr);
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 2437b48..896d645 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -360,6 +360,31 @@ probe_cache_entry__new(struct perf_probe_event *pev)
 	return ret;
 }
 
+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(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 */
 static int probe_cache__open(struct probe_cache *pcache, const char *target)
 {
@@ -528,7 +553,7 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
 	if (!cmd)
 		return NULL;
 
-	list_for_each_entry(entry, &pcache->list, list) {
+	for_each_probe_cache_entry(entry, pcache) {
 		if (pev->sdt) {
 			if (entry->pev.event &&
 			    streql(entry->pev.event, pev->event) &&
@@ -558,7 +583,7 @@ probe_cache__find_by_name(struct probe_cache *pcache,
 {
 	struct probe_cache_entry *entry = NULL;
 
-	list_for_each_entry(entry, &pcache->list, list) {
+	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))
@@ -711,7 +736,7 @@ int probe_cache__commit(struct probe_cache *pcache)
 	if (ret < 0)
 		goto out;
 
-	list_for_each_entry(entry, &pcache->list, list) {
+	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)
@@ -750,7 +775,7 @@ static int probe_cache__show_entries(struct probe_cache *pcache,
 {
 	struct probe_cache_entry *entry;
 
-	list_for_each_entry(entry, &pcache->list, list) {
+	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 ce98162..0faf083 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->list, list)
 
 /* probe-file.c depends on libelf */
 #ifdef HAVE_LIBELF_SUPPORT
@@ -34,6 +36,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,

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | linux.kernel


csiph-web