Skip to contentSkip to conversation

perf/core improvements and fixes

GIT PULL In review Arnaldo Carvalho de Melo 4 participants 27 messages Mar 24, 2015 – Mar 27, 2015 perf events

lore
Share & tools
lore

Arnaldo Carvalho de Melo

author maintainer
#0 lore raw

Hi Ingo,

Please consider pulling.

- Arnaldo

The following changes since commit 963a70b8a2d65538f7d58b2b84a2ae10a3ecb6ea:

Merge tag 'perf-core-for-mingo-2' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core (2015-03-22 10:56:19 +0100)

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo

for you to fetch changes up to e03eaa400cf8b8bded86cc5c41018a1c69152f16:

perf tools: Add pid/tid filtering to report and script commands (2015-03-24 13:02:46 -0300)

----------------------------------------------------------------
perf/core improvements and fixes:

User visible:

- Improve support of compressed kernel modules (Jiri Olsa)

- Add --kallsyms option to 'perf diff' (David Ahern)

- Add pid/tid filtering to 'report' and 'script' commands (David Ahern)

- Add support for __print_array() in libtraceevent (Javi Merino)

- Save DSO loading errno to better report errors (Arnaldo Carvalho de Melo)

- Fix 'probe' to get ummapped symbol address on kernel (Masami Hiramatsu)

- Print big numbers using thousands' group in 'kmem' (Namhyung Kim)

- Remove (null) value of "Sort order" for perf mem report (Yunlong Song)

Infrastructure:

- Handle NULL comm name in libtracevent (Josef Bacik)

- Libtraceevent synchronization with trace-cmd repo (Steven Rostedt)

- Work around lack of sched_getcpu in glibc < 2.6. (Vinson Lee)

----------------------------------------------------------------
Arnaldo Carvalho de Melo (2):
perf target: Simplify handling of strerror_r return perf symbols: Save DSO loading errno to better report errors

David Ahern (2):
perf diff: Add kallsyms option
perf tools: Add pid/tid filtering to report and script commands

Javi Merino (2):
tools lib traceevent: Factor out allocating and processing args tools lib traceevent: Add support for __print_array()

Jiri Olsa (7):
perf tools: Use kmod_path__parse in map_groups__set_modules_path_dir perf tools: Use kmod_path__parse in decompress_kmodule perf tools: Use kmod_path__parse in is_kernel_module perf tools: Remove compressed argument from is_kernel_module perf tools: Remove is_kmodule_extension function
perf tools: Try to lookup kernel module map before creating one perf annotate: Allow annotation for decompressed kernel modules

Josef Bacik (1):
tools lib traceevent: Handle NULL comm name

Masami Hiramatsu (1):
perf probe: Fix to get ummapped symbol address on kernel

Namhyung Kim (1):
perf kmem: Print big numbers using thousands' group

Steven Rostedt (1):
tools lib traceevent: Make plugin options either string or boolean

Steven Rostedt (Red Hat) (6):
tools lib traceevent: Copy trace_clock and free it
tools lib traceevent: Handle %z in bprint format
tools lib traceevent: Add pevent_data_pid_from_comm()
tools lib traceevent kbuffer: Remove extra update to data pointer in PADDING tools lib traceevent: Add way to find sub buffer boundary
tools lib traceevent: Free filter tokens in process_filter()

Vinson Lee (1):
perf tools: Work around lack of sched_getcpu in glibc < 2.6.

Yunlong Song (1):
perf tools: Remove (null) value of "Sort order" for perf mem report

 tools/lib/traceevent/event-parse.c                 | 267 ++++++++++++++++++---
 tools/lib/traceevent/event-parse.h                 |  21 +-
 tools/lib/traceevent/event-plugin.c                |  60 ++++-
 tools/lib/traceevent/kbuffer-parse.c               |  12 +-
 tools/lib/traceevent/kbuffer.h                     |   1 +
 tools/lib/traceevent/parse-filter.c                |   2 +
 tools/perf/Documentation/perf-diff.txt             |   3 +
 tools/perf/Documentation/perf-report.txt           |   5 +
 tools/perf/Documentation/perf-script.txt           |   6 +
 tools/perf/builtin-diff.c                          |   2 +
 tools/perf/builtin-kmem.c                          |  11 +-
 tools/perf/builtin-report.c                        |   6 +-
 tools/perf/builtin-script.c                        |   4 +
 tools/perf/builtin-top.c                           |   6 +-
 tools/perf/util/annotate.c                         |  32 ++-
 tools/perf/util/cloexec.c                          |   6 +
 tools/perf/util/cloexec.h                          |   6 +
 tools/perf/util/dso.c                              |  61 +++--
 tools/perf/util/dso.h                              |  31 ++-
 tools/perf/util/header.c                           |   2 +-
 tools/perf/util/machine.c                          |  72 ++++--
 tools/perf/util/probe-event.c                      |   5 +-
 .../perf/util/scripting-engines/trace-event-perl.c |   5 +
 .../util/scripting-engines/trace-event-python.c    |   5 +
 tools/perf/util/sort.h                             |   1 +
 tools/perf/util/symbol-elf.c                       |  57 +++--
 tools/perf/util/symbol-minimal.c                   |   7 +-
 tools/perf/util/symbol.c                           |  31 ++-
 tools/perf/util/symbol.h                           |   7 +
 tools/perf/util/target.c                           |   7 +-
 tools/perf/util/thread.h                           |  11 +
 31 files changed, 621 insertions(+), 131 deletions(-)
author maintainer
#1 lore raw

PATCH 1/25 perf tools: Use kmod_path__parse in map_groups__set_modules_path_dir

From: Jiri Olsa <[email protected]>

Replacing the file name parsing with kmod_path__parse and moving the dso update into new separate function.

---
 tools/perf/util/machine.c | 65 ++++++++++++++++++++++++++++++-----------------
 1 file changed, 41 insertions(+), 24 deletions(-)
tools/perf/util/machine.c +41 -24
index eb95b883fb44..6ca61a3427a6 100644
@@ -851,6 +851,39 @@ static char *get_kernel_version(const char *root_dir)
 	return strdup(name);
 }
 
+static bool is_kmod_dso(struct dso *dso)
+{
+	return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
+	       dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
+}
+
+static int map_groups__set_module_path(struct map_groups *mg, const char *path,
+				       struct kmod_path *m)
+{
+	struct map *map;
+	char *long_name;
+
+	map = map_groups__find_by_name(mg, MAP__FUNCTION, m->name);
+	if (map == NULL)
+		return 0;
+
+	long_name = strdup(path);
+	if (long_name == NULL)
+		return -ENOMEM;
+
+	dso__set_long_name(map->dso, long_name, true);
+	dso__kernel_module_get_build_id(map->dso, "");
+
+	/*
+	 * Full name could reveal us kmod compression, so
+	 * we need to update the symtab_type if needed.
+	 */
+	if (m->comp && is_kmod_dso(map->dso))
+		map->dso->symtab_type++;
+
+	return 0;
+}
+
 static int map_groups__set_modules_path_dir(struct map_groups *mg,
 				const char *dir_name, int depth)
 {
@@ -889,35 +922,19 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
 			if (ret < 0)
 				goto out;
 		} else {
-			char *dot = strrchr(dent->d_name, '.'),
-			     dso_name[PATH_MAX];
-			struct map *map;
-			char *long_name;
+			struct kmod_path m;
 
-			if (dot == NULL)
-				continue;
+			ret = kmod_path__parse_name(&m, dent->d_name);
+			if (ret)
+				goto out;
 
-			/* On some system, modules are compressed like .ko.gz */
-			if (is_supported_compression(dot + 1) &&
-			    is_kmodule_extension(dot - 2))
-				dot -= 3;
+			if (m.kmod)
+				ret = map_groups__set_module_path(mg, path, &m);
 
-			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
-				 (int)(dot - dent->d_name), dent->d_name);
+			free(m.name);
 
-			strxfrchar(dso_name, '-', '_');
-			map = map_groups__find_by_name(mg, MAP__FUNCTION,
-						       dso_name);
-			if (map == NULL)
-				continue;
-
-			long_name = strdup(path);
-			if (long_name == NULL) {
-				ret = -1;
+			if (ret)
 				goto out;
-			}
-			dso__set_long_name(map->dso, long_name, true);
-			dso__kernel_module_get_build_id(map->dso, "");
 		}
 	}
 
Signature · 1 line
1.9.3
author maintainer
#2 lore raw

PATCH 2/25 perf tools: Use kmod_path__parse in decompress_kmodule

In reply to Arnaldo Carvalho de Melo

From: Jiri Olsa <[email protected]>

Replacing the file name parsing with kmod_path__parse.

---
 tools/perf/util/symbol-elf.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)
tools/perf/util/symbol-elf.c +11 -9
index 62742e46c010..78ffde9df9bf 100644
@@ -579,32 +579,34 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata)
 static int decompress_kmodule(struct dso *dso, const char *name,
 			      enum dso_binary_type type)
 {
-	int fd;
-	const char *ext = strrchr(name, '.');
+	int fd = -1;
 	char tmpbuf[] = "/tmp/perf-kmod-XXXXXX";
+	struct kmod_path m;
 
 	if (type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP &&
 	    type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP &&
 	    type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
 		return -1;
 
-	if (!ext || !is_supported_compression(ext + 1)) {
-		ext = strrchr(dso->name, '.');
-		if (!ext || !is_supported_compression(ext + 1))
-			return -1;
-	}
+	if (type == DSO_BINARY_TYPE__BUILD_ID_CACHE)
+		name = dso->long_name;
+
+	if (kmod_path__parse_ext(&m, name) || !m.comp)
+		return -1;
 
 	fd = mkstemp(tmpbuf);
 	if (fd < 0)
-		return -1;
+		goto out;
 
-	if (!decompress_to_file(ext + 1, name, fd)) {
+	if (!decompress_to_file(m.ext, name, fd)) {
 		close(fd);
 		fd = -1;
 	}
 
 	unlink(tmpbuf);
 
+out:
+	free(m.ext);
 	return fd;
 }
 
Signature · 1 line
1.9.3
author maintainer
#3 lore raw

PATCH 3/25 perf tools: Use kmod_path__parse in is_kernel_module

In reply to Arnaldo Carvalho de Melo

From: Jiri Olsa <[email protected]>

Replacing the current parsing code with kmod_path__parse function call.

---
 tools/perf/util/dso.c | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)
tools/perf/util/dso.c +6 -10
index 7a7c54b42b41..f37548322c9d 100644
@@ -178,19 +178,15 @@ bool is_kmodule_extension(const char *ext)
 
 bool is_kernel_module(const char *pathname, bool *compressed)
 {
-	const char *ext = strrchr(pathname, '.');
+	struct kmod_path m;
 
-	if (ext == NULL)
-		return false;
+	if (kmod_path__parse(&m, pathname))
+		return NULL;
 
-	if (is_supported_compression(ext + 1)) {
-		if (compressed)
-			*compressed = true;
-		ext -= 3;
-	} else if (compressed)
-		*compressed = false;
+	if (compressed)
+		*compressed = m.comp;
 
-	return is_kmodule_extension(ext + 1);
+	return m.kmod;
 }
 
 bool decompress_to_file(const char *ext, const char *filename, int output_fd)
Signature · 1 line
1.9.3
author maintainer
#4 lore raw

PATCH 4/25 perf tools: Remove compressed argument from is_kernel_module

In reply to Arnaldo Carvalho de Melo

From: Jiri Olsa <[email protected]>

We no longer need the 'compressed' argument, because all current users use 'NULL' for it.

---
 tools/perf/util/dso.c     | 5 +----
 tools/perf/util/dso.h     | 2 +-
 tools/perf/util/header.c  | 2 +-
 tools/perf/util/machine.c | 2 +-
 4 files changed, 4 insertions(+), 7 deletions(-)
tools/perf/util/dso.c +1 -4
index f37548322c9d..8803a69fc260 100644
@@ -176,16 +176,13 @@ bool is_kmodule_extension(const char *ext)
 	return false;
 }
 
-bool is_kernel_module(const char *pathname, bool *compressed)
+bool is_kernel_module(const char *pathname)
 {
 	struct kmod_path m;
 
 	if (kmod_path__parse(&m, pathname))
 		return NULL;
 
-	if (compressed)
-		*compressed = m.comp;
-
 	return m.kmod;
 }
 
tools/perf/util/dso.h +1 -1
index 3c81d8378bc7..54dd03a490ce 100644
@@ -191,7 +191,7 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t
 				   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 is_kernel_module(const char *pathname);
 bool decompress_to_file(const char *ext, const char *filename, int output_fd);
 bool dso__needs_decompress(struct dso *dso);
 
tools/perf/util/header.c +1 -1
index 1f407f7352a7..fb432153e2aa 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 (!is_kernel_module(filename, NULL))
+		if (!is_kernel_module(filename))
 			dso->kernel = dso_type;
 
 		build_id__sprintf(dso->build_id, sizeof(dso->build_id),
tools/perf/util/machine.c +1 -1
index 6ca61a3427a6..1de5438ad070 100644
@@ -1104,7 +1104,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 		struct dso *dso;
 
 		list_for_each_entry(dso, &machine->kernel_dsos.head, node) {
-			if (is_kernel_module(dso->long_name, NULL))
+			if (is_kernel_module(dso->long_name))
 				continue;
 
 			kernel = dso;
Signature · 1 line
1.9.3
author maintainer
#5 lore raw

PATCH 5/25 perf tools: Remove is_kmodule_extension function

In reply to Arnaldo Carvalho de Melo

From: Jiri Olsa <[email protected]>

Because it's no longer needed.

---
 tools/perf/util/dso.c | 11 -----------
 tools/perf/util/dso.h |  1 -
 2 files changed, 12 deletions(-)
tools/perf/util/dso.c +0 -11
index 8803a69fc260..0d3667f92023 100644
@@ -165,17 +165,6 @@ bool is_supported_compression(const char *ext)
 	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)
 {
 	struct kmod_path m;
tools/perf/util/dso.h +0 -1
index 54dd03a490ce..88f345cc5be2 100644
@@ -190,7 +190,6 @@ 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 decompress_to_file(const char *ext, const char *filename, int output_fd);
 bool dso__needs_decompress(struct dso *dso);
Signature · 1 line
1.9.3
author maintainer
#6 lore raw

PATCH 6/25 perf tools: Try to lookup kernel module map before creating one

In reply to Arnaldo Carvalho de Melo

From: Jiri Olsa <[email protected]>

Currently we assume machine__new_module is called only once for each module so we create its map&dso unconditionally.

However it's possible that it's called multiple times for same module. Like for perf record:

1) via machine__create_module during machine init
2) via kernel MMAP event processing

Trying to lookup kernel module map before creating one.

---
 tools/perf/util/machine.c | 5 +++++
 1 file changed, 5 insertions(+)
tools/perf/util/machine.c +5 -0
index 1de5438ad070..e3353307330c 100644
@@ -498,6 +498,11 @@ struct map *machine__new_module(struct machine *machine, u64 start,
 	if (kmod_path__parse_name(&m, filename))
 		return NULL;
 
+	map = map_groups__find_by_name(&machine->kmaps, MAP__FUNCTION,
+				       m.name);
+	if (map)
+		goto out;
+
 	dso = machine__module_dso(machine, &m, filename);
 	if (dso == NULL)
 		goto out;
Signature · 1 line
1.9.3
author maintainer
#7 lore raw

PATCH 7/25 perf annotate: Allow annotation for decompressed kernel modules

In reply to Arnaldo Carvalho de Melo

From: Jiri Olsa <[email protected]>

Decompressing kernel module file for objdump command if needed. Annotation commands now display annotation for compressed kernel modules.

---
 tools/perf/util/annotate.c | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)
tools/perf/util/annotate.c +31 -1
index 61bf9128e1f2..b72086eca943 100644
@@ -1008,6 +1008,32 @@ fallback:
 			}
 			filename = symfs_filename;
 		}
+	} else if (dso__needs_decompress(dso)) {
+		char tmp[PATH_MAX];
+		struct kmod_path m;
+		int fd;
+		bool ret;
+
+		if (kmod_path__parse_ext(&m, symfs_filename))
+			goto out_free_filename;
+
+		snprintf(tmp, PATH_MAX, "/tmp/perf-kmod-XXXXXX");
+
+		fd = mkstemp(tmp);
+		if (fd < 0) {
+			free(m.ext);
+			goto out_free_filename;
+		}
+
+		ret = decompress_to_file(m.ext, symfs_filename, fd);
+
+		free(m.ext);
+		close(fd);
+
+		if (!ret)
+			goto out_free_filename;
+
+		strcpy(symfs_filename, tmp);
 	}
 
 	snprintf(command, sizeof(command),
@@ -1027,7 +1053,7 @@ fallback:
 
 	file = popen(command, "r");
 	if (!file)
-		goto out_free_filename;
+		goto out_remove_tmp;
 
 	while (!feof(file))
 		if (symbol__parse_objdump_line(sym, map, file, privsize,
@@ -1042,6 +1068,10 @@ fallback:
 		delete_last_nop(sym);
 
 	pclose(file);
+
+out_remove_tmp:
+	if (dso__needs_decompress(dso))
+		unlink(symfs_filename);
 out_free_filename:
 	if (delete_extract)
 		kcore_extract__delete(&kce);
Signature · 1 line
1.9.3
author maintainer
#8 lore raw

PATCH 8/25 perf tools: Remove (null) value of "Sort order" for perf mem report

In reply to Arnaldo Carvalho de Melo

From: Yunlong Song <[email protected]>

When '--sort' is not set, 'perf mem report" will print a null pointer as the output value of sort order, so fix it.

Example:

Before this patch:

 $ perf mem report
 # To display the perf.data header info, please use --header/--header-only options.
 #
 # Samples: 18  of event 'cpu/mem-loads/pp'
 # Total weight : 188
 # Sort order   : (null)
 #
 ...

After this patch:

 $ perf mem report
 # To display the perf.data header info, please use --header/--header-only options.
 #
 # Samples: 18  of event 'cpu/mem-loads/pp'
 # Total weight : 188
 # Sort order   : local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked
 #
 ...
---
 tools/perf/builtin-report.c | 2 +-
 tools/perf/util/sort.h      | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)
tools/perf/builtin-report.c +1 -1
index 0ae482689e3c..81c2f3b97c50 100644
@@ -304,7 +304,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
 
 	if (rep->mem_mode) {
 		ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events);
-		ret += fprintf(fp, "\n# Sort order   : %s", sort_order);
+		ret += fprintf(fp, "\n# Sort order   : %s", sort_order ? : default_mem_sort_order);
 	} else
 		ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
 	return ret + fprintf(fp, "\n#\n");
tools/perf/util/sort.h +1 -0
index 9c01b83eebca..846036a921dc 100644
@@ -44,6 +44,7 @@ extern struct sort_entry sort_dso_to;
 extern struct sort_entry sort_sym_from;
 extern struct sort_entry sort_sym_to;
 extern enum sort_type sort__first_dimension;
+extern const char default_mem_sort_order[];
 
 struct he_stat {
 	u64			period;
Signature · 1 line
1.9.3
author maintainer
#9 lore raw

PATCH 9/25 perf probe: Fix to get ummapped symbol address on kernel

In reply to Arnaldo Carvalho de Melo

From: Masami Hiramatsu <[email protected]>

Fix to get correctly unmapped symbol address on kernel. This allows us to probe on syscall symbols which are aliases of SyS_ functions with using debuginfo.

Without this fix:
----

  # ./perf probe -a sys_write
  Failed to find debug information for address 3b0100
  Probe point 'sys_write' not found.
    Error: Failed to add events.
  ----
The address 0x3b0100 is a mapped address, and not usable
in debuginfo.

With this fix:
----

  # ./perf probe -a sys_write
  Added new event:
    probe:sys_write      (on sys_write)

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

perf record -e probe:sys_write -aR sleep 1
----

---
 tools/perf/util/probe-event.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
tools/perf/util/probe-event.c +4 -1
index 6b95985db5b0..8feac0774c41 100644
@@ -310,7 +310,10 @@ static int find_alternative_probe_point(struct debuginfo *dinfo,
 
 	/* Find the address of given function */
 	map__for_each_symbol_by_name(map, pp->function, sym) {
-		address = sym->start;
+		if (uprobes)
+			address = sym->start;
+		else
+			address = map->unmap_ip(map, sym->start);
 		break;
 	}
 	if (!address) {
Signature · 1 line
1.9.3
author maintainer
#10 lore raw

PATCH 10/25 tools lib traceevent: Factor out allocating and processing args

In reply to Arnaldo Carvalho de Melo

From: Javi Merino <[email protected]>

The sequence of allocating the print_arg field, calling process_arg() and verifying that the next event delimiter is repeated twice in process_hex() and will also be used for process_int_array().

Factor it out to a function to avoid writing the same code again and again.

---
 tools/lib/traceevent/event-parse.c | 77 ++++++++++++++++++++------------------
 1 file changed, 40 insertions(+), 37 deletions(-)
tools/lib/traceevent/event-parse.c +40 -37
index d7c37a7d9255..8e5e4f6137bb 100644
@@ -2014,6 +2014,38 @@ process_entry(struct event_format *event __maybe_unused, struct print_arg *arg,
 	return EVENT_ERROR;
 }
 
+static int alloc_and_process_delim(struct event_format *event, char *next_token,
+				   struct print_arg **print_arg)
+{
+	struct print_arg *field;
+	enum event_type type;
+	char *token;
+	int ret = 0;
+
+	field = alloc_arg();
+	if (!field) {
+		do_warning_event(event, "%s: not enough memory!", __func__);
+		errno = ENOMEM;
+		return -1;
+	}
+
+	type = process_arg(event, field, &token);
+
+	if (test_type_token(type, token, EVENT_DELIM, next_token)) {
+		errno = EINVAL;
+		ret = -1;
+		free_arg(field);
+		goto out_free_token;
+	}
+
+	*print_arg = field;
+
+out_free_token:
+	free_token(token);
+
+	return ret;
+}
+
 static char *arg_eval (struct print_arg *arg);
 
 static unsigned long long
@@ -2486,49 +2518,20 @@ out_free:
 static enum event_type
 process_hex(struct event_format *event, struct print_arg *arg, char **tok)
 {
-	struct print_arg *field;
-	enum event_type type;
-	char *token = NULL;
-
 	memset(arg, 0, sizeof(*arg));
 	arg->type = PRINT_HEX;
 
-	field = alloc_arg();
-	if (!field) {
-		do_warning_event(event, "%s: not enough memory!", __func__);
-		goto out_free;
-	}
-
-	type = process_arg(event, field, &token);
-
-	if (test_type_token(type, token, EVENT_DELIM, ","))
-		goto out_free;
-
-	arg->hex.field = field;
-
-	free_token(token);
-
-	field = alloc_arg();
-	if (!field) {
-		do_warning_event(event, "%s: not enough memory!", __func__);
-		*tok = NULL;
-		return EVENT_ERROR;
-	}
-
-	type = process_arg(event, field, &token);
-
-	if (test_type_token(type, token, EVENT_DELIM, ")"))
-		goto out_free;
+	if (alloc_and_process_delim(event, ",", &arg->hex.field))
+		goto out;
 
-	arg->hex.size = field;
+	if (alloc_and_process_delim(event, ")", &arg->hex.size))
+		goto free_field;
 
-	free_token(token);
-	type = read_token_item(tok);
-	return type;
+	return read_token_item(tok);
 
- out_free:
-	free_arg(field);
-	free_token(token);
+free_field:
+	free_arg(arg->hex.field);
+out:
 	*tok = NULL;
 	return EVENT_ERROR;
 }
Signature · 1 line
1.9.3
author maintainer
#11 lore raw

PATCH 11/25 perf kmem: Print big numbers using thousands' group

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

Like perf stat, this makes easy to read the numbers on stat like below:

  # perf kmem stat

SUMMARY
=======
Total bytes requested: 9,770,900
Total bytes allocated: 9,782,712
Total bytes wasted on internal fragmentation: 11,812 Internal fragmentation: 0.120744%
Cross CPU allocations: 74/152,819

---
 tools/perf/builtin-kmem.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
tools/perf/builtin-kmem.c +7 -4
index 8c85aeb3327a..64d3623d45a0 100644
@@ -20,6 +20,7 @@
 
 #include <linux/rbtree.h>
 #include <linux/string.h>
+#include <locale.h>
 
 struct alloc_stat;
 typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
@@ -325,13 +326,13 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
 static void print_summary(void)
 {
 	printf("\nSUMMARY\n=======\n");
-	printf("Total bytes requested: %lu\n", total_requested);
-	printf("Total bytes allocated: %lu\n", total_allocated);
-	printf("Total bytes wasted on internal fragmentation: %lu\n",
+	printf("Total bytes requested: %'lu\n", total_requested);
+	printf("Total bytes allocated: %'lu\n", total_allocated);
+	printf("Total bytes wasted on internal fragmentation: %'lu\n",
 	       total_allocated - total_requested);
 	printf("Internal fragmentation: %f%%\n",
 	       fragmentation(total_requested, total_allocated));
-	printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs);
+	printf("Cross CPU allocations: %'lu/%'lu\n", nr_cross_allocs, nr_allocs);
 }
 
 static void print_result(struct perf_session *session)
@@ -706,6 +707,8 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
 	symbol__init(&session->header.env);
 
 	if (!strcmp(argv[0], "stat")) {
+		setlocale(LC_ALL, "");
+
 		if (cpu__setup_cpunode_map())
 			goto out_delete;
 
Signature · 1 line
1.9.3
author maintainer
#12 lore raw

PATCH 13/25 perf target: Simplify handling of strerror_r return

In reply to Arnaldo Carvalho de Melo

From: Arnaldo Carvalho de Melo <[email protected]>

To deal with forwarding the strerror_r (GNU) return we need to check if the returned value is the buffer we passed or maybe some constant (unknown error), simplify that action by using scnprintf, that will do all the buflen size checks, trimming if needed.

---
 tools/perf/util/target.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)
tools/perf/util/target.c +2 -5
index e74c5963dc7a..a53603b27e52 100644
@@ -123,11 +123,8 @@ int target__strerror(struct target *target, int errnum,
 	if (errnum >= 0) {
 		const char *err = strerror_r(errnum, buf, buflen);
 
-		if (err != buf) {
-			size_t len = strlen(err);
-			memcpy(buf, err, min(buflen - 1, len));
-			*(buf + min(buflen - 1, len)) = '\0';
-		}
+		if (err != buf)
+			scnprintf(buf, buflen, "%s", err);
 
 		return 0;
 	}
Signature · 1 line
1.9.3
author maintainer
#13 lore raw

PATCH 14/25 perf symbols: Save DSO loading errno to better report errors

In reply to Arnaldo Carvalho de Melo

From: Arnaldo Carvalho de Melo <[email protected]>

Before, when some problem happened while trying to load the kernel symtab, 'perf top' would show:

      ┌─Warning:───────────────────────────┐
      │The vmlinux file can't be used.     │
      │Kernel samples will not be resolved.│
      │                                    │
      │                                    │
      │Press any key...                    │
      └────────────────────────────────────┘

Now, it reports:

  # perf top --vmlinux /dev/null
      ┌─Warning:───────────────────────────────────────────┐
      │The /tmp/passwd file can't be used: Invalid ELF file│
      │Kernel samples will not be resolved.                │
      │                                                    │
      │                                                    │
      │Press any key...                                    │
      └────────────────────────────────────────────────────┘

This is possible because we now register the reason for not being able to load the symtab in the dso->load_errno member, and provide a dso__strerror_load() routine to format this error into a strerror like string with a short reason for the error while loading.

That can be just forwarding the dso__strerror_load() call to strerror_r(), or, for a separate errno range providing a custom message.

---
 tools/perf/builtin-top.c         |  6 ++++--
 tools/perf/util/dso.c            | 33 +++++++++++++++++++++++++++++++++
 tools/perf/util/dso.h            | 28 ++++++++++++++++++++++++++++
 tools/perf/util/symbol-elf.c     | 37 +++++++++++++++++++++++++++----------
 tools/perf/util/symbol-minimal.c |  7 ++++---
 5 files changed, 96 insertions(+), 15 deletions(-)
tools/perf/builtin-top.c +4 -2
index 5fb8723c7128..1cb3436276d1 100644
@@ -757,8 +757,10 @@ static void perf_event__process_sample(struct perf_tool *tool,
 		    al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
 		    RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
 			if (symbol_conf.vmlinux_name) {
-				ui__warning("The %s file can't be used.\n%s",
-					    symbol_conf.vmlinux_name, msg);
+				char serr[256];
+				dso__strerror_load(al.map->dso, serr, sizeof(serr));
+				ui__warning("The %s file can't be used: %s\n%s",
+					    symbol_conf.vmlinux_name, serr, msg);
 			} else {
 				ui__warning("A vmlinux file was not found.\n%s",
 					    msg);
tools/perf/util/dso.c +33 -0
index 0d3667f92023..fc0ddd5792a9 100644
@@ -1137,3 +1137,36 @@ enum dso_type dso__type(struct dso *dso, struct machine *machine)
 
 	return dso__type_fd(fd);
 }
+
+int dso__strerror_load(struct dso *dso, char *buf, size_t buflen)
+{
+	int idx, errnum = dso->load_errno;
+	/*
+	 * This must have a same ordering as the enum dso_load_errno.
+	 */
+	static const char *dso_load__error_str[] = {
+	"Internal tools/perf/ library error",
+	"Invalid ELF file",
+	"Can not read build id",
+	"Mismatching build id",
+	"Decompression failure",
+	};
+
+	BUG_ON(buflen == 0);
+
+	if (errnum >= 0) {
+		const char *err = strerror_r(errnum, buf, buflen);
+
+		if (err != buf)
+			scnprintf(buf, buflen, "%s", err);
+
+		return 0;
+	}
+
+	if (errnum <  __DSO_LOAD_ERRNO__START || errnum >= __DSO_LOAD_ERRNO__END)
+		return -1;
+
+	idx = errnum - __DSO_LOAD_ERRNO__START;
+	scnprintf(buf, buflen, "%s", dso_load__error_str[idx]);
+	return 0;
+}
tools/perf/util/dso.h +28 -0
index 88f345cc5be2..e0901b4ed8de 100644
@@ -60,6 +60,31 @@ enum dso_type {
 	DSO__TYPE_X32BIT,
 };
 
+enum dso_load_errno {
+	DSO_LOAD_ERRNO__SUCCESS		= 0,
+
+	/*
+	 * Choose an arbitrary negative big number not to clash with standard
+	 * errno since SUS requires the errno has distinct positive values.
+	 * See 'Issue 6' in the link below.
+	 *
+	 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
+	 */
+	__DSO_LOAD_ERRNO__START		= -10000,
+
+	DSO_LOAD_ERRNO__INTERNAL_ERROR	= __DSO_LOAD_ERRNO__START,
+
+	/* for symsrc__init() */
+	DSO_LOAD_ERRNO__INVALID_ELF,
+	DSO_LOAD_ERRNO__CANNOT_READ_BUILDID,
+	DSO_LOAD_ERRNO__MISMATCHING_BUILDID,
+
+	/* for decompress_kmodule */
+	DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE,
+
+	__DSO_LOAD_ERRNO__END,
+};
+
 #define DSO__SWAP(dso, type, val)			\
 ({							\
 	type ____r = val;				\
@@ -113,6 +138,7 @@ struct dso {
 	enum dso_swap_type	needs_swap;
 	enum dso_binary_type	symtab_type;
 	enum dso_binary_type	binary_type;
+	enum dso_load_errno	load_errno;
 	u8		 adjust_symbols:1;
 	u8		 has_build_id:1;
 	u8		 has_srcline:1;
@@ -294,4 +320,6 @@ void dso__free_a2l(struct dso *dso);
 
 enum dso_type dso__type(struct dso *dso, struct machine *machine);
 
+int dso__strerror_load(struct dso *dso, char *buf, size_t buflen);
+
 #endif /* __PERF_DSO */
tools/perf/util/symbol-elf.c +27 -10
index 78ffde9df9bf..476268c99431 100644
@@ -595,10 +595,13 @@ static int decompress_kmodule(struct dso *dso, const char *name,
 		return -1;
 
 	fd = mkstemp(tmpbuf);
-	if (fd < 0)
+	if (fd < 0) {
+		dso->load_errno = errno;
 		goto out;
+	}
 
 	if (!decompress_to_file(m.ext, name, fd)) {
+		dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
 		close(fd);
 		fd = -1;
 	}
@@ -635,37 +638,49 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
 	Elf *elf;
 	int fd;
 
-	if (dso__needs_decompress(dso))
+	if (dso__needs_decompress(dso)) {
 		fd = decompress_kmodule(dso, name, type);
-	else
+		if (fd < 0)
+			return -1;
+	} else {
 		fd = open(name, O_RDONLY);
-
-	if (fd < 0)
-		return -1;
+		if (fd < 0) {
+			dso->load_errno = errno;
+			return -1;
+		}
+	}
 
 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
 	if (elf == NULL) {
 		pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
+		dso->load_errno = DSO_LOAD_ERRNO__INVALID_ELF;
 		goto out_close;
 	}
 
 	if (gelf_getehdr(elf, &ehdr) == NULL) {
+		dso->load_errno = DSO_LOAD_ERRNO__INVALID_ELF;
 		pr_debug("%s: cannot get elf header.\n", __func__);
 		goto out_elf_end;
 	}
 
-	if (dso__swap_init(dso, ehdr.e_ident[EI_DATA]))
+	if (dso__swap_init(dso, ehdr.e_ident[EI_DATA])) {
+		dso->load_errno = DSO_LOAD_ERRNO__INTERNAL_ERROR;
 		goto out_elf_end;
+	}
 
 	/* Always reject images with a mismatched build-id: */
 	if (dso->has_build_id) {
 		u8 build_id[BUILD_ID_SIZE];
 
-		if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
+		if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) {
+			dso->load_errno = DSO_LOAD_ERRNO__CANNOT_READ_BUILDID;
 			goto out_elf_end;
+		}
 
-		if (!dso__build_id_equal(dso, build_id))
+		if (!dso__build_id_equal(dso, build_id)) {
+			dso->load_errno = DSO_LOAD_ERRNO__MISMATCHING_BUILDID;
 			goto out_elf_end;
+		}
 	}
 
 	ss->is_64_bit = (gelf_getclass(elf) == ELFCLASS64);
@@ -701,8 +716,10 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
 	}
 
 	ss->name   = strdup(name);
-	if (!ss->name)
+	if (!ss->name) {
+		dso->load_errno = errno;
 		goto out_elf_end;
+	}
 
 	ss->elf    = elf;
 	ss->fd     = fd;
tools/perf/util/symbol-minimal.c +4 -3
index d7efb03b3f9a..fd8477cacf88 100644
@@ -246,13 +246,12 @@ out:
 	return ret;
 }
 
-int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused,
-		 const char *name,
+int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
 	         enum dso_binary_type type)
 {
 	int fd = open(name, O_RDONLY);
 	if (fd < 0)
-		return -1;
+		goto out_errno;
 
 	ss->name = strdup(name);
 	if (!ss->name)
@@ -264,6 +263,8 @@ int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused,
 	return 0;
 out_close:
 	close(fd);
+out_errno:
+	dso->load_errno = errno;
 	return -1;
 }
 
Signature · 1 line
1.9.3
#14 lore raw

Re: [PATCH 14/25] perf symbols: Save DSO loading errno to better report errors

Quoted 44 lines · Arnaldo Carvalho de Melo

From: Arnaldo Carvalho de Melo <[email protected]>

Before, when some problem happened while trying to load the kernel symtab, 'perf top' would show:

      ┌─Warning:───────────────────────────┐
      │The vmlinux file can't be used.     │
      │Kernel samples will not be resolved.│
      │                                    │
      │                                    │
      │Press any key...                    │
      └────────────────────────────────────┘

Now, it reports:

  # perf top --vmlinux /dev/null
      ┌─Warning:───────────────────────────────────────────┐
      │The /tmp/passwd file can't be used: Invalid ELF file│
      │Kernel samples will not be resolved.                │
      │                                                    │
      │                                                    │
      │Press any key...                                    │
      └────────────────────────────────────────────────────┘

This is possible because we now register the reason for not being able to load the symtab in the dso->load_errno member, and provide a dso__strerror_load() routine to format this error into a strerror like string with a short reason for the error while loading.

That can be just forwarding the dso__strerror_load() call to strerror_r(), or, for a separate errno range providing a custom message.

...

Quoted 8 lines
tools/perf/util/dso.c +4 -0
@@ -1137,3 +1137,36 @@ enum dso_type dso__type(struct dso *dso, struct machine *machine)
 
 	return dso__type_fd(fd);
 }
+
+int dso__strerror_load(struct dso *dso, char *buf, size_t buflen)
+{
+	int idx, errnum = dso->load_errno;

tools/perf/util/dso.c enum dso_type dso__type(struct dso *dso, struct machine *machine) · line 1153

Quoted 10 lines
tools/perf/util/dso.c +10 -0
+	/*
+	 * This must have a same ordering as the enum dso_load_errno.
+	 */
+	static const char *dso_load__error_str[] = {
+	"Internal tools/perf/ library error",
+	"Invalid ELF file",
+	"Can not read build id",
+	"Mismatching build id",
+	"Decompression failure",
+	};

You could define this str array by using the dso_load_errno defines so that they're always in sync:

	static const char *dso_load__error_str[] = {
		[DSO_LOAD_ERRNO__INTERNAL_ERROR - __DSO_LOAD_ERRNO__START] = "Internal tools/perf/ library error",
		[DSO_LOAD_ERRNO__INVALID_ELF - __DSO_LOAD_ERRNO__START] = "Invalid ELF file",
		...

and even use a small macro to hide the __DSO_LOAD_ERRNO__START thing.

Signature · 5 lines
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--
#15 lore raw

Re: [PATCH 14/25] perf symbols: Save DSO loading errno to better report errors

Em Fri, Mar 27, 2015 at 11:32:43AM +0100, Borislav Petkov escreveu:

Quoted 15 lines · Arnaldo Carvalho de Melo

tools/perf/util/dso.c enum dso_type dso__type(struct dso *dso, struct machine *machine) · line 1153

Quoted 10 lines
tools/perf/util/dso.c +10 -0
+	/*
+	 * This must have a same ordering as the enum dso_load_errno.
+	 */
+	static const char *dso_load__error_str[] = {
+	"Internal tools/perf/ library error",
+	"Invalid ELF file",
+	"Can not read build id",
+	"Mismatching build id",
+	"Decompression failure",
+	};

You could define this str array by using the dso_load_errno defines so that they're always in sync:

Quoted 6 lines
	static const char *dso_load__error_str[] = {
		[DSO_LOAD_ERRNO__INTERNAL_ERROR - __DSO_LOAD_ERRNO__START] = "Internal tools/perf/ library error",
		[DSO_LOAD_ERRNO__INVALID_ELF - __DSO_LOAD_ERRNO__START] = "Invalid ELF file",
		...

and even use a small macro to hide the __DSO_LOAD_ERRNO__START thing.

Right, good idea, I'll change both this and the code that was used as a template.

- Arnaldo

author maintainer
#16 lore raw

PATCH 15/25 tools lib traceevent: Handle NULL comm name

In reply to Arnaldo Carvalho de Melo

From: Josef Bacik <[email protected]>

It is possible that a pid has no associated comm attached to it, although it can still be passed to pevent_register_comm().

But if comm is NULL, it will cause strdup() to segfault. To prevent this from happening, if comm is NULL use the default "<...>" name for the pid.

---
 tools/lib/traceevent/event-parse.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
tools/lib/traceevent/event-parse.c +4 -1
index 8e5e4f6137bb..31d4e7da191c 100644
@@ -304,7 +304,10 @@ int pevent_register_comm(struct pevent *pevent, const char *comm, int pid)
 	if (!item)
 		return -1;
 
-	item->comm = strdup(comm);
+	if (comm)
+		item->comm = strdup(comm);
+	else
+		item->comm = strdup("<...>");
 	if (!item->comm) {
 		free(item);
 		return -1;
Signature · 1 line
1.9.3
author maintainer
#17 lore raw

PATCH 16/25 tools lib traceevent: Copy trace_clock and free it

In reply to Arnaldo Carvalho de Melo

From: "Steven Rostedt (Red Hat)" <[email protected]>

The pevent->trace_clock should not be a direct pointer to what was given. It should be copied and freed.

Note, valgrind pointed this out when a caller passed in a pointer that needed to be freed and it never was. Ideally, pevent should copy it (which this change does), and free the copy. It's up to the caller to free the clock string passed in.

---
 tools/lib/traceevent/event-parse.c | 10 ++++++++--
 tools/lib/traceevent/event-parse.h |  2 +-
 2 files changed, 9 insertions(+), 3 deletions(-)
tools/lib/traceevent/event-parse.c +8 -2
index 31d4e7da191c..e71c472d6a81 100644
@@ -321,9 +321,14 @@ int pevent_register_comm(struct pevent *pevent, const char *comm, int pid)
 	return 0;
 }
 
-void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock)
+int pevent_register_trace_clock(struct pevent *pevent, const char *trace_clock)
 {
-	pevent->trace_clock = trace_clock;
+	pevent->trace_clock = strdup(trace_clock);
+	if (!pevent->trace_clock) {
+		errno = ENOMEM;
+		return -1;
+	}
+	return 0;
 }
 
 struct func_map {
@@ -6352,6 +6357,7 @@ void pevent_free(struct pevent *pevent)
 		free_handler(handle);
 	}
 
+	free(pevent->trace_clock);
 	free(pevent->events);
 	free(pevent->sort_events);
 
tools/lib/traceevent/event-parse.h +1 -1
index 6abda54d76f2..84e554f84574 100644
@@ -599,7 +599,7 @@ enum trace_flag_type {
 };
 
 int pevent_register_comm(struct pevent *pevent, const char *comm, int pid);
-void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock);
+int pevent_register_trace_clock(struct pevent *pevent, const char *trace_clock);
 int pevent_register_function(struct pevent *pevent, char *name,
 			     unsigned long long addr, char *mod);
 int pevent_register_print_string(struct pevent *pevent, const char *fmt,
Signature · 1 line
1.9.3
author maintainer
#18 lore raw

PATCH 17/25 tools lib traceevent: Handle %z in bprint format

In reply to Arnaldo Carvalho de Melo

From: "Steven Rostedt (Red Hat)" <[email protected]>

The %z printf specifier was not handled making trace_printk()s in the kernel that used this break on output.

---
 tools/lib/traceevent/event-parse.c | 4 ++++
 1 file changed, 4 insertions(+)
tools/lib/traceevent/event-parse.c +4 -0
index e71c472d6a81..bdb1dd618e0e 100644
@@ -4008,6 +4008,10 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
 				goto process_again;
 			case '.':
 				goto process_again;
+			case 'z':
+			case 'Z':
+				ls = 1;
+				goto process_again;
 			case 'p':
 				ls = 1;
 				/* fall through */
Signature · 1 line
1.9.3
author maintainer
#19 lore raw

PATCH 18/25 tools lib traceevent: Add pevent_data_pid_from_comm()

In reply to Arnaldo Carvalho de Melo

From: "Steven Rostedt (Red Hat)" <[email protected]>

There is a pevent_data_comm_from_pid() that returns the cmdline stored for a given pid in order for users to map pids to comms, but there's no method to convert a comm back to a pid. This is useful for filters that specify a comm instead of a PID (it's faster than searching each individual event).

Add a way to retrieve a comm from a pid. Since there can be more than one pid associated to a comm, it returns a data structure that lets the user iterate over all the saved comms for a given pid.

---
 tools/lib/traceevent/event-parse.c | 90 ++++++++++++++++++++++++++++++++++++++
 tools/lib/traceevent/event-parse.h |  5 +++
 2 files changed, 95 insertions(+)
tools/lib/traceevent/event-parse.c +90 -0
index bdb1dd618e0e..bc227225c7f4 100644
@@ -4954,6 +4954,96 @@ const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid)
 	return comm;
 }
 
+static struct cmdline *
+pid_from_cmdlist(struct pevent *pevent, const char *comm, struct cmdline *next)
+{
+	struct cmdline_list *cmdlist = (struct cmdline_list *)next;
+
+	if (cmdlist)
+		cmdlist = cmdlist->next;
+	else
+		cmdlist = pevent->cmdlist;
+
+	while (cmdlist && strcmp(cmdlist->comm, comm) != 0)
+		cmdlist = cmdlist->next;
+
+	return (struct cmdline *)cmdlist;
+}
+
+/**
+ * pevent_data_pid_from_comm - return the pid from a given comm
+ * @pevent: a handle to the pevent
+ * @comm: the cmdline to find the pid from
+ * @next: the cmdline structure to find the next comm
+ *
+ * This returns the cmdline structure that holds a pid for a given
+ * comm, or NULL if none found. As there may be more than one pid for
+ * a given comm, the result of this call can be passed back into
+ * a recurring call in the @next paramater, and then it will find the
+ * next pid.
+ * Also, it does a linear seach, so it may be slow.
+ */
+struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *comm,
+					  struct cmdline *next)
+{
+	struct cmdline *cmdline;
+
+	/*
+	 * If the cmdlines have not been converted yet, then use
+	 * the list.
+	 */
+	if (!pevent->cmdlines)
+		return pid_from_cmdlist(pevent, comm, next);
+
+	if (next) {
+		/*
+		 * The next pointer could have been still from
+		 * a previous call before cmdlines were created
+		 */
+		if (next < pevent->cmdlines ||
+		    next >= pevent->cmdlines + pevent->cmdline_count)
+			next = NULL;
+		else
+			cmdline  = next++;
+	}
+
+	if (!next)
+		cmdline = pevent->cmdlines;
+
+	while (cmdline < pevent->cmdlines + pevent->cmdline_count) {
+		if (strcmp(cmdline->comm, comm) == 0)
+			return cmdline;
+		cmdline++;
+	}
+	return NULL;
+}
+
+/**
+ * pevent_cmdline_pid - return the pid associated to a given cmdline
+ * @cmdline: The cmdline structure to get the pid from
+ *
+ * Returns the pid for a give cmdline. If @cmdline is NULL, then
+ * -1 is returned.
+ */
+int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline)
+{
+	struct cmdline_list *cmdlist = (struct cmdline_list *)cmdline;
+
+	if (!cmdline)
+		return -1;
+
+	/*
+	 * If cmdlines have not been created yet, or cmdline is
+	 * not part of the array, then treat it as a cmdlist instead.
+	 */
+	if (!pevent->cmdlines ||
+	    cmdline < pevent->cmdlines ||
+	    cmdline >= pevent->cmdlines + pevent->cmdline_count)
+		return cmdlist->pid;
+
+	return cmdline->pid;
+}
+
 /**
  * pevent_data_comm_from_pid - parse the data into the print format
  * @s: the trace_seq to write to
tools/lib/traceevent/event-parse.h +5 -0
index 84e554f84574..8bd7c6a4cbd7 100644
@@ -678,6 +678,11 @@ int pevent_data_type(struct pevent *pevent, struct pevent_record *rec);
 struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type);
 int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec);
 const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid);
+struct cmdline;
+struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *comm,
+					  struct cmdline *next);
+int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline);
+
 void pevent_event_info(struct trace_seq *s, struct event_format *event,
 		       struct pevent_record *record);
 int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum,
Signature · 1 line
1.9.3
author maintainer
#20 lore raw

PATCH 19/25 tools lib traceevent: Make plugin options either string or boolean

In reply to Arnaldo Carvalho de Melo

From: Steven Rostedt <[email protected]>

When a plugin option is defined, by default it is a boolean (true or false).

If the option is something else, then it needs to set its "value" field to a default string other than NULL (can be just "").

If the value is not set then the option is considered boolean, and the updating of the option value will be handled accordingly.

---
 tools/lib/traceevent/event-parse.h  |  6 +++-
 tools/lib/traceevent/event-plugin.c | 60 +++++++++++++++++++++++++++++++++----
 2 files changed, 59 insertions(+), 7 deletions(-)
tools/lib/traceevent/event-parse.h +5 -1
index 8bd7c6a4cbd7..8ca1b8ee50da 100644
@@ -116,7 +116,7 @@ struct pevent_plugin_option {
 	char				*name;
 	char				*plugin_alias;
 	char				*description;
-	char				*value;
+	const char			*value;
 	void				*priv;
 	int				set;
 };
@@ -154,6 +154,10 @@ struct pevent_plugin_option {
  *   .plugin_alias is used to give a shorter name to access
  *   the vairable. Useful if a plugin handles more than one event.
  *
+ *   If .value is not set, then it is considered a boolean and only
+ *   .set will be processed. If .value is defined, then it is considered
+ *   a string option and .set will be ignored.
+ *
  * PEVENT_PLUGIN_ALIAS: (optional)
  *   The name to use for finding options (uses filename if not defined)
  */
tools/lib/traceevent/event-plugin.c +54 -6

95 lines not on this page · raw message

Signature · 1 line
1.9.3
author maintainer
#21 lore raw

PATCH 21/25 tools lib traceevent: Add way to find sub buffer boundary

In reply to Arnaldo Carvalho de Melo

From: "Steven Rostedt (Red Hat)" <[email protected]>

For debugging purposes, it may be helpful for the kbuffer library to flag when crossing a sub buffer.

---
 tools/lib/traceevent/kbuffer-parse.c | 11 +++++++++++
 tools/lib/traceevent/kbuffer.h       |  1 +
 2 files changed, 12 insertions(+)
tools/lib/traceevent/kbuffer-parse.c +11 -0
index deb3569ab004..3bcada3ae05a 100644
@@ -729,3 +729,14 @@ void kbuffer_set_old_format(struct kbuffer *kbuf)
 
 	kbuf->next_event = __old_next_event;
 }
+
+/**
+ * kbuffer_start_of_data - return offset of where data starts on subbuffer
+ * @kbuf:	The kbuffer
+ *
+ * Returns the location on the subbuffer where the data starts.
+ */
+int kbuffer_start_of_data(struct kbuffer *kbuf)
+{
+	return kbuf->start;
+}
tools/lib/traceevent/kbuffer.h +1 -0
index c831f64b17a0..03dce757553f 100644
@@ -63,5 +63,6 @@ int kbuffer_missed_events(struct kbuffer *kbuf);
 int kbuffer_subbuffer_size(struct kbuffer *kbuf);
 
 void kbuffer_set_old_format(struct kbuffer *kbuf);
+int kbuffer_start_of_data(struct kbuffer *kbuf);
 
 #endif /* _K_BUFFER_H */
Signature · 1 line
1.9.3
author maintainer
#22 lore raw

PATCH 22/25 tools lib traceevent: Free filter tokens in process_filter()

In reply to Arnaldo Carvalho de Melo

From: "Steven Rostedt (Red Hat)" <[email protected]>

valgrind showed that the filter token wasn't being freed properly in process_filter().

---
 tools/lib/traceevent/parse-filter.c | 2 ++
 1 file changed, 2 insertions(+)
tools/lib/traceevent/parse-filter.c +2 -0
index b50234402fc2..0144b3d1bb77 100644
@@ -1058,6 +1058,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
 					*parg = current_op;
 				else
 					*parg = current_exp;
+				free(token);
 				return PEVENT_ERRNO__UNBALANCED_PAREN;
 			}
 			break;
@@ -1168,6 +1169,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
 
 	*parg = current_op;
 
+	free(token);
 	return 0;
 
  fail_alloc:
Signature · 1 line
1.9.3
author maintainer
#23 lore raw

PATCH 23/25 tools lib traceevent: Add support for __print_array()

In reply to Arnaldo Carvalho de Melo

From: Javi Merino <[email protected]>

Since 6ea22486ba46 ("tracing: Add array printing helper") trace can generate traces with variable element size arrays. Add support to parse them.

---
 tools/lib/traceevent/event-parse.c                 | 93 ++++++++++++++++++++++
 tools/lib/traceevent/event-parse.h                 |  8 ++
 .../perf/util/scripting-engines/trace-event-perl.c |  5 ++
 .../util/scripting-engines/trace-event-python.c    |  5 ++
 4 files changed, 111 insertions(+)
tools/lib/traceevent/event-parse.c +93 -0
index bc227225c7f4..b6d11eea8a57 100644
@@ -766,6 +766,11 @@ static void free_arg(struct print_arg *arg)
 		free_arg(arg->hex.field);
 		free_arg(arg->hex.size);
 		break;
+	case PRINT_INT_ARRAY:
+		free_arg(arg->int_array.field);
+		free_arg(arg->int_array.count);
+		free_arg(arg->int_array.el_size);
+		break;
 	case PRINT_TYPE:
 		free(arg->typecast.type);
 		free_arg(arg->typecast.item);
@@ -2545,6 +2550,32 @@ out:
 }
 
 static enum event_type
+process_int_array(struct event_format *event, struct print_arg *arg, char **tok)
+{
+	memset(arg, 0, sizeof(*arg));
+	arg->type = PRINT_INT_ARRAY;
+
+	if (alloc_and_process_delim(event, ",", &arg->int_array.field))
+		goto out;
+
+	if (alloc_and_process_delim(event, ",", &arg->int_array.count))
+		goto free_field;
+
+	if (alloc_and_process_delim(event, ")", &arg->int_array.el_size))
+		goto free_size;
+
+	return read_token_item(tok);
+
+free_size:
+	free_arg(arg->int_array.count);
+free_field:
+	free_arg(arg->int_array.field);
+out:
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+static enum event_type
 process_dynamic_array(struct event_format *event, struct print_arg *arg, char **tok)
 {
 	struct format_field *field;
@@ -2839,6 +2870,10 @@ process_function(struct event_format *event, struct print_arg *arg,
 		free_token(token);
 		return process_hex(event, arg, tok);
 	}
+	if (strcmp(token, "__print_array") == 0) {
+		free_token(token);
+		return process_int_array(event, arg, tok);
+	}
 	if (strcmp(token, "__get_str") == 0) {
 		free_token(token);
 		return process_str(event, arg, tok);
@@ -3367,6 +3402,7 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg
 		break;
 	case PRINT_FLAGS:
 	case PRINT_SYMBOL:
+	case PRINT_INT_ARRAY:
 	case PRINT_HEX:
 		break;
 	case PRINT_TYPE:
@@ -3777,6 +3813,54 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
 		}
 		break;
 
+	case PRINT_INT_ARRAY: {
+		void *num;
+		int el_size;
+
+		if (arg->int_array.field->type == PRINT_DYNAMIC_ARRAY) {
+			unsigned long offset;
+			struct format_field *field =
+				arg->int_array.field->dynarray.field;
+			offset = pevent_read_number(pevent,
+						    data + field->offset,
+						    field->size);
+			num = data + (offset & 0xffff);
+		} else {
+			field = arg->int_array.field->field.field;
+			if (!field) {
+				str = arg->int_array.field->field.name;
+				field = pevent_find_any_field(event, str);
+				if (!field)
+					goto out_warning_field;
+				arg->int_array.field->field.field = field;
+			}
+			num = data + field->offset;
+		}
+		len = eval_num_arg(data, size, event, arg->int_array.count);
+		el_size = eval_num_arg(data, size, event,
+				       arg->int_array.el_size);
+		for (i = 0; i < len; i++) {
+			if (i)
+				trace_seq_putc(s, ' ');
+
+			if (el_size == 1) {
+				trace_seq_printf(s, "%u", *(uint8_t *)num);
+			} else if (el_size == 2) {
+				trace_seq_printf(s, "%u", *(uint16_t *)num);
+			} else if (el_size == 4) {
+				trace_seq_printf(s, "%u", *(uint32_t *)num);
+			} else if (el_size == 8) {
+				trace_seq_printf(s, "%lu", *(uint64_t *)num);
+			} else {
+				trace_seq_printf(s, "BAD SIZE:%d 0x%x",
+						 el_size, *(uint8_t *)num);
+				el_size = 1;
+			}
+
+			num += el_size;
+		}
+		break;
+	}
 	case PRINT_TYPE:
 		break;
 	case PRINT_STRING: {
@@ -5361,6 +5445,15 @@ static void print_args(struct print_arg *args)
 		print_args(args->hex.size);
 		printf(")");
 		break;
+	case PRINT_INT_ARRAY:
+		printf("__print_array(");
+		print_args(args->int_array.field);
+		printf(", ");
+		print_args(args->int_array.count);
+		printf(", ");
+		print_args(args->int_array.el_size);
+		printf(")");
+		break;
 	case PRINT_STRING:
 	case PRINT_BSTRING:
 		printf("__get_str(%s)", args->string.string);
tools/lib/traceevent/event-parse.h +8 -0
index 8ca1b8ee50da..86a5839fb048 100644
@@ -251,6 +251,12 @@ struct print_arg_hex {
 	struct print_arg	*size;
 };
 
+struct print_arg_int_array {
+	struct print_arg	*field;
+	struct print_arg	*count;
+	struct print_arg	*el_size;
+};
+
 struct print_arg_dynarray {
 	struct format_field	*field;
 	struct print_arg	*index;
@@ -279,6 +285,7 @@ enum print_arg_type {
 	PRINT_FLAGS,
 	PRINT_SYMBOL,
 	PRINT_HEX,
+	PRINT_INT_ARRAY,
 	PRINT_TYPE,
 	PRINT_STRING,
 	PRINT_BSTRING,
@@ -298,6 +305,7 @@ struct print_arg {
 		struct print_arg_flags		flags;
 		struct print_arg_symbol		symbol;
 		struct print_arg_hex		hex;
+		struct print_arg_int_array	int_array;
 		struct print_arg_func		func;
 		struct print_arg_string		string;
 		struct print_arg_bitmask	bitmask;
tools/perf/util/scripting-engines/trace-event-perl.c +5 -0
index 22ebc46226e7..8171fed4136e 100644
@@ -214,6 +214,11 @@ static void define_event_symbols(struct event_format *event,
 		define_event_symbols(event, ev_name, args->hex.field);
 		define_event_symbols(event, ev_name, args->hex.size);
 		break;
+	case PRINT_INT_ARRAY:
+		define_event_symbols(event, ev_name, args->int_array.field);
+		define_event_symbols(event, ev_name, args->int_array.count);
+		define_event_symbols(event, ev_name, args->int_array.el_size);
+		break;
 	case PRINT_BSTRING:
 	case PRINT_DYNAMIC_ARRAY:
 	case PRINT_STRING:
tools/perf/util/scripting-engines/trace-event-python.c +5 -0
index 0c815a40a6e8..2ec5dfb5a456 100644
@@ -231,6 +231,11 @@ static void define_event_symbols(struct event_format *event,
 		define_event_symbols(event, ev_name, args->hex.field);
 		define_event_symbols(event, ev_name, args->hex.size);
 		break;
+	case PRINT_INT_ARRAY:
+		define_event_symbols(event, ev_name, args->int_array.field);
+		define_event_symbols(event, ev_name, args->int_array.count);
+		define_event_symbols(event, ev_name, args->int_array.el_size);
+		break;
 	case PRINT_STRING:
 		break;
 	case PRINT_TYPE:
Signature · 1 line
1.9.3
author maintainer
#24 lore raw

PATCH 24/25 perf diff: Add kallsyms option

In reply to Arnaldo Carvalho de Melo

From: David Ahern <[email protected]>

Required for off-box analysis to convert kernel addresses.

---
 tools/perf/Documentation/perf-diff.txt | 3 +++
 tools/perf/builtin-diff.c              | 2 ++
 2 files changed, 5 insertions(+)
tools/perf/Documentation/perf-diff.txt +3 -0
index 518266192d67..d1deb573877f 100644
@@ -31,6 +31,9 @@ OPTIONS
 --dump-raw-trace::
         Dump raw trace in ASCII.
 
+--kallsyms=<file>::
+        kallsyms pathname
+
 -m::
 --modules::
         Load module symbols. WARNING: use only with -k and LIVE kernel
tools/perf/builtin-diff.c +2 -0
index 473887d1d61a..df6307b4050a 100644
@@ -791,6 +791,8 @@ static const struct option options[] = {
 	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
 		    "dump raw trace in ASCII"),
 	OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
+	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
+		   "file", "kallsyms pathname"),
 	OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
 		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
 	OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
Signature · 1 line
1.9.3
#25 lore raw
In reply to Arnaldo Carvalho de Melo
Quoted 122 lines · Arnaldo Carvalho de Melo

Hi Ingo,

Please consider pulling.

- Arnaldo

The following changes since commit 963a70b8a2d65538f7d58b2b84a2ae10a3ecb6ea:

Merge tag 'perf-core-for-mingo-2' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core (2015-03-22 10:56:19 +0100)

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo

for you to fetch changes up to e03eaa400cf8b8bded86cc5c41018a1c69152f16:

perf tools: Add pid/tid filtering to report and script commands (2015-03-24 13:02:46 -0300)

----------------------------------------------------------------
perf/core improvements and fixes:

User visible:

- Improve support of compressed kernel modules (Jiri Olsa)

- Add --kallsyms option to 'perf diff' (David Ahern)

- Add pid/tid filtering to 'report' and 'script' commands (David Ahern)

- Add support for __print_array() in libtraceevent (Javi Merino)

- Save DSO loading errno to better report errors (Arnaldo Carvalho de Melo)

- Fix 'probe' to get ummapped symbol address on kernel (Masami Hiramatsu)

- Print big numbers using thousands' group in 'kmem' (Namhyung Kim)

- Remove (null) value of "Sort order" for perf mem report (Yunlong Song)

Infrastructure:

- Handle NULL comm name in libtracevent (Josef Bacik)

- Libtraceevent synchronization with trace-cmd repo (Steven Rostedt)

- Work around lack of sched_getcpu in glibc < 2.6. (Vinson Lee)

----------------------------------------------------------------
Arnaldo Carvalho de Melo (2):
perf target: Simplify handling of strerror_r return perf symbols: Save DSO loading errno to better report errors

David Ahern (2):
perf diff: Add kallsyms option
perf tools: Add pid/tid filtering to report and script commands

Javi Merino (2):
tools lib traceevent: Factor out allocating and processing args tools lib traceevent: Add support for __print_array()

Jiri Olsa (7):
perf tools: Use kmod_path__parse in map_groups__set_modules_path_dir perf tools: Use kmod_path__parse in decompress_kmodule perf tools: Use kmod_path__parse in is_kernel_module perf tools: Remove compressed argument from is_kernel_module perf tools: Remove is_kmodule_extension function
perf tools: Try to lookup kernel module map before creating one perf annotate: Allow annotation for decompressed kernel modules

Josef Bacik (1):
tools lib traceevent: Handle NULL comm name

Masami Hiramatsu (1):
perf probe: Fix to get ummapped symbol address on kernel

Namhyung Kim (1):
perf kmem: Print big numbers using thousands' group

Steven Rostedt (1):
tools lib traceevent: Make plugin options either string or boolean

Steven Rostedt (Red Hat) (6):
tools lib traceevent: Copy trace_clock and free it
tools lib traceevent: Handle %z in bprint format
tools lib traceevent: Add pevent_data_pid_from_comm()
tools lib traceevent kbuffer: Remove extra update to data pointer in PADDING tools lib traceevent: Add way to find sub buffer boundary
tools lib traceevent: Free filter tokens in process_filter()

Vinson Lee (1):
perf tools: Work around lack of sched_getcpu in glibc < 2.6.

Yunlong Song (1):
perf tools: Remove (null) value of "Sort order" for perf mem report

 tools/lib/traceevent/event-parse.c                 | 267 ++++++++++++++++++---
 tools/lib/traceevent/event-parse.h                 |  21 +-
 tools/lib/traceevent/event-plugin.c                |  60 ++++-
 tools/lib/traceevent/kbuffer-parse.c               |  12 +-
 tools/lib/traceevent/kbuffer.h                     |   1 +
 tools/lib/traceevent/parse-filter.c                |   2 +
 tools/perf/Documentation/perf-diff.txt             |   3 +
 tools/perf/Documentation/perf-report.txt           |   5 +
 tools/perf/Documentation/perf-script.txt           |   6 +
 tools/perf/builtin-diff.c                          |   2 +
 tools/perf/builtin-kmem.c                          |  11 +-
 tools/perf/builtin-report.c                        |   6 +-
 tools/perf/builtin-script.c                        |   4 +
 tools/perf/builtin-top.c                           |   6 +-
 tools/perf/util/annotate.c                         |  32 ++-
 tools/perf/util/cloexec.c                          |   6 +
 tools/perf/util/cloexec.h                          |   6 +
 tools/perf/util/dso.c                              |  61 +++--
 tools/perf/util/dso.h                              |  31 ++-
 tools/perf/util/header.c                           |   2 +-
 tools/perf/util/machine.c                          |  72 ++++--
 tools/perf/util/probe-event.c                      |   5 +-
 .../perf/util/scripting-engines/trace-event-perl.c |   5 +
 .../util/scripting-engines/trace-event-python.c    |   5 +
Quoted 8 lines
 tools/perf/util/sort.h                             |   1 +
 tools/perf/util/symbol-elf.c                       |  57 +++--
 tools/perf/util/symbol-minimal.c                   |   7 +-
 tools/perf/util/symbol.c                           |  31 ++-
 tools/perf/util/symbol.h                           |   7 +
 tools/perf/util/target.c                           |   7 +-
 tools/perf/util/thread.h                           |  11 +
 31 files changed, 621 insertions(+), 131 deletions(-)

Pulled, thanks a lot Arnaldo!

Ingo

author maintainer
#26 lore raw

PATCH 25/25 perf tools: Add pid/tid filtering to report and script commands

In reply to Arnaldo Carvalho de Melo

From: David Ahern <[email protected]>

The 'record' and 'top' tools already allow a user to specify a CSV of pids and/or tids of tasks to collect data.

Add those options to the 'report' and 'script' analysis commands to only consider samples related to the given pids/tids.

This is also inline with the existing comm option.

---
 tools/perf/Documentation/perf-report.txt |  5 +++++
 tools/perf/Documentation/perf-script.txt |  6 ++++++
 tools/perf/builtin-report.c              |  4 ++++
 tools/perf/builtin-script.c              |  4 ++++
 tools/perf/util/symbol.c                 | 31 ++++++++++++++++++++++++++++++-
 tools/perf/util/symbol.h                 |  7 +++++++
 tools/perf/util/thread.h                 | 11 +++++++++++
 7 files changed, 67 insertions(+), 1 deletion(-)
tools/perf/Documentation/perf-report.txt +5 -0
index dd7cccdde498..4879cf638824 100644
@@ -40,6 +40,11 @@ OPTIONS
 	Only consider symbols in these comms. CSV that understands
 	file://filename entries.  This option will affect the percentage of
 	the overhead column.  See --percentage for more info.
+--pid=::
+        Only show events for given process ID (comma separated list).
+
+--tid=::
+        Only show events for given thread ID (comma separated list).
 -d::
 --dsos=::
 	Only consider symbols in these dsos. CSV that understands
tools/perf/Documentation/perf-script.txt +6 -0
index a21eec05bc42..79445750fcb3 100644
@@ -193,6 +193,12 @@ OPTIONS
 	Only display events for these comms. CSV that understands
 	file://filename entries.
 
+--pid=::
+	Only show events for given process ID (comma separated list).
+
+--tid=::
+	Only show events for given thread ID (comma separated list).
+
 -I::
 --show-info::
 	Display extended information about the perf.data file. This adds
tools/perf/builtin-report.c +4 -0
index 81c2f3b97c50..b5b2ad4ca9c4 100644
@@ -669,6 +669,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 		   "only consider symbols in these dsos"),
 	OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
 		   "only consider symbols in these comms"),
+	OPT_STRING(0, "pid", &symbol_conf.pid_list_str, "pid[,pid...]",
+		   "only consider symbols in these pids"),
+	OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
+		   "only consider symbols in these tids"),
 	OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
 		   "only consider these symbols"),
 	OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter",
tools/perf/builtin-script.c +4 -0
index f2a348b57b8f..662366ceb572 100644
@@ -1562,6 +1562,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 	OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
 	OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
 		   "only display events for these comms"),
+	OPT_STRING(0, "pid", &symbol_conf.pid_list_str, "pid[,pid...]",
+		   "only consider symbols in these pids"),
+	OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
+		   "only consider symbols in these tids"),
 	OPT_BOOLEAN('I', "show-info", &show_full_info,
 		    "display extended information from perf.data file"),
 	OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path,
tools/perf/util/symbol.c +30 -1
index a69066865a55..fddeb9073039 100644
@@ -15,6 +15,7 @@
 #include "machine.h"
 #include "symbol.h"
 #include "strlist.h"
+#include "intlist.h"
 #include "header.h"
 
 #include <elf.h>
@@ -1859,6 +1860,20 @@ int setup_list(struct strlist **list, const char *list_str,
 	return 0;
 }
 
+int setup_intlist(struct intlist **list, const char *list_str,
+		  const char *list_name)
+{
+	if (list_str == NULL)
+		return 0;
+
+	*list = intlist__new(list_str);
+	if (!*list) {
+		pr_err("problems parsing %s list\n", list_name);
+		return -1;
+	}
+	return 0;
+}
+
 static bool symbol__read_kptr_restrict(void)
 {
 	bool value = false;
@@ -1909,9 +1924,17 @@ int symbol__init(struct perf_session_env *env)
 		       symbol_conf.comm_list_str, "comm") < 0)
 		goto out_free_dso_list;
 
+	if (setup_intlist(&symbol_conf.pid_list,
+		       symbol_conf.pid_list_str, "pid") < 0)
+		goto out_free_comm_list;
+
+	if (setup_intlist(&symbol_conf.tid_list,
+		       symbol_conf.tid_list_str, "tid") < 0)
+		goto out_free_pid_list;
+
 	if (setup_list(&symbol_conf.sym_list,
 		       symbol_conf.sym_list_str, "symbol") < 0)
-		goto out_free_comm_list;
+		goto out_free_tid_list;
 
 	/*
 	 * A path to symbols of "/" is identical to ""
@@ -1930,6 +1953,10 @@ int symbol__init(struct perf_session_env *env)
 	symbol_conf.initialized = true;
 	return 0;
 
+out_free_tid_list:
+	intlist__delete(symbol_conf.tid_list);
+out_free_pid_list:
+	intlist__delete(symbol_conf.pid_list);
 out_free_comm_list:
 	strlist__delete(symbol_conf.comm_list);
 out_free_dso_list:
@@ -1944,6 +1971,8 @@ void symbol__exit(void)
 	strlist__delete(symbol_conf.sym_list);
 	strlist__delete(symbol_conf.dso_list);
 	strlist__delete(symbol_conf.comm_list);
+	intlist__delete(symbol_conf.tid_list);
+	intlist__delete(symbol_conf.pid_list);
 	vmlinux_path__exit();
 	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
 	symbol_conf.initialized = false;
tools/perf/util/symbol.h +7 -0
index efdaaa544041..09561500164a 100644
@@ -78,6 +78,7 @@ static inline size_t symbol__size(const struct symbol *sym)
 }
 
 struct strlist;
+struct intlist;
 
 struct symbol_conf {
 	unsigned short	priv_size;
@@ -115,6 +116,8 @@ struct symbol_conf {
 	const char	*guestmount;
 	const char	*dso_list_str,
 			*comm_list_str,
+			*pid_list_str,
+			*tid_list_str,
 			*sym_list_str,
 			*col_width_list_str;
        struct strlist	*dso_list,
@@ -124,6 +127,8 @@ struct symbol_conf {
 			*dso_to_list,
 			*sym_from_list,
 			*sym_to_list;
+	struct intlist	*pid_list,
+			*tid_list;
 	const char	*symfs;
 };
 
@@ -295,5 +300,7 @@ int compare_proc_modules(const char *from, const char *to);
 
 int setup_list(struct strlist **list, const char *list_str,
 	       const char *list_name);
+int setup_intlist(struct intlist **list, const char *list_str,
+		  const char *list_name);
 
 #endif /* __PERF_SYMBOL */
tools/perf/util/thread.h +11 -0
index 783b6688d2f7..9b8a54dc34a8 100644
@@ -7,6 +7,7 @@
 #include <sys/types.h>
 #include "symbol.h"
 #include <strlist.h>
+#include <intlist.h>
 
 struct thread_stack;
 
@@ -100,6 +101,16 @@ static inline bool thread__is_filtered(struct thread *thread)
 		return true;
 	}
 
+	if (symbol_conf.pid_list &&
+	    !intlist__has_entry(symbol_conf.pid_list, thread->pid_)) {
+		return true;
+	}
+
+	if (symbol_conf.tid_list &&
+	    !intlist__has_entry(symbol_conf.tid_list, thread->tid)) {
+		return true;
+	}
+
 	return false;
 }
 
Signature · 1 line
1.9.3