static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
{ int i; int ret = fprintf(fp, " ");
if (left_margin > USHRT_MAX)
left_margin = USHRT_MAX;
for (i = 0; i < left_margin; i++)
ret += fprintf(fp, " ");
return ret;
}
static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask, int left_margin)
{ int i;
size_t ret = callchain__fprintf_left_margin(fp, left_margin);
for (i = 0; i < depth; i++) if (depth_mask & (1 << i))
ret += fprintf(fp, "| "); else
ret += fprintf(fp, " ");
ret += fprintf(fp, "\n");
return ret;
}
static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node, struct callchain_list *chain, int depth, int depth_mask, int period,
u64 total_samples, int left_margin)
{ int i;
size_t ret = 0; char bf[1024], *alloc_str = NULL; char buf[64]; constchar *str;
ret += callchain__fprintf_left_margin(fp, left_margin); for (i = 0; i < depth; i++) { if (depth_mask & (1 << i))
ret += fprintf(fp, "|"); else
ret += fprintf(fp, " "); if (!period && i == depth - 1) {
ret += fprintf(fp, "--");
ret += callchain_node__fprintf_value(node, fp, total_samples);
ret += fprintf(fp, "--");
} else
ret += fprintf(fp, "%s", " ");
}
/* * The depth mask manages the output of pipes that show * the depth. We don't want to keep the pipes of the current * level for the last child of this depth. * Except if we have remaining filtered hits. They will * supersede the last child
*/
next = rb_next(node); if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
new_depth_mask &= ~(1 << (depth - 1));
/* * But we keep the older depth mask for the line separator * to keep the level link until we reach the last child
*/
ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
left_margin);
i = 0;
list_for_each_entry(chain, &child->val, list) {
ret += ipchain__fprintf_graph(fp, child, chain, depth,
new_depth_mask, i++,
total_samples,
left_margin);
}
/* * 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.
*/ staticbool need_percent_display(struct rb_node *node, u64 parent_samples)
{ struct callchain_node *cnode;
static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
u64 total_samples, u64 parent_samples, int left_margin)
{ struct callchain_node *cnode; struct callchain_list *chain;
u32 entries_printed = 0; bool printed = false; struct rb_node *node; int i = 0; int ret = 0; char bf[1024];
node = rb_first(root); 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) { /* * If we sort by symbol, the first entry is the same than * the symbol. No need to print it otherwise it appears as * displayed twice.
*/ if (!i++ && field_order == NULL &&
sort_order && strstarts(sort_order, "sym")) continue;
if (!printed) {
ret += callchain__fprintf_left_margin(fp, left_margin);
ret += fprintf(fp, "|\n");
ret += callchain__fprintf_left_margin(fp, left_margin);
ret += fprintf(fp, "---");
left_margin += 3;
printed = true;
} else
ret += callchain__fprintf_left_margin(fp, left_margin);
ret += fprintf(fp, "%s",
callchain_list__sym_name(chain, bf, sizeof(bf), false));
if (symbol_conf.show_branchflag_count)
ret += callchain_list_counts__printf_value(
chain, fp, NULL, 0);
ret += fprintf(fp, "\n");
if (++entries_printed == callchain_param.print_limit) break;
}
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); if (ret) { /* do not add a blank line if it printed nothing */
ret += fprintf(fp, "\n");
}
while (rb_node) {
chain = rb_entry(rb_node, struct callchain_node, rb_node);
ret += fprintf(fp, " ");
ret += callchain_node__fprintf_value(chain, fp, total_samples);
ret += fprintf(fp, "\n");
ret += __callchain__fprintf_flat(fp, chain, total_samples);
ret += fprintf(fp, "\n"); if (++entries_printed == callchain_param.print_limit) break;
ret += callchain_node__fprintf_value(chain, fp, total_samples);
ret += fprintf(fp, " ");
ret += __callchain__fprintf_folded(fp, chain);
ret += fprintf(fp, "\n"); if (++entries_printed == callchain_param.print_limit) break;
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, total_samples,
parent_samples, left_margin); break; case CHAIN_GRAPH_ABS: return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
parent_samples, left_margin); break; case CHAIN_FLAT: return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples); break; case CHAIN_FOLDED: return callchain__fprintf_folded(fp, &he->sorted_chain, total_samples); break; case CHAIN_NONE: break; default:
pr_err("Bad callchain mode\n");
}
return 0;
}
int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp, struct perf_hpp_list *hpp_list)
{ constchar *sep = symbol_conf.field_sep; struct perf_hpp_fmt *fmt; char *start = hpp->buf; int ret; bool first = true;
if (symbol_conf.exclude_other && !he->parent) return 0;
perf_hpp_list__for_each_format(hpp_list, fmt) { if (perf_hpp__should_skip(fmt, he->hists)) continue;
/* * If there's no field_sep, we still need * to display initial ' '.
*/ if (!sep || !first) {
ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
advance_hpp(hpp, ret);
} else
first = false;
if (perf_hpp__use_color() && fmt->color)
ret = fmt->color(fmt, hpp, he); else
ret = fmt->entry(fmt, hpp, he);
ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
advance_hpp(hpp, ret);
}
/* the first hpp_list_node is for overhead columns */
fmt_node = list_first_entry(&hists->hpp_formats, struct perf_hpp_list_node, list);
perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { /* * If there's no field_sep, we still need * to display initial ' '.
*/ if (!sep || !first) {
ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
advance_hpp(hpp, ret);
} else
first = false;
if (perf_hpp__use_color() && fmt->color)
ret = fmt->color(fmt, hpp, he); else
ret = fmt->entry(fmt, hpp, he);
ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
advance_hpp(hpp, ret);
}
if (!sep)
ret = scnprintf(hpp->buf, hpp->size, "%*s",
(hists->nr_hpp_node - 2) * HIERARCHY_INDENT, "");
advance_hpp(hpp, ret);
/* * No need to call hist_entry__snprintf_alignment() since this * fmt is always the last column in the hierarchy mode.
*/ if (perf_hpp__use_color() && fmt->color)
fmt->color(fmt, hpp, he); else
fmt->entry(fmt, hpp, he);
/* * dynamic entries are right-aligned but we want left-aligned * in the hierarchy mode
*/
printed += fprintf(fp, "%s%s", sep ?: " ", skip_spaces(buf));
}
printed += putc('\n', fp);
if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
u64 total = hists__total_period(hists);
for (line = 0; line < hpp_list->nr_header_lines; line++) { /* first # is displayed one level up */ if (line)
fprintf(fp, "# ");
fprintf_line(hists, hpp, line, fp);
fprintf(fp, "\n");
}
if (symbol_conf.report_individual_block)
percent = block_info__total_cycles_percent(h); else
percent = hist_entry__get_percent_limit(h);
if (percent < min_pcnt) continue;
ret += hist_entry__fprintf(h, max_cols, line, linesz, fp, ignore_callchains);
if (max_rows && ++nr_rows >= max_rows) break;
/* * If all children are filtered out or percent-limited, * display "no entry >= x.xx%" message.
*/ if (!h->leaf && !hist_entry__has_hierarchy_children(h, min_pcnt)) { int depth = hists->nr_hpp_node + h->depth + 1;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.