return 1;
}
+static bool check_percent_display(struct rb_node *node, u64 parent_total)
+{
+ struct callchain_node *child;
+
+ if (node == NULL)
+ return false;
+
+ if (rb_next(node))
+ return true;
+
+ child = rb_entry(node, struct callchain_node, rb_node);
+ return callchain_cumul_hits(child) != parent_total;
+}
+
static int hist_browser__show_callchain_flat(struct hist_browser *browser,
struct rb_root *root,
unsigned short row, u64 total,
+ u64 parent_total,
print_callchain_entry_fn print,
struct callchain_print_arg *arg,
check_output_full_fn is_output_full)
bool need_percent;
node = rb_first(root);
- need_percent = node && rb_next(node);
+ need_percent = check_percent_display(node, parent_total);
while (node) {
struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
static int hist_browser__show_callchain_folded(struct hist_browser *browser,
struct rb_root *root,
unsigned short row, u64 total,
+ u64 parent_total,
print_callchain_entry_fn print,
struct callchain_print_arg *arg,
check_output_full_fn is_output_full)
bool need_percent;
node = rb_first(root);
- need_percent = node && rb_next(node);
+ need_percent = check_percent_display(node, parent_total);
while (node) {
struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
return row - first_row;
}
-static int hist_browser__show_callchain(struct hist_browser *browser,
+static int hist_browser__show_callchain_graph(struct hist_browser *browser,
struct rb_root *root, int level,
unsigned short row, u64 total,
+ u64 parent_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 * LEVEL_OFFSET_STEP;
- u64 new_total;
bool need_percent;
+ u64 percent_total = total;
+
+ if (callchain_param.mode == CHAIN_GRAPH_REL)
+ percent_total = parent_total;
node = rb_first(root);
- need_percent = node && rb_next(node);
+ need_percent = check_percent_display(node, parent_total);
while (node) {
struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
folded_sign = callchain_list__folded(chain);
row += hist_browser__show_callchain_list(browser, child,
- chain, row, total,
+ chain, row, percent_total,
was_first && need_percent,
offset + extra_offset,
print, arg);
if (folded_sign == '-') {
const int new_level = level + (extra_offset ? 2 : 1);
- if (callchain_param.mode == CHAIN_GRAPH_REL)
- new_total = child->children_hit;
- else
- new_total = total;
-
- row += hist_browser__show_callchain(browser, &child->rb_root,
- new_level, row, new_total,
+ row += hist_browser__show_callchain_graph(browser, &child->rb_root,
+ new_level, row, total,
+ child->children_hit,
print, arg, is_output_full);
}
if (is_output_full(browser, row))
return row - first_row;
}
+static int hist_browser__show_callchain(struct hist_browser *browser,
+ struct hist_entry *entry, int level,
+ unsigned short row,
+ print_callchain_entry_fn print,
+ struct callchain_print_arg *arg,
+ check_output_full_fn is_output_full)
+{
+ u64 total = hists__total_period(entry->hists);
+ u64 parent_total;
+ int printed;
+
+ if (symbol_conf.cumulate_callchain)
+ parent_total = entry->stat_acc->period;
+ else
+ parent_total = entry->stat.period;
+
+ if (callchain_param.mode == CHAIN_FLAT) {
+ printed = hist_browser__show_callchain_flat(browser,
+ &entry->sorted_chain, row,
+ total, parent_total, print, arg,
+ is_output_full);
+ } else if (callchain_param.mode == CHAIN_FOLDED) {
+ printed = hist_browser__show_callchain_folded(browser,
+ &entry->sorted_chain, row,
+ total, parent_total, print, arg,
+ is_output_full);
+ } else {
+ printed = hist_browser__show_callchain_graph(browser,
+ &entry->sorted_chain, level, row,
+ total, parent_total, print, arg,
+ is_output_full);
+ }
+
+ if (arg->is_current_entry)
+ browser->he_selection = entry;
+
+ return printed;
+}
+
struct hpp_arg {
struct ui_browser *b;
char folded_sign;
--row_offset;
if (folded_sign == '-' && row != browser->b.rows) {
- u64 total = hists__total_period(entry->hists);
struct callchain_print_arg arg = {
.row_offset = row_offset,
.is_current_entry = current_entry,
};
- if (callchain_param.mode == CHAIN_GRAPH_REL) {
- if (symbol_conf.cumulate_callchain)
- total = entry->stat_acc->period;
- else
- total = entry->stat.period;
- }
-
- if (callchain_param.mode == CHAIN_FLAT) {
- printed += hist_browser__show_callchain_flat(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,
+ printed += hist_browser__show_callchain(browser, entry, 1, row,
hist_browser__show_callchain_entry, &arg,
hist_browser__check_output_full);
- }
-
- if (arg.is_current_entry)
- browser->he_selection = entry;
}
return printed;
static int hist_browser__fprintf_callchain(struct hist_browser *browser,
struct hist_entry *he, FILE *fp)
{
- u64 total = hists__total_period(he->hists);
struct callchain_print_arg arg = {
.fp = fp,
};
- if (symbol_conf.cumulate_callchain)
- total = he->stat_acc->period;
-
- hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
+ hist_browser__show_callchain(browser, he, 1, 0,
hist_browser__fprintf_callchain_entry, &arg,
hist_browser__check_dump_full);
return arg.printed;
return ret;
}
+/*
+ * If have one single callchain root, don't bother printing
+ * its percentage (100 % in fractal mode and the same percentage
+ * than the hist in graph mode). This also avoid one level of column.
+ *
+ * However when percent-limit applied, it's possible that single callchain
+ * node have different (non-100% in fractal mode) percentage.
+ */
+static bool need_percent_display(struct rb_node *node, u64 parent_samples)
+{
+ struct callchain_node *cnode;
+
+ if (rb_next(node))
+ return true;
+
+ cnode = rb_entry(node, struct callchain_node, rb_node);
+ return callchain_cumul_hits(cnode) != parent_samples;
+}
+
static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
- u64 total_samples, int left_margin)
+ u64 total_samples, u64 parent_samples,
+ int left_margin)
{
struct callchain_node *cnode;
struct callchain_list *chain;
int ret = 0;
char bf[1024];
- /*
- * If have one single callchain root, don't bother printing
- * its percentage (100 % in fractal mode and the same percentage
- * than the hist in graph mode). This also avoid one level of column.
- */
node = rb_first(root);
- if (node && !rb_next(node)) {
+ if (node && !need_percent_display(node, parent_samples)) {
cnode = rb_entry(node, struct callchain_node, rb_node);
list_for_each_entry(chain, &cnode->val, list) {
/*
root = &cnode->rb_root;
}
+ if (callchain_param.mode == CHAIN_GRAPH_REL)
+ total_samples = parent_samples;
+
ret += __callchain__fprintf_graph(fp, root, total_samples,
1, 1, left_margin);
- ret += fprintf(fp, "\n");
+ if (ret) {
+ /* do not add a blank line if it printed nothing */
+ ret += fprintf(fp, "\n");
+ }
return ret;
}
u64 total_samples, int left_margin,
FILE *fp)
{
+ u64 parent_samples = he->stat.period;
+
+ if (symbol_conf.cumulate_callchain)
+ parent_samples = he->stat_acc->period;
+
switch (callchain_param.mode) {
case CHAIN_GRAPH_REL:
- return callchain__fprintf_graph(fp, &he->sorted_chain,
- symbol_conf.cumulate_callchain ?
- he->stat_acc->period : he->stat.period,
- left_margin);
+ return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
+ parent_samples, left_margin);
break;
case CHAIN_GRAPH_ABS:
return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
- left_margin);
+ parent_samples, left_margin);
break;
case CHAIN_FLAT:
return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
return 0;
}
-static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
- struct hists *hists,
- FILE *fp)
-{
- int left_margin = 0;
- u64 total_period = hists->stats.total_period;
-
- if (field_order == NULL && (sort_order == NULL ||
- !prefixcmp(sort_order, "comm"))) {
- struct perf_hpp_fmt *fmt;
-
- perf_hpp__for_each_format(fmt) {
- if (!perf_hpp__is_sort_entry(fmt))
- continue;
-
- /* must be 'comm' sort entry */
- left_margin = fmt->width(fmt, NULL, hists_to_evsel(hists));
- left_margin -= thread__comm_len(he->thread);
- break;
- }
- }
- return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
-}
-
static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
{
const char *sep = symbol_conf.field_sep;
.buf = bf,
.size = size,
};
+ u64 total_period = hists->stats.total_period;
if (size == 0 || size > bfsz)
size = hpp.size = bfsz;
ret = fprintf(fp, "%s\n", bf);
if (symbol_conf.use_callchain)
- ret += hist_entry__callchain_fprintf(he, hists, fp);
+ ret += hist_entry_callchain__fprintf(he, total_period, 0, fp);
return ret;
}