diff options
Diffstat (limited to 'tools/perf/ui/stdio/hist.c')
| -rw-r--r-- | tools/perf/ui/stdio/hist.c | 183 |
1 files changed, 106 insertions, 77 deletions
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index fbd4e32d074..90122abd372 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -3,6 +3,7 @@ #include "../../util/util.h" #include "../../util/hist.h" #include "../../util/sort.h" +#include "../../util/evsel.h" static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) @@ -182,7 +183,8 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, * the symbol. No need to print it otherwise it appears as * displayed twice. */ - if (!i++ && sort__first_dimension == SORT_SYM) + if (!i++ && field_order == NULL && + sort_order && !prefixcmp(sort_order, "sym")) continue; if (!printed) { ret += callchain__fprintf_left_margin(fp, left_margin); @@ -212,20 +214,19 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, return ret; } -static size_t __callchain__fprintf_flat(FILE *fp, - struct callchain_node *self, +static size_t __callchain__fprintf_flat(FILE *fp, struct callchain_node *node, u64 total_samples) { struct callchain_list *chain; size_t ret = 0; - if (!self) + if (!node) return 0; - ret += __callchain__fprintf_flat(fp, self->parent, total_samples); + ret += __callchain__fprintf_flat(fp, node->parent, total_samples); - list_for_each_entry(chain, &self->val, list) { + list_for_each_entry(chain, &node->val, list) { if (chain->ip >= PERF_CONTEXT_MAX) continue; if (chain->ms.sym) @@ -238,15 +239,14 @@ static size_t __callchain__fprintf_flat(FILE *fp, return ret; } -static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *self, +static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree, u64 total_samples) { size_t ret = 0; u32 entries_printed = 0; - struct rb_node *rb_node; struct callchain_node *chain; + struct rb_node *rb_node = rb_first(tree); - rb_node = rb_first(self); while (rb_node) { double percent; @@ -271,7 +271,9 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he, { switch (callchain_param.mode) { case CHAIN_GRAPH_REL: - return callchain__fprintf_graph(fp, &he->sorted_chain, he->stat.period, + return callchain__fprintf_graph(fp, &he->sorted_chain, + symbol_conf.cumulate_callchain ? + he->stat_acc->period : he->stat.period, left_margin); break; case CHAIN_GRAPH_ABS: @@ -297,32 +299,73 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he, int left_margin = 0; u64 total_period = hists->stats.total_period; - if (sort__first_dimension == SORT_COMM) { - struct sort_entry *se = list_first_entry(&hist_entry__sort_list, - typeof(*se), list); - left_margin = hists__col_len(hists, se->se_width_idx); - left_margin -= thread__comm_len(he->thread); - } + 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; + 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__for_each_format(fmt) { + if (perf_hpp__should_skip(fmt)) + 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); + + advance_hpp(hpp, ret); + } + + return hpp->buf - start; +} + static int hist_entry__fprintf(struct hist_entry *he, size_t size, - struct hists *hists, FILE *fp) + struct hists *hists, + char *bf, size_t bfsz, FILE *fp) { - char bf[512]; int ret; struct perf_hpp hpp = { .buf = bf, .size = size, }; - bool color = !symbol_conf.field_sep; - if (size == 0 || size > sizeof(bf)) - size = hpp.size = sizeof(bf); + if (size == 0 || size > bfsz) + size = hpp.size = bfsz; - ret = hist_entry__period_snprintf(&hpp, he, color); - hist_entry__sort_snprintf(he, bf + ret, size - ret, hists); + hist_entry__snprintf(he, &hpp); ret = fprintf(fp, "%s\n", bf); @@ -333,30 +376,36 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, } size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, - int max_cols, FILE *fp) + int max_cols, float min_pcnt, FILE *fp) { - struct sort_entry *se; + struct perf_hpp_fmt *fmt; struct rb_node *nd; size_t ret = 0; unsigned int width; const char *sep = symbol_conf.field_sep; - const char *col_width = symbol_conf.col_width_list_str; - int idx, nr_rows = 0; - char bf[64]; + int nr_rows = 0; + char bf[96]; struct perf_hpp dummy_hpp = { .buf = bf, .size = sizeof(bf), }; bool first = true; + size_t linesz; + char *line = NULL; init_rem_hits(); + + perf_hpp__for_each_format(fmt) + perf_hpp__reset_width(fmt, hists); + if (!show_header) goto print_entries; fprintf(fp, "# "); - for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { - if (!perf_hpp__format[idx].cond) + + perf_hpp__for_each_format(fmt) { + if (perf_hpp__should_skip(fmt)) continue; if (!first) @@ -364,32 +413,10 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, else first = false; - perf_hpp__format[idx].header(&dummy_hpp); + fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); fprintf(fp, "%s", bf); } - list_for_each_entry(se, &hist_entry__sort_list, list) { - if (se->elide) - continue; - if (sep) { - fprintf(fp, "%c%s", *sep, se->se_header); - continue; - } - width = strlen(se->se_header); - if (symbol_conf.col_width_list_str) { - if (col_width) { - hists__set_col_len(hists, se->se_width_idx, - atoi(col_width)); - col_width = strchr(col_width, ','); - if (col_width) - ++col_width; - } - } - if (!hists__new_col_len(hists, se->se_width_idx, width)) - width = hists__col_len(hists, se->se_width_idx); - fprintf(fp, " %*s", width, se->se_header); - } - fprintf(fp, "\n"); if (max_rows && ++nr_rows >= max_rows) goto out; @@ -400,10 +427,11 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, first = true; fprintf(fp, "# "); - for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { + + perf_hpp__for_each_format(fmt) { unsigned int i; - if (!perf_hpp__format[idx].cond) + if (perf_hpp__should_skip(fmt)) continue; if (!first) @@ -411,21 +439,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, else first = false; - width = perf_hpp__format[idx].width(&dummy_hpp); - for (i = 0; i < width; i++) - fprintf(fp, "."); - } - - list_for_each_entry(se, &hist_entry__sort_list, list) { - unsigned int i; - - if (se->elide) - continue; - - fprintf(fp, " "); - width = hists__col_len(hists, se->se_width_idx); - if (width == 0) - width = strlen(se->se_header); + width = fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); for (i = 0; i < width; i++) fprintf(fp, "."); } @@ -439,30 +453,45 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, goto out; print_entries: + linesz = hists__sort_list_width(hists) + 3 + 1; + linesz += perf_hpp__color_overhead(); + line = malloc(linesz); + if (line == NULL) { + ret = -1; + goto out; + } + for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); + float percent; if (h->filtered) continue; - ret += hist_entry__fprintf(h, max_cols, hists, fp); + percent = hist_entry__get_percent_limit(h); + if (percent < min_pcnt) + continue; + + ret += hist_entry__fprintf(h, max_cols, hists, line, linesz, fp); if (max_rows && ++nr_rows >= max_rows) - goto out; + break; if (h->ms.map == NULL && verbose > 1) { - __map_groups__fprintf_maps(&h->thread->mg, + __map_groups__fprintf_maps(h->thread->mg, MAP__FUNCTION, verbose, fp); fprintf(fp, "%.10s end\n", graph_dotted_line); } } + + free(line); out: - free(rem_sq_bracket); + zfree(&rem_sq_bracket); return ret; } -size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) +size_t events_stats__fprintf(struct events_stats *stats, FILE *fp) { int i; size_t ret = 0; @@ -470,7 +499,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { const char *name; - if (hists->stats.nr_events[i] == 0) + if (stats->nr_events[i] == 0) continue; name = perf_event__name(i); @@ -478,7 +507,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) continue; ret += fprintf(fp, "%16s events: %10d\n", name, - hists->stats.nr_events[i]); + stats->nr_events[i]); } return ret; |
