Skip to contentSkip to conversation

perf/urgent fixes

GIT PULL New Arnaldo Carvalho de Melo 2 participants 5 messages Jan 8, 2015 – Jan 9, 2015 perf events

lore
Share & tools
lore

Arnaldo Carvalho de Melo

author maintainer
#0 lore raw

Hi Ingo,

Please consider pulling,

- Arnaldo

The following changes since commit ed9eb845d7916b2bc863e5b93c82e18be8faf032:

Merge tag 'perf-urgent-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent (2015-01-08 08:59:22 +0100)

are available in the git repository at:

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

for you to fetch changes up to c09e31cc128cf1aec3a6cd47203508fbf0082873:

perf hists browser: Fix segfault when showing callchain (2015-01-08 11:59:16 -0300)

----------------------------------------------------------------
perf/urgent fixes:

. Free callchains when hist entries are deleted, plugging a massive leak in
'top -g', where hist_entries (and its callchains) are decayed over time. (Namhyung Kim)

. Fix segfault when showing callchain in the hists browser (report & top) (Namhyung Kim)

. Fix children sort key behavior, and also the 'perf test 32' test that
was failing due to reliance on undefined behaviour (Namhyung Kim)

----------------------------------------------------------------
Namhyung Kim (3):
perf hists: Fix children sort key behavior
perf callchain: Free callchains when hist entries are deleted perf hists browser: Fix segfault when showing callchain

 tools/perf/tests/hists_cumulate.c | 64 +++++++++++++++++++--------------------
 tools/perf/ui/browsers/hists.c    |  2 +-
 tools/perf/ui/hist.c              |  3 ++
 tools/perf/util/callchain.c       | 30 ++++++++++++++++++
 tools/perf/util/callchain.h       |  2 ++
 tools/perf/util/hist.c            |  1 +
 6 files changed, 69 insertions(+), 33 deletions(-)
author maintainer
#1 lore raw

PATCH 1/3 perf hists: Fix children sort key behavior

From: Namhyung Kim <[email protected]>

When perf report --children resorts output fields, it tries to put caller above the callee. But this was only meaningful for a same thread and doing this requires callchain enabled. So fix its check before comparing the callchain depth.

This also changes the hist accumulation tests: In test 3, xmalloc in bash thread should be above than other perf threads due to alphabetical order of comm string. Also it's under page_fault in bash thread since alphabetical order of dso name. The sys_perf_event_open in perf thread is put on the last line since it's self overhead is 0.

In test 4, the sys_perf_event_open is put above other perf entries that have same children overhead since its callchain depth is smaller.

---
 tools/perf/tests/hists_cumulate.c | 64 +++++++++++++++++++--------------------
 tools/perf/ui/hist.c              |  3 ++
 2 files changed, 35 insertions(+), 32 deletions(-)
tools/perf/tests/hists_cumulate.c +32 -32
index 4b8226e19a91..8d110dec393e 100644
@@ -454,12 +454,12 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
 	 *   30.00%    10.00%     perf  perf           [.] cmd_record
 	 *   20.00%     0.00%     bash  libc           [.] malloc
 	 *   10.00%    10.00%     bash  [kernel]       [k] page_fault
-	 *   10.00%    10.00%     perf  [kernel]       [k] schedule
-	 *   10.00%     0.00%     perf  [kernel]       [k] sys_perf_event_open
+	 *   10.00%    10.00%     bash  bash           [.] xmalloc
 	 *   10.00%    10.00%     perf  [kernel]       [k] page_fault
-	 *   10.00%    10.00%     perf  libc           [.] free
 	 *   10.00%    10.00%     perf  libc           [.] malloc
-	 *   10.00%    10.00%     bash  bash           [.] xmalloc
+	 *   10.00%    10.00%     perf  [kernel]       [k] schedule
+	 *   10.00%    10.00%     perf  libc           [.] free
+	 *   10.00%     0.00%     perf  [kernel]       [k] sys_perf_event_open
 	 */
 	struct result expected[] = {
 		{ 7000, 2000, "perf", "perf",     "main" },
@@ -468,12 +468,12 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
 		{ 3000, 1000, "perf", "perf",     "cmd_record" },
 		{ 2000,    0, "bash", "libc",     "malloc" },
 		{ 1000, 1000, "bash", "[kernel]", "page_fault" },
-		{ 1000, 1000, "perf", "[kernel]", "schedule" },
-		{ 1000,    0, "perf", "[kernel]", "sys_perf_event_open" },
+		{ 1000, 1000, "bash", "bash",     "xmalloc" },
 		{ 1000, 1000, "perf", "[kernel]", "page_fault" },
+		{ 1000, 1000, "perf", "[kernel]", "schedule" },
 		{ 1000, 1000, "perf", "libc",     "free" },
 		{ 1000, 1000, "perf", "libc",     "malloc" },
-		{ 1000, 1000, "bash", "bash",     "xmalloc" },
+		{ 1000,    0, "perf", "[kernel]", "sys_perf_event_open" },
 	};
 
 	symbol_conf.use_callchain = false;
@@ -537,10 +537,13 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
 	 *                  malloc
 	 *                  main
 	 *
-	 *   10.00%    10.00%     perf  [kernel]       [k] schedule
+	 *   10.00%    10.00%     bash  bash           [.] xmalloc
 	 *              |
-	 *              --- schedule
-	 *                  run_command
+	 *              --- xmalloc
+	 *                  malloc
+	 *                  xmalloc     <--- NOTE: there's a cycle
+	 *                  malloc
+	 *                  xmalloc
 	 *                  main
 	 *
 	 *   10.00%     0.00%     perf  [kernel]       [k] sys_perf_event_open
@@ -556,6 +559,12 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
 	 *                  run_command
 	 *                  main
 	 *
+	 *   10.00%    10.00%     perf  [kernel]       [k] schedule
+	 *              |
+	 *              --- schedule
+	 *                  run_command
+	 *                  main
+	 *
 	 *   10.00%    10.00%     perf  libc           [.] free
 	 *              |
 	 *              --- free
@@ -570,15 +579,6 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
 	 *                  run_command
 	 *                  main
 	 *
-	 *   10.00%    10.00%     bash  bash           [.] xmalloc
-	 *              |
-	 *              --- xmalloc
-	 *                  malloc
-	 *                  xmalloc     <--- NOTE: there's a cycle
-	 *                  malloc
-	 *                  xmalloc
-	 *                  main
-	 *
 	 */
 	struct result expected[] = {
 		{ 7000, 2000, "perf", "perf",     "main" },
@@ -587,12 +587,12 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
 		{ 3000, 1000, "perf", "perf",     "cmd_record" },
 		{ 2000,    0, "bash", "libc",     "malloc" },
 		{ 1000, 1000, "bash", "[kernel]", "page_fault" },
-		{ 1000, 1000, "perf", "[kernel]", "schedule" },
+		{ 1000, 1000, "bash", "bash",     "xmalloc" },
 		{ 1000,    0, "perf", "[kernel]", "sys_perf_event_open" },
 		{ 1000, 1000, "perf", "[kernel]", "page_fault" },
+		{ 1000, 1000, "perf", "[kernel]", "schedule" },
 		{ 1000, 1000, "perf", "libc",     "free" },
 		{ 1000, 1000, "perf", "libc",     "malloc" },
-		{ 1000, 1000, "bash", "bash",     "xmalloc" },
 	};
 	struct callchain_result expected_callchain[] = {
 		{
@@ -622,9 +622,12 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
 				{ "bash",     "main" }, },
 		},
 		{
-			3, {	{ "[kernel]", "schedule" },
-				{ "perf",     "run_command" },
-				{ "perf",     "main" }, },
+			6, {	{ "bash",     "xmalloc" },
+				{ "libc",     "malloc" },
+				{ "bash",     "xmalloc" },
+				{ "libc",     "malloc" },
+				{ "bash",     "xmalloc" },
+				{ "bash",     "main" }, },
 		},
 		{
 			3, {	{ "[kernel]", "sys_perf_event_open" },
@@ -638,6 +641,11 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
 				{ "perf",     "main" }, },
 		},
 		{
+			3, {	{ "[kernel]", "schedule" },
+				{ "perf",     "run_command" },
+				{ "perf",     "main" }, },
+		},
+		{
 			4, {	{ "libc",     "free" },
 				{ "perf",     "cmd_record" },
 				{ "perf",     "run_command" },
@@ -649,14 +657,6 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
 				{ "perf",     "run_command" },
 				{ "perf",     "main" }, },
 		},
-		{
-			6, {	{ "bash",     "xmalloc" },
-				{ "libc",     "malloc" },
-				{ "bash",     "xmalloc" },
-				{ "libc",     "malloc" },
-				{ "bash",     "xmalloc" },
-				{ "bash",     "main" }, },
-		},
 	};
 
 	symbol_conf.use_callchain = true;
tools/perf/ui/hist.c +3 -0
index dc0d095f318c..482adae3cc44 100644
@@ -204,6 +204,9 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,
 		if (ret)
 			return ret;
 
+		if (a->thread != b->thread || !symbol_conf.use_callchain)
+			return 0;
+
 		ret = b->callchain->max_depth - a->callchain->max_depth;
 	}
 	return ret;
Signature · 1 line
1.9.3
author maintainer
#2 lore raw

PATCH 2/3 perf callchain: Free callchains when hist entries are deleted

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

Markus reported that "perf top -g" can leak ~300MB per second on his machine. This is partly because it missed to free callchains when hist entries are deleted. Fix it.

---
 tools/perf/util/callchain.c | 30 ++++++++++++++++++++++++++++++
 tools/perf/util/callchain.h |  2 ++
 tools/perf/util/hist.c      |  1 +
 3 files changed, 33 insertions(+)
tools/perf/util/callchain.c +30 -0
index 64b377e591e4..14e7a123d43b 100644
@@ -841,3 +841,33 @@ char *callchain_list__sym_name(struct callchain_list *cl,
 
 	return bf;
 }
+
+static void free_callchain_node(struct callchain_node *node)
+{
+	struct callchain_list *list, *tmp;
+	struct callchain_node *child;
+	struct rb_node *n;
+
+	list_for_each_entry_safe(list, tmp, &node->val, list) {
+		list_del(&list->list);
+		free(list);
+	}
+
+	n = rb_first(&node->rb_root_in);
+	while (n) {
+		child = container_of(n, struct callchain_node, rb_node_in);
+		n = rb_next(n);
+		rb_erase(&child->rb_node_in, &node->rb_root_in);
+
+		free_callchain_node(child);
+		free(child);
+	}
+}
+
+void free_callchain(struct callchain_root *root)
+{
+	if (!symbol_conf.use_callchain)
+		return;
+
+	free_callchain_node(&root->node);
+}
tools/perf/util/callchain.h +2 -0
index dbc08cf5f970..c0ec1acc38e4 100644
@@ -198,4 +198,6 @@ static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused,
 char *callchain_list__sym_name(struct callchain_list *cl,
 			       char *bf, size_t bfsize, bool show_dso);
 
+void free_callchain(struct callchain_root *root);
+
 #endif	/* __PERF_CALLCHAIN_H */
tools/perf/util/hist.c +1 -0
index 0ced178ce306..182395546ddc 100644
@@ -947,6 +947,7 @@ void hist_entry__free(struct hist_entry *he)
 	zfree(&he->mem_info);
 	zfree(&he->stat_acc);
 	free_srcline(he->srcline);
+	free_callchain(he->callchain);
 	free(he);
 }
 
Signature · 1 line
1.9.3
author maintainer
#3 lore raw

PATCH 3/3 perf hists browser: Fix segfault when showing callchain

In reply to Arnaldo Carvalho de Melo

From: Namhyung Kim <[email protected]>

When perf report on TUI shows callchain it checks first node has siblings to determine whether it needs to print percentage value.

But it missed a case that first node is NULL. So sometimes it segfaults like below:

  $ perf top -g
  perf: Segmentation fault
  -------- backtrace --------
  perf[0x4fcefb]
  /usr/lib/libc.so.6(+0x33b20)[0x7f2a35839b20]
  perf(rb_next+0x8)[0x47d3d8]
  perf[0x4f6058]
  perf[0x4f833b]
  perf[0x4f8610]
  perf[0x4f209e]
  perf(ui_browser__run+0x3a)[0x4f2e6a]
  perf[0x4f94ee]
  perf(perf_evlist__tui_browse_hists+0x94)[0x4fbbf4]
  perf[0x444d10]
  /usr/lib/libpthread.so.0(+0x7314)[0x7f2a37070314]
  /usr/lib/libc.so.6(clone+0x6d)[0x7f2a358ee5bd]
  $ addr2line -e `which perf` 0x4f6058
  /home/namhyung/project/linux/tools/perf/ui/browsers/hists.c:553

I don't know why the backtrace didn't print some symbols..

Fixes 4087d11cd945 ("perf hists browser: Print overhead percent value for first-level callchain")
Cc Adrian Hunter <[email protected]>
Cc Andi Kleen <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Stephane Eranian <[email protected]>
---
 tools/perf/ui/browsers/hists.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/ui/browsers/hists.c +1 -1
index e6bb04b5b09b..788506eef567 100644
@@ -550,7 +550,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
 	bool need_percent;
 
 	node = rb_first(root);
-	need_percent = !!rb_next(node);
+	need_percent = node && rb_next(node);
 
 	while (node) {
 		struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
Signature · 1 line
1.9.3
#4 lore raw
In reply to Arnaldo Carvalho de Melo
Quoted 38 lines · Arnaldo Carvalho de Melo

Hi Ingo,

Please consider pulling,

- Arnaldo

The following changes since commit ed9eb845d7916b2bc863e5b93c82e18be8faf032:

Merge tag 'perf-urgent-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent (2015-01-08 08:59:22 +0100)

are available in the git repository at:

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

for you to fetch changes up to c09e31cc128cf1aec3a6cd47203508fbf0082873:

perf hists browser: Fix segfault when showing callchain (2015-01-08 11:59:16 -0300)

----------------------------------------------------------------
perf/urgent fixes:

. Free callchains when hist entries are deleted, plugging a massive leak in
'top -g', where hist_entries (and its callchains) are decayed over time. (Namhyung Kim)

. Fix segfault when showing callchain in the hists browser (report & top) (Namhyung Kim)

. Fix children sort key behavior, and also the 'perf test 32' test that
was failing due to reliance on undefined behaviour (Namhyung Kim)

----------------------------------------------------------------
Namhyung Kim (3):
perf hists: Fix children sort key behavior
perf callchain: Free callchains when hist entries are deleted perf hists browser: Fix segfault when showing callchain

Quoted 7 lines
 tools/perf/tests/hists_cumulate.c | 64 +++++++++++++++++++--------------------
 tools/perf/ui/browsers/hists.c    |  2 +-
 tools/perf/ui/hist.c              |  3 ++
 tools/perf/util/callchain.c       | 30 ++++++++++++++++++
 tools/perf/util/callchain.h       |  2 ++
 tools/perf/util/hist.c            |  1 +
 6 files changed, 69 insertions(+), 33 deletions(-)

Pulled, thanks a lot Arnaldo!

Ingo