From cebf7d51a6c3babc4d0589da7aec0de1af0a5691 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Wed, 25 Sep 2019 09:14:46 +0800 Subject: perf diff: Report noisy for cycles diff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch prints the stddev and hist for the cycles diff of program block. It can help us to understand if the cycles is noisy or not. This patch is inspired by Andi Kleen's patch: https://lwn.net/Articles/600471/ We create new option '--cycles-hist'. Example: perf record -b ./div perf record -b ./div perf diff -c cycles # Baseline [Program Block Range] Cycles Diff Shared Object Symbol # ........ .......................................................... .... ................. ............................ # 46.72% [div.c:40 -> div.c:40] 0 div [.] main 46.72% [div.c:42 -> div.c:44] 0 div [.] main 46.72% [div.c:42 -> div.c:39] 0 div [.] main 20.54% [random_r.c:357 -> random_r.c:394] 1 libc-2.27.so [.] __random_r 20.54% [random_r.c:357 -> random_r.c:380] 0 libc-2.27.so [.] __random_r 20.54% [random_r.c:388 -> random_r.c:388] 0 libc-2.27.so [.] __random_r 20.54% [random_r.c:388 -> random_r.c:391] 0 libc-2.27.so [.] __random_r 17.04% [random.c:288 -> random.c:291] 0 libc-2.27.so [.] __random 17.04% [random.c:291 -> random.c:291] 0 libc-2.27.so [.] __random 17.04% [random.c:293 -> random.c:293] 0 libc-2.27.so [.] __random 17.04% [random.c:295 -> random.c:295] 0 libc-2.27.so [.] __random 17.04% [random.c:295 -> random.c:295] 0 libc-2.27.so [.] __random 17.04% [random.c:298 -> random.c:298] 0 libc-2.27.so [.] __random 8.40% [div.c:22 -> div.c:25] 0 div [.] compute_flag 8.40% [div.c:27 -> div.c:28] 0 div [.] compute_flag 5.14% [rand.c:26 -> rand.c:27] 0 libc-2.27.so [.] rand 5.14% [rand.c:28 -> rand.c:28] 0 libc-2.27.so [.] rand 2.15% [rand@plt+0 -> rand@plt+0] 0 div [.] rand@plt 0.00% [kernel.kallsyms] [k] __x86_indirect_thunk_rax 0.00% [do_mmap+714 -> do_mmap+732] -10 [kernel.kallsyms] [k] do_mmap 0.00% [do_mmap+737 -> do_mmap+765] 1 [kernel.kallsyms] [k] do_mmap 0.00% [do_mmap+262 -> do_mmap+299] 0 [kernel.kallsyms] [k] do_mmap 0.00% [__x86_indirect_thunk_r15+0 -> __x86_indirect_thunk_r15+0] 7 [kernel.kallsyms] [k] __x86_indirect_thunk_r15 0.00% [native_sched_clock+0 -> native_sched_clock+119] -1 [kernel.kallsyms] [k] native_sched_clock 0.00% [native_write_msr+0 -> native_write_msr+16] -13 [kernel.kallsyms] [k] native_write_msr When we enable the option '--cycles-hist', the output is perf diff -c cycles --cycles-hist # Baseline [Program Block Range] Cycles Diff stddev/Hist Shared Object Symbol # ........ .......................................................... .... ................. ................. ............................ # 46.72% [div.c:40 -> div.c:40] 0 ± 37.8% ▁█▁▁██▁█ div [.] main 46.72% [div.c:42 -> div.c:44] 0 ± 49.4% ▁▁▂█▂▂▂▂ div [.] main 46.72% [div.c:42 -> div.c:39] 0 ± 24.1% ▃█▂▄▁▃▂▁ div [.] main 20.54% [random_r.c:357 -> random_r.c:394] 1 ± 33.5% ▅▂▁█▃▁▂▁ libc-2.27.so [.] __random_r 20.54% [random_r.c:357 -> random_r.c:380] 0 ± 39.4% ▁▁█▁██▅▁ libc-2.27.so [.] __random_r 20.54% [random_r.c:388 -> random_r.c:388] 0 libc-2.27.so [.] __random_r 20.54% [random_r.c:388 -> random_r.c:391] 0 ± 41.2% ▁▃▁▂█▄▃▁ libc-2.27.so [.] __random_r 17.04% [random.c:288 -> random.c:291] 0 ± 48.8% ▁▁▁▁███▁ libc-2.27.so [.] __random 17.04% [random.c:291 -> random.c:291] 0 ±100.0% ▁█▁▁▁▁▁▁ libc-2.27.so [.] __random 17.04% [random.c:293 -> random.c:293] 0 ±100.0% ▁█▁▁▁▁▁▁ libc-2.27.so [.] __random 17.04% [random.c:295 -> random.c:295] 0 ±100.0% ▁█▁▁▁▁▁▁ libc-2.27.so [.] __random 17.04% [random.c:295 -> random.c:295] 0 libc-2.27.so [.] __random 17.04% [random.c:298 -> random.c:298] 0 ± 75.6% ▃█▁▁▁▁▁▁ libc-2.27.so [.] __random 8.40% [div.c:22 -> div.c:25] 0 ± 42.1% ▁▃▁▁███▁ div [.] compute_flag 8.40% [div.c:27 -> div.c:28] 0 ± 41.8% ██▁▁▄▁▁▄ div [.] compute_flag 5.14% [rand.c:26 -> rand.c:27] 0 ± 37.8% ▁▁▁████▁ libc-2.27.so [.] rand 5.14% [rand.c:28 -> rand.c:28] 0 libc-2.27.so [.] rand 2.15% [rand@plt+0 -> rand@plt+0] 0 div [.] rand@plt 0.00% [kernel.kallsyms] [k] __x86_indirect_thunk_rax 0.00% [do_mmap+714 -> do_mmap+732] -10 [kernel.kallsyms] [k] do_mmap 0.00% [do_mmap+737 -> do_mmap+765] 1 [kernel.kallsyms] [k] do_mmap 0.00% [do_mmap+262 -> do_mmap+299] 0 [kernel.kallsyms] [k] do_mmap 0.00% [__x86_indirect_thunk_r15+0 -> __x86_indirect_thunk_r15+0] 7 [kernel.kallsyms] [k] __x86_indirect_thunk_r15 0.00% [native_sched_clock+0 -> native_sched_clock+119] -1 ± 38.5% ▄█▁ [kernel.kallsyms] [k] native_sched_clock 0.00% [native_write_msr+0 -> native_write_msr+16] -13 ± 47.1% ▁█▇▃▁▁ [kernel.kallsyms] [k] native_write_msr v8: --- Rebase to perf/core branch v7: --- 1. v6 got Jiri's ACK. 2. Rebase to latest perf/core branch. v6: --- 1. Jiri provides better code for using data__hpp_register() in ui_init(). Use this code in v6. v5: --- 1. Refine the use of data__hpp_register() in ui_init() according to Jiri's suggestion. v4: --- 1. Rename the new option from '--noisy' to '--cycles-hist' 2. Remove the option '-n'. 3. Only update the spark value and stats when '--cycles-hist' is enabled. 4. Remove the code of printing '..'. v3: --- 1. Move the histogram to a separate column 2. Move the svals[] out of struct stats v2: --- Jiri got a compile error, CC builtin-diff.o builtin-diff.c: In function ‘compute_cycles_diff’: builtin-diff.c:712:10: error: taking the absolute value of unsigned type ‘u64’ {aka ‘long unsigned int’} has no effect [-Werror=absolute-value] 712 | labs(pair->block_info->cycles_spark[i] - | ^~~~ Because the result of u64 - u64 is still u64. Now we change the type of cycles_spark[] to s64. Signed-off-by: Jin Yao Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Kan Liang Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20190925011446.30678-1-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index c37a78677955..5281629c27b1 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -23,6 +23,7 @@ #include "util/time-utils.h" #include "util/annotate.h" #include "util/map.h" +#include "util/spark.h" #include #include #include @@ -53,6 +54,7 @@ enum { PERF_HPP_DIFF__FORMULA, PERF_HPP_DIFF__DELTA_ABS, PERF_HPP_DIFF__CYCLES, + PERF_HPP_DIFF__CYCLES_HIST, PERF_HPP_DIFF__MAX_INDEX }; @@ -87,6 +89,7 @@ static bool force; static bool show_period; static bool show_formula; static bool show_baseline_only; +static bool cycles_hist; static unsigned int sort_compute = 1; static s64 compute_wdiff_w1; @@ -164,6 +167,10 @@ static struct header_column { [PERF_HPP_DIFF__CYCLES] = { .name = "[Program Block Range] Cycles Diff", .width = 70, + }, + [PERF_HPP_DIFF__CYCLES_HIST] = { + .name = "stddev/Hist", + .width = NUM_SPARKS + 9, } }; @@ -610,6 +617,9 @@ static void init_block_info(struct block_info *bi, struct symbol *sym, bi->cycles_aggr = ch->cycles_aggr; bi->num = ch->num; bi->num_aggr = ch->num_aggr; + + memcpy(bi->cycles_spark, ch->cycles_spark, + NUM_SPARKS * sizeof(u64)); } static int process_block_per_sym(struct hist_entry *he) @@ -689,6 +699,21 @@ static struct hist_entry *get_block_pair(struct hist_entry *he, return NULL; } +static void init_spark_values(unsigned long *svals, int num) +{ + for (int i = 0; i < num; i++) + svals[i] = 0; +} + +static void update_spark_value(unsigned long *svals, int num, + struct stats *stats, u64 val) +{ + int n = stats->n; + + if (n < num) + svals[n] = val; +} + static void compute_cycles_diff(struct hist_entry *he, struct hist_entry *pair) { @@ -697,6 +722,26 @@ static void compute_cycles_diff(struct hist_entry *he, pair->diff.cycles = pair->block_info->cycles_aggr / pair->block_info->num_aggr - he->block_info->cycles_aggr / he->block_info->num_aggr; + + if (!cycles_hist) + return; + + init_stats(&pair->diff.stats); + init_spark_values(pair->diff.svals, NUM_SPARKS); + + for (int i = 0; i < pair->block_info->num; i++) { + u64 val; + + if (i >= he->block_info->num || i >= NUM_SPARKS) + break; + + val = labs(pair->block_info->cycles_spark[i] - + he->block_info->cycles_spark[i]); + + update_spark_value(pair->diff.svals, NUM_SPARKS, + &pair->diff.stats, val); + update_stats(&pair->diff.stats, val); + } } } @@ -1255,6 +1300,9 @@ static const struct option options[] = { "Show period values."), OPT_BOOLEAN('F', "formula", &show_formula, "Show formula."), + OPT_BOOLEAN(0, "cycles-hist", &cycles_hist, + "Show cycles histogram and standard deviation " + "- WARNING: use only with -c cycles."), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), @@ -1462,6 +1510,90 @@ static int hpp__color_cycles(struct perf_hpp_fmt *fmt, return __hpp__color_compare(fmt, hpp, he, COMPUTE_CYCLES); } +static int all_zero(unsigned long *vals, int len) +{ + int i; + + for (i = 0; i < len; i++) + if (vals[i] != 0) + return 0; + return 1; +} + +static int print_cycles_spark(char *bf, int size, unsigned long *svals, u64 n) +{ + int printed; + + if (n <= 1) + return 0; + + if (n > NUM_SPARKS) + n = NUM_SPARKS; + if (all_zero(svals, n)) + return 0; + + printed = print_spark(bf, size, svals, n); + printed += scnprintf(bf + printed, size - printed, " "); + return printed; +} + +static int hpp__color_cycles_hist(struct perf_hpp_fmt *fmt, + struct perf_hpp *hpp, struct hist_entry *he) +{ + struct diff_hpp_fmt *dfmt = + container_of(fmt, struct diff_hpp_fmt, fmt); + struct hist_entry *pair = get_pair_fmt(he, dfmt); + struct block_hist *bh = container_of(he, struct block_hist, he); + struct block_hist *bh_pair; + struct hist_entry *block_he; + char spark[32], buf[128]; + double r; + int ret, pad; + + if (!pair) { + if (bh->block_idx) + hpp->skip = true; + + goto no_print; + } + + bh_pair = container_of(pair, struct block_hist, he); + + block_he = hists__get_entry(&bh_pair->block_hists, bh->block_idx); + if (!block_he) { + hpp->skip = true; + goto no_print; + } + + ret = print_cycles_spark(spark, sizeof(spark), block_he->diff.svals, + block_he->diff.stats.n); + + r = rel_stddev_stats(stddev_stats(&block_he->diff.stats), + avg_stats(&block_he->diff.stats)); + + if (ret) { + /* + * Padding spaces if number of sparks less than NUM_SPARKS + * otherwise the output is not aligned. + */ + pad = NUM_SPARKS - ((ret - 1) / 3); + scnprintf(buf, sizeof(buf), "%s%5.1f%% %s", "\u00B1", r, spark); + ret = scnprintf(hpp->buf, hpp->size, "%*s", + dfmt->header_width, buf); + + if (pad) { + ret += scnprintf(hpp->buf + ret, hpp->size - ret, + "%-*s", pad, " "); + } + + return ret; + } + +no_print: + return scnprintf(hpp->buf, hpp->size, "%*s", + dfmt->header_width, " "); +} + static void hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size) { @@ -1667,6 +1799,10 @@ static void data__hpp_register(struct data__file *d, int idx) fmt->color = hpp__color_cycles; fmt->sort = hist_entry__cmp_nop; break; + case PERF_HPP_DIFF__CYCLES_HIST: + fmt->color = hpp__color_cycles_hist; + fmt->sort = hist_entry__cmp_nop; + break; default: fmt->sort = hist_entry__cmp_nop; break; @@ -1692,10 +1828,14 @@ static int ui_init(void) * PERF_HPP_DIFF__DELTA * PERF_HPP_DIFF__RATIO * PERF_HPP_DIFF__WEIGHTED_DIFF + * PERF_HPP_DIFF__CYCLES */ data__hpp_register(d, i ? compute_2_hpp[compute] : PERF_HPP_DIFF__BASELINE); + if (cycles_hist && i) + data__hpp_register(d, PERF_HPP_DIFF__CYCLES_HIST); + /* * And the rest: * @@ -1850,6 +1990,9 @@ int cmd_diff(int argc, const char **argv) if (quiet) perf_quiet_option(); + if (cycles_hist && (compute != COMPUTE_CYCLES)) + usage_with_options(diff_usage, options); + symbol__annotation_init(); if (symbol__init(NULL) < 0) -- cgit v1.2.3 From 0bdf181fe0e5b6f6d5764ff482d7ae4707f8986b Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 7 Nov 2019 15:47:13 +0800 Subject: perf diff: Don't use hack to skip column length calculation Previously we use a nasty hack to skip the hists__calc_col_len for block since this function is not very suitable for block column length calculation. This patch removes the hack code and add a check at the entry of hists__calc_col_len to skip for block case. Signed-off-by: Jin Yao Reviewed-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jin Yao Cc: Kan Liang Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20191107074719.26139-2-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 11 ++--------- tools/perf/util/hist.c | 2 ++ 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 5281629c27b1..faf99a81ad3e 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -765,13 +765,6 @@ static void block_hists_match(struct hists *hists_base, } } -static int filter_cb(struct hist_entry *he, void *arg __maybe_unused) -{ - /* Skip the calculation of column length in output_resort */ - he->filtered = true; - return 0; -} - static void hists__precompute(struct hists *hists) { struct rb_root_cached *root; @@ -820,8 +813,8 @@ static void hists__precompute(struct hists *hists) if (bh->valid && pair_bh->valid) { block_hists_match(&bh->block_hists, &pair_bh->block_hists); - hists__output_resort_cb(&pair_bh->block_hists, - NULL, filter_cb); + hists__output_resort(&pair_bh->block_hists, + NULL); } break; default: diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 679a1d75090c..daa6eef4fde0 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -80,6 +80,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) int symlen; u16 len; + if (h->block_info) + return; /* * +4 accounts for '[x] ' priv level info * +2 accounts for 0x prefix on raw addresses -- cgit v1.2.3 From 6041441870ab521a2652f1d558a770c586b790be Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 7 Nov 2019 15:47:14 +0800 Subject: perf block: Cleanup and refactor block info functions We have already implemented some block-info related functions. Now it's time to do some cleanup, refactoring and move the functions and structures to new block-info.h/block-info.c. v4: --- Move code for skipping column length calculation to patch: 'perf diff: Don't use hack to skip column length calculation' v3: --- 1. Rename the patch title 2. Rename from block.h/block.c to block-info.h/block-info.c 3. Move more common part to block-info, such as block_info__process_sym. 4. Remove the nasty hack for skipping calculation of column length Signed-off-by: Jin Yao Reviewed-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jin Yao Cc: Kan Liang Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20191107074719.26139-3-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 107 ++++------------------------------- tools/perf/util/Build | 1 + tools/perf/util/block-info.c | 129 +++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/block-info.h | 43 +++++++++++++++ tools/perf/util/hist.c | 1 + tools/perf/util/symbol.c | 22 -------- tools/perf/util/symbol.h | 24 -------- 7 files changed, 185 insertions(+), 142 deletions(-) create mode 100644 tools/perf/util/block-info.c create mode 100644 tools/perf/util/block-info.h (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index faf99a81ad3e..6728568fe5c4 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -24,6 +24,7 @@ #include "util/annotate.h" #include "util/map.h" #include "util/spark.h" +#include "util/block-info.h" #include #include #include @@ -98,8 +99,6 @@ static s64 compute_wdiff_w2; static const char *cpu_list; static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); -static struct addr_location dummy_al; - enum { COMPUTE_DELTA, COMPUTE_RATIO, @@ -537,41 +536,6 @@ static void hists__baseline_only(struct hists *hists) } } -static int64_t block_cmp(struct perf_hpp_fmt *fmt __maybe_unused, - struct hist_entry *left, struct hist_entry *right) -{ - struct block_info *bi_l = left->block_info; - struct block_info *bi_r = right->block_info; - int cmp; - - if (!bi_l->sym || !bi_r->sym) { - if (!bi_l->sym && !bi_r->sym) - return 0; - else if (!bi_l->sym) - return -1; - else - return 1; - } - - if (bi_l->sym == bi_r->sym) { - if (bi_l->start == bi_r->start) { - if (bi_l->end == bi_r->end) - return 0; - else - return (int64_t)(bi_r->end - bi_l->end); - } else - return (int64_t)(bi_r->start - bi_l->start); - } else { - cmp = strcmp(bi_l->sym->name, bi_r->sym->name); - return cmp; - } - - if (bi_l->sym->start != bi_r->sym->start) - return (int64_t)(bi_r->sym->start - bi_l->sym->start); - - return (int64_t)(bi_r->sym->end - bi_l->sym->end); -} - static int64_t block_cycles_diff_cmp(struct hist_entry *left, struct hist_entry *right) { @@ -600,67 +564,13 @@ static void init_block_hist(struct block_hist *bh) INIT_LIST_HEAD(&bh->block_fmt.list); INIT_LIST_HEAD(&bh->block_fmt.sort_list); - bh->block_fmt.cmp = block_cmp; + bh->block_fmt.cmp = block_info__cmp; bh->block_fmt.sort = block_sort; perf_hpp_list__register_sort_field(&bh->block_list, &bh->block_fmt); bh->valid = true; } -static void init_block_info(struct block_info *bi, struct symbol *sym, - struct cyc_hist *ch, int offset) -{ - bi->sym = sym; - bi->start = ch->start; - bi->end = offset; - bi->cycles = ch->cycles; - bi->cycles_aggr = ch->cycles_aggr; - bi->num = ch->num; - bi->num_aggr = ch->num_aggr; - - memcpy(bi->cycles_spark, ch->cycles_spark, - NUM_SPARKS * sizeof(u64)); -} - -static int process_block_per_sym(struct hist_entry *he) -{ - struct annotation *notes; - struct cyc_hist *ch; - struct block_hist *bh; - - if (!he->ms.map || !he->ms.sym) - return 0; - - notes = symbol__annotation(he->ms.sym); - if (!notes || !notes->src || !notes->src->cycles_hist) - return 0; - - bh = container_of(he, struct block_hist, he); - init_block_hist(bh); - - ch = notes->src->cycles_hist; - for (unsigned int i = 0; i < symbol__size(he->ms.sym); i++) { - if (ch[i].num_aggr) { - struct block_info *bi; - struct hist_entry *he_block; - - bi = block_info__new(); - if (!bi) - return -1; - - init_block_info(bi, he->ms.sym, &ch[i], i); - he_block = hists__add_entry_block(&bh->block_hists, - &dummy_al, bi); - if (!he_block) { - block_info__put(bi); - return -1; - } - } - } - - return 0; -} - static int block_pair_cmp(struct hist_entry *a, struct hist_entry *b) { struct block_info *bi_a = a->block_info; @@ -785,8 +695,11 @@ static void hists__precompute(struct hists *hists) he = rb_entry(next, struct hist_entry, rb_node_in); next = rb_next(&he->rb_node_in); - if (compute == COMPUTE_CYCLES) - process_block_per_sym(he); + if (compute == COMPUTE_CYCLES) { + bh = container_of(he, struct block_hist, he); + init_block_hist(bh); + block_info__process_sym(he, bh, NULL, 0); + } data__for_each_file_new(i, d) { pair = get_pair_data(he, d); @@ -805,10 +718,12 @@ static void hists__precompute(struct hists *hists) compute_wdiff(he, pair); break; case COMPUTE_CYCLES: - process_block_per_sym(pair); - bh = container_of(he, struct block_hist, he); pair_bh = container_of(pair, struct block_hist, he); + init_block_hist(pair_bh); + block_info__process_sym(pair, pair_bh, NULL, 0); + + bh = container_of(he, struct block_hist, he); if (bh->valid && pair_bh->valid) { block_hists_match(&bh->block_hists, diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 39814b1806a6..b8e05a147b2b 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -1,4 +1,5 @@ perf-y += annotate.o +perf-y += block-info.o perf-y += block-range.o perf-y += build-id.o perf-y += cacheline.o diff --git a/tools/perf/util/block-info.c b/tools/perf/util/block-info.c new file mode 100644 index 000000000000..b9954a32b8f4 --- /dev/null +++ b/tools/perf/util/block-info.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include "block-info.h" +#include "sort.h" +#include "annotate.h" +#include "symbol.h" + +struct block_info *block_info__get(struct block_info *bi) +{ + if (bi) + refcount_inc(&bi->refcnt); + return bi; +} + +void block_info__put(struct block_info *bi) +{ + if (bi && refcount_dec_and_test(&bi->refcnt)) + free(bi); +} + +struct block_info *block_info__new(void) +{ + struct block_info *bi = zalloc(sizeof(*bi)); + + if (bi) + refcount_set(&bi->refcnt, 1); + return bi; +} + +int64_t block_info__cmp(struct perf_hpp_fmt *fmt __maybe_unused, + struct hist_entry *left, struct hist_entry *right) +{ + struct block_info *bi_l = left->block_info; + struct block_info *bi_r = right->block_info; + int cmp; + + if (!bi_l->sym || !bi_r->sym) { + if (!bi_l->sym && !bi_r->sym) + return 0; + else if (!bi_l->sym) + return -1; + else + return 1; + } + + if (bi_l->sym == bi_r->sym) { + if (bi_l->start == bi_r->start) { + if (bi_l->end == bi_r->end) + return 0; + else + return (int64_t)(bi_r->end - bi_l->end); + } else + return (int64_t)(bi_r->start - bi_l->start); + } else { + cmp = strcmp(bi_l->sym->name, bi_r->sym->name); + return cmp; + } + + if (bi_l->sym->start != bi_r->sym->start) + return (int64_t)(bi_r->sym->start - bi_l->sym->start); + + return (int64_t)(bi_r->sym->end - bi_l->sym->end); +} + +static void init_block_info(struct block_info *bi, struct symbol *sym, + struct cyc_hist *ch, int offset, + u64 total_cycles) +{ + bi->sym = sym; + bi->start = ch->start; + bi->end = offset; + bi->cycles = ch->cycles; + bi->cycles_aggr = ch->cycles_aggr; + bi->num = ch->num; + bi->num_aggr = ch->num_aggr; + bi->total_cycles = total_cycles; + + memcpy(bi->cycles_spark, ch->cycles_spark, + NUM_SPARKS * sizeof(u64)); +} + +int block_info__process_sym(struct hist_entry *he, struct block_hist *bh, + u64 *block_cycles_aggr, u64 total_cycles) +{ + struct annotation *notes; + struct cyc_hist *ch; + static struct addr_location al; + u64 cycles = 0; + + if (!he->ms.map || !he->ms.sym) + return 0; + + memset(&al, 0, sizeof(al)); + al.map = he->ms.map; + al.sym = he->ms.sym; + + notes = symbol__annotation(he->ms.sym); + if (!notes || !notes->src || !notes->src->cycles_hist) + return 0; + ch = notes->src->cycles_hist; + for (unsigned int i = 0; i < symbol__size(he->ms.sym); i++) { + if (ch[i].num_aggr) { + struct block_info *bi; + struct hist_entry *he_block; + + bi = block_info__new(); + if (!bi) + return -1; + + init_block_info(bi, he->ms.sym, &ch[i], i, + total_cycles); + cycles += bi->cycles_aggr / bi->num_aggr; + + he_block = hists__add_entry_block(&bh->block_hists, + &al, bi); + if (!he_block) { + block_info__put(bi); + return -1; + } + } + } + + if (block_cycles_aggr) + *block_cycles_aggr += cycles; + + return 0; +} diff --git a/tools/perf/util/block-info.h b/tools/perf/util/block-info.h new file mode 100644 index 000000000000..d55dfc2fda6f --- /dev/null +++ b/tools/perf/util/block-info.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_BLOCK_H +#define __PERF_BLOCK_H + +#include +#include +#include "util/hist.h" +#include "util/symbol.h" + +struct block_info { + struct symbol *sym; + u64 start; + u64 end; + u64 cycles; + u64 cycles_aggr; + s64 cycles_spark[NUM_SPARKS]; + u64 total_cycles; + int num; + int num_aggr; + refcount_t refcnt; +}; + +struct block_hist; + +struct block_info *block_info__new(void); +struct block_info *block_info__get(struct block_info *bi); +void block_info__put(struct block_info *bi); + +static inline void __block_info__zput(struct block_info **bi) +{ + block_info__put(*bi); + *bi = NULL; +} + +#define block_info__zput(bi) __block_info__zput(&bi) + +int64_t block_info__cmp(struct perf_hpp_fmt *fmt __maybe_unused, + struct hist_entry *left, struct hist_entry *right); + +int block_info__process_sym(struct hist_entry *he, struct block_hist *bh, + u64 *block_cycles_aggr, u64 total_cycles); + +#endif /* __PERF_BLOCK_H */ diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index daa6eef4fde0..a7fa061987e4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -18,6 +18,7 @@ #include "srcline.h" #include "symbol.h" #include "thread.h" +#include "block-info.h" #include "ui/progress.h" #include #include diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 4ad39cc6368d..2764863212b1 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -2351,25 +2351,3 @@ struct mem_info *mem_info__new(void) refcount_set(&mi->refcnt, 1); return mi; } - -struct block_info *block_info__get(struct block_info *bi) -{ - if (bi) - refcount_inc(&bi->refcnt); - return bi; -} - -void block_info__put(struct block_info *bi) -{ - if (bi && refcount_dec_and_test(&bi->refcnt)) - free(bi); -} - -struct block_info *block_info__new(void) -{ - struct block_info *bi = zalloc(sizeof(*bi)); - - if (bi) - refcount_set(&bi->refcnt, 1); - return bi; -} diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index cc2a89b99d3d..c3bd16d75d5d 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -106,18 +106,6 @@ struct ref_reloc_sym { u64 unrelocated_addr; }; -struct block_info { - struct symbol *sym; - u64 start; - u64 end; - u64 cycles; - u64 cycles_aggr; - s64 cycles_spark[NUM_SPARKS]; - int num; - int num_aggr; - refcount_t refcnt; -}; - struct addr_location { struct machine *machine; struct thread *thread; @@ -291,16 +279,4 @@ static inline void __mem_info__zput(struct mem_info **mi) #define mem_info__zput(mi) __mem_info__zput(&mi) -struct block_info *block_info__new(void); -struct block_info *block_info__get(struct block_info *bi); -void block_info__put(struct block_info *bi); - -static inline void __block_info__zput(struct block_info **bi) -{ - block_info__put(*bi); - *bi = NULL; -} - -#define block_info__zput(bi) __block_info__zput(&bi) - #endif /* __PERF_SYMBOL */ -- cgit v1.2.3 From 7841f40aed933dd3838f8d9f2dfcf286c352b7ee Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 7 Nov 2019 15:47:15 +0800 Subject: perf hist: Count the total cycles of all samples We can get the per sample cycles by hist__account_cycles(). It's also useful to know the total cycles of all samples in order to get the cycles coverage for a single program block in further. For example: coverage = per block sampled cycles / total sampled cycles This patch creates a new argument 'total_cycles' in hist__account_cycles(), which will be added with the cycles of each sample. Signed-off-by: Jin Yao Reviewed-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jin Yao Cc: Kan Liang Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20191107074719.26139-4-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-diff.c | 3 ++- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-top.c | 3 ++- tools/perf/util/hist.c | 6 +++++- tools/perf/util/hist.h | 3 ++- 6 files changed, 13 insertions(+), 6 deletions(-) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 8db8fc9bddef..6ab0cc45b287 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -201,7 +201,7 @@ static int process_branch_callback(struct evsel *evsel, if (a.map != NULL) a.map->dso->hit = 1; - hist__account_cycles(sample->branch_stack, al, sample, false); + hist__account_cycles(sample->branch_stack, al, sample, false, NULL); ret = hist_entry_iter__add(&iter, &a, PERF_MAX_STACK_DEPTH, ann); return ret; diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 6728568fe5c4..376dbf10ad64 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -426,7 +426,8 @@ static int diff__process_sample_event(struct perf_tool *tool, goto out_put; } - hist__account_cycles(sample->branch_stack, &al, sample, false); + hist__account_cycles(sample->branch_stack, &al, sample, false, + NULL); } /* diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 3bbad039abf2..bc15b9dcccd6 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -292,7 +292,7 @@ static int process_sample_event(struct perf_tool *tool, if (ui__has_annotation() || rep->symbol_ipc) { hist__account_cycles(sample->branch_stack, &al, sample, - rep->nonany_branch_mode); + rep->nonany_branch_mode, NULL); } ret = hist_entry_iter__add(&iter, &al, rep->max_stack, rep); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index d96f24c8770d..14c52e4d47f6 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -725,7 +725,8 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter, perf_top__record_precise_ip(top, he, iter->sample, evsel, al->addr); hist__account_cycles(iter->sample->branch_stack, al, iter->sample, - !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY)); + !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY), + NULL); return 0; } diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index a7fa061987e4..0e27d6830011 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -2572,7 +2572,8 @@ int hists__unlink(struct hists *hists) } void hist__account_cycles(struct branch_stack *bs, struct addr_location *al, - struct perf_sample *sample, bool nonany_branch_mode) + struct perf_sample *sample, bool nonany_branch_mode, + u64 *total_cycles) { struct branch_info *bi; @@ -2599,6 +2600,9 @@ void hist__account_cycles(struct branch_stack *bs, struct addr_location *al, nonany_branch_mode ? NULL : prev, bi[i].flags.cycles); prev = &bi[i].to; + + if (total_cycles) + *total_cycles += bi[i].flags.cycles; } free(bi); } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 6a186b668303..4d87c7b4c1b2 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -527,7 +527,8 @@ unsigned int hists__sort_list_width(struct hists *hists); unsigned int hists__overhead_width(struct hists *hists); void hist__account_cycles(struct branch_stack *bs, struct addr_location *al, - struct perf_sample *sample, bool nonany_branch_mode); + struct perf_sample *sample, bool nonany_branch_mode, + u64 *total_cycles); struct option; int parse_filter_percentage(const struct option *opt, const char *arg, int unset); -- cgit v1.2.3 From 98e93245113d0f5c279ef77f4a9e7d097323ad71 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 27 Nov 2019 09:58:22 -0300 Subject: perf diff: Use llabs() with 64-bit values To fix these build errors on a debian mipsel cross build environment: builtin-diff.c: In function 'block_cycles_diff_cmp': builtin-diff.c:550:6: error: absolute value function 'labs' given an argument of type 's64' {aka 'long long int'} but has parameter of type 'long int' which may cause truncation of value [-Werror=absolute-value] 550 | l = labs(left->diff.cycles); | ^~~~ builtin-diff.c:551:6: error: absolute value function 'labs' given an argument of type 's64' {aka 'long long int'} but has parameter of type 'long int' which may cause truncation of value [-Werror=absolute-value] 551 | r = labs(right->diff.cycles); | ^~~~ Fixes: 99150a1faab2 ("perf diff: Use hists to manage basic blocks per symbol") Cc: Jin Yao Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lkml.kernel.org/n/tip-pn7szy5uw384ntjgk6zckh6a@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 376dbf10ad64..eae879376283 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -547,8 +547,8 @@ static int64_t block_cycles_diff_cmp(struct hist_entry *left, if (!pairs_left && !pairs_right) return 0; - l = labs(left->diff.cycles); - r = labs(right->diff.cycles); + l = llabs(left->diff.cycles); + r = llabs(right->diff.cycles); return r - l; } -- cgit v1.2.3 From 2b1ac6403f8800babed0f16ab1d29ee3300be122 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 27 Nov 2019 09:58:22 -0300 Subject: perf diff: Use llabs() with 64-bit values To fix this build error on a debian mipsel cross build environment: builtin-diff.c: In function 'compute_cycles_diff': builtin-diff.c:649:10: error: absolute value function 'labs' given an argument of type 's64' {aka 'long long int'} but has parameter of type 'long int' which may cause truncation of value [-Werror=absolute-value] 649 | val = labs(pair->block_info->cycles_spark[i] - | ^~~~ Fixes: cebf7d51a6c3 ("perf diff: Report noisy for cycles diff") Cc: Jin Yao Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lkml.kernel.org/n/tip-pn7szy5uw384ntjgk6zckh6a@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index eae879376283..f8b6ae557d8b 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -646,7 +646,7 @@ static void compute_cycles_diff(struct hist_entry *he, if (i >= he->block_info->num || i >= NUM_SPARKS) break; - val = labs(pair->block_info->cycles_spark[i] - + val = llabs(pair->block_info->cycles_spark[i] - he->block_info->cycles_spark[i]); update_spark_value(pair->diff.svals, NUM_SPARKS, -- cgit v1.2.3