Skip to contentSkip to conversation

perf tools: Fix build-id matching on vmlinux

PATCH In review Namhyung Kim 6 participants 43 messages Sep 22, 2014 – Nov 7, 2014

Subsystems (2)
lore
Share & tools
lore

Namhyung Kim

author maintainer
#0 lore raw

PATCH v4 1/1 perf tools: Fix build-id matching on vmlinux

There's a problem on finding correct kernel symbols when perf report runs on a different kernel. Although a part of the problem was solved by the prior commit 0a7e6d1b6844 ("perf tools: Check recorded kernel version when finding vmlinux"), there's a remaining problem still.

When perf records samples, it synthesizes the kernel map using machine__mmap_name() and ref_reloc_sym like "[kernel.kallsyms]_text". You can easily see it using 'perf report -D' command.

After finishing record, it goes through the recorded events to find maps/dsos actually used. And then record build-id info of them.

During this process, it needs to load symbols in a dso and it'd call dso__load_vmlinux() since the default value of the symbol_conf.try_ vmlinux_path is true. However it changes dso->long_name to a real path of the vmlinux file (e.g. /lib/modules/3.16.0-rc2+/build/vmlinux) if one is running on a custom kernel.

It resulted in that perf report reads the build-id of the vmlinux, but cannot use it since it only knows about the [kernel.kallsyms] map. It then falls back to possible vmlinux paths by using the recorded kernel version (in case of a recent version) or a running kernel silently.

Even with the recent tools, this still has a possibility of breaking the result. As the build directory is a symbolic link, if one built a new kernel in the same directory with different source/config, the old link to vmlinux will point the new file. So it's absolutely needed to use build-id when finding a kernel image.

In this patch, it's now changed to try to search a kernel dso in the existing dso list which was constructed during build-id table parsing so it'll always have a build-id. If not found, search "[kernel.kallsyms]".

Before:

  $ perf report
  # Children      Self  Command  Shared Object      Symbol
  # ........  ........  .......  .................  ...............................
  #
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] set_curr_task_rt
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] native_calibrate_tsc
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] tsc_refine_calibration_work
      71.87%    71.87%  swapper  [kernel.kallsyms]  [k] module_finalize
   ...

After (for the same perf.data):

      72.15%     0.00%  swapper  vmlinux  [k] cpu_startup_entry
      72.15%     0.00%  swapper  vmlinux  [k] arch_cpu_idle
      72.15%     0.00%  swapper  vmlinux  [k] default_idle
      71.87%    71.87%  swapper  vmlinux  [k] native_safe_halt

...

---
 tools/perf/util/machine.c | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)
tools/perf/util/machine.c +21 -2
index b2ec38bf211e..5661195a8cf6 100644
@@ -12,6 +12,7 @@
 #include <stdbool.h>
 #include <symbol/kallsyms.h>
 #include "unwind.h"
+#include "asm/bug.h"
 
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 {
@@ -1062,8 +1063,26 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 		 * Should be there already, from the build-id table in
 		 * the header.
 		 */
-		struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
-						     kmmap_prefix);
+		struct dso *kernel = NULL;
+		struct dso *dso;
+
+		list_for_each_entry(dso, &machine->kernel_dsos, node) {
+			const char *suffix;
+			size_t len = strlen(dso->long_name);
+
+			if (WARN_ONCE(len <= 3, "Too short dso name"))
+				continue;
+
+			suffix = dso->long_name + len - 3;
+			if (strcmp(suffix, ".ko")) {
+				kernel = dso;
+				break;
+			}
+		}
+
+		if (kernel == NULL)
+			kernel = __dsos__findnew(&machine->kernel_dsos,
+						 kmmap_prefix);
 		if (kernel == NULL)
 			goto out_problem;
 
Signature · 1 line
2.1.0
Acked-by on v4 1/1
#1 lore raw
Quoted 87 lines · Namhyung Kim

There's a problem on finding correct kernel symbols when perf report runs on a different kernel. Although a part of the problem was solved by the prior commit 0a7e6d1b6844 ("perf tools: Check recorded kernel version when finding vmlinux"), there's a remaining problem still.

When perf records samples, it synthesizes the kernel map using machine__mmap_name() and ref_reloc_sym like "[kernel.kallsyms]_text". You can easily see it using 'perf report -D' command.

After finishing record, it goes through the recorded events to find maps/dsos actually used. And then record build-id info of them.

During this process, it needs to load symbols in a dso and it'd call dso__load_vmlinux() since the default value of the symbol_conf.try_ vmlinux_path is true. However it changes dso->long_name to a real path of the vmlinux file (e.g. /lib/modules/3.16.0-rc2+/build/vmlinux) if one is running on a custom kernel.

It resulted in that perf report reads the build-id of the vmlinux, but cannot use it since it only knows about the [kernel.kallsyms] map. It then falls back to possible vmlinux paths by using the recorded kernel version (in case of a recent version) or a running kernel silently.

Even with the recent tools, this still has a possibility of breaking the result. As the build directory is a symbolic link, if one built a new kernel in the same directory with different source/config, the old link to vmlinux will point the new file. So it's absolutely needed to use build-id when finding a kernel image.

In this patch, it's now changed to try to search a kernel dso in the existing dso list which was constructed during build-id table parsing so it'll always have a build-id. If not found, search "[kernel.kallsyms]".

Before:

  $ perf report
  # Children      Self  Command  Shared Object      Symbol
  # ........  ........  .......  .................  ...............................
  #
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] set_curr_task_rt
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] native_calibrate_tsc
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] tsc_refine_calibration_work
      71.87%    71.87%  swapper  [kernel.kallsyms]  [k] module_finalize
   ...

After (for the same perf.data):

      72.15%     0.00%  swapper  vmlinux  [k] cpu_startup_entry
      72.15%     0.00%  swapper  vmlinux  [k] arch_cpu_idle
      72.15%     0.00%  swapper  vmlinux  [k] default_idle
      71.87%    71.87%  swapper  vmlinux  [k] native_safe_halt

...

---
 tools/perf/util/machine.c | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)
tools/perf/util/machine.c +11 -2
index b2ec38bf211e..5661195a8cf6 100644
@@ -12,6 +12,7 @@
 #include <stdbool.h>
 #include <symbol/kallsyms.h>
 #include "unwind.h"
+#include "asm/bug.h"
 
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 {
@@ -1062,8 +1063,26 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 		 * Should be there already, from the build-id table in
 		 * the header.
 		 */
-		struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
-						     kmmap_prefix);
+		struct dso *kernel = NULL;
+		struct dso *dso;
+
+		list_for_each_entry(dso, &machine->kernel_dsos, node) {
+			const char *suffix;
+			size_t len = strlen(dso->long_name);
+
+			if (WARN_ONCE(len <= 3, "Too short dso name"))
+				continue;
+

tools/perf/util/machine.c static int machine__process_kernel_mmap_event(struct machine *machine, · line 1085

Quoted 10 lines
tools/perf/util/machine.c +10 -0
+			suffix = dso->long_name + len - 3;
+			if (strcmp(suffix, ".ko")) {
+				kernel = dso;
+				break;
+			}
+		}
+
+		if (kernel == NULL)
+			kernel = __dsos__findnew(&machine->kernel_dsos,
+						 kmmap_prefix);

Please don't break the line just to pacify checkpatch.pl. Other than that:

Thanks,

Ing

author maintainer
#2 lore raw

Hi Ingo and Arnaldo,

Quoted 14 lines · Ingo Molnar
Quoted 13 lines · Namhyung Kim
tools/perf/util/machine.c +7 -2
@@ -1062,8 +1063,26 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 		 * Should be there already, from the build-id table in
 		 * the header.
 		 */
-		struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
-						     kmmap_prefix);
+		struct dso *kernel = NULL;
+		struct dso *dso;
+
+		list_for_each_entry(dso, &machine->kernel_dsos, node) {
+			const char *suffix;
+			size_t len = strlen(dso->long_name);
+
Quoted 8 lines

tools/perf/util/machine.c static int machine__process_kernel_mmap_event(struct machine *machine, · line 1080

Quoted 8 lines
tools/perf/util/machine.c +8 -0
+			if (WARN_ONCE(len <= 3, "Too short dso name"))
+				continue;
+
+			suffix = dso->long_name + len - 3;
+			if (strcmp(suffix, ".ko")) {
+				kernel = dso;
+				break;
+			}

I just noticed that the modules can be gzip'ed on some system (e.g. Arch) so that it no longer has the ".ko" suffix.

  $ ls /lib/modules/`uname -r`/kernel/fs/btrfs/
  btrfs.ko.gz

Actually in this case, the dso->long_name cannot be set since when perf record synthesizes module map events, it checks the ".ko" suffix also. :/

And I also guess that if one loads a custom module not in a canonical path, it again cannot find the long name (absolute path) of the module and it results in no ".ko" suffix in the long name - so the check will be broken too.

Quoted 8 lines

tools/perf/util/machine.c static int machine__process_kernel_mmap_event(struct machine *machine, · line 1085

Quoted 5 lines
tools/perf/util/machine.c +5 -0
+		}
+
+		if (kernel == NULL)
+			kernel = __dsos__findnew(&machine->kernel_dsos,
+						 kmmap_prefix);

Please don't break the line just to pacify checkpatch.pl. Other than that:

For non string literals too? Anyway in this case, it's already broken. :)

Quoted 2 lines

Thanks anyway! :)

Namhyung

author maintainer
#3 lore raw

cover perf tools: Fix build-id matching on vmlinux (v5)

Hello,

This patchset addresses possible problem on kernel symbol matching. Since commit 5b7ba82a7591 ("perf symbols: Load kernel maps before using"), when perf record process samples to construct build-id table, it loads kernel map and it replaces dso->long_name. But perf report doesn't know about name other than [kernel.kallsyms] it failed to find existing kernel dso and falls back to running kernel's kallsyms.

So it's possible to report incorrect symbols for kernel functions if it runs on a different kernel:

Before:

  $ perf report
  # Children      Self  Command  Shared Object      Symbol
  # ........  ........  .......  .................  ...............................
  #
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] set_curr_task_rt
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] native_calibrate_tsc
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] tsc_refine_calibration_work
      71.87%    71.87%  swapper  [kernel.kallsyms]  [k] module_finalize
   ...

After (for the same perf.data):

      72.15%     0.00%  swapper  [kernel.vmlinux]  [k] cpu_startup_entry
      72.15%     0.00%  swapper  [kernel.vmlinux]  [k] arch_cpu_idle
      72.15%     0.00%  swapper  [kernel.vmlinux]  [k] default_idle
      71.87%    71.87%  swapper  [kernel.vmlinux]  [k] native_safe_halt

In this patch, it's now changed to try to search a kernel dso in the existing dso list which was constructed during build-id table parsing so it'll always have a build-id. If not found, search "[kernel.kallsyms]".

The patch 1-2 are to support module compression as some distro (e.g. Arch) already does it. The patch 3-5 are cleanup of build-id handling functions. The patch 6-7 are the main change of this series and finally patch 8 is just for suggestion which can be squashed into the previous patch or simply dropped.

You can get it on 'perf/vmlinux-v5' branch in my tree:

git://git.kernel.org/pub/scm/linux/kernel/git/namhyung/linux-perf.git

Any comments are welcome, thanks
Namhyung

Cc Adrian Hunter <[email protected]>

Namhyung Kim (8):
perf tools: Preparation for compressed kernel module support perf tools: Add gzip decompression support for kernel module perf tools: Get rid of unused dsos__hit_all()
perf tools: Rename dsos__write_buildid_table()
perf build-id: Move build-id related functions to util/build-id.c perf record: Do not save pathname in ./debug/.build-id directory for
vmlinux
perf tools: Fix build-id matching on vmlinux
perf tools: Make vmlinux short name more like kallsyms short name

 tools/perf/Makefile.perf                     |   7 +
 tools/perf/builtin-record.c                  |  11 +
 tools/perf/config/Makefile                   |  15 +-
 tools/perf/config/feature-checks/Makefile    |   6 +-
 tools/perf/config/feature-checks/test-zlib.c |   9 +
 tools/perf/util/build-id.c                   | 293 +++++++++++++++++++++++
 tools/perf/util/build-id.h                   |   5 +
 tools/perf/util/dso.c                        |  71 ++++++
 tools/perf/util/dso.h                        |   7 +
 tools/perf/util/header.c                     | 343 +--------------------------
 tools/perf/util/header.h                     |   4 +-
 tools/perf/util/machine.c                    |  38 ++-
 tools/perf/util/symbol-elf.c                 |  35 ++-
 tools/perf/util/symbol.c                     |  19 +-
 tools/perf/util/symbol.h                     |   1 +
 tools/perf/util/util.h                       |   5 +
 tools/perf/util/zlib.c                       |  78 ++++++
 17 files changed, 593 insertions(+), 354 deletions(-)
 create mode 100644 tools/perf/config/feature-checks/test-zlib.c
 create mode 100644 tools/perf/util/zlib.c
Signature · 1 line
2.1.2
author maintainer
#4 lore raw

PATCH 1/8 perf tools: Preparation for compressed kernel module support

This patch adds basic support to handle compressed kernel module as some distro (such as Archlinux) carries on it now. The actual work using compression library will be added later.

---
 tools/perf/util/dso.c        | 74 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/dso.h        |  7 +++++
 tools/perf/util/machine.c    | 19 +++++++++++-
 tools/perf/util/symbol-elf.c | 35 ++++++++++++++++++++-
 tools/perf/util/symbol.c     |  8 ++++-
 5 files changed, 140 insertions(+), 3 deletions(-)
tools/perf/util/dso.c +74 -0
index 0247acfdfaca..3293e2e21814 100644
@@ -21,8 +21,10 @@ char dso__symtab_origin(const struct dso *dso)
 		[DSO_BINARY_TYPE__BUILDID_DEBUGINFO]		= 'b',
 		[DSO_BINARY_TYPE__SYSTEM_PATH_DSO]		= 'd',
 		[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE]		= 'K',
+		[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP]	= 'm',
 		[DSO_BINARY_TYPE__GUEST_KALLSYMS]		= 'g',
 		[DSO_BINARY_TYPE__GUEST_KMODULE]		= 'G',
+		[DSO_BINARY_TYPE__GUEST_KMODULE_COMP]		= 'M',
 		[DSO_BINARY_TYPE__GUEST_VMLINUX]		= 'V',
 	};
 
@@ -112,11 +114,13 @@ int dso__read_binary_type_filename(const struct dso *dso,
 		break;
 
 	case DSO_BINARY_TYPE__GUEST_KMODULE:
+	case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
 		path__join3(filename, size, symbol_conf.symfs,
 			    root_dir, dso->long_name);
 		break;
 
 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
 		__symbol__join_symfs(filename, size, dso->long_name);
 		break;
 
@@ -137,6 +141,76 @@ int dso__read_binary_type_filename(const struct dso *dso,
 	return ret;
 }
 
+static int decompress_dummy(const char *input __maybe_unused,
+			    int output __maybe_unused)
+{
+	return -1;
+}
+
+static const struct {
+	const char *fmt;
+	int (*decompress)(const char *input, int output);
+} compressions[] = {
+	{ "gz", decompress_dummy },
+};
+
+bool is_supported_compression(const char *ext)
+{
+	unsigned i;
+
+	for (i = 0; i < ARRAY_SIZE(compressions); i++) {
+		if (!strcmp(ext, compressions[i].fmt))
+			return true;
+	}
+	return false;
+}
+
+bool is_kmodule_extension(const char *ext)
+{
+	if (!strcmp(ext, "ko"))
+		return true;
+
+	if (ext[2] == '\0' || (ext[2] == '.' && is_supported_compression(ext+3)))
+		return true;
+
+	return false;
+}
+
+bool is_kernel_module(const char *pathname, bool *compressed)
+{
+	const char *ext = strrchr(pathname, '.');
+
+	if (ext == NULL)
+		return false;
+
+	if (is_supported_compression(ext + 1)) {
+		if (compressed)
+			*compressed = true;
+		ext -= 3;
+	} else if (compressed)
+		*compressed = false;
+
+	return is_kmodule_extension(ext + 1);
+}
+
+bool decompress_to_file(const char *ext, const char *filename, int output_fd)
+{
+	unsigned i;
+
+	for (i = 0; i < ARRAY_SIZE(compressions); i++) {
+		if (!strcmp(ext, compressions[i].fmt))
+			return !compressions[i].decompress(filename,
+							   output_fd);
+	}
+	return false;
+}
+
+bool dso__needs_decompress(struct dso *dso)
+{
+	return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
+}
+
 /*
  * Global list of open DSOs and the counter.
  */
tools/perf/util/dso.h +7 -0
index a316e4af321f..3782c82c6e44 100644
@@ -22,7 +22,9 @@ enum dso_binary_type {
 	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
 	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
 	DSO_BINARY_TYPE__GUEST_KMODULE,
+	DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
 	DSO_BINARY_TYPE__KCORE,
 	DSO_BINARY_TYPE__GUEST_KCORE,
 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
@@ -185,6 +187,11 @@ int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
 char dso__symtab_origin(const struct dso *dso);
 int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
 				   char *root_dir, char *filename, size_t size);
+bool is_supported_compression(const char *ext);
+bool is_kmodule_extension(const char *ext);
+bool is_kernel_module(const char *pathname, bool *compressed);
+bool decompress_to_file(const char *ext, const char *filename, int output_fd);
+bool dso__needs_decompress(struct dso *dso);
 
 /*
  * The dso__data_* external interface provides following functions:
tools/perf/util/machine.c +18 -1
index 51a630301afa..946c7d62cb6e 100644
@@ -464,6 +464,7 @@ struct map *machine__new_module(struct machine *machine, u64 start,
 {
 	struct map *map;
 	struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
+	bool compressed;
 
 	if (dso == NULL)
 		return NULL;
@@ -476,6 +477,11 @@ struct map *machine__new_module(struct machine *machine, u64 start,
 		dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
 	else
 		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
+
+	/* _KMODULE_COMP should be next to _KMODULE */
+	if (is_kernel_module(filename, &compressed) && compressed)
+		dso->symtab_type++;
+
 	map_groups__insert(&machine->kmaps, map);
 	return map;
 }
@@ -861,8 +867,14 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
 			struct map *map;
 			char *long_name;
 
-			if (dot == NULL || strcmp(dot, ".ko"))
+			if (dot == NULL)
 				continue;
+
+			/* On some system, modules are compressed like .ko.gz */
+			if (is_supported_compression(dot + 1) &&
+			    is_kmodule_extension(dot - 2))
+				dot -= 3;
+
 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
 				 (int)(dot - dent->d_name), dent->d_name);
 
@@ -1044,6 +1056,11 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 			dot = strrchr(name, '.');
 			if (dot == NULL)
 				goto out_problem;
+			/* On some system, modules are compressed like .ko.gz */
+			if (is_supported_compression(dot + 1))
+				dot -= 3;
+			if (!is_kmodule_extension(dot + 1))
+				goto out_problem;
 			snprintf(short_module_name, sizeof(short_module_name),
 					"[%.*s]", (int)(dot - name), name);
 			strxfrchar(short_module_name, '-', '_');
tools/perf/util/symbol-elf.c +34 -1
index 1e23a5bfb044..efc7eb6b8f0f 100644
@@ -546,6 +546,35 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata)
 	return 0;
 }
 
+static int decompress_kmodule(struct dso *dso, const char *name,
+			      enum dso_binary_type type)
+{
+	int fd;
+	const char *ext = strrchr(name, '.');
+	char tmpbuf[] = "/tmp/perf-kmod-XXXXXX";
+
+	if ((type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP &&
+	     type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP) ||
+	    type != dso->symtab_type)
+		return -1;
+
+	if (!ext || !is_supported_compression(ext + 1))
+		return -1;
+
+	fd = mkstemp(tmpbuf);
+	if (fd < 0)
+		return -1;
+
+	if (!decompress_to_file(ext + 1, name, fd)) {
+		close(fd);
+		fd = -1;
+	}
+
+	unlink(tmpbuf);
+
+	return fd;
+}
+
 bool symsrc__possibly_runtime(struct symsrc *ss)
 {
 	return ss->dynsym || ss->opdsec;
@@ -571,7 +600,11 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
 	Elf *elf;
 	int fd;
 
-	fd = open(name, O_RDONLY);
+	if (dso__needs_decompress(dso))
+		fd = decompress_kmodule(dso, name, type);
+	else
+		fd = open(name, O_RDONLY);
+
 	if (fd < 0)
 		return -1;
 
tools/perf/util/symbol.c +7 -1
index 078331140d8c..c69915c9d5bc 100644
@@ -51,7 +51,9 @@ static enum dso_binary_type binary_type_symtab[] = {
 	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
 	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
 	DSO_BINARY_TYPE__GUEST_KMODULE,
+	DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
 	DSO_BINARY_TYPE__NOT_FOUND,
 };
@@ -1300,7 +1302,9 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
 		return dso->kernel == DSO_TYPE_GUEST_KERNEL;
 
 	case DSO_BINARY_TYPE__GUEST_KMODULE:
+	case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
 		/*
 		 * kernel modules know their symtab type - it's set when
 		 * creating a module dso in machine__new_module().
@@ -1368,7 +1372,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 		return -1;
 
 	kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
-		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
+		dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
+		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
 
 	/*
 	 * Iterate over candidate debug images.
Signature · 1 line
2.1.2
#5 lore raw

Re: [PATCH 1/8] perf tools: Preparation for compressed kernel module support

On Mon, Nov 03, 2014 at 04:27:51PM +0900, Namhyung Kim wrote:

SNIP

Quoted 21 lines
tools/perf/util/dso.c +21 -0
+static int decompress_dummy(const char *input __maybe_unused,
+			    int output __maybe_unused)
+{
+	return -1;
+}
+
+static const struct {
+	const char *fmt;
+	int (*decompress)(const char *input, int output);
+} compressions[] = {
+	{ "gz", decompress_dummy },
+};
+
+bool is_supported_compression(const char *ext)
+{
+	unsigned i;
+
+	for (i = 0; i < ARRAY_SIZE(compressions); i++) {
+		if (!strcmp(ext, compressions[i].fmt))
+			return true;
+	}

tools/perf/util/dso.c int dso__read_binary_type_filename(const struct dso *dso, · line 174

Quoted 10 lines
tools/perf/util/dso.c +10 -0
+	return false;
+}
+
+bool is_kmodule_extension(const char *ext)
+{
+	if (!strcmp(ext, "ko"))
+		return true;
+
+	if (ext[2] == '\0' || (ext[2] == '.' && is_supported_compression(ext+3)))
+		return true;

I got stuck in here.. so any 2 chars string is kernel module extension? plus how do u know ext[3] (or [2]) is valid memory?

thanks,
jirka

author maintainer
#6 lore raw

Re: [PATCH 1/8] perf tools: Preparation for compressed kernel module support

Hi Jiri,

Quoted 29 lines · Jiri Olsa

On Mon, Nov 03, 2014 at 04:27:51PM +0900, Namhyung Kim wrote:

SNIP

Quoted 25 lines
tools/perf/util/dso.c +25 -0
+static int decompress_dummy(const char *input __maybe_unused,
+                         int output __maybe_unused)
+{
+     return -1;
+}
+
+static const struct {
+     const char *fmt;
+     int (*decompress)(const char *input, int output);
+} compressions[] = {
+     { "gz", decompress_dummy },
+};
+
+bool is_supported_compression(const char *ext)
+{
+     unsigned i;
+
+     for (i = 0; i < ARRAY_SIZE(compressions); i++) {
+             if (!strcmp(ext, compressions[i].fmt))
+                     return true;
+     }
+     return false;
+}
+
+bool is_kmodule_extension(const char *ext)
Quoted 8 lines

tools/perf/util/dso.c int dso__read_binary_type_filename(const struct dso *dso, · line 174

Quoted 6 lines
tools/perf/util/dso.c +6 -0
+{
+     if (!strcmp(ext, "ko"))
+             return true;
+
+     if (ext[2] == '\0' || (ext[2] == '.' && is_supported_compression(ext+3)))
+             return true;

I got stuck in here.. so any 2 chars string is kernel module extension?

Oops, the first check should be:

    if (strncmp(ext, "ko", 2))
        return false;
Quoted 1 line

plus how do u know ext[3] (or [2]) is valid memory?

Hmm.. if it ends at ext[0] or ext[1], it should be checked in the first check above. And I check ext[2] first, and then access ext[3] and so on.

Thanks,
Namhyung

author maintainer
#7 lore raw

PATCH 2/8 perf tools: Add gzip decompression support for kernel module

In reply to Namhyung Kim

Now my Archlinux box shows module symbols correctly.

Before:

  $ perf report --stdio
  Failed to open /tmp/perf-3477.map, continuing without symbols
  no symbols found in /usr/bin/date, maybe install a debug package?
  No kallsyms or vmlinux with build-id 7b4ea0a49ae2111925857099aaf05c3246ff33e0 was found
  [drm] with build id 7b4ea0a49ae2111925857099aaf05c3246ff33e0 not found, continuing without symbols
  No kallsyms or vmlinux with build-id edd931629094b660ca9dec09a1b635c8d87aa2ee was found
  [jbd2] with build id edd931629094b660ca9dec09a1b635c8d87aa2ee not found, continuing without symbols
  No kallsyms or vmlinux with build-id a7b1eada671c34933e5610bb920b2ca4945a82c3 was found
  [ext4] with build id a7b1eada671c34933e5610bb920b2ca4945a82c3 not found, continuing without symbols
  No kallsyms or vmlinux with build-id d69511fa3e5840e770336ef45b06c83fef8d74e3 was found
  [scsi_mod] with build id d69511fa3e5840e770336ef45b06c83fef8d74e3 not found, continuing without symbols
  No kallsyms or vmlinux with build-id af0430af13461af058770ee9b87afc07922c2e77 was found
  [libata] with build id af0430af13461af058770ee9b87afc07922c2e77 not found, continuing without symbols
  No kallsyms or vmlinux with build-id aaeedff8160ce631a5f0333591c6ff291201d29f was found
  [libahci] with build id aaeedff8160ce631a5f0333591c6ff291201d29f not found, continuing without symbols
  No kallsyms or vmlinux with build-id c57907712becaf662dc4981824bb372c0441d605 was found
  [mac80211] with build id c57907712becaf662dc4981824bb372c0441d605 not found, continuing without symbols
  No kallsyms or vmlinux with build-id e0589077cc0ec8c3e4c40eb9f2d9e69d236bee8f was found
  [iwldvm] with build id e0589077cc0ec8c3e4c40eb9f2d9e69d236bee8f not found, continuing without symbols
  No kallsyms or vmlinux with build-id 2d86086bf136bf374a2f029cf85a48194f9b950b was found
  [cfg80211] with build id 2d86086bf136bf374a2f029cf85a48194f9b950b not found, continuing without symbols
  No kallsyms or vmlinux with build-id 4493c48599bdb3d91d0f8db5150e0be33fdd9221 was found
  [iwlwifi] with build id 4493c48599bdb3d91d0f8db5150e0be33fdd9221 not found, continuing without symbols
  ...
  #
  # Overhead  Command          Shared Object            Symbol
  # ........  ...............  .......................  ........................................................
  #
       0.03%  swapper          [ext4]                   [k] 0x000000000000fe2e
       0.03%  swapper          [kernel.kallsyms]        [k] account_entity_enqueue
       0.03%  swapper          [ext4]                   [k] 0x000000000000fc2b
       0.03%  irq/50-iwlwifi   [iwlwifi]                [k] 0x000000000000200b
       0.03%  swapper          [kernel.kallsyms]        [k] ktime_add_safe
       0.03%  swapper          [kernel.kallsyms]        [k] elv_completed_request
       0.03%  swapper          [libata]                 [k] 0x0000000000003997
       0.03%  swapper          [libahci]                [k] 0x0000000000001f25
       0.03%  swapper          [kernel.kallsyms]        [k] rb_next
       0.03%  swapper          [kernel.kallsyms]        [k] blk_finish_request
       0.03%  swapper          [ext4]                   [k] 0x0000000000010248
       0.00%  perf             [kernel.kallsyms]        [k] native_write_msr_safe

After:

  $ perf report --stdio
  Failed to open /tmp/perf-3477.map, continuing without symbols
  no symbols found in /usr/bin/tr, maybe install a debug package?
  ...
  #
  # Overhead  Command          Shared Object                Symbol
  # ........  ...............  ...........................  ......................................................
  #
       0.04%  kworker/u16:3    [ext4]                       [k] ext4_read_block_bitmap
       0.03%  kworker/u16:0    [mac80211]                   [k] ieee80211_sta_reset_beacon_monitor
       0.02%  irq/50-iwlwifi   [mac80211]                   [k] ieee80211_get_bssid
       0.02%  firefox          [e1000e]                     [k] __ew32_prepare
       0.02%  swapper          [libahci]                    [k] ahci_handle_port_interrupt
       0.02%  emacs            libglib-2.0.so.0.4000.0      [.] g_mutex_unlock
       0.02%  swapper          [e1000e]                     [k] e1000_clean_tx_irq
       0.02%  dwm              [kernel.kallsyms]            [k] __schedule
       0.02%  gnome-terminal-  [vdso]                       [.] __vdso_clock_gettime
       0.02%  swapper          [e1000e]                     [k] e1000_alloc_rx_buffers
       0.02%  irq/50-iwlwifi   [mac80211]                   [k] ieee80211_rx
       0.01%  firefox          [vdso]                       [.] __vdso_gettimeofday
       0.01%  irq/50-iwlwifi   [iwlwifi]                    [k] iwl_pcie_rxq_restock.part.13
---
 tools/perf/Makefile.perf                     |  7 +++
 tools/perf/config/Makefile                   | 15 +++++-
 tools/perf/config/feature-checks/Makefile    |  6 ++-
 tools/perf/config/feature-checks/test-zlib.c |  9 ++++
 tools/perf/util/dso.c                        | 15 +++---
 tools/perf/util/util.h                       |  5 ++
 tools/perf/util/zlib.c                       | 78 ++++++++++++++++++++++++++++
 7 files changed, 123 insertions(+), 12 deletions(-)
 create mode 100644 tools/perf/config/feature-checks/test-zlib.c
 create mode 100644 tools/perf/util/zlib.c
tools/perf/Makefile.perf +7 -0
index 3caf7dab50e8..31a76ee92c93 100644
@@ -66,6 +66,9 @@ include config/utilities.mak
 #
 # Define NO_PERF_READ_VDSOX32 if you do not want to build perf-read-vdsox32
 # for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode
+#
+# Define NO_ZLIB if you do not want to support compressed kernel modules
+
 
 ifeq ($(srctree),)
 srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -582,6 +585,10 @@ ifndef NO_LIBNUMA
   BUILTIN_OBJS += $(OUTPUT)bench/numa.o
 endif
 
+ifndef NO_ZLIB
+  LIB_OBJS += $(OUTPUT)util/zlib.o
+endif
+
 ifdef ASCIIDOC8
   export ASCIIDOC8
 endif
tools/perf/config/Makefile +13 -2
index 71264e41fa85..79f906c7124e 100644
@@ -200,7 +200,8 @@ CORE_FEATURE_TESTS =			\
 	libunwind			\
 	stackprotector-all		\
 	timerfd				\
-	libdw-dwarf-unwind
+	libdw-dwarf-unwind		\
+	zlib
 
 LIB_FEATURE_TESTS =			\
 	dwarf				\
@@ -214,7 +215,8 @@ LIB_FEATURE_TESTS =			\
 	libpython			\
 	libslang			\
 	libunwind			\
-	libdw-dwarf-unwind
+	libdw-dwarf-unwind		\
+	zlib
 
 VF_FEATURE_TESTS =			\
 	backtrace			\
@@ -604,6 +606,15 @@ ifneq ($(filter -lbfd,$(EXTLIBS)),)
   CFLAGS += -DHAVE_LIBBFD_SUPPORT
 endif
 
+ifndef NO_ZLIB
+  ifeq ($(feature-zlib), 1)
+    CFLAGS += -DHAVE_ZLIB_SUPPORT
+    EXTLIBS += -lz
+  else
+    NO_ZLIB := 1
+  endif
+endif
+
 ifndef NO_BACKTRACE
   ifeq ($(feature-backtrace), 1)
     CFLAGS += -DHAVE_BACKTRACE_SUPPORT
tools/perf/config/feature-checks/Makefile +5 -1
index 7c68ec74a808..9ced746a139a 100644
@@ -29,7 +29,8 @@ FILES=					\
 	test-timerfd.bin		\
 	test-libdw-dwarf-unwind.bin	\
 	test-compile-32.bin		\
-	test-compile-x32.bin
+	test-compile-x32.bin		\
+	test-zlib.bin
 
 CC := $(CROSS_COMPILE)gcc -MD
 PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -139,6 +140,9 @@ FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
 test-compile-x32.bin:
 	$(CC) -mx32 -o $(OUTPUT)$@ test-compile.c
 
+test-zlib.bin:
+	$(BUILD) -lz
+
 -include *.d
 
 ###############################
tools/perf/config/feature-checks/test-zlib.c new file +9 -0
new file mode 100644
index 000000000000..e111fff6240e
@@ -0,0 +1,9 @@
+#include <zlib.h>
+
+int main(void)
+{
+	z_stream zs;
+
+	inflateInit(&zs);
+	return 0;
+}
tools/perf/util/dso.c +6 -9
index 3293e2e21814..43bb3a7ccd81 100644
@@ -141,24 +141,21 @@ int dso__read_binary_type_filename(const struct dso *dso,
 	return ret;
 }
 
-static int decompress_dummy(const char *input __maybe_unused,
-			    int output __maybe_unused)
-{
-	return -1;
-}
-
 static const struct {
 	const char *fmt;
 	int (*decompress)(const char *input, int output);
 } compressions[] = {
-	{ "gz", decompress_dummy },
+#ifdef HAVE_ZLIB_SUPPORT
+	{ "gz", gzip_decompress_to_file },
+#endif
+	{ NULL, },
 };
 
 bool is_supported_compression(const char *ext)
 {
 	unsigned i;
 
-	for (i = 0; i < ARRAY_SIZE(compressions); i++) {
+	for (i = 0; compressions[i].fmt; i++) {
 		if (!strcmp(ext, compressions[i].fmt))
 			return true;
 	}
@@ -197,7 +194,7 @@ bool decompress_to_file(const char *ext, const char *filename, int output_fd)
 {
 	unsigned i;
 
-	for (i = 0; i < ARRAY_SIZE(compressions); i++) {
+	for (i = 0; compressions[i].fmt; i++) {
 		if (!strcmp(ext, compressions[i].fmt))
 			return !compressions[i].decompress(filename,
 							   output_fd);
tools/perf/util/util.h +5 -0
index 80bfdaa0e2a4..7dc44cfe25b3 100644
@@ -351,4 +351,9 @@ void mem_bswap_32(void *src, int byte_size);
 
 const char *get_filename_for_perf_kvm(void);
 bool find_process(const char *name);
+
+#ifdef HAVE_ZLIB_SUPPORT
+int gzip_decompress_to_file(const char *input, int output_fd);
+#endif
+
 #endif /* GIT_COMPAT_UTIL_H */
tools/perf/util/zlib.c new file +78 -0

78 lines not on this page · raw message

Signature · 1 line
2.1.2
#8 lore raw

Re: [PATCH 2/8] perf tools: Add gzip decompression support for kernel module

On Mon, Nov 03, 2014 at 04:27:52PM +0900, Namhyung Kim wrote:

SNIP

Quoted 19 lines

#

  # Overhead  Command          Shared Object                Symbol
  # ........  ...............  ...........................  ......................................................

#

       0.04%  kworker/u16:3    [ext4]                       [k] ext4_read_block_bitmap
       0.03%  kworker/u16:0    [mac80211]                   [k] ieee80211_sta_reset_beacon_monitor
       0.02%  irq/50-iwlwifi   [mac80211]                   [k] ieee80211_get_bssid
       0.02%  firefox          [e1000e]                     [k] __ew32_prepare
       0.02%  swapper          [libahci]                    [k] ahci_handle_port_interrupt
       0.02%  emacs            libglib-2.0.so.0.4000.0      [.] g_mutex_unlock
       0.02%  swapper          [e1000e]                     [k] e1000_clean_tx_irq
       0.02%  dwm              [kernel.kallsyms]            [k] __schedule
       0.02%  gnome-terminal-  [vdso]                       [.] __vdso_clock_gettime
       0.02%  swapper          [e1000e]                     [k] e1000_alloc_rx_buffers
       0.02%  irq/50-iwlwifi   [mac80211]                   [k] ieee80211_rx
       0.01%  firefox          [vdso]                       [.] __vdso_gettimeofday
       0.01%  irq/50-iwlwifi   [iwlwifi]                    [k] iwl_pcie_rxq_restock.part.13
Quoted 6 lines
---
 tools/perf/Makefile.perf                     |  7 +++
 tools/perf/config/Makefile                   | 15 +++++-
 tools/perf/config/feature-checks/Makefile    |  6 ++-
 tools/perf/config/feature-checks/test-zlib.c |  9 ++++

missing update for feature-checks/test-all.c

thanks,
jirka

author maintainer
#9 lore raw

Re: [PATCH 2/8] perf tools: Add gzip decompression support for kernel module

Quoted 23 lines · Jiri Olsa

On Mon, Nov 03, 2014 at 04:27:52PM +0900, Namhyung Kim wrote:

SNIP

Quoted 19 lines

#

  # Overhead  Command          Shared Object                Symbol
  # ........  ...............  ...........................  ......................................................

#

       0.04%  kworker/u16:3    [ext4]                       [k] ext4_read_block_bitmap
       0.03%  kworker/u16:0    [mac80211]                   [k] ieee80211_sta_reset_beacon_monitor
       0.02%  irq/50-iwlwifi   [mac80211]                   [k] ieee80211_get_bssid
       0.02%  firefox          [e1000e]                     [k] __ew32_prepare
       0.02%  swapper          [libahci]                    [k] ahci_handle_port_interrupt
       0.02%  emacs            libglib-2.0.so.0.4000.0      [.] g_mutex_unlock
       0.02%  swapper          [e1000e]                     [k] e1000_clean_tx_irq
       0.02%  dwm              [kernel.kallsyms]            [k] __schedule
       0.02%  gnome-terminal-  [vdso]                       [.] __vdso_clock_gettime
       0.02%  swapper          [e1000e]                     [k] e1000_alloc_rx_buffers
       0.02%  irq/50-iwlwifi   [mac80211]                   [k] ieee80211_rx
       0.01%  firefox          [vdso]                       [.] __vdso_gettimeofday
       0.01%  irq/50-iwlwifi   [iwlwifi]                    [k] iwl_pcie_rxq_restock.part.13
Quoted 8 lines
Quoted 6 lines
---
 tools/perf/Makefile.perf                     |  7 +++
 tools/perf/config/Makefile                   | 15 +++++-
 tools/perf/config/feature-checks/Makefile    |  6 ++-
 tools/perf/config/feature-checks/test-zlib.c |  9 ++++

missing update for feature-checks/test-all.c

Ah, right. Will add. :)

Thanks,
Namhyung

author maintainer
#10 lore raw

PATCH 3/8 perf tools: Get rid of unused dsos__hit_all()

In reply to Namhyung Kim

The dsos__hit_all() and its friends are not used anywhere. Let's get rid of them.

---
 tools/perf/util/header.c | 41 -----------------------------------------
 tools/perf/util/header.h |  2 --
 2 files changed, 43 deletions(-)
tools/perf/util/header.c +0 -41
index 0ecf4a304cbc..e7c762f54bee 100644
@@ -200,47 +200,6 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id,
 	return write_padded(fd, name, name_len + 1, len);
 }
 
-static int __dsos__hit_all(struct list_head *head)
-{
-	struct dso *pos;
-
-	list_for_each_entry(pos, head, node)
-		pos->hit = true;
-
-	return 0;
-}
-
-static int machine__hit_all_dsos(struct machine *machine)
-{
-	int err;
-
-	err = __dsos__hit_all(&machine->kernel_dsos.head);
-	if (err)
-		return err;
-
-	return __dsos__hit_all(&machine->user_dsos.head);
-}
-
-int dsos__hit_all(struct perf_session *session)
-{
-	struct rb_node *nd;
-	int err;
-
-	err = machine__hit_all_dsos(&session->machines.host);
-	if (err)
-		return err;
-
-	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
-		struct machine *pos = rb_entry(nd, struct machine, rb_node);
-
-		err = machine__hit_all_dsos(pos);
-		if (err)
-			return err;
-	}
-
-	return 0;
-}
-
 static int __dsos__write_buildid_table(struct list_head *head,
 				       struct machine *machine,
 				       pid_t pid, u16 misc, int fd)
tools/perf/util/header.h +0 -2
index 8f5cbaea64a5..d08cfe499404 100644
@@ -151,8 +151,6 @@ int perf_event__process_build_id(struct perf_tool *tool,
 				 struct perf_session *session);
 bool is_perf_magic(u64 magic);
 
-int dsos__hit_all(struct perf_session *session);
-
 /*
  * arch specific callback
  */
Signature · 1 line
2.1.2
reviewer
#11 lore raw

Re: [PATCH 3/8] perf tools: Get rid of unused dsos__hit_all()

Quoted 2 lines · Namhyung Kim

The dsos__hit_all() and its friends are not used anywhere. Let's get rid of them.

They were added for Intel PT preparation. Intel PT is still on its way, so they are still needed. Note the commit was:

commit 1f625b0b3dd641b74ba21640a1fea19a3dd893a2

Author: Adrian Hunter <[email protected]>
Date:   Tue Jul 22 16:17:23 2014 +0300

perf tools: Add dsos__hit_all()

Add ability to mark all dsos as hit.

This is needed in the case of Instruction Tracing. It takes so long to decode an Instruction Trace that it is not worth doing just to determine which dsos are hit. A later patch takes this into use.

Quoted 73 lines
---
 tools/perf/util/header.c | 41 -----------------------------------------
 tools/perf/util/header.h |  2 --
 2 files changed, 43 deletions(-)
tools/perf/util/header.c +0 -41
index 0ecf4a304cbc..e7c762f54bee 100644
@@ -200,47 +200,6 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id,
 	return write_padded(fd, name, name_len + 1, len);
 }
 
-static int __dsos__hit_all(struct list_head *head)
-{
-	struct dso *pos;
-
-	list_for_each_entry(pos, head, node)
-		pos->hit = true;
-
-	return 0;
-}
-
-static int machine__hit_all_dsos(struct machine *machine)
-{
-	int err;
-
-	err = __dsos__hit_all(&machine->kernel_dsos.head);
-	if (err)
-		return err;
-
-	return __dsos__hit_all(&machine->user_dsos.head);
-}
-
-int dsos__hit_all(struct perf_session *session)
-{
-	struct rb_node *nd;
-	int err;
-
-	err = machine__hit_all_dsos(&session->machines.host);
-	if (err)
-		return err;
-
-	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
-		struct machine *pos = rb_entry(nd, struct machine, rb_node);
-
-		err = machine__hit_all_dsos(pos);
-		if (err)
-			return err;
-	}
-
-	return 0;
-}
-
 static int __dsos__write_buildid_table(struct list_head *head,
 				       struct machine *machine,
 				       pid_t pid, u16 misc, int fd)
tools/perf/util/header.h +0 -2
index 8f5cbaea64a5..d08cfe499404 100644
@@ -151,8 +151,6 @@ int perf_event__process_build_id(struct perf_tool *tool,
 				 struct perf_session *session);
 bool is_perf_magic(u64 magic);
 
-int dsos__hit_all(struct perf_session *session);
-
 /*
  * arch specific callback
  */
author maintainer
#12 lore raw

Re: [PATCH 3/8] perf tools: Get rid of unused dsos__hit_all()

Hi Adrian,

Quoted 11 lines · Adrian Hunter
Quoted 2 lines · Namhyung Kim

The dsos__hit_all() and its friends are not used anywhere. Let's get rid of them.

They were added for Intel PT preparation. Intel PT is still on its way, so they are still needed. Note the commit was:

commit 1f625b0b3dd641b74ba21640a1fea19a3dd893a2

Author: Adrian Hunter <[email protected]>
Date:   Tue Jul 22 16:17:23 2014 +0300
Quoted 7 lines

perf tools: Add dsos__hit_all()

Add ability to mark all dsos as hit.

This is needed in the case of Instruction Tracing. It takes so long to decode an Instruction Trace that it is not worth doing just to determine which dsos are hit. A later patch takes this into use.

Oops, didn't notice. Sorry for not checking the commit log. So how about moving it into util/build-id.c then?

Thanks,
Namhyung

reviewer
#13 lore raw

Re: [PATCH 3/8] perf tools: Get rid of unused dsos__hit_all()

Quoted 16 lines · Namhyung Kim

Hi Adrian,

Quoted 13 lines · Adrian Hunter
Quoted 2 lines · Namhyung Kim

The dsos__hit_all() and its friends are not used anywhere. Let's get rid of them.

They were added for Intel PT preparation. Intel PT is still on its way, so they are still needed. Note the commit was:

commit 1f625b0b3dd641b74ba21640a1fea19a3dd893a2

Author: Adrian Hunter <[email protected]>
Date:   Tue Jul 22 16:17:23 2014 +0300

perf tools: Add dsos__hit_all()

Quoted 8 lines
Quoted 5 lines

Add ability to mark all dsos as hit.

This is needed in the case of Instruction Tracing. It takes so long to decode an Instruction Trace that it is not worth doing just to determine which dsos are hit. A later patch takes this into use.

Oops, didn't notice. Sorry for not checking the commit log. So how about moving it into util/build-id.c then?

OK by me.

author maintainer
#14 lore raw

PATCH 4/8 perf tools: Rename dsos__write_buildid_table()

In reply to Namhyung Kim

The dsos__write_buildid_table() is not use struct dso and it mostly uses perf_session struct. So rename it to perf_session__write_buildid_ table() so that it corresponds to other related functions such as perf_session__read_build_ids() and perf_session__cache_build_ids().

---
 tools/perf/util/header.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
tools/perf/util/header.c +2 -4
index e7c762f54bee..6e1ff5d64276 100644
@@ -256,10 +256,8 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
 	return err;
 }
 
-static int dsos__write_buildid_table(struct perf_header *header, int fd)
+static int perf_session__write_buildid_table(struct perf_session *session, int fd)
 {
-	struct perf_session *session = container_of(header,
-			struct perf_session, header);
 	struct rb_node *nd;
 	int err = machine__write_buildid_table(&session->machines.host, fd);
 
@@ -482,7 +480,7 @@ static int write_build_id(int fd, struct perf_header *h,
 	if (!perf_session__read_build_ids(session, true))
 		return -1;
 
-	err = dsos__write_buildid_table(h, fd);
+	err = perf_session__write_buildid_table(session, fd);
 	if (err < 0) {
 		pr_debug("failed to write buildid table\n");
 		return err;
Signature · 1 line
2.1.2
author maintainer
#15 lore raw

PATCH 5/8 perf build-id: Move build-id related functions to util/build-id.c

In reply to Namhyung Kim

It'd be better managing those functions in a separate place as util/header.c file is already big.

It now exports following 3 functions to others:

  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);
---
 tools/perf/util/build-id.c | 293 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/build-id.h |   5 +
 tools/perf/util/header.c   | 296 +--------------------------------------------
 tools/perf/util/header.h   |   4 +
 4 files changed, 303 insertions(+), 295 deletions(-)
tools/perf/util/build-id.c +293 -0
index 2e7c68e39330..acc50509f1d5 100644
@@ -15,6 +15,8 @@
 #include "debug.h"
 #include "session.h"
 #include "tool.h"
+#include "header.h"
+#include "vdso.h"
 
 int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
 			   union perf_event *event,
@@ -105,3 +107,294 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
 			 build_id_hex, build_id_hex + 2);
 	return bf;
 }
+
+#define dsos__for_each_with_build_id(pos, head)	\
+	list_for_each_entry(pos, head, node)	\
+		if (!pos->has_build_id)		\
+			continue;		\
+		else
+
+static int write_buildid(const char *name, size_t name_len, u8 *build_id,
+			 pid_t pid, u16 misc, int fd)
+{
+	int err;
+	struct build_id_event b;
+	size_t len;
+
+	len = name_len + 1;
+	len = PERF_ALIGN(len, NAME_ALIGN);
+
+	memset(&b, 0, sizeof(b));
+	memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
+	b.pid = pid;
+	b.header.misc = misc;
+	b.header.size = sizeof(b) + len;
+
+	err = writen(fd, &b, sizeof(b));
+	if (err < 0)
+		return err;
+
+	return write_padded(fd, name, name_len + 1, len);
+}
+
+static int __dsos__write_buildid_table(struct list_head *head,
+				       struct machine *machine,
+				       pid_t pid, u16 misc, int fd)
+{
+	char nm[PATH_MAX];
+	struct dso *pos;
+
+	dsos__for_each_with_build_id(pos, head) {
+		int err;
+		const char *name;
+		size_t name_len;
+
+		if (!pos->hit)
+			continue;
+
+		if (dso__is_vdso(pos)) {
+			name = pos->short_name;
+			name_len = pos->short_name_len + 1;
+		} else if (dso__is_kcore(pos)) {
+			machine__mmap_name(machine, nm, sizeof(nm));
+			name = nm;
+			name_len = strlen(nm) + 1;
+		} else {
+			name = pos->long_name;
+			name_len = pos->long_name_len + 1;
+		}
+
+		err = write_buildid(name, name_len, pos->build_id,
+				    pid, misc, fd);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int machine__write_buildid_table(struct machine *machine, int fd)
+{
+	int err;
+	u16 kmisc = PERF_RECORD_MISC_KERNEL,
+	    umisc = PERF_RECORD_MISC_USER;
+
+	if (!machine__is_host(machine)) {
+		kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
+		umisc = PERF_RECORD_MISC_GUEST_USER;
+	}
+
+	err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine,
+					  machine->pid, kmisc, fd);
+	if (err == 0)
+		err = __dsos__write_buildid_table(&machine->user_dsos.head,
+						  machine, machine->pid, umisc,
+						  fd);
+	return err;
+}
+
+int perf_session__write_buildid_table(struct perf_session *session, int fd)
+{
+	struct rb_node *nd;
+	int err = machine__write_buildid_table(&session->machines.host, fd);
+
+	if (err)
+		return err;
+
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+		struct machine *pos = rb_entry(nd, struct machine, rb_node);
+		err = machine__write_buildid_table(pos, fd);
+		if (err)
+			break;
+	}
+	return err;
+}
+
+int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
+			  const char *name, bool is_kallsyms, bool is_vdso)
+{
+	const size_t size = PATH_MAX;
+	char *realname, *filename = zalloc(size),
+	     *linkname = zalloc(size), *targetname;
+	int len, err = -1;
+	bool slash = is_kallsyms || is_vdso;
+
+	if (is_kallsyms) {
+		if (symbol_conf.kptr_restrict) {
+			pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
+			err = 0;
+			goto out_free;
+		}
+		realname = (char *) name;
+	} else
+		realname = realpath(name, NULL);
+
+	if (realname == NULL || filename == NULL || linkname == NULL)
+		goto out_free;
+
+	len = scnprintf(filename, size, "%s%s%s",
+		       debugdir, slash ? "/" : "",
+		       is_vdso ? DSO__NAME_VDSO : realname);
+	if (mkdir_p(filename, 0755))
+		goto out_free;
+
+	snprintf(filename + len, size - len, "/%s", sbuild_id);
+
+	if (access(filename, F_OK)) {
+		if (is_kallsyms) {
+			 if (copyfile("/proc/kallsyms", filename))
+				goto out_free;
+		} else if (link(realname, filename) && copyfile(name, filename))
+			goto out_free;
+	}
+
+	len = scnprintf(linkname, size, "%s/.build-id/%.2s",
+		       debugdir, sbuild_id);
+
+	if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
+		goto out_free;
+
+	snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
+	targetname = filename + strlen(debugdir) - 5;
+	memcpy(targetname, "../..", 5);
+
+	if (symlink(targetname, linkname) == 0)
+		err = 0;
+out_free:
+	if (!is_kallsyms)
+		free(realname);
+	free(filename);
+	free(linkname);
+	return err;
+}
+
+static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
+				 const char *name, const char *debugdir,
+				 bool is_kallsyms, bool is_vdso)
+{
+	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
+
+	build_id__sprintf(build_id, build_id_size, sbuild_id);
+
+	return build_id_cache__add_s(sbuild_id, debugdir, name,
+				     is_kallsyms, is_vdso);
+}
+
+int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
+{
+	const size_t size = PATH_MAX;
+	char *filename = zalloc(size),
+	     *linkname = zalloc(size);
+	int err = -1;
+
+	if (filename == NULL || linkname == NULL)
+		goto out_free;
+
+	snprintf(linkname, size, "%s/.build-id/%.2s/%s",
+		 debugdir, sbuild_id, sbuild_id + 2);
+
+	if (access(linkname, F_OK))
+		goto out_free;
+
+	if (readlink(linkname, filename, size - 1) < 0)
+		goto out_free;
+
+	if (unlink(linkname))
+		goto out_free;
+
+	/*
+	 * Since the link is relative, we must make it absolute:
+	 */
+	snprintf(linkname, size, "%s/.build-id/%.2s/%s",
+		 debugdir, sbuild_id, filename);
+
+	if (unlink(linkname))
+		goto out_free;
+
+	err = 0;
+out_free:
+	free(filename);
+	free(linkname);
+	return err;
+}
+
+static int dso__cache_build_id(struct dso *dso, struct machine *machine,
+			       const char *debugdir)
+{
+	bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
+	bool is_vdso = dso__is_vdso(dso);
+	const char *name = dso->long_name;
+	char nm[PATH_MAX];
+
+	if (dso__is_kcore(dso)) {
+		is_kallsyms = true;
+		machine__mmap_name(machine, nm, sizeof(nm));
+		name = nm;
+	}
+	return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
+				     debugdir, is_kallsyms, is_vdso);
+}
+
+static int __dsos__cache_build_ids(struct list_head *head,
+				   struct machine *machine, const char *debugdir)
+{
+	struct dso *pos;
+	int err = 0;
+
+	dsos__for_each_with_build_id(pos, head)
+		if (dso__cache_build_id(pos, machine, debugdir))
+			err = -1;
+
+	return err;
+}
+
+static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
+{
+	int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine,
+					  debugdir);
+	ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine,
+				       debugdir);
+	return ret;
+}
+
+int perf_session__cache_build_ids(struct perf_session *session)
+{
+	struct rb_node *nd;
+	int ret;
+	char debugdir[PATH_MAX];
+
+	snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
+
+	if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
+		return -1;
+
+	ret = machine__cache_build_ids(&session->machines.host, debugdir);
+
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+		struct machine *pos = rb_entry(nd, struct machine, rb_node);
+		ret |= machine__cache_build_ids(pos, debugdir);
+	}
+	return ret ? -1 : 0;
+}
+
+static bool machine__read_build_ids(struct machine *machine, bool with_hits)
+{
+	bool ret;
+
+	ret  = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits);
+	ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits);
+	return ret;
+}
+
+bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
+{
+	struct rb_node *nd;
+	bool ret = machine__read_build_ids(&session->machines.host, with_hits);
+
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+		struct machine *pos = rb_entry(nd, struct machine, rb_node);
+		ret |= machine__read_build_ids(pos, with_hits);
+	}
+
+	return ret;
+}
tools/perf/util/build-id.h +5 -0
index ae392561470b..e24477cc92f2 100644
@@ -15,4 +15,9 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
 int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
 			   struct perf_sample *sample, struct perf_evsel *evsel,
 			   struct machine *machine);
+
+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);
+
 #endif
tools/perf/util/header.c +1 -295

308 lines not on this page · raw message

tools/perf/util/header.h +4 -0
index d08cfe499404..785be448ca37 100644
@@ -151,6 +151,10 @@ int perf_event__process_build_id(struct perf_tool *tool,
 				 struct perf_session *session);
 bool is_perf_magic(u64 magic);
 
+#define NAME_ALIGN 64
+
+int write_padded(int fd, const void *bf, size_t count, size_t count_aligned);
+
 /*
  * arch specific callback
  */
Signature · 1 line
2.1.2
author maintainer
#16 lore raw

PATCH 6/8 perf record: Do not save pathname in ./debug/.build-id directory for vmlinux

In reply to Namhyung Kim

When perf record finishes a session recording, it then pre-process samples in order to write build-id info from actually used DSOs. During this process it'll call map__load() for kernel map, and it ends up calling dso__load_vmlinux_path() which replaces dso->long_name.

But this function checks kernel's build-id before searching vmlinux path so it'll have the cryptic name which can be confusing to users IMHO.

This patch adds a flag to skip the build-id check during record, so it'll have a vmlinux path for the kernel dso->long_name.

Before:

  # perf record -va sleep 3
  mmap size 528384B
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.196 MB perf.data (~8545 samples) ]
  Looking at the vmlinux_path (7 entries long)
  Using /home/namhyung/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551 for symbols

After:

  # perf record -va sleep 3
  mmap size 528384B
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.193 MB perf.data (~8432 samples) ]
  Looking at the vmlinux_path (7 entries long)
  Using /lib/modules/3.16.4-1-ARCH/build/vmlinux for symbols
---
 tools/perf/builtin-record.c | 11 +++++++++++
 tools/perf/util/symbol.c    | 11 ++++++-----
 tools/perf/util/symbol.h    |  1 +
 3 files changed, 18 insertions(+), 5 deletions(-)
tools/perf/builtin-record.c +11 -0
index 5091a27e6d28..582c4da155ea 100644
@@ -200,6 +200,17 @@ static int process_buildids(struct record *rec)
 	if (size == 0)
 		return 0;
 
+	/*
+	 * During this process, it'll load kernel map and replace the
+	 * dso->long_name to a real pathname it found.  In this case
+	 * we prefer the vmlinux path like
+	 *   /lib/modules/3.16.4/build/vmlinux
+	 *
+	 * rather than build-id path (in debug directory).
+	 *   $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
+	 */
+	symbol_conf.ignore_vmlinux_buildid = true;
+
 	return __perf_session__process_events(session, start,
 					      size - start,
 					      size, &build_id__mark_dso_hit_ops);
tools/perf/util/symbol.c +6 -5
index c69915c9d5bc..c24c5b83156c 100644
@@ -1511,12 +1511,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
 			   symbol_filter_t filter)
 {
 	int i, err = 0;
-	char *filename;
+	char *filename = NULL;
 
-	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
-		 vmlinux_path__nr_entries + 1);
-
-	filename = dso__build_id_filename(dso, NULL, 0);
+	if (!symbol_conf.ignore_vmlinux_buildid)
+		filename = dso__build_id_filename(dso, NULL, 0);
 	if (filename != NULL) {
 		err = dso__load_vmlinux(dso, map, filename, true, filter);
 		if (err > 0)
@@ -1524,6 +1522,9 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
 		free(filename);
 	}
 
+	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
+		 vmlinux_path__nr_entries + 1);
+
 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
 		if (err > 0)
tools/perf/util/symbol.h +1 -0
index eb2c19bf8d90..ded3ca7266de 100644
@@ -105,6 +105,7 @@ struct symbol_conf {
 	unsigned short	nr_events;
 	bool		try_vmlinux_path,
 			ignore_vmlinux,
+			ignore_vmlinux_buildid,
 			show_kernel_path,
 			use_modules,
 			sort_by_name,
Signature · 1 line
2.1.2
author maintainer
#17 lore raw

PATCH 7/8 perf tools: Fix build-id matching on vmlinux

In reply to Namhyung Kim

There's a problem on finding correct kernel symbols when perf report runs on a different kernel. Although a part of the problem was solved by the prior commit 0a7e6d1b6844 ("perf tools: Check recorded kernel version when finding vmlinux"), there's a remaining problem still.

When perf records samples, it synthesizes the kernel map using machine__mmap_name() and ref_reloc_sym like "[kernel.kallsyms]_text". You can easily see it using 'perf report -D' command.

After finishing record, it goes through the recorded events to find maps/dsos actually used. And then record build-id info of them.

During this process, it needs to load symbols in a dso and it'd call dso__load_vmlinux_path() since the default value of the symbol_conf. try_vmlinux_path is true. However it changes dso->long_name to a real path of the vmlinux file (e.g. /lib/modules/3.16.4/build/vmlinux) if one is running on a custom kernel.

It resulted in that perf report reads the build-id of the vmlinux, but cannot use it since it only knows about the [kernel.kallsyms] map. It then falls back to possible vmlinux paths by using the recorded kernel version (in case of a recent version) or a running kernel silently.

Even with the recent tools, this still has a possibility of breaking the result. As the build directory is a symbolic link, if one built a new kernel in the same directory with different source/config, the old link to vmlinux will point the new file. So it's absolutely needed to use build-id when finding a kernel image.

In this patch, it's now changed to try to search a kernel dso in the existing dso list which was constructed during build-id table parsing so it'll always have a build-id. If not found, search "[kernel.kallsyms]".

Before:

  $ perf report
  # Children      Self  Command  Shared Object      Symbol
  # ........  ........  .......  .................  ...............................
  #
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] set_curr_task_rt
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] native_calibrate_tsc
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] tsc_refine_calibration_work
      71.87%    71.87%  swapper  [kernel.kallsyms]  [k] module_finalize
   ...

After (for the same perf.data):

      72.15%     0.00%  swapper  vmlinux  [k] cpu_startup_entry
      72.15%     0.00%  swapper  vmlinux  [k] arch_cpu_idle
      72.15%     0.00%  swapper  vmlinux  [k] default_idle
      71.87%    71.87%  swapper  vmlinux  [k] native_safe_halt

...

---
 tools/perf/util/header.c  |  2 +-
 tools/perf/util/machine.c | 16 ++++++++++++++--
 2 files changed, 15 insertions(+), 3 deletions(-)
tools/perf/util/header.c +1 -1
index 3e2c156d9c64..76442caca37e 100644
@@ -1269,7 +1269,7 @@ static int __event_process_build_id(struct build_id_event *bev,
 
 		dso__set_build_id(dso, &bev->build_id);
 
-		if (filename[0] == '[')
+		if (!is_kernel_module(filename, NULL))
 			dso->kernel = dso_type;
 
 		build_id__sprintf(dso->build_id, sizeof(dso->build_id),
tools/perf/util/machine.c +14 -2
index 946c7d62cb6e..53f90e9c65fe 100644
@@ -1085,8 +1085,20 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 		 * Should be there already, from the build-id table in
 		 * the header.
 		 */
-		struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
-						     kmmap_prefix);
+		struct dso *kernel = NULL;
+		struct dso *dso;
+
+		list_for_each_entry(dso, &machine->kernel_dsos.head, node) {
+			if (is_kernel_module(dso->long_name, NULL))
+				continue;
+
+			kernel = dso;
+			break;
+		}
+
+		if (kernel == NULL)
+			kernel = __dsos__findnew(&machine->kernel_dsos,
+						 kmmap_prefix);
 		if (kernel == NULL)
 			goto out_problem;
 
Signature · 1 line
2.1.2
author maintainer
#18 lore raw

PATCH 8/8 perf tools: Make vmlinux short name more like kallsyms short name

In reply to Namhyung Kim

The previous patch changed kernel dso name from '[kernel.kallsyms]' to vmlinux. However it might add confusion to old users accustomed to the old name. So change the short name to '[kernel.vmlinux]' to reduce such confusion.

Before:

  # Overhead  Command         Shared Object            Symbol
  # ........  ..............  .......................  ...............................
  #
       9.83%  swapper         vmlinux                  [k] intel_idle
       4.10%  awk             libc-2.20.so             [.] __strcmp_sse2
       1.86%  sed             libc-2.20.so             [.] __strcmp_sse2
       1.78%  netctl-auto     libc-2.20.so             [.] __strcmp_sse2
       1.23%  netctl-auto     libc-2.20.so             [.] __mbrtowc
       1.21%  firefox         libxul.so                [.] 0x00000000024b62bd
       1.20%  swapper         vmlinux                  [k] cpuidle_enter_state
       1.03%  sleep           vmlinux                  [k] copy_user_generic_unrolled

After:

  # Overhead  Command         Shared Object            Symbol
  # ........  ..............  .......................  ...............................
  #
       9.83%  swapper         [kernel.vmlinux]         [k] intel_idle
       4.10%  awk             libc-2.20.so             [.] __strcmp_sse2
       1.86%  sed             libc-2.20.so             [.] __strcmp_sse2
       1.78%  netctl-auto     libc-2.20.so             [.] __strcmp_sse2
       1.23%  netctl-auto     libc-2.20.so             [.] __mbrtowc
       1.21%  firefox         libxul.so                [.] 0x00000000024b62bd
       1.20%  swapper         [kernel.vmlinux]         [k] cpuidle_enter_state
       1.03%  sleep           [kernel.vmlinux]         [k] copy_user_generic_unrolled
---
 tools/perf/util/machine.c | 3 +++
 1 file changed, 3 insertions(+)
tools/perf/util/machine.c +3 -0
index 53f90e9c65fe..52e94902afb1 100644
@@ -1106,6 +1106,9 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 		if (__machine__create_kernel_maps(machine, kernel) < 0)
 			goto out_problem;
 
+		if (strstr(dso->long_name, "vmlinux"))
+			dso__set_short_name(dso, "[kernel.vmlinux]", false);
+
 		machine__set_kernel_mmap_len(machine, event);
 
 		/*
Signature · 1 line
2.1.2
author maintainer
#19 lore raw

cover perf tools: Fix build-id matching on vmlinux (v6)

Hello,

This patchset addresses possible problem on kernel symbol matching. Since commit 5b7ba82a7591 ("perf symbols: Load kernel maps before using"), when perf record process samples to construct build-id table, it loads kernel map and it replaces dso->long_name. But perf report doesn't know about name other than [kernel.kallsyms] it failed to find existing kernel dso and falls back to running kernel's kallsyms.

So it's possible to report incorrect symbols for kernel functions if it runs on a different kernel:

Before:

  $ perf report
  # Children      Self  Command  Shared Object      Symbol
  # ........  ........  .......  .................  ...............................
  #
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] set_curr_task_rt
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] native_calibrate_tsc
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] tsc_refine_calibration_work
      71.87%    71.87%  swapper  [kernel.kallsyms]  [k] module_finalize
   ...

After (for the same perf.data):

      72.15%     0.00%  swapper  [kernel.vmlinux]  [k] cpu_startup_entry
      72.15%     0.00%  swapper  [kernel.vmlinux]  [k] arch_cpu_idle
      72.15%     0.00%  swapper  [kernel.vmlinux]  [k] default_idle
      71.87%    71.87%  swapper  [kernel.vmlinux]  [k] native_safe_halt

In this patch, it's now changed to try to search a kernel dso in the existing dso list which was constructed during build-id table parsing so it'll always have a build-id. If not found, search "[kernel.kallsyms]".

The patch 1-2 are to support module compression as some distro (e.g. Arch) already does it. The patch 3-5 are cleanup of build-id handling functions. The patch 6-7 are the main change of this series and finally patch 8 is just for suggestion which can be squashed into the previous patch or simply dropped.

* changes from v5)
- keep dsos__hit_all() in util/build-id.c (Adrian)
- fix bug in is_kernel_module function (Jiri)
- add missing zlib test to test-all.c (Jiri)
- move disable_buildid_cache function also

You can get it on 'perf/vmlinux-v6' branch in my tree:

git://git.kernel.org/pub/scm/linux/kernel/git/namhyung/linux-perf.git

Any comments are welcome, thanks
Namhyung

Cc Adrian Hunter <[email protected]>

Namhyung Kim (8):
perf tools: Preparation for compressed kernel module support perf tools: Add gzip decompression support for kernel module perf tools: Rename dsos__write_buildid_table()
perf build-id: Move build-id related functions to util/build-id.c perf tools: Move disable_buildid_cache() to util/build-id.c perf record: Do not save pathname in ./debug/.build-id directory for
vmlinux
perf tools: Fix build-id matching on vmlinux
perf tools: Make vmlinux short name more like kallsyms short name

 tools/perf/Makefile.perf                     |   7 +
 tools/perf/builtin-record.c                  |  11 +
 tools/perf/config/Makefile                   |  15 +-
 tools/perf/config/feature-checks/Makefile    |   6 +-
 tools/perf/config/feature-checks/test-all.c  |   5 +
 tools/perf/config/feature-checks/test-zlib.c |   9 +
 tools/perf/util/build-id.c                   | 345 ++++++++++++++++++++++++++
 tools/perf/util/build-id.h                   |  12 +
 tools/perf/util/dso.c                        |  71 ++++++
 tools/perf/util/dso.h                        |   7 +
 tools/perf/util/header.c                     | 353 +--------------------------
 tools/perf/util/header.h                     |   8 +-
 tools/perf/util/machine.c                    |  38 ++-
 tools/perf/util/symbol-elf.c                 |  35 ++-
 tools/perf/util/symbol.c                     |  19 +-
 tools/perf/util/symbol.h                     |   1 +
 tools/perf/util/util.h                       |   6 +-
 tools/perf/util/zlib.c                       |  78 ++++++
 18 files changed, 658 insertions(+), 368 deletions(-)
 create mode 100644 tools/perf/config/feature-checks/test-zlib.c
 create mode 100644 tools/perf/util/zlib.c
Signature · 1 line
2.1.2
author maintainer
#20 lore raw

PATCH 1/8 perf tools: Preparation for compressed kernel module support

This patch adds basic support to handle compressed kernel module as some distro (such as Archlinux) carries on it now. The actual work using compression library will be added later.

---
 tools/perf/util/dso.c        | 75 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/dso.h        |  7 +++++
 tools/perf/util/machine.c    | 19 ++++++++++-
 tools/perf/util/symbol-elf.c | 35 ++++++++++++++++++++-
 tools/perf/util/symbol.c     |  8 ++++-
 5 files changed, 141 insertions(+), 3 deletions(-)
tools/perf/util/dso.c +75 -0
index 0247acfdfaca..36a607cf8f50 100644
@@ -21,8 +21,10 @@ char dso__symtab_origin(const struct dso *dso)
 		[DSO_BINARY_TYPE__BUILDID_DEBUGINFO]		= 'b',
 		[DSO_BINARY_TYPE__SYSTEM_PATH_DSO]		= 'd',
 		[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE]		= 'K',
+		[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP]	= 'm',
 		[DSO_BINARY_TYPE__GUEST_KALLSYMS]		= 'g',
 		[DSO_BINARY_TYPE__GUEST_KMODULE]		= 'G',
+		[DSO_BINARY_TYPE__GUEST_KMODULE_COMP]		= 'M',
 		[DSO_BINARY_TYPE__GUEST_VMLINUX]		= 'V',
 	};
 
@@ -112,11 +114,13 @@ int dso__read_binary_type_filename(const struct dso *dso,
 		break;
 
 	case DSO_BINARY_TYPE__GUEST_KMODULE:
+	case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
 		path__join3(filename, size, symbol_conf.symfs,
 			    root_dir, dso->long_name);
 		break;
 
 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
 		__symbol__join_symfs(filename, size, dso->long_name);
 		break;
 
@@ -137,6 +141,77 @@ int dso__read_binary_type_filename(const struct dso *dso,
 	return ret;
 }
 
+static int decompress_dummy(const char *input __maybe_unused,
+			    int output __maybe_unused)
+{
+	return -1;
+}
+
+static const struct {
+	const char *fmt;
+	int (*decompress)(const char *input, int output);
+} compressions[] = {
+	{ "gz", decompress_dummy },
+	{ NULL, },
+};
+
+bool is_supported_compression(const char *ext)
+{
+	unsigned i;
+
+	for (i = 0; compressions[i].fmt; i++) {
+		if (!strcmp(ext, compressions[i].fmt))
+			return true;
+	}
+	return false;
+}
+
+bool is_kmodule_extension(const char *ext)
+{
+	if (strncmp(ext, "ko", 2))
+		return false;
+
+	if (ext[2] == '\0' || (ext[2] == '.' && is_supported_compression(ext+3)))
+		return true;
+
+	return false;
+}
+
+bool is_kernel_module(const char *pathname, bool *compressed)
+{
+	const char *ext = strrchr(pathname, '.');
+
+	if (ext == NULL)
+		return false;
+
+	if (is_supported_compression(ext + 1)) {
+		if (compressed)
+			*compressed = true;
+		ext -= 3;
+	} else if (compressed)
+		*compressed = false;
+
+	return is_kmodule_extension(ext + 1);
+}
+
+bool decompress_to_file(const char *ext, const char *filename, int output_fd)
+{
+	unsigned i;
+
+	for (i = 0; compressions[i].fmt; i++) {
+		if (!strcmp(ext, compressions[i].fmt))
+			return !compressions[i].decompress(filename,
+							   output_fd);
+	}
+	return false;
+}
+
+bool dso__needs_decompress(struct dso *dso)
+{
+	return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
+}
+
 /*
  * Global list of open DSOs and the counter.
  */
tools/perf/util/dso.h +7 -0
index a316e4af321f..3782c82c6e44 100644
@@ -22,7 +22,9 @@ enum dso_binary_type {
 	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
 	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
 	DSO_BINARY_TYPE__GUEST_KMODULE,
+	DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
 	DSO_BINARY_TYPE__KCORE,
 	DSO_BINARY_TYPE__GUEST_KCORE,
 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
@@ -185,6 +187,11 @@ int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
 char dso__symtab_origin(const struct dso *dso);
 int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
 				   char *root_dir, char *filename, size_t size);
+bool is_supported_compression(const char *ext);
+bool is_kmodule_extension(const char *ext);
+bool is_kernel_module(const char *pathname, bool *compressed);
+bool decompress_to_file(const char *ext, const char *filename, int output_fd);
+bool dso__needs_decompress(struct dso *dso);
 
 /*
  * The dso__data_* external interface provides following functions:
tools/perf/util/machine.c +18 -1
index 51a630301afa..946c7d62cb6e 100644
@@ -464,6 +464,7 @@ struct map *machine__new_module(struct machine *machine, u64 start,
 {
 	struct map *map;
 	struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
+	bool compressed;
 
 	if (dso == NULL)
 		return NULL;
@@ -476,6 +477,11 @@ struct map *machine__new_module(struct machine *machine, u64 start,
 		dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
 	else
 		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
+
+	/* _KMODULE_COMP should be next to _KMODULE */
+	if (is_kernel_module(filename, &compressed) && compressed)
+		dso->symtab_type++;
+
 	map_groups__insert(&machine->kmaps, map);
 	return map;
 }
@@ -861,8 +867,14 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
 			struct map *map;
 			char *long_name;
 
-			if (dot == NULL || strcmp(dot, ".ko"))
+			if (dot == NULL)
 				continue;
+
+			/* On some system, modules are compressed like .ko.gz */
+			if (is_supported_compression(dot + 1) &&
+			    is_kmodule_extension(dot - 2))
+				dot -= 3;
+
 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
 				 (int)(dot - dent->d_name), dent->d_name);
 
@@ -1044,6 +1056,11 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 			dot = strrchr(name, '.');
 			if (dot == NULL)
 				goto out_problem;
+			/* On some system, modules are compressed like .ko.gz */
+			if (is_supported_compression(dot + 1))
+				dot -= 3;
+			if (!is_kmodule_extension(dot + 1))
+				goto out_problem;
 			snprintf(short_module_name, sizeof(short_module_name),
 					"[%.*s]", (int)(dot - name), name);
 			strxfrchar(short_module_name, '-', '_');
tools/perf/util/symbol-elf.c +34 -1
index 1e23a5bfb044..efc7eb6b8f0f 100644
@@ -546,6 +546,35 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata)
 	return 0;
 }
 
+static int decompress_kmodule(struct dso *dso, const char *name,
+			      enum dso_binary_type type)
+{
+	int fd;
+	const char *ext = strrchr(name, '.');
+	char tmpbuf[] = "/tmp/perf-kmod-XXXXXX";
+
+	if ((type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP &&
+	     type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP) ||
+	    type != dso->symtab_type)
+		return -1;
+
+	if (!ext || !is_supported_compression(ext + 1))
+		return -1;
+
+	fd = mkstemp(tmpbuf);
+	if (fd < 0)
+		return -1;
+
+	if (!decompress_to_file(ext + 1, name, fd)) {
+		close(fd);
+		fd = -1;
+	}
+
+	unlink(tmpbuf);
+
+	return fd;
+}
+
 bool symsrc__possibly_runtime(struct symsrc *ss)
 {
 	return ss->dynsym || ss->opdsec;
@@ -571,7 +600,11 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
 	Elf *elf;
 	int fd;
 
-	fd = open(name, O_RDONLY);
+	if (dso__needs_decompress(dso))
+		fd = decompress_kmodule(dso, name, type);
+	else
+		fd = open(name, O_RDONLY);
+
 	if (fd < 0)
 		return -1;
 
tools/perf/util/symbol.c +7 -1
index 078331140d8c..c69915c9d5bc 100644
@@ -51,7 +51,9 @@ static enum dso_binary_type binary_type_symtab[] = {
 	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
 	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
 	DSO_BINARY_TYPE__GUEST_KMODULE,
+	DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
 	DSO_BINARY_TYPE__NOT_FOUND,
 };
@@ -1300,7 +1302,9 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
 		return dso->kernel == DSO_TYPE_GUEST_KERNEL;
 
 	case DSO_BINARY_TYPE__GUEST_KMODULE:
+	case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
 		/*
 		 * kernel modules know their symtab type - it's set when
 		 * creating a module dso in machine__new_module().
@@ -1368,7 +1372,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 		return -1;
 
 	kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
-		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
+		dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
+		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
 
 	/*
 	 * Iterate over candidate debug images.
Signature · 1 line
2.1.2
Acked-by on v1 1/8
#21 lore raw

Re: [PATCH 1/8] perf tools: Preparation for compressed kernel module support

Quoted 5 lines · Namhyung Kim

This patch adds basic support to handle compressed kernel module as some distro (such as Archlinux) carries on it now. The actual work using compression library will be added later.

thanks,
jirka

#22 lore raw

[tip:perf/core] perf symbols: Preparation for compressed kernel module support

In reply to Namhyung Kim
perf symbols: Preparation for compressed kernel module support
Commit-ID:  c00c48fc6e6ef63d83a7417923a06b08089bb34b
Gitweb:     http://git.kernel.org/tip/c00c48fc6e6ef63d83a7417923a06b08089bb34b
Author:     Namhyung Kim <[email protected]>
AuthorDate: Tue, 4 Nov 2014 10:14:27 +0900
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 4 Nov 2014 10:15:53 -0300

perf symbols: Preparation for compressed kernel module support

This patch adds basic support to handle compressed kernel module as some distro (such as Archlinux) carries on it now. The actual work using compression library will be added later.

---
 tools/perf/util/dso.c        | 75 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/dso.h        |  7 +++++
 tools/perf/util/machine.c    | 19 ++++++++++-
 tools/perf/util/symbol-elf.c | 35 ++++++++++++++++++++-
 tools/perf/util/symbol.c     |  8 ++++-
 5 files changed, 141 insertions(+), 3 deletions(-)
tools/perf/util/dso.c +75 -0
index 0247acf..36a607c 100644
@@ -21,8 +21,10 @@ char dso__symtab_origin(const struct dso *dso)
 		[DSO_BINARY_TYPE__BUILDID_DEBUGINFO]		= 'b',
 		[DSO_BINARY_TYPE__SYSTEM_PATH_DSO]		= 'd',
 		[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE]		= 'K',
+		[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP]	= 'm',
 		[DSO_BINARY_TYPE__GUEST_KALLSYMS]		= 'g',
 		[DSO_BINARY_TYPE__GUEST_KMODULE]		= 'G',
+		[DSO_BINARY_TYPE__GUEST_KMODULE_COMP]		= 'M',
 		[DSO_BINARY_TYPE__GUEST_VMLINUX]		= 'V',
 	};
 
@@ -112,11 +114,13 @@ int dso__read_binary_type_filename(const struct dso *dso,
 		break;
 
 	case DSO_BINARY_TYPE__GUEST_KMODULE:
+	case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
 		path__join3(filename, size, symbol_conf.symfs,
 			    root_dir, dso->long_name);
 		break;
 
 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
 		__symbol__join_symfs(filename, size, dso->long_name);
 		break;
 
@@ -137,6 +141,77 @@ int dso__read_binary_type_filename(const struct dso *dso,
 	return ret;
 }
 
+static int decompress_dummy(const char *input __maybe_unused,
+			    int output __maybe_unused)
+{
+	return -1;
+}
+
+static const struct {
+	const char *fmt;
+	int (*decompress)(const char *input, int output);
+} compressions[] = {
+	{ "gz", decompress_dummy },
+	{ NULL, },
+};
+
+bool is_supported_compression(const char *ext)
+{
+	unsigned i;
+
+	for (i = 0; compressions[i].fmt; i++) {
+		if (!strcmp(ext, compressions[i].fmt))
+			return true;
+	}
+	return false;
+}
+
+bool is_kmodule_extension(const char *ext)
+{
+	if (strncmp(ext, "ko", 2))
+		return false;
+
+	if (ext[2] == '\0' || (ext[2] == '.' && is_supported_compression(ext+3)))
+		return true;
+
+	return false;
+}
+
+bool is_kernel_module(const char *pathname, bool *compressed)
+{
+	const char *ext = strrchr(pathname, '.');
+
+	if (ext == NULL)
+		return false;
+
+	if (is_supported_compression(ext + 1)) {
+		if (compressed)
+			*compressed = true;
+		ext -= 3;
+	} else if (compressed)
+		*compressed = false;
+
+	return is_kmodule_extension(ext + 1);
+}
+
+bool decompress_to_file(const char *ext, const char *filename, int output_fd)
+{
+	unsigned i;
+
+	for (i = 0; compressions[i].fmt; i++) {
+		if (!strcmp(ext, compressions[i].fmt))
+			return !compressions[i].decompress(filename,
+							   output_fd);
+	}
+	return false;
+}
+
+bool dso__needs_decompress(struct dso *dso)
+{
+	return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
+}
+
 /*
  * Global list of open DSOs and the counter.
  */
tools/perf/util/dso.h +7 -0
index a316e4a..3782c82 100644
@@ -22,7 +22,9 @@ enum dso_binary_type {
 	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
 	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
 	DSO_BINARY_TYPE__GUEST_KMODULE,
+	DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
 	DSO_BINARY_TYPE__KCORE,
 	DSO_BINARY_TYPE__GUEST_KCORE,
 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
@@ -185,6 +187,11 @@ int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
 char dso__symtab_origin(const struct dso *dso);
 int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
 				   char *root_dir, char *filename, size_t size);
+bool is_supported_compression(const char *ext);
+bool is_kmodule_extension(const char *ext);
+bool is_kernel_module(const char *pathname, bool *compressed);
+bool decompress_to_file(const char *ext, const char *filename, int output_fd);
+bool dso__needs_decompress(struct dso *dso);
 
 /*
  * The dso__data_* external interface provides following functions:
tools/perf/util/machine.c +18 -1
index 51a6303..946c7d6 100644
@@ -464,6 +464,7 @@ struct map *machine__new_module(struct machine *machine, u64 start,
 {
 	struct map *map;
 	struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
+	bool compressed;
 
 	if (dso == NULL)
 		return NULL;
@@ -476,6 +477,11 @@ struct map *machine__new_module(struct machine *machine, u64 start,
 		dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
 	else
 		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
+
+	/* _KMODULE_COMP should be next to _KMODULE */
+	if (is_kernel_module(filename, &compressed) && compressed)
+		dso->symtab_type++;
+
 	map_groups__insert(&machine->kmaps, map);
 	return map;
 }
@@ -861,8 +867,14 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
 			struct map *map;
 			char *long_name;
 
-			if (dot == NULL || strcmp(dot, ".ko"))
+			if (dot == NULL)
 				continue;
+
+			/* On some system, modules are compressed like .ko.gz */
+			if (is_supported_compression(dot + 1) &&
+			    is_kmodule_extension(dot - 2))
+				dot -= 3;
+
 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
 				 (int)(dot - dent->d_name), dent->d_name);
 
@@ -1044,6 +1056,11 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 			dot = strrchr(name, '.');
 			if (dot == NULL)
 				goto out_problem;
+			/* On some system, modules are compressed like .ko.gz */
+			if (is_supported_compression(dot + 1))
+				dot -= 3;
+			if (!is_kmodule_extension(dot + 1))
+				goto out_problem;
 			snprintf(short_module_name, sizeof(short_module_name),
 					"[%.*s]", (int)(dot - name), name);
 			strxfrchar(short_module_name, '-', '_');
tools/perf/util/symbol-elf.c +34 -1
index 1e23a5b..efc7eb6 100644
@@ -546,6 +546,35 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata)
 	return 0;
 }
 
+static int decompress_kmodule(struct dso *dso, const char *name,
+			      enum dso_binary_type type)
+{
+	int fd;
+	const char *ext = strrchr(name, '.');
+	char tmpbuf[] = "/tmp/perf-kmod-XXXXXX";
+
+	if ((type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP &&
+	     type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP) ||
+	    type != dso->symtab_type)
+		return -1;
+
+	if (!ext || !is_supported_compression(ext + 1))
+		return -1;
+
+	fd = mkstemp(tmpbuf);
+	if (fd < 0)
+		return -1;
+
+	if (!decompress_to_file(ext + 1, name, fd)) {
+		close(fd);
+		fd = -1;
+	}
+
+	unlink(tmpbuf);
+
+	return fd;
+}
+
 bool symsrc__possibly_runtime(struct symsrc *ss)
 {
 	return ss->dynsym || ss->opdsec;
@@ -571,7 +600,11 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
 	Elf *elf;
 	int fd;
 
-	fd = open(name, O_RDONLY);
+	if (dso__needs_decompress(dso))
+		fd = decompress_kmodule(dso, name, type);
+	else
+		fd = open(name, O_RDONLY);
+
 	if (fd < 0)
 		return -1;
 
tools/perf/util/symbol.c +7 -1
index 0783311..c69915c 100644
@@ -51,7 +51,9 @@ static enum dso_binary_type binary_type_symtab[] = {
 	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
 	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
 	DSO_BINARY_TYPE__GUEST_KMODULE,
+	DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
 	DSO_BINARY_TYPE__NOT_FOUND,
 };
@@ -1300,7 +1302,9 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
 		return dso->kernel == DSO_TYPE_GUEST_KERNEL;
 
 	case DSO_BINARY_TYPE__GUEST_KMODULE:
+	case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
 		/*
 		 * kernel modules know their symtab type - it's set when
 		 * creating a module dso in machine__new_module().
@@ -1368,7 +1372,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 		return -1;
 
 	kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
-		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
+		dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
+		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
 
 	/*
 	 * Iterate over candidate debug images.
author maintainer
#23 lore raw

PATCH 2/8 perf tools: Add gzip decompression support for kernel module

In reply to Namhyung Kim

Now my Archlinux box shows module symbols correctly.

Before:

  $ perf report --stdio
  Failed to open /tmp/perf-3477.map, continuing without symbols
  no symbols found in /usr/bin/date, maybe install a debug package?
  No kallsyms or vmlinux with build-id 7b4ea0a49ae2111925857099aaf05c3246ff33e0 was found
  [drm] with build id 7b4ea0a49ae2111925857099aaf05c3246ff33e0 not found, continuing without symbols
  No kallsyms or vmlinux with build-id edd931629094b660ca9dec09a1b635c8d87aa2ee was found
  [jbd2] with build id edd931629094b660ca9dec09a1b635c8d87aa2ee not found, continuing without symbols
  No kallsyms or vmlinux with build-id a7b1eada671c34933e5610bb920b2ca4945a82c3 was found
  [ext4] with build id a7b1eada671c34933e5610bb920b2ca4945a82c3 not found, continuing without symbols
  No kallsyms or vmlinux with build-id d69511fa3e5840e770336ef45b06c83fef8d74e3 was found
  [scsi_mod] with build id d69511fa3e5840e770336ef45b06c83fef8d74e3 not found, continuing without symbols
  No kallsyms or vmlinux with build-id af0430af13461af058770ee9b87afc07922c2e77 was found
  [libata] with build id af0430af13461af058770ee9b87afc07922c2e77 not found, continuing without symbols
  No kallsyms or vmlinux with build-id aaeedff8160ce631a5f0333591c6ff291201d29f was found
  [libahci] with build id aaeedff8160ce631a5f0333591c6ff291201d29f not found, continuing without symbols
  No kallsyms or vmlinux with build-id c57907712becaf662dc4981824bb372c0441d605 was found
  [mac80211] with build id c57907712becaf662dc4981824bb372c0441d605 not found, continuing without symbols
  No kallsyms or vmlinux with build-id e0589077cc0ec8c3e4c40eb9f2d9e69d236bee8f was found
  [iwldvm] with build id e0589077cc0ec8c3e4c40eb9f2d9e69d236bee8f not found, continuing without symbols
  No kallsyms or vmlinux with build-id 2d86086bf136bf374a2f029cf85a48194f9b950b was found
  [cfg80211] with build id 2d86086bf136bf374a2f029cf85a48194f9b950b not found, continuing without symbols
  No kallsyms or vmlinux with build-id 4493c48599bdb3d91d0f8db5150e0be33fdd9221 was found
  [iwlwifi] with build id 4493c48599bdb3d91d0f8db5150e0be33fdd9221 not found, continuing without symbols
  ...
  #
  # Overhead  Command          Shared Object            Symbol
  # ........  ...............  .......................  ........................................................
  #
       0.03%  swapper          [ext4]                   [k] 0x000000000000fe2e
       0.03%  swapper          [kernel.kallsyms]        [k] account_entity_enqueue
       0.03%  swapper          [ext4]                   [k] 0x000000000000fc2b
       0.03%  irq/50-iwlwifi   [iwlwifi]                [k] 0x000000000000200b
       0.03%  swapper          [kernel.kallsyms]        [k] ktime_add_safe
       0.03%  swapper          [kernel.kallsyms]        [k] elv_completed_request
       0.03%  swapper          [libata]                 [k] 0x0000000000003997
       0.03%  swapper          [libahci]                [k] 0x0000000000001f25
       0.03%  swapper          [kernel.kallsyms]        [k] rb_next
       0.03%  swapper          [kernel.kallsyms]        [k] blk_finish_request
       0.03%  swapper          [ext4]                   [k] 0x0000000000010248
       0.00%  perf             [kernel.kallsyms]        [k] native_write_msr_safe

After:

  $ perf report --stdio
  Failed to open /tmp/perf-3477.map, continuing without symbols
  no symbols found in /usr/bin/tr, maybe install a debug package?
  ...
  #
  # Overhead  Command          Shared Object                Symbol
  # ........  ...............  ...........................  ......................................................
  #
       0.04%  kworker/u16:3    [ext4]                       [k] ext4_read_block_bitmap
       0.03%  kworker/u16:0    [mac80211]                   [k] ieee80211_sta_reset_beacon_monitor
       0.02%  irq/50-iwlwifi   [mac80211]                   [k] ieee80211_get_bssid
       0.02%  firefox          [e1000e]                     [k] __ew32_prepare
       0.02%  swapper          [libahci]                    [k] ahci_handle_port_interrupt
       0.02%  emacs            libglib-2.0.so.0.4000.0      [.] g_mutex_unlock
       0.02%  swapper          [e1000e]                     [k] e1000_clean_tx_irq
       0.02%  dwm              [kernel.kallsyms]            [k] __schedule
       0.02%  gnome-terminal-  [vdso]                       [.] __vdso_clock_gettime
       0.02%  swapper          [e1000e]                     [k] e1000_alloc_rx_buffers
       0.02%  irq/50-iwlwifi   [mac80211]                   [k] ieee80211_rx
       0.01%  firefox          [vdso]                       [.] __vdso_gettimeofday
       0.01%  irq/50-iwlwifi   [iwlwifi]                    [k] iwl_pcie_rxq_restock.part.13
---
 tools/perf/Makefile.perf                     |  7 +++
 tools/perf/config/Makefile                   | 15 +++++-
 tools/perf/config/feature-checks/Makefile    |  6 ++-
 tools/perf/config/feature-checks/test-all.c  |  5 ++
 tools/perf/config/feature-checks/test-zlib.c |  9 ++++
 tools/perf/util/dso.c                        | 10 ++--
 tools/perf/util/util.h                       |  5 ++
 tools/perf/util/zlib.c                       | 78 ++++++++++++++++++++++++++++
 8 files changed, 125 insertions(+), 10 deletions(-)
 create mode 100644 tools/perf/config/feature-checks/test-zlib.c
 create mode 100644 tools/perf/util/zlib.c
tools/perf/Makefile.perf +7 -0
index 3caf7dab50e8..31a76ee92c93 100644
@@ -66,6 +66,9 @@ include config/utilities.mak
 #
 # Define NO_PERF_READ_VDSOX32 if you do not want to build perf-read-vdsox32
 # for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode
+#
+# Define NO_ZLIB if you do not want to support compressed kernel modules
+
 
 ifeq ($(srctree),)
 srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -582,6 +585,10 @@ ifndef NO_LIBNUMA
   BUILTIN_OBJS += $(OUTPUT)bench/numa.o
 endif
 
+ifndef NO_ZLIB
+  LIB_OBJS += $(OUTPUT)util/zlib.o
+endif
+
 ifdef ASCIIDOC8
   export ASCIIDOC8
 endif
tools/perf/config/Makefile +13 -2
index 71264e41fa85..79f906c7124e 100644
@@ -200,7 +200,8 @@ CORE_FEATURE_TESTS =			\
 	libunwind			\
 	stackprotector-all		\
 	timerfd				\
-	libdw-dwarf-unwind
+	libdw-dwarf-unwind		\
+	zlib
 
 LIB_FEATURE_TESTS =			\
 	dwarf				\
@@ -214,7 +215,8 @@ LIB_FEATURE_TESTS =			\
 	libpython			\
 	libslang			\
 	libunwind			\
-	libdw-dwarf-unwind
+	libdw-dwarf-unwind		\
+	zlib
 
 VF_FEATURE_TESTS =			\
 	backtrace			\
@@ -604,6 +606,15 @@ ifneq ($(filter -lbfd,$(EXTLIBS)),)
   CFLAGS += -DHAVE_LIBBFD_SUPPORT
 endif
 
+ifndef NO_ZLIB
+  ifeq ($(feature-zlib), 1)
+    CFLAGS += -DHAVE_ZLIB_SUPPORT
+    EXTLIBS += -lz
+  else
+    NO_ZLIB := 1
+  endif
+endif
+
 ifndef NO_BACKTRACE
   ifeq ($(feature-backtrace), 1)
     CFLAGS += -DHAVE_BACKTRACE_SUPPORT
tools/perf/config/feature-checks/Makefile +5 -1
index 7c68ec74a808..9ced746a139a 100644
@@ -29,7 +29,8 @@ FILES=					\
 	test-timerfd.bin		\
 	test-libdw-dwarf-unwind.bin	\
 	test-compile-32.bin		\
-	test-compile-x32.bin
+	test-compile-x32.bin		\
+	test-zlib.bin
 
 CC := $(CROSS_COMPILE)gcc -MD
 PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -139,6 +140,9 @@ FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
 test-compile-x32.bin:
 	$(CC) -mx32 -o $(OUTPUT)$@ test-compile.c
 
+test-zlib.bin:
+	$(BUILD) -lz
+
 -include *.d
 
 ###############################
tools/perf/config/feature-checks/test-all.c +5 -0
index a7d022e161c0..652e0098eba6 100644
@@ -93,6 +93,10 @@
 # include "test-sync-compare-and-swap.c"
 #undef main
 
+#define main main_test_zlib
+# include "test-zlib.c"
+#undef main
+
 int main(int argc, char *argv[])
 {
 	main_test_libpython();
@@ -116,6 +120,7 @@ int main(int argc, char *argv[])
 	main_test_stackprotector_all();
 	main_test_libdw_dwarf_unwind();
 	main_test_sync_compare_and_swap(argc, argv);
+	main_test_zlib();
 
 	return 0;
 }
tools/perf/config/feature-checks/test-zlib.c new file +9 -0
new file mode 100644
index 000000000000..e111fff6240e
@@ -0,0 +1,9 @@
+#include <zlib.h>
+
+int main(void)
+{
+	z_stream zs;
+
+	inflateInit(&zs);
+	return 0;
+}
tools/perf/util/dso.c +3 -7
index 36a607cf8f50..3bf67fc34ed9 100644
@@ -141,17 +141,13 @@ int dso__read_binary_type_filename(const struct dso *dso,
 	return ret;
 }
 
-static int decompress_dummy(const char *input __maybe_unused,
-			    int output __maybe_unused)
-{
-	return -1;
-}
-
 static const struct {
 	const char *fmt;
 	int (*decompress)(const char *input, int output);
 } compressions[] = {
-	{ "gz", decompress_dummy },
+#ifdef HAVE_ZLIB_SUPPORT
+	{ "gz", gzip_decompress_to_file },
+#endif
 	{ NULL, },
 };
 
tools/perf/util/util.h +5 -0
index 80bfdaa0e2a4..7dc44cfe25b3 100644
@@ -351,4 +351,9 @@ void mem_bswap_32(void *src, int byte_size);
 
 const char *get_filename_for_perf_kvm(void);
 bool find_process(const char *name);
+
+#ifdef HAVE_ZLIB_SUPPORT
+int gzip_decompress_to_file(const char *input, int output_fd);
+#endif
+
 #endif /* GIT_COMPAT_UTIL_H */
tools/perf/util/zlib.c new file +78 -0

78 lines not on this page · raw message

Signature · 1 line
2.1.2
Acked-by on v1 2/8
#24 lore raw

Re: [PATCH 2/8] perf tools: Add gzip decompression support for kernel module

Quoted 1 line · Namhyung Kim

Now my Archlinux box shows module symbols correctly.

with the last comment addressed (-lz in test-all.bin):

thanks,
jirka

Quoted 334 lines

Before:

  $ perf report --stdio
  Failed to open /tmp/perf-3477.map, continuing without symbols
  no symbols found in /usr/bin/date, maybe install a debug package?
  No kallsyms or vmlinux with build-id 7b4ea0a49ae2111925857099aaf05c3246ff33e0 was found
  [drm] with build id 7b4ea0a49ae2111925857099aaf05c3246ff33e0 not found, continuing without symbols
  No kallsyms or vmlinux with build-id edd931629094b660ca9dec09a1b635c8d87aa2ee was found
  [jbd2] with build id edd931629094b660ca9dec09a1b635c8d87aa2ee not found, continuing without symbols
  No kallsyms or vmlinux with build-id a7b1eada671c34933e5610bb920b2ca4945a82c3 was found
  [ext4] with build id a7b1eada671c34933e5610bb920b2ca4945a82c3 not found, continuing without symbols
  No kallsyms or vmlinux with build-id d69511fa3e5840e770336ef45b06c83fef8d74e3 was found
  [scsi_mod] with build id d69511fa3e5840e770336ef45b06c83fef8d74e3 not found, continuing without symbols
  No kallsyms or vmlinux with build-id af0430af13461af058770ee9b87afc07922c2e77 was found
  [libata] with build id af0430af13461af058770ee9b87afc07922c2e77 not found, continuing without symbols
  No kallsyms or vmlinux with build-id aaeedff8160ce631a5f0333591c6ff291201d29f was found
  [libahci] with build id aaeedff8160ce631a5f0333591c6ff291201d29f not found, continuing without symbols
  No kallsyms or vmlinux with build-id c57907712becaf662dc4981824bb372c0441d605 was found
  [mac80211] with build id c57907712becaf662dc4981824bb372c0441d605 not found, continuing without symbols
  No kallsyms or vmlinux with build-id e0589077cc0ec8c3e4c40eb9f2d9e69d236bee8f was found
  [iwldvm] with build id e0589077cc0ec8c3e4c40eb9f2d9e69d236bee8f not found, continuing without symbols
  No kallsyms or vmlinux with build-id 2d86086bf136bf374a2f029cf85a48194f9b950b was found
  [cfg80211] with build id 2d86086bf136bf374a2f029cf85a48194f9b950b not found, continuing without symbols
  No kallsyms or vmlinux with build-id 4493c48599bdb3d91d0f8db5150e0be33fdd9221 was found
  [iwlwifi] with build id 4493c48599bdb3d91d0f8db5150e0be33fdd9221 not found, continuing without symbols
  ...
  #
  # Overhead  Command          Shared Object            Symbol
  # ........  ...............  .......................  ........................................................
  #
       0.03%  swapper          [ext4]                   [k] 0x000000000000fe2e
       0.03%  swapper          [kernel.kallsyms]        [k] account_entity_enqueue
       0.03%  swapper          [ext4]                   [k] 0x000000000000fc2b
       0.03%  irq/50-iwlwifi   [iwlwifi]                [k] 0x000000000000200b
       0.03%  swapper          [kernel.kallsyms]        [k] ktime_add_safe
       0.03%  swapper          [kernel.kallsyms]        [k] elv_completed_request
       0.03%  swapper          [libata]                 [k] 0x0000000000003997
       0.03%  swapper          [libahci]                [k] 0x0000000000001f25
       0.03%  swapper          [kernel.kallsyms]        [k] rb_next
       0.03%  swapper          [kernel.kallsyms]        [k] blk_finish_request
       0.03%  swapper          [ext4]                   [k] 0x0000000000010248
       0.00%  perf             [kernel.kallsyms]        [k] native_write_msr_safe

After:

  $ perf report --stdio
  Failed to open /tmp/perf-3477.map, continuing without symbols
  no symbols found in /usr/bin/tr, maybe install a debug package?
  ...
  #
  # Overhead  Command          Shared Object                Symbol
  # ........  ...............  ...........................  ......................................................
  #
       0.04%  kworker/u16:3    [ext4]                       [k] ext4_read_block_bitmap
       0.03%  kworker/u16:0    [mac80211]                   [k] ieee80211_sta_reset_beacon_monitor
       0.02%  irq/50-iwlwifi   [mac80211]                   [k] ieee80211_get_bssid
       0.02%  firefox          [e1000e]                     [k] __ew32_prepare
       0.02%  swapper          [libahci]                    [k] ahci_handle_port_interrupt
       0.02%  emacs            libglib-2.0.so.0.4000.0      [.] g_mutex_unlock
       0.02%  swapper          [e1000e]                     [k] e1000_clean_tx_irq
       0.02%  dwm              [kernel.kallsyms]            [k] __schedule
       0.02%  gnome-terminal-  [vdso]                       [.] __vdso_clock_gettime
       0.02%  swapper          [e1000e]                     [k] e1000_alloc_rx_buffers
       0.02%  irq/50-iwlwifi   [mac80211]                   [k] ieee80211_rx
       0.01%  firefox          [vdso]                       [.] __vdso_gettimeofday
       0.01%  irq/50-iwlwifi   [iwlwifi]                    [k] iwl_pcie_rxq_restock.part.13
---
 tools/perf/Makefile.perf                     |  7 +++
 tools/perf/config/Makefile                   | 15 +++++-
 tools/perf/config/feature-checks/Makefile    |  6 ++-
 tools/perf/config/feature-checks/test-all.c  |  5 ++
 tools/perf/config/feature-checks/test-zlib.c |  9 ++++
 tools/perf/util/dso.c                        | 10 ++--
 tools/perf/util/util.h                       |  5 ++
 tools/perf/util/zlib.c                       | 78 ++++++++++++++++++++++++++++
 8 files changed, 125 insertions(+), 10 deletions(-)
 create mode 100644 tools/perf/config/feature-checks/test-zlib.c
 create mode 100644 tools/perf/util/zlib.c
tools/perf/Makefile.perf +7 -0
index 3caf7dab50e8..31a76ee92c93 100644
@@ -66,6 +66,9 @@ include config/utilities.mak
 #
 # Define NO_PERF_READ_VDSOX32 if you do not want to build perf-read-vdsox32
 # for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode
+#
+# Define NO_ZLIB if you do not want to support compressed kernel modules
+
 
 ifeq ($(srctree),)
 srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -582,6 +585,10 @@ ifndef NO_LIBNUMA
   BUILTIN_OBJS += $(OUTPUT)bench/numa.o
 endif
 
+ifndef NO_ZLIB
+  LIB_OBJS += $(OUTPUT)util/zlib.o
+endif
+
 ifdef ASCIIDOC8
   export ASCIIDOC8
 endif
tools/perf/config/Makefile +13 -2
index 71264e41fa85..79f906c7124e 100644
@@ -200,7 +200,8 @@ CORE_FEATURE_TESTS =			\
 	libunwind			\
 	stackprotector-all		\
 	timerfd				\
-	libdw-dwarf-unwind
+	libdw-dwarf-unwind		\
+	zlib
 
 LIB_FEATURE_TESTS =			\
 	dwarf				\
@@ -214,7 +215,8 @@ LIB_FEATURE_TESTS =			\
 	libpython			\
 	libslang			\
 	libunwind			\
-	libdw-dwarf-unwind
+	libdw-dwarf-unwind		\
+	zlib
 
 VF_FEATURE_TESTS =			\
 	backtrace			\
@@ -604,6 +606,15 @@ ifneq ($(filter -lbfd,$(EXTLIBS)),)
   CFLAGS += -DHAVE_LIBBFD_SUPPORT
 endif
 
+ifndef NO_ZLIB
+  ifeq ($(feature-zlib), 1)
+    CFLAGS += -DHAVE_ZLIB_SUPPORT
+    EXTLIBS += -lz
+  else
+    NO_ZLIB := 1
+  endif
+endif
+
 ifndef NO_BACKTRACE
   ifeq ($(feature-backtrace), 1)
     CFLAGS += -DHAVE_BACKTRACE_SUPPORT
tools/perf/config/feature-checks/Makefile +5 -1
index 7c68ec74a808..9ced746a139a 100644
@@ -29,7 +29,8 @@ FILES=					\
 	test-timerfd.bin		\
 	test-libdw-dwarf-unwind.bin	\
 	test-compile-32.bin		\
-	test-compile-x32.bin
+	test-compile-x32.bin		\
+	test-zlib.bin
 
 CC := $(CROSS_COMPILE)gcc -MD
 PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -139,6 +140,9 @@ FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
 test-compile-x32.bin:
 	$(CC) -mx32 -o $(OUTPUT)$@ test-compile.c
 
+test-zlib.bin:
+	$(BUILD) -lz
+
 -include *.d
 
 ###############################
tools/perf/config/feature-checks/test-all.c +5 -0
index a7d022e161c0..652e0098eba6 100644
@@ -93,6 +93,10 @@
 # include "test-sync-compare-and-swap.c"
 #undef main
 
+#define main main_test_zlib
+# include "test-zlib.c"
+#undef main
+
 int main(int argc, char *argv[])
 {
 	main_test_libpython();
@@ -116,6 +120,7 @@ int main(int argc, char *argv[])
 	main_test_stackprotector_all();
 	main_test_libdw_dwarf_unwind();
 	main_test_sync_compare_and_swap(argc, argv);
+	main_test_zlib();
 
 	return 0;
 }
tools/perf/config/feature-checks/test-zlib.c new file +9 -0
new file mode 100644
index 000000000000..e111fff6240e
@@ -0,0 +1,9 @@
+#include <zlib.h>
+
+int main(void)
+{
+	z_stream zs;
+
+	inflateInit(&zs);
+	return 0;
+}
tools/perf/util/dso.c +3 -7
index 36a607cf8f50..3bf67fc34ed9 100644
@@ -141,17 +141,13 @@ int dso__read_binary_type_filename(const struct dso *dso,
 	return ret;
 }
 
-static int decompress_dummy(const char *input __maybe_unused,
-			    int output __maybe_unused)
-{
-	return -1;
-}
-
 static const struct {
 	const char *fmt;
 	int (*decompress)(const char *input, int output);
 } compressions[] = {
-	{ "gz", decompress_dummy },
+#ifdef HAVE_ZLIB_SUPPORT
+	{ "gz", gzip_decompress_to_file },
+#endif
 	{ NULL, },
 };
 
tools/perf/util/util.h +5 -0
index 80bfdaa0e2a4..7dc44cfe25b3 100644
@@ -351,4 +351,9 @@ void mem_bswap_32(void *src, int byte_size);
 
 const char *get_filename_for_perf_kvm(void);
 bool find_process(const char *name);
+
+#ifdef HAVE_ZLIB_SUPPORT
+int gzip_decompress_to_file(const char *input, int output_fd);
+#endif
+
 #endif /* GIT_COMPAT_UTIL_H */
tools/perf/util/zlib.c new file +78 -0
new file mode 100644
index 000000000000..495a449fc25c
@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <zlib.h>
+
+#include "util/util.h"
+#include "util/debug.h"
+
+
+#define CHUNK_SIZE  16384
+
+int gzip_decompress_to_file(const char *input, int output_fd)
+{
+	int ret = Z_STREAM_ERROR;
+	int input_fd;
+	void *ptr;
+	int len;
+	struct stat stbuf;
+	unsigned char buf[CHUNK_SIZE];
+	z_stream zs = {
+		.zalloc		= Z_NULL,
+		.zfree		= Z_NULL,
+		.opaque		= Z_NULL,
+		.avail_in	= 0,
+		.next_in	= Z_NULL,
+	};
+
+	input_fd = open(input, O_RDONLY);
+	if (input_fd < 0)
+		return -1;
+
+	if (fstat(input_fd, &stbuf) < 0)
+		goto out_close;
+
+	ptr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, input_fd, 0);
+	if (ptr == MAP_FAILED)
+		goto out_close;
+
+	if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK)
+		goto out_unmap;
+
+	zs.next_in = ptr;
+	zs.avail_in = stbuf.st_size;
+
+	do {
+		zs.next_out = buf;
+		zs.avail_out = CHUNK_SIZE;
+
+		ret = inflate(&zs, Z_NO_FLUSH);
+		switch (ret) {
+		case Z_NEED_DICT:
+			ret = Z_DATA_ERROR;
+			/* fall through */
+		case Z_DATA_ERROR:
+		case Z_MEM_ERROR:
+			goto out;
+		default:
+			break;
+		}
+
+		len = CHUNK_SIZE - zs.avail_out;
+		if (writen(output_fd, buf, len) != len) {
+			ret = Z_DATA_ERROR;
+			goto out;
+		}
+
+	} while (ret != Z_STREAM_END);
+
+out:
+	inflateEnd(&zs);
+out_unmap:
+	munmap(ptr, stbuf.st_size);
+out_close:
+	close(input_fd);
+
+	return ret == Z_STREAM_END ? 0 : -1;
+}
Signature · 1 line
2.1.2
maintainer Applied
#25 lore raw

Re: [PATCH 2/8] perf tools: Add gzip decompression support for kernel module

Em Tue, Nov 04, 2014 at 12:00:17PM +0100, Jiri Olsa escreveu:

Quoted 6 lines · Namhyung Kim
Quoted 1 line

Now my Archlinux box shows module symbols correctly.

with the last comment addressed (-lz in test-all.bin):

Thanks, applied the series.

- Arnaldo

author maintainer
#26 lore raw

Re: [PATCH 2/8] perf tools: Add gzip decompression support for kernel module

Quoted 9 lines · Arnaldo Carvalho de Melo

Em Tue, Nov 04, 2014 at 12:00:17PM +0100, Jiri Olsa escreveu:

Quoted 6 lines · Namhyung Kim
Quoted 1 line

Now my Archlinux box shows module symbols correctly.

with the last comment addressed (-lz in test-all.bin):

Thanks, applied the series.

Oh-oh, wait. I need to add -lz to test-all.bin target in Makefile so you need to apply this hunk, sorry. :-/

tools/perf/config/feature-checks/Mak renamed from tools/perf/config/feature-checks/Makefile +0 -0

efile
index 7c68ec74a808..53f19b5dbc37 100644

tools/perf/config/feature-checks/Makefile +1 -1
@@ -41,7 +42,7 @@ BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS)
 ###############################
 
 test-all.bin:
-       $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
+       $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz
 
 test-hello.bin:
        $(BUILD)

I pushed this to 'perf/vmlinux-v7' branch. Please check it there.

Thanks,
Namhyung

#27 lore raw

[tip:perf/core] perf tools: Add gzip decompression support for kernel module

perf tools: Add gzip decompression support for kernel module
Commit-ID:  e92ce12ed6a46302f64269d2d406cf04525f0a8f
Gitweb:     http://git.kernel.org/tip/e92ce12ed6a46302f64269d2d406cf04525f0a8f
Author:     Namhyung Kim <[email protected]>
AuthorDate: Fri, 31 Oct 2014 16:51:38 +0900
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 5 Nov 2014 10:11:26 -0300

perf tools: Add gzip decompression support for kernel module

Now my Archlinux box shows module symbols correctly.

Before:

  $ perf report --stdio
  Failed to open /tmp/perf-3477.map, continuing without symbols
  no symbols found in /usr/bin/date, maybe install a debug package?
  No kallsyms or vmlinux with build-id 7b4ea0a49ae2111925857099aaf05c3246ff33e0 was found
  [drm] with build id 7b4ea0a49ae2111925857099aaf05c3246ff33e0 not found, continuing without symbols
  No kallsyms or vmlinux with build-id edd931629094b660ca9dec09a1b635c8d87aa2ee was found
  [jbd2] with build id edd931629094b660ca9dec09a1b635c8d87aa2ee not found, continuing without symbols
  No kallsyms or vmlinux with build-id a7b1eada671c34933e5610bb920b2ca4945a82c3 was found
  [ext4] with build id a7b1eada671c34933e5610bb920b2ca4945a82c3 not found, continuing without symbols
  No kallsyms or vmlinux with build-id d69511fa3e5840e770336ef45b06c83fef8d74e3 was found
  [scsi_mod] with build id d69511fa3e5840e770336ef45b06c83fef8d74e3 not found, continuing without symbols
  No kallsyms or vmlinux with build-id af0430af13461af058770ee9b87afc07922c2e77 was found
  [libata] with build id af0430af13461af058770ee9b87afc07922c2e77 not found, continuing without symbols
  No kallsyms or vmlinux with build-id aaeedff8160ce631a5f0333591c6ff291201d29f was found
  [libahci] with build id aaeedff8160ce631a5f0333591c6ff291201d29f not found, continuing without symbols
  No kallsyms or vmlinux with build-id c57907712becaf662dc4981824bb372c0441d605 was found
  [mac80211] with build id c57907712becaf662dc4981824bb372c0441d605 not found, continuing without symbols
  No kallsyms or vmlinux with build-id e0589077cc0ec8c3e4c40eb9f2d9e69d236bee8f was found
  [iwldvm] with build id e0589077cc0ec8c3e4c40eb9f2d9e69d236bee8f not found, continuing without symbols
  No kallsyms or vmlinux with build-id 2d86086bf136bf374a2f029cf85a48194f9b950b was found
  [cfg80211] with build id 2d86086bf136bf374a2f029cf85a48194f9b950b not found, continuing without symbols
  No kallsyms or vmlinux with build-id 4493c48599bdb3d91d0f8db5150e0be33fdd9221 was found
  [iwlwifi] with build id 4493c48599bdb3d91d0f8db5150e0be33fdd9221 not found, continuing without symbols
  ...
  #
  # Overhead  Command          Shared Object            Symbol
  # ........  ...............  .......................  ........................................................
  #
       0.03%  swapper          [ext4]                   [k] 0x000000000000fe2e
       0.03%  swapper          [kernel.kallsyms]        [k] account_entity_enqueue
       0.03%  swapper          [ext4]                   [k] 0x000000000000fc2b
       0.03%  irq/50-iwlwifi   [iwlwifi]                [k] 0x000000000000200b
       0.03%  swapper          [kernel.kallsyms]        [k] ktime_add_safe
       0.03%  swapper          [kernel.kallsyms]        [k] elv_completed_request
       0.03%  swapper          [libata]                 [k] 0x0000000000003997
       0.03%  swapper          [libahci]                [k] 0x0000000000001f25
       0.03%  swapper          [kernel.kallsyms]        [k] rb_next
       0.03%  swapper          [kernel.kallsyms]        [k] blk_finish_request
       0.03%  swapper          [ext4]                   [k] 0x0000000000010248
       0.00%  perf             [kernel.kallsyms]        [k] native_write_msr_safe

After:

  $ perf report --stdio
  Failed to open /tmp/perf-3477.map, continuing without symbols
  no symbols found in /usr/bin/tr, maybe install a debug package?
  ...
  #
  # Overhead  Command          Shared Object                Symbol
  # ........  ...............  ...........................  ......................................................
  #
       0.04%  kworker/u16:3    [ext4]                       [k] ext4_read_block_bitmap
       0.03%  kworker/u16:0    [mac80211]                   [k] ieee80211_sta_reset_beacon_monitor
       0.02%  irq/50-iwlwifi   [mac80211]                   [k] ieee80211_get_bssid
       0.02%  firefox          [e1000e]                     [k] __ew32_prepare
       0.02%  swapper          [libahci]                    [k] ahci_handle_port_interrupt
       0.02%  emacs            libglib-2.0.so.0.4000.0      [.] g_mutex_unlock
       0.02%  swapper          [e1000e]                     [k] e1000_clean_tx_irq
       0.02%  dwm              [kernel.kallsyms]            [k] __schedule
       0.02%  gnome-terminal-  [vdso]                       [.] __vdso_clock_gettime
       0.02%  swapper          [e1000e]                     [k] e1000_alloc_rx_buffers
       0.02%  irq/50-iwlwifi   [mac80211]                   [k] ieee80211_rx
       0.01%  firefox          [vdso]                       [.] __vdso_gettimeofday
       0.01%  irq/50-iwlwifi   [iwlwifi]                    [k] iwl_pcie_rxq_restock.part.13
---
 tools/perf/Makefile.perf                     |  7 +++
 tools/perf/config/Makefile                   | 15 +++++-
 tools/perf/config/feature-checks/Makefile    |  8 ++-
 tools/perf/config/feature-checks/test-all.c  |  5 ++
 tools/perf/config/feature-checks/test-zlib.c |  9 ++++
 tools/perf/util/dso.c                        | 12 ++---
 tools/perf/util/util.h                       |  5 ++
 tools/perf/util/zlib.c                       | 78 ++++++++++++++++++++++++++++
 8 files changed, 127 insertions(+), 12 deletions(-)
tools/perf/Makefile.perf +7 -0
index 0ebcc4a..aecf61dc 100644
@@ -66,6 +66,9 @@ include config/utilities.mak
 #
 # Define NO_PERF_READ_VDSOX32 if you do not want to build perf-read-vdsox32
 # for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode
+#
+# Define NO_ZLIB if you do not want to support compressed kernel modules
+
 
 ifeq ($(srctree),)
 srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -584,6 +587,10 @@ ifndef NO_LIBNUMA
   BUILTIN_OBJS += $(OUTPUT)bench/numa.o
 endif
 
+ifndef NO_ZLIB
+  LIB_OBJS += $(OUTPUT)util/zlib.o
+endif
+
 ifdef ASCIIDOC8
   export ASCIIDOC8
 endif
tools/perf/config/Makefile +13 -2
index 71264e4..79f906c 100644
@@ -200,7 +200,8 @@ CORE_FEATURE_TESTS =			\
 	libunwind			\
 	stackprotector-all		\
 	timerfd				\
-	libdw-dwarf-unwind
+	libdw-dwarf-unwind		\
+	zlib
 
 LIB_FEATURE_TESTS =			\
 	dwarf				\
@@ -214,7 +215,8 @@ LIB_FEATURE_TESTS =			\
 	libpython			\
 	libslang			\
 	libunwind			\
-	libdw-dwarf-unwind
+	libdw-dwarf-unwind		\
+	zlib
 
 VF_FEATURE_TESTS =			\
 	backtrace			\
@@ -604,6 +606,15 @@ ifneq ($(filter -lbfd,$(EXTLIBS)),)
   CFLAGS += -DHAVE_LIBBFD_SUPPORT
 endif
 
+ifndef NO_ZLIB
+  ifeq ($(feature-zlib), 1)
+    CFLAGS += -DHAVE_ZLIB_SUPPORT
+    EXTLIBS += -lz
+  else
+    NO_ZLIB := 1
+  endif
+endif
+
 ifndef NO_BACKTRACE
   ifeq ($(feature-backtrace), 1)
     CFLAGS += -DHAVE_BACKTRACE_SUPPORT
tools/perf/config/feature-checks/Makefile +6 -2
index 7c68ec7..53f19b5 100644
@@ -29,7 +29,8 @@ FILES=					\
 	test-timerfd.bin		\
 	test-libdw-dwarf-unwind.bin	\
 	test-compile-32.bin		\
-	test-compile-x32.bin
+	test-compile-x32.bin		\
+	test-zlib.bin
 
 CC := $(CROSS_COMPILE)gcc -MD
 PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -41,7 +42,7 @@ BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS)
 ###############################
 
 test-all.bin:
-	$(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
+	$(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz
 
 test-hello.bin:
 	$(BUILD)
@@ -139,6 +140,9 @@ test-compile-32.bin:
 test-compile-x32.bin:
 	$(CC) -mx32 -o $(OUTPUT)$@ test-compile.c
 
+test-zlib.bin:
+	$(BUILD) -lz
+
 -include *.d
 
 ###############################
tools/perf/config/feature-checks/test-all.c +5 -0
index a7d022e..652e009 100644
@@ -93,6 +93,10 @@
 # include "test-sync-compare-and-swap.c"
 #undef main
 
+#define main main_test_zlib
+# include "test-zlib.c"
+#undef main
+
 int main(int argc, char *argv[])
 {
 	main_test_libpython();
@@ -116,6 +120,7 @@ int main(int argc, char *argv[])
 	main_test_stackprotector_all();
 	main_test_libdw_dwarf_unwind();
 	main_test_sync_compare_and_swap(argc, argv);
+	main_test_zlib();
 
 	return 0;
 }
tools/perf/config/feature-checks/test-zlib.c new file +9 -0
new file mode 100644
index 0000000..e111fff
@@ -0,0 +1,9 @@
+#include <zlib.h>
+
+int main(void)
+{
+	z_stream zs;
+
+	inflateInit(&zs);
+	return 0;
+}
tools/perf/util/dso.c +4 -8
index 36a607c..45be944 100644
@@ -141,18 +141,14 @@ int dso__read_binary_type_filename(const struct dso *dso,
 	return ret;
 }
 
-static int decompress_dummy(const char *input __maybe_unused,
-			    int output __maybe_unused)
-{
-	return -1;
-}
-
 static const struct {
 	const char *fmt;
 	int (*decompress)(const char *input, int output);
 } compressions[] = {
-	{ "gz", decompress_dummy },
-	{ NULL, },
+#ifdef HAVE_ZLIB_SUPPORT
+	{ "gz", gzip_decompress_to_file },
+#endif
+	{ NULL, NULL },
 };
 
 bool is_supported_compression(const char *ext)
tools/perf/util/util.h +5 -0
index 80bfdaa..7dc44cf 100644
@@ -351,4 +351,9 @@ void mem_bswap_32(void *src, int byte_size);
 
 const char *get_filename_for_perf_kvm(void);
 bool find_process(const char *name);
+
+#ifdef HAVE_ZLIB_SUPPORT
+int gzip_decompress_to_file(const char *input, int output_fd);
+#endif
+
 #endif /* GIT_COMPAT_UTIL_H */
tools/perf/util/zlib.c new file +78 -0

78 lines not on this page · raw message

#28 lore raw

Re: [PATCH 2/8] perf tools: Add gzip decompression support for kernel module

In reply to Namhyung Kim

Em Tue, Nov 04, 2014 at 10:14:28AM +0900, Namhyung Kim escreveu:

Quoted 1 line

Now my Archlinux box shows module symbols correctly.

Now my RHEL6 box doesn't build:

Quoted 4 lines

+++ b/tools/perf/util/dso.c

tools/perf/util/dso.c +0 -0
@@ -141,17 +141,13 @@ int dso__read_binary_type_filename(const struct dso *dso,
 	return ret;
 

tools/perf/util/dso.c int dso__read_binary_type_filename(const struct dso *dso, · line 151

Quoted 10 lines
tools/perf/util/dso.c +3 -1
 static const struct {
 	const char *fmt;
 	int (*decompress)(const char *input, int output);
 } compressions[] = {
-	{ "gz", decompress_dummy },
+#ifdef HAVE_ZLIB_SUPPORT
+	{ "gz", gzip_decompress_to_file },
+#endif
 	{ NULL, },
 };

CC /tmp/build/perf/util/dso.o
cc1: warnings being treated as errors
util/dso.c:151: error: missing initializer util/dso.c:151: error: (near initialization for ‘compressions[1].decompress’)
make[1]: *** [/tmp/build/perf/util/dso.o] Error 1
make: Leaving directory `/home/gita/perf-3.18.0-rc1/tools/perf'
make: *** [install] Error 2
[acme@zoo linux]$

Will try and fix it, nevermind :-)

- Arnaldo

author maintainer
#29 lore raw

Re: [PATCH 2/8] perf tools: Add gzip decompression support for kernel module

Quoted 30 lines · Arnaldo Carvalho de Melo

Em Tue, Nov 04, 2014 at 10:14:28AM +0900, Namhyung Kim escreveu:

Quoted 1 line

Now my Archlinux box shows module symbols correctly.

Now my RHEL6 box doesn't build:

Quoted 4 lines

+++ b/tools/perf/util/dso.c

tools/perf/util/dso.c +0 -0
@@ -141,17 +141,13 @@ int dso__read_binary_type_filename(const struct dso *dso,
 	return ret;
 

tools/perf/util/dso.c int dso__read_binary_type_filename(const struct dso *dso, · line 151

Quoted 10 lines
tools/perf/util/dso.c +3 -1
 static const struct {
 	const char *fmt;
 	int (*decompress)(const char *input, int output);
 } compressions[] = {
-	{ "gz", decompress_dummy },
+#ifdef HAVE_ZLIB_SUPPORT
+	{ "gz", gzip_decompress_to_file },
+#endif
 	{ NULL, },
 };

CC /tmp/build/perf/util/dso.o
cc1: warnings being treated as errors
util/dso.c:151: error: missing initializer util/dso.c:151: error: (near initialization for ‘compressions[1].decompress’)
make[1]: *** [/tmp/build/perf/util/dso.o] Error 1
make: Leaving directory `/home/gita/perf-3.18.0-rc1/tools/perf'
make: *** [install] Error 2
[acme@zoo linux]$

Quoted 1 line

Will try and fix it, nevermind :-)

Also fixed and pushed to perf/vmlinux-v7 branch.

Thanks,
Namhyung

author maintainer
#30 lore raw

PATCH 3/8 perf tools: Rename dsos__write_buildid_table()

In reply to Namhyung Kim

The dsos__write_buildid_table() is not use struct dso and it mostly uses perf_session struct. So rename it to perf_session__write_buildid_ table() so that it corresponds to other related functions such as perf_session__read_build_ids() and perf_session__cache_build_ids().

---
 tools/perf/util/header.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
tools/perf/util/header.c +2 -4
index 0ecf4a304cbc..be8d02eb97e9 100644
@@ -297,10 +297,8 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
 	return err;
 }
 
-static int dsos__write_buildid_table(struct perf_header *header, int fd)
+static int perf_session__write_buildid_table(struct perf_session *session, int fd)
 {
-	struct perf_session *session = container_of(header,
-			struct perf_session, header);
 	struct rb_node *nd;
 	int err = machine__write_buildid_table(&session->machines.host, fd);
 
@@ -523,7 +521,7 @@ static int write_build_id(int fd, struct perf_header *h,
 	if (!perf_session__read_build_ids(session, true))
 		return -1;
 
-	err = dsos__write_buildid_table(h, fd);
+	err = perf_session__write_buildid_table(session, fd);
 	if (err < 0) {
 		pr_debug("failed to write buildid table\n");
 		return err;
Signature · 1 line
2.1.2
#31 lore raw

[tip:perf/core] perf build-id: Rename dsos__write_buildid_table()

perf build-id: Rename dsos__write_buildid_table()
Commit-ID:  714c9c4a98f722115e10d021ea80600f4427b71e
Gitweb:     http://git.kernel.org/tip/714c9c4a98f722115e10d021ea80600f4427b71e
Author:     Namhyung Kim <[email protected]>
AuthorDate: Tue, 4 Nov 2014 10:14:29 +0900
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 5 Nov 2014 10:14:07 -0300

perf build-id: Rename dsos__write_buildid_table()

The dsos__write_buildid_table() is not use struct dso and it mostly uses perf_session struct.

So rename it to perf_session__write_buildid_ table() so that it corresponds to other related functions such as perf_session__read_build_ids() and perf_session__cache_build_ids().

---
 tools/perf/util/header.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
tools/perf/util/header.c +2 -4
index 0ecf4a3..be8d02e 100644
@@ -297,10 +297,8 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
 	return err;
 }
 
-static int dsos__write_buildid_table(struct perf_header *header, int fd)
+static int perf_session__write_buildid_table(struct perf_session *session, int fd)
 {
-	struct perf_session *session = container_of(header,
-			struct perf_session, header);
 	struct rb_node *nd;
 	int err = machine__write_buildid_table(&session->machines.host, fd);
 
@@ -523,7 +521,7 @@ static int write_build_id(int fd, struct perf_header *h,
 	if (!perf_session__read_build_ids(session, true))
 		return -1;
 
-	err = dsos__write_buildid_table(h, fd);
+	err = perf_session__write_buildid_table(session, fd);
 	if (err < 0) {
 		pr_debug("failed to write buildid table\n");
 		return err;
author maintainer
#32 lore raw

PATCH 4/8 perf build-id: Move build-id related functions to util/build-id.c

In reply to Namhyung Kim

It'd be better managing those functions in a separate place as util/header.c file is already big.

It now exports following 3 functions to others:

  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);
---
 tools/perf/util/build-id.c | 334 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/build-id.h |  11 ++
 tools/perf/util/header.c   | 337 +--------------------------------------------
 tools/perf/util/header.h   |   8 +-
 4 files changed, 349 insertions(+), 341 deletions(-)
tools/perf/util/build-id.c +334 -0
index 2e7c68e39330..dd2a3e52ada1 100644
@@ -15,6 +15,8 @@
 #include "debug.h"
 #include "session.h"
 #include "tool.h"
+#include "header.h"
+#include "vdso.h"
 
 int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
 			   union perf_event *event,
@@ -105,3 +107,335 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
 			 build_id_hex, build_id_hex + 2);
 	return bf;
 }
+
+#define dsos__for_each_with_build_id(pos, head)	\
+	list_for_each_entry(pos, head, node)	\
+		if (!pos->has_build_id)		\
+			continue;		\
+		else
+
+static int write_buildid(const char *name, size_t name_len, u8 *build_id,
+			 pid_t pid, u16 misc, int fd)
+{
+	int err;
+	struct build_id_event b;
+	size_t len;
+
+	len = name_len + 1;
+	len = PERF_ALIGN(len, NAME_ALIGN);
+
+	memset(&b, 0, sizeof(b));
+	memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
+	b.pid = pid;
+	b.header.misc = misc;
+	b.header.size = sizeof(b) + len;
+
+	err = writen(fd, &b, sizeof(b));
+	if (err < 0)
+		return err;
+
+	return write_padded(fd, name, name_len + 1, len);
+}
+
+static int __dsos__write_buildid_table(struct list_head *head,
+				       struct machine *machine,
+				       pid_t pid, u16 misc, int fd)
+{
+	char nm[PATH_MAX];
+	struct dso *pos;
+
+	dsos__for_each_with_build_id(pos, head) {
+		int err;
+		const char *name;
+		size_t name_len;
+
+		if (!pos->hit)
+			continue;
+
+		if (dso__is_vdso(pos)) {
+			name = pos->short_name;
+			name_len = pos->short_name_len + 1;
+		} else if (dso__is_kcore(pos)) {
+			machine__mmap_name(machine, nm, sizeof(nm));
+			name = nm;
+			name_len = strlen(nm) + 1;
+		} else {
+			name = pos->long_name;
+			name_len = pos->long_name_len + 1;
+		}
+
+		err = write_buildid(name, name_len, pos->build_id,
+				    pid, misc, fd);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int machine__write_buildid_table(struct machine *machine, int fd)
+{
+	int err;
+	u16 kmisc = PERF_RECORD_MISC_KERNEL,
+	    umisc = PERF_RECORD_MISC_USER;
+
+	if (!machine__is_host(machine)) {
+		kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
+		umisc = PERF_RECORD_MISC_GUEST_USER;
+	}
+
+	err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine,
+					  machine->pid, kmisc, fd);
+	if (err == 0)
+		err = __dsos__write_buildid_table(&machine->user_dsos.head,
+						  machine, machine->pid, umisc,
+						  fd);
+	return err;
+}
+
+int perf_session__write_buildid_table(struct perf_session *session, int fd)
+{
+	struct rb_node *nd;
+	int err = machine__write_buildid_table(&session->machines.host, fd);
+
+	if (err)
+		return err;
+
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+		struct machine *pos = rb_entry(nd, struct machine, rb_node);
+		err = machine__write_buildid_table(pos, fd);
+		if (err)
+			break;
+	}
+	return err;
+}
+
+static int __dsos__hit_all(struct list_head *head)
+{
+	struct dso *pos;
+
+	list_for_each_entry(pos, head, node)
+		pos->hit = true;
+
+	return 0;
+}
+
+static int machine__hit_all_dsos(struct machine *machine)
+{
+	int err;
+
+	err = __dsos__hit_all(&machine->kernel_dsos.head);
+	if (err)
+		return err;
+
+	return __dsos__hit_all(&machine->user_dsos.head);
+}
+
+int dsos__hit_all(struct perf_session *session)
+{
+	struct rb_node *nd;
+	int err;
+
+	err = machine__hit_all_dsos(&session->machines.host);
+	if (err)
+		return err;
+
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+		struct machine *pos = rb_entry(nd, struct machine, rb_node);
+
+		err = machine__hit_all_dsos(pos);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
+			  const char *name, bool is_kallsyms, bool is_vdso)
+{
+	const size_t size = PATH_MAX;
+	char *realname, *filename = zalloc(size),
+	     *linkname = zalloc(size), *targetname;
+	int len, err = -1;
+	bool slash = is_kallsyms || is_vdso;
+
+	if (is_kallsyms) {
+		if (symbol_conf.kptr_restrict) {
+			pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
+			err = 0;
+			goto out_free;
+		}
+		realname = (char *) name;
+	} else
+		realname = realpath(name, NULL);
+
+	if (realname == NULL || filename == NULL || linkname == NULL)
+		goto out_free;
+
+	len = scnprintf(filename, size, "%s%s%s",
+		       debugdir, slash ? "/" : "",
+		       is_vdso ? DSO__NAME_VDSO : realname);
+	if (mkdir_p(filename, 0755))
+		goto out_free;
+
+	snprintf(filename + len, size - len, "/%s", sbuild_id);
+
+	if (access(filename, F_OK)) {
+		if (is_kallsyms) {
+			 if (copyfile("/proc/kallsyms", filename))
+				goto out_free;
+		} else if (link(realname, filename) && copyfile(name, filename))
+			goto out_free;
+	}
+
+	len = scnprintf(linkname, size, "%s/.build-id/%.2s",
+		       debugdir, sbuild_id);
+
+	if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
+		goto out_free;
+
+	snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
+	targetname = filename + strlen(debugdir) - 5;
+	memcpy(targetname, "../..", 5);
+
+	if (symlink(targetname, linkname) == 0)
+		err = 0;
+out_free:
+	if (!is_kallsyms)
+		free(realname);
+	free(filename);
+	free(linkname);
+	return err;
+}
+
+static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
+				 const char *name, const char *debugdir,
+				 bool is_kallsyms, bool is_vdso)
+{
+	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
+
+	build_id__sprintf(build_id, build_id_size, sbuild_id);
+
+	return build_id_cache__add_s(sbuild_id, debugdir, name,
+				     is_kallsyms, is_vdso);
+}
+
+int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
+{
+	const size_t size = PATH_MAX;
+	char *filename = zalloc(size),
+	     *linkname = zalloc(size);
+	int err = -1;
+
+	if (filename == NULL || linkname == NULL)
+		goto out_free;
+
+	snprintf(linkname, size, "%s/.build-id/%.2s/%s",
+		 debugdir, sbuild_id, sbuild_id + 2);
+
+	if (access(linkname, F_OK))
+		goto out_free;
+
+	if (readlink(linkname, filename, size - 1) < 0)
+		goto out_free;
+
+	if (unlink(linkname))
+		goto out_free;
+
+	/*
+	 * Since the link is relative, we must make it absolute:
+	 */
+	snprintf(linkname, size, "%s/.build-id/%.2s/%s",
+		 debugdir, sbuild_id, filename);
+
+	if (unlink(linkname))
+		goto out_free;
+
+	err = 0;
+out_free:
+	free(filename);
+	free(linkname);
+	return err;
+}
+
+static int dso__cache_build_id(struct dso *dso, struct machine *machine,
+			       const char *debugdir)
+{
+	bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
+	bool is_vdso = dso__is_vdso(dso);
+	const char *name = dso->long_name;
+	char nm[PATH_MAX];
+
+	if (dso__is_kcore(dso)) {
+		is_kallsyms = true;
+		machine__mmap_name(machine, nm, sizeof(nm));
+		name = nm;
+	}
+	return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
+				     debugdir, is_kallsyms, is_vdso);
+}
+
+static int __dsos__cache_build_ids(struct list_head *head,
+				   struct machine *machine, const char *debugdir)
+{
+	struct dso *pos;
+	int err = 0;
+
+	dsos__for_each_with_build_id(pos, head)
+		if (dso__cache_build_id(pos, machine, debugdir))
+			err = -1;
+
+	return err;
+}
+
+static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
+{
+	int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine,
+					  debugdir);
+	ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine,
+				       debugdir);
+	return ret;
+}
+
+int perf_session__cache_build_ids(struct perf_session *session)
+{
+	struct rb_node *nd;
+	int ret;
+	char debugdir[PATH_MAX];
+
+	snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
+
+	if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
+		return -1;
+
+	ret = machine__cache_build_ids(&session->machines.host, debugdir);
+
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+		struct machine *pos = rb_entry(nd, struct machine, rb_node);
+		ret |= machine__cache_build_ids(pos, debugdir);
+	}
+	return ret ? -1 : 0;
+}
+
+static bool machine__read_build_ids(struct machine *machine, bool with_hits)
+{
+	bool ret;
+
+	ret  = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits);
+	ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits);
+	return ret;
+}
+
+bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
+{
+	struct rb_node *nd;
+	bool ret = machine__read_build_ids(&session->machines.host, with_hits);
+
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+		struct machine *pos = rb_entry(nd, struct machine, rb_node);
+		ret |= machine__read_build_ids(pos, with_hits);
+	}
+
+	return ret;
+}
tools/perf/util/build-id.h +11 -0
index ae392561470b..666a3bd4f64e 100644
@@ -15,4 +15,15 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
 int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
 			   struct perf_sample *sample, struct perf_evsel *evsel,
 			   struct machine *machine);
+
+int dsos__hit_all(struct perf_session *session);
+
+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);
+
+int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
+			  const char *name, bool is_kallsyms, bool is_vdso);
+int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
+
 #endif
tools/perf/util/header.c +1 -336

349 lines not on this page · raw message

tools/perf/util/header.h +3 -5
index 8f5cbaea64a5..3bb90ac172a1 100644
@@ -122,10 +122,6 @@ int perf_header__process_sections(struct perf_header *header, int fd,
 
 int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
 
-int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
-			  const char *name, bool is_kallsyms, bool is_vdso);
-int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
-
 int perf_event__synthesize_attr(struct perf_tool *tool,
 				struct perf_event_attr *attr, u32 ids, u64 *id,
 				perf_event__handler_t process);
@@ -151,7 +147,9 @@ int perf_event__process_build_id(struct perf_tool *tool,
 				 struct perf_session *session);
 bool is_perf_magic(u64 magic);
 
-int dsos__hit_all(struct perf_session *session);
+#define NAME_ALIGN 64
+
+int write_padded(int fd, const void *bf, size_t count, size_t count_aligned);
 
 /*
  * arch specific callback
Signature · 1 line
2.1.2
#33 lore raw

[tip:perf/core] perf build-id: Move build-id related functions to util/build-id.c

perf build-id: Move build-id related functions to util/build-id.c
Commit-ID:  e195fac8077f034b0160bf420bdf450ae476701d
Gitweb:     http://git.kernel.org/tip/e195fac8077f034b0160bf420bdf450ae476701d
Author:     Namhyung Kim <[email protected]>
AuthorDate: Tue, 4 Nov 2014 10:14:30 +0900
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 5 Nov 2014 10:14:07 -0300

perf build-id: Move build-id related functions to util/build-id.c

It'd be better managing those functions in a separate place as util/header.c file is already big.

It now exports following 3 functions to others:

  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);
---
 tools/perf/util/build-id.c | 334 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/build-id.h |  11 ++
 tools/perf/util/header.c   | 337 +--------------------------------------------
 tools/perf/util/header.h   |   8 +-
 4 files changed, 349 insertions(+), 341 deletions(-)
tools/perf/util/build-id.c +334 -0
index 2e7c68e..dd2a3e5 100644
@@ -15,6 +15,8 @@
 #include "debug.h"
 #include "session.h"
 #include "tool.h"
+#include "header.h"
+#include "vdso.h"
 
 int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
 			   union perf_event *event,
@@ -105,3 +107,335 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
 			 build_id_hex, build_id_hex + 2);
 	return bf;
 }
+
+#define dsos__for_each_with_build_id(pos, head)	\
+	list_for_each_entry(pos, head, node)	\
+		if (!pos->has_build_id)		\
+			continue;		\
+		else
+
+static int write_buildid(const char *name, size_t name_len, u8 *build_id,
+			 pid_t pid, u16 misc, int fd)
+{
+	int err;
+	struct build_id_event b;
+	size_t len;
+
+	len = name_len + 1;
+	len = PERF_ALIGN(len, NAME_ALIGN);
+
+	memset(&b, 0, sizeof(b));
+	memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
+	b.pid = pid;
+	b.header.misc = misc;
+	b.header.size = sizeof(b) + len;
+
+	err = writen(fd, &b, sizeof(b));
+	if (err < 0)
+		return err;
+
+	return write_padded(fd, name, name_len + 1, len);
+}
+
+static int __dsos__write_buildid_table(struct list_head *head,
+				       struct machine *machine,
+				       pid_t pid, u16 misc, int fd)
+{
+	char nm[PATH_MAX];
+	struct dso *pos;
+
+	dsos__for_each_with_build_id(pos, head) {
+		int err;
+		const char *name;
+		size_t name_len;
+
+		if (!pos->hit)
+			continue;
+
+		if (dso__is_vdso(pos)) {
+			name = pos->short_name;
+			name_len = pos->short_name_len + 1;
+		} else if (dso__is_kcore(pos)) {
+			machine__mmap_name(machine, nm, sizeof(nm));
+			name = nm;
+			name_len = strlen(nm) + 1;
+		} else {
+			name = pos->long_name;
+			name_len = pos->long_name_len + 1;
+		}
+
+		err = write_buildid(name, name_len, pos->build_id,
+				    pid, misc, fd);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int machine__write_buildid_table(struct machine *machine, int fd)
+{
+	int err;
+	u16 kmisc = PERF_RECORD_MISC_KERNEL,
+	    umisc = PERF_RECORD_MISC_USER;
+
+	if (!machine__is_host(machine)) {
+		kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
+		umisc = PERF_RECORD_MISC_GUEST_USER;
+	}
+
+	err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine,
+					  machine->pid, kmisc, fd);
+	if (err == 0)
+		err = __dsos__write_buildid_table(&machine->user_dsos.head,
+						  machine, machine->pid, umisc,
+						  fd);
+	return err;
+}
+
+int perf_session__write_buildid_table(struct perf_session *session, int fd)
+{
+	struct rb_node *nd;
+	int err = machine__write_buildid_table(&session->machines.host, fd);
+
+	if (err)
+		return err;
+
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+		struct machine *pos = rb_entry(nd, struct machine, rb_node);
+		err = machine__write_buildid_table(pos, fd);
+		if (err)
+			break;
+	}
+	return err;
+}
+
+static int __dsos__hit_all(struct list_head *head)
+{
+	struct dso *pos;
+
+	list_for_each_entry(pos, head, node)
+		pos->hit = true;
+
+	return 0;
+}
+
+static int machine__hit_all_dsos(struct machine *machine)
+{
+	int err;
+
+	err = __dsos__hit_all(&machine->kernel_dsos.head);
+	if (err)
+		return err;
+
+	return __dsos__hit_all(&machine->user_dsos.head);
+}
+
+int dsos__hit_all(struct perf_session *session)
+{
+	struct rb_node *nd;
+	int err;
+
+	err = machine__hit_all_dsos(&session->machines.host);
+	if (err)
+		return err;
+
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+		struct machine *pos = rb_entry(nd, struct machine, rb_node);
+
+		err = machine__hit_all_dsos(pos);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
+			  const char *name, bool is_kallsyms, bool is_vdso)
+{
+	const size_t size = PATH_MAX;
+	char *realname, *filename = zalloc(size),
+	     *linkname = zalloc(size), *targetname;
+	int len, err = -1;
+	bool slash = is_kallsyms || is_vdso;
+
+	if (is_kallsyms) {
+		if (symbol_conf.kptr_restrict) {
+			pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
+			err = 0;
+			goto out_free;
+		}
+		realname = (char *) name;
+	} else
+		realname = realpath(name, NULL);
+
+	if (realname == NULL || filename == NULL || linkname == NULL)
+		goto out_free;
+
+	len = scnprintf(filename, size, "%s%s%s",
+		       debugdir, slash ? "/" : "",
+		       is_vdso ? DSO__NAME_VDSO : realname);
+	if (mkdir_p(filename, 0755))
+		goto out_free;
+
+	snprintf(filename + len, size - len, "/%s", sbuild_id);
+
+	if (access(filename, F_OK)) {
+		if (is_kallsyms) {
+			 if (copyfile("/proc/kallsyms", filename))
+				goto out_free;
+		} else if (link(realname, filename) && copyfile(name, filename))
+			goto out_free;
+	}
+
+	len = scnprintf(linkname, size, "%s/.build-id/%.2s",
+		       debugdir, sbuild_id);
+
+	if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
+		goto out_free;
+
+	snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
+	targetname = filename + strlen(debugdir) - 5;
+	memcpy(targetname, "../..", 5);
+
+	if (symlink(targetname, linkname) == 0)
+		err = 0;
+out_free:
+	if (!is_kallsyms)
+		free(realname);
+	free(filename);
+	free(linkname);
+	return err;
+}
+
+static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
+				 const char *name, const char *debugdir,
+				 bool is_kallsyms, bool is_vdso)
+{
+	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
+
+	build_id__sprintf(build_id, build_id_size, sbuild_id);
+
+	return build_id_cache__add_s(sbuild_id, debugdir, name,
+				     is_kallsyms, is_vdso);
+}
+
+int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
+{
+	const size_t size = PATH_MAX;
+	char *filename = zalloc(size),
+	     *linkname = zalloc(size);
+	int err = -1;
+
+	if (filename == NULL || linkname == NULL)
+		goto out_free;
+
+	snprintf(linkname, size, "%s/.build-id/%.2s/%s",
+		 debugdir, sbuild_id, sbuild_id + 2);
+
+	if (access(linkname, F_OK))
+		goto out_free;
+
+	if (readlink(linkname, filename, size - 1) < 0)
+		goto out_free;
+
+	if (unlink(linkname))
+		goto out_free;
+
+	/*
+	 * Since the link is relative, we must make it absolute:
+	 */
+	snprintf(linkname, size, "%s/.build-id/%.2s/%s",
+		 debugdir, sbuild_id, filename);
+
+	if (unlink(linkname))
+		goto out_free;
+
+	err = 0;
+out_free:
+	free(filename);
+	free(linkname);
+	return err;
+}
+
+static int dso__cache_build_id(struct dso *dso, struct machine *machine,
+			       const char *debugdir)
+{
+	bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
+	bool is_vdso = dso__is_vdso(dso);
+	const char *name = dso->long_name;
+	char nm[PATH_MAX];
+
+	if (dso__is_kcore(dso)) {
+		is_kallsyms = true;
+		machine__mmap_name(machine, nm, sizeof(nm));
+		name = nm;
+	}
+	return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
+				     debugdir, is_kallsyms, is_vdso);
+}
+
+static int __dsos__cache_build_ids(struct list_head *head,
+				   struct machine *machine, const char *debugdir)
+{
+	struct dso *pos;
+	int err = 0;
+
+	dsos__for_each_with_build_id(pos, head)
+		if (dso__cache_build_id(pos, machine, debugdir))
+			err = -1;
+
+	return err;
+}
+
+static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
+{
+	int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine,
+					  debugdir);
+	ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine,
+				       debugdir);
+	return ret;
+}
+
+int perf_session__cache_build_ids(struct perf_session *session)
+{
+	struct rb_node *nd;
+	int ret;
+	char debugdir[PATH_MAX];
+
+	snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
+
+	if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
+		return -1;
+
+	ret = machine__cache_build_ids(&session->machines.host, debugdir);
+
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+		struct machine *pos = rb_entry(nd, struct machine, rb_node);
+		ret |= machine__cache_build_ids(pos, debugdir);
+	}
+	return ret ? -1 : 0;
+}
+
+static bool machine__read_build_ids(struct machine *machine, bool with_hits)
+{
+	bool ret;
+
+	ret  = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits);
+	ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits);
+	return ret;
+}
+
+bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
+{
+	struct rb_node *nd;
+	bool ret = machine__read_build_ids(&session->machines.host, with_hits);
+
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+		struct machine *pos = rb_entry(nd, struct machine, rb_node);
+		ret |= machine__read_build_ids(pos, with_hits);
+	}
+
+	return ret;
+}
tools/perf/util/build-id.h +11 -0
index ae39256..666a3bd 100644
@@ -15,4 +15,15 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
 int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
 			   struct perf_sample *sample, struct perf_evsel *evsel,
 			   struct machine *machine);
+
+int dsos__hit_all(struct perf_session *session);
+
+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);
+
+int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
+			  const char *name, bool is_kallsyms, bool is_vdso);
+int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
+
 #endif
tools/perf/util/header.c +1 -336

349 lines not on this page · raw message

tools/perf/util/header.h +3 -5
index 8f5cbae..3bb90ac 100644
@@ -122,10 +122,6 @@ int perf_header__process_sections(struct perf_header *header, int fd,
 
 int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
 
-int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
-			  const char *name, bool is_kallsyms, bool is_vdso);
-int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
-
 int perf_event__synthesize_attr(struct perf_tool *tool,
 				struct perf_event_attr *attr, u32 ids, u64 *id,
 				perf_event__handler_t process);
@@ -151,7 +147,9 @@ int perf_event__process_build_id(struct perf_tool *tool,
 				 struct perf_session *session);
 bool is_perf_magic(u64 magic);
 
-int dsos__hit_all(struct perf_session *session);
+#define NAME_ALIGN 64
+
+int write_padded(int fd, const void *bf, size_t count, size_t count_aligned);
 
 /*
  * arch specific callback
author maintainer
#34 lore raw

PATCH 5/8 perf tools: Move disable_buildid_cache() to util/build-id.c

In reply to Namhyung Kim

Also move static variable no_buildid_cache and check it in the perf_session_cache_build_ids().

---
 tools/perf/util/build-id.c | 11 +++++++++++
 tools/perf/util/build-id.h |  1 +
 tools/perf/util/header.c   | 10 +---------
 tools/perf/util/util.h     |  1 -
 4 files changed, 13 insertions(+), 10 deletions(-)
tools/perf/util/build-id.c +11 -0
index dd2a3e52ada1..e8d79e5bfaf7 100644
@@ -18,6 +18,9 @@
 #include "header.h"
 #include "vdso.h"
 
+
+static bool no_buildid_cache;
+
 int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
 			   union perf_event *event,
 			   struct perf_sample *sample,
@@ -251,6 +254,11 @@ int dsos__hit_all(struct perf_session *session)
 	return 0;
 }
 
+void disable_buildid_cache(void)
+{
+	no_buildid_cache = true;
+}
+
 int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
 			  const char *name, bool is_kallsyms, bool is_vdso)
 {
@@ -404,6 +412,9 @@ int perf_session__cache_build_ids(struct perf_session *session)
 	int ret;
 	char debugdir[PATH_MAX];
 
+	if (no_buildid_cache)
+		return 0;
+
 	snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
 
 	if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
tools/perf/util/build-id.h +1 -0
index 666a3bd4f64e..8236319514d5 100644
@@ -25,5 +25,6 @@ int perf_session__cache_build_ids(struct perf_session *session);
 int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
 			  const char *name, bool is_kallsyms, bool is_vdso);
 int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
+void disable_buildid_cache(void);
 
 #endif
tools/perf/util/header.c +1 -9
index 3e2c156d9c64..3081f030aef0 100644
@@ -24,8 +24,6 @@
 #include "build-id.h"
 #include "data.h"
 
-static bool no_buildid_cache = false;
-
 static u32 header_argc;
 static const char **header_argv;
 
@@ -191,8 +189,7 @@ static int write_build_id(int fd, struct perf_header *h,
 		pr_debug("failed to write buildid table\n");
 		return err;
 	}
-	if (!no_buildid_cache)
-		perf_session__cache_build_ids(session);
+	perf_session__cache_build_ids(session);
 
 	return 0;
 }
@@ -2790,8 +2787,3 @@ int perf_event__process_build_id(struct perf_tool *tool __maybe_unused,
 				 session);
 	return 0;
 }
-
-void disable_buildid_cache(void)
-{
-	no_buildid_cache = true;
-}
tools/perf/util/util.h +0 -1
index 7dc44cfe25b3..76d23d83eae5 100644
@@ -154,7 +154,6 @@ extern void set_die_routine(void (*routine)(const char *err, va_list params) NOR
 
 extern int prefixcmp(const char *str, const char *prefix);
 extern void set_buildid_dir(void);
-extern void disable_buildid_cache(void);
 
 static inline const char *skip_prefix(const char *str, const char *prefix)
 {
Signature · 1 line
2.1.2
author maintainer
#35 lore raw

PATCH 6/8 perf record: Do not save pathname in ./debug/.build-id directory for vmlinux

In reply to Namhyung Kim

When perf record finishes a session recording, it then pre-process samples in order to write build-id info from actually used DSOs. During this process it'll call map__load() for kernel map, and it ends up calling dso__load_vmlinux_path() which replaces dso->long_name.

But this function checks kernel's build-id before searching vmlinux path so it'll have the cryptic name which can be confusing to users IMHO.

This patch adds a flag to skip the build-id check during record, so it'll have a vmlinux path for the kernel dso->long_name.

Before:

  # perf record -va sleep 3
  mmap size 528384B
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.196 MB perf.data (~8545 samples) ]
  Looking at the vmlinux_path (7 entries long)
  Using /home/namhyung/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551 for symbols

After:

  # perf record -va sleep 3
  mmap size 528384B
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.193 MB perf.data (~8432 samples) ]
  Looking at the vmlinux_path (7 entries long)
  Using /lib/modules/3.16.4-1-ARCH/build/vmlinux for symbols
---
 tools/perf/builtin-record.c | 11 +++++++++++
 tools/perf/util/symbol.c    | 11 ++++++-----
 tools/perf/util/symbol.h    |  1 +
 3 files changed, 18 insertions(+), 5 deletions(-)
tools/perf/builtin-record.c +11 -0
index 5091a27e6d28..582c4da155ea 100644
@@ -200,6 +200,17 @@ static int process_buildids(struct record *rec)
 	if (size == 0)
 		return 0;
 
+	/*
+	 * During this process, it'll load kernel map and replace the
+	 * dso->long_name to a real pathname it found.  In this case
+	 * we prefer the vmlinux path like
+	 *   /lib/modules/3.16.4/build/vmlinux
+	 *
+	 * rather than build-id path (in debug directory).
+	 *   $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
+	 */
+	symbol_conf.ignore_vmlinux_buildid = true;
+
 	return __perf_session__process_events(session, start,
 					      size - start,
 					      size, &build_id__mark_dso_hit_ops);
tools/perf/util/symbol.c +6 -5
index c69915c9d5bc..c24c5b83156c 100644
@@ -1511,12 +1511,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
 			   symbol_filter_t filter)
 {
 	int i, err = 0;
-	char *filename;
+	char *filename = NULL;
 
-	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
-		 vmlinux_path__nr_entries + 1);
-
-	filename = dso__build_id_filename(dso, NULL, 0);
+	if (!symbol_conf.ignore_vmlinux_buildid)
+		filename = dso__build_id_filename(dso, NULL, 0);
 	if (filename != NULL) {
 		err = dso__load_vmlinux(dso, map, filename, true, filter);
 		if (err > 0)
@@ -1524,6 +1522,9 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
 		free(filename);
 	}
 
+	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
+		 vmlinux_path__nr_entries + 1);
+
 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
 		if (err > 0)
tools/perf/util/symbol.h +1 -0
index eb2c19bf8d90..ded3ca7266de 100644
@@ -105,6 +105,7 @@ struct symbol_conf {
 	unsigned short	nr_events;
 	bool		try_vmlinux_path,
 			ignore_vmlinux,
+			ignore_vmlinux_buildid,
 			show_kernel_path,
 			use_modules,
 			sort_by_name,
Signature · 1 line
2.1.2
#36 lore raw

Re: [PATCH 6/8] perf record: Do not save pathname in ./debug/.build-id directory for vmlinux

Em Tue, Nov 04, 2014 at 10:14:32AM +0900, Namhyung Kim escreveu:

Quoted 4 lines

When perf record finishes a session recording, it then pre-process samples in order to write build-id info from actually used DSOs. During this process it'll call map__load() for kernel map, and it ends up calling dso__load_vmlinux_path() which replaces dso->long_name.

Can't we achieve the same end result without introducing yet another symbol_conf entry?

I think there are way too many there, we need to remove, not add :-\

I'll add this since it improve the end result, but if you don't beat me to it I'll try to remove this symbol_conf entry while keeping the end result you achieved with it.

- Arnaldo

Quoted 96 lines

But this function checks kernel's build-id before searching vmlinux path so it'll have the cryptic name which can be confusing to users IMHO.

This patch adds a flag to skip the build-id check during record, so it'll have a vmlinux path for the kernel dso->long_name.

Before:

  # perf record -va sleep 3
  mmap size 528384B
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.196 MB perf.data (~8545 samples) ]
  Looking at the vmlinux_path (7 entries long)
  Using /home/namhyung/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551 for symbols

After:

  # perf record -va sleep 3
  mmap size 528384B
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.193 MB perf.data (~8432 samples) ]
  Looking at the vmlinux_path (7 entries long)
  Using /lib/modules/3.16.4-1-ARCH/build/vmlinux for symbols
---
 tools/perf/builtin-record.c | 11 +++++++++++
 tools/perf/util/symbol.c    | 11 ++++++-----
 tools/perf/util/symbol.h    |  1 +
 3 files changed, 18 insertions(+), 5 deletions(-)
tools/perf/builtin-record.c +11 -0
index 5091a27e6d28..582c4da155ea 100644
@@ -200,6 +200,17 @@ static int process_buildids(struct record *rec)
 	if (size == 0)
 		return 0;
 
+	/*
+	 * During this process, it'll load kernel map and replace the
+	 * dso->long_name to a real pathname it found.  In this case
+	 * we prefer the vmlinux path like
+	 *   /lib/modules/3.16.4/build/vmlinux
+	 *
+	 * rather than build-id path (in debug directory).
+	 *   $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
+	 */
+	symbol_conf.ignore_vmlinux_buildid = true;
+
 	return __perf_session__process_events(session, start,
 					      size - start,
 					      size, &build_id__mark_dso_hit_ops);
tools/perf/util/symbol.c +6 -5
index c69915c9d5bc..c24c5b83156c 100644
@@ -1511,12 +1511,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
 			   symbol_filter_t filter)
 {
 	int i, err = 0;
-	char *filename;
+	char *filename = NULL;
 
-	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
-		 vmlinux_path__nr_entries + 1);
-
-	filename = dso__build_id_filename(dso, NULL, 0);
+	if (!symbol_conf.ignore_vmlinux_buildid)
+		filename = dso__build_id_filename(dso, NULL, 0);
 	if (filename != NULL) {
 		err = dso__load_vmlinux(dso, map, filename, true, filter);
 		if (err > 0)
@@ -1524,6 +1522,9 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
 		free(filename);
 	}
 
+	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
+		 vmlinux_path__nr_entries + 1);
+
 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
 		if (err > 0)
tools/perf/util/symbol.h +1 -0
index eb2c19bf8d90..ded3ca7266de 100644
@@ -105,6 +105,7 @@ struct symbol_conf {
 	unsigned short	nr_events;
 	bool		try_vmlinux_path,
 			ignore_vmlinux,
+			ignore_vmlinux_buildid,
 			show_kernel_path,
 			use_modules,
 			sort_by_name,
Signature · 1 line
2.1.2
author maintainer
#37 lore raw

Re: [PATCH 6/8] perf record: Do not save pathname in ./debug/.build-id directory for vmlinux

Hi Arnaldo,

Quoted 10 lines · Arnaldo Carvalho de Melo

Em Tue, Nov 04, 2014 at 10:14:32AM +0900, Namhyung Kim escreveu:

Quoted 4 lines

When perf record finishes a session recording, it then pre-process samples in order to write build-id info from actually used DSOs. During this process it'll call map__load() for kernel map, and it ends up calling dso__load_vmlinux_path() which replaces dso->long_name.

Can't we achieve the same end result without introducing yet another symbol_conf entry?

I think there are way too many there, we need to remove, not add :-\

Agreed.

I also wanted to do it without a new entry, but failed to find a good way of it as it's a common code called both from record and report path and lives in a deep inside of sample processing.

Quoted 4 lines

I'll add this since it improve the end result, but if you don't beat me to it I'll try to remove this symbol_conf entry while keeping the end result you achieved with it.

It'd be really appreciated!

Thanks,
Namhyung

#38 lore raw

[tip:perf/core] perf record: Do not save pathname in ./debug/ .build-id directory for vmlinux

In reply to Namhyung Kim
perf record: Do not save pathname in ./debug/.build-id directory for vmlinux
Commit-ID:  00dc865798a31d3d5300dd5d70166a4a85f76a20
Gitweb:     http://git.kernel.org/tip/00dc865798a31d3d5300dd5d70166a4a85f76a20
Author:     Namhyung Kim <[email protected]>
AuthorDate: Tue, 4 Nov 2014 10:14:32 +0900
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 5 Nov 2014 10:14:08 -0300

perf record: Do not save pathname in ./debug/.build-id directory for vmlinux

When perf record finishes a session, it pre-processes samples in order to write build-id info from DSOs that had samples.

During this process it'll call map__load() for the kernel map, and it ends up calling dso__load_vmlinux_path() which replaces dso->long_name.

But this function checks kernel's build-id before searching vmlinux path so it'll end up with a cryptic name, the pathname for the entry in the ~/.debug cache, which can be confusing to users.

This patch adds a flag to skip the build-id check during record, so that it'll have the original vmlinux path for the kernel dso->long_name, not the entry in the ~/.debug cache.

Before:

  # perf record -va sleep 3
  mmap size 528384B
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.196 MB perf.data (~8545 samples) ]
  Looking at the vmlinux_path (7 entries long)
  Using /home/namhyung/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551 for symbols

After:

  # perf record -va sleep 3
  mmap size 528384B
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.193 MB perf.data (~8432 samples) ]
  Looking at the vmlinux_path (7 entries long)
  Using /lib/modules/3.16.4-1-ARCH/build/vmlinux for symbols
---
 tools/perf/builtin-record.c | 11 +++++++++++
 tools/perf/util/symbol.c    | 11 ++++++-----
 tools/perf/util/symbol.h    |  1 +
 3 files changed, 18 insertions(+), 5 deletions(-)
tools/perf/builtin-record.c +11 -0
index 5091a27..582c4da 100644
@@ -200,6 +200,17 @@ static int process_buildids(struct record *rec)
 	if (size == 0)
 		return 0;
 
+	/*
+	 * During this process, it'll load kernel map and replace the
+	 * dso->long_name to a real pathname it found.  In this case
+	 * we prefer the vmlinux path like
+	 *   /lib/modules/3.16.4/build/vmlinux
+	 *
+	 * rather than build-id path (in debug directory).
+	 *   $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
+	 */
+	symbol_conf.ignore_vmlinux_buildid = true;
+
 	return __perf_session__process_events(session, start,
 					      size - start,
 					      size, &build_id__mark_dso_hit_ops);
tools/perf/util/symbol.c +6 -5
index c69915c..c24c5b8 100644
@@ -1511,12 +1511,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
 			   symbol_filter_t filter)
 {
 	int i, err = 0;
-	char *filename;
+	char *filename = NULL;
 
-	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
-		 vmlinux_path__nr_entries + 1);
-
-	filename = dso__build_id_filename(dso, NULL, 0);
+	if (!symbol_conf.ignore_vmlinux_buildid)
+		filename = dso__build_id_filename(dso, NULL, 0);
 	if (filename != NULL) {
 		err = dso__load_vmlinux(dso, map, filename, true, filter);
 		if (err > 0)
@@ -1524,6 +1522,9 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
 		free(filename);
 	}
 
+	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
+		 vmlinux_path__nr_entries + 1);
+
 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
 		if (err > 0)
tools/perf/util/symbol.h +1 -0
index eb2c19b..ded3ca7 100644
@@ -105,6 +105,7 @@ struct symbol_conf {
 	unsigned short	nr_events;
 	bool		try_vmlinux_path,
 			ignore_vmlinux,
+			ignore_vmlinux_buildid,
 			show_kernel_path,
 			use_modules,
 			sort_by_name,
author maintainer
#39 lore raw

PATCH 7/8 perf tools: Fix build-id matching on vmlinux

In reply to Namhyung Kim

There's a problem on finding correct kernel symbols when perf report runs on a different kernel. Although a part of the problem was solved by the prior commit 0a7e6d1b6844 ("perf tools: Check recorded kernel version when finding vmlinux"), there's a remaining problem still.

When perf records samples, it synthesizes the kernel map using machine__mmap_name() and ref_reloc_sym like "[kernel.kallsyms]_text". You can easily see it using 'perf report -D' command.

After finishing record, it goes through the recorded events to find maps/dsos actually used. And then record build-id info of them.

During this process, it needs to load symbols in a dso and it'd call dso__load_vmlinux_path() since the default value of the symbol_conf. try_vmlinux_path is true. However it changes dso->long_name to a real path of the vmlinux file (e.g. /lib/modules/3.16.4/build/vmlinux) if one is running on a custom kernel.

It resulted in that perf report reads the build-id of the vmlinux, but cannot use it since it only knows about the [kernel.kallsyms] map. It then falls back to possible vmlinux paths by using the recorded kernel version (in case of a recent version) or a running kernel silently.

Even with the recent tools, this still has a possibility of breaking the result. As the build directory is a symbolic link, if one built a new kernel in the same directory with different source/config, the old link to vmlinux will point the new file. So it's absolutely needed to use build-id when finding a kernel image.

In this patch, it's now changed to try to search a kernel dso in the existing dso list which was constructed during build-id table parsing so it'll always have a build-id. If not found, search "[kernel.kallsyms]".

Before:

  $ perf report
  # Children      Self  Command  Shared Object      Symbol
  # ........  ........  .......  .................  ...............................
  #
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] set_curr_task_rt
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] native_calibrate_tsc
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] tsc_refine_calibration_work
      71.87%    71.87%  swapper  [kernel.kallsyms]  [k] module_finalize
   ...

After (for the same perf.data):

      72.15%     0.00%  swapper  vmlinux  [k] cpu_startup_entry
      72.15%     0.00%  swapper  vmlinux  [k] arch_cpu_idle
      72.15%     0.00%  swapper  vmlinux  [k] default_idle
      71.87%    71.87%  swapper  vmlinux  [k] native_safe_halt

...

---
 tools/perf/util/header.c  |  2 +-
 tools/perf/util/machine.c | 16 ++++++++++++++--
 2 files changed, 15 insertions(+), 3 deletions(-)
tools/perf/util/header.c +1 -1
index 3081f030aef0..e86fffd89e2b 100644
@@ -1266,7 +1266,7 @@ static int __event_process_build_id(struct build_id_event *bev,
 
 		dso__set_build_id(dso, &bev->build_id);
 
-		if (filename[0] == '[')
+		if (!is_kernel_module(filename, NULL))
 			dso->kernel = dso_type;
 
 		build_id__sprintf(dso->build_id, sizeof(dso->build_id),
tools/perf/util/machine.c +14 -2
index 946c7d62cb6e..53f90e9c65fe 100644
@@ -1085,8 +1085,20 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 		 * Should be there already, from the build-id table in
 		 * the header.
 		 */
-		struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
-						     kmmap_prefix);
+		struct dso *kernel = NULL;
+		struct dso *dso;
+
+		list_for_each_entry(dso, &machine->kernel_dsos.head, node) {
+			if (is_kernel_module(dso->long_name, NULL))
+				continue;
+
+			kernel = dso;
+			break;
+		}
+
+		if (kernel == NULL)
+			kernel = __dsos__findnew(&machine->kernel_dsos,
+						 kmmap_prefix);
 		if (kernel == NULL)
 			goto out_problem;
 
Signature · 1 line
2.1.2
#40 lore raw
perf tools: Fix build-id matching on vmlinux
Commit-ID:  b837a8bdc48925e6512412973b845c53cbe2b412
Gitweb:     http://git.kernel.org/tip/b837a8bdc48925e6512412973b845c53cbe2b412
Author:     Namhyung Kim <[email protected]>
AuthorDate: Tue, 4 Nov 2014 10:14:33 +0900
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 5 Nov 2014 10:14:08 -0300

perf tools: Fix build-id matching on vmlinux

There's a problem on finding correct kernel symbols when perf report runs on a different kernel. Although a part of the problem was solved by the prior commit 0a7e6d1b6844 ("perf tools: Check recorded kernel version when finding vmlinux"), there's a remaining problem still.

When perf records samples, it synthesizes the kernel map using machine__mmap_name() and ref_reloc_sym like "[kernel.kallsyms]_text". You can easily see it using 'perf report -D' command.

After finishing record, it goes through the recorded events to find maps/dsos actually used. And then record build-id info of them.

During this process, it needs to load symbols in a dso and it'd call dso__load_vmlinux_path() since the default value of the symbol_conf. try_vmlinux_path is true. However it changes dso->long_name to a real path of the vmlinux file (e.g. /lib/modules/3.16.4/build/vmlinux) if one is running on a custom kernel.

It resulted in that perf report reads the build-id of the vmlinux, but cannot use it since it only knows about the [kernel.kallsyms] map. It then falls back to possible vmlinux paths by using the recorded kernel version (in case of a recent version) or a running kernel silently.

Even with the recent tools, this still has a possibility of breaking the result. As the build directory is a symbolic link, if one built a new kernel in the same directory with different source/config, the old link to vmlinux will point the new file. So it's absolutely needed to use build-id when finding a kernel image.

In this patch, it's now changed to try to search a kernel dso in the existing dso list which was constructed during build-id table parsing so it'll always have a build-id. If not found, search "[kernel.kallsyms]".

Before:

  $ perf report
  # Children      Self  Command  Shared Object      Symbol
  # ........  ........  .......  .................  ...............................
  #
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] set_curr_task_rt
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] native_calibrate_tsc
      72.15%     0.00%  swapper  [kernel.kallsyms]  [k] tsc_refine_calibration_work
      71.87%    71.87%  swapper  [kernel.kallsyms]  [k] module_finalize
   ...

After (for the same perf.data):

      72.15%     0.00%  swapper  vmlinux  [k] cpu_startup_entry
      72.15%     0.00%  swapper  vmlinux  [k] arch_cpu_idle
      72.15%     0.00%  swapper  vmlinux  [k] default_idle
      71.87%    71.87%  swapper  vmlinux  [k] native_safe_halt

...

---
 tools/perf/util/header.c  |  2 +-
 tools/perf/util/machine.c | 16 ++++++++++++++--
 2 files changed, 15 insertions(+), 3 deletions(-)
tools/perf/util/header.c +1 -1
index 3e2c156..76442ca 100644
@@ -1269,7 +1269,7 @@ static int __event_process_build_id(struct build_id_event *bev,
 
 		dso__set_build_id(dso, &bev->build_id);
 
-		if (filename[0] == '[')
+		if (!is_kernel_module(filename, NULL))
 			dso->kernel = dso_type;
 
 		build_id__sprintf(dso->build_id, sizeof(dso->build_id),
tools/perf/util/machine.c +14 -2
index 946c7d6..53f90e9 100644
@@ -1085,8 +1085,20 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 		 * Should be there already, from the build-id table in
 		 * the header.
 		 */
-		struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
-						     kmmap_prefix);
+		struct dso *kernel = NULL;
+		struct dso *dso;
+
+		list_for_each_entry(dso, &machine->kernel_dsos.head, node) {
+			if (is_kernel_module(dso->long_name, NULL))
+				continue;
+
+			kernel = dso;
+			break;
+		}
+
+		if (kernel == NULL)
+			kernel = __dsos__findnew(&machine->kernel_dsos,
+						 kmmap_prefix);
 		if (kernel == NULL)
 			goto out_problem;
 
author maintainer
#41 lore raw

PATCH 8/8 perf tools: Make vmlinux short name more like kallsyms short name

In reply to Namhyung Kim

The previous patch changed kernel dso name from '[kernel.kallsyms]' to vmlinux. However it might add confusion to old users accustomed to the old name. So change the short name to '[kernel.vmlinux]' to reduce such confusion.

Before:

  # Overhead  Command         Shared Object            Symbol
  # ........  ..............  .......................  ...............................
  #
       9.83%  swapper         vmlinux                  [k] intel_idle
       4.10%  awk             libc-2.20.so             [.] __strcmp_sse2
       1.86%  sed             libc-2.20.so             [.] __strcmp_sse2
       1.78%  netctl-auto     libc-2.20.so             [.] __strcmp_sse2
       1.23%  netctl-auto     libc-2.20.so             [.] __mbrtowc
       1.21%  firefox         libxul.so                [.] 0x00000000024b62bd
       1.20%  swapper         vmlinux                  [k] cpuidle_enter_state
       1.03%  sleep           vmlinux                  [k] copy_user_generic_unrolled

After:

  # Overhead  Command         Shared Object            Symbol
  # ........  ..............  .......................  ...............................
  #
       9.83%  swapper         [kernel.vmlinux]         [k] intel_idle
       4.10%  awk             libc-2.20.so             [.] __strcmp_sse2
       1.86%  sed             libc-2.20.so             [.] __strcmp_sse2
       1.78%  netctl-auto     libc-2.20.so             [.] __strcmp_sse2
       1.23%  netctl-auto     libc-2.20.so             [.] __mbrtowc
       1.21%  firefox         libxul.so                [.] 0x00000000024b62bd
       1.20%  swapper         [kernel.vmlinux]         [k] cpuidle_enter_state
       1.03%  sleep           [kernel.vmlinux]         [k] copy_user_generic_unrolled
---
 tools/perf/util/machine.c | 3 +++
 1 file changed, 3 insertions(+)
tools/perf/util/machine.c +3 -0
index 53f90e9c65fe..52e94902afb1 100644
@@ -1106,6 +1106,9 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 		if (__machine__create_kernel_maps(machine, kernel) < 0)
 			goto out_problem;
 
+		if (strstr(dso->long_name, "vmlinux"))
+			dso__set_short_name(dso, "[kernel.vmlinux]", false);
+
 		machine__set_kernel_mmap_len(machine, event);
 
 		/*
Signature · 1 line
2.1.2
#42 lore raw

[tip:perf/core] perf tools: Make vmlinux short name more like kallsyms short name

perf tools: Make vmlinux short name more like kallsyms short name
Commit-ID:  96d78059d6d9da45d77078a219924304860497f2
Gitweb:     http://git.kernel.org/tip/96d78059d6d9da45d77078a219924304860497f2
Author:     Namhyung Kim <[email protected]>
AuthorDate: Tue, 4 Nov 2014 10:14:34 +0900
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 5 Nov 2014 10:14:09 -0300

perf tools: Make vmlinux short name more like kallsyms short name

The previous patch changed kernel dso name from '[kernel.kallsyms]' to vmlinux. However it might add confusion to old users accustomed to the old name. So change the short name to '[kernel.vmlinux]' to reduce such confusion.

Before:

  # Overhead  Command         Shared Object            Symbol
  # ........  ..............  .......................  ...............................
  #
       9.83%  swapper         vmlinux                  [k] intel_idle
       4.10%  awk             libc-2.20.so             [.] __strcmp_sse2
       1.86%  sed             libc-2.20.so             [.] __strcmp_sse2
       1.78%  netctl-auto     libc-2.20.so             [.] __strcmp_sse2
       1.23%  netctl-auto     libc-2.20.so             [.] __mbrtowc
       1.21%  firefox         libxul.so                [.] 0x00000000024b62bd
       1.20%  swapper         vmlinux                  [k] cpuidle_enter_state
       1.03%  sleep           vmlinux                  [k] copy_user_generic_unrolled

After:

  # Overhead  Command         Shared Object            Symbol
  # ........  ..............  .......................  ...............................
  #
       9.83%  swapper         [kernel.vmlinux]         [k] intel_idle
       4.10%  awk             libc-2.20.so             [.] __strcmp_sse2
       1.86%  sed             libc-2.20.so             [.] __strcmp_sse2
       1.78%  netctl-auto     libc-2.20.so             [.] __strcmp_sse2
       1.23%  netctl-auto     libc-2.20.so             [.] __mbrtowc
       1.21%  firefox         libxul.so                [.] 0x00000000024b62bd
       1.20%  swapper         [kernel.vmlinux]         [k] cpuidle_enter_state
       1.03%  sleep           [kernel.vmlinux]         [k] copy_user_generic_unrolled
---
 tools/perf/util/machine.c | 3 +++
 1 file changed, 3 insertions(+)
tools/perf/util/machine.c +3 -0
index 53f90e9..52e9490 100644
@@ -1106,6 +1106,9 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 		if (__machine__create_kernel_maps(machine, kernel) < 0)
 			goto out_problem;
 
+		if (strstr(dso->long_name, "vmlinux"))
+			dso__set_short_name(dso, "[kernel.vmlinux]", false);
+
 		machine__set_kernel_mmap_len(machine, event);
 
 		/*