diff options
author | Namhyung Kim <namhyung@kernel.org> | 2014-12-30 00:38:13 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2015-01-08 09:56:35 -0500 |
commit | d114960c488b5a95705a04bba305f931cef0efd6 (patch) | |
tree | f77f5ed8815a9fd1ce543b837be35c70d8af9c8c /tools | |
parent | 5ca8271022da8583f0d618aeda5b2bae785e7882 (diff) |
perf callchain: Free callchains when hist entries are deleted
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.
Reported-by: Markus Trippelsdorf <markus@trippelsdorf.de>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Markus Trippelsdorf <markus@trippelsdorf.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20141230053813.GD6081@sejong
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/util/callchain.c | 30 | ||||
-rw-r--r-- | tools/perf/util/callchain.h | 2 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 1 |
3 files changed, 33 insertions, 0 deletions
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 64b377e591e4..14e7a123d43b 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -841,3 +841,33 @@ char *callchain_list__sym_name(struct callchain_list *cl, | |||
841 | 841 | ||
842 | return bf; | 842 | return bf; |
843 | } | 843 | } |
844 | |||
845 | static void free_callchain_node(struct callchain_node *node) | ||
846 | { | ||
847 | struct callchain_list *list, *tmp; | ||
848 | struct callchain_node *child; | ||
849 | struct rb_node *n; | ||
850 | |||
851 | list_for_each_entry_safe(list, tmp, &node->val, list) { | ||
852 | list_del(&list->list); | ||
853 | free(list); | ||
854 | } | ||
855 | |||
856 | n = rb_first(&node->rb_root_in); | ||
857 | while (n) { | ||
858 | child = container_of(n, struct callchain_node, rb_node_in); | ||
859 | n = rb_next(n); | ||
860 | rb_erase(&child->rb_node_in, &node->rb_root_in); | ||
861 | |||
862 | free_callchain_node(child); | ||
863 | free(child); | ||
864 | } | ||
865 | } | ||
866 | |||
867 | void free_callchain(struct callchain_root *root) | ||
868 | { | ||
869 | if (!symbol_conf.use_callchain) | ||
870 | return; | ||
871 | |||
872 | free_callchain_node(&root->node); | ||
873 | } | ||
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index dbc08cf5f970..c0ec1acc38e4 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -198,4 +198,6 @@ static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused, | |||
198 | char *callchain_list__sym_name(struct callchain_list *cl, | 198 | char *callchain_list__sym_name(struct callchain_list *cl, |
199 | char *bf, size_t bfsize, bool show_dso); | 199 | char *bf, size_t bfsize, bool show_dso); |
200 | 200 | ||
201 | void free_callchain(struct callchain_root *root); | ||
202 | |||
201 | #endif /* __PERF_CALLCHAIN_H */ | 203 | #endif /* __PERF_CALLCHAIN_H */ |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 0ced178ce306..182395546ddc 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -947,6 +947,7 @@ void hist_entry__free(struct hist_entry *he) | |||
947 | zfree(&he->mem_info); | 947 | zfree(&he->mem_info); |
948 | zfree(&he->stat_acc); | 948 | zfree(&he->stat_acc); |
949 | free_srcline(he->srcline); | 949 | free_srcline(he->srcline); |
950 | free_callchain(he->callchain); | ||
950 | free(he); | 951 | free(he); |
951 | } | 952 | } |
952 | 953 | ||