Skip to content

Commit

Permalink
perf callchain: Free callchains when hist entries are deleted
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Namhyung Kim authored and Arnaldo Carvalho de Melo committed Jan 8, 2015
1 parent 5ca8271 commit d114960
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 0 deletions.
30 changes: 30 additions & 0 deletions tools/perf/util/callchain.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
2 changes: 2 additions & 0 deletions tools/perf/util/callchain.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
1 change: 1 addition & 0 deletions tools/perf/util/hist.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down

0 comments on commit d114960

Please sign in to comment.