Skip to contentSkip to conversation

perf/core improvements and fixes

GIT PULL New Arnaldo Carvalho de Melo 2 participants 43 messages Aug 13, 2014 – Aug 14, 2014 perf events

lore
Share & tools
lore

Arnaldo Carvalho de Melo

author maintainer
#0 lore raw

Hi Ingo,

Please consider pulling, more to come! :-)

- Arnaldo

The following changes since commit ddcd0973fe02aad3d4bdc59dd0f1db90f51105a9:

perf/x86/uncore: Rename IvyTown to IvyBridge-EP (2014-08-13 07:51:18 +0200)

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 1c65056c547141a0cb52fb8e6056f63524d2bbf2:

perf evlist: Add perf_evlist__enable_event_idx() (2014-08-13 19:23:48 -0300)

----------------------------------------------------------------
perf/probe fixes and improvements:

User visible changes:

. Do not show +/- callchain expansion when there are no childs (top/report) (Namhyung Kim)

. Fix -z and add respective 'z' hotkey to zero samples before refresh
in 'perf top' (Namhyung Kim)

. Capability probing fixes, improving the detection of
kernel features for non-priviledged users (Adrian Hunter)

. Add beautifier for mremap flags param in 'trace' (Alex Snast)

. Fix --list and --del options to show events when just uprobes is
enabled (Masami Hiramatsu)

. perf script: Allow callchains if any event samples them

. Don't look for kernel idle symbols in all DSOs in 'perf top' (Arnaldo Carvalho de Melo)

. Add cpu_startup_entry to the list of kernel idle symbols (Arnaldo Carvalho de Melo)

. 'perf top' terminal output fixes (Jiri Olsa)

. Fix stdin handling for 'perf kvm stat live' (Jiri Olsa)

. Fix missing label symbols (Adrian Hunter)

. Don't demangle C++ parameters and such by default, only in
--verbose mode (Namhyung Kim)

. Set proper sort__mode for the branch option (Naohiro Aota)

. Check recorded kernel version when finding vmlinux (Namhyung Kim)

Developer Stuff:

. More prep work for intel PT (Adrian Hunter)

. Fix possible memory leaks (Namhyung Kim)

. Fix a memory leak in vmlinux_path__init() (Namhyung Kim)

----------------------------------------------------------------
Adrian Hunter (14):
perf tools: Fix CLOEXEC probe for perf_event_paranoid == 2 perf tools: Fix one of the probe events to exclude kernel perf tools: Fix probing the kernel API with cpu-wide events perf tools: Prefer to use a cpu-wide event for probing CLOEXEC perf symbols: Fix missing label symbols
perf evlist: Add 'system_wide' option
perf evlist: Add perf_evlist__set_tracking_event() perf session: Add perf_session__peek_event()
perf script: Allow callchains if any event samples them perf script python: Add helpers for calling Python objects perf tools: Identify which comms are from exec
perf machine: Add machine__thread_exec_comm()
perf tools: Add flags and insn_len to struct sample perf evlist: Add perf_evlist__enable_event_idx()

Alex Snast (1):
perf trace: Add beautifier for mremap flags param

Arnaldo Carvalho de Melo (2):
perf top: Don't look for kernel idle symbols in all DSOs perf tools: Add cpu_startup_entry to the list of kernel idle symbols

Jiri Olsa (4):
perf top: Join the display thread on exit
perf tools: Introduce set_term_quiet_input helper function perf top: Setup signals for terminal output
perf kvm: Fix stdin handling for 'kvm stat live' command

Masami Hiramatsu (2):
perf probe: Fix --list option to show events only with uprobe events perf probe: Fix --del option to delete events only with uprobe events

Namhyung Kim (17):
perf script: Fix possible memory leaks
perf symbols: Fix a memory leak in vmlinux_path__init() perf annotate: Move session handling out of __cmd_annotate() perf buildid-cache: Move session handling into cmd_buildid_cache() perf inject: Move session handling out of __cmd_inject() perf kmem: Move session handling out of __cmd_kmem() perf kvm: Move call to symbol__init() after creating session perf lock: Move call to symbol__init() after creating session perf sched: Move call to symbol__init() after creating session perf script: Move call to symbol__init() after creating session perf timechart: Move call to symbol__init() after creating session perf trace: Move call to symbol__init() after creating session perf tools: Check recorded kernel version when finding vmlinux perf hists browser: Fix a small callchain display bug perf top: Fix -z option behavior
perf top: Handle 'z' key for toggle zeroing samples in TUI perf symbols: Don't demangle parameters and such by default

[email protected] (1):
perf report: Set proper sort__mode for the branch option

 tools/perf/builtin-annotate.c                      |  75 +++++++-------
 tools/perf/builtin-buildid-cache.c                 |  37 ++++---
 tools/perf/builtin-diff.c                          |   2 +-
 tools/perf/builtin-inject.c                        |  31 +++---
 tools/perf/builtin-kmem.c                          |  49 +++++----
 tools/perf/builtin-kvm.c                           |  24 ++---
 tools/perf/builtin-lock.c                          |   3 +-
 tools/perf/builtin-mem.c                           |   2 +-
 tools/perf/builtin-record.c                        |   2 +-
 tools/perf/builtin-report.c                        |   4 +-
 tools/perf/builtin-sched.c                         |   3 +-
 tools/perf/builtin-script.c                        |  57 +++++++----
 tools/perf/builtin-timechart.c                     |   4 +-
 tools/perf/builtin-top.c                           |  59 ++++++++---
 tools/perf/builtin-trace.c                         |  34 +++++-
 tools/perf/tests/builtin-test.c                    |   2 +-
 tools/perf/ui/browsers/hists.c                     |  13 ++-
 tools/perf/util/cloexec.c                          |  23 ++++-
 tools/perf/util/comm.c                             |   7 +-
 tools/perf/util/comm.h                             |   6 +-
 tools/perf/util/event.h                            |   2 +
 tools/perf/util/evlist.c                           | 109 ++++++++++++++++++--
 tools/perf/util/evlist.h                           |   5 +
 tools/perf/util/evsel.c                            |  34 ++++--
 tools/perf/util/evsel.h                            |   2 +
 tools/perf/util/hist.c                             |  22 ++++
 tools/perf/util/hist.h                             |   1 +
 tools/perf/util/machine.c                          |  30 +++++-
 tools/perf/util/machine.h                          |   4 +
 tools/perf/util/probe-event.c                      |  98 ++++++++++++------
 tools/perf/util/record.c                           |  40 ++++++--
 .../util/scripting-engines/trace-event-python.c    | 114 +++++++++------------
 tools/perf/util/session.c                          |  79 +++++++++++++-
 tools/perf/util/session.h                          |   5 +
 tools/perf/util/symbol-elf.c                       |   9 +-
 tools/perf/util/symbol.c                           |  31 ++++--
 tools/perf/util/symbol.h                           |   4 +-
 tools/perf/util/thread.c                           |  24 ++++-
 tools/perf/util/thread.h                           |  10 +-
 tools/perf/util/util.c                             |  13 +++
 tools/perf/util/util.h                             |   2 +
 41 files changed, 770 insertions(+), 305 deletions(-)
author maintainer
#1 lore raw

PATCH 1/41 perf top: Don't look for kernel idle symbols in all DSOs

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

The 'top' tool initially supported only kernel symbols, when making it support userspace symbols we forgot to make the symbol filter first check that the DSO is the kernel one. Fix it.

Cc: Adrian Hunter <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Don Zickus <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
c: Stephane Eranian <[email protected]>

---
 tools/perf/builtin-top.c | 4 +++-
 tools/perf/util/symbol.c | 4 ++++
 2 files changed, 7 insertions(+), 1 deletion(-)
tools/perf/builtin-top.c +3 -1
index bde216b2071c..4fb6f726271c 100644
@@ -623,10 +623,12 @@ repeat:
 	return NULL;
 }
 
-static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
+static int symbol_filter(struct map *map, struct symbol *sym)
 {
 	const char *name = sym->name;
 
+	if (!map->dso->kernel)
+		return 0;
 	/*
 	 * ppc64 uses function descriptors and appends a '.' to the
 	 * start of every instruction address. Remove it.
tools/perf/util/symbol.c +4 -0
index f134ec138934..35a8bd56cd15 100644
@@ -523,6 +523,10 @@ struct process_kallsyms_args {
 	struct dso *dso;
 };
 
+/*
+ * These are symbols in the kernel image, so make sure that
+ * sym is from a kernel DSO.
+ */
 bool symbol__is_idle(struct symbol *sym)
 {
 	const char * const idle_symbols[] = {
Signature · 1 line
1.9.3
author maintainer
#2 lore raw

PATCH 2/41 perf tools: Add cpu_startup_entry to the list of kernel idle symbols

In reply to Arnaldo Carvalho de Melo

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

Cc Adrian Hunter <[email protected]>
Cc David Ahern <[email protected]>
Cc Don Zickus <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Mike Galbraith <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Stephane Eranian <[email protected]>
---
 tools/perf/util/symbol.c | 1 +
 1 file changed, 1 insertion(+)
tools/perf/util/symbol.c +1 -0
index 35a8bd56cd15..581c56836567 100644
@@ -531,6 +531,7 @@ bool symbol__is_idle(struct symbol *sym)
 {
 	const char * const idle_symbols[] = {
 		"cpu_idle",
+		"cpu_startup_entry",
 		"intel_idle",
 		"default_idle",
 		"native_safe_halt",
Signature · 1 line
1.9.3
author maintainer
#3 lore raw

PATCH 3/41 perf top: Join the display thread on exit

In reply to Arnaldo Carvalho de Melo

From: Jiri Olsa <[email protected]>

We create the display thread, but never join it. It gives the display thread a chance to quit and cleanup properly.

Cc Adrian Hunter <[email protected]>
Cc Corey Ashford <[email protected]>
Cc David Ahern <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Jean Pihet <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Peter Zijlstra <[email protected]>
---
 tools/perf/builtin-top.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/builtin-top.c +3 -1
index 4fb6f726271c..10fc7e844872 100644
@@ -965,7 +965,7 @@ static int __cmd_top(struct perf_top *top)
 		param.sched_priority = top->realtime_prio;
 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
 			ui__error("Could not set realtime priority.\n");
-			goto out_delete;
+			goto out_join;
 		}
 	}
 
@@ -979,6 +979,8 @@ static int __cmd_top(struct perf_top *top)
 	}
 
 	ret = 0;
+out_join:
+	pthread_join(thread, NULL);
 out_delete:
 	perf_session__delete(top->session);
 	top->session = NULL;
Signature · 1 line
1.9.3
author maintainer
#4 lore raw

PATCH 4/41 perf tools: Introduce set_term_quiet_input helper function

In reply to Arnaldo Carvalho de Melo

From: Jiri Olsa <[email protected]>

Adding set_term_quiet_input helper to set the terminal quiet, out from 'perf top', used in following patches in 'perf kvm'.

Cc Adrian Hunter <[email protected]>
Cc Corey Ashford <[email protected]>
Cc David Ahern <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Jean Pihet <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Peter Zijlstra <[email protected]>
---
 tools/perf/builtin-top.c | 10 ++--------
 tools/perf/util/util.c   | 13 +++++++++++++
 tools/perf/util/util.h   |  2 ++
 3 files changed, 17 insertions(+), 8 deletions(-)
tools/perf/builtin-top.c +2 -8
index 10fc7e844872..e8459e260c3b 100644
@@ -580,20 +580,14 @@ static void *display_thread_tui(void *arg)
 static void *display_thread(void *arg)
 {
 	struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
-	struct termios tc, save;
+	struct termios save;
 	struct perf_top *top = arg;
 	int delay_msecs, c;
 
-	tcgetattr(0, &save);
-	tc = save;
-	tc.c_lflag &= ~(ICANON | ECHO);
-	tc.c_cc[VMIN] = 0;
-	tc.c_cc[VTIME] = 0;
-
 	pthread__unblock_sigwinch();
 repeat:
 	delay_msecs = top->delay_secs * 1000;
-	tcsetattr(0, TCSANOW, &tc);
+	set_term_quiet_input(&save);
 	/* trash return*/
 	getc(stdin);
 
tools/perf/util/util.c +13 -0
index b82a93cb1694..25822bdf7bbf 100644
@@ -13,6 +13,7 @@
 #include <limits.h>
 #include <byteswap.h>
 #include <linux/kernel.h>
+#include <unistd.h>
 
 /*
  * XXX We need to find a better place for these things...
@@ -282,6 +283,18 @@ void get_term_dimensions(struct winsize *ws)
 	ws->ws_col = 80;
 }
 
+void set_term_quiet_input(struct termios *old)
+{
+	struct termios tc;
+
+	tcgetattr(0, old);
+	tc = *old;
+	tc.c_lflag &= ~(ICANON | ECHO);
+	tc.c_cc[VMIN] = 0;
+	tc.c_cc[VTIME] = 0;
+	tcsetattr(0, TCSANOW, &tc);
+}
+
 static void set_tracing_events_path(const char *mountpoint)
 {
 	snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
tools/perf/util/util.h +2 -0
index 03a1ea2266b8..d6a79b1fb28c 100644
@@ -75,6 +75,7 @@
 #include <api/fs/debugfs.h>
 #include <termios.h>
 #include <linux/bitops.h>
+#include <termios.h>
 
 extern const char *graph_line;
 extern const char *graph_dotted_line;
@@ -308,6 +309,7 @@ extern unsigned int page_size;
 extern int cacheline_size;
 
 void get_term_dimensions(struct winsize *ws);
+void set_term_quiet_input(struct termios *old);
 
 struct parse_tag {
 	char tag;
Signature · 1 line
1.9.3
author maintainer
#5 lore raw

PATCH 5/41 perf top: Setup signals for terminal output

In reply to Arnaldo Carvalho de Melo

From: Jiri Olsa <[email protected]>

The TUI code setup standard signals handling, while the stdio display code does not. This leads to premature termination of display thread when signal is received and leaving terminal in wrong state.

Also adding terminal cleanup at the end of display thread, to ensure we get the old terminal state in case of signal interruption.

Cc Adrian Hunter <[email protected]>
Cc Corey Ashford <[email protected]>
Cc David Ahern <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Jean Pihet <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Peter Zijlstra <[email protected]>
---
 tools/perf/builtin-top.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
tools/perf/builtin-top.c +16 -0
index e8459e260c3b..0ab3ea7f7525 100644
@@ -577,6 +577,20 @@ static void *display_thread_tui(void *arg)
 	return NULL;
 }
 
+static void display_sig(int sig __maybe_unused)
+{
+	done = 1;
+}
+
+static void display_setup_sig(void)
+{
+	signal(SIGSEGV, display_sig);
+	signal(SIGFPE,  display_sig);
+	signal(SIGINT,  display_sig);
+	signal(SIGQUIT, display_sig);
+	signal(SIGTERM, display_sig);
+}
+
 static void *display_thread(void *arg)
 {
 	struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -584,6 +598,7 @@ static void *display_thread(void *arg)
 	struct perf_top *top = arg;
 	int delay_msecs, c;
 
+	display_setup_sig();
 	pthread__unblock_sigwinch();
 repeat:
 	delay_msecs = top->delay_secs * 1000;
@@ -614,6 +629,7 @@ repeat:
 		}
 	}
 
+	tcsetattr(0, TCSAFLUSH, &save);
 	return NULL;
 }
 
Signature · 1 line
1.9.3
author maintainer
#6 lore raw

PATCH 6/41 perf kvm: Fix stdin handling for 'kvm stat live' command

In reply to Arnaldo Carvalho de Melo

From: Jiri Olsa <[email protected]>

Currently the initial ~(ICANON | ECHO) terminal mode is not set, so we dont get stdin data until we press ENTER.

Fixing this by early setting of the ~(ICANON | ECHO) mode and leaving this mode for whole life of the command, because canonical mode is not needed.

Cc Adrian Hunter <[email protected]>
Cc Corey Ashford <[email protected]>
Cc David Ahern <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Jean Pihet <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Peter Zijlstra <[email protected]>
---
 tools/perf/builtin-kvm.c | 18 +++++-------------
 1 file changed, 5 insertions(+), 13 deletions(-)
tools/perf/builtin-kvm.c +5 -13
index 7ccceadcd9f8..ff404750d744 100644
@@ -885,15 +885,11 @@ static int fd_set_nonblock(int fd)
 	return 0;
 }
 
-static
-int perf_kvm__handle_stdin(struct termios *tc_now, struct termios *tc_save)
+static int perf_kvm__handle_stdin(void)
 {
 	int c;
 
-	tcsetattr(0, TCSANOW, tc_now);
 	c = getc(stdin);
-	tcsetattr(0, TCSAFLUSH, tc_save);
-
 	if (c == 'q')
 		return 1;
 
@@ -904,7 +900,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
 {
 	struct pollfd *pollfds = NULL;
 	int nr_fds, nr_stdin, ret, err = -EINVAL;
-	struct termios tc, save;
+	struct termios save;
 
 	/* live flag must be set first */
 	kvm->live = true;
@@ -919,14 +915,9 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
 		goto out;
 	}
 
+	set_term_quiet_input(&save);
 	init_kvm_event_record(kvm);
 
-	tcgetattr(0, &save);
-	tc = save;
-	tc.c_lflag &= ~(ICANON | ECHO);
-	tc.c_cc[VMIN] = 0;
-	tc.c_cc[VTIME] = 0;
-
 	signal(SIGINT, sig_handler);
 	signal(SIGTERM, sig_handler);
 
@@ -972,7 +963,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
 			goto out;
 
 		if (pollfds[nr_stdin].revents & POLLIN)
-			done = perf_kvm__handle_stdin(&tc, &save);
+			done = perf_kvm__handle_stdin();
 
 		if (!rc && !done)
 			err = poll(pollfds, nr_fds, 100);
@@ -989,6 +980,7 @@ out:
 	if (kvm->timerfd >= 0)
 		close(kvm->timerfd);
 
+	tcsetattr(0, TCSAFLUSH, &save);
 	free(pollfds);
 	return err;
 }
Signature · 1 line
1.9.3
author maintainer
#7 lore raw

PATCH 7/41 perf probe: Fix --list option to show events only with uprobe events

In reply to Arnaldo Carvalho de Melo

From: Masami Hiramatsu <[email protected]>

Current perf probe --list doesn't work if only CONFIG_UPROBE_EVENTS=y because it aborts when it fails to open kprobe_events file before checking uprobe_events file.

This fixes --list option to show dynamic events if it can open either kprobe_events or uprobe_events. Only if it failed to open both of them, it shows an error message and aborts.

Without this patch, if we run perf probe -l on the kernel configured with CONFIG_KPROBE_EVENTS=n and CONFIG_UPROBE_EVENTS=y,

  # perf probe -l
  /sys/kernel/debug/tracing/kprobe_events file does not exist - please rebuild ker
    Error: Failed to show event list.

With this patch,

  # perf probe -l
    probe_perf:alloc_event (on alloc_event@lib/traceevent/event-parse.c in /home/fedora/ksrc/linux-3/tools/perf/perf)

Changes in v2:
- Use strerror_r instead of strerror.

---
 tools/perf/util/probe-event.c | 89 ++++++++++++++++++++++++++++---------------
 1 file changed, 59 insertions(+), 30 deletions(-)
tools/perf/util/probe-event.c +59 -30
index 9a0a1839a377..50aa7f05ceb1 100644
@@ -1780,10 +1780,11 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
 	memset(tev, 0, sizeof(*tev));
 }
 
-static void print_warn_msg(const char *file, bool is_kprobe)
+static void print_open_warning(int err, bool is_kprobe)
 {
+	char sbuf[128];
 
-	if (errno == ENOENT) {
+	if (err == -ENOENT) {
 		const char *config;
 
 		if (!is_kprobe)
@@ -1791,25 +1792,26 @@ static void print_warn_msg(const char *file, bool is_kprobe)
 		else
 			config = "CONFIG_KPROBE_EVENTS";
 
-		pr_warning("%s file does not exist - please rebuild kernel"
-				" with %s.\n", file, config);
-	} else
-		pr_warning("Failed to open %s file: %s\n", file,
-				strerror(errno));
+		pr_warning("%cprobe_events file does not exist"
+			   " - please rebuild kernel with %s.\n",
+			   is_kprobe ? 'k' : 'u', config);
+	} else if (err == -ENOTSUP)
+		pr_warning("Debugfs is not mounted.\n");
+	else
+		pr_warning("Failed to open %cprobe_events: %s\n",
+			   is_kprobe ? 'k' : 'u',
+			   strerror_r(-err, sbuf, sizeof(sbuf)));
 }
 
-static int open_probe_events(const char *trace_file, bool readwrite,
-				bool is_kprobe)
+static int open_probe_events(const char *trace_file, bool readwrite)
 {
 	char buf[PATH_MAX];
 	const char *__debugfs;
 	int ret;
 
 	__debugfs = debugfs_find_mountpoint();
-	if (__debugfs == NULL) {
-		pr_warning("Debugfs is not mounted.\n");
-		return -ENOENT;
-	}
+	if (__debugfs == NULL)
+		return -ENOTSUP;
 
 	ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
 	if (ret >= 0) {
@@ -1820,19 +1822,19 @@ static int open_probe_events(const char *trace_file, bool readwrite,
 			ret = open(buf, O_RDONLY, 0);
 
 		if (ret < 0)
-			print_warn_msg(buf, is_kprobe);
+			ret = -errno;
 	}
 	return ret;
 }
 
 static int open_kprobe_events(bool readwrite)
 {
-	return open_probe_events("tracing/kprobe_events", readwrite, true);
+	return open_probe_events("tracing/kprobe_events", readwrite);
 }
 
 static int open_uprobe_events(bool readwrite)
 {
-	return open_probe_events("tracing/uprobe_events", readwrite, false);
+	return open_probe_events("tracing/uprobe_events", readwrite);
 }
 
 /* Get raw string list of current kprobe_events  or uprobe_events */
@@ -1940,27 +1942,47 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
 /* List up current perf-probe events */
 int show_perf_probe_events(void)
 {
-	int fd, ret;
+	int kp_fd, up_fd, ret;
 
 	setup_pager();
-	fd = open_kprobe_events(false);
-
-	if (fd < 0)
-		return fd;
 
 	ret = init_symbol_maps(false);
 	if (ret < 0)
 		return ret;
 
-	ret = __show_perf_probe_events(fd, true);
-	close(fd);
+	kp_fd = open_kprobe_events(false);
+	if (kp_fd >= 0) {
+		ret = __show_perf_probe_events(kp_fd, true);
+		close(kp_fd);
+		if (ret < 0)
+			goto out;
+	}
 
-	fd = open_uprobe_events(false);
-	if (fd >= 0) {
-		ret = __show_perf_probe_events(fd, false);
-		close(fd);
+	up_fd = open_uprobe_events(false);
+	if (kp_fd < 0 && up_fd < 0) {
+		/* Both kprobes and uprobes are disabled, warn it. */
+		if (kp_fd == -ENOTSUP && up_fd == -ENOTSUP)
+			pr_warning("Debugfs is not mounted.\n");
+		else if (kp_fd == -ENOENT && up_fd == -ENOENT)
+			pr_warning("Please rebuild kernel with "
+				   "CONFIG_KPROBE_EVENTS or/and "
+				   "CONFIG_UPROBE_EVENTS.\n");
+		else {
+			char sbuf[128];
+			pr_warning("Failed to open kprobe events: %s.\n",
+				   strerror_r(-kp_fd, sbuf, sizeof(sbuf)));
+			pr_warning("Failed to open uprobe events: %s.\n",
+				   strerror_r(-up_fd, sbuf, sizeof(sbuf)));
+		}
+		ret = kp_fd;
+		goto out;
 	}
 
+	if (up_fd >= 0) {
+		ret = __show_perf_probe_events(up_fd, false);
+		close(up_fd);
+	}
+out:
 	exit_symbol_maps();
 	return ret;
 }
@@ -2075,8 +2097,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 	else
 		fd = open_kprobe_events(true);
 
-	if (fd < 0)
+	if (fd < 0) {
+		print_open_warning(fd, !pev->uprobes);
 		return fd;
+	}
+
 	/* Get current event names */
 	namelist = get_probe_trace_event_names(fd, false);
 	if (!namelist) {
@@ -2449,13 +2474,17 @@ int del_perf_probe_events(struct strlist *dellist)
 
 	/* Get current event names */
 	kfd = open_kprobe_events(true);
-	if (kfd < 0)
+	if (kfd < 0) {
+		print_open_warning(kfd, true);
 		return kfd;
+	}
 
 	namelist = get_probe_trace_event_names(kfd, true);
 	ufd = open_uprobe_events(true);
 
-	if (ufd >= 0)
+	if (ufd < 0)
+		print_open_warning(ufd, false);
+	else
 		unamelist = get_probe_trace_event_names(ufd, true);
 
 	if (namelist == NULL && unamelist == NULL)
Signature · 1 line
1.9.3
author maintainer
#8 lore raw

PATCH 8/41 perf probe: Fix --del option to delete events only with uprobe events

In reply to Arnaldo Carvalho de Melo

From: Masami Hiramatsu <[email protected]>

Current perf probe --del doesn't work if only CONFIG_UPROBE_EVENTS=y because it aborts when it fails to open kprobe_events file before checking uprobe_events file.

This fixes --del option to delete dynamic events if it can open either kprobe_events or uprobe_events. Only if it failed to open both of them, it shows an error message and aborts.

Without this patch, if we run perf probe -d on the kernel configured with CONFIG_KPROBE_EVENTS=n and CONFIG_UPROBE_EVENTS=y,

  # perf probe -d \*
  kprobe_events file does not exist - please rebuild kernel with CONFIG_KPROBE_EVENTS.
    Error: Failed to delete events.

With this patch,

  # perf probe -d \*
  Removed event: probe_perf:alloc_event

Changes in v2:
- Use strerror_r instead of strerror.

---
 tools/perf/util/probe-event.c | 49 +++++++++++++++++++++++--------------------
 1 file changed, 26 insertions(+), 23 deletions(-)
tools/perf/util/probe-event.c +26 -23
index 50aa7f05ceb1..443225cb62f7 100644
@@ -1803,6 +1803,23 @@ static void print_open_warning(int err, bool is_kprobe)
 			   strerror_r(-err, sbuf, sizeof(sbuf)));
 }
 
+static void print_both_open_warning(int kerr, int uerr)
+{
+	/* Both kprobes and uprobes are disabled, warn it. */
+	if (kerr == -ENOTSUP && uerr == -ENOTSUP)
+		pr_warning("Debugfs is not mounted.\n");
+	else if (kerr == -ENOENT && uerr == -ENOENT)
+		pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS "
+			   "or/and CONFIG_UPROBE_EVENTS.\n");
+	else {
+		char sbuf[128];
+		pr_warning("Failed to open kprobe events: %s.\n",
+			   strerror_r(-kerr, sbuf, sizeof(sbuf)));
+		pr_warning("Failed to open uprobe events: %s.\n",
+			   strerror_r(-uerr, sbuf, sizeof(sbuf)));
+	}
+}
+
 static int open_probe_events(const char *trace_file, bool readwrite)
 {
 	char buf[PATH_MAX];
@@ -1960,20 +1977,7 @@ int show_perf_probe_events(void)
 
 	up_fd = open_uprobe_events(false);
 	if (kp_fd < 0 && up_fd < 0) {
-		/* Both kprobes and uprobes are disabled, warn it. */
-		if (kp_fd == -ENOTSUP && up_fd == -ENOTSUP)
-			pr_warning("Debugfs is not mounted.\n");
-		else if (kp_fd == -ENOENT && up_fd == -ENOENT)
-			pr_warning("Please rebuild kernel with "
-				   "CONFIG_KPROBE_EVENTS or/and "
-				   "CONFIG_UPROBE_EVENTS.\n");
-		else {
-			char sbuf[128];
-			pr_warning("Failed to open kprobe events: %s.\n",
-				   strerror_r(-kp_fd, sbuf, sizeof(sbuf)));
-			pr_warning("Failed to open uprobe events: %s.\n",
-				   strerror_r(-up_fd, sbuf, sizeof(sbuf)));
-		}
+		print_both_open_warning(kp_fd, up_fd);
 		ret = kp_fd;
 		goto out;
 	}
@@ -2474,19 +2478,18 @@ int del_perf_probe_events(struct strlist *dellist)
 
 	/* Get current event names */
 	kfd = open_kprobe_events(true);
-	if (kfd < 0) {
-		print_open_warning(kfd, true);
-		return kfd;
-	}
+	if (kfd >= 0)
+		namelist = get_probe_trace_event_names(kfd, true);
 
-	namelist = get_probe_trace_event_names(kfd, true);
 	ufd = open_uprobe_events(true);
-
-	if (ufd < 0)
-		print_open_warning(ufd, false);
-	else
+	if (ufd >= 0)
 		unamelist = get_probe_trace_event_names(ufd, true);
 
+	if (kfd < 0 && ufd < 0) {
+		print_both_open_warning(kfd, ufd);
+		goto error;
+	}
+
 	if (namelist == NULL && unamelist == NULL)
 		goto error;
 
Signature · 1 line
1.9.3
author maintainer
#9 lore raw

PATCH 9/41 perf trace: Add beautifier for mremap flags param

In reply to Arnaldo Carvalho de Melo

From: Alex Snast <[email protected]>

~/devel/kernel/tools/perf(branch:master*) » sudo ./perf trace ~/mremap_test

     0.543 ( 0.003 ms): mprotect(start: 0x600000, len: 4096, prot: READ      ) = 0
     0.550 ( 0.003 ms): mprotect(start: 0x7f441260d000, len: 4096, prot: READ) = 0
     0.561 ( 0.010 ms): munmap(addr: 0x7f44125e2000, len: 165572             ) = 0
     0.595 ( 0.012 ms): mmap(len: 12288, prot: READ|WRITE, flags: SHARED|ANONYMOUS|LOCKED, fd: -1) = 0x12608000
     0.603 ( 0.006 ms): mremap(addr: 0x7f4412608000, old_len: 4096, new_len: 4096, flags: MAYMOVE|FIXED, new_addr: 0x7f16da295000) = 0xda295000
     0.608 ( 0.003 ms): mremap(addr: 0x7f441260a000, old_len: 4096, new_len: 4096, flags: MAYMOVE|FIXED, new_addr: 0x7f16da297000) = 0xda297000
     0.612 ( 0.003 ms): mremap(addr: 0x7f4412609000, old_len: 4096, new_len: 4096, flags: MAYMOVE|FIXED, new_addr: 0x7f16da296000) = 0xda296000
     0.619 ( 0.000 ms): exit_group(
---
 tools/perf/builtin-trace.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)
tools/perf/builtin-trace.c +26 -0
index 36ae51d61be2..20fac5083771 100644
@@ -402,6 +402,31 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
 
 #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
 
+static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
+						  struct syscall_arg *arg)
+{
+	int printed = 0, flags = arg->val;
+
+#define P_MREMAP_FLAG(n) \
+	if (flags & MREMAP_##n) { \
+		printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
+		flags &= ~MREMAP_##n; \
+	}
+
+	P_MREMAP_FLAG(MAYMOVE);
+#ifdef MREMAP_FIXED
+	P_MREMAP_FLAG(FIXED);
+#endif
+#undef P_MREMAP_FLAG
+
+	if (flags)
+		printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
+
+	return printed;
+}
+
+#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
+
 static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
 						      struct syscall_arg *arg)
 {
@@ -1004,6 +1029,7 @@ static struct syscall_fmt {
 			     [2] = SCA_MMAP_PROT, /* prot */ }, },
 	{ .name	    = "mremap",	    .hexret = true,
 	  .arg_scnprintf = { [0] = SCA_HEX, /* addr */
+			     [3] = SCA_MREMAP_FLAGS, /* flags */
 			     [4] = SCA_HEX, /* new_addr */ }, },
 	{ .name	    = "munlock",    .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Signature · 1 line
1.9.3
author maintainer
#10 lore raw

PATCH 10/41 perf tools: Fix CLOEXEC probe for perf_event_paranoid == 2

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

With /proc/sys/kernel/perf_event_paranoid set to 2, the probe of PERF_FLAG_FD_CLOEXEC would fail. Fix by excluding kernel profiling from the probe event.

---
 tools/perf/util/cloexec.c | 1 +
 1 file changed, 1 insertion(+)
tools/perf/util/cloexec.c +1 -0
index 5073c01af618..000047cb3fee 100644
@@ -11,6 +11,7 @@ static int perf_flag_probe(void)
 	struct perf_event_attr attr = {
 		.type = PERF_TYPE_SOFTWARE,
 		.config = PERF_COUNT_SW_CPU_CLOCK,
+		.exclude_kernel = 1,
 	};
 	int fd;
 	int err;
Signature · 1 line
1.9.3
author maintainer
#11 lore raw

PATCH 11/41 perf tools: Fix one of the probe events to exclude kernel

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

When probing the kernel API the kernel should be excluded otherwise the probe will fail for users with insufficient privilege to profile the kernel.

---
 tools/perf/util/record.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/record.c +1 -1
index fe8079edbdc1..58267a85705f 100644
@@ -47,7 +47,7 @@ out_delete:
 
 static bool perf_probe_api(setup_probe_fn_t fn)
 {
-	const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL};
+	const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL};
 	struct cpu_map *cpus;
 	int cpu, ret, i = 0;
 
Signature · 1 line
1.9.3
author maintainer
#12 lore raw

PATCH 12/41 perf tools: Fix probing the kernel API with cpu-wide events

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

Fall back to probing with the current pid if cpu-wide probing fails. This primarily affects the setting of comm_exec flag when the user is un-privileged and /proc/sys/kernel/perf_event_paranoid > 0.

The change to comm_exec can be observed by using -vv with perf record and a kernel that supports comm_exec.

---
 tools/perf/util/record.c | 36 +++++++++++++++++++++++++++---------
 1 file changed, 27 insertions(+), 9 deletions(-)
tools/perf/util/record.c +27 -9
index 58267a85705f..e778afda0fb9 100644
@@ -14,6 +14,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
 	struct perf_evsel *evsel;
 	unsigned long flags = perf_event_open_cloexec_flag();
 	int err = -EAGAIN, fd;
+	static pid_t pid = -1;
 
 	evlist = perf_evlist__new();
 	if (!evlist)
@@ -24,14 +25,22 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
 
 	evsel = perf_evlist__first(evlist);
 
-	fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
-	if (fd < 0)
-		goto out_delete;
+	while (1) {
+		fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags);
+		if (fd < 0) {
+			if (pid == -1 && errno == EACCES) {
+				pid = 0;
+				continue;
+			}
+			goto out_delete;
+		}
+		break;
+	}
 	close(fd);
 
 	fn(evsel);
 
-	fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
+	fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags);
 	if (fd < 0) {
 		if (errno == EINVAL)
 			err = -EINVAL;
@@ -201,6 +210,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
 	struct perf_evsel *evsel;
 	int err, fd, cpu;
 	bool ret = false;
+	pid_t pid = -1;
 
 	temp_evlist = perf_evlist__new();
 	if (!temp_evlist)
@@ -221,12 +231,20 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
 		cpu = evlist->cpus->map[0];
 	}
 
-	fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1,
-				 perf_event_open_cloexec_flag());
-	if (fd >= 0) {
-		close(fd);
-		ret = true;
+	while (1) {
+		fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1,
+					 perf_event_open_cloexec_flag());
+		if (fd < 0) {
+			if (pid == -1 && errno == EACCES) {
+				pid = 0;
+				continue;
+			}
+			goto out_delete;
+		}
+		break;
 	}
+	close(fd);
+	ret = true;
 
 out_delete:
 	perf_evlist__delete(temp_evlist);
Signature · 1 line
1.9.3
author maintainer
#13 lore raw

PATCH 13/41 perf tools: Prefer to use a cpu-wide event for probing CLOEXEC

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

When doing a system-wide trace with Intel PT, the jump label set up as a result of probing CLOEXEC gets reset while the trace is running. That causes an Intel PT decoding error because the object code (obtained from /proc/kcore) does not match the running code at that point. While we can't expect there never to be jump label changes, we can avoid cases that the perf tool itself creates.

The problem is avoided by first trying a cpu-wide event (pid = -1) for probing the PERF_FLAG_FD_CLOEXEC flag and falling back to an event for the current process (pid = 0).

---
 tools/perf/util/cloexec.c | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)
tools/perf/util/cloexec.c +18 -4
index 000047cb3fee..4945aa56a017 100644
@@ -1,3 +1,4 @@
+#include <sched.h>
 #include "util.h"
 #include "../perf.h"
 #include "cloexec.h"
@@ -15,10 +16,23 @@ static int perf_flag_probe(void)
 	};
 	int fd;
 	int err;
+	int cpu;
+	pid_t pid = -1;
 
-	/* check cloexec flag */
-	fd = sys_perf_event_open(&attr, 0, -1, -1,
-				 PERF_FLAG_FD_CLOEXEC);
+	cpu = sched_getcpu();
+	if (cpu < 0)
+		cpu = 0;
+
+	while (1) {
+		/* check cloexec flag */
+		fd = sys_perf_event_open(&attr, pid, cpu, -1,
+					 PERF_FLAG_FD_CLOEXEC);
+		if (fd < 0 && pid == -1 && errno == EACCES) {
+			pid = 0;
+			continue;
+		}
+		break;
+	}
 	err = errno;
 
 	if (fd >= 0) {
@@ -31,7 +45,7 @@ static int perf_flag_probe(void)
 		  err, strerror(err));
 
 	/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
-	fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
+	fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
 	err = errno;
 
 	if (WARN_ONCE(fd < 0 && err != EBUSY,
Signature · 1 line
1.9.3
author maintainer
#14 lore raw

PATCH 14/41 perf script: Fix possible memory leaks

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

Some paths in perf script don't call perf_session__delete() after creating a new session.

Cc Adrian Hunter <[email protected]>
Cc David Ahern <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Minchan Kim <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Peter Zijlstra <[email protected]>
[ Saved errno value before calling perror(), as pointed out by Adrian Hunter ]
---
 tools/perf/builtin-script.c | 35 ++++++++++++++++++++++-------------
 1 file changed, 22 insertions(+), 13 deletions(-)
tools/perf/builtin-script.c +22 -13
index 868c17d09762..c84d723e0484 100644
@@ -1471,12 +1471,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 	bool show_full_info = false;
 	bool header = false;
 	bool header_only = false;
+	bool script_started = false;
 	char *rec_script_path = NULL;
 	char *rep_script_path = NULL;
 	struct perf_session *session;
 	char *script_path = NULL;
 	const char **__argv;
-	int i, j, err;
+	int i, j, err = 0;
 	struct perf_script script = {
 		.tool = {
 			.sample		 = process_sample_event,
@@ -1730,14 +1731,15 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 	if (header || header_only) {
 		perf_session__fprintf_info(session, stdout, show_full_info);
 		if (header_only)
-			return 0;
+			goto out_delete;
 	}
 
 	script.session = session;
 
 	if (cpu_list) {
-		if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
-			return -1;
+		err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
+		if (err < 0)
+			goto out_delete;
 	}
 
 	if (!no_callchain)
@@ -1752,53 +1754,60 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 		if (output_set_by_user()) {
 			fprintf(stderr,
 				"custom fields not supported for generated scripts");
-			return -1;
+			err = -EINVAL;
+			goto out_delete;
 		}
 
 		input = open(file.path, O_RDONLY);	/* input_name */
 		if (input < 0) {
+			err = -errno;
 			perror("failed to open file");
-			return -1;
+			goto out_delete;
 		}
 
 		err = fstat(input, &perf_stat);
 		if (err < 0) {
 			perror("failed to stat file");
-			return -1;
+			goto out_delete;
 		}
 
 		if (!perf_stat.st_size) {
 			fprintf(stderr, "zero-sized file, nothing to do!\n");
-			return 0;
+			goto out_delete;
 		}
 
 		scripting_ops = script_spec__lookup(generate_script_lang);
 		if (!scripting_ops) {
 			fprintf(stderr, "invalid language specifier");
-			return -1;
+			err = -ENOENT;
+			goto out_delete;
 		}
 
 		err = scripting_ops->generate_script(session->tevent.pevent,
 						     "perf-script");
-		goto out;
+		goto out_delete;
 	}
 
 	if (script_name) {
 		err = scripting_ops->start_script(script_name, argc, argv);
 		if (err)
-			goto out;
+			goto out_delete;
 		pr_debug("perf script started with script %s\n\n", script_name);
+		script_started = true;
 	}
 
 
 	err = perf_session__check_output_opt(session);
 	if (err < 0)
-		goto out;
+		goto out_delete;
 
 	err = __cmd_script(&script);
 
+out_delete:
 	perf_session__delete(session);
-	cleanup_scripting();
+
+	if (script_started)
+		cleanup_scripting();
 out:
 	return err;
 }
Signature · 1 line
1.9.3
author maintainer
#15 lore raw

PATCH 15/41 perf symbols: Fix a memory leak in vmlinux_path__init()

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

When uname() failed, it should free vmlinux_path.

---
 tools/perf/util/symbol.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/symbol.c +1 -1
index 581c56836567..009a9d064f11 100644
@@ -1772,7 +1772,7 @@ static int vmlinux_path__init(void)
 		return 0;
 
 	if (uname(&uts) < 0)
-		return -1;
+		goto out_fail;
 
 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
Signature · 1 line
1.9.3
author maintainer
#16 lore raw

PATCH 16/41 perf annotate: Move session handling out of __cmd_annotate()

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init().

---
 tools/perf/builtin-annotate.c | 75 +++++++++++++++++++++++--------------------
 1 file changed, 40 insertions(+), 35 deletions(-)
tools/perf/builtin-annotate.c +40 -35
index 952b5ece6740..c0464dc38057 100644
@@ -36,7 +36,8 @@
 
 struct perf_annotate {
 	struct perf_tool tool;
-	bool	   force, use_tui, use_stdio, use_gtk;
+	struct perf_session *session;
+	bool	   use_tui, use_stdio, use_gtk;
 	bool	   full_paths;
 	bool	   print_line;
 	bool	   skip_missing;
@@ -188,18 +189,9 @@ find_next:
 static int __cmd_annotate(struct perf_annotate *ann)
 {
 	int ret;
-	struct perf_session *session;
+	struct perf_session *session = ann->session;
 	struct perf_evsel *pos;
 	u64 total_nr_samples;
-	struct perf_data_file file = {
-		.path  = input_name,
-		.mode  = PERF_DATA_MODE_READ,
-		.force = ann->force,
-	};
-
-	session = perf_session__new(&file, false, &ann->tool);
-	if (session == NULL)
-		return -ENOMEM;
 
 	machines__set_symbol_filter(&session->machines, symbol__annotate_init);
 
@@ -207,22 +199,22 @@ static int __cmd_annotate(struct perf_annotate *ann)
 		ret = perf_session__cpu_bitmap(session, ann->cpu_list,
 					       ann->cpu_bitmap);
 		if (ret)
-			goto out_delete;
+			goto out;
 	}
 
 	if (!objdump_path) {
 		ret = perf_session_env__lookup_objdump(&session->header.env);
 		if (ret)
-			goto out_delete;
+			goto out;
 	}
 
 	ret = perf_session__process_events(session, &ann->tool);
 	if (ret)
-		goto out_delete;
+		goto out;
 
 	if (dump_trace) {
 		perf_session__fprintf_nr_events(session, stdout);
-		goto out_delete;
+		goto out;
 	}
 
 	if (verbose > 3)
@@ -250,8 +242,8 @@ static int __cmd_annotate(struct perf_annotate *ann)
 	}
 
 	if (total_nr_samples == 0) {
-		ui__error("The %s file has no samples!\n", file.path);
-		goto out_delete;
+		ui__error("The %s file has no samples!\n", session->file->path);
+		goto out;
 	}
 
 	if (use_browser == 2) {
@@ -261,24 +253,12 @@ static int __cmd_annotate(struct perf_annotate *ann)
 					 "perf_gtk__show_annotations");
 		if (show_annotations == NULL) {
 			ui__error("GTK browser not found!\n");
-			goto out_delete;
+			goto out;
 		}
 		show_annotations();
 	}
 
-out_delete:
-	/*
-	 * Speed up the exit process, for large files this can
-	 * take quite a while.
-	 *
-	 * XXX Enable this when using valgrind or if we ever
-	 * librarize this command.
-	 *
-	 * Also experiment with obstacks to see how much speed
-	 * up we'll get here.
-	 *
-	 * perf_session__delete(session);
-	 */
+out:
 	return ret;
 }
 
@@ -301,6 +281,10 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
 			.ordering_requires_timestamps = true,
 		},
 	};
+	struct perf_data_file file = {
+		.path  = input_name,
+		.mode  = PERF_DATA_MODE_READ,
+	};
 	const struct option options[] = {
 	OPT_STRING('i', "input", &input_name, "file",
 		    "input file name"),
@@ -308,7 +292,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
 		   "only consider symbols in these dsos"),
 	OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol",
 		    "symbol to annotate"),
-	OPT_BOOLEAN('f', "force", &annotate.force, "don't complain, do it"),
+	OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
 	OPT_INCR('v', "verbose", &verbose,
 		    "be more verbose (show symbol address, etc)"),
 	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
@@ -341,6 +325,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
 		    "Show event group information together"),
 	OPT_END()
 	};
+	int ret;
 
 	argc = parse_options(argc, argv, options, annotate_usage, 0);
 
@@ -353,11 +338,16 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
 
 	setup_browser(true);
 
+	annotate.session = perf_session__new(&file, false, &annotate.tool);
+	if (annotate.session == NULL)
+		return -ENOMEM;
+
 	symbol_conf.priv_size = sizeof(struct annotation);
 	symbol_conf.try_vmlinux_path = true;
 
-	if (symbol__init() < 0)
-		return -1;
+	ret = symbol__init();
+	if (ret < 0)
+		goto out_delete;
 
 	if (setup_sorting() < 0)
 		usage_with_options(annotate_usage, options);
@@ -373,5 +363,20 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
 		annotate.sym_hist_filter = argv[0];
 	}
 
-	return __cmd_annotate(&annotate);
+	ret = __cmd_annotate(&annotate);
+
+out_delete:
+	/*
+	 * Speed up the exit process, for large files this can
+	 * take quite a while.
+	 *
+	 * XXX Enable this when using valgrind or if we ever
+	 * librarize this command.
+	 *
+	 * Also experiment with obstacks to see how much speed
+	 * up we'll get here.
+	 *
+	 * perf_session__delete(session);
+	 */
+	return ret;
 }
Signature · 1 line
1.9.3
author maintainer
#17 lore raw

PATCH 17/41 perf buildid-cache: Move session handling into cmd_buildid_cache()

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init().

---
 tools/perf/builtin-buildid-cache.c | 35 +++++++++++++++++++++--------------
 1 file changed, 21 insertions(+), 14 deletions(-)
tools/perf/builtin-buildid-cache.c +21 -14
index 2a2c78f80876..d91bfa6632e8 100644
@@ -246,20 +246,9 @@ static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
 	return true;
 }
 
-static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp)
+static int build_id_cache__fprintf_missing(struct perf_session *session, FILE *fp)
 {
-	struct perf_data_file file = {
-		.path  = filename,
-		.mode  = PERF_DATA_MODE_READ,
-		.force = force,
-	};
-	struct perf_session *session = perf_session__new(&file, false, NULL);
-	if (session == NULL)
-		return -1;
-
 	perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0);
-	perf_session__delete(session);
-
 	return 0;
 }
 
@@ -303,6 +292,11 @@ int cmd_buildid_cache(int argc, const char **argv,
 		   *update_name_list_str = NULL,
 		   *kcore_filename;
 
+	struct perf_data_file file = {
+		.mode  = PERF_DATA_MODE_READ,
+	};
+	struct perf_session *session = NULL;
+
 	const struct option buildid_cache_options[] = {
 	OPT_STRING('a', "add", &add_name_list_str,
 		   "file list", "file(s) to add"),
@@ -326,8 +320,17 @@ int cmd_buildid_cache(int argc, const char **argv,
 	argc = parse_options(argc, argv, buildid_cache_options,
 			     buildid_cache_usage, 0);
 
+	if (missing_filename) {
+		file.path = missing_filename;
+		file.force = force;
+
+		session = perf_session__new(&file, false, NULL);
+		if (session == NULL)
+			return -1;
+	}
+
 	if (symbol__init() < 0)
-		return -1;
+		goto out;
 
 	setup_pager();
 
@@ -370,7 +373,7 @@ int cmd_buildid_cache(int argc, const char **argv,
 	}
 
 	if (missing_filename)
-		ret = build_id_cache__fprintf_missing(missing_filename, force, stdout);
+		ret = build_id_cache__fprintf_missing(session, stdout);
 
 	if (update_name_list_str) {
 		list = strlist__new(true, update_name_list_str);
@@ -394,5 +397,9 @@ int cmd_buildid_cache(int argc, const char **argv,
 	    build_id_cache__add_kcore(kcore_filename, debugdir, force))
 		pr_warning("Couldn't add %s\n", kcore_filename);
 
+out:
+	if (session)
+		perf_session__delete(session);
+
 	return ret;
 }
Signature · 1 line
1.9.3
author maintainer
#18 lore raw

PATCH 18/41 perf inject: Move session handling out of __cmd_inject()

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init().

---
 tools/perf/builtin-inject.c | 29 +++++++++++++++++------------
 1 file changed, 17 insertions(+), 12 deletions(-)
tools/perf/builtin-inject.c +17 -12
index ee875cca13b1..18eaefd3cd0c 100644
@@ -23,6 +23,7 @@
 
 struct perf_inject {
 	struct perf_tool	tool;
+	struct perf_session	*session;
 	bool			build_ids;
 	bool			sched_stat;
 	const char		*input_name;
@@ -340,12 +341,8 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel,
 
 static int __cmd_inject(struct perf_inject *inject)
 {
-	struct perf_session *session;
 	int ret = -EINVAL;
-	struct perf_data_file file = {
-		.path = inject->input_name,
-		.mode = PERF_DATA_MODE_READ,
-	};
+	struct perf_session *session = inject->session;
 	struct perf_data_file *file_out = &inject->output;
 
 	signal(SIGINT, sig_handler);
@@ -357,10 +354,6 @@ static int __cmd_inject(struct perf_inject *inject)
 		inject->tool.tracing_data = perf_event__repipe_tracing_data;
 	}
 
-	session = perf_session__new(&file, true, &inject->tool);
-	if (session == NULL)
-		return -ENOMEM;
-
 	if (inject->build_ids) {
 		inject->tool.sample = perf_event__inject_buildid;
 	} else if (inject->sched_stat) {
@@ -396,8 +389,6 @@ static int __cmd_inject(struct perf_inject *inject)
 		perf_session__write_header(session, session->evlist, file_out->fd, true);
 	}
 
-	perf_session__delete(session);
-
 	return ret;
 }
 
@@ -427,6 +418,11 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 			.mode = PERF_DATA_MODE_WRITE,
 		},
 	};
+	struct perf_data_file file = {
+		.mode = PERF_DATA_MODE_READ,
+	};
+	int ret;
+
 	const struct option options[] = {
 		OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
 			    "Inject build-ids into the output stream"),
@@ -461,8 +457,17 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 		return -1;
 	}
 
+	file.path = inject.input_name;
+	inject.session = perf_session__new(&file, true, &inject.tool);
+	if (inject.session == NULL)
+		return -ENOMEM;
+
 	if (symbol__init() < 0)
 		return -1;
 
-	return __cmd_inject(&inject);
+	ret = __cmd_inject(&inject);
+
+	perf_session__delete(inject.session);
+
+	return ret;
 }
Signature · 1 line
1.9.3
author maintainer
#19 lore raw

PATCH 19/41 perf kmem: Move session handling out of __cmd_kmem()

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init().

---
 tools/perf/builtin-kmem.c | 49 +++++++++++++++++++++++++++--------------------
 1 file changed, 28 insertions(+), 21 deletions(-)
tools/perf/builtin-kmem.c +28 -21
index 84b82397a28e..349d9b46098e 100644
@@ -405,10 +405,9 @@ static void sort_result(void)
 	__sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
 }
 
-static int __cmd_kmem(void)
+static int __cmd_kmem(struct perf_session *session)
 {
 	int err = -EINVAL;
-	struct perf_session *session;
 	const struct perf_evsel_str_handler kmem_tracepoints[] = {
 		{ "kmem:kmalloc",		perf_evsel__process_alloc_event, },
     		{ "kmem:kmem_cache_alloc",	perf_evsel__process_alloc_event, },
@@ -417,31 +416,22 @@ static int __cmd_kmem(void)
 		{ "kmem:kfree",			perf_evsel__process_free_event, },
     		{ "kmem:kmem_cache_free",	perf_evsel__process_free_event, },
 	};
-	struct perf_data_file file = {
-		.path = input_name,
-		.mode = PERF_DATA_MODE_READ,
-	};
-
-	session = perf_session__new(&file, false, &perf_kmem);
-	if (session == NULL)
-		return -ENOMEM;
 
 	if (!perf_session__has_traces(session, "kmem record"))
-		goto out_delete;
+		goto out;
 
 	if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) {
 		pr_err("Initializing perf session tracepoint handlers failed\n");
-		return -1;
+		goto out;
 	}
 
 	setup_pager();
 	err = perf_session__process_events(session, &perf_kmem);
 	if (err != 0)
-		goto out_delete;
+		goto out;
 	sort_result();
 	print_result(session);
-out_delete:
-	perf_session__delete(session);
+out:
 	return err;
 }
 
@@ -688,29 +678,46 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
 		NULL,
 		NULL
 	};
+	struct perf_session *session;
+	struct perf_data_file file = {
+		.path = input_name,
+		.mode = PERF_DATA_MODE_READ,
+	};
+	int ret = -1;
+
 	argc = parse_options_subcommand(argc, argv, kmem_options,
 					kmem_subcommands, kmem_usage, 0);
 
 	if (!argc)
 		usage_with_options(kmem_usage, kmem_options);
 
-	symbol__init();
-
 	if (!strncmp(argv[0], "rec", 3)) {
+		symbol__init();
 		return __cmd_record(argc, argv);
-	} else if (!strcmp(argv[0], "stat")) {
+	}
+
+	session = perf_session__new(&file, false, &perf_kmem);
+	if (session == NULL)
+		return -ENOMEM;
+
+	symbol__init();
+
+	if (!strcmp(argv[0], "stat")) {
 		if (cpu__setup_cpunode_map())
-			return -1;
+			goto out_delete;
 
 		if (list_empty(&caller_sort))
 			setup_sorting(&caller_sort, default_sort_order);
 		if (list_empty(&alloc_sort))
 			setup_sorting(&alloc_sort, default_sort_order);
 
-		return __cmd_kmem();
+		ret = __cmd_kmem(session);
 	} else
 		usage_with_options(kmem_usage, kmem_options);
 
-	return 0;
+out_delete:
+	perf_session__delete(session);
+
+	return ret;
 }
 
Signature · 1 line
1.9.3
author maintainer
#20 lore raw

PATCH 20/41 perf kvm: Move call to symbol__init() after creating session

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init().

---
 tools/perf/builtin-kvm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
tools/perf/builtin-kvm.c +2 -2
index ff404750d744..7f2b55513863 100644
@@ -1064,6 +1064,8 @@ static int read_events(struct perf_kvm_stat *kvm)
 		return -EINVAL;
 	}
 
+	symbol__init();
+
 	if (!perf_session__has_traces(kvm->session, "kvm record"))
 		return -EINVAL;
 
@@ -1193,8 +1195,6 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
 		NULL
 	};
 
-	symbol__init();
-
 	if (argc) {
 		argc = parse_options(argc, argv,
 				     kvm_events_report_options,
Signature · 1 line
1.9.3
author maintainer
#21 lore raw

PATCH 21/41 perf lock: Move call to symbol__init() after creating session

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init().

---
 tools/perf/builtin-lock.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/builtin-lock.c +2 -1
index c8122d323621..d73580b39908 100644
@@ -865,6 +865,8 @@ static int __cmd_report(bool display_info)
 		return -ENOMEM;
 	}
 
+	symbol__init();
+
 	if (!perf_session__has_traces(session, "lock record"))
 		goto out_delete;
 
@@ -974,7 +976,6 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
 	unsigned int i;
 	int rc = 0;
 
-	symbol__init();
 	for (i = 0; i < LOCKHASH_SIZE; i++)
 		INIT_LIST_HEAD(lockhash_table + i);
 
Signature · 1 line
1.9.3
author maintainer
#22 lore raw

PATCH 22/41 perf sched: Move call to symbol__init() after creating session

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init().

---
 tools/perf/builtin-sched.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/builtin-sched.c +2 -1
index 7c16aeb6b675..dcd9ebf5a7df 100644
@@ -1462,6 +1462,8 @@ static int perf_sched__read_events(struct perf_sched *sched,
 		return -1;
 	}
 
+	symbol__init();
+
 	if (perf_session__set_tracepoints_handlers(session, handlers))
 		goto out_delete;
 
@@ -1747,7 +1749,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
 	if (!strcmp(argv[0], "script"))
 		return cmd_script(argc, argv, prefix);
 
-	symbol__init();
 	if (!strncmp(argv[0], "rec", 3)) {
 		return __cmd_record(argc, argv);
 	} else if (!strncmp(argv[0], "lat", 3)) {
Signature · 1 line
1.9.3
author maintainer
#23 lore raw

PATCH 23/41 perf script: Move call to symbol__init() after creating session

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init().

---
 tools/perf/builtin-script.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
tools/perf/builtin-script.c +3 -2
index c84d723e0484..9ca7a2d03f17 100644
@@ -1719,8 +1719,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 		exit(-1);
 	}
 
-	if (symbol__init() < 0)
-		return -1;
 	if (!script_name)
 		setup_pager();
 
@@ -1734,6 +1732,9 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 			goto out_delete;
 	}
 
+	if (symbol__init() < 0)
+		goto out_delete;
+
 	script.session = session;
 
 	if (cpu_list) {
Signature · 1 line
1.9.3
author maintainer
#24 lore raw

PATCH 24/41 perf timechart: Move call to symbol__init() after creating session

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init().

---
 tools/perf/builtin-timechart.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
tools/perf/builtin-timechart.c +2 -2
index 912e3b5bb22b..df3b1c5ae7b9 100644
@@ -1607,6 +1607,8 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
 	if (session == NULL)
 		return -ENOMEM;
 
+	symbol__init();
+
 	(void)perf_header__process_sections(&session->header,
 					    perf_data_file__fd(session->file),
 					    tchart,
@@ -1982,8 +1984,6 @@ int cmd_timechart(int argc, const char **argv,
 		return -1;
 	}
 
-	symbol__init();
-
 	if (argc && !strncmp(argv[0], "rec", 3)) {
 		argc = parse_options(argc, argv, record_options, record_usage,
 				     PARSE_OPT_STOP_AT_NON_OPTION);
Signature · 1 line
1.9.3
author maintainer
#25 lore raw

PATCH 25/41 perf trace: Move call to symbol__init() after creating session

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init().

---
 tools/perf/builtin-trace.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
tools/perf/builtin-trace.c +3 -3
index 20fac5083771..8a83bd835327 100644
@@ -2241,13 +2241,13 @@ static int trace__replay(struct trace *trace)
 	/* add tid to output */
 	trace->multiple_threads = true;
 
-	if (symbol__init() < 0)
-		return -1;
-
 	session = perf_session__new(&file, false, &trace->tool);
 	if (session == NULL)
 		return -ENOMEM;
 
+	if (symbol__init() < 0)
+		goto out;
+
 	trace->host = &session->machines.host;
 
 	err = perf_session__set_tracepoints_handlers(session, handlers);
Signature · 1 line
1.9.3
author maintainer
#26 lore raw

PATCH 26/41 perf tools: Check recorded kernel version when finding vmlinux

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

Currently vmlinux_path__init() only tries to find vmlinux file from current directory, /boot and some canonical directories with version number of the running kernel. This can be a problem when reporting old data recorded on a kernel version not running currently.

We can use --symfs option for this but it's annoying for user to do it always. As we already have the info in the perf.data file, it can be changed to use it for the search automatically.

Before:

  $ perf report
  ...
  # Samples: 4K of event 'cpu-clock'
  # Event count (approx.): 1067250000
  #
  # Overhead  Command     Shared Object      Symbol
  # ........  ..........  .................  ..............................
      71.87%     swapper  [kernel.kallsyms]  [k] recover_probed_instruction

After:

  # Overhead  Command     Shared Object      Symbol
  # ........  ..........  .................  ....................
      71.87%     swapper  [kernel.kallsyms]  [k] native_safe_halt

This requires to change signature of symbol__init() to receive struct perf_session_env *.

Cc Adrian Hunter <[email protected]>
Cc David Ahern <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Masami Hiramatsu <[email protected]>
Cc Minchan Kim <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Stephane Eranian <[email protected]>
---
 tools/perf/builtin-annotate.c      |  2 +-
 tools/perf/builtin-buildid-cache.c |  2 +-
 tools/perf/builtin-diff.c          |  2 +-
 tools/perf/builtin-inject.c        |  2 +-
 tools/perf/builtin-kmem.c          |  4 ++--
 tools/perf/builtin-kvm.c           |  4 ++--
 tools/perf/builtin-lock.c          |  2 +-
 tools/perf/builtin-mem.c           |  2 +-
 tools/perf/builtin-record.c        |  2 +-
 tools/perf/builtin-report.c        |  2 +-
 tools/perf/builtin-sched.c         |  2 +-
 tools/perf/builtin-script.c        |  2 +-
 tools/perf/builtin-timechart.c     |  2 +-
 tools/perf/builtin-top.c           |  2 +-
 tools/perf/builtin-trace.c         |  4 ++--
 tools/perf/tests/builtin-test.c    |  2 +-
 tools/perf/util/probe-event.c      |  2 +-
 tools/perf/util/symbol.c           | 26 +++++++++++++++++---------
 tools/perf/util/symbol.h           |  3 ++-
 19 files changed, 39 insertions(+), 30 deletions(-)
tools/perf/builtin-annotate.c +1 -1
index c0464dc38057..d4da6929597f 100644
@@ -345,7 +345,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
 	symbol_conf.priv_size = sizeof(struct annotation);
 	symbol_conf.try_vmlinux_path = true;
 
-	ret = symbol__init();
+	ret = symbol__init(&annotate.session->header.env);
 	if (ret < 0)
 		goto out_delete;
 
tools/perf/builtin-buildid-cache.c +1 -1
index d91bfa6632e8..ac5838e0b1bd 100644
@@ -329,7 +329,7 @@ int cmd_buildid_cache(int argc, const char **argv,
 			return -1;
 	}
 
-	if (symbol__init() < 0)
+	if (symbol__init(session ? &session->header.env : NULL) < 0)
 		goto out;
 
 	setup_pager();
tools/perf/builtin-diff.c +1 -1
index c10cc44bae19..190d0b6b28cc 100644
@@ -1143,7 +1143,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
 
 	argc = parse_options(argc, argv, options, diff_usage, 0);
 
-	if (symbol__init() < 0)
+	if (symbol__init(NULL) < 0)
 		return -1;
 
 	if (data_init(argc, argv) < 0)
tools/perf/builtin-inject.c +1 -1
index 18eaefd3cd0c..3a62b6b3c8fd 100644
@@ -462,7 +462,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 	if (inject.session == NULL)
 		return -ENOMEM;
 
-	if (symbol__init() < 0)
+	if (symbol__init(&inject.session->header.env) < 0)
 		return -1;
 
 	ret = __cmd_inject(&inject);
tools/perf/builtin-kmem.c +2 -2
index 349d9b46098e..23762187a219 100644
@@ -692,7 +692,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
 		usage_with_options(kmem_usage, kmem_options);
 
 	if (!strncmp(argv[0], "rec", 3)) {
-		symbol__init();
+		symbol__init(NULL);
 		return __cmd_record(argc, argv);
 	}
 
@@ -700,7 +700,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
 	if (session == NULL)
 		return -ENOMEM;
 
-	symbol__init();
+	symbol__init(&session->header.env);
 
 	if (!strcmp(argv[0], "stat")) {
 		if (cpu__setup_cpunode_map())
tools/perf/builtin-kvm.c +2 -2
index 7f2b55513863..14d03edc81c2 100644
@@ -1064,7 +1064,7 @@ static int read_events(struct perf_kvm_stat *kvm)
 		return -EINVAL;
 	}
 
-	symbol__init();
+	symbol__init(&kvm->session->header.env);
 
 	if (!perf_session__has_traces(kvm->session, "kvm record"))
 		return -EINVAL;
@@ -1314,7 +1314,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
 	kvm->opts.target.uid_str = NULL;
 	kvm->opts.target.uid = UINT_MAX;
 
-	symbol__init();
+	symbol__init(NULL);
 	disable_buildid_cache();
 
 	use_browser = 0;
tools/perf/builtin-lock.c +1 -1
index d73580b39908..92790ed7af45 100644
@@ -865,7 +865,7 @@ static int __cmd_report(bool display_info)
 		return -ENOMEM;
 	}
 
-	symbol__init();
+	symbol__init(&session->header.env);
 
 	if (!perf_session__has_traces(session, "lock record"))
 		goto out_delete;
tools/perf/builtin-mem.c +1 -1
index 80e57c84adef..8b4a87fe3858 100644
@@ -133,7 +133,7 @@ static int report_raw_events(struct perf_mem *mem)
 			goto out_delete;
 	}
 
-	if (symbol__init() < 0)
+	if (symbol__init(&session->header.env) < 0)
 		return -1;
 
 	printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n");
tools/perf/builtin-record.c +1 -1
index ca0251e8470d..4db670d4b8da 100644
@@ -908,7 +908,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
 		usage_with_options(record_usage, record_options);
 	}
 
-	symbol__init();
+	symbol__init(NULL);
 
 	if (symbol_conf.kptr_restrict)
 		pr_warning(
tools/perf/builtin-report.c +1 -1
index 041e93da13e4..b9e0fcac4d71 100644
@@ -798,7 +798,7 @@ repeat:
 		}
 	}
 
-	if (symbol__init() < 0)
+	if (symbol__init(&session->header.env) < 0)
 		goto error;
 
 	if (argc) {
tools/perf/builtin-sched.c +1 -1
index dcd9ebf5a7df..f5874a27b346 100644
@@ -1462,7 +1462,7 @@ static int perf_sched__read_events(struct perf_sched *sched,
 		return -1;
 	}
 
-	symbol__init();
+	symbol__init(&session->header.env);
 
 	if (perf_session__set_tracepoints_handlers(session, handlers))
 		goto out_delete;
tools/perf/builtin-script.c +1 -1
index 9ca7a2d03f17..37d2b608d388 100644
@@ -1732,7 +1732,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 			goto out_delete;
 	}
 
-	if (symbol__init() < 0)
+	if (symbol__init(&session->header.env) < 0)
 		goto out_delete;
 
 	script.session = session;
tools/perf/builtin-timechart.c +1 -1
index df3b1c5ae7b9..48eea6cd2f5b 100644
@@ -1607,7 +1607,7 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
 	if (session == NULL)
 		return -ENOMEM;
 
-	symbol__init();
+	symbol__init(&session->header.env);
 
 	(void)perf_header__process_sections(&session->header,
 					    perf_data_file__fd(session->file),
tools/perf/builtin-top.c +1 -1
index 0ab3ea7f7525..4b0e15c2b2a8 100644
@@ -1234,7 +1234,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
 	symbol_conf.priv_size = sizeof(struct annotation);
 
 	symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
-	if (symbol__init() < 0)
+	if (symbol__init(NULL) < 0)
 		return -1;
 
 	sort__setup_elide(stdout);
tools/perf/builtin-trace.c +2 -2
index 8a83bd835327..d080b9cf0354 100644
@@ -1411,7 +1411,7 @@ static int trace__tool_process(struct perf_tool *tool,
 
 static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
 {
-	int err = symbol__init();
+	int err = symbol__init(NULL);
 
 	if (err)
 		return err;
@@ -2245,7 +2245,7 @@ static int trace__replay(struct trace *trace)
 	if (session == NULL)
 		return -ENOMEM;
 
-	if (symbol__init() < 0)
+	if (symbol__init(&session->header.env) < 0)
 		goto out;
 
 	trace->host = &session->machines.host;
tools/perf/tests/builtin-test.c +1 -1
index 6f8b01bc6033..c6796d22423a 100644
@@ -297,7 +297,7 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
 	symbol_conf.sort_by_name = true;
 	symbol_conf.try_vmlinux_path = true;
 
-	if (symbol__init() < 0)
+	if (symbol__init(NULL) < 0)
 		return -1;
 
 	if (skip != NULL)
tools/perf/util/probe-event.c +1 -1
index 443225cb62f7..784ea42ad8cb 100644
@@ -79,7 +79,7 @@ static int init_symbol_maps(bool user_only)
 	int ret;
 
 	symbol_conf.sort_by_name = true;
-	ret = symbol__init();
+	ret = symbol__init(NULL);
 	if (ret < 0) {
 		pr_debug("Failed to init symbol map.\n");
 		goto out;
tools/perf/util/symbol.c +17 -9
index 009a9d064f11..ac098a3c2a31 100644
@@ -15,6 +15,7 @@
 #include "machine.h"
 #include "symbol.h"
 #include "strlist.h"
+#include "header.h"
 
 #include <elf.h>
 #include <limits.h>
@@ -1749,10 +1750,11 @@ static void vmlinux_path__exit(void)
 	zfree(&vmlinux_path);
 }
 
-static int vmlinux_path__init(void)
+static int vmlinux_path__init(struct perf_session_env *env)
 {
 	struct utsname uts;
 	char bf[PATH_MAX];
+	char *kernel_version;
 
 	vmlinux_path = malloc(sizeof(char *) * 5);
 	if (vmlinux_path == NULL)
@@ -1767,25 +1769,31 @@ static int vmlinux_path__init(void)
 		goto out_fail;
 	++vmlinux_path__nr_entries;
 
-	/* only try running kernel version if no symfs was given */
+	/* only try kernel version if no symfs was given */
 	if (symbol_conf.symfs[0] != 0)
 		return 0;
 
-	if (uname(&uts) < 0)
-		goto out_fail;
+	if (env) {
+		kernel_version = env->os_release;
+	} else {
+		if (uname(&uts) < 0)
+			goto out_fail;
+
+		kernel_version = uts.release;
+	}
 
-	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
+	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version);
 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
 		goto out_fail;
 	++vmlinux_path__nr_entries;
-	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
+	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
 		goto out_fail;
 	++vmlinux_path__nr_entries;
 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
-		 uts.release);
+		 kernel_version);
 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
 		goto out_fail;
@@ -1831,7 +1839,7 @@ static bool symbol__read_kptr_restrict(void)
 	return value;
 }
 
-int symbol__init(void)
+int symbol__init(struct perf_session_env *env)
 {
 	const char *symfs;
 
@@ -1846,7 +1854,7 @@ int symbol__init(void)
 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
 					  sizeof(struct symbol));
 
-	if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
+	if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0)
 		return -1;
 
 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
tools/perf/util/symbol.h +2 -1
index 196b29104276..b95e3a36d654 100644
@@ -262,7 +262,8 @@ int modules__parse(const char *filename, void *arg,
 int filename__read_debuglink(const char *filename, char *debuglink,
 			     size_t size);
 
-int symbol__init(void);
+struct perf_session_env;
+int symbol__init(struct perf_session_env *env);
 void symbol__exit(void);
 void symbol__elf_init(void);
 struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
Signature · 1 line
1.9.3
author maintainer
#27 lore raw

PATCH 27/41 perf hists browser: Fix a small callchain display bug

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

The currently when perf TUI report shows callchain, the first level chains have bogus '+' sign even though only the last one has children.

Since they are on a single line of the chain, toggling intermediate entries has no effect. Fix it to show '+' sign at the last entry only. Note that non-first level callchain entries don't have this problem.

Before:
---------------------------------------------------------------------------

    Children      Self  Command  Shared Object      Symbols
  -   40.70%     0.00%  swapper  [kernel.kallsyms]  [k] cpuidle_wrap_enter

+ cpuidle_wrap_enter
+ cpuidle_enter_tk
+ cpuidle_idle_call
+ cpu_idle

After:
---------------------------------------------------------------------------

    Children      Self  Command  Shared Object      Symbols
  -   40.70%     0.00%  swapper  [kernel.kallsyms]  [k] cpuidle_wrap_enter

cpuidle_wrap_enter
cpuidle_enter_tk
cpuidle_idle_call
+ cpu_idle

---
 tools/perf/ui/browsers/hists.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/ui/browsers/hists.c +3 -1
index 045c1e16ac59..1818d1275d02 100644
@@ -228,8 +228,10 @@ static void callchain_node__init_have_children(struct callchain_node *node)
 {
 	struct callchain_list *chain;
 
-	list_for_each_entry(chain, &node->val, list)
+	if (!list_empty(&node->val)) {
+		chain = list_entry(node->val.prev, struct callchain_list, list);
 		chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
+	}
 
 	callchain_node__init_have_children_rb_tree(node);
 }
Signature · 1 line
1.9.3
author maintainer
#28 lore raw

PATCH 28/41 perf report: Set proper sort__mode for the branch option

In reply to Arnaldo Carvalho de Melo

From: "[email protected]" <[email protected]>

When you specify "--branch-stack"("-b" for short) or "--no-branch-stack", "branch_mode" variable is set to 1 or 0 respectively. However, the code is just checking if the variable is -1 or not, ignoring "branch_mode == 1" case. Thus "perf report -b" dose not show its result with the branch sorted mode. This patch fix the problem.

---
 tools/perf/builtin-report.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/builtin-report.c +1 -1
index b9e0fcac4d71..3da59a87ec7c 100644
@@ -730,7 +730,7 @@ repeat:
 	has_br_stack = perf_header__has_feat(&session->header,
 					     HEADER_BRANCH_STACK);
 
-	if (branch_mode == -1 && has_br_stack) {
+	if ((branch_mode == -1 && has_br_stack) || branch_mode == 1) {
 		sort__mode = SORT_MODE__BRANCH;
 		symbol_conf.cumulate_callchain = false;
 	}
Signature · 1 line
1.9.3
author maintainer
#29 lore raw

PATCH 29/41 perf top: Fix -z option behavior

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

The current -z option does almost nothing. It doesn't zero the existing samples so that we can see profiles of exited process after last refresh. It seems it only affects annotation.

This patch clears existing entries before processing if -z option is given. For this original decaying logic also moved before processing.

---
 tools/perf/builtin-top.c | 23 +++++++++++++++++------
 tools/perf/util/hist.c   | 22 ++++++++++++++++++++++
 tools/perf/util/hist.h   |  1 +
 3 files changed, 40 insertions(+), 6 deletions(-)
tools/perf/builtin-top.c +17 -6
index 4b0e15c2b2a8..87a6615a40fa 100644
@@ -276,11 +276,17 @@ static void perf_top__print_sym_table(struct perf_top *top)
 		return;
 	}
 
+	if (top->zero) {
+		hists__delete_entries(&top->sym_evsel->hists);
+	} else {
+		hists__decay_entries(&top->sym_evsel->hists,
+				     top->hide_user_symbols,
+				     top->hide_kernel_symbols);
+	}
+
 	hists__collapse_resort(&top->sym_evsel->hists, NULL);
 	hists__output_resort(&top->sym_evsel->hists);
-	hists__decay_entries(&top->sym_evsel->hists,
-			     top->hide_user_symbols,
-			     top->hide_kernel_symbols);
+
 	hists__output_recalc_col_len(&top->sym_evsel->hists,
 				     top->print_entries - printed);
 	putchar('\n');
@@ -542,11 +548,16 @@ static void perf_top__sort_new_samples(void *arg)
 	if (t->evlist->selected != NULL)
 		t->sym_evsel = t->evlist->selected;
 
+	if (t->zero) {
+		hists__delete_entries(&t->sym_evsel->hists);
+	} else {
+		hists__decay_entries(&t->sym_evsel->hists,
+				     t->hide_user_symbols,
+				     t->hide_kernel_symbols);
+	}
+
 	hists__collapse_resort(&t->sym_evsel->hists, NULL);
 	hists__output_resort(&t->sym_evsel->hists);
-	hists__decay_entries(&t->sym_evsel->hists,
-			     t->hide_user_symbols,
-			     t->hide_kernel_symbols);
 }
 
 static void *display_thread_tui(void *arg)
tools/perf/util/hist.c +22 -0
index 30df6187ee02..86569fa3651d 100644
@@ -277,6 +277,28 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
 	}
 }
 
+void hists__delete_entries(struct hists *hists)
+{
+	struct rb_node *next = rb_first(&hists->entries);
+	struct hist_entry *n;
+
+	while (next) {
+		n = rb_entry(next, struct hist_entry, rb_node);
+		next = rb_next(&n->rb_node);
+
+		rb_erase(&n->rb_node, &hists->entries);
+
+		if (sort__need_collapse)
+			rb_erase(&n->rb_node_in, &hists->entries_collapsed);
+
+		--hists->nr_entries;
+		if (!n->filtered)
+			--hists->nr_non_filtered_entries;
+
+		hist_entry__free(n);
+	}
+}
+
 /*
  * histogram, sorted on item, collects periods
  */
tools/perf/util/hist.h +1 -0
index 95405a8fbd95..8c9c70e18cbb 100644
@@ -152,6 +152,7 @@ void hists__output_resort(struct hists *hists);
 void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
 
 void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
+void hists__delete_entries(struct hists *hists);
 void hists__output_recalc_col_len(struct hists *hists, int max_rows);
 
 u64 hists__total_period(struct hists *hists);
Signature · 1 line
1.9.3
author maintainer
#30 lore raw

PATCH 30/41 perf top: Handle 'z' key for toggle zeroing samples in TUI

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

The perf top TUI lacks 'z' key support to toggle sample zeroing. Add it.

---
 tools/perf/ui/browsers/hists.c | 9 +++++++++
 1 file changed, 9 insertions(+)
tools/perf/ui/browsers/hists.c +9 -0
index 1818d1275d02..4892480e8298 100644
@@ -10,6 +10,7 @@
 #include "../../util/pstack.h"
 #include "../../util/sort.h"
 #include "../../util/util.h"
+#include "../../util/top.h"
 #include "../../arch/common.h"
 
 #include "../browser.h"
@@ -1532,6 +1533,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
 	"P             Print histograms to perf.hist.N\n"
 	"t             Zoom into current Thread\n"
 	"V             Verbose (DSO names in callchains, etc)\n"
+	"z             Toggle zeroing of samples\n"
 	"/             Filter symbol by name";
 
 	if (browser == NULL)
@@ -1632,6 +1634,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
 		case 'F':
 			symbol_conf.filter_relative ^= 1;
 			continue;
+		case 'z':
+			if (!is_report_browser(hbt)) {
+				struct perf_top *top = hbt->arg;
+
+				top->zero = !top->zero;
+			}
+			continue;
 		case K_F1:
 		case 'h':
 		case '?':
Signature · 1 line
1.9.3
author maintainer
#31 lore raw

PATCH 31/41 perf symbols: Don't demangle parameters and such by default

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

Some C++ symbols have very long name and they make column length longer. Most of them are about parameters including templates and we can ignore such info most of time IMHO.

This patch passes DMGL_NO_OPTS by default when calling bfd_demangle(). One can still see full symbols with -v/--verbose option.

before:
JS_CallFunctionValue(JSContext*, JSObject*, JS::Value, unsigned int, JS::Value*, JS::Value*)

after:
JS_CallFunctionValue

---
 tools/perf/util/symbol-elf.c | 7 +++++--
 tools/perf/util/symbol.h     | 1 +
 2 files changed, 6 insertions(+), 2 deletions(-)
tools/perf/util/symbol-elf.c +5 -2
index d75349979e65..ec5ec1c9d9b5 100644
@@ -939,8 +939,11 @@ new_symbol:
 		 * to it...
 		 */
 		if (symbol_conf.demangle) {
-			demangled = bfd_demangle(NULL, elf_name,
-						 DMGL_PARAMS | DMGL_ANSI);
+			int demangle_flags = DMGL_NO_OPTS;
+			if (verbose)
+				demangle_flags = DMGL_PARAMS | DMGL_ANSI;
+
+			demangled = bfd_demangle(NULL, elf_name, demangle_flags);
 			if (demangled != NULL)
 				elf_name = demangled;
 		}
tools/perf/util/symbol.h +1 -0
index b95e3a36d654..3f95ea0357e3 100644
@@ -60,6 +60,7 @@ extern Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
 #endif
 
 #ifndef DMGL_PARAMS
+#define DMGL_NO_OPTS     0              /* For readability... */
 #define DMGL_PARAMS      (1 << 0)       /* Include function args */
 #define DMGL_ANSI        (1 << 1)       /* Include const, volatile, etc */
 #endif
Signature · 1 line
1.9.3
author maintainer
#32 lore raw

PATCH 32/41 perf symbols: Fix missing label symbols

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

Label symbols are missing because elf_sec__is_a() fails to find the section because the section strings do not match the section headers because the sections headers are from the 'runtime' object and the sections strings are from the 'symbol source' object.

Fix by getting the section strings from the 'runtime' object so that they match the section headers.

---
 tools/perf/util/symbol-elf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/symbol-elf.c +1 -1
index ec5ec1c9d9b5..9fb5e9e9f161 100644
@@ -736,7 +736,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
 	if (symstrs == NULL)
 		goto out_elf_end;
 
-	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
+	sec_strndx = elf_getscn(runtime_ss->elf, runtime_ss->ehdr.e_shstrndx);
 	if (sec_strndx == NULL)
 		goto out_elf_end;
 
Signature · 1 line
1.9.3
author maintainer
#33 lore raw

PATCH 33/41 perf evlist: Add 'system_wide' option

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

Add an option to cause a selected event to be opened always without a pid when configured by perf_evsel__config().

This is needed when using the sched_switch tracepoint to follow object code execution.

sched_switch occurs before the task switch and so it cannot record it in a context limited to that task. Note that also means that sched_switch is useless when capturing data per-thread, as is the 'context-switches' software event for the same reason.

---
 tools/perf/util/evlist.c | 45 +++++++++++++++++++++++++++++++++++++--------
 tools/perf/util/evsel.c  | 31 ++++++++++++++++++++++++++-----
 tools/perf/util/evsel.h  |  1 +
 3 files changed, 64 insertions(+), 13 deletions(-)
tools/perf/util/evlist.c +37 -8
index 3b366c085021..c74d8ecc9c70 100644
@@ -265,17 +265,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist,
 	return 0;
 }
 
+static int perf_evlist__nr_threads(struct perf_evlist *evlist,
+				   struct perf_evsel *evsel)
+{
+	if (evsel->system_wide)
+		return 1;
+	else
+		return thread_map__nr(evlist->threads);
+}
+
 void perf_evlist__disable(struct perf_evlist *evlist)
 {
 	int cpu, thread;
 	struct perf_evsel *pos;
 	int nr_cpus = cpu_map__nr(evlist->cpus);
-	int nr_threads = thread_map__nr(evlist->threads);
+	int nr_threads;
 
 	for (cpu = 0; cpu < nr_cpus; cpu++) {
 		evlist__for_each(evlist, pos) {
 			if (!perf_evsel__is_group_leader(pos) || !pos->fd)
 				continue;
+			nr_threads = perf_evlist__nr_threads(evlist, pos);
 			for (thread = 0; thread < nr_threads; thread++)
 				ioctl(FD(pos, cpu, thread),
 				      PERF_EVENT_IOC_DISABLE, 0);
@@ -288,12 +298,13 @@ void perf_evlist__enable(struct perf_evlist *evlist)
 	int cpu, thread;
 	struct perf_evsel *pos;
 	int nr_cpus = cpu_map__nr(evlist->cpus);
-	int nr_threads = thread_map__nr(evlist->threads);
+	int nr_threads;
 
 	for (cpu = 0; cpu < nr_cpus; cpu++) {
 		evlist__for_each(evlist, pos) {
 			if (!perf_evsel__is_group_leader(pos) || !pos->fd)
 				continue;
+			nr_threads = perf_evlist__nr_threads(evlist, pos);
 			for (thread = 0; thread < nr_threads; thread++)
 				ioctl(FD(pos, cpu, thread),
 				      PERF_EVENT_IOC_ENABLE, 0);
@@ -305,12 +316,14 @@ int perf_evlist__disable_event(struct perf_evlist *evlist,
 			       struct perf_evsel *evsel)
 {
 	int cpu, thread, err;
+	int nr_cpus = cpu_map__nr(evlist->cpus);
+	int nr_threads = perf_evlist__nr_threads(evlist, evsel);
 
 	if (!evsel->fd)
 		return 0;
 
-	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-		for (thread = 0; thread < evlist->threads->nr; thread++) {
+	for (cpu = 0; cpu < nr_cpus; cpu++) {
+		for (thread = 0; thread < nr_threads; thread++) {
 			err = ioctl(FD(evsel, cpu, thread),
 				    PERF_EVENT_IOC_DISABLE, 0);
 			if (err)
@@ -324,12 +337,14 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,
 			      struct perf_evsel *evsel)
 {
 	int cpu, thread, err;
+	int nr_cpus = cpu_map__nr(evlist->cpus);
+	int nr_threads = perf_evlist__nr_threads(evlist, evsel);
 
 	if (!evsel->fd)
 		return -EINVAL;
 
-	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-		for (thread = 0; thread < evlist->threads->nr; thread++) {
+	for (cpu = 0; cpu < nr_cpus; cpu++) {
+		for (thread = 0; thread < nr_threads; thread++) {
 			err = ioctl(FD(evsel, cpu, thread),
 				    PERF_EVENT_IOC_ENABLE, 0);
 			if (err)
@@ -343,7 +358,16 @@ static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
 {
 	int nr_cpus = cpu_map__nr(evlist->cpus);
 	int nr_threads = thread_map__nr(evlist->threads);
-	int nfds = nr_cpus * nr_threads * evlist->nr_entries;
+	int nfds = 0;
+	struct perf_evsel *evsel;
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		if (evsel->system_wide)
+			nfds += nr_cpus;
+		else
+			nfds += nr_cpus * nr_threads;
+	}
+
 	evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
 	return evlist->pollfd != NULL ? 0 : -ENOMEM;
 }
@@ -636,7 +660,12 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
 	struct perf_evsel *evsel;
 
 	evlist__for_each(evlist, evsel) {
-		int fd = FD(evsel, cpu, thread);
+		int fd;
+
+		if (evsel->system_wide && thread)
+			continue;
+
+		fd = FD(evsel, cpu, thread);
 
 		if (*output == -1) {
 			*output = fd;
tools/perf/util/evsel.c +26 -5
index 0c8919decac8..66de9a708163 100644
@@ -695,6 +695,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
 	int cpu, thread;
+
+	if (evsel->system_wide)
+		nthreads = 1;
+
 	evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
 
 	if (evsel->fd) {
@@ -713,6 +717,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea
 {
 	int cpu, thread;
 
+	if (evsel->system_wide)
+		nthreads = 1;
+
 	for (cpu = 0; cpu < ncpus; cpu++) {
 		for (thread = 0; thread < nthreads; thread++) {
 			int fd = FD(evsel, cpu, thread),
@@ -743,6 +750,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
 
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
+	if (evsel->system_wide)
+		nthreads = 1;
+
 	evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
 	if (evsel->sample_id == NULL)
 		return -ENOMEM;
@@ -787,6 +797,9 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
 	int cpu, thread;
 
+	if (evsel->system_wide)
+		nthreads = 1;
+
 	for (cpu = 0; cpu < ncpus; cpu++)
 		for (thread = 0; thread < nthreads; ++thread) {
 			close(FD(evsel, cpu, thread));
@@ -875,6 +888,9 @@ int __perf_evsel__read(struct perf_evsel *evsel,
 	int cpu, thread;
 	struct perf_counts_values *aggr = &evsel->counts->aggr, count;
 
+	if (evsel->system_wide)
+		nthreads = 1;
+
 	aggr->val = aggr->ena = aggr->run = 0;
 
 	for (cpu = 0; cpu < ncpus; cpu++) {
@@ -997,13 +1013,18 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
 			      struct thread_map *threads)
 {
-	int cpu, thread;
+	int cpu, thread, nthreads;
 	unsigned long flags = PERF_FLAG_FD_CLOEXEC;
 	int pid = -1, err;
 	enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
 
+	if (evsel->system_wide)
+		nthreads = 1;
+	else
+		nthreads = threads->nr;
+
 	if (evsel->fd == NULL &&
-	    perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
+	    perf_evsel__alloc_fd(evsel, cpus->nr, nthreads) < 0)
 		return -ENOMEM;
 
 	if (evsel->cgrp) {
@@ -1027,10 +1048,10 @@ retry_sample_id:
 
 	for (cpu = 0; cpu < cpus->nr; cpu++) {
 
-		for (thread = 0; thread < threads->nr; thread++) {
+		for (thread = 0; thread < nthreads; thread++) {
 			int group_fd;
 
-			if (!evsel->cgrp)
+			if (!evsel->cgrp && !evsel->system_wide)
 				pid = threads->map[thread];
 
 			group_fd = get_group_fd(evsel, cpu, thread);
@@ -1103,7 +1124,7 @@ out_close:
 			close(FD(evsel, cpu, thread));
 			FD(evsel, cpu, thread) = -1;
 		}
-		thread = threads->nr;
+		thread = nthreads;
 	} while (--cpu >= 0);
 	return err;
 }
tools/perf/util/evsel.h +1 -0
index d7f93ce0ebc1..dbb2a0d20907 100644
@@ -85,6 +85,7 @@ struct perf_evsel {
 	bool 			needs_swap;
 	bool			no_aux_samples;
 	bool			immediate;
+	bool			system_wide;
 	/* parse modifier helper */
 	int			exclude_GH;
 	int			nr_members;
Signature · 1 line
1.9.3
author maintainer
#34 lore raw

PATCH 34/41 perf evlist: Add perf_evlist__set_tracking_event()

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

Add a function to change which event is used to track mmap, comm and task events.

This is needed with Instruction Tracing because the Instruction Tracing event must come first but cannot be used for tracking because it will be disabled under some circumstances.

---
 tools/perf/util/evlist.c | 17 +++++++++++++++++
 tools/perf/util/evlist.h |  3 +++
 tools/perf/util/evsel.c  |  3 ++-
 tools/perf/util/evsel.h  |  1 +
 tools/perf/util/record.c |  2 +-
 5 files changed, 24 insertions(+), 2 deletions(-)
tools/perf/util/evlist.c +17 -0
index c74d8ecc9c70..9d863db3f4b2 100644
@@ -122,6 +122,7 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
 {
 	list_add_tail(&entry->node, &evlist->entries);
 	entry->idx = evlist->nr_entries;
+	entry->tracking = !entry->idx;
 
 	if (!evlist->nr_entries++)
 		perf_evlist__set_id_pos(evlist);
@@ -1295,3 +1296,19 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
 
 	list_splice(&move, &evlist->entries);
 }
+
+void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
+				     struct perf_evsel *tracking_evsel)
+{
+	struct perf_evsel *evsel;
+
+	if (tracking_evsel->tracking)
+		return;
+
+	evlist__for_each(evlist, evsel) {
+		if (evsel != tracking_evsel)
+			evsel->tracking = false;
+	}
+
+	tracking_evsel->tracking = true;
+}
tools/perf/util/evlist.h +3 -0
index f5173cd63693..e0084f90c271 100644
@@ -262,4 +262,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
 #define evlist__for_each_safe(evlist, tmp, evsel) \
 	__evlist__for_each_safe(&(evlist)->entries, tmp, evsel)
 
+void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
+				     struct perf_evsel *tracking_evsel);
+
 #endif /* __PERF_EVLIST_H */
tools/perf/util/evsel.c +2 -1
index 66de9a708163..01ce14c3575e 100644
@@ -162,6 +162,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
 		      struct perf_event_attr *attr, int idx)
 {
 	evsel->idx	   = idx;
+	evsel->tracking	   = !idx;
 	evsel->attr	   = *attr;
 	evsel->leader	   = evsel;
 	evsel->unit	   = "";
@@ -561,7 +562,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 {
 	struct perf_evsel *leader = evsel->leader;
 	struct perf_event_attr *attr = &evsel->attr;
-	int track = !evsel->idx; /* only the first counter needs these */
+	int track = evsel->tracking;
 	bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread;
 
 	attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
tools/perf/util/evsel.h +1 -0
index dbb2a0d20907..7bc314be6a7b 100644
@@ -86,6 +86,7 @@ struct perf_evsel {
 	bool			no_aux_samples;
 	bool			immediate;
 	bool			system_wide;
+	bool			tracking;
 	/* parse modifier helper */
 	int			exclude_GH;
 	int			nr_members;
tools/perf/util/record.c +1 -1
index e778afda0fb9..cf69325b985f 100644
@@ -115,7 +115,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
 
 	evlist__for_each(evlist, evsel) {
 		perf_evsel__config(evsel, opts);
-		if (!evsel->idx && use_comm_exec)
+		if (evsel->tracking && use_comm_exec)
 			evsel->attr.comm_exec = 1;
 	}
 
Signature · 1 line
1.9.3
author maintainer
#35 lore raw

PATCH 35/41 perf session: Add perf_session__peek_event()

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

Add a function to peek at other events in the event stream.

---
 tools/perf/util/session.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/session.h |  5 +++++
 2 files changed, 60 insertions(+)
tools/perf/util/session.c +55 -0
index 7e27f1eb260c..1b383bd93af6 100644
@@ -897,6 +897,61 @@ static void event_swap(union perf_event *event, bool sample_id_all)
 		swap(event, sample_id_all);
 }
 
+int perf_session__peek_event(struct perf_session *session, off_t file_offset,
+			     void *buf, size_t buf_sz,
+			     union perf_event **event_ptr,
+			     struct perf_sample *sample)
+{
+	union perf_event *event;
+	size_t hdr_sz, rest;
+	int fd;
+
+	if (session->one_mmap && !session->header.needs_swap) {
+		event = file_offset - session->one_mmap_offset +
+			session->one_mmap_addr;
+		goto out_parse_sample;
+	}
+
+	if (perf_data_file__is_pipe(session->file))
+		return -1;
+
+	fd = perf_data_file__fd(session->file);
+	hdr_sz = sizeof(struct perf_event_header);
+
+	if (buf_sz < hdr_sz)
+		return -1;
+
+	if (lseek(fd, file_offset, SEEK_SET) == (off_t)-1 ||
+	    readn(fd, &buf, hdr_sz) != (ssize_t)hdr_sz)
+		return -1;
+
+	event = (union perf_event *)buf;
+
+	if (session->header.needs_swap)
+		perf_event_header__bswap(&event->header);
+
+	if (event->header.size < hdr_sz)
+		return -1;
+
+	rest = event->header.size - hdr_sz;
+
+	if (readn(fd, &buf, rest) != (ssize_t)rest)
+		return -1;
+
+	if (session->header.needs_swap)
+		event_swap(event, perf_evlist__sample_id_all(session->evlist));
+
+out_parse_sample:
+
+	if (sample && event->header.type < PERF_RECORD_USER_TYPE_START &&
+	    perf_evlist__parse_sample(session->evlist, event, sample))
+		return -1;
+
+	*event_ptr = event;
+
+	return 0;
+}
+
 static s64 perf_session__process_event(struct perf_session *session,
 				       union perf_event *event,
 				       struct perf_tool *tool,
tools/perf/util/session.h +5 -0
index 0630e658f8be..8dd41cad2d59 100644
@@ -45,6 +45,11 @@ void perf_session__delete(struct perf_session *session);
 
 void perf_event_header__bswap(struct perf_event_header *hdr);
 
+int perf_session__peek_event(struct perf_session *session, off_t file_offset,
+			     void *buf, size_t buf_sz,
+			     union perf_event **event_ptr,
+			     struct perf_sample *sample);
+
 int __perf_session__process_events(struct perf_session *session,
 				   u64 data_offset, u64 data_size, u64 size,
 				   struct perf_tool *tool);
Signature · 1 line
1.9.3
author maintainer
#36 lore raw

PATCH 36/41 perf script: Allow callchains if any event samples them

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

perf script was not displaying callchains if any selected event did not have PERF_SAMPLE_CALLCHAIN.

Change this to disable callchains only if all selected events do not have PERF_SAMPLE_CALLCHAIN.

---
 tools/perf/builtin-script.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)
tools/perf/builtin-script.c +13 -4
index 37d2b608d388..c1b7029884b1 100644
@@ -184,10 +184,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
 		if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP",
 					    PERF_OUTPUT_IP))
 			return -EINVAL;
-
-		if (!no_callchain &&
-		    !(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
-			symbol_conf.use_callchain = false;
 	}
 
 	if (PRINT_FIELD(ADDR) &&
@@ -290,6 +286,19 @@ static int perf_session__check_output_opt(struct perf_session *session)
 		set_print_ip_opts(&evsel->attr);
 	}
 
+	if (!no_callchain) {
+		bool use_callchain = false;
+
+		evlist__for_each(session->evlist, evsel) {
+			if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
+				use_callchain = true;
+				break;
+			}
+		}
+		if (!use_callchain)
+			symbol_conf.use_callchain = false;
+	}
+
 	/*
 	 * set default for tracepoints to print symbols only
 	 * if callchains are present
Signature · 1 line
1.9.3
author maintainer
#37 lore raw

PATCH 37/41 perf script python: Add helpers for calling Python objects

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

The Python script API repeatedly uses the same lines of code to get and call objects. Make that into helper functions instead.

A side-effect is that some reference counting bugs disappear because the new call_object() function always decrements the reference count of 'retval'.

---
 .../util/scripting-engines/trace-event-python.c    | 114 +++++++++------------
 1 file changed, 47 insertions(+), 67 deletions(-)
tools/perf/util/scripting-engines/trace-event-python.c +47 -67
index cbce2545da45..26e5f14239ed 100644
@@ -73,6 +73,35 @@ static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObj
 	Py_DECREF(val);
 }
 
+static PyObject *get_handler(const char *handler_name)
+{
+	PyObject *handler;
+
+	handler = PyDict_GetItemString(main_dict, handler_name);
+	if (handler && !PyCallable_Check(handler))
+		return NULL;
+	return handler;
+}
+
+static void call_object(PyObject *handler, PyObject *args, const char *die_msg)
+{
+	PyObject *retval;
+
+	retval = PyObject_CallObject(handler, args);
+	if (retval == NULL)
+		handler_call_die(die_msg);
+	Py_DECREF(retval);
+}
+
+static void try_call_object(const char *handler_name, PyObject *args)
+{
+	PyObject *handler;
+
+	handler = get_handler(handler_name);
+	if (handler)
+		call_object(handler, args, handler_name);
+}
+
 static void define_value(enum print_arg_type field_type,
 			 const char *ev_name,
 			 const char *field_name,
@@ -80,7 +109,7 @@ static void define_value(enum print_arg_type field_type,
 			 const char *field_str)
 {
 	const char *handler_name = "define_flag_value";
-	PyObject *handler, *t, *retval;
+	PyObject *t;
 	unsigned long long value;
 	unsigned n = 0;
 
@@ -98,13 +127,7 @@ static void define_value(enum print_arg_type field_type,
 	PyTuple_SetItem(t, n++, PyInt_FromLong(value));
 	PyTuple_SetItem(t, n++, PyString_FromString(field_str));
 
-	handler = PyDict_GetItemString(main_dict, handler_name);
-	if (handler && PyCallable_Check(handler)) {
-		retval = PyObject_CallObject(handler, t);
-		if (retval == NULL)
-			handler_call_die(handler_name);
-		Py_DECREF(retval);
-	}
+	try_call_object(handler_name, t);
 
 	Py_DECREF(t);
 }
@@ -127,7 +150,7 @@ static void define_field(enum print_arg_type field_type,
 			 const char *delim)
 {
 	const char *handler_name = "define_flag_field";
-	PyObject *handler, *t, *retval;
+	PyObject *t;
 	unsigned n = 0;
 
 	if (field_type == PRINT_SYMBOL)
@@ -145,13 +168,7 @@ static void define_field(enum print_arg_type field_type,
 	if (field_type == PRINT_FLAGS)
 		PyTuple_SetItem(t, n++, PyString_FromString(delim));
 
-	handler = PyDict_GetItemString(main_dict, handler_name);
-	if (handler && PyCallable_Check(handler)) {
-		retval = PyObject_CallObject(handler, t);
-		if (retval == NULL)
-			handler_call_die(handler_name);
-		Py_DECREF(retval);
-	}
+	try_call_object(handler_name, t);
 
 	Py_DECREF(t);
 }
@@ -362,7 +379,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
 				      struct thread *thread,
 				      struct addr_location *al)
 {
-	PyObject *handler, *retval, *context, *t, *obj, *callchain;
+	PyObject *handler, *context, *t, *obj, *callchain;
 	PyObject *dict = NULL;
 	static char handler_name[256];
 	struct format_field *field;
@@ -387,9 +404,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
 
 	sprintf(handler_name, "%s__%s", event->system, event->name);
 
-	handler = PyDict_GetItemString(main_dict, handler_name);
-	if (handler && !PyCallable_Check(handler))
-		handler = NULL;
+	handler = get_handler(handler_name);
 	if (!handler) {
 		dict = PyDict_New();
 		if (!dict)
@@ -450,19 +465,9 @@ static void python_process_tracepoint(struct perf_sample *sample,
 		Py_FatalError("error resizing Python tuple");
 
 	if (handler) {
-		retval = PyObject_CallObject(handler, t);
-		if (retval == NULL)
-			handler_call_die(handler_name);
-		Py_DECREF(retval);
+		call_object(handler, t, handler_name);
 	} else {
-		handler = PyDict_GetItemString(main_dict, "trace_unhandled");
-		if (handler && PyCallable_Check(handler)) {
-
-			retval = PyObject_CallObject(handler, t);
-			if (retval == NULL)
-				handler_call_die("trace_unhandled");
-			Py_DECREF(retval);
-		}
+		try_call_object("trace_unhandled", t);
 		Py_DECREF(dict);
 	}
 
@@ -474,7 +479,7 @@ static void python_process_general_event(struct perf_sample *sample,
 					 struct thread *thread,
 					 struct addr_location *al)
 {
-	PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample;
+	PyObject *handler, *t, *dict, *callchain, *dict_sample;
 	static char handler_name[64];
 	unsigned n = 0;
 
@@ -496,8 +501,8 @@ static void python_process_general_event(struct perf_sample *sample,
 
 	snprintf(handler_name, sizeof(handler_name), "%s", "process_event");
 
-	handler = PyDict_GetItemString(main_dict, handler_name);
-	if (!handler || !PyCallable_Check(handler))
+	handler = get_handler(handler_name);
+	if (!handler)
 		goto exit;
 
 	pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
@@ -539,10 +544,7 @@ static void python_process_general_event(struct perf_sample *sample,
 	if (_PyTuple_Resize(&t, n) == -1)
 		Py_FatalError("error resizing Python tuple");
 
-	retval = PyObject_CallObject(handler, t);
-	if (retval == NULL)
-		handler_call_die(handler_name);
-	Py_DECREF(retval);
+	call_object(handler, t, handler_name);
 exit:
 	Py_DECREF(dict);
 	Py_DECREF(t);
@@ -566,36 +568,24 @@ static void python_process_event(union perf_event *event __maybe_unused,
 
 static int run_start_sub(void)
 {
-	PyObject *handler, *retval;
-	int err = 0;
-
 	main_module = PyImport_AddModule("__main__");
 	if (main_module == NULL)
 		return -1;
 	Py_INCREF(main_module);
 
 	main_dict = PyModule_GetDict(main_module);
-	if (main_dict == NULL) {
-		err = -1;
+	if (main_dict == NULL)
 		goto error;
-	}
 	Py_INCREF(main_dict);
 
-	handler = PyDict_GetItemString(main_dict, "trace_begin");
-	if (handler == NULL || !PyCallable_Check(handler))
-		goto out;
+	try_call_object("trace_begin", NULL);
 
-	retval = PyObject_CallObject(handler, NULL);
-	if (retval == NULL)
-		handler_call_die("trace_begin");
+	return 0;
 
-	Py_DECREF(retval);
-	return err;
 error:
 	Py_XDECREF(main_dict);
 	Py_XDECREF(main_module);
-out:
-	return err;
+	return -1;
 }
 
 /*
@@ -654,23 +644,13 @@ error:
  */
 static int python_stop_script(void)
 {
-	PyObject *handler, *retval;
-	int err = 0;
+	try_call_object("trace_end", NULL);
 
-	handler = PyDict_GetItemString(main_dict, "trace_end");
-	if (handler == NULL || !PyCallable_Check(handler))
-		goto out;
-
-	retval = PyObject_CallObject(handler, NULL);
-	if (retval == NULL)
-		handler_call_die("trace_end");
-	Py_DECREF(retval);
-out:
 	Py_XDECREF(main_dict);
 	Py_XDECREF(main_module);
 	Py_Finalize();
 
-	return err;
+	return 0;
 }
 
 static int python_generate_script(struct pevent *pevent, const char *outfile)
Signature · 1 line
1.9.3
author maintainer
#38 lore raw

PATCH 38/41 perf tools: Identify which comms are from exec

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

For grouping together all the data from a single execution, which is needed for pairing calls and returns e.g. any outstanding calls when a process exec's will never return.

Cc David Ahern <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Stephane Eranian <[email protected]>
[ Remove testing if comm->exec is false before setting it to true ]
---
 tools/perf/util/comm.c    |  7 +++++--
 tools/perf/util/comm.h    |  6 ++++--
 tools/perf/util/machine.c |  4 +++-
 tools/perf/util/thread.c  | 24 +++++++++++++++++++-----
 tools/perf/util/thread.h  | 10 +++++++++-
 5 files changed, 40 insertions(+), 11 deletions(-)
tools/perf/util/comm.c +5 -2
index f9e777629e21..b2bb59df65e1 100644
@@ -74,7 +74,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
 	return new;
 }
 
-struct comm *comm__new(const char *str, u64 timestamp)
+struct comm *comm__new(const char *str, u64 timestamp, bool exec)
 {
 	struct comm *comm = zalloc(sizeof(*comm));
 
@@ -82,6 +82,7 @@ struct comm *comm__new(const char *str, u64 timestamp)
 		return NULL;
 
 	comm->start = timestamp;
+	comm->exec = exec;
 
 	comm->comm_str = comm_str__findnew(str, &comm_str_root);
 	if (!comm->comm_str) {
@@ -94,7 +95,7 @@ struct comm *comm__new(const char *str, u64 timestamp)
 	return comm;
 }
 
-int comm__override(struct comm *comm, const char *str, u64 timestamp)
+int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
 {
 	struct comm_str *new, *old = comm->comm_str;
 
@@ -106,6 +107,8 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp)
 	comm_str__put(old);
 	comm->comm_str = new;
 	comm->start = timestamp;
+	if (exec)
+		comm->exec = true;
 
 	return 0;
 }
tools/perf/util/comm.h +4 -2
index fac5bd51befc..51c10ab257f8 100644
@@ -11,11 +11,13 @@ struct comm {
 	struct comm_str *comm_str;
 	u64 start;
 	struct list_head list;
+	bool exec;
 };
 
 void comm__free(struct comm *comm);
-struct comm *comm__new(const char *str, u64 timestamp);
+struct comm *comm__new(const char *str, u64 timestamp, bool exec);
 const char *comm__str(const struct comm *comm);
-int comm__override(struct comm *comm, const char *str, u64 timestamp);
+int comm__override(struct comm *comm, const char *str, u64 timestamp,
+		   bool exec);
 
 #endif  /* __PERF_COMM_H */
tools/perf/util/machine.c +3 -1
index 16bba9fff2c8..ea3e09f6a9c6 100644
@@ -404,11 +404,13 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
 	struct thread *thread = machine__findnew_thread(machine,
 							event->comm.pid,
 							event->comm.tid);
+	bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC;
 
 	if (dump_trace)
 		perf_event__fprintf_comm(event, stdout);
 
-	if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) {
+	if (thread == NULL ||
+	    __thread__set_comm(thread, event->comm.comm, sample->time, exec)) {
 		dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
 		return -1;
 	}
tools/perf/util/thread.c +19 -5
index 12c7a253a63c..a9df7f2c6dc9 100644
@@ -42,7 +42,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
 			goto err_thread;
 
 		snprintf(comm_str, 32, ":%d", tid);
-		comm = comm__new(comm_str, 0);
+		comm = comm__new(comm_str, 0, false);
 		free(comm_str);
 		if (!comm)
 			goto err_thread;
@@ -81,19 +81,33 @@ struct comm *thread__comm(const struct thread *thread)
 	return list_first_entry(&thread->comm_list, struct comm, list);
 }
 
+struct comm *thread__exec_comm(const struct thread *thread)
+{
+	struct comm *comm, *last = NULL;
+
+	list_for_each_entry(comm, &thread->comm_list, list) {
+		if (comm->exec)
+			return comm;
+		last = comm;
+	}
+
+	return last;
+}
+
 /* CHECKME: time should always be 0 if event aren't ordered */
-int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
+int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
+		       bool exec)
 {
 	struct comm *new, *curr = thread__comm(thread);
 	int err;
 
 	/* Override latest entry if it had no specific time coverage */
-	if (!curr->start) {
-		err = comm__override(curr, str, timestamp);
+	if (!curr->start && !curr->exec) {
+		err = comm__override(curr, str, timestamp, exec);
 		if (err)
 			return err;
 	} else {
-		new = comm__new(str, timestamp);
+		new = comm__new(str, timestamp, exec);
 		if (!new)
 			return -ENOMEM;
 		list_add(&new->list, &thread->comm_list);
tools/perf/util/thread.h +9 -1
index 716b7723cce2..8c75fa774706 100644
@@ -38,9 +38,17 @@ static inline void thread__exited(struct thread *thread)
 	thread->dead = true;
 }
 
-int thread__set_comm(struct thread *thread, const char *comm, u64 timestamp);
+int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp,
+		       bool exec);
+static inline int thread__set_comm(struct thread *thread, const char *comm,
+				   u64 timestamp)
+{
+	return __thread__set_comm(thread, comm, timestamp, false);
+}
+
 int thread__comm_len(struct thread *thread);
 struct comm *thread__comm(const struct thread *thread);
+struct comm *thread__exec_comm(const struct thread *thread);
 const char *thread__comm_str(const struct thread *thread);
 void thread__insert_map(struct thread *thread, struct map *map);
 int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
Signature · 1 line
1.9.3
author maintainer
#39 lore raw

PATCH 39/41 perf machine: Add machine__thread_exec_comm()

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

Add machine__thread_exec_comm() to return the comm that matches the last exec, if the comm_exec flag is present, or the last comm otherwise.

---
 tools/perf/util/machine.c | 26 ++++++++++++++++++++++++++
 tools/perf/util/machine.h |  4 ++++
 tools/perf/util/session.c | 24 +++++++++++++++++++++++-
 3 files changed, 53 insertions(+), 1 deletion(-)
tools/perf/util/machine.c +26 -0
index ea3e09f6a9c6..b093b93607fb 100644
@@ -31,6 +31,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 
 	machine->symbol_filter = NULL;
 	machine->id_hdr_size = 0;
+	machine->comm_exec = false;
 
 	machine->root_dir = strdup(root_dir);
 	if (machine->root_dir == NULL)
@@ -179,6 +180,19 @@ void machines__set_symbol_filter(struct machines *machines,
 	}
 }
 
+void machines__set_comm_exec(struct machines *machines, bool comm_exec)
+{
+	struct rb_node *nd;
+
+	machines->host.comm_exec = comm_exec;
+
+	for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
+		struct machine *machine = rb_entry(nd, struct machine, rb_node);
+
+		machine->comm_exec = comm_exec;
+	}
+}
+
 struct machine *machines__find(struct machines *machines, pid_t pid)
 {
 	struct rb_node **p = &machines->guests.rb_node;
@@ -398,6 +412,15 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid,
 	return __machine__findnew_thread(machine, pid, tid, false);
 }
 
+struct comm *machine__thread_exec_comm(struct machine *machine,
+				       struct thread *thread)
+{
+	if (machine->comm_exec)
+		return thread__exec_comm(thread);
+	else
+		return thread__comm(thread);
+}
+
 int machine__process_comm_event(struct machine *machine, union perf_event *event,
 				struct perf_sample *sample)
 {
@@ -406,6 +429,9 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
 							event->comm.tid);
 	bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC;
 
+	if (exec)
+		machine->comm_exec = true;
+
 	if (dump_trace)
 		perf_event__fprintf_comm(event, stdout);
 
tools/perf/util/machine.h +4 -0
index b972824e6294..61216e028319 100644
@@ -26,6 +26,7 @@ struct machine {
 	struct rb_node	  rb_node;
 	pid_t		  pid;
 	u16		  id_hdr_size;
+	bool		  comm_exec;
 	char		  *root_dir;
 	struct rb_root	  threads;
 	struct list_head  dead_threads;
@@ -47,6 +48,8 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
 
 struct thread *machine__find_thread(struct machine *machine, pid_t pid,
 				    pid_t tid);
+struct comm *machine__thread_exec_comm(struct machine *machine,
+				       struct thread *thread);
 
 int machine__process_comm_event(struct machine *machine, union perf_event *event,
 				struct perf_sample *sample);
@@ -88,6 +91,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
 
 void machines__set_symbol_filter(struct machines *machines,
 				 symbol_filter_t symbol_filter);
+void machines__set_comm_exec(struct machines *machines, bool comm_exec);
 
 struct machine *machine__new_host(void);
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
tools/perf/util/session.c +23 -1
index 1b383bd93af6..6d2d50dea1d8 100644
@@ -67,6 +67,25 @@ static void perf_session__destroy_kernel_maps(struct perf_session *session)
 	machines__destroy_kernel_maps(&session->machines);
 }
 
+static bool perf_session__has_comm_exec(struct perf_session *session)
+{
+	struct perf_evsel *evsel;
+
+	evlist__for_each(session->evlist, evsel) {
+		if (evsel->attr.comm_exec)
+			return true;
+	}
+
+	return false;
+}
+
+static void perf_session__set_comm_exec(struct perf_session *session)
+{
+	bool comm_exec = perf_session__has_comm_exec(session);
+
+	machines__set_comm_exec(&session->machines, comm_exec);
+}
+
 struct perf_session *perf_session__new(struct perf_data_file *file,
 				       bool repipe, struct perf_tool *tool)
 {
@@ -90,6 +109,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
 				goto out_close;
 
 			perf_session__set_id_hdr_size(session);
+			perf_session__set_comm_exec(session);
 		}
 	}
 
@@ -866,8 +886,10 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 	switch (event->header.type) {
 	case PERF_RECORD_HEADER_ATTR:
 		err = tool->attr(tool, event, &session->evlist);
-		if (err == 0)
+		if (err == 0) {
 			perf_session__set_id_hdr_size(session);
+			perf_session__set_comm_exec(session);
+		}
 		return err;
 	case PERF_RECORD_HEADER_EVENT_TYPE:
 		/*
Signature · 1 line
1.9.3
author maintainer
#40 lore raw

PATCH 40/41 perf tools: Add flags and insn_len to struct sample

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

The flags will be used to export branch type and transaction status.

insn_len is preparation for pairing calls and returns because the return address equals the call address plus the instruction length (insn_len).

---
 tools/perf/util/event.h | 2 ++
 1 file changed, 2 insertions(+)
tools/perf/util/event.h +2 -0
index 94d6976180da..7eb7107731ec 100644
@@ -156,6 +156,8 @@ struct perf_sample {
 	u32 cpu;
 	u32 raw_size;
 	u64 data_src;
+	u32 flags;
+	u16 insn_len;
 	void *raw_data;
 	struct ip_callchain *callchain;
 	struct branch_stack *branch_stack;
Signature · 1 line
1.9.3
author maintainer
#41 lore raw

PATCH 41/41 perf evlist: Add perf_evlist__enable_event_idx()

In reply to Arnaldo Carvalho de Melo

From: Adrian Hunter <[email protected]>

Add a function to enable a specific event within a specific perf event buffer.

---
 tools/perf/util/evlist.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/evlist.h |  2 ++
 2 files changed, 49 insertions(+)
tools/perf/util/evlist.c +47 -0
index 9d863db3f4b2..5dcd28c79c6e 100644
@@ -355,6 +355,53 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,
 	return 0;
 }
 
+static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist,
+					 struct perf_evsel *evsel, int cpu)
+{
+	int thread, err;
+	int nr_threads = perf_evlist__nr_threads(evlist, evsel);
+
+	if (!evsel->fd)
+		return -EINVAL;
+
+	for (thread = 0; thread < nr_threads; thread++) {
+		err = ioctl(FD(evsel, cpu, thread),
+			    PERF_EVENT_IOC_ENABLE, 0);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+static int perf_evlist__enable_event_thread(struct perf_evlist *evlist,
+					    struct perf_evsel *evsel,
+					    int thread)
+{
+	int cpu, err;
+	int nr_cpus = cpu_map__nr(evlist->cpus);
+
+	if (!evsel->fd)
+		return -EINVAL;
+
+	for (cpu = 0; cpu < nr_cpus; cpu++) {
+		err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
+				  struct perf_evsel *evsel, int idx)
+{
+	bool per_cpu_mmaps = !cpu_map__empty(evlist->cpus);
+
+	if (per_cpu_mmaps)
+		return perf_evlist__enable_event_cpu(evlist, evsel, idx);
+	else
+		return perf_evlist__enable_event_thread(evlist, evsel, idx);
+}
+
 static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
 {
 	int nr_cpus = cpu_map__nr(evlist->cpus);
tools/perf/util/evlist.h +2 -0
index e0084f90c271..106de53a6a74 100644
@@ -122,6 +122,8 @@ int perf_evlist__disable_event(struct perf_evlist *evlist,
 			       struct perf_evsel *evsel);
 int perf_evlist__enable_event(struct perf_evlist *evlist,
 			      struct perf_evsel *evsel);
+int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
+				  struct perf_evsel *evsel, int idx);
 
 void perf_evlist__set_selected(struct perf_evlist *evlist,
 			       struct perf_evsel *evsel);
Signature · 1 line
1.9.3
#42 lore raw
In reply to Arnaldo Carvalho de Melo
Quoted 155 lines · Arnaldo Carvalho de Melo

Hi Ingo,

Please consider pulling, more to come! :-)

- Arnaldo

The following changes since commit ddcd0973fe02aad3d4bdc59dd0f1db90f51105a9:

perf/x86/uncore: Rename IvyTown to IvyBridge-EP (2014-08-13 07:51:18 +0200)

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 1c65056c547141a0cb52fb8e6056f63524d2bbf2:

perf evlist: Add perf_evlist__enable_event_idx() (2014-08-13 19:23:48 -0300)

----------------------------------------------------------------
perf/probe fixes and improvements:

User visible changes:

. Do not show +/- callchain expansion when there are no childs (top/report) (Namhyung Kim)

. Fix -z and add respective 'z' hotkey to zero samples before refresh
in 'perf top' (Namhyung Kim)

. Capability probing fixes, improving the detection of
kernel features for non-priviledged users (Adrian Hunter)

. Add beautifier for mremap flags param in 'trace' (Alex Snast)

. Fix --list and --del options to show events when just uprobes is
enabled (Masami Hiramatsu)

. perf script: Allow callchains if any event samples them

. Don't look for kernel idle symbols in all DSOs in 'perf top' (Arnaldo Carvalho de Melo)

. Add cpu_startup_entry to the list of kernel idle symbols (Arnaldo Carvalho de Melo)

. 'perf top' terminal output fixes (Jiri Olsa)

. Fix stdin handling for 'perf kvm stat live' (Jiri Olsa)

. Fix missing label symbols (Adrian Hunter)

. Don't demangle C++ parameters and such by default, only in
--verbose mode (Namhyung Kim)

. Set proper sort__mode for the branch option (Naohiro Aota)

. Check recorded kernel version when finding vmlinux (Namhyung Kim)

Developer Stuff:

. More prep work for intel PT (Adrian Hunter)

. Fix possible memory leaks (Namhyung Kim)

. Fix a memory leak in vmlinux_path__init() (Namhyung Kim)

----------------------------------------------------------------
Adrian Hunter (14):
perf tools: Fix CLOEXEC probe for perf_event_paranoid == 2 perf tools: Fix one of the probe events to exclude kernel perf tools: Fix probing the kernel API with cpu-wide events perf tools: Prefer to use a cpu-wide event for probing CLOEXEC perf symbols: Fix missing label symbols
perf evlist: Add 'system_wide' option
perf evlist: Add perf_evlist__set_tracking_event() perf session: Add perf_session__peek_event()
perf script: Allow callchains if any event samples them perf script python: Add helpers for calling Python objects perf tools: Identify which comms are from exec
perf machine: Add machine__thread_exec_comm()
perf tools: Add flags and insn_len to struct sample perf evlist: Add perf_evlist__enable_event_idx()

Alex Snast (1):
perf trace: Add beautifier for mremap flags param

Arnaldo Carvalho de Melo (2):
perf top: Don't look for kernel idle symbols in all DSOs perf tools: Add cpu_startup_entry to the list of kernel idle symbols

Jiri Olsa (4):
perf top: Join the display thread on exit
perf tools: Introduce set_term_quiet_input helper function perf top: Setup signals for terminal output
perf kvm: Fix stdin handling for 'kvm stat live' command

Masami Hiramatsu (2):
perf probe: Fix --list option to show events only with uprobe events perf probe: Fix --del option to delete events only with uprobe events

Namhyung Kim (17):
perf script: Fix possible memory leaks
perf symbols: Fix a memory leak in vmlinux_path__init() perf annotate: Move session handling out of __cmd_annotate() perf buildid-cache: Move session handling into cmd_buildid_cache() perf inject: Move session handling out of __cmd_inject() perf kmem: Move session handling out of __cmd_kmem() perf kvm: Move call to symbol__init() after creating session perf lock: Move call to symbol__init() after creating session perf sched: Move call to symbol__init() after creating session perf script: Move call to symbol__init() after creating session perf timechart: Move call to symbol__init() after creating session perf trace: Move call to symbol__init() after creating session perf tools: Check recorded kernel version when finding vmlinux perf hists browser: Fix a small callchain display bug perf top: Fix -z option behavior
perf top: Handle 'z' key for toggle zeroing samples in TUI perf symbols: Don't demangle parameters and such by default

[email protected] (1):
perf report: Set proper sort__mode for the branch option

 tools/perf/builtin-annotate.c                      |  75 +++++++-------
 tools/perf/builtin-buildid-cache.c                 |  37 ++++---
 tools/perf/builtin-diff.c                          |   2 +-
 tools/perf/builtin-inject.c                        |  31 +++---
 tools/perf/builtin-kmem.c                          |  49 +++++----
 tools/perf/builtin-kvm.c                           |  24 ++---
 tools/perf/builtin-lock.c                          |   3 +-
 tools/perf/builtin-mem.c                           |   2 +-
 tools/perf/builtin-record.c                        |   2 +-
 tools/perf/builtin-report.c                        |   4 +-
 tools/perf/builtin-sched.c                         |   3 +-
 tools/perf/builtin-script.c                        |  57 +++++++----
 tools/perf/builtin-timechart.c                     |   4 +-
 tools/perf/builtin-top.c                           |  59 ++++++++---
 tools/perf/builtin-trace.c                         |  34 +++++-
 tools/perf/tests/builtin-test.c                    |   2 +-
 tools/perf/ui/browsers/hists.c                     |  13 ++-
 tools/perf/util/cloexec.c                          |  23 ++++-
 tools/perf/util/comm.c                             |   7 +-
 tools/perf/util/comm.h                             |   6 +-
 tools/perf/util/event.h                            |   2 +
 tools/perf/util/evlist.c                           | 109 ++++++++++++++++++--
 tools/perf/util/evlist.h                           |   5 +
 tools/perf/util/evsel.c                            |  34 ++++--
 tools/perf/util/evsel.h                            |   2 +
 tools/perf/util/hist.c                             |  22 ++++
 tools/perf/util/hist.h                             |   1 +
 tools/perf/util/machine.c                          |  30 +++++-
 tools/perf/util/machine.h                          |   4 +
 tools/perf/util/probe-event.c                      |  98 ++++++++++++------
 tools/perf/util/record.c                           |  40 ++++++--
 .../util/scripting-engines/trace-event-python.c    | 114 +++++++++------------
 tools/perf/util/session.c                          |  79 +++++++++++++-
 tools/perf/util/session.h                          |   5 +
Quoted 8 lines
 tools/perf/util/symbol-elf.c                       |   9 +-
 tools/perf/util/symbol.c                           |  31 ++++--
 tools/perf/util/symbol.h                           |   4 +-
 tools/perf/util/thread.c                           |  24 ++++-
 tools/perf/util/thread.h                           |  10 +-
 tools/perf/util/util.c                             |  13 +++
 tools/perf/util/util.h                             |   2 +
 41 files changed, 770 insertions(+), 305 deletions(-)

Pulled, thanks a lot Arnaldo!

Ingo