diff options
Diffstat (limited to 'tools/perf/util/annotate.c')
-rw-r--r-- | tools/perf/util/annotate.c | 305 |
1 files changed, 183 insertions, 122 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f91775b4bc3c..20061cf42288 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -49,6 +49,7 @@ struct annotation_options annotation__default_options = { .jump_arrows = true, .annotate_src = true, .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, + .percent_type = PERCENT_PERIOD_LOCAL, }; static regex_t file_lineno; @@ -1108,7 +1109,7 @@ annotation_line__new(struct annotate_args *args, size_t privsize) if (perf_evsel__is_group_event(evsel)) nr = evsel->nr_members; - size += sizeof(al->samples[0]) * nr; + size += sizeof(al->data[0]) * nr; al = zalloc(size); if (al) { @@ -1117,7 +1118,7 @@ annotation_line__new(struct annotate_args *args, size_t privsize) al->offset = args->offset; al->line = strdup(args->line); al->line_nr = args->line_nr; - al->samples_nr = nr; + al->data_nr = nr; } return al; @@ -1297,7 +1298,8 @@ static int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_wi static int annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, - int max_lines, struct annotation_line *queue, int addr_fmt_width) + int max_lines, struct annotation_line *queue, int addr_fmt_width, + int percent_type) { struct disasm_line *dl = container_of(al, struct disasm_line, al); static const char *prev_line; @@ -1309,15 +1311,18 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start const char *color; struct annotation *notes = symbol__annotation(sym); - for (i = 0; i < al->samples_nr; i++) { - struct annotation_data *sample = &al->samples[i]; + for (i = 0; i < al->data_nr; i++) { + double percent; - if (sample->percent > max_percent) - max_percent = sample->percent; + percent = annotation_data__percent(&al->data[i], + percent_type); + + if (percent > max_percent) + max_percent = percent; } - if (al->samples_nr > nr_percent) - nr_percent = al->samples_nr; + if (al->data_nr > nr_percent) + nr_percent = al->data_nr; if (max_percent < min_pcnt) return -1; @@ -1330,7 +1335,8 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start if (queue == al) break; annotation_line__print(queue, sym, start, evsel, len, - 0, 0, 1, NULL, addr_fmt_width); + 0, 0, 1, NULL, addr_fmt_width, + percent_type); } } @@ -1351,18 +1357,20 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start } for (i = 0; i < nr_percent; i++) { - struct annotation_data *sample = &al->samples[i]; + struct annotation_data *data = &al->data[i]; + double percent; - color = get_percent_color(sample->percent); + percent = annotation_data__percent(data, percent_type); + color = get_percent_color(percent); if (symbol_conf.show_total_period) color_fprintf(stdout, color, " %11" PRIu64, - sample->he.period); + data->he.period); else if (symbol_conf.show_nr_samples) color_fprintf(stdout, color, " %7" PRIu64, - sample->he.nr_samples); + data->he.nr_samples); else - color_fprintf(stdout, color, " %7.2f", sample->percent); + color_fprintf(stdout, color, " %7.2f", percent); } printf(" : "); @@ -1621,6 +1629,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) char symfs_filename[PATH_MAX]; struct kcore_extract kce; bool delete_extract = false; + bool decomp = false; int stdout_fd[2]; int lineno = 0; int nline; @@ -1654,6 +1663,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) tmp, sizeof(tmp)) < 0) goto out; + decomp = true; strcpy(symfs_filename, tmp); } @@ -1740,7 +1750,7 @@ out_free_command: out_remove_tmp: close(stdout_fd[0]); - if (dso__needs_decompress(dso)) + if (decomp) unlink(symfs_filename); if (delete_extract) @@ -1753,34 +1763,45 @@ out_close_stdout: goto out_free_command; } -static void calc_percent(struct sym_hist *hist, - struct annotation_data *sample, +static void calc_percent(struct sym_hist *sym_hist, + struct hists *hists, + struct annotation_data *data, s64 offset, s64 end) { unsigned int hits = 0; u64 period = 0; while (offset < end) { - hits += hist->addr[offset].nr_samples; - period += hist->addr[offset].period; + hits += sym_hist->addr[offset].nr_samples; + period += sym_hist->addr[offset].period; ++offset; } - if (hist->nr_samples) { - sample->he.period = period; - sample->he.nr_samples = hits; - sample->percent = 100.0 * hits / hist->nr_samples; + if (sym_hist->nr_samples) { + data->he.period = period; + data->he.nr_samples = hits; + data->percent[PERCENT_HITS_LOCAL] = 100.0 * hits / sym_hist->nr_samples; } + + if (hists->stats.nr_non_filtered_samples) + data->percent[PERCENT_HITS_GLOBAL] = 100.0 * hits / hists->stats.nr_non_filtered_samples; + + if (sym_hist->period) + data->percent[PERCENT_PERIOD_LOCAL] = 100.0 * period / sym_hist->period; + + if (hists->stats.total_period) + data->percent[PERCENT_PERIOD_GLOBAL] = 100.0 * period / hists->stats.total_period; } static void annotation__calc_percent(struct annotation *notes, - struct perf_evsel *evsel, s64 len) + struct perf_evsel *leader, s64 len) { struct annotation_line *al, *next; + struct perf_evsel *evsel; list_for_each_entry(al, ¬es->src->source, node) { s64 end; - int i; + int i = 0; if (al->offset == -1) continue; @@ -1788,14 +1809,17 @@ static void annotation__calc_percent(struct annotation *notes, next = annotation_line__next(al, ¬es->src->source); end = next ? next->offset : len; - for (i = 0; i < al->samples_nr; i++) { - struct annotation_data *sample; - struct sym_hist *hist; + for_each_group_evsel(evsel, leader) { + struct hists *hists = evsel__hists(evsel); + struct annotation_data *data; + struct sym_hist *sym_hist; + + BUG_ON(i >= al->data_nr); - hist = annotation__histogram(notes, evsel->idx + i); - sample = &al->samples[i]; + sym_hist = annotation__histogram(notes, evsel->idx); + data = &al->data[i++]; - calc_percent(hist, sample, al->offset, end); + calc_percent(sym_hist, hists, data, al->offset, end); } } } @@ -1846,7 +1870,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, return symbol__disassemble(sym, &args); } -static void insert_source_line(struct rb_root *root, struct annotation_line *al) +static void insert_source_line(struct rb_root *root, struct annotation_line *al, + struct annotation_options *opts) { struct annotation_line *iter; struct rb_node **p = &root->rb_node; @@ -1859,8 +1884,10 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al) ret = strcmp(iter->path, al->path); if (ret == 0) { - for (i = 0; i < al->samples_nr; i++) - iter->samples[i].percent_sum += al->samples[i].percent; + for (i = 0; i < al->data_nr; i++) { + iter->data[i].percent_sum += annotation_data__percent(&al->data[i], + opts->percent_type); + } return; } @@ -1870,8 +1897,10 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al) p = &(*p)->rb_right; } - for (i = 0; i < al->samples_nr; i++) - al->samples[i].percent_sum = al->samples[i].percent; + for (i = 0; i < al->data_nr; i++) { + al->data[i].percent_sum = annotation_data__percent(&al->data[i], + opts->percent_type); + } rb_link_node(&al->rb_node, parent, p); rb_insert_color(&al->rb_node, root); @@ -1881,10 +1910,10 @@ static int cmp_source_line(struct annotation_line *a, struct annotation_line *b) { int i; - for (i = 0; i < a->samples_nr; i++) { - if (a->samples[i].percent_sum == b->samples[i].percent_sum) + for (i = 0; i < a->data_nr; i++) { + if (a->data[i].percent_sum == b->data[i].percent_sum) continue; - return a->samples[i].percent_sum > b->samples[i].percent_sum; + return a->data[i].percent_sum > b->data[i].percent_sum; } return 0; @@ -1949,8 +1978,8 @@ static void print_summary(struct rb_root *root, const char *filename) int i; al = rb_entry(node, struct annotation_line, rb_node); - for (i = 0; i < al->samples_nr; i++) { - percent = al->samples[i].percent_sum; + for (i = 0; i < al->data_nr; i++) { + percent = al->data[i].percent_sum; color = get_percent_color(percent); color_fprintf(stdout, color, " %7.2f", percent); @@ -2029,10 +2058,12 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, evsel_name = buf; } - graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n", + graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples, " + "percent: %s)\n", width, width, symbol_conf.show_total_period ? "Period" : symbol_conf.show_nr_samples ? "Samples" : "Percent", - d_filename, evsel_name, h->nr_samples); + d_filename, evsel_name, h->nr_samples, + percent_type_str(opts->percent_type)); printf("%-*.*s----\n", graph_dotted_len, graph_dotted_len, graph_dotted_line); @@ -2052,7 +2083,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, err = annotation_line__print(pos, sym, start, evsel, len, opts->min_pcnt, printed, opts->max_lines, - queue, addr_fmt_width); + queue, addr_fmt_width, opts->percent_type); switch (err) { case 0: @@ -2129,10 +2160,11 @@ static void FILE__write_graph(void *fp, int graph) fputs(s, fp); } -int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) +static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, + struct annotation_options *opts) { struct annotation *notes = symbol__annotation(sym); - struct annotation_write_ops ops = { + struct annotation_write_ops wops = { .first_line = true, .obj = fp, .set_color = FILE__set_color, @@ -2146,15 +2178,16 @@ int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) list_for_each_entry(al, ¬es->src->source, node) { if (annotation_line__filter(al, notes)) continue; - annotation_line__write(al, notes, &ops); + annotation_line__write(al, notes, &wops, opts); fputc('\n', fp); - ops.first_line = false; + wops.first_line = false; } return 0; } -int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel) +int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel, + struct annotation_options *opts) { const char *ev_name = perf_evsel__name(evsel); char buf[1024]; @@ -2176,7 +2209,7 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel) fprintf(fp, "%s() %s\nEvent: %s\n\n", ms->sym->name, ms->map->dso->long_name, ev_name); - symbol__annotate_fprintf2(ms->sym, fp); + symbol__annotate_fprintf2(ms->sym, fp, opts); fclose(fp); err = 0; @@ -2346,7 +2379,8 @@ void annotation__update_column_widths(struct annotation *notes) } static void annotation__calc_lines(struct annotation *notes, struct map *map, - struct rb_root *root) + struct rb_root *root, + struct annotation_options *opts) { struct annotation_line *al; struct rb_root tmp_root = RB_ROOT; @@ -2355,13 +2389,14 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, double percent_max = 0.0; int i; - for (i = 0; i < al->samples_nr; i++) { - struct annotation_data *sample; + for (i = 0; i < al->data_nr; i++) { + double percent; - sample = &al->samples[i]; + percent = annotation_data__percent(&al->data[i], + opts->percent_type); - if (sample->percent > percent_max) - percent_max = sample->percent; + if (percent > percent_max) + percent_max = percent; } if (percent_max <= 0.5) @@ -2369,18 +2404,19 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, al->path = get_srcline(map->dso, notes->start + al->offset, NULL, false, true, notes->start + al->offset); - insert_source_line(&tmp_root, al); + insert_source_line(&tmp_root, al, opts); } resort_source_line(root, &tmp_root); } static void symbol__calc_lines(struct symbol *sym, struct map *map, - struct rb_root *root) + struct rb_root *root, + struct annotation_options *opts) { struct annotation *notes = symbol__annotation(sym); - annotation__calc_lines(notes, map, root); + annotation__calc_lines(notes, map, root, opts); } int symbol__tty_annotate2(struct symbol *sym, struct map *map, @@ -2389,7 +2425,7 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, { struct dso *dso = map->dso; struct rb_root source_line = RB_ROOT; - struct annotation *notes = symbol__annotation(sym); + struct hists *hists = evsel__hists(evsel); char buf[1024]; if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0) @@ -2397,13 +2433,14 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, if (opts->print_lines) { srcline_full_filename = opts->full_path; - symbol__calc_lines(sym, map, &source_line); + symbol__calc_lines(sym, map, &source_line, opts); print_summary(&source_line, dso->long_name); } - annotation__scnprintf_samples_period(notes, buf, sizeof(buf), evsel); - fprintf(stdout, "%s\n%s() %s\n", buf, sym->name, dso->long_name); - symbol__annotate_fprintf2(sym, stdout); + hists__scnprintf_title(hists, buf, sizeof(buf)); + fprintf(stdout, "%s, [percent: %s]\n%s() %s\n", + buf, percent_type_str(opts->percent_type), sym->name, dso->long_name); + symbol__annotate_fprintf2(sym, stdout, opts); annotated_source__purge(symbol__annotation(sym)->src); @@ -2424,7 +2461,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, if (opts->print_lines) { srcline_full_filename = opts->full_path; - symbol__calc_lines(sym, map, &source_line); + symbol__calc_lines(sym, map, &source_line, opts); print_summary(&source_line, dso->long_name); } @@ -2441,14 +2478,21 @@ bool ui__has_annotation(void) } -double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes) +static double annotation_line__max_percent(struct annotation_line *al, + struct annotation *notes, + unsigned int percent_type) { double percent_max = 0.0; int i; for (i = 0; i < notes->nr_events; i++) { - if (al->samples[i].percent > percent_max) - percent_max = al->samples[i].percent; + double percent; + + percent = annotation_data__percent(&al->data[i], + percent_type); + + if (percent > percent_max) + percent_max = percent; } return percent_max; @@ -2487,7 +2531,7 @@ call_like: static void __annotation_line__write(struct annotation_line *al, struct annotation *notes, bool first_line, bool current_entry, bool change_color, int width, - void *obj, + void *obj, unsigned int percent_type, int (*obj__set_color)(void *obj, int color), void (*obj__set_percent_color)(void *obj, double percent, bool current), int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), @@ -2495,7 +2539,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati void (*obj__write_graph)(void *obj, int graph)) { - double percent_max = annotation_line__max_percent(al, notes); + double percent_max = annotation_line__max_percent(al, notes, percent_type); int pcnt_width = annotation__pcnt_width(notes), cycles_width = annotation__cycles_width(notes); bool show_title = false; @@ -2514,15 +2558,18 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati int i; for (i = 0; i < notes->nr_events; i++) { - obj__set_percent_color(obj, al->samples[i].percent, current_entry); + double percent; + + percent = annotation_data__percent(&al->data[i], percent_type); + + obj__set_percent_color(obj, percent, current_entry); if (notes->options->show_total_period) { - obj__printf(obj, "%11" PRIu64 " ", al->samples[i].he.period); + obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period); } else if (notes->options->show_nr_samples) { obj__printf(obj, "%6" PRIu64 " ", - al->samples[i].he.nr_samples); + al->data[i].he.nr_samples); } else { - obj__printf(obj, "%6.2f ", - al->samples[i].percent); + obj__printf(obj, "%6.2f ", percent); } } } else { @@ -2640,13 +2687,15 @@ print_addr: } void annotation_line__write(struct annotation_line *al, struct annotation *notes, - struct annotation_write_ops *ops) + struct annotation_write_ops *wops, + struct annotation_options *opts) { - __annotation_line__write(al, notes, ops->first_line, ops->current_entry, - ops->change_color, ops->width, ops->obj, - ops->set_color, ops->set_percent_color, - ops->set_jumps_percent_color, ops->printf, - ops->write_graph); + __annotation_line__write(al, notes, wops->first_line, wops->current_entry, + wops->change_color, wops->width, wops->obj, + opts->percent_type, + wops->set_color, wops->set_percent_color, + wops->set_jumps_percent_color, wops->printf, + wops->write_graph); } int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, @@ -2688,46 +2737,6 @@ out_free_offsets: return -1; } -int __annotation__scnprintf_samples_period(struct annotation *notes, - char *bf, size_t size, - struct perf_evsel *evsel, - bool show_freq) -{ - const char *ev_name = perf_evsel__name(evsel); - char buf[1024], ref[30] = " show reference callgraph, "; - char sample_freq_str[64] = ""; - unsigned long nr_samples = 0; - int nr_members = 1; - bool enable_ref = false; - u64 nr_events = 0; - char unit; - int i; - - if (perf_evsel__is_group_event(evsel)) { - perf_evsel__group_desc(evsel, buf, sizeof(buf)); - ev_name = buf; - nr_members = evsel->nr_members; - } - - for (i = 0; i < nr_members; i++) { - struct sym_hist *ah = annotation__histogram(notes, evsel->idx + i); - - nr_samples += ah->nr_samples; - nr_events += ah->period; - } - - if (symbol_conf.show_ref_callgraph && strstr(ev_name, "call-graph=no")) - enable_ref = true; - - if (show_freq) - scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); - - nr_samples = convert_unit(nr_samples, &unit); - return scnprintf(bf, size, "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, - nr_samples, unit, evsel->nr_members > 1 ? "s" : "", - ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); -} - #define ANNOTATION__CFG(n) \ { .name = #n, .value = &annotation__default_options.n, } @@ -2792,3 +2801,55 @@ void annotation_config__init(void) annotation__default_options.show_total_period = symbol_conf.show_total_period; annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples; } + +static unsigned int parse_percent_type(char *str1, char *str2) +{ + unsigned int type = (unsigned int) -1; + + if (!strcmp("period", str1)) { + if (!strcmp("local", str2)) + type = PERCENT_PERIOD_LOCAL; + else if (!strcmp("global", str2)) + type = PERCENT_PERIOD_GLOBAL; + } + + if (!strcmp("hits", str1)) { + if (!strcmp("local", str2)) + type = PERCENT_HITS_LOCAL; + else if (!strcmp("global", str2)) + type = PERCENT_HITS_GLOBAL; + } + + return type; +} + +int annotate_parse_percent_type(const struct option *opt, const char *_str, + int unset __maybe_unused) +{ + struct annotation_options *opts = opt->value; + unsigned int type; + char *str1, *str2; + int err = -1; + + str1 = strdup(_str); + if (!str1) + return -ENOMEM; + + str2 = strchr(str1, '-'); + if (!str2) + goto out; + + *str2++ = 0; + + type = parse_percent_type(str1, str2); + if (type == (unsigned int) -1) + type = parse_percent_type(str2, str1); + if (type != (unsigned int) -1) { + opts->percent_type = type; + err = 0; + } + +out: + free(str1); + return err; +} |