1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
286a9eee0SArnaldo Carvalho de Melo /*
386a9eee0SArnaldo Carvalho de Melo * builtin-diff.c
486a9eee0SArnaldo Carvalho de Melo *
586a9eee0SArnaldo Carvalho de Melo * Builtin diff command: Analyze two perf.data input files, look up and read
686a9eee0SArnaldo Carvalho de Melo * DSOs and symbol information, sort them and produce a diff.
786a9eee0SArnaldo Carvalho de Melo */
886a9eee0SArnaldo Carvalho de Melo #include "builtin.h"
902b5ed8aSIan Rogers #include "perf.h"
1086a9eee0SArnaldo Carvalho de Melo
1186a9eee0SArnaldo Carvalho de Melo #include "util/debug.h"
1286a9eee0SArnaldo Carvalho de Melo #include "util/event.h"
1386a9eee0SArnaldo Carvalho de Melo #include "util/hist.h"
14743eb868SArnaldo Carvalho de Melo #include "util/evsel.h"
15863e451fSJiri Olsa #include "util/evlist.h"
1686a9eee0SArnaldo Carvalho de Melo #include "util/session.h"
1745694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
1886a9eee0SArnaldo Carvalho de Melo #include "util/sort.h"
1997b9d866SArnaldo Carvalho de Melo #include "util/srcline.h"
2086a9eee0SArnaldo Carvalho de Melo #include "util/symbol.h"
21f5fc1412SJiri Olsa #include "util/data.h"
22d49dd15dSNamhyung Kim #include "util/config.h"
234802138dSJin Yao #include "util/time-utils.h"
2499150a1fSJin Yao #include "util/annotate.h"
25b10c78c5SJin Yao #include "util/map.h"
26cebf7d51SJin Yao #include "util/spark.h"
2760414418SJin Yao #include "util/block-info.h"
282a09a84cSJin Yao #include "util/stream.h"
29ea0c5239SIan Rogers #include "util/util.h"
306ef81c55SMamatha Inamdar #include <linux/err.h>
317f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
328520a98dSArnaldo Carvalho de Melo #include <subcmd/pager.h>
3397b9d866SArnaldo Carvalho de Melo #include <subcmd/parse-options.h>
3486a9eee0SArnaldo Carvalho de Melo
35a43783aeSArnaldo Carvalho de Melo #include <errno.h>
36fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
3786a9eee0SArnaldo Carvalho de Melo #include <stdlib.h>
38345dc0b4SJiri Olsa #include <math.h>
39345dc0b4SJiri Olsa
404802138dSJin Yao struct perf_diff {
414802138dSJin Yao struct perf_tool tool;
424802138dSJin Yao const char *time_str;
434802138dSJin Yao struct perf_time_interval *ptime_range;
444802138dSJin Yao int range_size;
454802138dSJin Yao int range_num;
4630d81553SJin Yao bool has_br_stack;
472a09a84cSJin Yao bool stream;
484802138dSJin Yao };
494802138dSJin Yao
50345dc0b4SJiri Olsa /* Diff command specific HPP columns. */
51345dc0b4SJiri Olsa enum {
52345dc0b4SJiri Olsa PERF_HPP_DIFF__BASELINE,
53345dc0b4SJiri Olsa PERF_HPP_DIFF__PERIOD,
54345dc0b4SJiri Olsa PERF_HPP_DIFF__PERIOD_BASELINE,
55345dc0b4SJiri Olsa PERF_HPP_DIFF__DELTA,
56345dc0b4SJiri Olsa PERF_HPP_DIFF__RATIO,
57345dc0b4SJiri Olsa PERF_HPP_DIFF__WEIGHTED_DIFF,
58345dc0b4SJiri Olsa PERF_HPP_DIFF__FORMULA,
59a1668c25SNamhyung Kim PERF_HPP_DIFF__DELTA_ABS,
60b10c78c5SJin Yao PERF_HPP_DIFF__CYCLES,
61cebf7d51SJin Yao PERF_HPP_DIFF__CYCLES_HIST,
62345dc0b4SJiri Olsa
63345dc0b4SJiri Olsa PERF_HPP_DIFF__MAX_INDEX
64345dc0b4SJiri Olsa };
65345dc0b4SJiri Olsa
66345dc0b4SJiri Olsa struct diff_hpp_fmt {
67345dc0b4SJiri Olsa struct perf_hpp_fmt fmt;
68345dc0b4SJiri Olsa int idx;
69345dc0b4SJiri Olsa char *header;
70345dc0b4SJiri Olsa int header_width;
71345dc0b4SJiri Olsa };
7286a9eee0SArnaldo Carvalho de Melo
73ec308426SJiri Olsa struct data__file {
74ec308426SJiri Olsa struct perf_session *session;
758ceb41d7SJiri Olsa struct perf_data data;
76ec308426SJiri Olsa int idx;
7722aeb7f5SJiri Olsa struct hists *hists;
782a09a84cSJin Yao struct evlist_streams *evlist_streams;
79c818b498SJiri Olsa struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
80ec308426SJiri Olsa };
81ec308426SJiri Olsa
82ec308426SJiri Olsa static struct data__file *data__files;
83ec308426SJiri Olsa static int data__files_cnt;
84ec308426SJiri Olsa
85ec308426SJiri Olsa #define data__for_each_file_start(i, d, s) \
86ec308426SJiri Olsa for (i = s, d = &data__files[s]; \
87ec308426SJiri Olsa i < data__files_cnt; \
88ec308426SJiri Olsa i++, d = &data__files[i])
89ec308426SJiri Olsa
90ec308426SJiri Olsa #define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
9122aeb7f5SJiri Olsa #define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
92ec308426SJiri Olsa
93c0555642SIan Munsie static bool force;
9461949b21SJiri Olsa static bool show_period;
95ed279da2SJiri Olsa static bool show_formula;
96a06d143eSJiri Olsa static bool show_baseline_only;
97cebf7d51SJin Yao static bool cycles_hist;
98be57b3fdSNamhyung Kim static unsigned int sort_compute = 1;
9986a9eee0SArnaldo Carvalho de Melo
10081d5f958SJiri Olsa static s64 compute_wdiff_w1;
10181d5f958SJiri Olsa static s64 compute_wdiff_w2;
10281d5f958SJiri Olsa
103daca23b2SJin Yao static const char *cpu_list;
104daca23b2SJin Yao static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
105daca23b2SJin Yao
1067aaf6b35SJiri Olsa enum {
1077aaf6b35SJiri Olsa COMPUTE_DELTA,
1087aaf6b35SJiri Olsa COMPUTE_RATIO,
10981d5f958SJiri Olsa COMPUTE_WEIGHTED_DIFF,
110a1668c25SNamhyung Kim COMPUTE_DELTA_ABS,
11199150a1fSJin Yao COMPUTE_CYCLES,
1127aaf6b35SJiri Olsa COMPUTE_MAX,
1132a09a84cSJin Yao COMPUTE_STREAM, /* After COMPUTE_MAX to avoid use current compute arrays */
1147aaf6b35SJiri Olsa };
1157aaf6b35SJiri Olsa
1167aaf6b35SJiri Olsa const char *compute_names[COMPUTE_MAX] = {
1177aaf6b35SJiri Olsa [COMPUTE_DELTA] = "delta",
118a1668c25SNamhyung Kim [COMPUTE_DELTA_ABS] = "delta-abs",
1197aaf6b35SJiri Olsa [COMPUTE_RATIO] = "ratio",
12081d5f958SJiri Olsa [COMPUTE_WEIGHTED_DIFF] = "wdiff",
12199150a1fSJin Yao [COMPUTE_CYCLES] = "cycles",
1227aaf6b35SJiri Olsa };
1237aaf6b35SJiri Olsa
124be57b3fdSNamhyung Kim static int compute = COMPUTE_DELTA_ABS;
1257aaf6b35SJiri Olsa
126345dc0b4SJiri Olsa static int compute_2_hpp[COMPUTE_MAX] = {
127345dc0b4SJiri Olsa [COMPUTE_DELTA] = PERF_HPP_DIFF__DELTA,
128a1668c25SNamhyung Kim [COMPUTE_DELTA_ABS] = PERF_HPP_DIFF__DELTA_ABS,
129345dc0b4SJiri Olsa [COMPUTE_RATIO] = PERF_HPP_DIFF__RATIO,
130345dc0b4SJiri Olsa [COMPUTE_WEIGHTED_DIFF] = PERF_HPP_DIFF__WEIGHTED_DIFF,
131b10c78c5SJin Yao [COMPUTE_CYCLES] = PERF_HPP_DIFF__CYCLES,
132345dc0b4SJiri Olsa };
133345dc0b4SJiri Olsa
134345dc0b4SJiri Olsa #define MAX_COL_WIDTH 70
135345dc0b4SJiri Olsa
136345dc0b4SJiri Olsa static struct header_column {
137345dc0b4SJiri Olsa const char *name;
138345dc0b4SJiri Olsa int width;
139345dc0b4SJiri Olsa } columns[PERF_HPP_DIFF__MAX_INDEX] = {
140345dc0b4SJiri Olsa [PERF_HPP_DIFF__BASELINE] = {
141345dc0b4SJiri Olsa .name = "Baseline",
142345dc0b4SJiri Olsa },
143345dc0b4SJiri Olsa [PERF_HPP_DIFF__PERIOD] = {
144345dc0b4SJiri Olsa .name = "Period",
145345dc0b4SJiri Olsa .width = 14,
146345dc0b4SJiri Olsa },
147345dc0b4SJiri Olsa [PERF_HPP_DIFF__PERIOD_BASELINE] = {
148345dc0b4SJiri Olsa .name = "Base period",
149345dc0b4SJiri Olsa .width = 14,
150345dc0b4SJiri Olsa },
151345dc0b4SJiri Olsa [PERF_HPP_DIFF__DELTA] = {
152345dc0b4SJiri Olsa .name = "Delta",
153345dc0b4SJiri Olsa .width = 7,
154345dc0b4SJiri Olsa },
155a1668c25SNamhyung Kim [PERF_HPP_DIFF__DELTA_ABS] = {
156a1668c25SNamhyung Kim .name = "Delta Abs",
157a1668c25SNamhyung Kim .width = 7,
158a1668c25SNamhyung Kim },
159345dc0b4SJiri Olsa [PERF_HPP_DIFF__RATIO] = {
160345dc0b4SJiri Olsa .name = "Ratio",
161345dc0b4SJiri Olsa .width = 14,
162345dc0b4SJiri Olsa },
163345dc0b4SJiri Olsa [PERF_HPP_DIFF__WEIGHTED_DIFF] = {
164345dc0b4SJiri Olsa .name = "Weighted diff",
165345dc0b4SJiri Olsa .width = 14,
166345dc0b4SJiri Olsa },
167345dc0b4SJiri Olsa [PERF_HPP_DIFF__FORMULA] = {
168345dc0b4SJiri Olsa .name = "Formula",
169345dc0b4SJiri Olsa .width = MAX_COL_WIDTH,
170b10c78c5SJin Yao },
171b10c78c5SJin Yao [PERF_HPP_DIFF__CYCLES] = {
172b10c78c5SJin Yao .name = "[Program Block Range] Cycles Diff",
173b10c78c5SJin Yao .width = 70,
174cebf7d51SJin Yao },
175cebf7d51SJin Yao [PERF_HPP_DIFF__CYCLES_HIST] = {
176cebf7d51SJin Yao .name = "stddev/Hist",
177cebf7d51SJin Yao .width = NUM_SPARKS + 9,
178345dc0b4SJiri Olsa }
179345dc0b4SJiri Olsa };
180345dc0b4SJiri Olsa
setup_compute_opt_wdiff(char * opt)18181d5f958SJiri Olsa static int setup_compute_opt_wdiff(char *opt)
18281d5f958SJiri Olsa {
18381d5f958SJiri Olsa char *w1_str = opt;
18481d5f958SJiri Olsa char *w2_str;
18581d5f958SJiri Olsa
18681d5f958SJiri Olsa int ret = -EINVAL;
18781d5f958SJiri Olsa
18881d5f958SJiri Olsa if (!opt)
18981d5f958SJiri Olsa goto out;
19081d5f958SJiri Olsa
19181d5f958SJiri Olsa w2_str = strchr(opt, ',');
19281d5f958SJiri Olsa if (!w2_str)
19381d5f958SJiri Olsa goto out;
19481d5f958SJiri Olsa
19581d5f958SJiri Olsa *w2_str++ = 0x0;
19681d5f958SJiri Olsa if (!*w2_str)
19781d5f958SJiri Olsa goto out;
19881d5f958SJiri Olsa
19981d5f958SJiri Olsa compute_wdiff_w1 = strtol(w1_str, NULL, 10);
20081d5f958SJiri Olsa compute_wdiff_w2 = strtol(w2_str, NULL, 10);
20181d5f958SJiri Olsa
20281d5f958SJiri Olsa if (!compute_wdiff_w1 || !compute_wdiff_w2)
20381d5f958SJiri Olsa goto out;
20481d5f958SJiri Olsa
20581d5f958SJiri Olsa pr_debug("compute wdiff w1(%" PRId64 ") w2(%" PRId64 ")\n",
20681d5f958SJiri Olsa compute_wdiff_w1, compute_wdiff_w2);
20781d5f958SJiri Olsa
20881d5f958SJiri Olsa ret = 0;
20981d5f958SJiri Olsa
21081d5f958SJiri Olsa out:
21181d5f958SJiri Olsa if (ret)
21281d5f958SJiri Olsa pr_err("Failed: wrong weight data, use 'wdiff:w1,w2'\n");
21381d5f958SJiri Olsa
21481d5f958SJiri Olsa return ret;
21581d5f958SJiri Olsa }
21681d5f958SJiri Olsa
setup_compute_opt(char * opt)21781d5f958SJiri Olsa static int setup_compute_opt(char *opt)
21881d5f958SJiri Olsa {
21981d5f958SJiri Olsa if (compute == COMPUTE_WEIGHTED_DIFF)
22081d5f958SJiri Olsa return setup_compute_opt_wdiff(opt);
22181d5f958SJiri Olsa
22281d5f958SJiri Olsa if (opt) {
22381d5f958SJiri Olsa pr_err("Failed: extra option specified '%s'", opt);
22481d5f958SJiri Olsa return -EINVAL;
22581d5f958SJiri Olsa }
22681d5f958SJiri Olsa
22781d5f958SJiri Olsa return 0;
22881d5f958SJiri Olsa }
22981d5f958SJiri Olsa
setup_compute(const struct option * opt,const char * str,int unset __maybe_unused)2307aaf6b35SJiri Olsa static int setup_compute(const struct option *opt, const char *str,
2317aaf6b35SJiri Olsa int unset __maybe_unused)
2327aaf6b35SJiri Olsa {
2337aaf6b35SJiri Olsa int *cp = (int *) opt->value;
23481d5f958SJiri Olsa char *cstr = (char *) str;
23581d5f958SJiri Olsa char buf[50];
2367aaf6b35SJiri Olsa unsigned i;
23781d5f958SJiri Olsa char *option;
2387aaf6b35SJiri Olsa
2397aaf6b35SJiri Olsa if (!str) {
2407aaf6b35SJiri Olsa *cp = COMPUTE_DELTA;
2417aaf6b35SJiri Olsa return 0;
2427aaf6b35SJiri Olsa }
2437aaf6b35SJiri Olsa
24481d5f958SJiri Olsa option = strchr(str, ':');
24581d5f958SJiri Olsa if (option) {
24681d5f958SJiri Olsa unsigned len = option++ - str;
24781d5f958SJiri Olsa
24881d5f958SJiri Olsa /*
24981d5f958SJiri Olsa * The str data are not writeable, so we need
25081d5f958SJiri Olsa * to use another buffer.
25181d5f958SJiri Olsa */
25281d5f958SJiri Olsa
25381d5f958SJiri Olsa /* No option value is longer. */
25481d5f958SJiri Olsa if (len >= sizeof(buf))
25581d5f958SJiri Olsa return -EINVAL;
25681d5f958SJiri Olsa
25781d5f958SJiri Olsa strncpy(buf, str, len);
25881d5f958SJiri Olsa buf[len] = 0x0;
25981d5f958SJiri Olsa cstr = buf;
26081d5f958SJiri Olsa }
26181d5f958SJiri Olsa
2627aaf6b35SJiri Olsa for (i = 0; i < COMPUTE_MAX; i++)
26381d5f958SJiri Olsa if (!strcmp(cstr, compute_names[i])) {
2647aaf6b35SJiri Olsa *cp = i;
26581d5f958SJiri Olsa return setup_compute_opt(option);
2667aaf6b35SJiri Olsa }
2677aaf6b35SJiri Olsa
2687aaf6b35SJiri Olsa pr_err("Failed: '%s' is not computation method "
26981d5f958SJiri Olsa "(use 'delta','ratio' or 'wdiff')\n", str);
2707aaf6b35SJiri Olsa return -EINVAL;
2717aaf6b35SJiri Olsa }
2727aaf6b35SJiri Olsa
period_percent(struct hist_entry * he,u64 period)273ef358e6dSJiri Olsa static double period_percent(struct hist_entry *he, u64 period)
27496c47f19SJiri Olsa {
2758810f6ceSNamhyung Kim u64 total = hists__total_period(he->hists);
2768810f6ceSNamhyung Kim
27796c47f19SJiri Olsa return (period * 100.0) / total;
27896c47f19SJiri Olsa }
27996c47f19SJiri Olsa
compute_delta(struct hist_entry * he,struct hist_entry * pair)280ef358e6dSJiri Olsa static double compute_delta(struct hist_entry *he, struct hist_entry *pair)
28196c47f19SJiri Olsa {
282ef358e6dSJiri Olsa double old_percent = period_percent(he, he->stat.period);
283ef358e6dSJiri Olsa double new_percent = period_percent(pair, pair->stat.period);
28496c47f19SJiri Olsa
2859af303e2SJiri Olsa pair->diff.period_ratio_delta = new_percent - old_percent;
2869af303e2SJiri Olsa pair->diff.computed = true;
2879af303e2SJiri Olsa return pair->diff.period_ratio_delta;
28896c47f19SJiri Olsa }
28996c47f19SJiri Olsa
compute_ratio(struct hist_entry * he,struct hist_entry * pair)290ef358e6dSJiri Olsa static double compute_ratio(struct hist_entry *he, struct hist_entry *pair)
29196c47f19SJiri Olsa {
2929af303e2SJiri Olsa double old_period = he->stat.period ?: 1;
2939af303e2SJiri Olsa double new_period = pair->stat.period;
29496c47f19SJiri Olsa
2959af303e2SJiri Olsa pair->diff.computed = true;
2969af303e2SJiri Olsa pair->diff.period_ratio = new_period / old_period;
2979af303e2SJiri Olsa return pair->diff.period_ratio;
29896c47f19SJiri Olsa }
29996c47f19SJiri Olsa
compute_wdiff(struct hist_entry * he,struct hist_entry * pair)300ef358e6dSJiri Olsa static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
30181d5f958SJiri Olsa {
3029af303e2SJiri Olsa u64 old_period = he->stat.period;
3039af303e2SJiri Olsa u64 new_period = pair->stat.period;
30481d5f958SJiri Olsa
3059af303e2SJiri Olsa pair->diff.computed = true;
3069af303e2SJiri Olsa pair->diff.wdiff = new_period * compute_wdiff_w2 -
30781d5f958SJiri Olsa old_period * compute_wdiff_w1;
30881d5f958SJiri Olsa
3099af303e2SJiri Olsa return pair->diff.wdiff;
31081d5f958SJiri Olsa }
31181d5f958SJiri Olsa
formula_delta(struct hist_entry * he,struct hist_entry * pair,char * buf,size_t size)312f4c8bae1SJiri Olsa static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
313f4c8bae1SJiri Olsa char *buf, size_t size)
314ed279da2SJiri Olsa {
3158810f6ceSNamhyung Kim u64 he_total = he->hists->stats.total_period;
3168810f6ceSNamhyung Kim u64 pair_total = pair->hists->stats.total_period;
3178810f6ceSNamhyung Kim
3188810f6ceSNamhyung Kim if (symbol_conf.filter_relative) {
3198810f6ceSNamhyung Kim he_total = he->hists->stats.total_non_filtered_period;
3208810f6ceSNamhyung Kim pair_total = pair->hists->stats.total_non_filtered_period;
3218810f6ceSNamhyung Kim }
322ed279da2SJiri Olsa return scnprintf(buf, size,
323ed279da2SJiri Olsa "(%" PRIu64 " * 100 / %" PRIu64 ") - "
324ed279da2SJiri Olsa "(%" PRIu64 " * 100 / %" PRIu64 ")",
3258810f6ceSNamhyung Kim pair->stat.period, pair_total,
3268810f6ceSNamhyung Kim he->stat.period, he_total);
327ed279da2SJiri Olsa }
328ed279da2SJiri Olsa
formula_ratio(struct hist_entry * he,struct hist_entry * pair,char * buf,size_t size)329f4c8bae1SJiri Olsa static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
330f4c8bae1SJiri Olsa char *buf, size_t size)
331ed279da2SJiri Olsa {
3329af303e2SJiri Olsa double old_period = he->stat.period;
3339af303e2SJiri Olsa double new_period = pair->stat.period;
334ed279da2SJiri Olsa
335ed279da2SJiri Olsa return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
336ed279da2SJiri Olsa }
337ed279da2SJiri Olsa
formula_wdiff(struct hist_entry * he,struct hist_entry * pair,char * buf,size_t size)338f4c8bae1SJiri Olsa static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
339f4c8bae1SJiri Olsa char *buf, size_t size)
340ed279da2SJiri Olsa {
3419af303e2SJiri Olsa u64 old_period = he->stat.period;
3429af303e2SJiri Olsa u64 new_period = pair->stat.period;
343ed279da2SJiri Olsa
344ed279da2SJiri Olsa return scnprintf(buf, size,
345ed279da2SJiri Olsa "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
346ed279da2SJiri Olsa new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
347ed279da2SJiri Olsa }
348ed279da2SJiri Olsa
formula_fprintf(struct hist_entry * he,struct hist_entry * pair,char * buf,size_t size)349ef358e6dSJiri Olsa static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
350f4c8bae1SJiri Olsa char *buf, size_t size)
351ed279da2SJiri Olsa {
352ed279da2SJiri Olsa switch (compute) {
353ed279da2SJiri Olsa case COMPUTE_DELTA:
354a1668c25SNamhyung Kim case COMPUTE_DELTA_ABS:
355f4c8bae1SJiri Olsa return formula_delta(he, pair, buf, size);
356ed279da2SJiri Olsa case COMPUTE_RATIO:
357f4c8bae1SJiri Olsa return formula_ratio(he, pair, buf, size);
358ed279da2SJiri Olsa case COMPUTE_WEIGHTED_DIFF:
359f4c8bae1SJiri Olsa return formula_wdiff(he, pair, buf, size);
360ed279da2SJiri Olsa default:
361ed279da2SJiri Olsa BUG_ON(1);
362ed279da2SJiri Olsa }
363ed279da2SJiri Olsa
364ed279da2SJiri Olsa return -1;
365ed279da2SJiri Olsa }
366ed279da2SJiri Olsa
block_hist_zalloc(size_t size)36799150a1fSJin Yao static void *block_hist_zalloc(size_t size)
36899150a1fSJin Yao {
36999150a1fSJin Yao struct block_hist *bh;
37099150a1fSJin Yao
37199150a1fSJin Yao bh = zalloc(size + sizeof(*bh));
37299150a1fSJin Yao if (!bh)
37399150a1fSJin Yao return NULL;
37499150a1fSJin Yao
37599150a1fSJin Yao return &bh->he;
37699150a1fSJin Yao }
37799150a1fSJin Yao
block_hist_free(void * he)37899150a1fSJin Yao static void block_hist_free(void *he)
37999150a1fSJin Yao {
38099150a1fSJin Yao struct block_hist *bh;
38199150a1fSJin Yao
38299150a1fSJin Yao bh = container_of(he, struct block_hist, he);
38399150a1fSJin Yao hists__delete_entries(&bh->block_hists);
38499150a1fSJin Yao free(bh);
38599150a1fSJin Yao }
38699150a1fSJin Yao
38799150a1fSJin Yao struct hist_entry_ops block_hist_ops = {
38899150a1fSJin Yao .new = block_hist_zalloc,
38999150a1fSJin Yao .free = block_hist_free,
39099150a1fSJin Yao };
39199150a1fSJin Yao
diff__process_sample_event(const struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct evsel * evsel,struct machine * machine)39230f29baeSIan Rogers static int diff__process_sample_event(const struct perf_tool *tool,
393d20deb64SArnaldo Carvalho de Melo union perf_event *event,
3948d50e5b4SArnaldo Carvalho de Melo struct perf_sample *sample,
39532dcd021SJiri Olsa struct evsel *evsel,
396743eb868SArnaldo Carvalho de Melo struct machine *machine)
39786a9eee0SArnaldo Carvalho de Melo {
3984802138dSJin Yao struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool);
39986a9eee0SArnaldo Carvalho de Melo struct addr_location al;
4004ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel);
4012a09a84cSJin Yao struct hist_entry_iter iter = {
4022a09a84cSJin Yao .evsel = evsel,
4032a09a84cSJin Yao .sample = sample,
4042a09a84cSJin Yao .ops = &hist_iter_normal,
4052a09a84cSJin Yao };
406b91fc39fSArnaldo Carvalho de Melo int ret = -1;
40786a9eee0SArnaldo Carvalho de Melo
4084802138dSJin Yao if (perf_time__ranges_skip_sample(pdiff->ptime_range, pdiff->range_num,
4094802138dSJin Yao sample->time)) {
4104802138dSJin Yao return 0;
4114802138dSJin Yao }
4124802138dSJin Yao
4130dd5041cSIan Rogers addr_location__init(&al);
414bb3eb566SArnaldo Carvalho de Melo if (machine__resolve(machine, &al, sample) < 0) {
41586a9eee0SArnaldo Carvalho de Melo pr_warning("problem processing %d event, skipping it.\n",
41686a9eee0SArnaldo Carvalho de Melo event->header.type);
4170dd5041cSIan Rogers ret = -1;
4180dd5041cSIan Rogers goto out;
41986a9eee0SArnaldo Carvalho de Melo }
42086a9eee0SArnaldo Carvalho de Melo
421daca23b2SJin Yao if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) {
422daca23b2SJin Yao ret = 0;
4230dd5041cSIan Rogers goto out;
424daca23b2SJin Yao }
425daca23b2SJin Yao
4262a09a84cSJin Yao switch (compute) {
4272a09a84cSJin Yao case COMPUTE_CYCLES:
42899150a1fSJin Yao if (!hists__add_entry_ops(hists, &block_hist_ops, &al, NULL,
429ebf39d29SLeo Yan NULL, NULL, NULL, sample, true)) {
43099150a1fSJin Yao pr_warning("problem incrementing symbol period, "
43199150a1fSJin Yao "skipping event\n");
4320dd5041cSIan Rogers goto out;
43399150a1fSJin Yao }
43499150a1fSJin Yao
4351f2b7fbbSKan Liang hist__account_cycles(sample->branch_stack, &al, sample,
4361f2b7fbbSKan Liang false, NULL, evsel);
4372a09a84cSJin Yao break;
4382a09a84cSJin Yao
4392a09a84cSJin Yao case COMPUTE_STREAM:
4402a09a84cSJin Yao if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH,
4412a09a84cSJin Yao NULL)) {
4422a09a84cSJin Yao pr_debug("problem adding hist entry, skipping event\n");
4430dd5041cSIan Rogers goto out;
4442a09a84cSJin Yao }
4452a09a84cSJin Yao break;
4462a09a84cSJin Yao
4472a09a84cSJin Yao default:
448ebf39d29SLeo Yan if (!hists__add_entry(hists, &al, NULL, NULL, NULL, NULL, sample,
4492a09a84cSJin Yao true)) {
4502a09a84cSJin Yao pr_warning("problem incrementing symbol period, "
4512a09a84cSJin Yao "skipping event\n");
4520dd5041cSIan Rogers goto out;
4532a09a84cSJin Yao }
45499150a1fSJin Yao }
45586a9eee0SArnaldo Carvalho de Melo
456820bc81fSNamhyung Kim /*
457820bc81fSNamhyung Kim * The total_period is updated here before going to the output
458820bc81fSNamhyung Kim * tree since normally only the baseline hists will call
459820bc81fSNamhyung Kim * hists__output_resort() and precompute needs the total
460820bc81fSNamhyung Kim * period in order to sort entries by percentage delta.
461820bc81fSNamhyung Kim */
4624ea062edSArnaldo Carvalho de Melo hists->stats.total_period += sample->period;
463820bc81fSNamhyung Kim if (!al.filtered)
4644ea062edSArnaldo Carvalho de Melo hists->stats.total_non_filtered_period += sample->period;
465b91fc39fSArnaldo Carvalho de Melo ret = 0;
4660dd5041cSIan Rogers out:
4670dd5041cSIan Rogers addr_location__exit(&al);
468b91fc39fSArnaldo Carvalho de Melo return ret;
46986a9eee0SArnaldo Carvalho de Melo }
47086a9eee0SArnaldo Carvalho de Melo
4711e1ec8f2SIan Rogers static struct perf_diff pdiff;
47286a9eee0SArnaldo Carvalho de Melo
evsel_match(struct evsel * evsel,struct evlist * evlist)47322a4db3cSIan Rogers static struct evsel *evsel_match(struct evsel *evsel, struct evlist *evlist)
474863e451fSJiri Olsa {
47532dcd021SJiri Olsa struct evsel *e;
476863e451fSJiri Olsa
477e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, e) {
47822a4db3cSIan Rogers if ((evsel->core.attr.type == e->core.attr.type) &&
47922a4db3cSIan Rogers (evsel->core.attr.config == e->core.attr.config))
480863e451fSJiri Olsa return e;
4810050f7aaSArnaldo Carvalho de Melo }
482863e451fSJiri Olsa
483863e451fSJiri Olsa return NULL;
484863e451fSJiri Olsa }
485863e451fSJiri Olsa
evlist__collapse_resort(struct evlist * evlist)486b979a2f1SArnaldo Carvalho de Melo static void evlist__collapse_resort(struct evlist *evlist)
487dd464345SJiri Olsa {
48832dcd021SJiri Olsa struct evsel *evsel;
489dd464345SJiri Olsa
490e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) {
4914ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel);
492dd464345SJiri Olsa
493c1fb5651SNamhyung Kim hists__collapse_resort(hists, NULL);
494dd464345SJiri Olsa }
495dd464345SJiri Olsa }
496dd464345SJiri Olsa
fmt_to_data_file(struct perf_hpp_fmt * fmt)497ff21cef6SNamhyung Kim static struct data__file *fmt_to_data_file(struct perf_hpp_fmt *fmt)
498ff21cef6SNamhyung Kim {
499ff21cef6SNamhyung Kim struct diff_hpp_fmt *dfmt = container_of(fmt, struct diff_hpp_fmt, fmt);
500ff21cef6SNamhyung Kim void *ptr = dfmt - dfmt->idx;
501ff21cef6SNamhyung Kim struct data__file *d = container_of(ptr, struct data__file, fmt);
502ff21cef6SNamhyung Kim
503ff21cef6SNamhyung Kim return d;
504ff21cef6SNamhyung Kim }
505ff21cef6SNamhyung Kim
5065f3f8d3bSJiri Olsa static struct hist_entry*
get_pair_data(struct hist_entry * he,struct data__file * d)5075f3f8d3bSJiri Olsa get_pair_data(struct hist_entry *he, struct data__file *d)
5085f3f8d3bSJiri Olsa {
5095f3f8d3bSJiri Olsa if (hist_entry__has_pairs(he)) {
5105f3f8d3bSJiri Olsa struct hist_entry *pair;
5115f3f8d3bSJiri Olsa
5125f3f8d3bSJiri Olsa list_for_each_entry(pair, &he->pairs.head, pairs.node)
5135f3f8d3bSJiri Olsa if (pair->hists == d->hists)
5145f3f8d3bSJiri Olsa return pair;
5155f3f8d3bSJiri Olsa }
5165f3f8d3bSJiri Olsa
5175f3f8d3bSJiri Olsa return NULL;
5185f3f8d3bSJiri Olsa }
5195f3f8d3bSJiri Olsa
5205f3f8d3bSJiri Olsa static struct hist_entry*
get_pair_fmt(struct hist_entry * he,struct diff_hpp_fmt * dfmt)5215f3f8d3bSJiri Olsa get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)
5225f3f8d3bSJiri Olsa {
523ff21cef6SNamhyung Kim struct data__file *d = fmt_to_data_file(&dfmt->fmt);
5245f3f8d3bSJiri Olsa
5255f3f8d3bSJiri Olsa return get_pair_data(he, d);
5265f3f8d3bSJiri Olsa }
5275f3f8d3bSJiri Olsa
hists__baseline_only(struct hists * hists)528a06d143eSJiri Olsa static void hists__baseline_only(struct hists *hists)
529a06d143eSJiri Olsa {
5302eb3d689SDavidlohr Bueso struct rb_root_cached *root;
531ce74f60eSNamhyung Kim struct rb_node *next;
532a06d143eSJiri Olsa
53352225036SJiri Olsa if (hists__has(hists, need_collapse))
534ce74f60eSNamhyung Kim root = &hists->entries_collapsed;
535ce74f60eSNamhyung Kim else
536ce74f60eSNamhyung Kim root = hists->entries_in;
537ce74f60eSNamhyung Kim
5382eb3d689SDavidlohr Bueso next = rb_first_cached(root);
539a06d143eSJiri Olsa while (next != NULL) {
540ce74f60eSNamhyung Kim struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
541a06d143eSJiri Olsa
542ce74f60eSNamhyung Kim next = rb_next(&he->rb_node_in);
543b821c732SArnaldo Carvalho de Melo if (!hist_entry__next_pair(he)) {
5442eb3d689SDavidlohr Bueso rb_erase_cached(&he->rb_node_in, root);
5456733d1bfSArnaldo Carvalho de Melo hist_entry__delete(he);
546a06d143eSJiri Olsa }
547a06d143eSJiri Olsa }
548a06d143eSJiri Olsa }
549a06d143eSJiri Olsa
block_cycles_diff_cmp(struct hist_entry * left,struct hist_entry * right)55099150a1fSJin Yao static int64_t block_cycles_diff_cmp(struct hist_entry *left,
55199150a1fSJin Yao struct hist_entry *right)
55299150a1fSJin Yao {
55399150a1fSJin Yao bool pairs_left = hist_entry__has_pairs(left);
55499150a1fSJin Yao bool pairs_right = hist_entry__has_pairs(right);
55599150a1fSJin Yao s64 l, r;
55699150a1fSJin Yao
55799150a1fSJin Yao if (!pairs_left && !pairs_right)
55899150a1fSJin Yao return 0;
55999150a1fSJin Yao
56098e93245SArnaldo Carvalho de Melo l = llabs(left->diff.cycles);
56198e93245SArnaldo Carvalho de Melo r = llabs(right->diff.cycles);
56299150a1fSJin Yao return r - l;
56399150a1fSJin Yao }
56499150a1fSJin Yao
block_sort(struct perf_hpp_fmt * fmt __maybe_unused,struct hist_entry * left,struct hist_entry * right)56599150a1fSJin Yao static int64_t block_sort(struct perf_hpp_fmt *fmt __maybe_unused,
56699150a1fSJin Yao struct hist_entry *left, struct hist_entry *right)
56799150a1fSJin Yao {
56899150a1fSJin Yao return block_cycles_diff_cmp(right, left);
56999150a1fSJin Yao }
57099150a1fSJin Yao
init_block_hist(struct block_hist * bh)57199150a1fSJin Yao static void init_block_hist(struct block_hist *bh)
57299150a1fSJin Yao {
57399150a1fSJin Yao __hists__init(&bh->block_hists, &bh->block_list);
57499150a1fSJin Yao perf_hpp_list__init(&bh->block_list);
57599150a1fSJin Yao
57699150a1fSJin Yao INIT_LIST_HEAD(&bh->block_fmt.list);
57799150a1fSJin Yao INIT_LIST_HEAD(&bh->block_fmt.sort_list);
57860414418SJin Yao bh->block_fmt.cmp = block_info__cmp;
57999150a1fSJin Yao bh->block_fmt.sort = block_sort;
58099150a1fSJin Yao perf_hpp_list__register_sort_field(&bh->block_list,
58199150a1fSJin Yao &bh->block_fmt);
58299150a1fSJin Yao bh->valid = true;
58399150a1fSJin Yao }
58499150a1fSJin Yao
get_block_pair(struct hist_entry * he,struct hists * hists_pair)585f3810817SJin Yao static struct hist_entry *get_block_pair(struct hist_entry *he,
586f3810817SJin Yao struct hists *hists_pair)
587f3810817SJin Yao {
588f3810817SJin Yao struct rb_root_cached *root = hists_pair->entries_in;
589f3810817SJin Yao struct rb_node *next = rb_first_cached(root);
590a8a9f6dcSJin Yao int64_t cmp;
591f3810817SJin Yao
592f3810817SJin Yao while (next != NULL) {
593f3810817SJin Yao struct hist_entry *he_pair = rb_entry(next, struct hist_entry,
594f3810817SJin Yao rb_node_in);
595f3810817SJin Yao
596f3810817SJin Yao next = rb_next(&he_pair->rb_node_in);
597f3810817SJin Yao
598a8a9f6dcSJin Yao cmp = __block_info__cmp(he_pair, he);
599f3810817SJin Yao if (!cmp)
600f3810817SJin Yao return he_pair;
601f3810817SJin Yao }
602f3810817SJin Yao
603f3810817SJin Yao return NULL;
604f3810817SJin Yao }
605f3810817SJin Yao
init_spark_values(unsigned long * svals,int num)606cebf7d51SJin Yao static void init_spark_values(unsigned long *svals, int num)
607cebf7d51SJin Yao {
608cebf7d51SJin Yao for (int i = 0; i < num; i++)
609cebf7d51SJin Yao svals[i] = 0;
610cebf7d51SJin Yao }
611cebf7d51SJin Yao
update_spark_value(unsigned long * svals,int num,struct stats * stats,u64 val)612cebf7d51SJin Yao static void update_spark_value(unsigned long *svals, int num,
613cebf7d51SJin Yao struct stats *stats, u64 val)
614cebf7d51SJin Yao {
615cebf7d51SJin Yao int n = stats->n;
616cebf7d51SJin Yao
617cebf7d51SJin Yao if (n < num)
618cebf7d51SJin Yao svals[n] = val;
619cebf7d51SJin Yao }
620cebf7d51SJin Yao
compute_cycles_diff(struct hist_entry * he,struct hist_entry * pair)621f3810817SJin Yao static void compute_cycles_diff(struct hist_entry *he,
622f3810817SJin Yao struct hist_entry *pair)
623f3810817SJin Yao {
624f3810817SJin Yao pair->diff.computed = true;
625f3810817SJin Yao if (pair->block_info->num && he->block_info->num) {
626f3810817SJin Yao pair->diff.cycles =
627f3810817SJin Yao pair->block_info->cycles_aggr / pair->block_info->num_aggr -
628f3810817SJin Yao he->block_info->cycles_aggr / he->block_info->num_aggr;
629cebf7d51SJin Yao
630cebf7d51SJin Yao if (!cycles_hist)
631cebf7d51SJin Yao return;
632cebf7d51SJin Yao
633cebf7d51SJin Yao init_stats(&pair->diff.stats);
634cebf7d51SJin Yao init_spark_values(pair->diff.svals, NUM_SPARKS);
635cebf7d51SJin Yao
636cebf7d51SJin Yao for (int i = 0; i < pair->block_info->num; i++) {
637cebf7d51SJin Yao u64 val;
638cebf7d51SJin Yao
639cebf7d51SJin Yao if (i >= he->block_info->num || i >= NUM_SPARKS)
640cebf7d51SJin Yao break;
641cebf7d51SJin Yao
6422b1ac640SArnaldo Carvalho de Melo val = llabs(pair->block_info->cycles_spark[i] -
643cebf7d51SJin Yao he->block_info->cycles_spark[i]);
644cebf7d51SJin Yao
645cebf7d51SJin Yao update_spark_value(pair->diff.svals, NUM_SPARKS,
646cebf7d51SJin Yao &pair->diff.stats, val);
647cebf7d51SJin Yao update_stats(&pair->diff.stats, val);
648cebf7d51SJin Yao }
649f3810817SJin Yao }
650f3810817SJin Yao }
651f3810817SJin Yao
block_hists_match(struct hists * hists_base,struct hists * hists_pair)652f3810817SJin Yao static void block_hists_match(struct hists *hists_base,
653f3810817SJin Yao struct hists *hists_pair)
654f3810817SJin Yao {
655f3810817SJin Yao struct rb_root_cached *root = hists_base->entries_in;
656f3810817SJin Yao struct rb_node *next = rb_first_cached(root);
657f3810817SJin Yao
658f3810817SJin Yao while (next != NULL) {
659f3810817SJin Yao struct hist_entry *he = rb_entry(next, struct hist_entry,
660f3810817SJin Yao rb_node_in);
661f3810817SJin Yao struct hist_entry *pair = get_block_pair(he, hists_pair);
662f3810817SJin Yao
663f3810817SJin Yao next = rb_next(&he->rb_node_in);
664f3810817SJin Yao
665f3810817SJin Yao if (pair) {
666f3810817SJin Yao hist_entry__add_pair(pair, he);
667f3810817SJin Yao compute_cycles_diff(he, pair);
668f3810817SJin Yao }
669f3810817SJin Yao }
670f3810817SJin Yao }
671f3810817SJin Yao
hists__precompute(struct hists * hists)67296c47f19SJiri Olsa static void hists__precompute(struct hists *hists)
67396c47f19SJiri Olsa {
6742eb3d689SDavidlohr Bueso struct rb_root_cached *root;
675367c53c0SJiri Olsa struct rb_node *next;
67696c47f19SJiri Olsa
67752225036SJiri Olsa if (hists__has(hists, need_collapse))
678367c53c0SJiri Olsa root = &hists->entries_collapsed;
679367c53c0SJiri Olsa else
680367c53c0SJiri Olsa root = hists->entries_in;
681367c53c0SJiri Olsa
6822eb3d689SDavidlohr Bueso next = rb_first_cached(root);
68396c47f19SJiri Olsa while (next != NULL) {
684f3810817SJin Yao struct block_hist *bh, *pair_bh;
6855f3f8d3bSJiri Olsa struct hist_entry *he, *pair;
68656495a8aSNamhyung Kim struct data__file *d;
68756495a8aSNamhyung Kim int i;
68896c47f19SJiri Olsa
6895f3f8d3bSJiri Olsa he = rb_entry(next, struct hist_entry, rb_node_in);
690367c53c0SJiri Olsa next = rb_next(&he->rb_node_in);
6915f3f8d3bSJiri Olsa
69260414418SJin Yao if (compute == COMPUTE_CYCLES) {
69360414418SJin Yao bh = container_of(he, struct block_hist, he);
69460414418SJin Yao init_block_hist(bh);
69520d6f555SKan Liang block_info__process_sym(he, bh, NULL, 0, 0);
69660414418SJin Yao }
69799150a1fSJin Yao
69856495a8aSNamhyung Kim data__for_each_file_new(i, d) {
69956495a8aSNamhyung Kim pair = get_pair_data(he, d);
70005472daaSJiri Olsa if (!pair)
70105472daaSJiri Olsa continue;
70296c47f19SJiri Olsa
70396c47f19SJiri Olsa switch (compute) {
70496c47f19SJiri Olsa case COMPUTE_DELTA:
705a1668c25SNamhyung Kim case COMPUTE_DELTA_ABS:
706ef358e6dSJiri Olsa compute_delta(he, pair);
70796c47f19SJiri Olsa break;
70896c47f19SJiri Olsa case COMPUTE_RATIO:
709ef358e6dSJiri Olsa compute_ratio(he, pair);
71096c47f19SJiri Olsa break;
71181d5f958SJiri Olsa case COMPUTE_WEIGHTED_DIFF:
712ef358e6dSJiri Olsa compute_wdiff(he, pair);
71381d5f958SJiri Olsa break;
71499150a1fSJin Yao case COMPUTE_CYCLES:
715f3810817SJin Yao pair_bh = container_of(pair, struct block_hist,
716f3810817SJin Yao he);
71760414418SJin Yao init_block_hist(pair_bh);
71820d6f555SKan Liang block_info__process_sym(pair, pair_bh, NULL, 0, 0);
71960414418SJin Yao
72060414418SJin Yao bh = container_of(he, struct block_hist, he);
721f3810817SJin Yao
722f3810817SJin Yao if (bh->valid && pair_bh->valid) {
723f3810817SJin Yao block_hists_match(&bh->block_hists,
724f3810817SJin Yao &pair_bh->block_hists);
7250bdf181fSJin Yao hists__output_resort(&pair_bh->block_hists,
7260bdf181fSJin Yao NULL);
727f3810817SJin Yao }
72899150a1fSJin Yao break;
72996c47f19SJiri Olsa default:
73096c47f19SJiri Olsa BUG_ON(1);
73196c47f19SJiri Olsa }
73296c47f19SJiri Olsa }
73396c47f19SJiri Olsa }
73456495a8aSNamhyung Kim }
73596c47f19SJiri Olsa
cmp_doubles(double l,double r)73696c47f19SJiri Olsa static int64_t cmp_doubles(double l, double r)
73796c47f19SJiri Olsa {
73896c47f19SJiri Olsa if (l > r)
73996c47f19SJiri Olsa return -1;
74096c47f19SJiri Olsa else if (l < r)
74196c47f19SJiri Olsa return 1;
74296c47f19SJiri Olsa else
74396c47f19SJiri Olsa return 0;
74496c47f19SJiri Olsa }
74596c47f19SJiri Olsa
74696c47f19SJiri Olsa static int64_t
__hist_entry__cmp_compute(struct hist_entry * left,struct hist_entry * right,int c)7475f3f8d3bSJiri Olsa __hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
74896c47f19SJiri Olsa int c)
74996c47f19SJiri Olsa {
75096c47f19SJiri Olsa switch (c) {
75196c47f19SJiri Olsa case COMPUTE_DELTA:
75296c47f19SJiri Olsa {
75396c47f19SJiri Olsa double l = left->diff.period_ratio_delta;
75496c47f19SJiri Olsa double r = right->diff.period_ratio_delta;
75596c47f19SJiri Olsa
75696c47f19SJiri Olsa return cmp_doubles(l, r);
75796c47f19SJiri Olsa }
758a1668c25SNamhyung Kim case COMPUTE_DELTA_ABS:
759a1668c25SNamhyung Kim {
760a1668c25SNamhyung Kim double l = fabs(left->diff.period_ratio_delta);
761a1668c25SNamhyung Kim double r = fabs(right->diff.period_ratio_delta);
762a1668c25SNamhyung Kim
763a1668c25SNamhyung Kim return cmp_doubles(l, r);
764a1668c25SNamhyung Kim }
76596c47f19SJiri Olsa case COMPUTE_RATIO:
76696c47f19SJiri Olsa {
76796c47f19SJiri Olsa double l = left->diff.period_ratio;
76896c47f19SJiri Olsa double r = right->diff.period_ratio;
76996c47f19SJiri Olsa
77096c47f19SJiri Olsa return cmp_doubles(l, r);
77196c47f19SJiri Olsa }
77281d5f958SJiri Olsa case COMPUTE_WEIGHTED_DIFF:
77381d5f958SJiri Olsa {
77481d5f958SJiri Olsa s64 l = left->diff.wdiff;
77581d5f958SJiri Olsa s64 r = right->diff.wdiff;
77681d5f958SJiri Olsa
77781d5f958SJiri Olsa return r - l;
77881d5f958SJiri Olsa }
77996c47f19SJiri Olsa default:
78096c47f19SJiri Olsa BUG_ON(1);
78196c47f19SJiri Olsa }
78296c47f19SJiri Olsa
78396c47f19SJiri Olsa return 0;
78496c47f19SJiri Olsa }
78596c47f19SJiri Olsa
7865f3f8d3bSJiri Olsa static int64_t
hist_entry__cmp_compute(struct hist_entry * left,struct hist_entry * right,int c,int sort_idx)7875f3f8d3bSJiri Olsa hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
78856495a8aSNamhyung Kim int c, int sort_idx)
7895f3f8d3bSJiri Olsa {
7905f3f8d3bSJiri Olsa bool pairs_left = hist_entry__has_pairs(left);
7915f3f8d3bSJiri Olsa bool pairs_right = hist_entry__has_pairs(right);
7925f3f8d3bSJiri Olsa struct hist_entry *p_right, *p_left;
7935f3f8d3bSJiri Olsa
7945f3f8d3bSJiri Olsa if (!pairs_left && !pairs_right)
7955f3f8d3bSJiri Olsa return 0;
7965f3f8d3bSJiri Olsa
7975f3f8d3bSJiri Olsa if (!pairs_left || !pairs_right)
7985f3f8d3bSJiri Olsa return pairs_left ? -1 : 1;
7995f3f8d3bSJiri Olsa
80056495a8aSNamhyung Kim p_left = get_pair_data(left, &data__files[sort_idx]);
80156495a8aSNamhyung Kim p_right = get_pair_data(right, &data__files[sort_idx]);
8025f3f8d3bSJiri Olsa
8035f3f8d3bSJiri Olsa if (!p_left && !p_right)
8045f3f8d3bSJiri Olsa return 0;
8055f3f8d3bSJiri Olsa
8065f3f8d3bSJiri Olsa if (!p_left || !p_right)
8075f3f8d3bSJiri Olsa return p_left ? -1 : 1;
8085f3f8d3bSJiri Olsa
8095f3f8d3bSJiri Olsa /*
8105f3f8d3bSJiri Olsa * We have 2 entries of same kind, let's
8115f3f8d3bSJiri Olsa * make the data comparison.
8125f3f8d3bSJiri Olsa */
8135f3f8d3bSJiri Olsa return __hist_entry__cmp_compute(p_left, p_right, c);
8145f3f8d3bSJiri Olsa }
8155f3f8d3bSJiri Olsa
816e7024fc3SNamhyung Kim static int64_t
hist_entry__cmp_compute_idx(struct hist_entry * left,struct hist_entry * right,int c,int sort_idx)817566b5cfbSNamhyung Kim hist_entry__cmp_compute_idx(struct hist_entry *left, struct hist_entry *right,
818566b5cfbSNamhyung Kim int c, int sort_idx)
819566b5cfbSNamhyung Kim {
820566b5cfbSNamhyung Kim struct hist_entry *p_right, *p_left;
821566b5cfbSNamhyung Kim
822566b5cfbSNamhyung Kim p_left = get_pair_data(left, &data__files[sort_idx]);
823566b5cfbSNamhyung Kim p_right = get_pair_data(right, &data__files[sort_idx]);
824566b5cfbSNamhyung Kim
825566b5cfbSNamhyung Kim if (!p_left && !p_right)
826566b5cfbSNamhyung Kim return 0;
827566b5cfbSNamhyung Kim
828566b5cfbSNamhyung Kim if (!p_left || !p_right)
829566b5cfbSNamhyung Kim return p_left ? -1 : 1;
830566b5cfbSNamhyung Kim
831a1668c25SNamhyung Kim if (c != COMPUTE_DELTA && c != COMPUTE_DELTA_ABS) {
832566b5cfbSNamhyung Kim /*
833566b5cfbSNamhyung Kim * The delta can be computed without the baseline, but
834566b5cfbSNamhyung Kim * others are not. Put those entries which have no
835566b5cfbSNamhyung Kim * values below.
836566b5cfbSNamhyung Kim */
837566b5cfbSNamhyung Kim if (left->dummy && right->dummy)
838566b5cfbSNamhyung Kim return 0;
839566b5cfbSNamhyung Kim
840566b5cfbSNamhyung Kim if (left->dummy || right->dummy)
841566b5cfbSNamhyung Kim return left->dummy ? 1 : -1;
842566b5cfbSNamhyung Kim }
843566b5cfbSNamhyung Kim
844566b5cfbSNamhyung Kim return __hist_entry__cmp_compute(p_left, p_right, c);
845566b5cfbSNamhyung Kim }
846566b5cfbSNamhyung Kim
847566b5cfbSNamhyung Kim static int64_t
hist_entry__cmp_nop(struct perf_hpp_fmt * fmt __maybe_unused,struct hist_entry * left __maybe_unused,struct hist_entry * right __maybe_unused)84887bbdf76SNamhyung Kim hist_entry__cmp_nop(struct perf_hpp_fmt *fmt __maybe_unused,
84987bbdf76SNamhyung Kim struct hist_entry *left __maybe_unused,
850e7024fc3SNamhyung Kim struct hist_entry *right __maybe_unused)
851e7024fc3SNamhyung Kim {
852e7024fc3SNamhyung Kim return 0;
853e7024fc3SNamhyung Kim }
854e7024fc3SNamhyung Kim
855e7024fc3SNamhyung Kim static int64_t
hist_entry__cmp_baseline(struct perf_hpp_fmt * fmt __maybe_unused,struct hist_entry * left,struct hist_entry * right)85687bbdf76SNamhyung Kim hist_entry__cmp_baseline(struct perf_hpp_fmt *fmt __maybe_unused,
85787bbdf76SNamhyung Kim struct hist_entry *left, struct hist_entry *right)
858e7024fc3SNamhyung Kim {
859e7024fc3SNamhyung Kim if (left->stat.period == right->stat.period)
860e7024fc3SNamhyung Kim return 0;
861e7024fc3SNamhyung Kim return left->stat.period > right->stat.period ? 1 : -1;
862e7024fc3SNamhyung Kim }
863e7024fc3SNamhyung Kim
864e7024fc3SNamhyung Kim static int64_t
hist_entry__cmp_delta(struct perf_hpp_fmt * fmt,struct hist_entry * left,struct hist_entry * right)86556495a8aSNamhyung Kim hist_entry__cmp_delta(struct perf_hpp_fmt *fmt,
86687bbdf76SNamhyung Kim struct hist_entry *left, struct hist_entry *right)
867e7024fc3SNamhyung Kim {
86856495a8aSNamhyung Kim struct data__file *d = fmt_to_data_file(fmt);
86956495a8aSNamhyung Kim
87056495a8aSNamhyung Kim return hist_entry__cmp_compute(right, left, COMPUTE_DELTA, d->idx);
871e7024fc3SNamhyung Kim }
872e7024fc3SNamhyung Kim
873e7024fc3SNamhyung Kim static int64_t
hist_entry__cmp_delta_abs(struct perf_hpp_fmt * fmt,struct hist_entry * left,struct hist_entry * right)874a1668c25SNamhyung Kim hist_entry__cmp_delta_abs(struct perf_hpp_fmt *fmt,
875a1668c25SNamhyung Kim struct hist_entry *left, struct hist_entry *right)
876a1668c25SNamhyung Kim {
877a1668c25SNamhyung Kim struct data__file *d = fmt_to_data_file(fmt);
878a1668c25SNamhyung Kim
879a1668c25SNamhyung Kim return hist_entry__cmp_compute(right, left, COMPUTE_DELTA_ABS, d->idx);
880a1668c25SNamhyung Kim }
881a1668c25SNamhyung Kim
882a1668c25SNamhyung Kim static int64_t
hist_entry__cmp_ratio(struct perf_hpp_fmt * fmt,struct hist_entry * left,struct hist_entry * right)88356495a8aSNamhyung Kim hist_entry__cmp_ratio(struct perf_hpp_fmt *fmt,
88487bbdf76SNamhyung Kim struct hist_entry *left, struct hist_entry *right)
885e7024fc3SNamhyung Kim {
88656495a8aSNamhyung Kim struct data__file *d = fmt_to_data_file(fmt);
88756495a8aSNamhyung Kim
88856495a8aSNamhyung Kim return hist_entry__cmp_compute(right, left, COMPUTE_RATIO, d->idx);
889e7024fc3SNamhyung Kim }
890e7024fc3SNamhyung Kim
891e7024fc3SNamhyung Kim static int64_t
hist_entry__cmp_wdiff(struct perf_hpp_fmt * fmt,struct hist_entry * left,struct hist_entry * right)89256495a8aSNamhyung Kim hist_entry__cmp_wdiff(struct perf_hpp_fmt *fmt,
89387bbdf76SNamhyung Kim struct hist_entry *left, struct hist_entry *right)
894e7024fc3SNamhyung Kim {
89556495a8aSNamhyung Kim struct data__file *d = fmt_to_data_file(fmt);
89656495a8aSNamhyung Kim
89756495a8aSNamhyung Kim return hist_entry__cmp_compute(right, left, COMPUTE_WEIGHTED_DIFF, d->idx);
898e7024fc3SNamhyung Kim }
899e7024fc3SNamhyung Kim
900566b5cfbSNamhyung Kim static int64_t
hist_entry__cmp_delta_idx(struct perf_hpp_fmt * fmt __maybe_unused,struct hist_entry * left,struct hist_entry * right)901566b5cfbSNamhyung Kim hist_entry__cmp_delta_idx(struct perf_hpp_fmt *fmt __maybe_unused,
902566b5cfbSNamhyung Kim struct hist_entry *left, struct hist_entry *right)
903566b5cfbSNamhyung Kim {
904566b5cfbSNamhyung Kim return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA,
905566b5cfbSNamhyung Kim sort_compute);
906566b5cfbSNamhyung Kim }
907566b5cfbSNamhyung Kim
908566b5cfbSNamhyung Kim static int64_t
hist_entry__cmp_delta_abs_idx(struct perf_hpp_fmt * fmt __maybe_unused,struct hist_entry * left,struct hist_entry * right)909a1668c25SNamhyung Kim hist_entry__cmp_delta_abs_idx(struct perf_hpp_fmt *fmt __maybe_unused,
910a1668c25SNamhyung Kim struct hist_entry *left, struct hist_entry *right)
911a1668c25SNamhyung Kim {
912a1668c25SNamhyung Kim return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA_ABS,
913a1668c25SNamhyung Kim sort_compute);
914a1668c25SNamhyung Kim }
915a1668c25SNamhyung Kim
916a1668c25SNamhyung Kim static int64_t
hist_entry__cmp_ratio_idx(struct perf_hpp_fmt * fmt __maybe_unused,struct hist_entry * left,struct hist_entry * right)917566b5cfbSNamhyung Kim hist_entry__cmp_ratio_idx(struct perf_hpp_fmt *fmt __maybe_unused,
918566b5cfbSNamhyung Kim struct hist_entry *left, struct hist_entry *right)
919566b5cfbSNamhyung Kim {
920566b5cfbSNamhyung Kim return hist_entry__cmp_compute_idx(right, left, COMPUTE_RATIO,
921566b5cfbSNamhyung Kim sort_compute);
922566b5cfbSNamhyung Kim }
923566b5cfbSNamhyung Kim
924566b5cfbSNamhyung Kim static int64_t
hist_entry__cmp_wdiff_idx(struct perf_hpp_fmt * fmt __maybe_unused,struct hist_entry * left,struct hist_entry * right)925566b5cfbSNamhyung Kim hist_entry__cmp_wdiff_idx(struct perf_hpp_fmt *fmt __maybe_unused,
926566b5cfbSNamhyung Kim struct hist_entry *left, struct hist_entry *right)
927566b5cfbSNamhyung Kim {
928566b5cfbSNamhyung Kim return hist_entry__cmp_compute_idx(right, left, COMPUTE_WEIGHTED_DIFF,
929566b5cfbSNamhyung Kim sort_compute);
930566b5cfbSNamhyung Kim }
931566b5cfbSNamhyung Kim
hists__process(struct hists * hists)93222aeb7f5SJiri Olsa static void hists__process(struct hists *hists)
933a06d143eSJiri Olsa {
934a06d143eSJiri Olsa if (show_baseline_only)
93522aeb7f5SJiri Olsa hists__baseline_only(hists);
936a06d143eSJiri Olsa
93722aeb7f5SJiri Olsa hists__precompute(hists);
938740b97f9SNamhyung Kim hists__output_resort(hists, NULL);
93996c47f19SJiri Olsa
940b10c78c5SJin Yao if (compute == COMPUTE_CYCLES)
941b10c78c5SJin Yao symbol_conf.report_block = true;
942b10c78c5SJin Yao
94363b42fceSNamhyung Kim hists__fprintf(hists, !quiet, 0, 0, 0, stdout,
944e9de7e2fSArnaldo Carvalho de Melo !symbol_conf.use_callchain);
945a06d143eSJiri Olsa }
946a06d143eSJiri Olsa
data__fprintf(void)9471d81c7fcSJiri Olsa static void data__fprintf(void)
9481d81c7fcSJiri Olsa {
9491d81c7fcSJiri Olsa struct data__file *d;
9501d81c7fcSJiri Olsa int i;
9511d81c7fcSJiri Olsa
9521d81c7fcSJiri Olsa fprintf(stdout, "# Data files:\n");
9531d81c7fcSJiri Olsa
9541d81c7fcSJiri Olsa data__for_each_file(i, d)
9551d81c7fcSJiri Olsa fprintf(stdout, "# [%d] %s %s\n",
9562d4f2799SJiri Olsa d->idx, d->data.path,
9571d81c7fcSJiri Olsa !d->idx ? "(Baseline)" : "");
9581d81c7fcSJiri Olsa
9591d81c7fcSJiri Olsa fprintf(stdout, "#\n");
9601d81c7fcSJiri Olsa }
9611d81c7fcSJiri Olsa
data_process(void)962ec308426SJiri Olsa static void data_process(void)
96386a9eee0SArnaldo Carvalho de Melo {
96463503dbaSJiri Olsa struct evlist *evlist_base = data__files[0].session->evlist;
96532dcd021SJiri Olsa struct evsel *evsel_base;
966863e451fSJiri Olsa bool first = true;
96786a9eee0SArnaldo Carvalho de Melo
968e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist_base, evsel_base) {
9694ea062edSArnaldo Carvalho de Melo struct hists *hists_base = evsel__hists(evsel_base);
97022aeb7f5SJiri Olsa struct data__file *d;
97122aeb7f5SJiri Olsa int i;
97286a9eee0SArnaldo Carvalho de Melo
97322aeb7f5SJiri Olsa data__for_each_file_new(i, d) {
97463503dbaSJiri Olsa struct evlist *evlist = d->session->evlist;
97532dcd021SJiri Olsa struct evsel *evsel;
9764ea062edSArnaldo Carvalho de Melo struct hists *hists;
97722aeb7f5SJiri Olsa
97822aeb7f5SJiri Olsa evsel = evsel_match(evsel_base, evlist);
97922aeb7f5SJiri Olsa if (!evsel)
980863e451fSJiri Olsa continue;
981863e451fSJiri Olsa
9824ea062edSArnaldo Carvalho de Melo hists = evsel__hists(evsel);
9834ea062edSArnaldo Carvalho de Melo d->hists = hists;
98422aeb7f5SJiri Olsa
9854ea062edSArnaldo Carvalho de Melo hists__match(hists_base, hists);
98622aeb7f5SJiri Olsa
98722aeb7f5SJiri Olsa if (!show_baseline_only)
9884ea062edSArnaldo Carvalho de Melo hists__link(hists_base, hists);
98922aeb7f5SJiri Olsa }
99022aeb7f5SJiri Olsa
99163b42fceSNamhyung Kim if (!quiet) {
992863e451fSJiri Olsa fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
9938ab2e96dSArnaldo Carvalho de Melo evsel__name(evsel_base));
99463b42fceSNamhyung Kim }
995863e451fSJiri Olsa
996863e451fSJiri Olsa first = false;
997863e451fSJiri Olsa
99863b42fceSNamhyung Kim if (verbose > 0 || ((data__files_cnt > 2) && !quiet))
9991d81c7fcSJiri Olsa data__fprintf();
10001d81c7fcSJiri Olsa
1001f9db0d0fSKan Liang /* Don't sort callchain for perf diff */
1002862b2f8fSArnaldo Carvalho de Melo evsel__reset_sample_bit(evsel_base, CALLCHAIN);
1003f9db0d0fSKan Liang
10044ea062edSArnaldo Carvalho de Melo hists__process(hists_base);
1005ec308426SJiri Olsa }
1006863e451fSJiri Olsa }
1007863e451fSJiri Olsa
process_base_stream(struct data__file * data_base,struct data__file * data_pair,const char * title __maybe_unused)10082a09a84cSJin Yao static int process_base_stream(struct data__file *data_base,
10092a09a84cSJin Yao struct data__file *data_pair,
10102a09a84cSJin Yao const char *title __maybe_unused)
10112a09a84cSJin Yao {
10122a09a84cSJin Yao struct evlist *evlist_base = data_base->session->evlist;
10132a09a84cSJin Yao struct evlist *evlist_pair = data_pair->session->evlist;
10142a09a84cSJin Yao struct evsel *evsel_base, *evsel_pair;
10152a09a84cSJin Yao struct evsel_streams *es_base, *es_pair;
10162a09a84cSJin Yao
10172a09a84cSJin Yao evlist__for_each_entry(evlist_base, evsel_base) {
10182a09a84cSJin Yao evsel_pair = evsel_match(evsel_base, evlist_pair);
10192a09a84cSJin Yao if (!evsel_pair)
10202a09a84cSJin Yao continue;
10212a09a84cSJin Yao
10222a09a84cSJin Yao es_base = evsel_streams__entry(data_base->evlist_streams,
1023*2f0539faSIan Rogers evsel_base);
10242a09a84cSJin Yao if (!es_base)
10252a09a84cSJin Yao return -1;
10262a09a84cSJin Yao
10272a09a84cSJin Yao es_pair = evsel_streams__entry(data_pair->evlist_streams,
1028*2f0539faSIan Rogers evsel_pair);
10292a09a84cSJin Yao if (!es_pair)
10302a09a84cSJin Yao return -1;
10312a09a84cSJin Yao
10322a09a84cSJin Yao evsel_streams__match(es_base, es_pair);
10332a09a84cSJin Yao evsel_streams__report(es_base, es_pair);
10342a09a84cSJin Yao }
10352a09a84cSJin Yao
10362a09a84cSJin Yao return 0;
10372a09a84cSJin Yao }
10382a09a84cSJin Yao
stream_process(void)10392a09a84cSJin Yao static void stream_process(void)
10402a09a84cSJin Yao {
10412a09a84cSJin Yao /*
10422a09a84cSJin Yao * Stream comparison only supports two data files.
10432a09a84cSJin Yao * perf.data.old and perf.data. data__files[0] is perf.data.old,
10442a09a84cSJin Yao * data__files[1] is perf.data.
10452a09a84cSJin Yao */
10462a09a84cSJin Yao process_base_stream(&data__files[0], &data__files[1],
10472a09a84cSJin Yao "# Output based on old perf data:\n#\n");
10482a09a84cSJin Yao }
10492a09a84cSJin Yao
data__free(struct data__file * d)1050c818b498SJiri Olsa static void data__free(struct data__file *d)
1051c818b498SJiri Olsa {
1052c818b498SJiri Olsa int col;
1053c818b498SJiri Olsa
10542a09a84cSJin Yao if (d->evlist_streams)
10552a09a84cSJin Yao evlist_streams__delete(d->evlist_streams);
10562a09a84cSJin Yao
1057c818b498SJiri Olsa for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
1058c818b498SJiri Olsa struct diff_hpp_fmt *fmt = &d->fmt[col];
1059c818b498SJiri Olsa
106074cf249dSArnaldo Carvalho de Melo zfree(&fmt->header);
1061c818b498SJiri Olsa }
1062c818b498SJiri Olsa }
1063c818b498SJiri Olsa
abstime_str_dup(char ** pstr)10644802138dSJin Yao static int abstime_str_dup(char **pstr)
10654802138dSJin Yao {
10664802138dSJin Yao char *str = NULL;
10674802138dSJin Yao
10684802138dSJin Yao if (pdiff.time_str && strchr(pdiff.time_str, ':')) {
10694802138dSJin Yao str = strdup(pdiff.time_str);
10704802138dSJin Yao if (!str)
10714802138dSJin Yao return -ENOMEM;
10724802138dSJin Yao }
10734802138dSJin Yao
10744802138dSJin Yao *pstr = str;
10754802138dSJin Yao return 0;
10764802138dSJin Yao }
10774802138dSJin Yao
parse_absolute_time(struct data__file * d,char ** pstr)10784802138dSJin Yao static int parse_absolute_time(struct data__file *d, char **pstr)
10794802138dSJin Yao {
10804802138dSJin Yao char *p = *pstr;
10814802138dSJin Yao int ret;
10824802138dSJin Yao
10834802138dSJin Yao /*
10844802138dSJin Yao * Absolute timestamp for one file has the format: a.b,c.d
10854802138dSJin Yao * For multiple files, the format is: a.b,c.d:a.b,c.d
10864802138dSJin Yao */
10874802138dSJin Yao p = strchr(*pstr, ':');
10884802138dSJin Yao if (p) {
10894802138dSJin Yao if (p == *pstr) {
10904802138dSJin Yao pr_err("Invalid time string\n");
10914802138dSJin Yao return -EINVAL;
10924802138dSJin Yao }
10934802138dSJin Yao
10944802138dSJin Yao *p = 0;
10954802138dSJin Yao p++;
10964802138dSJin Yao if (*p == 0) {
10974802138dSJin Yao pr_err("Invalid time string\n");
10984802138dSJin Yao return -EINVAL;
10994802138dSJin Yao }
11004802138dSJin Yao }
11014802138dSJin Yao
11024802138dSJin Yao ret = perf_time__parse_for_ranges(*pstr, d->session,
11034802138dSJin Yao &pdiff.ptime_range,
11044802138dSJin Yao &pdiff.range_size,
11054802138dSJin Yao &pdiff.range_num);
11064802138dSJin Yao if (ret < 0)
11074802138dSJin Yao return ret;
11084802138dSJin Yao
11094802138dSJin Yao if (!p || *p == 0)
11104802138dSJin Yao *pstr = NULL;
11114802138dSJin Yao else
11124802138dSJin Yao *pstr = p;
11134802138dSJin Yao
11144802138dSJin Yao return ret;
11154802138dSJin Yao }
11164802138dSJin Yao
parse_percent_time(struct data__file * d)11174802138dSJin Yao static int parse_percent_time(struct data__file *d)
11184802138dSJin Yao {
11194802138dSJin Yao int ret;
11204802138dSJin Yao
11214802138dSJin Yao ret = perf_time__parse_for_ranges(pdiff.time_str, d->session,
11224802138dSJin Yao &pdiff.ptime_range,
11234802138dSJin Yao &pdiff.range_size,
11244802138dSJin Yao &pdiff.range_num);
11254802138dSJin Yao return ret;
11264802138dSJin Yao }
11274802138dSJin Yao
parse_time_str(struct data__file * d,char * abstime_ostr,char ** pabstime_tmp)11284802138dSJin Yao static int parse_time_str(struct data__file *d, char *abstime_ostr,
11294802138dSJin Yao char **pabstime_tmp)
11304802138dSJin Yao {
11314802138dSJin Yao int ret = 0;
11324802138dSJin Yao
11334802138dSJin Yao if (abstime_ostr)
11344802138dSJin Yao ret = parse_absolute_time(d, pabstime_tmp);
11354802138dSJin Yao else if (pdiff.time_str)
11364802138dSJin Yao ret = parse_percent_time(d);
11374802138dSJin Yao
11384802138dSJin Yao return ret;
11394802138dSJin Yao }
11404802138dSJin Yao
check_file_brstack(void)114130d81553SJin Yao static int check_file_brstack(void)
114230d81553SJin Yao {
114330d81553SJin Yao struct data__file *d;
114430d81553SJin Yao bool has_br_stack;
114530d81553SJin Yao int i;
114630d81553SJin Yao
114730d81553SJin Yao data__for_each_file(i, d) {
11482681bd85SNamhyung Kim d->session = perf_session__new(&d->data, &pdiff.tool);
11496ef81c55SMamatha Inamdar if (IS_ERR(d->session)) {
115030d81553SJin Yao pr_err("Failed to open %s\n", d->data.path);
11516ef81c55SMamatha Inamdar return PTR_ERR(d->session);
115230d81553SJin Yao }
115330d81553SJin Yao
115430d81553SJin Yao has_br_stack = perf_header__has_feat(&d->session->header,
115530d81553SJin Yao HEADER_BRANCH_STACK);
115630d81553SJin Yao perf_session__delete(d->session);
115730d81553SJin Yao if (!has_br_stack)
115830d81553SJin Yao return 0;
115930d81553SJin Yao }
116030d81553SJin Yao
116130d81553SJin Yao /* Set only all files having branch stacks */
116230d81553SJin Yao pdiff.has_br_stack = true;
116330d81553SJin Yao return 0;
116430d81553SJin Yao }
116530d81553SJin Yao
__cmd_diff(void)1166ec308426SJiri Olsa static int __cmd_diff(void)
1167ec308426SJiri Olsa {
1168ec308426SJiri Olsa struct data__file *d;
11694802138dSJin Yao int ret, i;
11704802138dSJin Yao char *abstime_ostr, *abstime_tmp;
11714802138dSJin Yao
11724802138dSJin Yao ret = abstime_str_dup(&abstime_ostr);
11734802138dSJin Yao if (ret)
11744802138dSJin Yao return ret;
11754802138dSJin Yao
11764802138dSJin Yao abstime_tmp = abstime_ostr;
11774802138dSJin Yao ret = -EINVAL;
1178ec308426SJiri Olsa
1179ec308426SJiri Olsa data__for_each_file(i, d) {
11802681bd85SNamhyung Kim d->session = perf_session__new(&d->data, &pdiff.tool);
11816ef81c55SMamatha Inamdar if (IS_ERR(d->session)) {
11826ef81c55SMamatha Inamdar ret = PTR_ERR(d->session);
11832d4f2799SJiri Olsa pr_err("Failed to open %s\n", d->data.path);
1184ec308426SJiri Olsa goto out_delete;
1185ec308426SJiri Olsa }
1186ec308426SJiri Olsa
11874802138dSJin Yao if (pdiff.time_str) {
11884802138dSJin Yao ret = parse_time_str(d, abstime_ostr, &abstime_tmp);
11894802138dSJin Yao if (ret < 0)
11904802138dSJin Yao goto out_delete;
11914802138dSJin Yao }
11924802138dSJin Yao
1193daca23b2SJin Yao if (cpu_list) {
1194daca23b2SJin Yao ret = perf_session__cpu_bitmap(d->session, cpu_list,
1195daca23b2SJin Yao cpu_bitmap);
1196daca23b2SJin Yao if (ret < 0)
1197daca23b2SJin Yao goto out_delete;
1198daca23b2SJin Yao }
1199daca23b2SJin Yao
1200b7b61cbeSArnaldo Carvalho de Melo ret = perf_session__process_events(d->session);
1201ec308426SJiri Olsa if (ret) {
12022d4f2799SJiri Olsa pr_err("Failed to process %s\n", d->data.path);
1203ec308426SJiri Olsa goto out_delete;
1204ec308426SJiri Olsa }
1205ec308426SJiri Olsa
1206b979a2f1SArnaldo Carvalho de Melo evlist__collapse_resort(d->session->evlist);
12074802138dSJin Yao
12084802138dSJin Yao if (pdiff.ptime_range)
12094802138dSJin Yao zfree(&pdiff.ptime_range);
12102a09a84cSJin Yao
12112a09a84cSJin Yao if (compute == COMPUTE_STREAM) {
12122a09a84cSJin Yao d->evlist_streams = evlist__create_streams(
12132a09a84cSJin Yao d->session->evlist, 5);
121497130700SZhen Lei if (!d->evlist_streams) {
121597130700SZhen Lei ret = -ENOMEM;
12162a09a84cSJin Yao goto out_delete;
12172a09a84cSJin Yao }
1218ec308426SJiri Olsa }
121997130700SZhen Lei }
1220ec308426SJiri Olsa
12212a09a84cSJin Yao if (compute == COMPUTE_STREAM)
12222a09a84cSJin Yao stream_process();
12232a09a84cSJin Yao else
1224ec308426SJiri Olsa data_process();
1225ec308426SJiri Olsa
122686a9eee0SArnaldo Carvalho de Melo out_delete:
1227ec308426SJiri Olsa data__for_each_file(i, d) {
1228ffc52b7aSDmitry Safonov if (!IS_ERR(d->session))
1229ec308426SJiri Olsa perf_session__delete(d->session);
1230c818b498SJiri Olsa data__free(d);
1231ec308426SJiri Olsa }
1232ec308426SJiri Olsa
1233ec308426SJiri Olsa free(data__files);
12344802138dSJin Yao
12354802138dSJin Yao if (pdiff.ptime_range)
12364802138dSJin Yao zfree(&pdiff.ptime_range);
12374802138dSJin Yao
12384802138dSJin Yao if (abstime_ostr)
12394802138dSJin Yao free(abstime_ostr);
12404802138dSJin Yao
124186a9eee0SArnaldo Carvalho de Melo return ret;
124286a9eee0SArnaldo Carvalho de Melo }
124386a9eee0SArnaldo Carvalho de Melo
124486a9eee0SArnaldo Carvalho de Melo static const char * const diff_usage[] = {
124586a9eee0SArnaldo Carvalho de Melo "perf diff [<options>] [old_file] [new_file]",
12460422a4fcSArnaldo Carvalho de Melo NULL,
124786a9eee0SArnaldo Carvalho de Melo };
124886a9eee0SArnaldo Carvalho de Melo
124986a9eee0SArnaldo Carvalho de Melo static const struct option options[] = {
1250c0555642SIan Munsie OPT_INCR('v', "verbose", &verbose,
125186a9eee0SArnaldo Carvalho de Melo "be more verbose (show symbol address, etc)"),
1252a527c2c1SJames Clark OPT_BOOLEAN('q', "quiet", &quiet, "Do not show any warnings or messages"),
1253a06d143eSJiri Olsa OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
1254a06d143eSJiri Olsa "Show only items with match in baseline"),
125581d5f958SJiri Olsa OPT_CALLBACK('c', "compute", &compute,
1256b10c78c5SJin Yao "delta,delta-abs,ratio,wdiff:w1,w2 (default delta-abs),cycles",
12577aaf6b35SJiri Olsa "Entries differential computation selection",
12587aaf6b35SJiri Olsa setup_compute),
125961949b21SJiri Olsa OPT_BOOLEAN('p', "period", &show_period,
126061949b21SJiri Olsa "Show period values."),
1261ed279da2SJiri Olsa OPT_BOOLEAN('F', "formula", &show_formula,
1262ed279da2SJiri Olsa "Show formula."),
1263cebf7d51SJin Yao OPT_BOOLEAN(0, "cycles-hist", &cycles_hist,
1264cebf7d51SJin Yao "Show cycles histogram and standard deviation "
1265cebf7d51SJin Yao "- WARNING: use only with -c cycles."),
126686a9eee0SArnaldo Carvalho de Melo OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
126786a9eee0SArnaldo Carvalho de Melo "dump raw trace in ASCII"),
126886a9eee0SArnaldo Carvalho de Melo OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
12696b1f3423SDavid Ahern OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
12706b1f3423SDavid Ahern "file", "kallsyms pathname"),
127186a9eee0SArnaldo Carvalho de Melo OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
127286a9eee0SArnaldo Carvalho de Melo "load module symbols - WARNING: use only with -k and LIVE kernel"),
1273c410a338SArnaldo Carvalho de Melo OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
1274c410a338SArnaldo Carvalho de Melo "only consider symbols in these dsos"),
1275c410a338SArnaldo Carvalho de Melo OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1276c410a338SArnaldo Carvalho de Melo "only consider symbols in these comms"),
1277c410a338SArnaldo Carvalho de Melo OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1278c410a338SArnaldo Carvalho de Melo "only consider these symbols"),
1279c351c281SArnaldo Carvalho de Melo OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1280a2ce067eSNamhyung Kim "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
1281a2ce067eSNamhyung Kim " Please refer the man page for the complete list."),
12828b8ca6e1SWang Nan OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator",
1283c351c281SArnaldo Carvalho de Melo "separator for columns, no spaces will be added between "
1284c351c281SArnaldo Carvalho de Melo "columns '.' is reserved."),
1285a7066709SHe Kuang OPT_CALLBACK(0, "symfs", NULL, "directory",
1286a7066709SHe Kuang "Look for files with symbols relative to this directory",
1287a7066709SHe Kuang symbol__config_symfs),
12885f3f8d3bSJiri Olsa OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
12898810f6ceSNamhyung Kim OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
12908810f6ceSNamhyung Kim "How to display percentage of filtered entries", parse_filter_percentage),
12914802138dSJin Yao OPT_STRING(0, "time", &pdiff.time_str, "str",
12924802138dSJin Yao "Time span (time percent or absolute timestamp)"),
1293daca23b2SJin Yao OPT_STRING(0, "cpu", &cpu_list, "cpu", "list of cpus to profile"),
1294c1d3e633SJin Yao OPT_STRING(0, "pid", &symbol_conf.pid_list_str, "pid[,pid...]",
1295c1d3e633SJin Yao "only consider symbols in these pids"),
1296c1d3e633SJin Yao OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
1297c1d3e633SJin Yao "only consider symbols in these tids"),
12982a09a84cSJin Yao OPT_BOOLEAN(0, "stream", &pdiff.stream,
12992a09a84cSJin Yao "Enable hot streams comparison."),
130086a9eee0SArnaldo Carvalho de Melo OPT_END()
130186a9eee0SArnaldo Carvalho de Melo };
130286a9eee0SArnaldo Carvalho de Melo
baseline_percent(struct hist_entry * he)1303345dc0b4SJiri Olsa static double baseline_percent(struct hist_entry *he)
13041d77822eSJiri Olsa {
13058810f6ceSNamhyung Kim u64 total = hists__total_period(he->hists);
13068810f6ceSNamhyung Kim
13078810f6ceSNamhyung Kim return 100.0 * he->stat.period / total;
1308345dc0b4SJiri Olsa }
13097aaf6b35SJiri Olsa
hpp__color_baseline(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)1310345dc0b4SJiri Olsa static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
1311345dc0b4SJiri Olsa struct perf_hpp *hpp, struct hist_entry *he)
1312345dc0b4SJiri Olsa {
1313345dc0b4SJiri Olsa struct diff_hpp_fmt *dfmt =
1314345dc0b4SJiri Olsa container_of(fmt, struct diff_hpp_fmt, fmt);
1315345dc0b4SJiri Olsa double percent = baseline_percent(he);
1316345dc0b4SJiri Olsa char pfmt[20] = " ";
1317345dc0b4SJiri Olsa
1318345dc0b4SJiri Olsa if (!he->dummy) {
1319345dc0b4SJiri Olsa scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1);
1320345dc0b4SJiri Olsa return percent_color_snprintf(hpp->buf, hpp->size,
1321345dc0b4SJiri Olsa pfmt, percent);
1322345dc0b4SJiri Olsa } else
1323345dc0b4SJiri Olsa return scnprintf(hpp->buf, hpp->size, "%*s",
1324345dc0b4SJiri Olsa dfmt->header_width, pfmt);
1325345dc0b4SJiri Olsa }
1326345dc0b4SJiri Olsa
hpp__entry_baseline(struct hist_entry * he,char * buf,size_t size)1327345dc0b4SJiri Olsa static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
1328345dc0b4SJiri Olsa {
1329345dc0b4SJiri Olsa double percent = baseline_percent(he);
1330345dc0b4SJiri Olsa const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
1331345dc0b4SJiri Olsa int ret = 0;
1332345dc0b4SJiri Olsa
1333345dc0b4SJiri Olsa if (!he->dummy)
1334345dc0b4SJiri Olsa ret = scnprintf(buf, size, fmt, percent);
1335345dc0b4SJiri Olsa
1336345dc0b4SJiri Olsa return ret;
1337345dc0b4SJiri Olsa }
1338345dc0b4SJiri Olsa
cycles_printf(struct hist_entry * he,struct hist_entry * pair,struct perf_hpp * hpp,int width)1339b10c78c5SJin Yao static int cycles_printf(struct hist_entry *he, struct hist_entry *pair,
1340b10c78c5SJin Yao struct perf_hpp *hpp, int width)
1341b10c78c5SJin Yao {
1342b10c78c5SJin Yao struct block_hist *bh = container_of(he, struct block_hist, he);
1343b10c78c5SJin Yao struct block_hist *bh_pair = container_of(pair, struct block_hist, he);
1344b10c78c5SJin Yao struct hist_entry *block_he;
1345b10c78c5SJin Yao struct block_info *bi;
1346b10c78c5SJin Yao char buf[128];
1347b10c78c5SJin Yao char *start_line, *end_line;
1348b10c78c5SJin Yao
1349b10c78c5SJin Yao block_he = hists__get_entry(&bh_pair->block_hists, bh->block_idx);
1350b10c78c5SJin Yao if (!block_he) {
1351b10c78c5SJin Yao hpp->skip = true;
1352b10c78c5SJin Yao return 0;
1353b10c78c5SJin Yao }
1354b10c78c5SJin Yao
1355b10c78c5SJin Yao /*
1356b10c78c5SJin Yao * Avoid printing the warning "addr2line_init failed for ..."
1357b10c78c5SJin Yao */
1358b10c78c5SJin Yao symbol_conf.disable_add2line_warn = true;
1359b10c78c5SJin Yao
1360b10c78c5SJin Yao bi = block_he->block_info;
1361b10c78c5SJin Yao
1362b10c78c5SJin Yao start_line = map__srcline(he->ms.map, bi->sym->start + bi->start,
1363b10c78c5SJin Yao he->ms.sym);
1364b10c78c5SJin Yao
1365b10c78c5SJin Yao end_line = map__srcline(he->ms.map, bi->sym->start + bi->end,
1366b10c78c5SJin Yao he->ms.sym);
1367b10c78c5SJin Yao
1368922db21dSArnaldo Carvalho de Melo if (start_line != SRCLINE_UNKNOWN &&
1369922db21dSArnaldo Carvalho de Melo end_line != SRCLINE_UNKNOWN) {
1370b10c78c5SJin Yao scnprintf(buf, sizeof(buf), "[%s -> %s] %4ld",
1371b10c78c5SJin Yao start_line, end_line, block_he->diff.cycles);
1372b10c78c5SJin Yao } else {
1373b10c78c5SJin Yao scnprintf(buf, sizeof(buf), "[%7lx -> %7lx] %4ld",
1374b10c78c5SJin Yao bi->start, bi->end, block_he->diff.cycles);
1375b10c78c5SJin Yao }
1376b10c78c5SJin Yao
1377625db36eSIan Rogers zfree_srcline(&start_line);
1378625db36eSIan Rogers zfree_srcline(&end_line);
1379b10c78c5SJin Yao
1380b10c78c5SJin Yao return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1381b10c78c5SJin Yao }
1382b10c78c5SJin Yao
__hpp__color_compare(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he,int comparison_method)138301f10bc8SRamkumar Ramachandra static int __hpp__color_compare(struct perf_hpp_fmt *fmt,
138401f10bc8SRamkumar Ramachandra struct perf_hpp *hpp, struct hist_entry *he,
138501f10bc8SRamkumar Ramachandra int comparison_method)
138601f10bc8SRamkumar Ramachandra {
138701f10bc8SRamkumar Ramachandra struct diff_hpp_fmt *dfmt =
138801f10bc8SRamkumar Ramachandra container_of(fmt, struct diff_hpp_fmt, fmt);
138901f10bc8SRamkumar Ramachandra struct hist_entry *pair = get_pair_fmt(he, dfmt);
139001f10bc8SRamkumar Ramachandra double diff;
1391a5846e21SRamkumar Ramachandra s64 wdiff;
139201f10bc8SRamkumar Ramachandra char pfmt[20] = " ";
139301f10bc8SRamkumar Ramachandra
1394b10c78c5SJin Yao if (!pair) {
1395b10c78c5SJin Yao if (comparison_method == COMPUTE_CYCLES) {
1396b10c78c5SJin Yao struct block_hist *bh;
1397b10c78c5SJin Yao
1398b10c78c5SJin Yao bh = container_of(he, struct block_hist, he);
1399b10c78c5SJin Yao if (bh->block_idx)
1400b10c78c5SJin Yao hpp->skip = true;
1401b10c78c5SJin Yao }
1402b10c78c5SJin Yao
1403ec3d07cbSNamhyung Kim goto no_print;
1404b10c78c5SJin Yao }
140501f10bc8SRamkumar Ramachandra
140601f10bc8SRamkumar Ramachandra switch (comparison_method) {
140701f10bc8SRamkumar Ramachandra case COMPUTE_DELTA:
140801f10bc8SRamkumar Ramachandra if (pair->diff.computed)
140901f10bc8SRamkumar Ramachandra diff = pair->diff.period_ratio_delta;
141001f10bc8SRamkumar Ramachandra else
141101f10bc8SRamkumar Ramachandra diff = compute_delta(he, pair);
141201f10bc8SRamkumar Ramachandra
141301f10bc8SRamkumar Ramachandra scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1);
141401f10bc8SRamkumar Ramachandra return percent_color_snprintf(hpp->buf, hpp->size,
141501f10bc8SRamkumar Ramachandra pfmt, diff);
14161f513b2cSRamkumar Ramachandra case COMPUTE_RATIO:
14171f513b2cSRamkumar Ramachandra if (he->dummy)
14181f513b2cSRamkumar Ramachandra goto dummy_print;
14191f513b2cSRamkumar Ramachandra if (pair->diff.computed)
14201f513b2cSRamkumar Ramachandra diff = pair->diff.period_ratio;
14211f513b2cSRamkumar Ramachandra else
14221f513b2cSRamkumar Ramachandra diff = compute_ratio(he, pair);
14231f513b2cSRamkumar Ramachandra
14241f513b2cSRamkumar Ramachandra scnprintf(pfmt, 20, "%%%d.6f", dfmt->header_width);
14251f513b2cSRamkumar Ramachandra return value_color_snprintf(hpp->buf, hpp->size,
14261f513b2cSRamkumar Ramachandra pfmt, diff);
1427a5846e21SRamkumar Ramachandra case COMPUTE_WEIGHTED_DIFF:
1428a5846e21SRamkumar Ramachandra if (he->dummy)
1429a5846e21SRamkumar Ramachandra goto dummy_print;
1430a5846e21SRamkumar Ramachandra if (pair->diff.computed)
1431a5846e21SRamkumar Ramachandra wdiff = pair->diff.wdiff;
1432a5846e21SRamkumar Ramachandra else
1433a5846e21SRamkumar Ramachandra wdiff = compute_wdiff(he, pair);
1434a5846e21SRamkumar Ramachandra
1435a5846e21SRamkumar Ramachandra scnprintf(pfmt, 20, "%%14ld", dfmt->header_width);
1436a5846e21SRamkumar Ramachandra return color_snprintf(hpp->buf, hpp->size,
1437a5846e21SRamkumar Ramachandra get_percent_color(wdiff),
1438a5846e21SRamkumar Ramachandra pfmt, wdiff);
1439b10c78c5SJin Yao case COMPUTE_CYCLES:
1440b10c78c5SJin Yao return cycles_printf(he, pair, hpp, dfmt->header_width);
144101f10bc8SRamkumar Ramachandra default:
144201f10bc8SRamkumar Ramachandra BUG_ON(1);
144301f10bc8SRamkumar Ramachandra }
144401f10bc8SRamkumar Ramachandra dummy_print:
144501f10bc8SRamkumar Ramachandra return scnprintf(hpp->buf, hpp->size, "%*s",
1446ec3d07cbSNamhyung Kim dfmt->header_width, "N/A");
1447ec3d07cbSNamhyung Kim no_print:
1448ec3d07cbSNamhyung Kim return scnprintf(hpp->buf, hpp->size, "%*s",
144901f10bc8SRamkumar Ramachandra dfmt->header_width, pfmt);
145001f10bc8SRamkumar Ramachandra }
145101f10bc8SRamkumar Ramachandra
hpp__color_delta(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)145201f10bc8SRamkumar Ramachandra static int hpp__color_delta(struct perf_hpp_fmt *fmt,
145301f10bc8SRamkumar Ramachandra struct perf_hpp *hpp, struct hist_entry *he)
145401f10bc8SRamkumar Ramachandra {
145501f10bc8SRamkumar Ramachandra return __hpp__color_compare(fmt, hpp, he, COMPUTE_DELTA);
145601f10bc8SRamkumar Ramachandra }
145701f10bc8SRamkumar Ramachandra
hpp__color_ratio(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)14581f513b2cSRamkumar Ramachandra static int hpp__color_ratio(struct perf_hpp_fmt *fmt,
14591f513b2cSRamkumar Ramachandra struct perf_hpp *hpp, struct hist_entry *he)
14601f513b2cSRamkumar Ramachandra {
14611f513b2cSRamkumar Ramachandra return __hpp__color_compare(fmt, hpp, he, COMPUTE_RATIO);
14621f513b2cSRamkumar Ramachandra }
14631f513b2cSRamkumar Ramachandra
hpp__color_wdiff(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)1464a5846e21SRamkumar Ramachandra static int hpp__color_wdiff(struct perf_hpp_fmt *fmt,
1465a5846e21SRamkumar Ramachandra struct perf_hpp *hpp, struct hist_entry *he)
1466a5846e21SRamkumar Ramachandra {
1467a5846e21SRamkumar Ramachandra return __hpp__color_compare(fmt, hpp, he, COMPUTE_WEIGHTED_DIFF);
1468a5846e21SRamkumar Ramachandra }
1469a5846e21SRamkumar Ramachandra
hpp__color_cycles(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)1470b10c78c5SJin Yao static int hpp__color_cycles(struct perf_hpp_fmt *fmt,
1471b10c78c5SJin Yao struct perf_hpp *hpp, struct hist_entry *he)
1472b10c78c5SJin Yao {
1473b10c78c5SJin Yao return __hpp__color_compare(fmt, hpp, he, COMPUTE_CYCLES);
1474b10c78c5SJin Yao }
1475b10c78c5SJin Yao
all_zero(unsigned long * vals,int len)1476cebf7d51SJin Yao static int all_zero(unsigned long *vals, int len)
1477cebf7d51SJin Yao {
1478cebf7d51SJin Yao int i;
1479cebf7d51SJin Yao
1480cebf7d51SJin Yao for (i = 0; i < len; i++)
1481cebf7d51SJin Yao if (vals[i] != 0)
1482cebf7d51SJin Yao return 0;
1483cebf7d51SJin Yao return 1;
1484cebf7d51SJin Yao }
1485cebf7d51SJin Yao
print_cycles_spark(char * bf,int size,unsigned long * svals,u64 n)1486cebf7d51SJin Yao static int print_cycles_spark(char *bf, int size, unsigned long *svals, u64 n)
1487cebf7d51SJin Yao {
1488cebf7d51SJin Yao int printed;
1489cebf7d51SJin Yao
1490cebf7d51SJin Yao if (n <= 1)
1491cebf7d51SJin Yao return 0;
1492cebf7d51SJin Yao
1493cebf7d51SJin Yao if (n > NUM_SPARKS)
1494cebf7d51SJin Yao n = NUM_SPARKS;
1495cebf7d51SJin Yao if (all_zero(svals, n))
1496cebf7d51SJin Yao return 0;
1497cebf7d51SJin Yao
1498cebf7d51SJin Yao printed = print_spark(bf, size, svals, n);
1499cebf7d51SJin Yao printed += scnprintf(bf + printed, size - printed, " ");
1500cebf7d51SJin Yao return printed;
1501cebf7d51SJin Yao }
1502cebf7d51SJin Yao
hpp__color_cycles_hist(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)1503cebf7d51SJin Yao static int hpp__color_cycles_hist(struct perf_hpp_fmt *fmt,
1504cebf7d51SJin Yao struct perf_hpp *hpp, struct hist_entry *he)
1505cebf7d51SJin Yao {
1506cebf7d51SJin Yao struct diff_hpp_fmt *dfmt =
1507cebf7d51SJin Yao container_of(fmt, struct diff_hpp_fmt, fmt);
1508cebf7d51SJin Yao struct hist_entry *pair = get_pair_fmt(he, dfmt);
1509cebf7d51SJin Yao struct block_hist *bh = container_of(he, struct block_hist, he);
1510cebf7d51SJin Yao struct block_hist *bh_pair;
1511cebf7d51SJin Yao struct hist_entry *block_he;
1512cebf7d51SJin Yao char spark[32], buf[128];
1513cebf7d51SJin Yao double r;
1514cebf7d51SJin Yao int ret, pad;
1515cebf7d51SJin Yao
1516cebf7d51SJin Yao if (!pair) {
1517cebf7d51SJin Yao if (bh->block_idx)
1518cebf7d51SJin Yao hpp->skip = true;
1519cebf7d51SJin Yao
1520cebf7d51SJin Yao goto no_print;
1521cebf7d51SJin Yao }
1522cebf7d51SJin Yao
1523cebf7d51SJin Yao bh_pair = container_of(pair, struct block_hist, he);
1524cebf7d51SJin Yao
1525cebf7d51SJin Yao block_he = hists__get_entry(&bh_pair->block_hists, bh->block_idx);
1526cebf7d51SJin Yao if (!block_he) {
1527cebf7d51SJin Yao hpp->skip = true;
1528cebf7d51SJin Yao goto no_print;
1529cebf7d51SJin Yao }
1530cebf7d51SJin Yao
1531cebf7d51SJin Yao ret = print_cycles_spark(spark, sizeof(spark), block_he->diff.svals,
1532cebf7d51SJin Yao block_he->diff.stats.n);
1533cebf7d51SJin Yao
1534cebf7d51SJin Yao r = rel_stddev_stats(stddev_stats(&block_he->diff.stats),
1535cebf7d51SJin Yao avg_stats(&block_he->diff.stats));
1536cebf7d51SJin Yao
1537cebf7d51SJin Yao if (ret) {
1538cebf7d51SJin Yao /*
1539cebf7d51SJin Yao * Padding spaces if number of sparks less than NUM_SPARKS
1540cebf7d51SJin Yao * otherwise the output is not aligned.
1541cebf7d51SJin Yao */
1542cebf7d51SJin Yao pad = NUM_SPARKS - ((ret - 1) / 3);
1543cebf7d51SJin Yao scnprintf(buf, sizeof(buf), "%s%5.1f%% %s", "\u00B1", r, spark);
1544cebf7d51SJin Yao ret = scnprintf(hpp->buf, hpp->size, "%*s",
1545cebf7d51SJin Yao dfmt->header_width, buf);
1546cebf7d51SJin Yao
1547cebf7d51SJin Yao if (pad) {
1548cebf7d51SJin Yao ret += scnprintf(hpp->buf + ret, hpp->size - ret,
1549cebf7d51SJin Yao "%-*s", pad, " ");
1550cebf7d51SJin Yao }
1551cebf7d51SJin Yao
1552cebf7d51SJin Yao return ret;
1553cebf7d51SJin Yao }
1554cebf7d51SJin Yao
1555cebf7d51SJin Yao no_print:
1556cebf7d51SJin Yao return scnprintf(hpp->buf, hpp->size, "%*s",
1557cebf7d51SJin Yao dfmt->header_width, " ");
1558cebf7d51SJin Yao }
1559cebf7d51SJin Yao
1560345dc0b4SJiri Olsa static void
hpp__entry_unpair(struct hist_entry * he,int idx,char * buf,size_t size)1561345dc0b4SJiri Olsa hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
1562345dc0b4SJiri Olsa {
1563345dc0b4SJiri Olsa switch (idx) {
1564345dc0b4SJiri Olsa case PERF_HPP_DIFF__PERIOD_BASELINE:
1565345dc0b4SJiri Olsa scnprintf(buf, size, "%" PRIu64, he->stat.period);
15667aaf6b35SJiri Olsa break;
1567345dc0b4SJiri Olsa
1568345dc0b4SJiri Olsa default:
15697aaf6b35SJiri Olsa break;
1570345dc0b4SJiri Olsa }
1571345dc0b4SJiri Olsa }
1572345dc0b4SJiri Olsa
1573345dc0b4SJiri Olsa static void
hpp__entry_pair(struct hist_entry * he,struct hist_entry * pair,int idx,char * buf,size_t size)1574345dc0b4SJiri Olsa hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
1575345dc0b4SJiri Olsa int idx, char *buf, size_t size)
1576345dc0b4SJiri Olsa {
1577345dc0b4SJiri Olsa double diff;
1578345dc0b4SJiri Olsa double ratio;
1579345dc0b4SJiri Olsa s64 wdiff;
1580345dc0b4SJiri Olsa
1581345dc0b4SJiri Olsa switch (idx) {
1582345dc0b4SJiri Olsa case PERF_HPP_DIFF__DELTA:
1583a1668c25SNamhyung Kim case PERF_HPP_DIFF__DELTA_ABS:
1584345dc0b4SJiri Olsa if (pair->diff.computed)
1585345dc0b4SJiri Olsa diff = pair->diff.period_ratio_delta;
1586345dc0b4SJiri Olsa else
1587ef358e6dSJiri Olsa diff = compute_delta(he, pair);
1588345dc0b4SJiri Olsa
1589345dc0b4SJiri Olsa scnprintf(buf, size, "%+4.2F%%", diff);
159081d5f958SJiri Olsa break;
1591345dc0b4SJiri Olsa
1592345dc0b4SJiri Olsa case PERF_HPP_DIFF__RATIO:
1593345dc0b4SJiri Olsa /* No point for ratio number if we are dummy.. */
1594ec3d07cbSNamhyung Kim if (he->dummy) {
1595ec3d07cbSNamhyung Kim scnprintf(buf, size, "N/A");
1596345dc0b4SJiri Olsa break;
1597ec3d07cbSNamhyung Kim }
1598345dc0b4SJiri Olsa
1599345dc0b4SJiri Olsa if (pair->diff.computed)
1600345dc0b4SJiri Olsa ratio = pair->diff.period_ratio;
1601345dc0b4SJiri Olsa else
1602ef358e6dSJiri Olsa ratio = compute_ratio(he, pair);
1603345dc0b4SJiri Olsa
1604345dc0b4SJiri Olsa if (ratio > 0.0)
1605345dc0b4SJiri Olsa scnprintf(buf, size, "%14.6F", ratio);
1606345dc0b4SJiri Olsa break;
1607345dc0b4SJiri Olsa
1608345dc0b4SJiri Olsa case PERF_HPP_DIFF__WEIGHTED_DIFF:
1609345dc0b4SJiri Olsa /* No point for wdiff number if we are dummy.. */
1610ec3d07cbSNamhyung Kim if (he->dummy) {
1611ec3d07cbSNamhyung Kim scnprintf(buf, size, "N/A");
1612345dc0b4SJiri Olsa break;
1613ec3d07cbSNamhyung Kim }
1614345dc0b4SJiri Olsa
1615345dc0b4SJiri Olsa if (pair->diff.computed)
1616345dc0b4SJiri Olsa wdiff = pair->diff.wdiff;
1617345dc0b4SJiri Olsa else
1618ef358e6dSJiri Olsa wdiff = compute_wdiff(he, pair);
1619345dc0b4SJiri Olsa
1620345dc0b4SJiri Olsa if (wdiff != 0)
1621345dc0b4SJiri Olsa scnprintf(buf, size, "%14ld", wdiff);
1622345dc0b4SJiri Olsa break;
1623345dc0b4SJiri Olsa
1624345dc0b4SJiri Olsa case PERF_HPP_DIFF__FORMULA:
1625ef358e6dSJiri Olsa formula_fprintf(he, pair, buf, size);
1626345dc0b4SJiri Olsa break;
1627345dc0b4SJiri Olsa
1628345dc0b4SJiri Olsa case PERF_HPP_DIFF__PERIOD:
1629345dc0b4SJiri Olsa scnprintf(buf, size, "%" PRIu64, pair->stat.period);
1630345dc0b4SJiri Olsa break;
1631345dc0b4SJiri Olsa
16327aaf6b35SJiri Olsa default:
16337aaf6b35SJiri Olsa BUG_ON(1);
16348284bbeaSZou Wei }
1635345dc0b4SJiri Olsa }
1636345dc0b4SJiri Olsa
163722aeb7f5SJiri Olsa static void
__hpp__entry_global(struct hist_entry * he,struct diff_hpp_fmt * dfmt,char * buf,size_t size)163822aeb7f5SJiri Olsa __hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt,
163922aeb7f5SJiri Olsa char *buf, size_t size)
164022aeb7f5SJiri Olsa {
16415f3f8d3bSJiri Olsa struct hist_entry *pair = get_pair_fmt(he, dfmt);
164222aeb7f5SJiri Olsa int idx = dfmt->idx;
1643345dc0b4SJiri Olsa
1644345dc0b4SJiri Olsa /* baseline is special */
1645345dc0b4SJiri Olsa if (idx == PERF_HPP_DIFF__BASELINE)
1646345dc0b4SJiri Olsa hpp__entry_baseline(he, buf, size);
1647345dc0b4SJiri Olsa else {
1648345dc0b4SJiri Olsa if (pair)
1649345dc0b4SJiri Olsa hpp__entry_pair(he, pair, idx, buf, size);
1650345dc0b4SJiri Olsa else
1651345dc0b4SJiri Olsa hpp__entry_unpair(he, idx, buf, size);
1652345dc0b4SJiri Olsa }
1653345dc0b4SJiri Olsa }
1654345dc0b4SJiri Olsa
hpp__entry_global(struct perf_hpp_fmt * _fmt,struct perf_hpp * hpp,struct hist_entry * he)1655345dc0b4SJiri Olsa static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
1656345dc0b4SJiri Olsa struct hist_entry *he)
1657345dc0b4SJiri Olsa {
1658345dc0b4SJiri Olsa struct diff_hpp_fmt *dfmt =
1659345dc0b4SJiri Olsa container_of(_fmt, struct diff_hpp_fmt, fmt);
1660345dc0b4SJiri Olsa char buf[MAX_COL_WIDTH] = " ";
1661345dc0b4SJiri Olsa
166222aeb7f5SJiri Olsa __hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH);
1663345dc0b4SJiri Olsa
1664345dc0b4SJiri Olsa if (symbol_conf.field_sep)
1665345dc0b4SJiri Olsa return scnprintf(hpp->buf, hpp->size, "%s", buf);
1666345dc0b4SJiri Olsa else
1667345dc0b4SJiri Olsa return scnprintf(hpp->buf, hpp->size, "%*s",
1668345dc0b4SJiri Olsa dfmt->header_width, buf);
1669345dc0b4SJiri Olsa }
1670345dc0b4SJiri Olsa
hpp__header(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hists * hists __maybe_unused,int line __maybe_unused,int * span __maybe_unused)167194a0793dSNamhyung Kim static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
167274bb43f2SJiri Olsa struct hists *hists __maybe_unused,
167329659ab4SJiri Olsa int line __maybe_unused,
167429659ab4SJiri Olsa int *span __maybe_unused)
1675345dc0b4SJiri Olsa {
1676345dc0b4SJiri Olsa struct diff_hpp_fmt *dfmt =
1677345dc0b4SJiri Olsa container_of(fmt, struct diff_hpp_fmt, fmt);
1678345dc0b4SJiri Olsa
1679345dc0b4SJiri Olsa BUG_ON(!dfmt->header);
1680345dc0b4SJiri Olsa return scnprintf(hpp->buf, hpp->size, dfmt->header);
1681345dc0b4SJiri Olsa }
1682345dc0b4SJiri Olsa
hpp__width(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp __maybe_unused,struct hists * hists __maybe_unused)1683345dc0b4SJiri Olsa static int hpp__width(struct perf_hpp_fmt *fmt,
168494a0793dSNamhyung Kim struct perf_hpp *hpp __maybe_unused,
1685da1b0407SJiri Olsa struct hists *hists __maybe_unused)
1686345dc0b4SJiri Olsa {
1687345dc0b4SJiri Olsa struct diff_hpp_fmt *dfmt =
1688345dc0b4SJiri Olsa container_of(fmt, struct diff_hpp_fmt, fmt);
1689345dc0b4SJiri Olsa
1690345dc0b4SJiri Olsa BUG_ON(dfmt->header_width <= 0);
1691345dc0b4SJiri Olsa return dfmt->header_width;
1692345dc0b4SJiri Olsa }
1693345dc0b4SJiri Olsa
init_header(struct data__file * d,struct diff_hpp_fmt * dfmt)169422aeb7f5SJiri Olsa static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt)
1695345dc0b4SJiri Olsa {
1696345dc0b4SJiri Olsa #define MAX_HEADER_NAME 100
1697345dc0b4SJiri Olsa char buf_indent[MAX_HEADER_NAME];
1698345dc0b4SJiri Olsa char buf[MAX_HEADER_NAME];
1699345dc0b4SJiri Olsa const char *header = NULL;
1700345dc0b4SJiri Olsa int width = 0;
1701345dc0b4SJiri Olsa
1702345dc0b4SJiri Olsa BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX);
1703345dc0b4SJiri Olsa header = columns[dfmt->idx].name;
1704345dc0b4SJiri Olsa width = columns[dfmt->idx].width;
1705345dc0b4SJiri Olsa
1706345dc0b4SJiri Olsa /* Only our defined HPP fmts should appear here. */
1707345dc0b4SJiri Olsa BUG_ON(!header);
1708345dc0b4SJiri Olsa
170922aeb7f5SJiri Olsa if (data__files_cnt > 2)
171022aeb7f5SJiri Olsa scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx);
171122aeb7f5SJiri Olsa
1712345dc0b4SJiri Olsa #define NAME (data__files_cnt > 2 ? buf : header)
1713345dc0b4SJiri Olsa dfmt->header_width = width;
1714345dc0b4SJiri Olsa width = (int) strlen(NAME);
1715345dc0b4SJiri Olsa if (dfmt->header_width < width)
1716345dc0b4SJiri Olsa dfmt->header_width = width;
1717345dc0b4SJiri Olsa
1718345dc0b4SJiri Olsa scnprintf(buf_indent, MAX_HEADER_NAME, "%*s",
1719345dc0b4SJiri Olsa dfmt->header_width, NAME);
1720345dc0b4SJiri Olsa
1721345dc0b4SJiri Olsa dfmt->header = strdup(buf_indent);
1722345dc0b4SJiri Olsa #undef MAX_HEADER_NAME
1723345dc0b4SJiri Olsa #undef NAME
1724345dc0b4SJiri Olsa }
1725345dc0b4SJiri Olsa
data__hpp_register(struct data__file * d,int idx)1726c818b498SJiri Olsa static void data__hpp_register(struct data__file *d, int idx)
1727345dc0b4SJiri Olsa {
1728c818b498SJiri Olsa struct diff_hpp_fmt *dfmt = &d->fmt[idx];
1729c818b498SJiri Olsa struct perf_hpp_fmt *fmt = &dfmt->fmt;
1730345dc0b4SJiri Olsa
1731c818b498SJiri Olsa dfmt->idx = idx;
1732c818b498SJiri Olsa
1733c818b498SJiri Olsa fmt->header = hpp__header;
1734c818b498SJiri Olsa fmt->width = hpp__width;
1735c818b498SJiri Olsa fmt->entry = hpp__entry_global;
1736e7024fc3SNamhyung Kim fmt->cmp = hist_entry__cmp_nop;
1737e7024fc3SNamhyung Kim fmt->collapse = hist_entry__cmp_nop;
1738c818b498SJiri Olsa
1739c818b498SJiri Olsa /* TODO more colors */
174001f10bc8SRamkumar Ramachandra switch (idx) {
174101f10bc8SRamkumar Ramachandra case PERF_HPP_DIFF__BASELINE:
1742c818b498SJiri Olsa fmt->color = hpp__color_baseline;
1743e7024fc3SNamhyung Kim fmt->sort = hist_entry__cmp_baseline;
174401f10bc8SRamkumar Ramachandra break;
174501f10bc8SRamkumar Ramachandra case PERF_HPP_DIFF__DELTA:
174601f10bc8SRamkumar Ramachandra fmt->color = hpp__color_delta;
1747e7024fc3SNamhyung Kim fmt->sort = hist_entry__cmp_delta;
174801f10bc8SRamkumar Ramachandra break;
17491f513b2cSRamkumar Ramachandra case PERF_HPP_DIFF__RATIO:
17501f513b2cSRamkumar Ramachandra fmt->color = hpp__color_ratio;
1751e7024fc3SNamhyung Kim fmt->sort = hist_entry__cmp_ratio;
17521f513b2cSRamkumar Ramachandra break;
1753a5846e21SRamkumar Ramachandra case PERF_HPP_DIFF__WEIGHTED_DIFF:
1754a5846e21SRamkumar Ramachandra fmt->color = hpp__color_wdiff;
1755e7024fc3SNamhyung Kim fmt->sort = hist_entry__cmp_wdiff;
1756a5846e21SRamkumar Ramachandra break;
1757a1668c25SNamhyung Kim case PERF_HPP_DIFF__DELTA_ABS:
1758a1668c25SNamhyung Kim fmt->color = hpp__color_delta;
1759a1668c25SNamhyung Kim fmt->sort = hist_entry__cmp_delta_abs;
1760a1668c25SNamhyung Kim break;
1761b10c78c5SJin Yao case PERF_HPP_DIFF__CYCLES:
1762b10c78c5SJin Yao fmt->color = hpp__color_cycles;
1763b10c78c5SJin Yao fmt->sort = hist_entry__cmp_nop;
1764b10c78c5SJin Yao break;
1765cebf7d51SJin Yao case PERF_HPP_DIFF__CYCLES_HIST:
1766cebf7d51SJin Yao fmt->color = hpp__color_cycles_hist;
1767cebf7d51SJin Yao fmt->sort = hist_entry__cmp_nop;
1768cebf7d51SJin Yao break;
176901f10bc8SRamkumar Ramachandra default:
1770e7024fc3SNamhyung Kim fmt->sort = hist_entry__cmp_nop;
177101f10bc8SRamkumar Ramachandra break;
177201f10bc8SRamkumar Ramachandra }
1773c818b498SJiri Olsa
177422aeb7f5SJiri Olsa init_header(d, dfmt);
1775c818b498SJiri Olsa perf_hpp__column_register(fmt);
1776e7024fc3SNamhyung Kim perf_hpp__register_sort_field(fmt);
1777345dc0b4SJiri Olsa }
1778345dc0b4SJiri Olsa
ui_init(void)1779566b5cfbSNamhyung Kim static int ui_init(void)
1780345dc0b4SJiri Olsa {
1781c818b498SJiri Olsa struct data__file *d;
1782566b5cfbSNamhyung Kim struct perf_hpp_fmt *fmt;
1783c818b498SJiri Olsa int i;
1784c818b498SJiri Olsa
1785c818b498SJiri Olsa data__for_each_file(i, d) {
1786c818b498SJiri Olsa
1787345dc0b4SJiri Olsa /*
17884d39c89fSIngo Molnar * Baseline or compute related columns:
1789c818b498SJiri Olsa *
1790c818b498SJiri Olsa * PERF_HPP_DIFF__BASELINE
1791c818b498SJiri Olsa * PERF_HPP_DIFF__DELTA
1792c818b498SJiri Olsa * PERF_HPP_DIFF__RATIO
1793c818b498SJiri Olsa * PERF_HPP_DIFF__WEIGHTED_DIFF
1794cebf7d51SJin Yao * PERF_HPP_DIFF__CYCLES
1795345dc0b4SJiri Olsa */
1796c818b498SJiri Olsa data__hpp_register(d, i ? compute_2_hpp[compute] :
1797c818b498SJiri Olsa PERF_HPP_DIFF__BASELINE);
17981d77822eSJiri Olsa
1799cebf7d51SJin Yao if (cycles_hist && i)
1800cebf7d51SJin Yao data__hpp_register(d, PERF_HPP_DIFF__CYCLES_HIST);
1801cebf7d51SJin Yao
1802c818b498SJiri Olsa /*
1803c818b498SJiri Olsa * And the rest:
1804c818b498SJiri Olsa *
1805c818b498SJiri Olsa * PERF_HPP_DIFF__FORMULA
1806c818b498SJiri Olsa * PERF_HPP_DIFF__PERIOD
1807c818b498SJiri Olsa * PERF_HPP_DIFF__PERIOD_BASELINE
1808c818b498SJiri Olsa */
1809c818b498SJiri Olsa if (show_formula && i)
1810c818b498SJiri Olsa data__hpp_register(d, PERF_HPP_DIFF__FORMULA);
1811ed279da2SJiri Olsa
1812c818b498SJiri Olsa if (show_period)
1813c818b498SJiri Olsa data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD :
1814c818b498SJiri Olsa PERF_HPP_DIFF__PERIOD_BASELINE);
181561949b21SJiri Olsa }
1816566b5cfbSNamhyung Kim
1817566b5cfbSNamhyung Kim if (!sort_compute)
1818566b5cfbSNamhyung Kim return 0;
1819566b5cfbSNamhyung Kim
1820566b5cfbSNamhyung Kim /*
1821566b5cfbSNamhyung Kim * Prepend an fmt to sort on columns at 'sort_compute' first.
1822566b5cfbSNamhyung Kim * This fmt is added only to the sort list but not to the
1823566b5cfbSNamhyung Kim * output fields list.
1824566b5cfbSNamhyung Kim *
1825566b5cfbSNamhyung Kim * Note that this column (data) can be compared twice - one
1826566b5cfbSNamhyung Kim * for this 'sort_compute' fmt and another for the normal
1827566b5cfbSNamhyung Kim * diff_hpp_fmt. But it shouldn't a problem as most entries
1828566b5cfbSNamhyung Kim * will be sorted out by first try or baseline and comparing
1829566b5cfbSNamhyung Kim * is not a costly operation.
1830566b5cfbSNamhyung Kim */
1831566b5cfbSNamhyung Kim fmt = zalloc(sizeof(*fmt));
1832566b5cfbSNamhyung Kim if (fmt == NULL) {
1833566b5cfbSNamhyung Kim pr_err("Memory allocation failed\n");
1834566b5cfbSNamhyung Kim return -1;
1835566b5cfbSNamhyung Kim }
1836566b5cfbSNamhyung Kim
1837566b5cfbSNamhyung Kim fmt->cmp = hist_entry__cmp_nop;
1838566b5cfbSNamhyung Kim fmt->collapse = hist_entry__cmp_nop;
1839566b5cfbSNamhyung Kim
1840566b5cfbSNamhyung Kim switch (compute) {
1841566b5cfbSNamhyung Kim case COMPUTE_DELTA:
1842566b5cfbSNamhyung Kim fmt->sort = hist_entry__cmp_delta_idx;
1843566b5cfbSNamhyung Kim break;
1844566b5cfbSNamhyung Kim case COMPUTE_RATIO:
1845566b5cfbSNamhyung Kim fmt->sort = hist_entry__cmp_ratio_idx;
1846566b5cfbSNamhyung Kim break;
1847566b5cfbSNamhyung Kim case COMPUTE_WEIGHTED_DIFF:
1848566b5cfbSNamhyung Kim fmt->sort = hist_entry__cmp_wdiff_idx;
1849566b5cfbSNamhyung Kim break;
1850a1668c25SNamhyung Kim case COMPUTE_DELTA_ABS:
1851a1668c25SNamhyung Kim fmt->sort = hist_entry__cmp_delta_abs_idx;
1852a1668c25SNamhyung Kim break;
185399150a1fSJin Yao case COMPUTE_CYCLES:
185499150a1fSJin Yao /*
185599150a1fSJin Yao * Should set since 'fmt->sort' is called without
185699150a1fSJin Yao * checking valid during sorting
185799150a1fSJin Yao */
185899150a1fSJin Yao fmt->sort = hist_entry__cmp_nop;
185999150a1fSJin Yao break;
1860566b5cfbSNamhyung Kim default:
1861566b5cfbSNamhyung Kim BUG_ON(1);
1862566b5cfbSNamhyung Kim }
1863566b5cfbSNamhyung Kim
1864a1c9f97fSNamhyung Kim perf_hpp__prepend_sort_field(fmt);
1865566b5cfbSNamhyung Kim return 0;
18661d77822eSJiri Olsa }
18671d77822eSJiri Olsa
data_init(int argc,const char ** argv)1868ec308426SJiri Olsa static int data_init(int argc, const char **argv)
186986a9eee0SArnaldo Carvalho de Melo {
1870ec308426SJiri Olsa struct data__file *d;
1871ec308426SJiri Olsa static const char *defaults[] = {
1872ec308426SJiri Olsa "perf.data.old",
1873ec308426SJiri Olsa "perf.data",
1874ec308426SJiri Olsa };
187522aeb7f5SJiri Olsa bool use_default = true;
1876ec308426SJiri Olsa int i;
1877ec308426SJiri Olsa
1878ec308426SJiri Olsa data__files_cnt = 2;
1879ec308426SJiri Olsa
188086a9eee0SArnaldo Carvalho de Melo if (argc) {
188122aeb7f5SJiri Olsa if (argc == 1)
1882ec308426SJiri Olsa defaults[1] = argv[0];
188322aeb7f5SJiri Olsa else {
188422aeb7f5SJiri Olsa data__files_cnt = argc;
188522aeb7f5SJiri Olsa use_default = false;
188622aeb7f5SJiri Olsa }
1887d8d9608fSDongsheng Yang } else if (perf_guest) {
1888ec308426SJiri Olsa defaults[0] = "perf.data.host";
1889ec308426SJiri Olsa defaults[1] = "perf.data.guest";
189086a9eee0SArnaldo Carvalho de Melo }
189186a9eee0SArnaldo Carvalho de Melo
18925f3f8d3bSJiri Olsa if (sort_compute >= (unsigned int) data__files_cnt) {
18935f3f8d3bSJiri Olsa pr_err("Order option out of limit.\n");
18945f3f8d3bSJiri Olsa return -EINVAL;
18955f3f8d3bSJiri Olsa }
18965f3f8d3bSJiri Olsa
1897ec308426SJiri Olsa data__files = zalloc(sizeof(*data__files) * data__files_cnt);
1898ec308426SJiri Olsa if (!data__files)
1899ec308426SJiri Olsa return -ENOMEM;
1900ec308426SJiri Olsa
1901ec308426SJiri Olsa data__for_each_file(i, d) {
19028ceb41d7SJiri Olsa struct perf_data *data = &d->data;
1903f5fc1412SJiri Olsa
19042d4f2799SJiri Olsa data->path = use_default ? defaults[i] : argv[i];
1905681f34d5SLu Hongfei data->mode = PERF_DATA_MODE_READ;
1906681f34d5SLu Hongfei data->force = force;
1907f5fc1412SJiri Olsa
1908ec308426SJiri Olsa d->idx = i;
1909ec308426SJiri Olsa }
1910ec308426SJiri Olsa
1911ec308426SJiri Olsa return 0;
1912ec308426SJiri Olsa }
1913ec308426SJiri Olsa
diff__config(const char * var,const char * value,void * cb __maybe_unused)1914d49dd15dSNamhyung Kim static int diff__config(const char *var, const char *value,
1915d49dd15dSNamhyung Kim void *cb __maybe_unused)
1916d49dd15dSNamhyung Kim {
1917d49dd15dSNamhyung Kim if (!strcmp(var, "diff.order")) {
191825ce4bb8SArnaldo Carvalho de Melo int ret;
191925ce4bb8SArnaldo Carvalho de Melo if (perf_config_int(&ret, var, value) < 0)
192025ce4bb8SArnaldo Carvalho de Melo return -1;
192125ce4bb8SArnaldo Carvalho de Melo sort_compute = ret;
1922d49dd15dSNamhyung Kim return 0;
1923d49dd15dSNamhyung Kim }
19244b35994aSNamhyung Kim if (!strcmp(var, "diff.compute")) {
19254b35994aSNamhyung Kim if (!strcmp(value, "delta")) {
19264b35994aSNamhyung Kim compute = COMPUTE_DELTA;
19274b35994aSNamhyung Kim } else if (!strcmp(value, "delta-abs")) {
19284b35994aSNamhyung Kim compute = COMPUTE_DELTA_ABS;
19294b35994aSNamhyung Kim } else if (!strcmp(value, "ratio")) {
19304b35994aSNamhyung Kim compute = COMPUTE_RATIO;
19314b35994aSNamhyung Kim } else if (!strcmp(value, "wdiff")) {
19324b35994aSNamhyung Kim compute = COMPUTE_WEIGHTED_DIFF;
19334b35994aSNamhyung Kim } else {
19344b35994aSNamhyung Kim pr_err("Invalid compute method: %s\n", value);
19354b35994aSNamhyung Kim return -1;
19364b35994aSNamhyung Kim }
19374b35994aSNamhyung Kim }
1938d49dd15dSNamhyung Kim
1939d49dd15dSNamhyung Kim return 0;
1940d49dd15dSNamhyung Kim }
1941d49dd15dSNamhyung Kim
cmd_diff(int argc,const char ** argv)1942b0ad8ea6SArnaldo Carvalho de Melo int cmd_diff(int argc, const char **argv)
1943ec308426SJiri Olsa {
19449ab1f508SKan Liang int ret = hists__init();
19459ab1f508SKan Liang
19469ab1f508SKan Liang if (ret < 0)
19479ab1f508SKan Liang return ret;
19489ab1f508SKan Liang
19491e1ec8f2SIan Rogers perf_tool__init(&pdiff.tool, /*ordered_events=*/true);
19501e1ec8f2SIan Rogers pdiff.tool.sample = diff__process_sample_event;
19511e1ec8f2SIan Rogers pdiff.tool.mmap = perf_event__process_mmap;
19521e1ec8f2SIan Rogers pdiff.tool.mmap2 = perf_event__process_mmap2;
19531e1ec8f2SIan Rogers pdiff.tool.comm = perf_event__process_comm;
19541e1ec8f2SIan Rogers pdiff.tool.exit = perf_event__process_exit;
19551e1ec8f2SIan Rogers pdiff.tool.fork = perf_event__process_fork;
19561e1ec8f2SIan Rogers pdiff.tool.lost = perf_event__process_lost;
19571e1ec8f2SIan Rogers pdiff.tool.namespaces = perf_event__process_namespaces;
19581e1ec8f2SIan Rogers pdiff.tool.cgroup = perf_event__process_cgroup;
19591e1ec8f2SIan Rogers pdiff.tool.ordering_requires_timestamps = true;
19601e1ec8f2SIan Rogers
1961d49dd15dSNamhyung Kim perf_config(diff__config, NULL);
1962d49dd15dSNamhyung Kim
1963ec308426SJiri Olsa argc = parse_options(argc, argv, options, diff_usage, 0);
1964ec308426SJiri Olsa
196563b42fceSNamhyung Kim if (quiet)
196663b42fceSNamhyung Kim perf_quiet_option();
196763b42fceSNamhyung Kim
1968cebf7d51SJin Yao if (cycles_hist && (compute != COMPUTE_CYCLES))
1969cebf7d51SJin Yao usage_with_options(diff_usage, options);
1970cebf7d51SJin Yao
19712a09a84cSJin Yao if (pdiff.stream)
19722a09a84cSJin Yao compute = COMPUTE_STREAM;
19732a09a84cSJin Yao
197499150a1fSJin Yao symbol__annotation_init();
197599150a1fSJin Yao
19760a7e6d1bSNamhyung Kim if (symbol__init(NULL) < 0)
1977655000e7SArnaldo Carvalho de Melo return -1;
1978655000e7SArnaldo Carvalho de Melo
1979ec308426SJiri Olsa if (data_init(argc, argv) < 0)
1980ec308426SJiri Olsa return -1;
1981ec308426SJiri Olsa
198230d81553SJin Yao if (check_file_brstack() < 0)
198330d81553SJin Yao return -1;
198430d81553SJin Yao
19852a09a84cSJin Yao if ((compute == COMPUTE_CYCLES || compute == COMPUTE_STREAM)
19862a09a84cSJin Yao && !pdiff.has_br_stack) {
198799150a1fSJin Yao return -1;
19882a09a84cSJin Yao }
198999150a1fSJin Yao
19902a09a84cSJin Yao if (compute == COMPUTE_STREAM) {
19912a09a84cSJin Yao symbol_conf.show_branchflag_count = true;
19922a09a84cSJin Yao symbol_conf.disable_add2line_warn = true;
19932a09a84cSJin Yao callchain_param.mode = CHAIN_FLAT;
19942a09a84cSJin Yao callchain_param.key = CCKEY_SRCLINE;
19952a09a84cSJin Yao callchain_param.branch_callstack = 1;
19962a09a84cSJin Yao symbol_conf.use_callchain = true;
19972a09a84cSJin Yao callchain_register_param(&callchain_param);
19982a09a84cSJin Yao sort_order = "srcline,symbol,dso";
19992a09a84cSJin Yao } else {
2000566b5cfbSNamhyung Kim if (ui_init() < 0)
2001566b5cfbSNamhyung Kim return -1;
20021d77822eSJiri Olsa
2003512ae1bdSNamhyung Kim sort__mode = SORT_MODE__DIFF;
20042a09a84cSJin Yao }
2005512ae1bdSNamhyung Kim
200640184c46SNamhyung Kim if (setup_sorting(NULL) < 0)
200755309985SNamhyung Kim usage_with_options(diff_usage, options);
200855309985SNamhyung Kim
200986a9eee0SArnaldo Carvalho de Melo setup_pager();
2010c351c281SArnaldo Carvalho de Melo
201108e71542SNamhyung Kim sort__setup_elide(NULL);
2012c351c281SArnaldo Carvalho de Melo
201386a9eee0SArnaldo Carvalho de Melo return __cmd_diff();
201486a9eee0SArnaldo Carvalho de Melo }
2015