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


Groups > linux.kernel > #1399123 > unrolled thread

[PATCH perf/core v7 00/21] perf-probe --cache and SDT support

Started byMasami Hiramatsu <mhiramat@kernel.org>
First post2016-05-11 16:00 +0200
Last post2016-05-11 17:50 +0200
Articles 20 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH perf/core v7 00/21] perf-probe --cache and SDT support Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-11 16:00 +0200
    [PATCH perf/core v7 18/21] perf-list: Skip SDTs placed in invalid binaries Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-11 16:00 +0200
    [PATCH perf/core v7 07/21] perf symbol: Cleanup the code flow of dso__find_kallsyms Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-11 16:00 +0200
      Re: [PATCH perf/core v7 07/21] perf symbol: Cleanup the code flow of  dso__find_kallsyms Arnaldo Carvalho de Melo <acme@kernel.org> - 2016-05-11 18:00 +0200
        Re: [PATCH perf/core v7 07/21] perf symbol: Cleanup the code flow  of dso__find_kallsyms Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-12 03:50 +0200
    [PATCH perf/core v7 17/21] perf-list: Show SDT and pre-cached events Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-11 16:00 +0200
    [PATCH perf/core v7 16/21] perf probe: Accept %sdt and %cached event name Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-11 16:00 +0200
    [PATCH perf/core v7 10/21] perf probe: Use cache entry if possible Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-11 16:00 +0200
    [PATCH perf/core v7 15/21] perf buildid-cache: Scan and import user SDT events to probe cache Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-11 16:00 +0200
    [PATCH perf/core v7 01/21] tools/perf: Fix lsdir to set errno correctly Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-11 16:00 +0200
      [tip:perf/core] perf tools: Fix lsdir to set errno correctly tip-bot for Masami Hiramatsu <tipbot@zytor.com> - 2016-05-12 12:30 +0200
    [PATCH perf/core v7 20/21] perf probe: Support @BUILDID or @FILE suffix for SDT events Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-11 16:00 +0200
    [PATCH perf/core v7 19/21] perf probe: Allow wildcard for cached events Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-11 16:00 +0200
    [PATCH perf/core v7 02/21] perf buildid: Fix to set correct dso name for kallsyms Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-11 16:00 +0200
      Re: [PATCH perf/core v7 02/21] perf buildid: Fix to set correct dso  name for kallsyms Arnaldo Carvalho de Melo <acme@kernel.org> - 2016-05-11 17:50 +0200
        Re: [PATCH perf/core v7 02/21] perf buildid: Fix to set correct dso  name for kallsyms Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-12 04:10 +0200
          Re: [PATCH perf/core v7 02/21] perf buildid: Fix to set correct dso  name for kallsyms Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-12 11:00 +0200
    [PATCH perf/core v7 09/21] perf probe: Add --cache option to cache the probe definitions Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-11 16:00 +0200
    [PATCH perf/core v7 03/21] perf buildid: Introduce DSO__NAME_KALLSYMS and DSO__NAME_KCORE Masami Hiramatsu <mhiramat@kernel.org> - 2016-05-11 16:10 +0200
      Re: [PATCH perf/core v7 03/21] perf buildid: Introduce  DSO__NAME_KALLSYMS and DSO__NAME_KCORE Arnaldo Carvalho de Melo <acme@kernel.org> - 2016-05-11 17:50 +0200

#1399123 — [PATCH perf/core v7 00/21] perf-probe --cache and SDT support

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-11 16:00 +0200
Subject[PATCH perf/core v7 00/21] perf-probe --cache and SDT support
Message-ID<rxCQa-UH-17@gated-at.bofh.it>
Hi,

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

The previous version is here; https://lkml.org/lkml/2116/4/29/358

This version add some bugfixes and cleanup patches. Also, tested
by using runtests (https://github.com/mhiramat/runtests) which found
several bugs in previous version.
(I've added test.d/buildid-cache/*.tc, test.d/probe/cache*.tc and
 test.d/probe/sdt.tc for this series)

Changes in v7:
 - [1/21]-[5/21], [7/21] Newly added for bugfix and cleanup.
 - [6/21] Remove unneeded local strlist.
 - [8/21] Move kallsyms buildid related code into build-id.c
    (as build_id_cache__kallsyms_path).
 - [11/21] Remove the top '/' from binary name if it is not a regular file.
 - [16/21] Fix a bug to return an error if no SDT/cached events found in cache.
 - [18/21] Validate build-id via sysfs if it is for kallsyms,
 - [19/21] Continue to search caches if a build-id cache has no probe cache.
 - [19/21] Make probe_cache__open() to accept DSO__NAME_KALLSYMS for kernel.
 - [19/21] Fix to add probes correctly when a wildcard matchs both of
    uprobes and kprobes.
 - [21/21] as Brendan suggested, special support for "sdt_" prefix
      (treat it as same as "%sdt_" )


Thank you,

---

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

Masami Hiramatsu (20):
      tools/perf: Fix lsdir to set errno correctly
      perf buildid: Fix to set correct dso name for kallsyms
      perf buildid: Introduce DSO__NAME_KALLSYMS and DSO__NAME_KCORE
      perf: Use SBUILD_ID_SIZE macro instead of BUILD_ID_SIZE macro
      perf symbol: Use lsdir for search in kcore cache directory
      perf-buildid-cache: Use lsdir for looking up buildid caches
      perf symbol: Cleanup the code flow of dso__find_kallsyms
      perf-buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
      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
      perf probe: Support a special SDT probe format


 tools/perf/Documentation/perf-probe.txt            |   26 +
 tools/perf/builtin-buildid-cache.c                 |    8 
 tools/perf/builtin-list.c                          |    4 
 tools/perf/builtin-probe.c                         |   30 +
 tools/perf/util/annotate.c                         |    4 
 tools/perf/util/build-id.c                         |  334 +++++++++++--
 tools/perf/util/build-id.h                         |    8 
 tools/perf/util/dso.c                              |    4 
 tools/perf/util/dso.h                              |    5 
 tools/perf/util/header.c                           |    2 
 tools/perf/util/machine.c                          |    2 
 tools/perf/util/map.c                              |    2 
 tools/perf/util/parse-events.c                     |   83 +++
 tools/perf/util/parse-events.h                     |    2 
 tools/perf/util/probe-event.c                      |  492 +++++++++++++++++---
 tools/perf/util/probe-event.h                      |    7 
 tools/perf/util/probe-file.c                       |  502 ++++++++++++++++++++
 tools/perf/util/probe-file.h                       |   41 ++
 .../util/scripting-engines/trace-event-python.c    |    2 
 tools/perf/util/symbol-elf.c                       |  252 ++++++++++
 tools/perf/util/symbol.c                           |   93 ++--
 tools/perf/util/symbol.h                           |   25 +
 tools/perf/util/util.c                             |    2 
 23 files changed, 1743 insertions(+), 187 deletions(-)

--
Masami Hiramatsu

[toc] | [next] | [standalone]


#1399125 — [PATCH perf/core v7 18/21] perf-list: Skip SDTs placed in invalid binaries

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-11 16:00 +0200
Subject[PATCH perf/core v7 18/21] perf-list: Skip SDTs placed in invalid binaries
Message-ID<rxCQc-UH-63@gated-at.bofh.it>
In reply to#1399123
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 v7:
  - Validate build-id via sysfs if it is for kallsyms,
 Changes in v4:
  - Rename a parameter 'valid' to 'validonly' :)
---
 tools/perf/builtin-probe.c     |    2 +-
 tools/perf/util/build-id.c     |   33 ++++++++++++++++++++++++++++++++-
 tools/perf/util/build-id.h     |    2 +-
 tools/perf/util/parse-events.c |    2 +-
 tools/perf/util/probe-file.c   |    2 +-
 5 files changed, 36 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 6063bee..ce02668 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -209,6 +209,31 @@ out:
 	return ret;
 }
 
+/* Check if the given build_id cache is valid on current running system */
+static bool build_id_cache__valid_id(char *sbuild_id)
+{
+	char real_sbuild_id[SBUILD_ID_SIZE] = "";
+	char *pathname;
+	int ret = 0;
+	bool result = false;
+
+	pathname = build_id_cache__origname(sbuild_id);
+	if (!pathname)
+		return false;
+
+	if (!strcmp(pathname, DSO__NAME_KALLSYMS))
+		ret = sysfs__sprintf_build_id("/", real_sbuild_id);
+	else if (pathname[0] == '/')
+		ret = filename__sprintf_build_id(pathname, real_sbuild_id);
+	else
+		ret = -EINVAL;	/* Should we support other special DSO cache? */
+	if (ret >= 0)
+		result = (strcmp(sbuild_id, real_sbuild_id) == 0);
+	free(pathname);
+
+	return result;
+}
+
 static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
 {
 	return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
@@ -420,7 +445,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;
@@ -428,6 +453,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;
@@ -457,6 +486,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 c05503e..480600b 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -34,7 +34,7 @@ char *build_id_cache__origname(const char *sbuild_id);
 char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
 char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
 			       bool is_kallsyms, bool is_vdso);
-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 bc82a55..c4104c4 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -779,7 +779,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]


#1399126 — [PATCH perf/core v7 07/21] perf symbol: Cleanup the code flow of dso__find_kallsyms

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-11 16:00 +0200
Subject[PATCH perf/core v7 07/21] perf symbol: Cleanup the code flow of dso__find_kallsyms
Message-ID<rxCQc-UH-67@gated-at.bofh.it>
In reply to#1399123
Cleanup the code flow of dso__find_kallsyms() to remove
redundant checking code and add some comment for readability.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 tools/perf/util/symbol.c |   60 +++++++++++++++++++++-------------------------
 1 file changed, 27 insertions(+), 33 deletions(-)

diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index e112bbd..b2b06b7 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1629,6 +1629,15 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
 	return ret;
 }
 
+static bool filename__readable(const char *file)
+{
+	int fd = open(file, O_RDONLY);
+	if (fd < 0)
+		return false;
+	close(fd);
+	return true;
+}
+
 static char *dso__find_kallsyms(struct dso *dso, struct map *map)
 {
 	u8 host_build_id[BUILD_ID_SIZE];
@@ -1648,45 +1657,33 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
 				 sizeof(host_build_id)) == 0)
 		is_host = dso__build_id_equal(dso, host_build_id);
 
-	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
-
-	scnprintf(path, sizeof(path), "%s/%s/%s", buildid_dir,
-		  DSO__NAME_KCORE, sbuild_id);
-
-	/* Use /proc/kallsyms if possible */
+	/* Try a fast path for /proc/kallsyms if possible */
 	if (is_host) {
-		DIR *d;
-		int fd;
-
-		/* If no cached kcore go with /proc/kallsyms */
-		d = opendir(path);
-		if (!d)
-			goto proc_kallsyms;
-		closedir(d);
-
 		/*
-		 * Do not check the build-id cache, until we know we cannot use
-		 * /proc/kcore.
+		 * Do not check the build-id cache, unless we know we cannot use
+		 * /proc/kcore or module maps don't match to /proc/kallsyms.
 		 */
-		fd = open("/proc/kcore", O_RDONLY);
-		if (fd != -1) {
-			close(fd);
-			/* If module maps match go with /proc/kallsyms */
-			if (!validate_kcore_addresses("/proc/kallsyms", map))
-				goto proc_kallsyms;
-		}
-
-		/* Find kallsyms in build-id cache with kcore */
-		if (!find_matching_kcore(map, path, sizeof(path)))
-			return strdup(path);
-
-		goto proc_kallsyms;
+		if (filename__readable("/proc/kcore") &&
+		    !validate_kcore_addresses("/proc/kallsyms", map))
+			goto proc_kallsyms;
 	}
 
+	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
+
 	/* Find kallsyms in build-id cache with kcore */
+	scnprintf(path, sizeof(path), "%s/%s/%s",
+		  buildid_dir, DSO__NAME_KCORE, sbuild_id);
+
 	if (!find_matching_kcore(map, path, sizeof(path)))
 		return strdup(path);
 
+	/* Use current /proc/kallsyms if possible */
+	if (is_host) {
+proc_kallsyms:
+		return strdup("/proc/kallsyms");
+	}
+
+	/* Finally, find a cache of kallsyms */
 	scnprintf(path, sizeof(path), "%s/%s/%s",
 		  buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
 
@@ -1697,9 +1694,6 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
 	}
 
 	return strdup(path);
-
-proc_kallsyms:
-	return strdup("/proc/kallsyms");
 }
 
 static int dso__load_kernel_sym(struct dso *dso, struct map *map,

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


#1399288 — Re: [PATCH perf/core v7 07/21] perf symbol: Cleanup the code flow of dso__find_kallsyms

FromArnaldo Carvalho de Melo <acme@kernel.org>
Date2016-05-11 18:00 +0200
SubjectRe: [PATCH perf/core v7 07/21] perf symbol: Cleanup the code flow of dso__find_kallsyms
Message-ID<rxEIh-2LV-1@gated-at.bofh.it>
In reply to#1399126
Em Wed, May 11, 2016 at 10:52:27PM +0900, Masami Hiramatsu escreveu:
> Cleanup the code flow of dso__find_kallsyms() to remove
> redundant checking code and add some comment for readability.
> 
> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> ---
>  tools/perf/util/symbol.c |   60 +++++++++++++++++++++-------------------------
>  1 file changed, 27 insertions(+), 33 deletions(-)
> 
> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> index e112bbd..b2b06b7 100644
> --- a/tools/perf/util/symbol.c
> +++ b/tools/perf/util/symbol.c
> @@ -1629,6 +1629,15 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
>  	return ret;
>  }
>  
> +static bool filename__readable(const char *file)
> +{
> +	int fd = open(file, O_RDONLY);
> +	if (fd < 0)
> +		return false;
> +	close(fd);
> +	return true;
> +}

Do we really have to use this big hammer just for checking if a file is
readable? What is wronte with:

	access(pathname, R_OK)

?

I see, you're keeping the existing logic, but since you've gone to the
trouble of introducing a seemingly generic function like
filename__readable(), you could as well use the canonical way to check
if a file is readable, namely access(R_OK), no?

Adrian, is there something magical about /proc/kcore for this test to be
done that way? If so, we better document not to waste our time next time
we look at this...

- Arnaldo

> +
>  static char *dso__find_kallsyms(struct dso *dso, struct map *map)
>  {
>  	u8 host_build_id[BUILD_ID_SIZE];
> @@ -1648,45 +1657,33 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
>  				 sizeof(host_build_id)) == 0)
>  		is_host = dso__build_id_equal(dso, host_build_id);
>  
> -	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
> -
> -	scnprintf(path, sizeof(path), "%s/%s/%s", buildid_dir,
> -		  DSO__NAME_KCORE, sbuild_id);
> -
> -	/* Use /proc/kallsyms if possible */
> +	/* Try a fast path for /proc/kallsyms if possible */

How that improves the previous comment?

>  	if (is_host) {
> -		DIR *d;
> -		int fd;
> -
> -		/* If no cached kcore go with /proc/kallsyms */
> -		d = opendir(path);
> -		if (!d)
> -			goto proc_kallsyms;
> -		closedir(d);
> -
>  		/*
> -		 * Do not check the build-id cache, until we know we cannot use
> -		 * /proc/kcore.
> +		 * Do not check the build-id cache, unless we know we cannot use
> +		 * /proc/kcore or module maps don't match to /proc/kallsyms.
>  		 */
> -		fd = open("/proc/kcore", O_RDONLY);
> -		if (fd != -1) {
> -			close(fd);
> -			/* If module maps match go with /proc/kallsyms */
> -			if (!validate_kcore_addresses("/proc/kallsyms", map))
> -				goto proc_kallsyms;
> -		}
> -
> -		/* Find kallsyms in build-id cache with kcore */
> -		if (!find_matching_kcore(map, path, sizeof(path)))
> -			return strdup(path);
> -
> -		goto proc_kallsyms;
> +		if (filename__readable("/proc/kcore") &&
> +		    !validate_kcore_addresses("/proc/kallsyms", map))
> +			goto proc_kallsyms;
>  	}
>  
> +	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
> +
>  	/* Find kallsyms in build-id cache with kcore */
> +	scnprintf(path, sizeof(path), "%s/%s/%s",
> +		  buildid_dir, DSO__NAME_KCORE, sbuild_id);
> +
>  	if (!find_matching_kcore(map, path, sizeof(path)))
>  		return strdup(path);
>  
> +	/* Use current /proc/kallsyms if possible */
> +	if (is_host) {
> +proc_kallsyms:
> +		return strdup("/proc/kallsyms");
> +	}
> +
> +	/* Finally, find a cache of kallsyms */
>  	scnprintf(path, sizeof(path), "%s/%s/%s",
>  		  buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
>  
> @@ -1697,9 +1694,6 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
>  	}
>  
>  	return strdup(path);
> -
> -proc_kallsyms:
> -	return strdup("/proc/kallsyms");
>  }
>  
>  static int dso__load_kernel_sym(struct dso *dso, struct map *map,

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


#1399635 — Re: [PATCH perf/core v7 07/21] perf symbol: Cleanup the code flow of dso__find_kallsyms

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-12 03:50 +0200
SubjectRe: [PATCH perf/core v7 07/21] perf symbol: Cleanup the code flow of dso__find_kallsyms
Message-ID<rxNVg-3vp-11@gated-at.bofh.it>
In reply to#1399288
On Wed, 11 May 2016 12:55:50 -0300
Arnaldo Carvalho de Melo <acme@kernel.org> wrote:

> Em Wed, May 11, 2016 at 10:52:27PM +0900, Masami Hiramatsu escreveu:
> > Cleanup the code flow of dso__find_kallsyms() to remove
> > redundant checking code and add some comment for readability.
> > 
> > Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> > ---
> >  tools/perf/util/symbol.c |   60 +++++++++++++++++++++-------------------------
> >  1 file changed, 27 insertions(+), 33 deletions(-)
> > 
> > diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> > index e112bbd..b2b06b7 100644
> > --- a/tools/perf/util/symbol.c
> > +++ b/tools/perf/util/symbol.c
> > @@ -1629,6 +1629,15 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
> >  	return ret;
> >  }
> >  
> > +static bool filename__readable(const char *file)
> > +{
> > +	int fd = open(file, O_RDONLY);
> > +	if (fd < 0)
> > +		return false;
> > +	close(fd);
> > +	return true;
> > +}
> 
> Do we really have to use this big hammer just for checking if a file is
> readable? What is wronte with:
> 
> 	access(pathname, R_OK)
> 
> ?

Yes, I actually had done that at prototyping. But as the manpage of access
said, access() checks accessibility by real uid/gid, but open() checks
by effective uid/gid. So, I considered this could cause unexpected
issue if we decided to use setuid(). I just wanted to check it was OK.

> I see, you're keeping the existing logic, but since you've gone to the
> trouble of introducing a seemingly generic function like
> filename__readable(), you could as well use the canonical way to check
> if a file is readable, namely access(R_OK), no?

I agreed in general :) If we don't can use access(R_OK) I'd like to use it.

> 
> Adrian, is there something magical about /proc/kcore for this test to be
> done that way? If so, we better document not to waste our time next time
> we look at this...

Ah, right. At least I had to write a comment about it.

Thank you,

> 
> - Arnaldo
> 
> > +
> >  static char *dso__find_kallsyms(struct dso *dso, struct map *map)
> >  {
> >  	u8 host_build_id[BUILD_ID_SIZE];
> > @@ -1648,45 +1657,33 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
> >  				 sizeof(host_build_id)) == 0)
> >  		is_host = dso__build_id_equal(dso, host_build_id);
> >  
> > -	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
> > -
> > -	scnprintf(path, sizeof(path), "%s/%s/%s", buildid_dir,
> > -		  DSO__NAME_KCORE, sbuild_id);
> > -
> > -	/* Use /proc/kallsyms if possible */
> > +	/* Try a fast path for /proc/kallsyms if possible */
> 
> How that improves the previous comment?
> 
> >  	if (is_host) {
> > -		DIR *d;
> > -		int fd;
> > -
> > -		/* If no cached kcore go with /proc/kallsyms */
> > -		d = opendir(path);
> > -		if (!d)
> > -			goto proc_kallsyms;
> > -		closedir(d);
> > -
> >  		/*
> > -		 * Do not check the build-id cache, until we know we cannot use
> > -		 * /proc/kcore.
> > +		 * Do not check the build-id cache, unless we know we cannot use
> > +		 * /proc/kcore or module maps don't match to /proc/kallsyms.
> >  		 */
> > -		fd = open("/proc/kcore", O_RDONLY);
> > -		if (fd != -1) {
> > -			close(fd);
> > -			/* If module maps match go with /proc/kallsyms */
> > -			if (!validate_kcore_addresses("/proc/kallsyms", map))
> > -				goto proc_kallsyms;
> > -		}
> > -
> > -		/* Find kallsyms in build-id cache with kcore */
> > -		if (!find_matching_kcore(map, path, sizeof(path)))
> > -			return strdup(path);
> > -
> > -		goto proc_kallsyms;
> > +		if (filename__readable("/proc/kcore") &&
> > +		    !validate_kcore_addresses("/proc/kallsyms", map))
> > +			goto proc_kallsyms;
> >  	}
> >  
> > +	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
> > +
> >  	/* Find kallsyms in build-id cache with kcore */
> > +	scnprintf(path, sizeof(path), "%s/%s/%s",
> > +		  buildid_dir, DSO__NAME_KCORE, sbuild_id);
> > +
> >  	if (!find_matching_kcore(map, path, sizeof(path)))
> >  		return strdup(path);
> >  
> > +	/* Use current /proc/kallsyms if possible */
> > +	if (is_host) {
> > +proc_kallsyms:
> > +		return strdup("/proc/kallsyms");
> > +	}
> > +
> > +	/* Finally, find a cache of kallsyms */
> >  	scnprintf(path, sizeof(path), "%s/%s/%s",
> >  		  buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
> >  
> > @@ -1697,9 +1694,6 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
> >  	}
> >  
> >  	return strdup(path);
> > -
> > -proc_kallsyms:
> > -	return strdup("/proc/kallsyms");
> >  }
> >  
> >  static int dso__load_kernel_sym(struct dso *dso, struct map *map,


-- 
Masami Hiramatsu <mhiramat@kernel.org>

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


#1399127 — [PATCH perf/core v7 17/21] perf-list: Show SDT and pre-cached events

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-11 16:00 +0200
Subject[PATCH perf/core v7 17/21] perf-list: Show SDT and pre-cached events
Message-ID<rxCQc-UH-71@gated-at.bofh.it>
In reply to#1399123
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

Show SDT and pre-cached events by perf-list with "sdt". This also
shows the binary and build-id where the events are placed only
when there are same name events on different binaries.
e.g.
  ----
  # perf list sdt

  List of pre-defined events (to be used in -e):

    sdt_libc:lll_futex_wake                            [SDT event]
    sdt_libc:lll_lock_wait_private                     [SDT event]
    sdt_libc:longjmp                                   [SDT event]
    sdt_libc:longjmp_target                            [SDT event]
  ...
    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)
  ----

The binary path and build-id are shown in below format;

  <GROUP>:<EVENT>@<PATH>(<BUILD-ID>)

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v5:
  - Fix a build error for minimal option.

 Changes in v4:
  - Update patch description.
  - Change event list format.
---
 tools/perf/builtin-list.c      |    4 ++
 tools/perf/util/parse-events.c |   83 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/parse-events.h |    2 +
 tools/perf/util/probe-file.h   |    9 ++++
 4 files changed, 98 insertions(+)

diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 5e22db4..3cba865 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -62,6 +62,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
 			print_hwcache_events(NULL, raw_dump);
 		else if (strcmp(argv[i], "pmu") == 0)
 			print_pmu_events(NULL, raw_dump);
+		else if (strcmp(argv[i], "sdt") == 0)
+			print_sdt_events(NULL, NULL, raw_dump);
 		else if ((sep = strchr(argv[i], ':')) != NULL) {
 			int sep_idx;
 
@@ -76,6 +78,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
 
 			s[sep_idx] = '\0';
 			print_tracepoint_events(s, s + sep_idx + 1, raw_dump);
+			print_sdt_events(s, s + sep_idx + 1, raw_dump);
 			free(s);
 		} else {
 			if (asprintf(&s, "*%s*", argv[i]) < 0) {
@@ -89,6 +92,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
 			print_hwcache_events(s, raw_dump);
 			print_pmu_events(s, raw_dump);
 			print_tracepoint_events(NULL, s, raw_dump);
+			print_sdt_events(NULL, s, raw_dump);
 			free(s);
 		}
 	}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index bcbc983..f9c8b7b 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -20,6 +20,7 @@
 #include "pmu.h"
 #include "thread_map.h"
 #include "cpumap.h"
+#include "probe-file.h"
 #include "asm/bug.h"
 
 #define MAX_NAME_LEN 100
@@ -1976,6 +1977,86 @@ static bool is_event_supported(u8 type, unsigned config)
 	return ret;
 }
 
+void print_sdt_events(const char *subsys_glob, const char *event_glob,
+		      bool name_only)
+{
+	struct probe_cache *pcache;
+	struct probe_cache_entry *ent;
+	struct strlist *bidlist, *sdtlist;
+	struct strlist_config cfg = {.dont_dupstr = true};
+	struct str_node *nd, *nd2;
+	char *buf, *path, *ptr = NULL;
+	bool show_detail = false;
+	int ret;
+
+	sdtlist = strlist__new(NULL, &cfg);
+	if (!sdtlist) {
+		pr_debug("Failed to allocate new strlist for SDT\n");
+		return;
+	}
+	ret = build_id_cache__list_all(&bidlist);
+	if (ret < 0) {
+		pr_debug("Failed to get buildids: %d\n", ret);
+		return;
+	}
+	strlist__for_each(nd, bidlist) {
+		pcache = probe_cache__new(nd->s);
+		if (!pcache)
+			continue;
+		if (!list_empty(&pcache->list))
+			list_for_each_entry(ent, &pcache->list, list) {
+				if (!ent->sdt)
+					continue;
+				if (subsys_glob &&
+				    !strglobmatch(ent->pev.group, subsys_glob))
+					continue;
+				if (event_glob &&
+				    !strglobmatch(ent->pev.event, event_glob))
+					continue;
+				ret = asprintf(&buf, "%s:%s@%s", ent->pev.group,
+						ent->pev.event, nd->s);
+				if (ret > 0)
+					strlist__add(sdtlist, buf);
+			}
+		probe_cache__delete(pcache);
+	}
+	strlist__delete(bidlist);
+
+	strlist__for_each(nd, sdtlist) {
+		buf = strchr(nd->s, '@');
+		if (buf)
+			*(buf++) = '\0';
+		if (name_only) {
+			printf("%s ", nd->s);
+			continue;
+		}
+		nd2 = strlist__next(nd);
+		if (nd2) {
+			ptr = strchr(nd2->s, '@');
+			if (ptr)
+				*ptr = '\0';
+			if (strcmp(nd->s, nd2->s) == 0)
+				show_detail = true;
+		}
+		if (show_detail) {
+			path = build_id_cache__origname(buf);
+			ret = asprintf(&buf, "%s@%s(%.12s)", nd->s, path, buf);
+			if (ret > 0) {
+				printf("  %-50s [%s]\n", buf, "SDT event");
+				free(buf);
+			}
+		} else
+			printf("  %-50s [%s]\n", nd->s, "SDT event");
+		if (nd2) {
+			if (strcmp(nd->s, nd2->s) != 0)
+				show_detail = false;
+			if (ptr)
+				*ptr = '@';
+		}
+	}
+	strlist__delete(sdtlist);
+}
+
 int print_hwcache_events(const char *event_glob, bool name_only)
 {
 	unsigned int type, op, i, evt_i = 0, evt_num = 0;
@@ -2158,6 +2239,8 @@ void print_events(const char *event_glob, bool name_only)
 	}
 
 	print_tracepoint_events(NULL, NULL, name_only);
+
+	print_sdt_events(NULL, NULL, name_only);
 }
 
 int parse_events__is_hardcoded_term(struct parse_events_term *term)
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index d740c3c..c08daa9 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -182,6 +182,8 @@ void print_symbol_events(const char *event_glob, unsigned type,
 void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
 			     bool name_only);
 int print_hwcache_events(const char *event_glob, bool name_only);
+void print_sdt_events(const char *subsys_glob, const char *event_glob,
+		      bool name_only);
 int is_valid_tracepoint(const char *event_string);
 
 int valid_event_mount(const char *eventfs);
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 93aa193..ce98162 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -22,6 +22,8 @@ struct probe_cache {
 #define PF_FL_UPROBE	1
 #define PF_FL_RW	2
 
+/* probe-file.c depends on libelf */
+#ifdef HAVE_LIBELF_SUPPORT
 int probe_file__open(int flag);
 int probe_file__open_both(int *kfd, int *ufd, int flag);
 struct strlist *probe_file__get_namelist(int fd);
@@ -46,4 +48,11 @@ struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
 struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
 					const char *group, const char *event);
 int probe_cache__show_all_caches(struct strfilter *filter);
+#else	/* ! HAVE_LIBELF_SUPPORT */
+static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused)
+{
+	return NULL;
+}
+#define probe_cache__delete(pcache) do {} while(0)
+#endif
 #endif

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


#1399128 — [PATCH perf/core v7 16/21] perf probe: Accept %sdt and %cached event name

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-11 16:00 +0200
Subject[PATCH perf/core v7 16/21] perf probe: Accept %sdt and %cached event name
Message-ID<rxCQe-UH-77@gated-at.bofh.it>
In reply to#1399123
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

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

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

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

          perf record -e sdt_libc:lll_lock_wait_private -aR sleep 1

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

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

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

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

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

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


#1399129 — [PATCH perf/core v7 10/21] perf probe: Use cache entry if possible

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-11 16:00 +0200
Subject[PATCH perf/core v7 10/21] perf probe: Use cache entry if possible
Message-ID<rxCQd-UH-73@gated-at.bofh.it>
In reply to#1399123
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

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

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v6:
  - Remove fallback lookup routine by using function name
    as cached event name, because it should be done by following
    patch which supports %cached-event.
---
 tools/perf/util/probe-event.c |   65 ++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/probe-file.c  |   20 ++++++++++++-
 tools/perf/util/probe-file.h  |    5 +++
 3 files changed, 86 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 854885b..acc8341 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2472,17 +2472,24 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,
 	char buf[64];
 	int ret;
 
+	/* If probe_event or trace_event already have the name, reuse it */
 	if (pev->event)
 		event = pev->event;
-	else
+	else if (tev->event)
+		event = tev->event;
+	else {
+		/* Or generate new one from probe point */
 		if (pev->point.function &&
 			(strncmp(pev->point.function, "0x", 2) != 0) &&
 			!strisglob(pev->point.function))
 			event = pev->point.function;
 		else
 			event = tev->point.realname;
+	}
 	if (pev->group)
 		group = pev->group;
+	else if (tev->group)
+		group = tev->group;
 	else
 		group = PERFPROBE_GROUP;
 
@@ -2529,7 +2536,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 	for (i = 0; i < ntevs; i++) {
 		tev = &tevs[i];
 		/* Skip if the symbol is out of .text or blacklisted */
-		if (!tev->point.symbol)
+		if (!tev->point.symbol && !pev->uprobes)
 			continue;
 
 		/* Set new name for tev (and update namelist) */
@@ -2842,6 +2849,55 @@ errout:
 
 bool __weak arch__prefers_symtab(void) { return false; }
 
+static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
+					      struct probe_trace_event **tevs)
+{
+	struct probe_cache *cache;
+	struct probe_cache_entry *entry;
+	struct probe_trace_event *tev;
+	struct str_node *node;
+	int ret, i;
+
+	cache = probe_cache__new(pev->target);
+	if (!cache)
+		return 0;
+
+	entry = probe_cache__find(cache, pev);
+	if (!entry) {
+		ret = 0;
+		goto out;
+	}
+
+	ret = strlist__nr_entries(entry->tevlist);
+	if (ret > probe_conf.max_probes) {
+		pr_debug("Too many entries matched in the cache of %s\n",
+			 pev->target ? : "kernel");
+		ret = -E2BIG;
+		goto out;
+	}
+
+	*tevs = zalloc(ret * sizeof(*tev));
+	if (!*tevs) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	i = 0;
+	strlist__for_each(node, entry->tevlist) {
+		tev = &(*tevs)[i++];
+		ret = parse_probe_trace_command(node->s, tev);
+		if (ret < 0)
+			goto out;
+		/* Set the uprobes attribute as same as original */
+		tev->uprobes = pev->uprobes;
+	}
+	ret = i;
+
+out:
+	probe_cache__delete(cache);
+	return ret;
+}
+
 static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 					 struct probe_trace_event **tevs)
 {
@@ -2864,6 +2920,11 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 	if (ret > 0)
 		return ret;
 
+	/* At first, we need to lookup cache entry */
+	ret = find_probe_trace_events_from_cache(pev, tevs);
+	if (ret > 0)
+		return ret;	/* Found in probe cache */
+
 	if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) {
 		ret = find_probe_trace_events_from_map(pev, tevs);
 		if (ret > 0)
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 689d874..f30f609 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -514,7 +514,7 @@ static bool streql(const char *a, const char *b)
 	return !strcmp(a, b);
 }
 
-static struct probe_cache_entry *
+struct probe_cache_entry *
 probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
 {
 	struct probe_cache_entry *entry = NULL;
@@ -539,6 +539,24 @@ found:
 	return entry;
 }
 
+struct probe_cache_entry *
+probe_cache__find_by_name(struct probe_cache *pcache,
+			  const char *group, const char *event)
+{
+	struct probe_cache_entry *entry = NULL;
+
+	list_for_each_entry(entry, &pcache->list, list) {
+		/* Hit if same event name or same command-string */
+		if (streql(entry->pev.group, group) &&
+		    streql(entry->pev.event, event))
+			goto found;
+	}
+	entry = NULL;
+
+found:
+	return entry;
+}
+
 int probe_cache__add_entry(struct probe_cache *pcache,
 			   struct perf_probe_event *pev,
 			   struct probe_trace_event *tevs, int ntevs)
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index d2b8791d..1385c8b 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -37,5 +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);
-
+struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
+					    struct perf_probe_event *pev);
+struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
+					const char *group, const char *event);
 #endif

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


#1399130 — [PATCH perf/core v7 15/21] perf buildid-cache: Scan and import user SDT events to probe cache

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-11 16:00 +0200
Subject[PATCH perf/core v7 15/21] perf buildid-cache: Scan and import user SDT events to probe cache
Message-ID<rxCQe-UH-75@gated-at.bofh.it>
In reply to#1399123
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

perf buildid-cache --add <binary> scans given binary and add
the SDT events to probe cache. "sdt_" prefix is appended for
all SDT providers to avoid event-name clash with other pre-defined
events. It is possible to use the cached SDT events as other cached
events, via perf probe --add "sdt_<provider>:<event>=<event>".

e.g.
  ----
  # perf buildid-cache --add /lib/libc-2.17.so
  # perf probe --cache --list | head -n 5
  /usr/lib/libc-2.17.so (a6fb821bdf53660eb2c29f778757aef294d3d392):
  sdt_libc:setjmp=setjmp
  sdt_libc:longjmp=longjmp
  sdt_libc:longjmp_target=longjmp_target
  sdt_libc:memory_heap_new=memory_heap_new
  # perf probe -x /usr/lib/libc-2.17.so \
    -a sdt_libc:memory_heap_new=memory_heap_new
  Added new event:
    sdt_libc:memory_heap_new (on memory_heap_new
   in /usr/lib/libc-2.17.so)

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

          perf record -e sdt_libc:memory_heap_new -aR sleep 1

  # perf probe -l
    sdt_libc:memory_heap_new (on new_heap+183 in /usr/lib/libc-2.17.so)
  ----

Note that SDT event entries in probe-cache file is somewhat different
from normal cached events. Normal one starts with "#", but SDTs are
starting with "%".

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v4:
  - Fix a bug to copy correct group name to entries.
  - Fix to consolidate same-name entries.
---
 tools/perf/util/build-id.c   |   27 +++++++++++++++--
 tools/perf/util/probe-file.c |   67 ++++++++++++++++++++++++++++++++++++++++--
 tools/perf/util/probe-file.h |    2 +
 3 files changed, 90 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index be84c17..6063bee 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -17,6 +17,7 @@
 #include "tool.h"
 #include "header.h"
 #include "vdso.h"
+#include "probe-file.h"
 
 
 static bool no_buildid_cache;
@@ -516,6 +517,23 @@ int build_id_cache__list_build_ids(const char *pathname,
 	return ret;
 }
 
+#ifdef HAVE_LIBELF_SUPPORT
+static void build_id_cache__add_sdt_cache(const char *sbuild_id,
+					  const char *realname)
+{
+	struct probe_cache *cache;
+
+	cache = probe_cache__new(sbuild_id);
+	if (!cache)
+		return;
+	if (probe_cache__scan_sdt(cache, realname) >= 0)
+		probe_cache__commit(cache);
+	probe_cache__delete(cache);
+}
+#else
+#define build_id_cache__add_sdt_cache(sbuild_id, realname) do { } while (0)
+#endif
+
 int build_id_cache__add_s(const char *sbuild_id, const char *name,
 			  bool is_kallsyms, bool is_vdso)
 {
@@ -559,20 +577,23 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
 			goto out_free;
 	}
 
+	/* Make a symbolic link */
 	if (!build_id_cache__linkname(sbuild_id, linkname, size))
 		goto out_free;
+
 	tmp = strrchr(linkname, '/');
 	*tmp = '\0';
-
 	if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
 		goto out_free;
-
 	*tmp = '/';
 	tmp = dir_name + strlen(buildid_dir) - 5;
 	memcpy(tmp, "../..", 5);
-
 	if (symlink(tmp, linkname) == 0)
 		err = 0;
+
+	/* Update SDT cache */
+	build_id_cache__add_sdt_cache(sbuild_id, realname);
+
 out_free:
 	if (!is_kallsyms)
 		free(realname);
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index cc0f183..da241ed 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -429,12 +429,15 @@ static int probe_cache__load(struct probe_cache *pcache)
 		p = strchr(buf, '\n');
 		if (p)
 			*p = '\0';
-		if (buf[0] == '#') {	/* #perf_probe_event */
+		/* #perf_probe_event or %sdt_event */
+		if (buf[0] == '#' || buf[0] == '%') {
 			entry = probe_cache_entry__new(NULL);
 			if (!entry) {
 				ret = -ENOMEM;
 				goto out;
 			}
+			if (buf[0] == '%')
+				entry->sdt = true;
 			entry->spev = strdup(buf + 1);
 			if (entry->spev)
 				ret = parse_perf_probe_command(buf + 1,
@@ -611,14 +614,72 @@ out_err:
 	return ret;
 }
 
+static unsigned long long sdt_note__get_addr(struct sdt_note *note)
+{
+	return note->bit32 ? (unsigned long long)note->addr.a32[0]
+		 : (unsigned long long)note->addr.a64[0];
+}
+
+int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
+{
+	struct probe_cache_entry *entry = NULL;
+	struct list_head sdtlist;
+	struct sdt_note *note;
+	char *buf;
+	char sdtgrp[64];
+	int ret;
+
+	INIT_LIST_HEAD(&sdtlist);
+	ret = get_sdt_note_list(&sdtlist, pathname);
+	if (ret < 0) {
+		pr_debug("Failed to get sdt note: %d\n", ret);
+		return ret;
+	}
+	list_for_each_entry(note, &sdtlist, note_list) {
+		ret = snprintf(sdtgrp, 64, "sdt_%s", note->provider);
+		if (ret < 0)
+			break;
+		/* Try to find same-name entry */
+		entry = probe_cache__find_by_name(pcache, sdtgrp, note->name);
+		if (!entry) {
+			entry = probe_cache_entry__new(NULL);
+			if (!entry) {
+				ret = -ENOMEM;
+				break;
+			}
+			entry->sdt = true;
+			ret = asprintf(&entry->spev, "%s:%s=%s", sdtgrp,
+					note->name, note->name);
+			if (ret < 0)
+				break;
+			entry->pev.event = strdup(note->name);
+			entry->pev.group = strdup(sdtgrp);
+			list_add_tail(&entry->list, &pcache->list);
+		}
+		ret = asprintf(&buf, "p:%s/%s %s:0x%llx",
+				sdtgrp, note->name, pathname,
+				sdt_note__get_addr(note));
+		if (ret < 0)
+			break;
+		strlist__add(entry->tevlist, buf);
+		free(buf);
+		entry = NULL;
+	}
+	if (entry)
+		probe_cache_entry__delete(entry);
+	cleanup_sdt_note_list(&sdtlist);
+	return ret;
+}
+
 static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd)
 {
 	struct str_node *snode;
 	struct iovec iov[3];
+	const char *prefix = entry->sdt ? "%" : "#";
 	int ret;
 
-	pr_debug("Writing cache: #%s\n", entry->spev);
-	iov[0].iov_base = (void *)"#"; iov[0].iov_len = 1;
+	pr_debug("Writing cache: %s%s\n", prefix, entry->spev);
+	iov[0].iov_base = (void *)prefix; iov[0].iov_len = 1;
 	iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev);
 	iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1;
 	ret = writev(fd, iov, 3);
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index e6fd9b9..93aa193 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -8,6 +8,7 @@
 /* Cache of probe definitions */
 struct probe_cache_entry {
 	struct list_head	list;
+	bool			sdt;
 	struct perf_probe_event pev;
 	char			*spev;
 	struct strlist		*tevlist;
@@ -35,6 +36,7 @@ struct probe_cache *probe_cache__new(const char *target);
 int probe_cache__add_entry(struct probe_cache *pcache,
 			   struct perf_probe_event *pev,
 			   struct probe_trace_event *tevs, int ntevs);
+int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname);
 int probe_cache__commit(struct probe_cache *pcache);
 void probe_cache__delete(struct probe_cache *pcache);
 int probe_cache__remove_entries(struct probe_cache *pcache,

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


#1399132 — [PATCH perf/core v7 01/21] tools/perf: Fix lsdir to set errno correctly

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-11 16:00 +0200
Subject[PATCH perf/core v7 01/21] tools/perf: Fix lsdir to set errno correctly
Message-ID<rxCQa-UH-27@gated-at.bofh.it>
In reply to#1399123
Fix lsdir() to set correct positive error number (ENOMEM).
Since "errno" must have a positive error number instead of
negative number, fix lsdir to set it correctly.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 tools/perf/util/util.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 01c9433..eab077a 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -139,7 +139,7 @@ struct strlist *lsdir(const char *name,
 
 	list = strlist__new(NULL, NULL);
 	if (!list) {
-		errno = -ENOMEM;
+		errno = ENOMEM;
 		goto out;
 	}
 

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


#1399874 — [tip:perf/core] perf tools: Fix lsdir to set errno correctly

Fromtip-bot for Masami Hiramatsu <tipbot@zytor.com>
Date2016-05-12 12:30 +0200
Subject[tip:perf/core] perf tools: Fix lsdir to set errno correctly
Message-ID<rxW2w-3Gh-43@gated-at.bofh.it>
In reply to#1399132
Commit-ID:  357a54f32a065835d3e6a08b07a91a57e52f32c7
Gitweb:     http://git.kernel.org/tip/357a54f32a065835d3e6a08b07a91a57e52f32c7
Author:     Masami Hiramatsu <mhiramat@kernel.org>
AuthorDate: Wed, 11 May 2016 22:51:27 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Wed, 11 May 2016 13:06:05 -0300

perf tools: Fix lsdir to set errno correctly

Fix lsdir() to set correct positive error number (ENOMEM).  Since
"errno" must have a positive error number instead of negative number,
fix lsdir to set it correctly.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Fixes: e1ce726e1db2 ("perf tools: Add lsdir() helper to read a directory")
Link: http://lkml.kernel.org/r/20160511135127.23943.40644.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/util.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 01c9433..eab077a 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -139,7 +139,7 @@ struct strlist *lsdir(const char *name,
 
 	list = strlist__new(NULL, NULL);
 	if (!list) {
-		errno = -ENOMEM;
+		errno = ENOMEM;
 		goto out;
 	}
 

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


#1399135 — [PATCH perf/core v7 20/21] perf probe: Support @BUILDID or @FILE suffix for SDT events

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-11 16:00 +0200
Subject[PATCH perf/core v7 20/21] perf probe: Support @BUILDID or @FILE suffix for SDT events
Message-ID<rxCQe-UH-81@gated-at.bofh.it>
In reply to#1399123
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 |   16 ++++++++++++++--
 3 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index ce02668..eac4c0b 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -504,6 +504,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__cachedir(const char *sbuild_id, const char *name,
 			       bool is_kallsyms, bool is_vdso)
 {
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 480600b..9bd6d0b 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -35,6 +35,7 @@ char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
 char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
 			       bool is_kallsyms, bool is_vdso);
 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 0019a22..bd31cac 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1253,8 +1253,20 @@ 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;
+			*ptr = '\0';
 		}
 		ret = parse_perf_probe_event_name(&arg, pev);
 		if (ret == 0) {

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


#1399136 — [PATCH perf/core v7 19/21] perf probe: Allow wildcard for cached events

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-11 16:00 +0200
Subject[PATCH perf/core v7 19/21] perf probe: Allow wildcard for cached events
Message-ID<rxCQf-UH-93@gated-at.bofh.it>
In reply to#1399123
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 v7:
  - Continue to search caches if a build-id cache has no probe cache.
  - Make probe_cache__open() to accept DSO__NAME_KALLSYMS for kernel.
  - Fix to add probes correctly when a wildcard matchs both of
    uprobes and kprobes.
 Changes in v5.1:
  - Fix a SEGV bug when a group name is omitted. (Thanks Hemant!)
---
 tools/perf/util/probe-event.c |  211 +++++++++++++++++++++++++++++++++++++----
 tools/perf/util/probe-event.h |    1 
 tools/perf/util/probe-file.c  |   46 +++++++--
 tools/perf/util/probe-file.h  |    5 +
 4 files changed, 232 insertions(+), 31 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 5ec98b2..0019a22 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];
@@ -2514,7 +2519,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;
@@ -2527,7 +2532,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;
@@ -2552,41 +2557,60 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,
 	return 0;
 }
 
-static int __add_probe_trace_events(struct perf_probe_event *pev,
-				     struct probe_trace_event *tevs,
-				     int ntevs, bool allow_suffix)
+static int __open_probe_file_and_namelist(bool uprobe,
+					  struct strlist **namelist)
 {
-	int i, fd, ret;
-	struct probe_trace_event *tev = NULL;
-	struct probe_cache *cache = NULL;
-	struct strlist *namelist;
+	int fd;
 
-	fd = probe_file__open(PF_FL_RW | (pev->uprobes ? PF_FL_UPROBE : 0));
+	fd = probe_file__open(PF_FL_RW | (uprobe ? PF_FL_UPROBE : 0));
 	if (fd < 0)
 		return fd;
 
 	/* Get current event names */
-	namelist = probe_file__get_namelist(fd);
-	if (!namelist) {
+	*namelist = probe_file__get_namelist(fd);
+	if (!(*namelist)) {
 		pr_debug("Failed to get current event list.\n");
-		ret = -ENOMEM;
-		goto close_out;
+		close(fd);
+		return -ENOMEM;
 	}
+	return fd;
+}
+
+static int __add_probe_trace_events(struct perf_probe_event *pev,
+				     struct probe_trace_event *tevs,
+				     int ntevs, bool allow_suffix)
+{
+	int i, fd[2] = {-1, -1}, up, ret;
+	struct probe_trace_event *tev = NULL;
+	struct probe_cache *cache = NULL;
+	struct strlist *namelist[2] = {NULL, NULL};
+
+	up = pev->uprobes ? 1 : 0;
+	fd[up] = __open_probe_file_and_namelist(up, &namelist[up]);
+	if (fd[up] < 0)
+		return fd[up];
 
 	ret = 0;
 	for (i = 0; i < ntevs; i++) {
 		tev = &tevs[i];
+		up = tev->uprobes ? 1 : 0;
+		if (fd[up] == -1) {	/* Open the kprobe/uprobe_events */
+			fd[up] = __open_probe_file_and_namelist(up,
+								&namelist[up]);
+			if (fd[up] < 0)
+				goto close_out;
+		}
 		/* Skip if the symbol is out of .text or blacklisted */
 		if (!tev->point.symbol && !pev->uprobes)
 			continue;
 
 		/* Set new name for tev (and update namelist) */
-		ret = probe_trace_event__set_name(tev, pev, namelist,
+		ret = probe_trace_event__set_name(tev, pev, namelist[up],
 						  allow_suffix);
 		if (ret < 0)
 			break;
 
-		ret = probe_file__add_event(fd, tev);
+		ret = probe_file__add_event(fd[up], tev);
 		if (ret < 0)
 			break;
 
@@ -2609,9 +2633,12 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 		}
 	}
 
-	strlist__delete(namelist);
 close_out:
-	close(fd);
+	for (up = 0; up < 2; up++) {
+		strlist__delete(namelist[up]);
+		if (fd[up] >= 0)
+			close(fd[up]);
+	}
 	return ret;
 }
 
@@ -2890,6 +2917,141 @@ errout:
 
 bool __weak arch__prefers_symtab(void) { return false; }
 
+/* Concatinate two arrays */
+static void *memcat(void *a, size_t sz_a, void *b, size_t sz_b)
+{
+	void *ret;
+
+	ret = malloc(sz_a + sz_b);
+	if (ret) {
+		memcpy(ret, a, sz_a);
+		memcpy(ret + sz_a, b, sz_b);
+	}
+	return ret;
+}
+
+static int
+concat_probe_trace_events(struct probe_trace_event **tevs, int *ntevs,
+			  struct probe_trace_event **tevs2, int ntevs2)
+{
+	struct probe_trace_event *new_tevs;
+	int ret = 0;
+
+	if (ntevs == 0) {
+		*tevs = *tevs2;
+		*ntevs = ntevs2;
+		*tevs2 = NULL;
+		return 0;
+	}
+
+	if (*ntevs + ntevs2 > probe_conf.max_probes)
+		ret = -E2BIG;
+	else {
+		/* Concatinate the array of probe_trace_event */
+		new_tevs = memcat(*tevs, (*ntevs) * sizeof(**tevs),
+				  *tevs2, ntevs2 * sizeof(**tevs2));
+		if (!new_tevs)
+			ret = -ENOMEM;
+		else {
+			free(*tevs);
+			*tevs = new_tevs;
+			*ntevs += ntevs2;
+		}
+	}
+	if (ret < 0)
+		clear_probe_trace_events(*tevs2, ntevs2);
+	zfree(tevs2);
+
+	return ret;
+}
+
+/*
+ * Try to find probe_trace_event from given probe caches. Return the number
+ * of cached events found, if an error occurs return the error.
+ */
+static int find_cached_events(struct perf_probe_event *pev,
+			      struct probe_trace_event **tevs,
+			      const char *target)
+{
+	struct probe_cache *cache;
+	struct probe_cache_entry *entry;
+	struct probe_trace_event *tmp_tevs = NULL;
+	int ntevs = 0;
+	int ret = 0;
+
+	cache = probe_cache__new(target);
+	/* Return 0 ("not found") if the target has no probe cache. */
+	if (!cache)
+		return 0;
+
+	for_each_probe_cache_entry(entry, cache) {
+		/* Skip the cache entry which has no name */
+		if (!entry->pev.event || !entry->pev.group)
+			continue;
+		if ((!pev->group || strglobmatch(entry->pev.group, pev->group)) &&
+		    strglobmatch(entry->pev.event, pev->event)) {
+			ret = probe_cache_entry__get_event(entry, &tmp_tevs);
+			if (ret > 0)
+				ret = concat_probe_trace_events(tevs, &ntevs,
+								&tmp_tevs, ret);
+			if (ret < 0)
+				break;
+		}
+	}
+	probe_cache__delete(cache);
+	if (ret < 0) {
+		clear_probe_trace_events(*tevs, ntevs);
+		zfree(tevs);
+	} else {
+		ret = ntevs;
+		if (ntevs > 0 && target[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);
+		/* In the case of cnt == 0, we just skip it */
+		if (ret > 0)
+			ret = concat_probe_trace_events(tevs, &ntevs,
+							&tmp_tevs, ret);
+		free(pathname);
+		if (ret < 0)
+			break;
+	}
+	strlist__delete(bidlist);
+
+	if (ret < 0) {
+		clear_probe_trace_events(*tevs, ntevs);
+		zfree(tevs);
+	} else
+		ret = ntevs;
+
+	return ret;
+}
+
 static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
 					      struct probe_trace_event **tevs)
 {
@@ -2899,6 +3061,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 e18ea9f..a027bfe 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 c4104c4..4d25882 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -360,13 +360,38 @@ probe_cache_entry__new(struct perf_probe_event *pev)
 	return ret;
 }
 
-/* For the kernel probe caches, pass target = NULL */
+int probe_cache_entry__get_event(struct probe_cache_entry *entry,
+				 struct probe_trace_event **tevs)
+{
+	struct probe_trace_event *tev;
+	struct str_node *node;
+	int ret, i;
+
+	ret = strlist__nr_entries(entry->tevlist);
+	if (ret > probe_conf.max_probes)
+		return -E2BIG;
+
+	*tevs = zalloc(ret * sizeof(*tev));
+	if (!*tevs)
+		return -ENOMEM;
+
+	i = 0;
+	strlist__for_each(node, entry->tevlist) {
+		tev = &(*tevs)[i++];
+		ret = parse_probe_trace_command(node->s, tev);
+		if (ret < 0)
+			break;
+	}
+	return i;
+}
+
+/* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */
 static int probe_cache__open(struct probe_cache *pcache, const char *target)
 {
 	char cpath[PATH_MAX];
 	char sbuildid[SBUILD_ID_SIZE];
 	char *dir_name = NULL;
-	bool is_kallsyms = !target;
+	bool is_kallsyms = false;
 	int ret, fd;
 
 	if (target && build_id_cache__cached(target)) {
@@ -376,12 +401,13 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
 		goto found;
 	}
 
-	if (target)
-		ret = filename__sprintf_build_id(target, sbuildid);
-	else {
+	if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) {
 		target = DSO__NAME_KALLSYMS;
+		is_kallsyms = true;
 		ret = sysfs__sprintf_build_id("/", sbuildid);
-	}
+	} else
+		ret = filename__sprintf_build_id(target, sbuildid);
+
 	if (ret < 0) {
 		pr_debug("Failed to get build-id from %s.\n", target);
 		return ret;
@@ -537,7 +563,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) &&
@@ -567,7 +593,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))
@@ -720,7 +746,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)
@@ -759,7 +785,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]


#1399138 — [PATCH perf/core v7 02/21] perf buildid: Fix to set correct dso name for kallsyms

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-11 16:00 +0200
Subject[PATCH perf/core v7 02/21] perf buildid: Fix to set correct dso name for kallsyms
Message-ID<rxCQf-UH-95@gated-at.bofh.it>
In reply to#1399123
Fix to set correct dso name ("[kernel.kallsyms]") for
kallsyms, as for vdso does.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 tools/perf/util/build-id.c |   12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index b6ecf87..234d8a1 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -343,21 +343,25 @@ void disable_buildid_cache(void)
 static char *build_id_cache__dirname_from_path(const char *name,
 					       bool is_kallsyms, bool is_vdso)
 {
-	char *realname = (char *)name, *filename;
+	const char *realname = name;
+	char *filename;
 	bool slash = is_kallsyms || is_vdso;
 
 	if (!slash) {
 		realname = realpath(name, NULL);
 		if (!realname)
 			return NULL;
-	}
+	} else if (is_vdso)
+		realname = DSO__NAME_VDSO;
+	else
+		realname = "[kernel.kallsyms]";
 
 	if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "",
-		     is_vdso ? DSO__NAME_VDSO : realname) < 0)
+		     realname) < 0)
 		filename = NULL;
 
 	if (!slash)
-		free(realname);
+		free((char *)realname);
 
 	return filename;
 }

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


#1399287 — Re: [PATCH perf/core v7 02/21] perf buildid: Fix to set correct dso name for kallsyms

FromArnaldo Carvalho de Melo <acme@kernel.org>
Date2016-05-11 17:50 +0200
SubjectRe: [PATCH perf/core v7 02/21] perf buildid: Fix to set correct dso name for kallsyms
Message-ID<rxEyC-2Hv-29@gated-at.bofh.it>
In reply to#1399138
Em Wed, May 11, 2016 at 10:51:37PM +0900, Masami Hiramatsu escreveu:
> Fix to set correct dso name ("[kernel.kallsyms]") for
> kallsyms, as for vdso does.

Can you rewrite the above comment and also break this down in two
patches, probably decribing what is the problem that it fixes?

- Arnaldo
 
> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> ---
>  tools/perf/util/build-id.c |   12 ++++++++----
>  1 file changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> index b6ecf87..234d8a1 100644
> --- a/tools/perf/util/build-id.c
> +++ b/tools/perf/util/build-id.c
> @@ -343,21 +343,25 @@ void disable_buildid_cache(void)
>  static char *build_id_cache__dirname_from_path(const char *name,
>  					       bool is_kallsyms, bool is_vdso)
>  {
> -	char *realname = (char *)name, *filename;
> +	const char *realname = name;
> +	char *filename;
>  	bool slash = is_kallsyms || is_vdso;
>  
>  	if (!slash) {
>  		realname = realpath(name, NULL);
>  		if (!realname)
>  			return NULL;
> -	}
> +	} else if (is_vdso)
> +		realname = DSO__NAME_VDSO;
> +	else
> +		realname = "[kernel.kallsyms]";
>  
>  	if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "",
> -		     is_vdso ? DSO__NAME_VDSO : realname) < 0)
> +		     realname) < 0)
>  		filename = NULL;
>  
>  	if (!slash)
> -		free(realname);
> +		free((char *)realname);
>  
>  	return filename;
>  }

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


#1399639 — Re: [PATCH perf/core v7 02/21] perf buildid: Fix to set correct dso name for kallsyms

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-12 04:10 +0200
SubjectRe: [PATCH perf/core v7 02/21] perf buildid: Fix to set correct dso name for kallsyms
Message-ID<rxOeC-3YK-3@gated-at.bofh.it>
In reply to#1399287
On Wed, 11 May 2016 12:45:00 -0300
Arnaldo Carvalho de Melo <acme@kernel.org> wrote:

> Em Wed, May 11, 2016 at 10:51:37PM +0900, Masami Hiramatsu escreveu:
> > Fix to set correct dso name ("[kernel.kallsyms]") for
> > kallsyms, as for vdso does.
> 
> Can you rewrite the above comment and also break this down in two
> patches,

No, could you explain what parts this consists of?
I think this patch is done just one thing. Actually I can rewrite
this as one-line patch like below

  	if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "",
-		     is_vdso ? DSO__NAME_VDSO : realname) < 0)
+		     is_vdso ? DSO__NAME_VDSO : (is_kallsyms ? "[kernel.kallsyms]": realname)) < 0)

But indeed this is not readable so clean it up like below.

> probably decribing what is the problem that it fixes?

Ah, indeed. This is actually not a fix for existing bug, instead
it will prevent buggy behavior. Current function can get any filepath
with is_vdso = true or is_kallsyms = true, but it seems easily giving
contradictory combination.

Hmm, OK, I think I have to solve this issue in another way.

Thanks!

> 
> - Arnaldo
>  
> > Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> > ---
> >  tools/perf/util/build-id.c |   12 ++++++++----
> >  1 file changed, 8 insertions(+), 4 deletions(-)
> > 
> > diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> > index b6ecf87..234d8a1 100644
> > --- a/tools/perf/util/build-id.c
> > +++ b/tools/perf/util/build-id.c
> > @@ -343,21 +343,25 @@ void disable_buildid_cache(void)
> >  static char *build_id_cache__dirname_from_path(const char *name,
> >  					       bool is_kallsyms, bool is_vdso)
> >  {
> > -	char *realname = (char *)name, *filename;
> > +	const char *realname = name;
> > +	char *filename;
> >  	bool slash = is_kallsyms || is_vdso;
> >  
> >  	if (!slash) {
> >  		realname = realpath(name, NULL);
> >  		if (!realname)
> >  			return NULL;
> > -	}
> > +	} else if (is_vdso)
> > +		realname = DSO__NAME_VDSO;
> > +	else
> > +		realname = "[kernel.kallsyms]";
> >  
> >  	if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "",
> > -		     is_vdso ? DSO__NAME_VDSO : realname) < 0)
> > +		     realname) < 0)
> >  		filename = NULL;
> >  
> >  	if (!slash)
> > -		free(realname);
> > +		free((char *)realname);
> >  
> >  	return filename;
> >  }


-- 
Masami Hiramatsu <mhiramat@kernel.org>

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


#1399785 — Re: [PATCH perf/core v7 02/21] perf buildid: Fix to set correct dso name for kallsyms

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-12 11:00 +0200
SubjectRe: [PATCH perf/core v7 02/21] perf buildid: Fix to set correct dso name for kallsyms
Message-ID<rxUDq-21y-47@gated-at.bofh.it>
In reply to#1399639
On Thu, 12 May 2016 11:02:12 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> On Wed, 11 May 2016 12:45:00 -0300
> Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
> 
> > Em Wed, May 11, 2016 at 10:51:37PM +0900, Masami Hiramatsu escreveu:
> > > Fix to set correct dso name ("[kernel.kallsyms]") for
> > > kallsyms, as for vdso does.
> > 
> > Can you rewrite the above comment and also break this down in two
> > patches,
> 
> No, could you explain what parts this consists of?
> I think this patch is done just one thing. Actually I can rewrite
> this as one-line patch like below
> 
>   	if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "",
> -		     is_vdso ? DSO__NAME_VDSO : realname) < 0)
> +		     is_vdso ? DSO__NAME_VDSO : (is_kallsyms ? "[kernel.kallsyms]": realname)) < 0)
> 
> But indeed this is not readable so clean it up like below.
> 
> > probably decribing what is the problem that it fixes?
> 
> Ah, indeed. This is actually not a fix for existing bug, instead
> it will prevent buggy behavior. Current function can get any filepath
> with is_vdso = true or is_kallsyms = true, but it seems easily giving
> contradictory combination.
> 
> Hmm, OK, I think I have to solve this issue in another way.

OK, from further investigation, I found this is not a real bug, but
just an unneeded behavior changing. At this moment, I should drop this
from the series. Here is what I understand.

At first, the path of the original binary is used only when storing
build-id caches.
When loading the cache, perf uses build-id symlink to access it.

OK, so this is the callgraph of build_id_cache__dirname_from_path.
'<-' shows the caller, and with what parameters given.
 
build_id_cache__dirname_from_path
	<- build_id_cache__add_s, with (pathname, is_kallsyms, is_vdso)
		<- build_id_cache__add_b, with (sbuild_id, name, is_kallsyms, is_vdso)
			<-dso__cache_build_id
		<- build_id_cache__add_file, with (sbuild_id,filepath,false,false)
		<- build_id_cache__update_file, with (sbuild_id,filepath,false,false)
	<- build_id_cache__list_build_ids, with (pathname, false, false)

Focusing on the is_kallsyms and is_vdso, the callgraph to
build_id_cache__list_build_ids(), build_id_cache__add_file()
and build_id_cache__update_file() are not using those parameters.
These functions just pass the file path, so we can ignore.
(BTW, in this case we can not remove/purge the caches for vdso, kallsyms and
 kcore from buildid directory ...)

The last callgraph is dso__cache_build_id(), and only it uses is_kallsyms and is_vdso.
Those parameters are given as below

  is_kallsyms = dso->kernel && dso->long_name[0] != '/'
  is_vdso = dso__is_vdso(dso) <- check the dso->short_name is DSO__NAME_VDSO*
  pathname = dso->long_name

So, is_vdso == true, build_id_cache__dirname_from_path() stores all
DSO__NAME_VDSO* ("[vdso]", "[vdso32]", and "[vdsox32]") caches under
DSO__NAME_VDSO("[vdso]").

This seems is_kallsyms == true, the pathname has no real filename.

And the kernel dso will be made by machine__get_kernel(), which sets the
kernel dso's long name is whether the user given (guest)vmlinux name or
the name given by machine__mmap_name(). The machine__mmap_name() returns
[kernel.kallsyms], [guest.kernel.kallsyms] or [guest.kernel.kallsyms.<PID>].

OK, so the question is, should we do same thing on kallsyms as vdso?
This patch actually tried it, all the "[*kernel.kallsyms*]" dso caches
stored under "[kernel.kallsyms]".

Thank you,


> >  
> > > Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> > > ---
> > >  tools/perf/util/build-id.c |   12 ++++++++----
> > >  1 file changed, 8 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> > > index b6ecf87..234d8a1 100644
> > > --- a/tools/perf/util/build-id.c
> > > +++ b/tools/perf/util/build-id.c
> > > @@ -343,21 +343,25 @@ void disable_buildid_cache(void)
> > >  static char *build_id_cache__dirname_from_path(const char *name,
> > >  					       bool is_kallsyms, bool is_vdso)
> > >  {
> > > -	char *realname = (char *)name, *filename;
> > > +	const char *realname = name;
> > > +	char *filename;
> > >  	bool slash = is_kallsyms || is_vdso;
> > >  
> > >  	if (!slash) {
> > >  		realname = realpath(name, NULL);
> > >  		if (!realname)
> > >  			return NULL;
> > > -	}
> > > +	} else if (is_vdso)
> > > +		realname = DSO__NAME_VDSO;
> > > +	else
> > > +		realname = "[kernel.kallsyms]";
> > >  
> > >  	if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "",
> > > -		     is_vdso ? DSO__NAME_VDSO : realname) < 0)
> > > +		     realname) < 0)
> > >  		filename = NULL;
> > >  
> > >  	if (!slash)
> > > -		free(realname);
> > > +		free((char *)realname);
> > >  
> > >  	return filename;
> > >  }
> 
> 
> -- 
> Masami Hiramatsu <mhiramat@kernel.org>


-- 
Masami Hiramatsu <mhiramat@kernel.org>

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


#1399139 — [PATCH perf/core v7 09/21] perf probe: Add --cache option to cache the probe definitions

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-11 16:00 +0200
Subject[PATCH perf/core v7 09/21] perf probe: Add --cache option to cache the probe definitions
Message-ID<rxCQf-UH-89@gated-at.bofh.it>
In reply to#1399123
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 v6:
  - Remove unneeded O_APPEND from open(). (Thanks Namhyung!)
  - Fix to check the return value of probe_cache_entry__new and strdup.(ditto)
 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              |   12 +
 tools/perf/util/build-id.h              |    2 
 tools/perf/util/probe-event.c           |  124 +++++++++++--
 tools/perf/util/probe-event.h           |    5 +
 tools/perf/util/probe-file.c            |  307 +++++++++++++++++++++++++++++++
 tools/perf/util/probe-file.h            |   19 ++
 8 files changed, 447 insertions(+), 27 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 39d1667..9b8edf3 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -390,9 +390,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__cachedir(const char *sbuild_id, const char *name,
+			       bool is_kallsyms, bool is_vdso)
 {
 	const char *realname = name;
 	char *filename;
@@ -423,8 +422,7 @@ 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__cachedir(NULL, pathname, false, false);
 	if (!dir_name)
 		return -ENOMEM;
 
@@ -450,8 +448,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__cachedir(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 e5435f4..d8c7f2f 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -30,6 +30,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__cachedir(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 74401a2..854885b 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 */
@@ -1712,7 +1711,7 @@ out:
 }
 
 /* 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, *ret = NULL;
@@ -1751,30 +1750,36 @@ out:
 	return ret;
 }
 
-#if 0
 char *synthesize_perf_probe_command(struct perf_probe_event *pev)
 {
-	char *buf;
-	int i, len, ret;
+	struct strbuf buf;
+	char *tmp, *ret = NULL;
+	int i;
 
-	buf = synthesize_perf_probe_point(&pev->point);
-	if (!buf)
+	if (strbuf_init(&buf, 64))
 		return NULL;
+	if (pev->event)
+		if (strbuf_addf(&buf, "%s:%s=", pev->group ?: PERFPROBE_GROUP,
+				pev->event) < 0)
+			goto out;
+
+	tmp = synthesize_perf_probe_point(&pev->point);
+	if (!tmp || strbuf_addstr(&buf, tmp) < 0)
+		goto out;
+	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 || strbuf_addf(&buf, " %s", tmp) < 0)
+			goto out;
+		free(tmp);
 	}
 
-	return buf;
+	ret = strbuf_detach(&buf, NULL);
+out:
+	strbuf_release(&buf);
+	return ret;
 }
-#endif
 
 static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
 					    struct strbuf *buf, int depth)
@@ -2026,6 +2031,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;
@@ -2432,6 +2510,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));
@@ -2473,6 +2552,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:
@@ -2501,9 +2588,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 5a27eb4..432b690 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..689d874 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,309 @@ 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 = DSO__NAME_KALLSYMS;
+		ret = sysfs__sprintf_build_id("/", sbuildid);
+	}
+	if (ret < 0) {
+		pr_debug("Failed to get build-id from %s.\n", target);
+		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__cachedir(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, 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);
+			if (!entry) {
+				ret = -ENOMEM;
+				goto out;
+			}
+			entry->spev = strdup(buf + 1);
+			if (entry->spev)
+				ret = parse_perf_probe_command(buf + 1,
+								&entry->pev);
+			else
+				ret = -ENOMEM;
+			if (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]


#1399142 — [PATCH perf/core v7 03/21] perf buildid: Introduce DSO__NAME_KALLSYMS and DSO__NAME_KCORE

FromMasami Hiramatsu <mhiramat@kernel.org>
Date2016-05-11 16:10 +0200
Subject[PATCH perf/core v7 03/21] perf buildid: Introduce DSO__NAME_KALLSYMS and DSO__NAME_KCORE
Message-ID<rxCZP-1jh-3@gated-at.bofh.it>
In reply to#1399123
Instead of using raw string, use DSO__NAME_KALLSYMS and DSO__NAME_KCORE
macros for kallsyms and kcore.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 tools/perf/builtin-buildid-cache.c |    8 ++++----
 tools/perf/util/annotate.c         |    2 +-
 tools/perf/util/build-id.c         |    2 +-
 tools/perf/util/machine.c          |    2 +-
 tools/perf/util/symbol.c           |   10 +++++-----
 tools/perf/util/symbol.h           |    3 +++
 6 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index 632efc6..d75bded 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -119,8 +119,8 @@ static int build_id_cache__add_kcore(const char *filename, bool force)
 	if (build_id_cache__kcore_buildid(from_dir, sbuildid) < 0)
 		return -1;
 
-	scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
-		  buildid_dir, sbuildid);
+	scnprintf(to_dir, sizeof(to_dir), "%s/%s/%s",
+		  buildid_dir, DSO__NAME_KCORE, sbuildid);
 
 	if (!force &&
 	    !build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
@@ -131,8 +131,8 @@ static int build_id_cache__add_kcore(const char *filename, bool force)
 	if (build_id_cache__kcore_dir(dir, sizeof(dir)))
 		return -1;
 
-	scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s/%s",
-		  buildid_dir, sbuildid, dir);
+	scnprintf(to_dir, sizeof(to_dir), "%s/%s/%s/%s",
+		  buildid_dir, DSO__NAME_KCORE, sbuildid, dir);
 
 	if (mkdir_p(to_dir, 0755))
 		return -1;
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index d4b3d03..1168442 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -1122,7 +1122,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
 	} else if (dso__is_kcore(dso)) {
 		goto fallback;
 	} else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
-		   strstr(command, "[kernel.kallsyms]") ||
+		   strstr(command, DSO__NAME_KALLSYMS) ||
 		   access(symfs_filename, R_OK)) {
 		free(filename);
 fallback:
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 234d8a1..53df9aa 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -354,7 +354,7 @@ static char *build_id_cache__dirname_from_path(const char *name,
 	} else if (is_vdso)
 		realname = DSO__NAME_VDSO;
 	else
-		realname = "[kernel.kallsyms]";
+		realname = DSO__NAME_KALLSYMS;
 
 	if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "",
 		     realname) < 0)
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 639a290..18dd96b 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -709,7 +709,7 @@ static struct dso *machine__get_kernel(struct machine *machine)
 	if (machine__is_host(machine)) {
 		vmlinux_name = symbol_conf.vmlinux_name;
 		if (!vmlinux_name)
-			vmlinux_name = "[kernel.kallsyms]";
+			vmlinux_name = DSO__NAME_KALLSYMS;
 
 		kernel = machine__findnew_kernel(machine, vmlinux_name,
 						 "[kernel]", DSO_TYPE_KERNEL);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 2946295..49caa91 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1648,8 +1648,8 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
 
 	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
 
-	scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir,
-		  sbuild_id);
+	scnprintf(path, sizeof(path), "%s/%s/%s", buildid_dir,
+		  DSO__NAME_KCORE, sbuild_id);
 
 	/* Use /proc/kallsyms if possible */
 	if (is_host) {
@@ -1685,8 +1685,8 @@ 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",
-		  buildid_dir, sbuild_id);
+	scnprintf(path, sizeof(path), "%s/%s/%s",
+		  buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
 
 	if (access(path, F_OK)) {
 		pr_err("No kallsyms or vmlinux with build-id %s was found\n",
@@ -1755,7 +1755,7 @@ do_kallsyms:
 
 	if (err > 0 && !dso__is_kcore(dso)) {
 		dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
-		dso__set_long_name(dso, "[kernel.kallsyms]", false);
+		dso__set_long_name(dso, DSO__NAME_KALLSYMS, false);
 		map__fixup_start(map);
 		map__fixup_end(map);
 	}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 07211c2..78e3bbf 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -44,6 +44,9 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
 #define DMGL_ANSI        (1 << 1)       /* Include const, volatile, etc */
 #endif
 
+#define DSO__NAME_KALLSYMS	"[kernel.kallsyms]"
+#define DSO__NAME_KCORE		"[kernel.kcore]"
+
 /** struct symbol - symtab entry
  *
  * @ignore - resolvable but tools ignore it (e.g. idle routines)

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


#1399284 — Re: [PATCH perf/core v7 03/21] perf buildid: Introduce DSO__NAME_KALLSYMS and DSO__NAME_KCORE

FromArnaldo Carvalho de Melo <acme@kernel.org>
Date2016-05-11 17:50 +0200
SubjectRe: [PATCH perf/core v7 03/21] perf buildid: Introduce DSO__NAME_KALLSYMS and DSO__NAME_KCORE
Message-ID<rxEyB-2Hv-9@gated-at.bofh.it>
In reply to#1399142
Em Wed, May 11, 2016 at 10:51:49PM +0900, Masami Hiramatsu escreveu:
> Instead of using raw string, use DSO__NAME_KALLSYMS and DSO__NAME_KCORE
> macros for kallsyms and kcore.

Depends on the previous patch,

- Arnaldo
 
> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> ---
>  tools/perf/builtin-buildid-cache.c |    8 ++++----
>  tools/perf/util/annotate.c         |    2 +-
>  tools/perf/util/build-id.c         |    2 +-
>  tools/perf/util/machine.c          |    2 +-
>  tools/perf/util/symbol.c           |   10 +++++-----
>  tools/perf/util/symbol.h           |    3 +++
>  6 files changed, 15 insertions(+), 12 deletions(-)
> 
> diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
> index 632efc6..d75bded 100644
> --- a/tools/perf/builtin-buildid-cache.c
> +++ b/tools/perf/builtin-buildid-cache.c
> @@ -119,8 +119,8 @@ static int build_id_cache__add_kcore(const char *filename, bool force)
>  	if (build_id_cache__kcore_buildid(from_dir, sbuildid) < 0)
>  		return -1;
>  
> -	scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
> -		  buildid_dir, sbuildid);
> +	scnprintf(to_dir, sizeof(to_dir), "%s/%s/%s",
> +		  buildid_dir, DSO__NAME_KCORE, sbuildid);
>  
>  	if (!force &&
>  	    !build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
> @@ -131,8 +131,8 @@ static int build_id_cache__add_kcore(const char *filename, bool force)
>  	if (build_id_cache__kcore_dir(dir, sizeof(dir)))
>  		return -1;
>  
> -	scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s/%s",
> -		  buildid_dir, sbuildid, dir);
> +	scnprintf(to_dir, sizeof(to_dir), "%s/%s/%s/%s",
> +		  buildid_dir, DSO__NAME_KCORE, sbuildid, dir);
>  
>  	if (mkdir_p(to_dir, 0755))
>  		return -1;
> diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
> index d4b3d03..1168442 100644
> --- a/tools/perf/util/annotate.c
> +++ b/tools/perf/util/annotate.c
> @@ -1122,7 +1122,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
>  	} else if (dso__is_kcore(dso)) {
>  		goto fallback;
>  	} else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
> -		   strstr(command, "[kernel.kallsyms]") ||
> +		   strstr(command, DSO__NAME_KALLSYMS) ||
>  		   access(symfs_filename, R_OK)) {
>  		free(filename);
>  fallback:
> diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> index 234d8a1..53df9aa 100644
> --- a/tools/perf/util/build-id.c
> +++ b/tools/perf/util/build-id.c
> @@ -354,7 +354,7 @@ static char *build_id_cache__dirname_from_path(const char *name,
>  	} else if (is_vdso)
>  		realname = DSO__NAME_VDSO;
>  	else
> -		realname = "[kernel.kallsyms]";
> +		realname = DSO__NAME_KALLSYMS;
>  
>  	if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "",
>  		     realname) < 0)
> diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
> index 639a290..18dd96b 100644
> --- a/tools/perf/util/machine.c
> +++ b/tools/perf/util/machine.c
> @@ -709,7 +709,7 @@ static struct dso *machine__get_kernel(struct machine *machine)
>  	if (machine__is_host(machine)) {
>  		vmlinux_name = symbol_conf.vmlinux_name;
>  		if (!vmlinux_name)
> -			vmlinux_name = "[kernel.kallsyms]";
> +			vmlinux_name = DSO__NAME_KALLSYMS;
>  
>  		kernel = machine__findnew_kernel(machine, vmlinux_name,
>  						 "[kernel]", DSO_TYPE_KERNEL);
> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> index 2946295..49caa91 100644
> --- a/tools/perf/util/symbol.c
> +++ b/tools/perf/util/symbol.c
> @@ -1648,8 +1648,8 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
>  
>  	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
>  
> -	scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir,
> -		  sbuild_id);
> +	scnprintf(path, sizeof(path), "%s/%s/%s", buildid_dir,
> +		  DSO__NAME_KCORE, sbuild_id);
>  
>  	/* Use /proc/kallsyms if possible */
>  	if (is_host) {
> @@ -1685,8 +1685,8 @@ 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",
> -		  buildid_dir, sbuild_id);
> +	scnprintf(path, sizeof(path), "%s/%s/%s",
> +		  buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
>  
>  	if (access(path, F_OK)) {
>  		pr_err("No kallsyms or vmlinux with build-id %s was found\n",
> @@ -1755,7 +1755,7 @@ do_kallsyms:
>  
>  	if (err > 0 && !dso__is_kcore(dso)) {
>  		dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
> -		dso__set_long_name(dso, "[kernel.kallsyms]", false);
> +		dso__set_long_name(dso, DSO__NAME_KALLSYMS, false);
>  		map__fixup_start(map);
>  		map__fixup_end(map);
>  	}
> diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
> index 07211c2..78e3bbf 100644
> --- a/tools/perf/util/symbol.h
> +++ b/tools/perf/util/symbol.h
> @@ -44,6 +44,9 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
>  #define DMGL_ANSI        (1 << 1)       /* Include const, volatile, etc */
>  #endif
>  
> +#define DSO__NAME_KALLSYMS	"[kernel.kallsyms]"
> +#define DSO__NAME_KCORE		"[kernel.kcore]"
> +
>  /** struct symbol - symtab entry
>   *
>   * @ignore - resolvable but tools ignore it (e.g. idle routines)

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web