Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752882AbbKIFq4 (ORCPT ); Mon, 9 Nov 2015 00:46:56 -0500 Received: from LGEAMRELO12.lge.com ([156.147.23.52]:52794 "EHLO lgeamrelo12.lge.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752440AbbKIFpx (ORCPT ); Mon, 9 Nov 2015 00:45:53 -0500 X-Original-SENDERIP: 156.147.1.151 X-Original-MAILFROM: namhyung@kernel.org X-Original-SENDERIP: 10.177.227.17 X-Original-MAILFROM: namhyung@kernel.org From: Namhyung Kim To: Arnaldo Carvalho de Melo Cc: Ingo Molnar , Peter Zijlstra , Jiri Olsa , LKML , Brendan Gregg , David Ahern , Frederic Weisbecker , Andi Kleen , Kan Liang Subject: [PATCH v5 7/9] perf hists browser: Support folded callchains Date: Mon, 9 Nov 2015 14:45:44 +0900 Message-Id: <1447047946-1691-9-git-send-email-namhyung@kernel.org> X-Mailer: git-send-email 2.6.2 In-Reply-To: <1447047946-1691-1-git-send-email-namhyung@kernel.org> References: <1447047946-1691-1-git-send-email-namhyung@kernel.org> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6092 Lines: 194 The folded callchain mode is to print all chains in a single line. Currently perf report --tui doesn't support folded callchains. Like flat callchains, only leaf nodes are added to the final rbtree so it should show entries in parent nodes. To do that, add flat_val list to struct callchain_node and show them along with the (normal) val list. For example, folded callchain looks like below: $ perf report -g folded --tui Samples: 234 of event 'cycles:pp', Event count (approx.): 32605268 Overhead Command Shared Object Symbol - 39.93% swapper [kernel.vmlinux] [k] intel_idle + 28.63% intel_idle; cpuidle_enter_state; cpuidle_enter; ... + 11.30% intel_idle; cpuidle_enter_state; cpuidle_enter; ... Cc: Brendan Gregg Signed-off-by: Namhyung Kim --- tools/perf/ui/browsers/hists.c | 126 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index f4216d92282d..3efe7c74f47d 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -207,6 +207,11 @@ static int callchain_node__count_flat_rows(struct callchain_node *node) return n; } +static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused) +{ + return 1; +} + static int callchain_node__count_rows(struct callchain_node *node) { struct callchain_list *chain; @@ -215,6 +220,8 @@ static int callchain_node__count_rows(struct callchain_node *node) if (callchain_param.mode == CHAIN_FLAT) return callchain_node__count_flat_rows(node); + else if (callchain_param.mode == CHAIN_FOLDED) + return callchain_node__count_folded_rows(node); list_for_each_entry(chain, &node->val, list) { ++n; @@ -311,7 +318,8 @@ static void callchain__init_have_children(struct rb_root *root) for (nd = rb_first(root); nd; nd = rb_next(nd)) { struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); callchain_node__init_have_children(node, has_sibling); - if (callchain_param.mode == CHAIN_FLAT) + if (callchain_param.mode == CHAIN_FLAT || + callchain_param.mode == CHAIN_FOLDED) callchain_node__make_parent_list(node); } } @@ -723,6 +731,117 @@ static int hist_browser__show_callchain_flat(struct hist_browser *browser, return row - first_row; } +static char *hist_browser__folded_callchain_str(struct hist_browser *browser, + struct callchain_list *chain, + char *value_str, char *old_str) +{ + char bf[1024]; + const char *str; + char *new; + + str = callchain_list__sym_name(chain, bf, sizeof(bf), + browser->show_dso); + if (old_str) { + if (asprintf(&new, "%s%s%s", old_str, + symbol_conf.field_sep ?: ";", str) < 0) + new = NULL; + } else { + if (value_str) { + if (asprintf(&new, "%s %s", value_str, str) < 0) + new = NULL; + } else { + if (asprintf(&new, "%s", str) < 0) + new = NULL; + } + } + return new; +} + +static int hist_browser__show_callchain_folded(struct hist_browser *browser, + struct rb_root *root, + unsigned short row, u64 total, + print_callchain_entry_fn print, + struct callchain_print_arg *arg, + check_output_full_fn is_output_full) +{ + struct rb_node *node; + int first_row = row, offset = LEVEL_OFFSET_STEP; + bool need_percent; + + node = rb_first(root); + need_percent = node && rb_next(node); + + while (node) { + struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); + struct rb_node *next = rb_next(node); + struct callchain_list *chain, *first_chain = NULL; + int first = true; + char *value_str = NULL, *value_str_alloc = NULL; + char *chain_str = NULL, *chain_str_alloc = NULL; + + if (arg->row_offset != 0) { + arg->row_offset--; + goto next; + } + + if (need_percent) { + char buf[64]; + + callchain_node__sprintf_value(child, buf, sizeof(buf), + total); + if (asprintf(&value_str, "%s", buf) < 0) { + value_str = (char *)"<...>"; + goto do_print; + } + value_str_alloc = value_str; + } + + list_for_each_entry(chain, &child->parent_val, list) { + chain_str = hist_browser__folded_callchain_str(browser, + chain, value_str, chain_str); + if (first) { + first = false; + first_chain = chain; + } + + if (chain_str == NULL) { + chain_str = (char *)"Not enough memory!"; + goto do_print; + } + + chain_str_alloc = chain_str; + } + + list_for_each_entry(chain, &child->val, list) { + chain_str = hist_browser__folded_callchain_str(browser, + chain, value_str, chain_str); + if (first) { + first = false; + first_chain = chain; + } + + if (chain_str == NULL) { + chain_str = (char *)"Not enough memory!"; + goto do_print; + } + + chain_str_alloc = chain_str; + } + +do_print: + print(browser, first_chain, chain_str, offset, row++, arg); + free(value_str_alloc); + free(chain_str_alloc); + +next: + if (is_output_full(browser, row)) + break; + node = next; + } + + return row - first_row; +} + static int hist_browser__show_callchain(struct hist_browser *browser, struct rb_root *root, int level, unsigned short row, u64 total, @@ -980,6 +1099,11 @@ static int hist_browser__show_entry(struct hist_browser *browser, &entry->sorted_chain, row, total, hist_browser__show_callchain_entry, &arg, hist_browser__check_output_full); + } else if (callchain_param.mode == CHAIN_FOLDED) { + printed += hist_browser__show_callchain_folded(browser, + &entry->sorted_chain, row, total, + hist_browser__show_callchain_entry, &arg, + hist_browser__check_output_full); } else { printed += hist_browser__show_callchain(browser, &entry->sorted_chain, 1, row, total, -- 2.6.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/