Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags   |
// SPDX-License-Identifier: GPL-2.0
#include <stdio.h>
#include <stdlib.h>
#include <linux/string.h>
#include "../../util/callchain.h"
#include "../../util/debug.h"
#include "../../util/event.h"
#include "../../util/hist.h"
#include "../../util/map.h"
#include "../../util/maps.h"
#include "../../util/symbol.h"
#include "../../util/sort.h"
#include "../../util/evsel.h"
#include "../../util/srcline.h"
#include "../../util/string2.h"
#include "../../util/thread.h"
#include "../../util/block-info.h"
#include <linux/ctype.h>
#include <linux/zalloc.h>
static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
{
<------>int i;
<------>int ret = fprintf(fp, " ");
<------>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];
<------>const char *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", " ");
<------>}
<------>str = callchain_list__sym_name(chain, bf, sizeof(bf), false);
<------>if (symbol_conf.show_branchflag_count) {
<------><------>callchain_list_counts__printf_value(chain, NULL,
<------><------><------><------><------><------> buf, sizeof(buf));
<------><------>if (asprintf(&alloc_str, "%s%s", str, buf) < 0)
<------><------><------>str = "Not enough memory!";
<------><------>else
<------><------><------>str = alloc_str;
<------>}
<------>fputs(str, fp);
<------>fputc('\n', fp);
<------>free(alloc_str);
<------>return ret;
}
static struct symbol *rem_sq_bracket;
static struct callchain_list rem_hits;
static void init_rem_hits(void)
{
<------>rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
<------>if (!rem_sq_bracket) {
<------><------>fprintf(stderr, "Not enough memory to display remaining hits\n");
<------><------>return;
<------>}
<------>strcpy(rem_sq_bracket->name, "[...]");
<------>rem_hits.ms.sym = rem_sq_bracket;
}
static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
<------><------><------><------><------> u64 total_samples, int depth,
<------><------><------><------><------> int depth_mask, int left_margin)
{
<------>struct rb_node *node, *next;
<------>struct callchain_node *child = NULL;
<------>struct callchain_list *chain;
<------>int new_depth_mask = depth_mask;
<------>u64 remaining;
<------>size_t ret = 0;
<------>int i;
<------>uint entries_printed = 0;
<------>int cumul_count = 0;
<------>remaining = total_samples;
<------>node = rb_first(root);
<------>while (node) {
<------><------>u64 new_total;
<------><------>u64 cumul;
<------><------>child = rb_entry(node, struct callchain_node, rb_node);
<------><------>cumul = callchain_cumul_hits(child);
<------><------>remaining -= cumul;
<------><------>cumul_count += callchain_cumul_counts(child);
<------><------>/*
<------><------> * 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 (callchain_param.mode == CHAIN_GRAPH_REL)
<------><------><------>new_total = child->children_hit;
<------><------>else
<------><------><------>new_total = total_samples;
<------><------>ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,
<------><------><------><------><------><------> depth + 1,
<------><------><------><------><------><------> new_depth_mask | (1 << depth),
<------><------><------><------><------><------> left_margin);
<------><------>node = next;
<------><------>if (++entries_printed == callchain_param.print_limit)
<------><------><------>break;
<------>}
<------>if (callchain_param.mode == CHAIN_GRAPH_REL &&
<------><------>remaining && remaining != total_samples) {
<------><------>struct callchain_node rem_node = {
<------><------><------>.hit = remaining,
<------><------>};
<------><------>if (!rem_sq_bracket)
<------><------><------>return ret;
<------><------>if (callchain_param.value == CCVAL_COUNT && child && child->parent) {
<------><------><------>rem_node.count = child->parent->children_count - cumul_count;
<------><------><------>if (rem_node.count <= 0)
<------><------><------><------>return ret;
<------><------>}
<------><------>new_depth_mask &= ~(1 << (depth - 1));
<------><------>ret += ipchain__fprintf_graph(fp, &rem_node, &rem_hits, depth,
<------><------><------><------><------> new_depth_mask, 0, total_samples,
<------><------><------><------><------> left_margin);
<------>}
<------>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, 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");
<------>}
<------>return ret;
}
static size_t __callchain__fprintf_flat(FILE *fp, struct callchain_node *node,
<------><------><------><------><------>u64 total_samples)
{
<------>struct callchain_list *chain;
<------>size_t ret = 0;
<------>char bf[1024];
<------>if (!node)
<------><------>return 0;
<------>ret += __callchain__fprintf_flat(fp, node->parent, total_samples);
<------>list_for_each_entry(chain, &node->val, list) {
<------><------>if (chain->ip >= PERF_CONTEXT_MAX)
<------><------><------>continue;
<------><------>ret += fprintf(fp, " %s\n", callchain_list__sym_name(chain,
<------><------><------><------><------>bf, sizeof(bf), false));
<------>}
<------>return ret;
}
static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
<------><------><------><------> u64 total_samples)
{
<------>size_t ret = 0;
<------>u32 entries_printed = 0;
<------>struct callchain_node *chain;
<------>struct rb_node *rb_node = rb_first(tree);
<------>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;
<------><------>rb_node = rb_next(rb_node);
<------>}
<------>return ret;
}
static size_t __callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
{
<------>const char *sep = symbol_conf.field_sep ?: ";";
<------>struct callchain_list *chain;
<------>size_t ret = 0;
<------>char bf[1024];
<------>bool first;
<------>if (!node)
<------><------>return 0;
<------>ret += __callchain__fprintf_folded(fp, node->parent);
<------>first = (ret == 0);
<------>list_for_each_entry(chain, &node->val, list) {
<------><------>if (chain->ip >= PERF_CONTEXT_MAX)
<------><------><------>continue;
<------><------>ret += fprintf(fp, "%s%s", first ? "" : sep,
<------><------><------> callchain_list__sym_name(chain,
<------><------><------><------><------><------>bf, sizeof(bf), false));
<------><------>first = false;
<------>}
<------>return ret;
}
static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree,
<------><------><------><------><------>u64 total_samples)
{
<------>size_t ret = 0;
<------>u32 entries_printed = 0;
<------>struct callchain_node *chain;
<------>struct rb_node *rb_node = rb_first(tree);
<------>while (rb_node) {
<------><------>chain = rb_entry(rb_node, struct callchain_node, rb_node);
<------><------>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;
<------><------>rb_node = rb_next(rb_node);
<------>}
<------>return ret;
}
static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
<------><------><------><------><------> 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, 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)
{
<------>const char *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);
<------>}
<------>return hpp->buf - start;
}
static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
{
<------>return __hist_entry__snprintf(he, hpp, he->hists->hpp_list);
}
static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
<------><------><------><------><------> struct perf_hpp *hpp,
<------><------><------><------><------> struct hists *hists,
<------><------><------><------><------> FILE *fp)
{
<------>const char *sep = symbol_conf.field_sep;
<------>struct perf_hpp_fmt *fmt;
<------>struct perf_hpp_list_node *fmt_node;
<------>char *buf = hpp->buf;
<------>size_t size = hpp->size;
<------>int ret, printed = 0;
<------>bool first = true;
<------>if (symbol_conf.exclude_other && !he->parent)
<------><------>return 0;
<------>ret = scnprintf(hpp->buf, hpp->size, "%*s", he->depth * HIERARCHY_INDENT, "");
<------>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);
<------>printed += fprintf(fp, "%s", buf);
<------>perf_hpp_list__for_each_format(he->hpp_list, fmt) {
<------><------>hpp->buf = buf;
<------><------>hpp->size = size;
<------><------>/*
<------><------> * 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);
<------><------>printed += hist_entry_callchain__fprintf(he, total, 0, fp);
<------><------>goto out;
<------>}
out:
<------>return printed;
}
static int hist_entry__block_fprintf(struct hist_entry *he,
<------><------><------><------> char *bf, size_t size,
<------><------><------><------> FILE *fp)
{
<------>struct block_hist *bh = container_of(he, struct block_hist, he);
<------>int ret = 0;
<------>for (unsigned int i = 0; i < bh->block_hists.nr_entries; i++) {
<------><------>struct perf_hpp hpp = {
<------><------><------>.buf = bf,
<------><------><------>.size = size,
<------><------><------>.skip = false,
<------><------>};
<------><------>bh->block_idx = i;
<------><------>hist_entry__snprintf(he, &hpp);
<------><------>if (!hpp.skip)
<------><------><------>ret += fprintf(fp, "%s\n", bf);
<------>}
<------>return ret;
}
static int hist_entry__individual_block_fprintf(struct hist_entry *he,
<------><------><------><------><------><------>char *bf, size_t size,
<------><------><------><------><------><------>FILE *fp)
{
<------>int ret = 0;
<------>struct perf_hpp hpp = {
<------><------>.buf = bf,
<------><------>.size = size,
<------><------>.skip = false,
<------>};
<------>hist_entry__snprintf(he, &hpp);
<------>if (!hpp.skip)
<------><------>ret += fprintf(fp, "%s\n", bf);
<------>return ret;
}
static int hist_entry__fprintf(struct hist_entry *he, size_t size,
<------><------><------> char *bf, size_t bfsz, FILE *fp,
<------><------><------> bool ignore_callchains)
{
<------>int ret;
<------>int callchain_ret = 0;
<------>struct perf_hpp hpp = {
<------><------>.buf = bf,
<------><------>.size = size,
<------>};
<------>struct hists *hists = he->hists;
<------>u64 total_period = hists->stats.total_period;
<------>if (size == 0 || size > bfsz)
<------><------>size = hpp.size = bfsz;
<------>if (symbol_conf.report_hierarchy)
<------><------>return hist_entry__hierarchy_fprintf(he, &hpp, hists, fp);
<------>if (symbol_conf.report_block)
<------><------>return hist_entry__block_fprintf(he, bf, size, fp);
<------>if (symbol_conf.report_individual_block)
<------><------>return hist_entry__individual_block_fprintf(he, bf, size, fp);
<------>hist_entry__snprintf(he, &hpp);
<------>ret = fprintf(fp, "%s\n", bf);
<------>if (hist_entry__has_callchains(he) && !ignore_callchains)
<------><------>callchain_ret = hist_entry_callchain__fprintf(he, total_period,
<------><------><------><------><------><------><------> 0, fp);
<------>ret += callchain_ret;
<------>return ret;
}
static int print_hierarchy_indent(const char *sep, int indent,
<------><------><------><------> const char *line, FILE *fp)
{
<------>int width;
<------>if (sep != NULL || indent < 2)
<------><------>return 0;
<------>width = (indent - 2) * HIERARCHY_INDENT;
<------>return fprintf(fp, "%-*.*s", width, width, line);
}
static int hists__fprintf_hierarchy_headers(struct hists *hists,
<------><------><------><------><------> struct perf_hpp *hpp, FILE *fp)
{
<------>bool first_node, first_col;
<------>int indent;
<------>int depth;
<------>unsigned width = 0;
<------>unsigned header_width = 0;
<------>struct perf_hpp_fmt *fmt;
<------>struct perf_hpp_list_node *fmt_node;
<------>const char *sep = symbol_conf.field_sep;
<------>indent = hists->nr_hpp_node;
<------>/* preserve max indent depth for column headers */
<------>print_hierarchy_indent(sep, indent, " ", fp);
<------>/* 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) {
<------><------>fmt->header(fmt, hpp, hists, 0, NULL);
<------><------>fprintf(fp, "%s%s", hpp->buf, sep ?: " ");
<------>}
<------>/* combine sort headers with ' / ' */
<------>first_node = true;
<------>list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
<------><------>if (!first_node)
<------><------><------>header_width += fprintf(fp, " / ");
<------><------>first_node = false;
<------><------>first_col = true;
<------><------>perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
<------><------><------>if (perf_hpp__should_skip(fmt, hists))
<------><------><------><------>continue;
<------><------><------>if (!first_col)
<------><------><------><------>header_width += fprintf(fp, "+");
<------><------><------>first_col = false;
<------><------><------>fmt->header(fmt, hpp, hists, 0, NULL);
<------><------><------>header_width += fprintf(fp, "%s", strim(hpp->buf));
<------><------>}
<------>}
<------>fprintf(fp, "\n# ");
<------>/* preserve max indent depth for initial dots */
<------>print_hierarchy_indent(sep, indent, dots, fp);
<------>/* the first hpp_list_node is for overhead columns */
<------>fmt_node = list_first_entry(&hists->hpp_formats,
<------><------><------><------> struct perf_hpp_list_node, list);
<------>first_col = true;
<------>perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
<------><------>if (!first_col)
<------><------><------>fprintf(fp, "%s", sep ?: "..");
<------><------>first_col = false;
<------><------>width = fmt->width(fmt, hpp, hists);
<------><------>fprintf(fp, "%.*s", width, dots);
<------>}
<------>depth = 0;
<------>list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
<------><------>first_col = true;
<------><------>width = depth * HIERARCHY_INDENT;
<------><------>perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
<------><------><------>if (perf_hpp__should_skip(fmt, hists))
<------><------><------><------>continue;
<------><------><------>if (!first_col)
<------><------><------><------>width++; /* for '+' sign between column header */
<------><------><------>first_col = false;
<------><------><------>width += fmt->width(fmt, hpp, hists);
<------><------>}
<------><------>if (width > header_width)
<------><------><------>header_width = width;
<------><------>depth++;
<------>}
<------>fprintf(fp, "%s%-.*s", sep ?: " ", header_width, dots);
<------>fprintf(fp, "\n#\n");
<------>return 2;
}
static void fprintf_line(struct hists *hists, struct perf_hpp *hpp,
<------><------><------> int line, FILE *fp)
{
<------>struct perf_hpp_fmt *fmt;
<------>const char *sep = symbol_conf.field_sep;
<------>bool first = true;
<------>int span = 0;
<------>hists__for_each_format(hists, fmt) {
<------><------>if (perf_hpp__should_skip(fmt, hists))
<------><------><------>continue;
<------><------>if (!first && !span)
<------><------><------>fprintf(fp, "%s", sep ?: " ");
<------><------>else
<------><------><------>first = false;
<------><------>fmt->header(fmt, hpp, hists, line, &span);
<------><------>if (!span)
<------><------><------>fprintf(fp, "%s", hpp->buf);
<------>}
}
static int
hists__fprintf_standard_headers(struct hists *hists,
<------><------><------><------>struct perf_hpp *hpp,
<------><------><------><------>FILE *fp)
{
<------>struct perf_hpp_list *hpp_list = hists->hpp_list;
<------>struct perf_hpp_fmt *fmt;
<------>unsigned int width;
<------>const char *sep = symbol_conf.field_sep;
<------>bool first = true;
<------>int line;
<------>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 (sep)
<------><------>return hpp_list->nr_header_lines;
<------>first = true;
<------>fprintf(fp, "# ");
<------>hists__for_each_format(hists, fmt) {
<------><------>unsigned int i;
<------><------>if (perf_hpp__should_skip(fmt, hists))
<------><------><------>continue;
<------><------>if (!first)
<------><------><------>fprintf(fp, "%s", sep ?: " ");
<------><------>else
<------><------><------>first = false;
<------><------>width = fmt->width(fmt, hpp, hists);
<------><------>for (i = 0; i < width; i++)
<------><------><------>fprintf(fp, ".");
<------>}
<------>fprintf(fp, "\n");
<------>fprintf(fp, "#\n");
<------>return hpp_list->nr_header_lines + 2;
}
int hists__fprintf_headers(struct hists *hists, FILE *fp)
{
<------>char bf[1024];
<------>struct perf_hpp dummy_hpp = {
<------><------>.buf = bf,
<------><------>.size = sizeof(bf),
<------>};
<------>fprintf(fp, "# ");
<------>if (symbol_conf.report_hierarchy)
<------><------>return hists__fprintf_hierarchy_headers(hists, &dummy_hpp, fp);
<------>else
<------><------>return hists__fprintf_standard_headers(hists, &dummy_hpp, fp);
}
size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
<------><------> int max_cols, float min_pcnt, FILE *fp,
<------><------> bool ignore_callchains)
{
<------>struct rb_node *nd;
<------>size_t ret = 0;
<------>const char *sep = symbol_conf.field_sep;
<------>int nr_rows = 0;
<------>size_t linesz;
<------>char *line = NULL;
<------>unsigned indent;
<------>init_rem_hits();
<------>hists__reset_column_width(hists);
<------>if (symbol_conf.col_width_list_str)
<------><------>perf_hpp__set_user_width(symbol_conf.col_width_list_str);
<------>if (show_header)
<------><------>nr_rows += hists__fprintf_headers(hists, fp);
<------>if (max_rows && nr_rows >= max_rows)
<------><------>goto out;
<------>linesz = hists__sort_list_width(hists) + 3 + 1;
<------>linesz += perf_hpp__color_overhead();
<------>line = malloc(linesz);
<------>if (line == NULL) {
<------><------>ret = -1;
<------><------>goto out;
<------>}
<------>indent = hists__overhead_width(hists) + 4;
<------>for (nd = rb_first_cached(&hists->entries); nd;
<------> nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD)) {
<------><------>struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
<------><------>float percent;
<------><------>if (h->filtered)
<------><------><------>continue;
<------><------>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;
<------><------><------>print_hierarchy_indent(sep, depth, " ", fp);
<------><------><------>fprintf(fp, "%*sno entry >= %.2f%%\n", indent, "", min_pcnt);
<------><------><------>if (max_rows && ++nr_rows >= max_rows)
<------><------><------><------>break;
<------><------>}
<------><------>if (h->ms.map == NULL && verbose > 1) {
<------><------><------>maps__fprintf(h->thread->maps, fp);
<------><------><------>fprintf(fp, "%.10s end\n", graph_dotted_line);
<------><------>}
<------>}
<------>free(line);
out:
<------>zfree(&rem_sq_bracket);
<------>return ret;
}
size_t events_stats__fprintf(struct events_stats *stats, FILE *fp)
{
<------>int i;
<------>size_t ret = 0;
<------>for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
<------><------>const char *name;
<------><------>name = perf_event__name(i);
<------><------>if (!strcmp(name, "UNKNOWN"))
<------><------><------>continue;
<------><------>ret += fprintf(fp, "%16s events: %10d\n", name, stats->nr_events[i]);
<------>}
<------>return ret;
}