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"
986a9eee0SArnaldo Carvalho de Melo
1086a9eee0SArnaldo Carvalho de Melo #include "util/debug.h"
1186a9eee0SArnaldo Carvalho de Melo #include "util/event.h"
1286a9eee0SArnaldo Carvalho de Melo #include "util/hist.h"
13743eb868SArnaldo Carvalho de Melo #include "util/evsel.h"
14863e451fSJiri Olsa #include "util/evlist.h"
1586a9eee0SArnaldo Carvalho de Melo #include "util/session.h"
1645694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
1786a9eee0SArnaldo Carvalho de Melo #include "util/sort.h"
1897b9d866SArnaldo Carvalho de Melo #include "util/srcline.h"
1986a9eee0SArnaldo Carvalho de Melo #include "util/symbol.h"
20f5fc1412SJiri Olsa #include "util/data.h"
21d49dd15dSNamhyung Kim #include "util/config.h"
224802138dSJin Yao #include "util/time-utils.h"
2399150a1fSJin Yao #include "util/annotate.h"
24b10c78c5SJin Yao #include "util/map.h"
25cebf7d51SJin Yao #include "util/spark.h"
2660414418SJin Yao #include "util/block-info.h"
272a09a84cSJin Yao #include "util/stream.h"
28ea0c5239SIan Rogers #include "util/util.h"
296ef81c55SMamatha Inamdar #include <linux/err.h>
307f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
318520a98dSArnaldo Carvalho de Melo #include <subcmd/pager.h>
3297b9d866SArnaldo Carvalho de Melo #include <subcmd/parse-options.h>
3386a9eee0SArnaldo Carvalho de Melo
34a43783aeSArnaldo Carvalho de Melo #include <errno.h>
35fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
3686a9eee0SArnaldo Carvalho de Melo #include <stdlib.h>
37345dc0b4SJiri Olsa #include <math.h>
38345dc0b4SJiri Olsa
394802138dSJin Yao struct perf_diff {
404802138dSJin Yao struct perf_tool tool;
414802138dSJin Yao const char *time_str;
424802138dSJin Yao struct perf_time_interval *ptime_range;
434802138dSJin Yao int range_size;
444802138dSJin Yao int range_num;
4530d81553SJin Yao bool has_br_stack;
462a09a84cSJin Yao bool stream;
474802138dSJin Yao };
484802138dSJin Yao
49345dc0b4SJiri Olsa /* Diff command specific HPP columns. */
50345dc0b4SJiri Olsa enum {
51345dc0b4SJiri Olsa PERF_HPP_DIFF__BASELINE,
52345dc0b4SJiri Olsa PERF_HPP_DIFF__PERIOD,
53345dc0b4SJiri Olsa PERF_HPP_DIFF__PERIOD_BASELINE,
54345dc0b4SJiri Olsa PERF_HPP_DIFF__DELTA,
55345dc0b4SJiri Olsa PERF_HPP_DIFF__RATIO,
56345dc0b4SJiri Olsa PERF_HPP_DIFF__WEIGHTED_DIFF,
57345dc0b4SJiri Olsa PERF_HPP_DIFF__FORMULA,
58a1668c25SNamhyung Kim PERF_HPP_DIFF__DELTA_ABS,
59b10c78c5SJin Yao PERF_HPP_DIFF__CYCLES,
60cebf7d51SJin Yao PERF_HPP_DIFF__CYCLES_HIST,
61345dc0b4SJiri Olsa
62345dc0b4SJiri Olsa PERF_HPP_DIFF__MAX_INDEX
63345dc0b4SJiri Olsa };
64345dc0b4SJiri Olsa
65345dc0b4SJiri Olsa struct diff_hpp_fmt {
66345dc0b4SJiri Olsa struct perf_hpp_fmt fmt;
67345dc0b4SJiri Olsa int idx;
68345dc0b4SJiri Olsa char *header;
69345dc0b4SJiri Olsa int header_width;
70345dc0b4SJiri Olsa };
7186a9eee0SArnaldo Carvalho de Melo
72ec308426SJiri Olsa struct data__file {
73ec308426SJiri Olsa struct perf_session *session;
748ceb41d7SJiri Olsa struct perf_data data;
75ec308426SJiri Olsa int idx;
7622aeb7f5SJiri Olsa struct hists *hists;
772a09a84cSJin Yao struct evlist_streams *evlist_streams;
78c818b498SJiri Olsa struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
79ec308426SJiri Olsa };
80ec308426SJiri Olsa
81ec308426SJiri Olsa static struct data__file *data__files;
82ec308426SJiri Olsa static int data__files_cnt;
83ec308426SJiri Olsa
84ec308426SJiri Olsa #define data__for_each_file_start(i, d, s) \
85ec308426SJiri Olsa for (i = s, d = &data__files[s]; \
86ec308426SJiri Olsa i < data__files_cnt; \
87ec308426SJiri Olsa i++, d = &data__files[i])
88ec308426SJiri Olsa
89ec308426SJiri Olsa #define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
9022aeb7f5SJiri Olsa #define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
91ec308426SJiri Olsa
92c0555642SIan Munsie static bool force;
9361949b21SJiri Olsa static bool show_period;
94ed279da2SJiri Olsa static bool show_formula;
95a06d143eSJiri Olsa static bool show_baseline_only;
96cebf7d51SJin Yao static bool cycles_hist;
97be57b3fdSNamhyung Kim static unsigned int sort_compute = 1;
9886a9eee0SArnaldo Carvalho de Melo
9981d5f958SJiri Olsa static s64 compute_wdiff_w1;
10081d5f958SJiri Olsa static s64 compute_wdiff_w2;
10181d5f958SJiri Olsa
102daca23b2SJin Yao static const char *cpu_list;
103daca23b2SJin Yao static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
104daca23b2SJin Yao
1057aaf6b35SJiri Olsa enum {
1067aaf6b35SJiri Olsa COMPUTE_DELTA,
1077aaf6b35SJiri Olsa COMPUTE_RATIO,
10881d5f958SJiri Olsa COMPUTE_WEIGHTED_DIFF,
109a1668c25SNamhyung Kim COMPUTE_DELTA_ABS,
11099150a1fSJin Yao COMPUTE_CYCLES,
1117aaf6b35SJiri Olsa COMPUTE_MAX,
1122a09a84cSJin Yao COMPUTE_STREAM, /* After COMPUTE_MAX to avoid use current compute arrays */
1137aaf6b35SJiri Olsa };
1147aaf6b35SJiri Olsa
1157aaf6b35SJiri Olsa const char *compute_names[COMPUTE_MAX] = {
1167aaf6b35SJiri Olsa [COMPUTE_DELTA] = "delta",
117a1668c25SNamhyung Kim [COMPUTE_DELTA_ABS] = "delta-abs",
1187aaf6b35SJiri Olsa [COMPUTE_RATIO] = "ratio",
11981d5f958SJiri Olsa [COMPUTE_WEIGHTED_DIFF] = "wdiff",
12099150a1fSJin Yao [COMPUTE_CYCLES] = "cycles",
1217aaf6b35SJiri Olsa };
1227aaf6b35SJiri Olsa
123be57b3fdSNamhyung Kim static int compute = COMPUTE_DELTA_ABS;
1247aaf6b35SJiri Olsa
125345dc0b4SJiri Olsa static int compute_2_hpp[COMPUTE_MAX] = {
126345dc0b4SJiri Olsa [COMPUTE_DELTA] = PERF_HPP_DIFF__DELTA,
127a1668c25SNamhyung Kim [COMPUTE_DELTA_ABS] = PERF_HPP_DIFF__DELTA_ABS,
128345dc0b4SJiri Olsa [COMPUTE_RATIO] = PERF_HPP_DIFF__RATIO,
129345dc0b4SJiri Olsa [COMPUTE_WEIGHTED_DIFF] = PERF_HPP_DIFF__WEIGHTED_DIFF,
130b10c78c5SJin Yao [COMPUTE_CYCLES] = PERF_HPP_DIFF__CYCLES,
131345dc0b4SJiri Olsa };
132345dc0b4SJiri Olsa
133345dc0b4SJiri Olsa #define MAX_COL_WIDTH 70
134345dc0b4SJiri Olsa
135345dc0b4SJiri Olsa static struct header_column {
136345dc0b4SJiri Olsa const char *name;
137345dc0b4SJiri Olsa int width;
138345dc0b4SJiri Olsa } columns[PERF_HPP_DIFF__MAX_INDEX] = {
139345dc0b4SJiri Olsa [PERF_HPP_DIFF__BASELINE] = {
140345dc0b4SJiri Olsa .name = "Baseline",
141345dc0b4SJiri Olsa },
142345dc0b4SJiri Olsa [PERF_HPP_DIFF__PERIOD] = {
143345dc0b4SJiri Olsa .name = "Period",
144345dc0b4SJiri Olsa .width = 14,
145345dc0b4SJiri Olsa },
146345dc0b4SJiri Olsa [PERF_HPP_DIFF__PERIOD_BASELINE] = {
147345dc0b4SJiri Olsa .name = "Base period",
148345dc0b4SJiri Olsa .width = 14,
149345dc0b4SJiri Olsa },
150345dc0b4SJiri Olsa [PERF_HPP_DIFF__DELTA] = {
151345dc0b4SJiri Olsa .name = "Delta",
152345dc0b4SJiri Olsa .width = 7,
153345dc0b4SJiri Olsa },
154a1668c25SNamhyung Kim [PERF_HPP_DIFF__DELTA_ABS] = {
155a1668c25SNamhyung Kim .name = "Delta Abs",
156a1668c25SNamhyung Kim .width = 7,
157a1668c25SNamhyung Kim },
158345dc0b4SJiri Olsa [PERF_HPP_DIFF__RATIO] = {
159345dc0b4SJiri Olsa .name = "Ratio",
160345dc0b4SJiri Olsa .width = 14,
161345dc0b4SJiri Olsa },
162345dc0b4SJiri Olsa [PERF_HPP_DIFF__WEIGHTED_DIFF] = {
163345dc0b4SJiri Olsa .name = "Weighted diff",
164345dc0b4SJiri Olsa .width = 14,
165345dc0b4SJiri Olsa },
166345dc0b4SJiri Olsa [PERF_HPP_DIFF__FORMULA] = {
167345dc0b4SJiri Olsa .name = "Formula",
168345dc0b4SJiri Olsa .width = MAX_COL_WIDTH,
169b10c78c5SJin Yao },
170b10c78c5SJin Yao [PERF_HPP_DIFF__CYCLES] = {
171b10c78c5SJin Yao .name = "[Program Block Range] Cycles Diff",
172b10c78c5SJin Yao .width = 70,
173cebf7d51SJin Yao },
174cebf7d51SJin Yao [PERF_HPP_DIFF__CYCLES_HIST] = {
175cebf7d51SJin Yao .name = "stddev/Hist",
176cebf7d51SJin Yao .width = NUM_SPARKS + 9,
177345dc0b4SJiri Olsa }
178345dc0b4SJiri Olsa };
179345dc0b4SJiri Olsa
setup_compute_opt_wdiff(char * opt)18081d5f958SJiri Olsa static int setup_compute_opt_wdiff(char *opt)
18181d5f958SJiri Olsa {
18281d5f958SJiri Olsa char *w1_str = opt;
18381d5f958SJiri Olsa char *w2_str;
18481d5f958SJiri Olsa
18581d5f958SJiri Olsa int ret = -EINVAL;
18681d5f958SJiri Olsa
18781d5f958SJiri Olsa if (!opt)
18881d5f958SJiri Olsa goto out;
18981d5f958SJiri Olsa
19081d5f958SJiri Olsa w2_str = strchr(opt, ',');
19181d5f958SJiri Olsa if (!w2_str)
19281d5f958SJiri Olsa goto out;
19381d5f958SJiri Olsa
19481d5f958SJiri Olsa *w2_str++ = 0x0;
19581d5f958SJiri Olsa if (!*w2_str)
19681d5f958SJiri Olsa goto out;
19781d5f958SJiri Olsa
19881d5f958SJiri Olsa compute_wdiff_w1 = strtol(w1_str, NULL, 10);
19981d5f958SJiri Olsa compute_wdiff_w2 = strtol(w2_str, NULL, 10);
20081d5f958SJiri Olsa
20181d5f958SJiri Olsa if (!compute_wdiff_w1 || !compute_wdiff_w2)
20281d5f958SJiri Olsa goto out;
20381d5f958SJiri Olsa
20481d5f958SJiri Olsa pr_debug("compute wdiff w1(%" PRId64 ") w2(%" PRId64 ")\n",
20581d5f958SJiri Olsa compute_wdiff_w1, compute_wdiff_w2);
20681d5f958SJiri Olsa
20781d5f958SJiri Olsa ret = 0;
20881d5f958SJiri Olsa
20981d5f958SJiri Olsa out:
21081d5f958SJiri Olsa if (ret)
21181d5f958SJiri Olsa pr_err("Failed: wrong weight data, use 'wdiff:w1,w2'\n");
21281d5f958SJiri Olsa
21381d5f958SJiri Olsa return ret;
21481d5f958SJiri Olsa }
21581d5f958SJiri Olsa
setup_compute_opt(char * opt)21681d5f958SJiri Olsa static int setup_compute_opt(char *opt)
21781d5f958SJiri Olsa {
21881d5f958SJiri Olsa if (compute == COMPUTE_WEIGHTED_DIFF)
21981d5f958SJiri Olsa return setup_compute_opt_wdiff(opt);
22081d5f958SJiri Olsa
22181d5f958SJiri Olsa if (opt) {
22281d5f958SJiri Olsa pr_err("Failed: extra option specified '%s'", opt);
22381d5f958SJiri Olsa return -EINVAL;
22481d5f958SJiri Olsa }
22581d5f958SJiri Olsa
22681d5f958SJiri Olsa return 0;
22781d5f958SJiri Olsa }
22881d5f958SJiri Olsa
setup_compute(const struct option * opt,const char * str,int unset __maybe_unused)2297aaf6b35SJiri Olsa static int setup_compute(const struct option *opt, const char *str,
2307aaf6b35SJiri Olsa int unset __maybe_unused)
2317aaf6b35SJiri Olsa {
2327aaf6b35SJiri Olsa int *cp = (int *) opt->value;
23381d5f958SJiri Olsa char *cstr = (char *) str;
23481d5f958SJiri Olsa char buf[50];
2357aaf6b35SJiri Olsa unsigned i;
23681d5f958SJiri Olsa char *option;
2377aaf6b35SJiri Olsa
2387aaf6b35SJiri Olsa if (!str) {
2397aaf6b35SJiri Olsa *cp = COMPUTE_DELTA;
2407aaf6b35SJiri Olsa return 0;
2417aaf6b35SJiri Olsa }
2427aaf6b35SJiri Olsa
24381d5f958SJiri Olsa option = strchr(str, ':');
24481d5f958SJiri Olsa if (option) {
24581d5f958SJiri Olsa unsigned len = option++ - str;
24681d5f958SJiri Olsa
24781d5f958SJiri Olsa /*
24881d5f958SJiri Olsa * The str data are not writeable, so we need
24981d5f958SJiri Olsa * to use another buffer.
25081d5f958SJiri Olsa */
25181d5f958SJiri Olsa
25281d5f958SJiri Olsa /* No option value is longer. */
25381d5f958SJiri Olsa if (len >= sizeof(buf))
25481d5f958SJiri Olsa return -EINVAL;
25581d5f958SJiri Olsa
25681d5f958SJiri Olsa strncpy(buf, str, len);
25781d5f958SJiri Olsa buf[len] = 0x0;
25881d5f958SJiri Olsa cstr = buf;
25981d5f958SJiri Olsa }
26081d5f958SJiri Olsa
2617aaf6b35SJiri Olsa for (i = 0; i < COMPUTE_MAX; i++)
26281d5f958SJiri Olsa if (!strcmp(cstr, compute_names[i])) {
2637aaf6b35SJiri Olsa *cp = i;
26481d5f958SJiri Olsa return setup_compute_opt(option);
2657aaf6b35SJiri Olsa }
2667aaf6b35SJiri Olsa
2677aaf6b35SJiri Olsa pr_err("Failed: '%s' is not computation method "
26881d5f958SJiri Olsa "(use 'delta','ratio' or 'wdiff')\n", str);
2697aaf6b35SJiri Olsa return -EINVAL;
2707aaf6b35SJiri Olsa }
2717aaf6b35SJiri Olsa
period_percent(struct hist_entry * he,u64 period)272ef358e6dSJiri Olsa static double period_percent(struct hist_entry *he, u64 period)
27396c47f19SJiri Olsa {
2748810f6ceSNamhyung Kim u64 total = hists__total_period(he->hists);
2758810f6ceSNamhyung Kim
27696c47f19SJiri Olsa return (period * 100.0) / total;
27796c47f19SJiri Olsa }
27896c47f19SJiri Olsa
compute_delta(struct hist_entry * he,struct hist_entry * pair)279ef358e6dSJiri Olsa static double compute_delta(struct hist_entry *he, struct hist_entry *pair)
28096c47f19SJiri Olsa {
281ef358e6dSJiri Olsa double old_percent = period_percent(he, he->stat.period);
282ef358e6dSJiri Olsa double new_percent = period_percent(pair, pair->stat.period);
28396c47f19SJiri Olsa
2849af303e2SJiri Olsa pair->diff.period_ratio_delta = new_percent - old_percent;
2859af303e2SJiri Olsa pair->diff.computed = true;
2869af303e2SJiri Olsa return pair->diff.period_ratio_delta;
28796c47f19SJiri Olsa }
28896c47f19SJiri Olsa
compute_ratio(struct hist_entry * he,struct hist_entry * pair)289ef358e6dSJiri Olsa static double compute_ratio(struct hist_entry *he, struct hist_entry *pair)
29096c47f19SJiri Olsa {
2919af303e2SJiri Olsa double old_period = he->stat.period ?: 1;
2929af303e2SJiri Olsa double new_period = pair->stat.period;
29396c47f19SJiri Olsa
2949af303e2SJiri Olsa pair->diff.computed = true;
2959af303e2SJiri Olsa pair->diff.period_ratio = new_period / old_period;
2969af303e2SJiri Olsa return pair->diff.period_ratio;
29796c47f19SJiri Olsa }
29896c47f19SJiri Olsa
compute_wdiff(struct hist_entry * he,struct hist_entry * pair)299ef358e6dSJiri Olsa static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
30081d5f958SJiri Olsa {
3019af303e2SJiri Olsa u64 old_period = he->stat.period;
3029af303e2SJiri Olsa u64 new_period = pair->stat.period;
30381d5f958SJiri Olsa
3049af303e2SJiri Olsa pair->diff.computed = true;
3059af303e2SJiri Olsa pair->diff.wdiff = new_period * compute_wdiff_w2 -
30681d5f958SJiri Olsa old_period * compute_wdiff_w1;
30781d5f958SJiri Olsa
3089af303e2SJiri Olsa return pair->diff.wdiff;
30981d5f958SJiri Olsa }
31081d5f958SJiri Olsa
formula_delta(struct hist_entry * he,struct hist_entry * pair,char * buf,size_t size)311f4c8bae1SJiri Olsa static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
312f4c8bae1SJiri Olsa char *buf, size_t size)
313ed279da2SJiri Olsa {
3148810f6ceSNamhyung Kim u64 he_total = he->hists->stats.total_period;
3158810f6ceSNamhyung Kim u64 pair_total = pair->hists->stats.total_period;
3168810f6ceSNamhyung Kim
3178810f6ceSNamhyung Kim if (symbol_conf.filter_relative) {
3188810f6ceSNamhyung Kim he_total = he->hists->stats.total_non_filtered_period;
3198810f6ceSNamhyung Kim pair_total = pair->hists->stats.total_non_filtered_period;
3208810f6ceSNamhyung Kim }
321ed279da2SJiri Olsa return scnprintf(buf, size,
322ed279da2SJiri Olsa "(%" PRIu64 " * 100 / %" PRIu64 ") - "
323ed279da2SJiri Olsa "(%" PRIu64 " * 100 / %" PRIu64 ")",
3248810f6ceSNamhyung Kim pair->stat.period, pair_total,
3258810f6ceSNamhyung Kim he->stat.period, he_total);
326ed279da2SJiri Olsa }
327ed279da2SJiri Olsa
formula_ratio(struct hist_entry * he,struct hist_entry * pair,char * buf,size_t size)328f4c8bae1SJiri Olsa static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
329f4c8bae1SJiri Olsa char *buf, size_t size)
330ed279da2SJiri Olsa {
3319af303e2SJiri Olsa double old_period = he->stat.period;
3329af303e2SJiri Olsa double new_period = pair->stat.period;
333ed279da2SJiri Olsa
334ed279da2SJiri Olsa return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
335ed279da2SJiri Olsa }
336ed279da2SJiri Olsa
formula_wdiff(struct hist_entry * he,struct hist_entry * pair,char * buf,size_t size)337f4c8bae1SJiri Olsa static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
338f4c8bae1SJiri Olsa char *buf, size_t size)
339ed279da2SJiri Olsa {
3409af303e2SJiri Olsa u64 old_period = he->stat.period;
3419af303e2SJiri Olsa u64 new_period = pair->stat.period;
342ed279da2SJiri Olsa
343ed279da2SJiri Olsa return scnprintf(buf, size,
344ed279da2SJiri Olsa "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
345ed279da2SJiri Olsa new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
346ed279da2SJiri Olsa }
347ed279da2SJiri Olsa
formula_fprintf(struct hist_entry * he,struct hist_entry * pair,char * buf,size_t size)348ef358e6dSJiri Olsa static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
349f4c8bae1SJiri Olsa char *buf, size_t size)
350ed279da2SJiri Olsa {
351ed279da2SJiri Olsa switch (compute) {
352ed279da2SJiri Olsa case COMPUTE_DELTA:
353a1668c25SNamhyung Kim case COMPUTE_DELTA_ABS:
354f4c8bae1SJiri Olsa return formula_delta(he, pair, buf, size);
355ed279da2SJiri Olsa case COMPUTE_RATIO:
356f4c8bae1SJiri Olsa return formula_ratio(he, pair, buf, size);
357ed279da2SJiri Olsa case COMPUTE_WEIGHTED_DIFF:
358f4c8bae1SJiri Olsa return formula_wdiff(he, pair, buf, size);
359ed279da2SJiri Olsa default:
360ed279da2SJiri Olsa BUG_ON(1);
361ed279da2SJiri Olsa }
362ed279da2SJiri Olsa
363ed279da2SJiri Olsa return -1;
364ed279da2SJiri Olsa }
365ed279da2SJiri Olsa
block_hist_zalloc(size_t size)36699150a1fSJin Yao static void *block_hist_zalloc(size_t size)
36799150a1fSJin Yao {
36899150a1fSJin Yao struct block_hist *bh;
36999150a1fSJin Yao
37099150a1fSJin Yao bh = zalloc(size + sizeof(*bh));
37199150a1fSJin Yao if (!bh)
37299150a1fSJin Yao return NULL;
37399150a1fSJin Yao
37499150a1fSJin Yao return &bh->he;
37599150a1fSJin Yao }
37699150a1fSJin Yao
block_hist_free(void * he)37799150a1fSJin Yao static void block_hist_free(void *he)
37899150a1fSJin Yao {
37999150a1fSJin Yao struct block_hist *bh;
38099150a1fSJin Yao
38199150a1fSJin Yao bh = container_of(he, struct block_hist, he);
38299150a1fSJin Yao hists__delete_entries(&bh->block_hists);
38399150a1fSJin Yao free(bh);
38499150a1fSJin Yao }
38599150a1fSJin Yao
38699150a1fSJin Yao struct hist_entry_ops block_hist_ops = {
38799150a1fSJin Yao .new = block_hist_zalloc,
38899150a1fSJin Yao .free = block_hist_free,
38999150a1fSJin Yao };
39099150a1fSJin Yao
diff__process_sample_event(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct evsel * evsel,struct machine * machine)3914802138dSJin Yao static int diff__process_sample_event(struct perf_tool *tool,
392d20deb64SArnaldo Carvalho de Melo union perf_event *event,
3938d50e5b4SArnaldo Carvalho de Melo struct perf_sample *sample,
39432dcd021SJiri Olsa struct evsel *evsel,
395743eb868SArnaldo Carvalho de Melo struct machine *machine)
39686a9eee0SArnaldo Carvalho de Melo {
3974802138dSJin Yao struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool);
39886a9eee0SArnaldo Carvalho de Melo struct addr_location al;
3994ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel);
4002a09a84cSJin Yao struct hist_entry_iter iter = {
4012a09a84cSJin Yao .evsel = evsel,
4022a09a84cSJin Yao .sample = sample,
4032a09a84cSJin Yao .ops = &hist_iter_normal,
4042a09a84cSJin Yao };
405b91fc39fSArnaldo Carvalho de Melo int ret = -1;
40686a9eee0SArnaldo Carvalho de Melo
4074802138dSJin Yao if (perf_time__ranges_skip_sample(pdiff->ptime_range, pdiff->range_num,
4084802138dSJin Yao sample->time)) {
4094802138dSJin Yao return 0;
4104802138dSJin Yao }
4114802138dSJin Yao
4120dd5041cSIan Rogers addr_location__init(&al);
413bb3eb566SArnaldo Carvalho de Melo if (machine__resolve(machine, &al, sample) < 0) {
41486a9eee0SArnaldo Carvalho de Melo pr_warning("problem processing %d event, skipping it.\n",
41586a9eee0SArnaldo Carvalho de Melo event->header.type);
4160dd5041cSIan Rogers ret = -1;
4170dd5041cSIan Rogers goto out;
41886a9eee0SArnaldo Carvalho de Melo }
41986a9eee0SArnaldo Carvalho de Melo
420daca23b2SJin Yao if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) {
421daca23b2SJin Yao ret = 0;
4220dd5041cSIan Rogers goto out;
423daca23b2SJin Yao }
424daca23b2SJin Yao
4252a09a84cSJin Yao switch (compute) {
4262a09a84cSJin Yao case COMPUTE_CYCLES:
42799150a1fSJin Yao if (!hists__add_entry_ops(hists, &block_hist_ops, &al, NULL,
428ebf39d29SLeo Yan NULL, NULL, NULL, sample, true)) {
42999150a1fSJin Yao pr_warning("problem incrementing symbol period, "
43099150a1fSJin Yao "skipping event\n");
4310dd5041cSIan Rogers goto out;
43299150a1fSJin Yao }
43399150a1fSJin Yao
4347841f40aSJin Yao hist__account_cycles(sample->branch_stack, &al, sample, false,
4357841f40aSJin Yao NULL);
4362a09a84cSJin Yao break;
4372a09a84cSJin Yao
4382a09a84cSJin Yao case COMPUTE_STREAM:
4392a09a84cSJin Yao if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH,
4402a09a84cSJin Yao NULL)) {
4412a09a84cSJin Yao pr_debug("problem adding hist entry, skipping event\n");
4420dd5041cSIan Rogers goto out;
4432a09a84cSJin Yao }
4442a09a84cSJin Yao break;
4452a09a84cSJin Yao
4462a09a84cSJin Yao default:
447ebf39d29SLeo Yan if (!hists__add_entry(hists, &al, NULL, NULL, NULL, NULL, sample,
4482a09a84cSJin Yao true)) {
4492a09a84cSJin Yao pr_warning("problem incrementing symbol period, "
4502a09a84cSJin Yao "skipping event\n");
4510dd5041cSIan Rogers goto out;
4522a09a84cSJin Yao }
45399150a1fSJin Yao }
45486a9eee0SArnaldo Carvalho de Melo
455820bc81fSNamhyung Kim /*
456820bc81fSNamhyung Kim * The total_period is updated here before going to the output
457820bc81fSNamhyung Kim * tree since normally only the baseline hists will call
458820bc81fSNamhyung Kim * hists__output_resort() and precompute needs the total
459820bc81fSNamhyung Kim * period in order to sort entries by percentage delta.
460820bc81fSNamhyung Kim */
4614ea062edSArnaldo Carvalho de Melo hists->stats.total_period += sample->period;
462820bc81fSNamhyung Kim if (!al.filtered)
4634ea062edSArnaldo Carvalho de Melo hists->stats.total_non_filtered_period += sample->period;
464b91fc39fSArnaldo Carvalho de Melo ret = 0;
4650dd5041cSIan Rogers out:
4660dd5041cSIan Rogers addr_location__exit(&al);
467b91fc39fSArnaldo Carvalho de Melo return ret;
46886a9eee0SArnaldo Carvalho de Melo }
46986a9eee0SArnaldo Carvalho de Melo
4704802138dSJin Yao static struct perf_diff pdiff = {
4714802138dSJin Yao .tool = {
47255aa640fSArnaldo Carvalho de Melo .sample = diff__process_sample_event,
4738115d60cSArnaldo Carvalho de Melo .mmap = perf_event__process_mmap,
47468ca9d65SKan Liang .mmap2 = perf_event__process_mmap2,
4758115d60cSArnaldo Carvalho de Melo .comm = perf_event__process_comm,
476f62d3f0fSArnaldo Carvalho de Melo .exit = perf_event__process_exit,
477f62d3f0fSArnaldo Carvalho de Melo .fork = perf_event__process_fork,
4788115d60cSArnaldo Carvalho de Melo .lost = perf_event__process_lost,
479f3b3614aSHari Bathini .namespaces = perf_event__process_namespaces,
480ba78c1c5SNamhyung Kim .cgroup = perf_event__process_cgroup,
4810a8cb85cSJiri Olsa .ordered_events = true,
482eac23d1cSIan Munsie .ordering_requires_timestamps = true,
4834802138dSJin Yao },
48486a9eee0SArnaldo Carvalho de Melo };
48586a9eee0SArnaldo Carvalho de Melo
evsel_match(struct evsel * evsel,struct evlist * evlist)48632dcd021SJiri Olsa static struct evsel *evsel_match(struct evsel *evsel,
48763503dbaSJiri Olsa struct evlist *evlist)
488863e451fSJiri Olsa {
48932dcd021SJiri Olsa struct evsel *e;
490863e451fSJiri Olsa
491e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, e) {
492c754c382SArnaldo Carvalho de Melo if (evsel__match2(evsel, e))
493863e451fSJiri Olsa return e;
4940050f7aaSArnaldo Carvalho de Melo }
495863e451fSJiri Olsa
496863e451fSJiri Olsa return NULL;
497863e451fSJiri Olsa }
498863e451fSJiri Olsa
evlist__collapse_resort(struct evlist * evlist)499b979a2f1SArnaldo Carvalho de Melo static void evlist__collapse_resort(struct evlist *evlist)
500dd464345SJiri Olsa {
50132dcd021SJiri Olsa struct evsel *evsel;
502dd464345SJiri Olsa
503e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) {
5044ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel);
505dd464345SJiri Olsa
506c1fb5651SNamhyung Kim hists__collapse_resort(hists, NULL);
507dd464345SJiri Olsa }
508dd464345SJiri Olsa }
509dd464345SJiri Olsa
fmt_to_data_file(struct perf_hpp_fmt * fmt)510ff21cef6SNamhyung Kim static struct data__file *fmt_to_data_file(struct perf_hpp_fmt *fmt)
511ff21cef6SNamhyung Kim {
512ff21cef6SNamhyung Kim struct diff_hpp_fmt *dfmt = container_of(fmt, struct diff_hpp_fmt, fmt);
513ff21cef6SNamhyung Kim void *ptr = dfmt - dfmt->idx;
514ff21cef6SNamhyung Kim struct data__file *d = container_of(ptr, struct data__file, fmt);
515ff21cef6SNamhyung Kim
516ff21cef6SNamhyung Kim return d;
517ff21cef6SNamhyung Kim }
518ff21cef6SNamhyung Kim
5195f3f8d3bSJiri Olsa static struct hist_entry*
get_pair_data(struct hist_entry * he,struct data__file * d)5205f3f8d3bSJiri Olsa get_pair_data(struct hist_entry *he, struct data__file *d)
5215f3f8d3bSJiri Olsa {
5225f3f8d3bSJiri Olsa if (hist_entry__has_pairs(he)) {
5235f3f8d3bSJiri Olsa struct hist_entry *pair;
5245f3f8d3bSJiri Olsa
5255f3f8d3bSJiri Olsa list_for_each_entry(pair, &he->pairs.head, pairs.node)
5265f3f8d3bSJiri Olsa if (pair->hists == d->hists)
5275f3f8d3bSJiri Olsa return pair;
5285f3f8d3bSJiri Olsa }
5295f3f8d3bSJiri Olsa
5305f3f8d3bSJiri Olsa return NULL;
5315f3f8d3bSJiri Olsa }
5325f3f8d3bSJiri Olsa
5335f3f8d3bSJiri Olsa static struct hist_entry*
get_pair_fmt(struct hist_entry * he,struct diff_hpp_fmt * dfmt)5345f3f8d3bSJiri Olsa get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)
5355f3f8d3bSJiri Olsa {
536ff21cef6SNamhyung Kim struct data__file *d = fmt_to_data_file(&dfmt->fmt);
5375f3f8d3bSJiri Olsa
5385f3f8d3bSJiri Olsa return get_pair_data(he, d);
5395f3f8d3bSJiri Olsa }
5405f3f8d3bSJiri Olsa
hists__baseline_only(struct hists * hists)541a06d143eSJiri Olsa static void hists__baseline_only(struct hists *hists)
542a06d143eSJiri Olsa {
5432eb3d689SDavidlohr Bueso struct rb_root_cached *root;
544ce74f60eSNamhyung Kim struct rb_node *next;
545a06d143eSJiri Olsa
54652225036SJiri Olsa if (hists__has(hists, need_collapse))
547ce74f60eSNamhyung Kim root = &hists->entries_collapsed;
548ce74f60eSNamhyung Kim else
549ce74f60eSNamhyung Kim root = hists->entries_in;
550ce74f60eSNamhyung Kim
5512eb3d689SDavidlohr Bueso next = rb_first_cached(root);
552a06d143eSJiri Olsa while (next != NULL) {
553ce74f60eSNamhyung Kim struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
554a06d143eSJiri Olsa
555ce74f60eSNamhyung Kim next = rb_next(&he->rb_node_in);
556b821c732SArnaldo Carvalho de Melo if (!hist_entry__next_pair(he)) {
5572eb3d689SDavidlohr Bueso rb_erase_cached(&he->rb_node_in, root);
5586733d1bfSArnaldo Carvalho de Melo hist_entry__delete(he);
559a06d143eSJiri Olsa }
560a06d143eSJiri Olsa }
561a06d143eSJiri Olsa }
562a06d143eSJiri Olsa
block_cycles_diff_cmp(struct hist_entry * left,struct hist_entry * right)56399150a1fSJin Yao static int64_t block_cycles_diff_cmp(struct hist_entry *left,
56499150a1fSJin Yao struct hist_entry *right)
56599150a1fSJin Yao {
56699150a1fSJin Yao bool pairs_left = hist_entry__has_pairs(left);
56799150a1fSJin Yao bool pairs_right = hist_entry__has_pairs(right);
56899150a1fSJin Yao s64 l, r;
56999150a1fSJin Yao
57099150a1fSJin Yao if (!pairs_left && !pairs_right)
57199150a1fSJin Yao return 0;
57299150a1fSJin Yao
57398e93245SArnaldo Carvalho de Melo l = llabs(left->diff.cycles);
57498e93245SArnaldo Carvalho de Melo r = llabs(right->diff.cycles);
57599150a1fSJin Yao return r - l;
57699150a1fSJin Yao }
57799150a1fSJin Yao
block_sort(struct perf_hpp_fmt * fmt __maybe_unused,struct hist_entry * left,struct hist_entry * right)57899150a1fSJin Yao static int64_t block_sort(struct perf_hpp_fmt *fmt __maybe_unused,
57999150a1fSJin Yao struct hist_entry *left, struct hist_entry *right)
58099150a1fSJin Yao {
58199150a1fSJin Yao return block_cycles_diff_cmp(right, left);
58299150a1fSJin Yao }
58399150a1fSJin Yao
init_block_hist(struct block_hist * bh)58499150a1fSJin Yao static void init_block_hist(struct block_hist *bh)
58599150a1fSJin Yao {
58699150a1fSJin Yao __hists__init(&bh->block_hists, &bh->block_list);
58799150a1fSJin Yao perf_hpp_list__init(&bh->block_list);
58899150a1fSJin Yao
58999150a1fSJin Yao INIT_LIST_HEAD(&bh->block_fmt.list);
59099150a1fSJin Yao INIT_LIST_HEAD(&bh->block_fmt.sort_list);
59160414418SJin Yao bh->block_fmt.cmp = block_info__cmp;
59299150a1fSJin Yao bh->block_fmt.sort = block_sort;
59399150a1fSJin Yao perf_hpp_list__register_sort_field(&bh->block_list,
59499150a1fSJin Yao &bh->block_fmt);
59599150a1fSJin Yao bh->valid = true;
59699150a1fSJin Yao }
59799150a1fSJin Yao
get_block_pair(struct hist_entry * he,struct hists * hists_pair)598f3810817SJin Yao static struct hist_entry *get_block_pair(struct hist_entry *he,
599f3810817SJin Yao struct hists *hists_pair)
600f3810817SJin Yao {
601f3810817SJin Yao struct rb_root_cached *root = hists_pair->entries_in;
602f3810817SJin Yao struct rb_node *next = rb_first_cached(root);
603a8a9f6dcSJin Yao int64_t cmp;
604f3810817SJin Yao
605f3810817SJin Yao while (next != NULL) {
606f3810817SJin Yao struct hist_entry *he_pair = rb_entry(next, struct hist_entry,
607f3810817SJin Yao rb_node_in);
608f3810817SJin Yao
609f3810817SJin Yao next = rb_next(&he_pair->rb_node_in);
610f3810817SJin Yao
611a8a9f6dcSJin Yao cmp = __block_info__cmp(he_pair, he);
612f3810817SJin Yao if (!cmp)
613f3810817SJin Yao return he_pair;
614f3810817SJin Yao }
615f3810817SJin Yao
616f3810817SJin Yao return NULL;
617f3810817SJin Yao }
618f3810817SJin Yao
init_spark_values(unsigned long * svals,int num)619cebf7d51SJin Yao static void init_spark_values(unsigned long *svals, int num)
620cebf7d51SJin Yao {
621cebf7d51SJin Yao for (int i = 0; i < num; i++)
622cebf7d51SJin Yao svals[i] = 0;
623cebf7d51SJin Yao }
624cebf7d51SJin Yao
update_spark_value(unsigned long * svals,int num,struct stats * stats,u64 val)625cebf7d51SJin Yao static void update_spark_value(unsigned long *svals, int num,
626cebf7d51SJin Yao struct stats *stats, u64 val)
627cebf7d51SJin Yao {
628cebf7d51SJin Yao int n = stats->n;
629cebf7d51SJin Yao
630cebf7d51SJin Yao if (n < num)
631cebf7d51SJin Yao svals[n] = val;
632cebf7d51SJin Yao }
633cebf7d51SJin Yao
compute_cycles_diff(struct hist_entry * he,struct hist_entry * pair)634f3810817SJin Yao static void compute_cycles_diff(struct hist_entry *he,
635f3810817SJin Yao struct hist_entry *pair)
636f3810817SJin Yao {
637f3810817SJin Yao pair->diff.computed = true;
638f3810817SJin Yao if (pair->block_info->num && he->block_info->num) {
639f3810817SJin Yao pair->diff.cycles =
640f3810817SJin Yao pair->block_info->cycles_aggr / pair->block_info->num_aggr -
641f3810817SJin Yao he->block_info->cycles_aggr / he->block_info->num_aggr;
642cebf7d51SJin Yao
643cebf7d51SJin Yao if (!cycles_hist)
644cebf7d51SJin Yao return;
645cebf7d51SJin Yao
646cebf7d51SJin Yao init_stats(&pair->diff.stats);
647cebf7d51SJin Yao init_spark_values(pair->diff.svals, NUM_SPARKS);
648cebf7d51SJin Yao
649cebf7d51SJin Yao for (int i = 0; i < pair->block_info->num; i++) {
650cebf7d51SJin Yao u64 val;
651cebf7d51SJin Yao
652cebf7d51SJin Yao if (i >= he->block_info->num || i >= NUM_SPARKS)
653cebf7d51SJin Yao break;
654cebf7d51SJin Yao
6552b1ac640SArnaldo Carvalho de Melo val = llabs(pair->block_info->cycles_spark[i] -
656cebf7d51SJin Yao he->block_info->cycles_spark[i]);
657cebf7d51SJin Yao
658cebf7d51SJin Yao update_spark_value(pair->diff.svals, NUM_SPARKS,
659cebf7d51SJin Yao &pair->diff.stats, val);
660cebf7d51SJin Yao update_stats(&pair->diff.stats, val);
661cebf7d51SJin Yao }
662f3810817SJin Yao }
663f3810817SJin Yao }
664f3810817SJin Yao
block_hists_match(struct hists * hists_base,struct hists * hists_pair)665f3810817SJin Yao static void block_hists_match(struct hists *hists_base,
666f3810817SJin Yao struct hists *hists_pair)
667f3810817SJin Yao {
668f3810817SJin Yao struct rb_root_cached *root = hists_base->entries_in;
669f3810817SJin Yao struct rb_node *next = rb_first_cached(root);
670f3810817SJin Yao
671f3810817SJin Yao while (next != NULL) {
672f3810817SJin Yao struct hist_entry *he = rb_entry(next, struct hist_entry,
673f3810817SJin Yao rb_node_in);
674f3810817SJin Yao struct hist_entry *pair = get_block_pair(he, hists_pair);
675f3810817SJin Yao
676f3810817SJin Yao next = rb_next(&he->rb_node_in);
677f3810817SJin Yao
678f3810817SJin Yao if (pair) {
679f3810817SJin Yao hist_entry__add_pair(pair, he);
680f3810817SJin Yao compute_cycles_diff(he, pair);
681f3810817SJin Yao }
682f3810817SJin Yao }
683f3810817SJin Yao }
684f3810817SJin Yao
hists__precompute(struct hists * hists)68596c47f19SJiri Olsa static void hists__precompute(struct hists *hists)
68696c47f19SJiri Olsa {
6872eb3d689SDavidlohr Bueso struct rb_root_cached *root;
688367c53c0SJiri Olsa struct rb_node *next;
68996c47f19SJiri Olsa
69052225036SJiri Olsa if (hists__has(hists, need_collapse))
691367c53c0SJiri Olsa root = &hists->entries_collapsed;
692367c53c0SJiri Olsa else
693367c53c0SJiri Olsa root = hists->entries_in;
694367c53c0SJiri Olsa
6952eb3d689SDavidlohr Bueso next = rb_first_cached(root);
69696c47f19SJiri Olsa while (next != NULL) {
697f3810817SJin Yao struct block_hist *bh, *pair_bh;
6985f3f8d3bSJiri Olsa struct hist_entry *he, *pair;
69956495a8aSNamhyung Kim struct data__file *d;
70056495a8aSNamhyung Kim int i;
70196c47f19SJiri Olsa
7025f3f8d3bSJiri Olsa he = rb_entry(next, struct hist_entry, rb_node_in);
703367c53c0SJiri Olsa next = rb_next(&he->rb_node_in);
7045f3f8d3bSJiri Olsa
70560414418SJin Yao if (compute == COMPUTE_CYCLES) {
70660414418SJin Yao bh = container_of(he, struct block_hist, he);
70760414418SJin Yao init_block_hist(bh);
70860414418SJin Yao block_info__process_sym(he, bh, NULL, 0);
70960414418SJin Yao }
71099150a1fSJin Yao
71156495a8aSNamhyung Kim data__for_each_file_new(i, d) {
71256495a8aSNamhyung Kim pair = get_pair_data(he, d);
71305472daaSJiri Olsa if (!pair)
71405472daaSJiri Olsa continue;
71596c47f19SJiri Olsa
71696c47f19SJiri Olsa switch (compute) {
71796c47f19SJiri Olsa case COMPUTE_DELTA:
718a1668c25SNamhyung Kim case COMPUTE_DELTA_ABS:
719ef358e6dSJiri Olsa compute_delta(he, pair);
72096c47f19SJiri Olsa break;
72196c47f19SJiri Olsa case COMPUTE_RATIO:
722ef358e6dSJiri Olsa compute_ratio(he, pair);
72396c47f19SJiri Olsa break;
72481d5f958SJiri Olsa case COMPUTE_WEIGHTED_DIFF:
725ef358e6dSJiri Olsa compute_wdiff(he, pair);
72681d5f958SJiri Olsa break;
72799150a1fSJin Yao case COMPUTE_CYCLES:
728f3810817SJin Yao pair_bh = container_of(pair, struct block_hist,
729f3810817SJin Yao he);
73060414418SJin Yao init_block_hist(pair_bh);
73160414418SJin Yao block_info__process_sym(pair, pair_bh, NULL, 0);
73260414418SJin Yao
73360414418SJin Yao bh = container_of(he, struct block_hist, he);
734f3810817SJin Yao
735f3810817SJin Yao if (bh->valid && pair_bh->valid) {
736f3810817SJin Yao block_hists_match(&bh->block_hists,
737f3810817SJin Yao &pair_bh->block_hists);
7380bdf181fSJin Yao hists__output_resort(&pair_bh->block_hists,
7390bdf181fSJin Yao NULL);
740f3810817SJin Yao }
74199150a1fSJin Yao break;
74296c47f19SJiri Olsa default:
74396c47f19SJiri Olsa BUG_ON(1);
74496c47f19SJiri Olsa }
74596c47f19SJiri Olsa }
74696c47f19SJiri Olsa }
74756495a8aSNamhyung Kim }
74896c47f19SJiri Olsa
cmp_doubles(double l,double r)74996c47f19SJiri Olsa static int64_t cmp_doubles(double l, double r)
75096c47f19SJiri Olsa {
75196c47f19SJiri Olsa if (l > r)
75296c47f19SJiri Olsa return -1;
75396c47f19SJiri Olsa else if (l < r)
75496c47f19SJiri Olsa return 1;
75596c47f19SJiri Olsa else
75696c47f19SJiri Olsa return 0;
75796c47f19SJiri Olsa }
75896c47f19SJiri Olsa
75996c47f19SJiri Olsa static int64_t
__hist_entry__cmp_compute(struct hist_entry * left,struct hist_entry * right,int c)7605f3f8d3bSJiri Olsa __hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
76196c47f19SJiri Olsa int c)
76296c47f19SJiri Olsa {
76396c47f19SJiri Olsa switch (c) {
76496c47f19SJiri Olsa case COMPUTE_DELTA:
76596c47f19SJiri Olsa {
76696c47f19SJiri Olsa double l = left->diff.period_ratio_delta;
76796c47f19SJiri Olsa double r = right->diff.period_ratio_delta;
76896c47f19SJiri Olsa
76996c47f19SJiri Olsa return cmp_doubles(l, r);
77096c47f19SJiri Olsa }
771a1668c25SNamhyung Kim case COMPUTE_DELTA_ABS:
772a1668c25SNamhyung Kim {
773a1668c25SNamhyung Kim double l = fabs(left->diff.period_ratio_delta);
774a1668c25SNamhyung Kim double r = fabs(right->diff.period_ratio_delta);
775a1668c25SNamhyung Kim
776a1668c25SNamhyung Kim return cmp_doubles(l, r);
777a1668c25SNamhyung Kim }
77896c47f19SJiri Olsa case COMPUTE_RATIO:
77996c47f19SJiri Olsa {
78096c47f19SJiri Olsa double l = left->diff.period_ratio;
78196c47f19SJiri Olsa double r = right->diff.period_ratio;
78296c47f19SJiri Olsa
78396c47f19SJiri Olsa return cmp_doubles(l, r);
78496c47f19SJiri Olsa }
78581d5f958SJiri Olsa case COMPUTE_WEIGHTED_DIFF:
78681d5f958SJiri Olsa {
78781d5f958SJiri Olsa s64 l = left->diff.wdiff;
78881d5f958SJiri Olsa s64 r = right->diff.wdiff;
78981d5f958SJiri Olsa
79081d5f958SJiri Olsa return r - l;
79181d5f958SJiri Olsa }
79296c47f19SJiri Olsa default:
79396c47f19SJiri Olsa BUG_ON(1);
79496c47f19SJiri Olsa }
79596c47f19SJiri Olsa
79696c47f19SJiri Olsa return 0;
79796c47f19SJiri Olsa }
79896c47f19SJiri Olsa
7995f3f8d3bSJiri Olsa static int64_t
hist_entry__cmp_compute(struct hist_entry * left,struct hist_entry * right,int c,int sort_idx)8005f3f8d3bSJiri Olsa hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
80156495a8aSNamhyung Kim int c, int sort_idx)
8025f3f8d3bSJiri Olsa {
8035f3f8d3bSJiri Olsa bool pairs_left = hist_entry__has_pairs(left);
8045f3f8d3bSJiri Olsa bool pairs_right = hist_entry__has_pairs(right);
8055f3f8d3bSJiri Olsa struct hist_entry *p_right, *p_left;
8065f3f8d3bSJiri Olsa
8075f3f8d3bSJiri Olsa if (!pairs_left && !pairs_right)
8085f3f8d3bSJiri Olsa return 0;
8095f3f8d3bSJiri Olsa
8105f3f8d3bSJiri Olsa if (!pairs_left || !pairs_right)
8115f3f8d3bSJiri Olsa return pairs_left ? -1 : 1;
8125f3f8d3bSJiri Olsa
81356495a8aSNamhyung Kim p_left = get_pair_data(left, &data__files[sort_idx]);
81456495a8aSNamhyung Kim p_right = get_pair_data(right, &data__files[sort_idx]);
8155f3f8d3bSJiri Olsa
8165f3f8d3bSJiri Olsa if (!p_left && !p_right)
8175f3f8d3bSJiri Olsa return 0;
8185f3f8d3bSJiri Olsa
8195f3f8d3bSJiri Olsa if (!p_left || !p_right)
8205f3f8d3bSJiri Olsa return p_left ? -1 : 1;
8215f3f8d3bSJiri Olsa
8225f3f8d3bSJiri Olsa /*
8235f3f8d3bSJiri Olsa * We have 2 entries of same kind, let's
8245f3f8d3bSJiri Olsa * make the data comparison.
8255f3f8d3bSJiri Olsa */
8265f3f8d3bSJiri Olsa return __hist_entry__cmp_compute(p_left, p_right, c);
8275f3f8d3bSJiri Olsa }
8285f3f8d3bSJiri Olsa
829e7024fc3SNamhyung Kim static int64_t
hist_entry__cmp_compute_idx(struct hist_entry * left,struct hist_entry * right,int c,int sort_idx)830566b5cfbSNamhyung Kim hist_entry__cmp_compute_idx(struct hist_entry *left, struct hist_entry *right,
831566b5cfbSNamhyung Kim int c, int sort_idx)
832566b5cfbSNamhyung Kim {
833566b5cfbSNamhyung Kim struct hist_entry *p_right, *p_left;
834566b5cfbSNamhyung Kim
835566b5cfbSNamhyung Kim p_left = get_pair_data(left, &data__files[sort_idx]);
836566b5cfbSNamhyung Kim p_right = get_pair_data(right, &data__files[sort_idx]);
837566b5cfbSNamhyung Kim
838566b5cfbSNamhyung Kim if (!p_left && !p_right)
839566b5cfbSNamhyung Kim return 0;
840566b5cfbSNamhyung Kim
841566b5cfbSNamhyung Kim if (!p_left || !p_right)
842566b5cfbSNamhyung Kim return p_left ? -1 : 1;
843566b5cfbSNamhyung Kim
844a1668c25SNamhyung Kim if (c != COMPUTE_DELTA && c != COMPUTE_DELTA_ABS) {
845566b5cfbSNamhyung Kim /*
846566b5cfbSNamhyung Kim * The delta can be computed without the baseline, but
847566b5cfbSNamhyung Kim * others are not. Put those entries which have no
848566b5cfbSNamhyung Kim * values below.
849566b5cfbSNamhyung Kim */
850566b5cfbSNamhyung Kim if (left->dummy && right->dummy)
851566b5cfbSNamhyung Kim return 0;
852566b5cfbSNamhyung Kim
853566b5cfbSNamhyung Kim if (left->dummy || right->dummy)
854566b5cfbSNamhyung Kim return left->dummy ? 1 : -1;
855566b5cfbSNamhyung Kim }
856566b5cfbSNamhyung Kim
857566b5cfbSNamhyung Kim return __hist_entry__cmp_compute(p_left, p_right, c);
858566b5cfbSNamhyung Kim }
859566b5cfbSNamhyung Kim
860566b5cfbSNamhyung 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)86187bbdf76SNamhyung Kim hist_entry__cmp_nop(struct perf_hpp_fmt *fmt __maybe_unused,
86287bbdf76SNamhyung Kim struct hist_entry *left __maybe_unused,
863e7024fc3SNamhyung Kim struct hist_entry *right __maybe_unused)
864e7024fc3SNamhyung Kim {
865e7024fc3SNamhyung Kim return 0;
866e7024fc3SNamhyung Kim }
867e7024fc3SNamhyung Kim
868e7024fc3SNamhyung Kim static int64_t
hist_entry__cmp_baseline(struct perf_hpp_fmt * fmt __maybe_unused,struct hist_entry * left,struct hist_entry * right)86987bbdf76SNamhyung Kim hist_entry__cmp_baseline(struct perf_hpp_fmt *fmt __maybe_unused,
87087bbdf76SNamhyung Kim struct hist_entry *left, struct hist_entry *right)
871e7024fc3SNamhyung Kim {
872e7024fc3SNamhyung Kim if (left->stat.period == right->stat.period)
873e7024fc3SNamhyung Kim return 0;
874e7024fc3SNamhyung Kim return left->stat.period > right->stat.period ? 1 : -1;
875e7024fc3SNamhyung Kim }
876e7024fc3SNamhyung Kim
877e7024fc3SNamhyung Kim static int64_t
hist_entry__cmp_delta(struct perf_hpp_fmt * fmt,struct hist_entry * left,struct hist_entry * right)87856495a8aSNamhyung Kim hist_entry__cmp_delta(struct perf_hpp_fmt *fmt,
87987bbdf76SNamhyung Kim struct hist_entry *left, struct hist_entry *right)
880e7024fc3SNamhyung Kim {
88156495a8aSNamhyung Kim struct data__file *d = fmt_to_data_file(fmt);
88256495a8aSNamhyung Kim
88356495a8aSNamhyung Kim return hist_entry__cmp_compute(right, left, COMPUTE_DELTA, d->idx);
884e7024fc3SNamhyung Kim }
885e7024fc3SNamhyung Kim
886e7024fc3SNamhyung Kim static int64_t
hist_entry__cmp_delta_abs(struct perf_hpp_fmt * fmt,struct hist_entry * left,struct hist_entry * right)887a1668c25SNamhyung Kim hist_entry__cmp_delta_abs(struct perf_hpp_fmt *fmt,
888a1668c25SNamhyung Kim struct hist_entry *left, struct hist_entry *right)
889a1668c25SNamhyung Kim {
890a1668c25SNamhyung Kim struct data__file *d = fmt_to_data_file(fmt);
891a1668c25SNamhyung Kim
892a1668c25SNamhyung Kim return hist_entry__cmp_compute(right, left, COMPUTE_DELTA_ABS, d->idx);
893a1668c25SNamhyung Kim }
894a1668c25SNamhyung Kim
895a1668c25SNamhyung Kim static int64_t
hist_entry__cmp_ratio(struct perf_hpp_fmt * fmt,struct hist_entry * left,struct hist_entry * right)89656495a8aSNamhyung Kim hist_entry__cmp_ratio(struct perf_hpp_fmt *fmt,
89787bbdf76SNamhyung Kim struct hist_entry *left, struct hist_entry *right)
898e7024fc3SNamhyung Kim {
89956495a8aSNamhyung Kim struct data__file *d = fmt_to_data_file(fmt);
90056495a8aSNamhyung Kim
90156495a8aSNamhyung Kim return hist_entry__cmp_compute(right, left, COMPUTE_RATIO, d->idx);
902e7024fc3SNamhyung Kim }
903e7024fc3SNamhyung Kim
904e7024fc3SNamhyung Kim static int64_t
hist_entry__cmp_wdiff(struct perf_hpp_fmt * fmt,struct hist_entry * left,struct hist_entry * right)90556495a8aSNamhyung Kim hist_entry__cmp_wdiff(struct perf_hpp_fmt *fmt,
90687bbdf76SNamhyung Kim struct hist_entry *left, struct hist_entry *right)
907e7024fc3SNamhyung Kim {
90856495a8aSNamhyung Kim struct data__file *d = fmt_to_data_file(fmt);
90956495a8aSNamhyung Kim
91056495a8aSNamhyung Kim return hist_entry__cmp_compute(right, left, COMPUTE_WEIGHTED_DIFF, d->idx);
911e7024fc3SNamhyung Kim }
912e7024fc3SNamhyung Kim
913566b5cfbSNamhyung Kim static int64_t
hist_entry__cmp_delta_idx(struct perf_hpp_fmt * fmt __maybe_unused,struct hist_entry * left,struct hist_entry * right)914566b5cfbSNamhyung Kim hist_entry__cmp_delta_idx(struct perf_hpp_fmt *fmt __maybe_unused,
915566b5cfbSNamhyung Kim struct hist_entry *left, struct hist_entry *right)
916566b5cfbSNamhyung Kim {
917566b5cfbSNamhyung Kim return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA,
918566b5cfbSNamhyung Kim sort_compute);
919566b5cfbSNamhyung Kim }
920566b5cfbSNamhyung Kim
921566b5cfbSNamhyung 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)922a1668c25SNamhyung Kim hist_entry__cmp_delta_abs_idx(struct perf_hpp_fmt *fmt __maybe_unused,
923a1668c25SNamhyung Kim struct hist_entry *left, struct hist_entry *right)
924a1668c25SNamhyung Kim {
925a1668c25SNamhyung Kim return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA_ABS,
926a1668c25SNamhyung Kim sort_compute);
927a1668c25SNamhyung Kim }
928a1668c25SNamhyung Kim
929a1668c25SNamhyung Kim static int64_t
hist_entry__cmp_ratio_idx(struct perf_hpp_fmt * fmt __maybe_unused,struct hist_entry * left,struct hist_entry * right)930566b5cfbSNamhyung Kim hist_entry__cmp_ratio_idx(struct perf_hpp_fmt *fmt __maybe_unused,
931566b5cfbSNamhyung Kim struct hist_entry *left, struct hist_entry *right)
932566b5cfbSNamhyung Kim {
933566b5cfbSNamhyung Kim return hist_entry__cmp_compute_idx(right, left, COMPUTE_RATIO,
934566b5cfbSNamhyung Kim sort_compute);
935566b5cfbSNamhyung Kim }
936566b5cfbSNamhyung Kim
937566b5cfbSNamhyung Kim static int64_t
hist_entry__cmp_wdiff_idx(struct perf_hpp_fmt * fmt __maybe_unused,struct hist_entry * left,struct hist_entry * right)938566b5cfbSNamhyung Kim hist_entry__cmp_wdiff_idx(struct perf_hpp_fmt *fmt __maybe_unused,
939566b5cfbSNamhyung Kim struct hist_entry *left, struct hist_entry *right)
940566b5cfbSNamhyung Kim {
941566b5cfbSNamhyung Kim return hist_entry__cmp_compute_idx(right, left, COMPUTE_WEIGHTED_DIFF,
942566b5cfbSNamhyung Kim sort_compute);
943566b5cfbSNamhyung Kim }
944566b5cfbSNamhyung Kim
hists__process(struct hists * hists)94522aeb7f5SJiri Olsa static void hists__process(struct hists *hists)
946a06d143eSJiri Olsa {
947a06d143eSJiri Olsa if (show_baseline_only)
94822aeb7f5SJiri Olsa hists__baseline_only(hists);
949a06d143eSJiri Olsa
95022aeb7f5SJiri Olsa hists__precompute(hists);
951740b97f9SNamhyung Kim hists__output_resort(hists, NULL);
95296c47f19SJiri Olsa
953b10c78c5SJin Yao if (compute == COMPUTE_CYCLES)
954b10c78c5SJin Yao symbol_conf.report_block = true;
955b10c78c5SJin Yao
95663b42fceSNamhyung Kim hists__fprintf(hists, !quiet, 0, 0, 0, stdout,
957e9de7e2fSArnaldo Carvalho de Melo !symbol_conf.use_callchain);
958a06d143eSJiri Olsa }
959a06d143eSJiri Olsa
data__fprintf(void)9601d81c7fcSJiri Olsa static void data__fprintf(void)
9611d81c7fcSJiri Olsa {
9621d81c7fcSJiri Olsa struct data__file *d;
9631d81c7fcSJiri Olsa int i;
9641d81c7fcSJiri Olsa
9651d81c7fcSJiri Olsa fprintf(stdout, "# Data files:\n");
9661d81c7fcSJiri Olsa
9671d81c7fcSJiri Olsa data__for_each_file(i, d)
9681d81c7fcSJiri Olsa fprintf(stdout, "# [%d] %s %s\n",
9692d4f2799SJiri Olsa d->idx, d->data.path,
9701d81c7fcSJiri Olsa !d->idx ? "(Baseline)" : "");
9711d81c7fcSJiri Olsa
9721d81c7fcSJiri Olsa fprintf(stdout, "#\n");
9731d81c7fcSJiri Olsa }
9741d81c7fcSJiri Olsa
data_process(void)975ec308426SJiri Olsa static void data_process(void)
97686a9eee0SArnaldo Carvalho de Melo {
97763503dbaSJiri Olsa struct evlist *evlist_base = data__files[0].session->evlist;
97832dcd021SJiri Olsa struct evsel *evsel_base;
979863e451fSJiri Olsa bool first = true;
98086a9eee0SArnaldo Carvalho de Melo
981e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist_base, evsel_base) {
9824ea062edSArnaldo Carvalho de Melo struct hists *hists_base = evsel__hists(evsel_base);
98322aeb7f5SJiri Olsa struct data__file *d;
98422aeb7f5SJiri Olsa int i;
98586a9eee0SArnaldo Carvalho de Melo
98622aeb7f5SJiri Olsa data__for_each_file_new(i, d) {
98763503dbaSJiri Olsa struct evlist *evlist = d->session->evlist;
98832dcd021SJiri Olsa struct evsel *evsel;
9894ea062edSArnaldo Carvalho de Melo struct hists *hists;
99022aeb7f5SJiri Olsa
99122aeb7f5SJiri Olsa evsel = evsel_match(evsel_base, evlist);
99222aeb7f5SJiri Olsa if (!evsel)
993863e451fSJiri Olsa continue;
994863e451fSJiri Olsa
9954ea062edSArnaldo Carvalho de Melo hists = evsel__hists(evsel);
9964ea062edSArnaldo Carvalho de Melo d->hists = hists;
99722aeb7f5SJiri Olsa
9984ea062edSArnaldo Carvalho de Melo hists__match(hists_base, hists);
99922aeb7f5SJiri Olsa
100022aeb7f5SJiri Olsa if (!show_baseline_only)
10014ea062edSArnaldo Carvalho de Melo hists__link(hists_base, hists);
100222aeb7f5SJiri Olsa }
100322aeb7f5SJiri Olsa
100463b42fceSNamhyung Kim if (!quiet) {
1005863e451fSJiri Olsa fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
10068ab2e96dSArnaldo Carvalho de Melo evsel__name(evsel_base));
100763b42fceSNamhyung Kim }
1008863e451fSJiri Olsa
1009863e451fSJiri Olsa first = false;
1010863e451fSJiri Olsa
101163b42fceSNamhyung Kim if (verbose > 0 || ((data__files_cnt > 2) && !quiet))
10121d81c7fcSJiri Olsa data__fprintf();
10131d81c7fcSJiri Olsa
1014f9db0d0fSKan Liang /* Don't sort callchain for perf diff */
1015862b2f8fSArnaldo Carvalho de Melo evsel__reset_sample_bit(evsel_base, CALLCHAIN);
1016f9db0d0fSKan Liang
10174ea062edSArnaldo Carvalho de Melo hists__process(hists_base);
1018ec308426SJiri Olsa }
1019863e451fSJiri Olsa }
1020863e451fSJiri Olsa
process_base_stream(struct data__file * data_base,struct data__file * data_pair,const char * title __maybe_unused)10212a09a84cSJin Yao static int process_base_stream(struct data__file *data_base,
10222a09a84cSJin Yao struct data__file *data_pair,
10232a09a84cSJin Yao const char *title __maybe_unused)
10242a09a84cSJin Yao {
10252a09a84cSJin Yao struct evlist *evlist_base = data_base->session->evlist;
10262a09a84cSJin Yao struct evlist *evlist_pair = data_pair->session->evlist;
10272a09a84cSJin Yao struct evsel *evsel_base, *evsel_pair;
10282a09a84cSJin Yao struct evsel_streams *es_base, *es_pair;
10292a09a84cSJin Yao
10302a09a84cSJin Yao evlist__for_each_entry(evlist_base, evsel_base) {
10312a09a84cSJin Yao evsel_pair = evsel_match(evsel_base, evlist_pair);
10322a09a84cSJin Yao if (!evsel_pair)
10332a09a84cSJin Yao continue;
10342a09a84cSJin Yao
10352a09a84cSJin Yao es_base = evsel_streams__entry(data_base->evlist_streams,
103638fe0e01SJiri Olsa evsel_base->core.idx);
10372a09a84cSJin Yao if (!es_base)
10382a09a84cSJin Yao return -1;
10392a09a84cSJin Yao
10402a09a84cSJin Yao es_pair = evsel_streams__entry(data_pair->evlist_streams,
104138fe0e01SJiri Olsa evsel_pair->core.idx);
10422a09a84cSJin Yao if (!es_pair)
10432a09a84cSJin Yao return -1;
10442a09a84cSJin Yao
10452a09a84cSJin Yao evsel_streams__match(es_base, es_pair);
10462a09a84cSJin Yao evsel_streams__report(es_base, es_pair);
10472a09a84cSJin Yao }
10482a09a84cSJin Yao
10492a09a84cSJin Yao return 0;
10502a09a84cSJin Yao }
10512a09a84cSJin Yao
stream_process(void)10522a09a84cSJin Yao static void stream_process(void)
10532a09a84cSJin Yao {
10542a09a84cSJin Yao /*
10552a09a84cSJin Yao * Stream comparison only supports two data files.
10562a09a84cSJin Yao * perf.data.old and perf.data. data__files[0] is perf.data.old,
10572a09a84cSJin Yao * data__files[1] is perf.data.
10582a09a84cSJin Yao */
10592a09a84cSJin Yao process_base_stream(&data__files[0], &data__files[1],
10602a09a84cSJin Yao "# Output based on old perf data:\n#\n");
10612a09a84cSJin Yao }
10622a09a84cSJin Yao
data__free(struct data__file * d)1063c818b498SJiri Olsa static void data__free(struct data__file *d)
1064c818b498SJiri Olsa {
1065c818b498SJiri Olsa int col;
1066c818b498SJiri Olsa
10672a09a84cSJin Yao if (d->evlist_streams)
10682a09a84cSJin Yao evlist_streams__delete(d->evlist_streams);
10692a09a84cSJin Yao
1070c818b498SJiri Olsa for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
1071c818b498SJiri Olsa struct diff_hpp_fmt *fmt = &d->fmt[col];
1072c818b498SJiri Olsa
107374cf249dSArnaldo Carvalho de Melo zfree(&fmt->header);
1074c818b498SJiri Olsa }
1075c818b498SJiri Olsa }
1076c818b498SJiri Olsa
abstime_str_dup(char ** pstr)10774802138dSJin Yao static int abstime_str_dup(char **pstr)
10784802138dSJin Yao {
10794802138dSJin Yao char *str = NULL;
10804802138dSJin Yao
10814802138dSJin Yao if (pdiff.time_str && strchr(pdiff.time_str, ':')) {
10824802138dSJin Yao str = strdup(pdiff.time_str);
10834802138dSJin Yao if (!str)
10844802138dSJin Yao return -ENOMEM;
10854802138dSJin Yao }
10864802138dSJin Yao
10874802138dSJin Yao *pstr = str;
10884802138dSJin Yao return 0;
10894802138dSJin Yao }
10904802138dSJin Yao
parse_absolute_time(struct data__file * d,char ** pstr)10914802138dSJin Yao static int parse_absolute_time(struct data__file *d, char **pstr)
10924802138dSJin Yao {
10934802138dSJin Yao char *p = *pstr;
10944802138dSJin Yao int ret;
10954802138dSJin Yao
10964802138dSJin Yao /*
10974802138dSJin Yao * Absolute timestamp for one file has the format: a.b,c.d
10984802138dSJin Yao * For multiple files, the format is: a.b,c.d:a.b,c.d
10994802138dSJin Yao */
11004802138dSJin Yao p = strchr(*pstr, ':');
11014802138dSJin Yao if (p) {
11024802138dSJin Yao if (p == *pstr) {
11034802138dSJin Yao pr_err("Invalid time string\n");
11044802138dSJin Yao return -EINVAL;
11054802138dSJin Yao }
11064802138dSJin Yao
11074802138dSJin Yao *p = 0;
11084802138dSJin Yao p++;
11094802138dSJin Yao if (*p == 0) {
11104802138dSJin Yao pr_err("Invalid time string\n");
11114802138dSJin Yao return -EINVAL;
11124802138dSJin Yao }
11134802138dSJin Yao }
11144802138dSJin Yao
11154802138dSJin Yao ret = perf_time__parse_for_ranges(*pstr, d->session,
11164802138dSJin Yao &pdiff.ptime_range,
11174802138dSJin Yao &pdiff.range_size,
11184802138dSJin Yao &pdiff.range_num);
11194802138dSJin Yao if (ret < 0)
11204802138dSJin Yao return ret;
11214802138dSJin Yao
11224802138dSJin Yao if (!p || *p == 0)
11234802138dSJin Yao *pstr = NULL;
11244802138dSJin Yao else
11254802138dSJin Yao *pstr = p;
11264802138dSJin Yao
11274802138dSJin Yao return ret;
11284802138dSJin Yao }
11294802138dSJin Yao
parse_percent_time(struct data__file * d)11304802138dSJin Yao static int parse_percent_time(struct data__file *d)
11314802138dSJin Yao {
11324802138dSJin Yao int ret;
11334802138dSJin Yao
11344802138dSJin Yao ret = perf_time__parse_for_ranges(pdiff.time_str, d->session,
11354802138dSJin Yao &pdiff.ptime_range,
11364802138dSJin Yao &pdiff.range_size,
11374802138dSJin Yao &pdiff.range_num);
11384802138dSJin Yao return ret;
11394802138dSJin Yao }
11404802138dSJin Yao
parse_time_str(struct data__file * d,char * abstime_ostr,char ** pabstime_tmp)11414802138dSJin Yao static int parse_time_str(struct data__file *d, char *abstime_ostr,
11424802138dSJin Yao char **pabstime_tmp)
11434802138dSJin Yao {
11444802138dSJin Yao int ret = 0;
11454802138dSJin Yao
11464802138dSJin Yao if (abstime_ostr)
11474802138dSJin Yao ret = parse_absolute_time(d, pabstime_tmp);
11484802138dSJin Yao else if (pdiff.time_str)
11494802138dSJin Yao ret = parse_percent_time(d);
11504802138dSJin Yao
11514802138dSJin Yao return ret;
11524802138dSJin Yao }
11534802138dSJin Yao
check_file_brstack(void)115430d81553SJin Yao static int check_file_brstack(void)
115530d81553SJin Yao {
115630d81553SJin Yao struct data__file *d;
115730d81553SJin Yao bool has_br_stack;
115830d81553SJin Yao int i;
115930d81553SJin Yao
116030d81553SJin Yao data__for_each_file(i, d) {
11612681bd85SNamhyung Kim d->session = perf_session__new(&d->data, &pdiff.tool);
11626ef81c55SMamatha Inamdar if (IS_ERR(d->session)) {
116330d81553SJin Yao pr_err("Failed to open %s\n", d->data.path);
11646ef81c55SMamatha Inamdar return PTR_ERR(d->session);
116530d81553SJin Yao }
116630d81553SJin Yao
116730d81553SJin Yao has_br_stack = perf_header__has_feat(&d->session->header,
116830d81553SJin Yao HEADER_BRANCH_STACK);
116930d81553SJin Yao perf_session__delete(d->session);
117030d81553SJin Yao if (!has_br_stack)
117130d81553SJin Yao return 0;
117230d81553SJin Yao }
117330d81553SJin Yao
117430d81553SJin Yao /* Set only all files having branch stacks */
117530d81553SJin Yao pdiff.has_br_stack = true;
117630d81553SJin Yao return 0;
117730d81553SJin Yao }
117830d81553SJin Yao
__cmd_diff(void)1179ec308426SJiri Olsa static int __cmd_diff(void)
1180ec308426SJiri Olsa {
1181ec308426SJiri Olsa struct data__file *d;
11824802138dSJin Yao int ret, i;
11834802138dSJin Yao char *abstime_ostr, *abstime_tmp;
11844802138dSJin Yao
11854802138dSJin Yao ret = abstime_str_dup(&abstime_ostr);
11864802138dSJin Yao if (ret)
11874802138dSJin Yao return ret;
11884802138dSJin Yao
11894802138dSJin Yao abstime_tmp = abstime_ostr;
11904802138dSJin Yao ret = -EINVAL;
1191ec308426SJiri Olsa
1192ec308426SJiri Olsa data__for_each_file(i, d) {
11932681bd85SNamhyung Kim d->session = perf_session__new(&d->data, &pdiff.tool);
11946ef81c55SMamatha Inamdar if (IS_ERR(d->session)) {
11956ef81c55SMamatha Inamdar ret = PTR_ERR(d->session);
11962d4f2799SJiri Olsa pr_err("Failed to open %s\n", d->data.path);
1197ec308426SJiri Olsa goto out_delete;
1198ec308426SJiri Olsa }
1199ec308426SJiri Olsa
12004802138dSJin Yao if (pdiff.time_str) {
12014802138dSJin Yao ret = parse_time_str(d, abstime_ostr, &abstime_tmp);
12024802138dSJin Yao if (ret < 0)
12034802138dSJin Yao goto out_delete;
12044802138dSJin Yao }
12054802138dSJin Yao
1206daca23b2SJin Yao if (cpu_list) {
1207daca23b2SJin Yao ret = perf_session__cpu_bitmap(d->session, cpu_list,
1208daca23b2SJin Yao cpu_bitmap);
1209daca23b2SJin Yao if (ret < 0)
1210daca23b2SJin Yao goto out_delete;
1211daca23b2SJin Yao }
1212daca23b2SJin Yao
1213b7b61cbeSArnaldo Carvalho de Melo ret = perf_session__process_events(d->session);
1214ec308426SJiri Olsa if (ret) {
12152d4f2799SJiri Olsa pr_err("Failed to process %s\n", d->data.path);
1216ec308426SJiri Olsa goto out_delete;
1217ec308426SJiri Olsa }
1218ec308426SJiri Olsa
1219b979a2f1SArnaldo Carvalho de Melo evlist__collapse_resort(d->session->evlist);
12204802138dSJin Yao
12214802138dSJin Yao if (pdiff.ptime_range)
12224802138dSJin Yao zfree(&pdiff.ptime_range);
12232a09a84cSJin Yao
12242a09a84cSJin Yao if (compute == COMPUTE_STREAM) {
12252a09a84cSJin Yao d->evlist_streams = evlist__create_streams(
12262a09a84cSJin Yao d->session->evlist, 5);
122797130700SZhen Lei if (!d->evlist_streams) {
122897130700SZhen Lei ret = -ENOMEM;
12292a09a84cSJin Yao goto out_delete;
12302a09a84cSJin Yao }
1231ec308426SJiri Olsa }
123297130700SZhen Lei }
1233ec308426SJiri Olsa
12342a09a84cSJin Yao if (compute == COMPUTE_STREAM)
12352a09a84cSJin Yao stream_process();
12362a09a84cSJin Yao else
1237ec308426SJiri Olsa data_process();
1238ec308426SJiri Olsa
123986a9eee0SArnaldo Carvalho de Melo out_delete:
1240ec308426SJiri Olsa data__for_each_file(i, d) {
1241ffc52b7aSDmitry Safonov if (!IS_ERR(d->session))
1242ec308426SJiri Olsa perf_session__delete(d->session);
1243c818b498SJiri Olsa data__free(d);
1244ec308426SJiri Olsa }
1245ec308426SJiri Olsa
1246ec308426SJiri Olsa free(data__files);
12474802138dSJin Yao
12484802138dSJin Yao if (pdiff.ptime_range)
12494802138dSJin Yao zfree(&pdiff.ptime_range);
12504802138dSJin Yao
12514802138dSJin Yao if (abstime_ostr)
12524802138dSJin Yao free(abstime_ostr);
12534802138dSJin Yao
125486a9eee0SArnaldo Carvalho de Melo return ret;
125586a9eee0SArnaldo Carvalho de Melo }
125686a9eee0SArnaldo Carvalho de Melo
125786a9eee0SArnaldo Carvalho de Melo static const char * const diff_usage[] = {
125886a9eee0SArnaldo Carvalho de Melo "perf diff [<options>] [old_file] [new_file]",
12590422a4fcSArnaldo Carvalho de Melo NULL,
126086a9eee0SArnaldo Carvalho de Melo };
126186a9eee0SArnaldo Carvalho de Melo
126286a9eee0SArnaldo Carvalho de Melo static const struct option options[] = {
1263c0555642SIan Munsie OPT_INCR('v', "verbose", &verbose,
126486a9eee0SArnaldo Carvalho de Melo "be more verbose (show symbol address, etc)"),
1265a527c2c1SJames Clark OPT_BOOLEAN('q', "quiet", &quiet, "Do not show any warnings or messages"),
1266a06d143eSJiri Olsa OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
1267a06d143eSJiri Olsa "Show only items with match in baseline"),
126881d5f958SJiri Olsa OPT_CALLBACK('c', "compute", &compute,
1269b10c78c5SJin Yao "delta,delta-abs,ratio,wdiff:w1,w2 (default delta-abs),cycles",
12707aaf6b35SJiri Olsa "Entries differential computation selection",
12717aaf6b35SJiri Olsa setup_compute),
127261949b21SJiri Olsa OPT_BOOLEAN('p', "period", &show_period,
127361949b21SJiri Olsa "Show period values."),
1274ed279da2SJiri Olsa OPT_BOOLEAN('F', "formula", &show_formula,
1275ed279da2SJiri Olsa "Show formula."),
1276cebf7d51SJin Yao OPT_BOOLEAN(0, "cycles-hist", &cycles_hist,
1277cebf7d51SJin Yao "Show cycles histogram and standard deviation "
1278cebf7d51SJin Yao "- WARNING: use only with -c cycles."),
127986a9eee0SArnaldo Carvalho de Melo OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
128086a9eee0SArnaldo Carvalho de Melo "dump raw trace in ASCII"),
128186a9eee0SArnaldo Carvalho de Melo OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
12826b1f3423SDavid Ahern OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
12836b1f3423SDavid Ahern "file", "kallsyms pathname"),
128486a9eee0SArnaldo Carvalho de Melo OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
128586a9eee0SArnaldo Carvalho de Melo "load module symbols - WARNING: use only with -k and LIVE kernel"),
1286c410a338SArnaldo Carvalho de Melo OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
1287c410a338SArnaldo Carvalho de Melo "only consider symbols in these dsos"),
1288c410a338SArnaldo Carvalho de Melo OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1289c410a338SArnaldo Carvalho de Melo "only consider symbols in these comms"),
1290c410a338SArnaldo Carvalho de Melo OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1291c410a338SArnaldo Carvalho de Melo "only consider these symbols"),
1292c351c281SArnaldo Carvalho de Melo OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1293a2ce067eSNamhyung Kim "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
1294a2ce067eSNamhyung Kim " Please refer the man page for the complete list."),
12958b8ca6e1SWang Nan OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator",
1296c351c281SArnaldo Carvalho de Melo "separator for columns, no spaces will be added between "
1297c351c281SArnaldo Carvalho de Melo "columns '.' is reserved."),
1298a7066709SHe Kuang OPT_CALLBACK(0, "symfs", NULL, "directory",
1299a7066709SHe Kuang "Look for files with symbols relative to this directory",
1300a7066709SHe Kuang symbol__config_symfs),
13015f3f8d3bSJiri Olsa OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
13028810f6ceSNamhyung Kim OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
13038810f6ceSNamhyung Kim "How to display percentage of filtered entries", parse_filter_percentage),
13044802138dSJin Yao OPT_STRING(0, "time", &pdiff.time_str, "str",
13054802138dSJin Yao "Time span (time percent or absolute timestamp)"),
1306daca23b2SJin Yao OPT_STRING(0, "cpu", &cpu_list, "cpu", "list of cpus to profile"),
1307c1d3e633SJin Yao OPT_STRING(0, "pid", &symbol_conf.pid_list_str, "pid[,pid...]",
1308c1d3e633SJin Yao "only consider symbols in these pids"),
1309c1d3e633SJin Yao OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
1310c1d3e633SJin Yao "only consider symbols in these tids"),
13112a09a84cSJin Yao OPT_BOOLEAN(0, "stream", &pdiff.stream,
13122a09a84cSJin Yao "Enable hot streams comparison."),
131386a9eee0SArnaldo Carvalho de Melo OPT_END()
131486a9eee0SArnaldo Carvalho de Melo };
131586a9eee0SArnaldo Carvalho de Melo
baseline_percent(struct hist_entry * he)1316345dc0b4SJiri Olsa static double baseline_percent(struct hist_entry *he)
13171d77822eSJiri Olsa {
13188810f6ceSNamhyung Kim u64 total = hists__total_period(he->hists);
13198810f6ceSNamhyung Kim
13208810f6ceSNamhyung Kim return 100.0 * he->stat.period / total;
1321345dc0b4SJiri Olsa }
13227aaf6b35SJiri Olsa
hpp__color_baseline(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)1323345dc0b4SJiri Olsa static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
1324345dc0b4SJiri Olsa struct perf_hpp *hpp, struct hist_entry *he)
1325345dc0b4SJiri Olsa {
1326345dc0b4SJiri Olsa struct diff_hpp_fmt *dfmt =
1327345dc0b4SJiri Olsa container_of(fmt, struct diff_hpp_fmt, fmt);
1328345dc0b4SJiri Olsa double percent = baseline_percent(he);
1329345dc0b4SJiri Olsa char pfmt[20] = " ";
1330345dc0b4SJiri Olsa
1331345dc0b4SJiri Olsa if (!he->dummy) {
1332345dc0b4SJiri Olsa scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1);
1333345dc0b4SJiri Olsa return percent_color_snprintf(hpp->buf, hpp->size,
1334345dc0b4SJiri Olsa pfmt, percent);
1335345dc0b4SJiri Olsa } else
1336345dc0b4SJiri Olsa return scnprintf(hpp->buf, hpp->size, "%*s",
1337345dc0b4SJiri Olsa dfmt->header_width, pfmt);
1338345dc0b4SJiri Olsa }
1339345dc0b4SJiri Olsa
hpp__entry_baseline(struct hist_entry * he,char * buf,size_t size)1340345dc0b4SJiri Olsa static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
1341345dc0b4SJiri Olsa {
1342345dc0b4SJiri Olsa double percent = baseline_percent(he);
1343345dc0b4SJiri Olsa const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
1344345dc0b4SJiri Olsa int ret = 0;
1345345dc0b4SJiri Olsa
1346345dc0b4SJiri Olsa if (!he->dummy)
1347345dc0b4SJiri Olsa ret = scnprintf(buf, size, fmt, percent);
1348345dc0b4SJiri Olsa
1349345dc0b4SJiri Olsa return ret;
1350345dc0b4SJiri Olsa }
1351345dc0b4SJiri Olsa
cycles_printf(struct hist_entry * he,struct hist_entry * pair,struct perf_hpp * hpp,int width)1352b10c78c5SJin Yao static int cycles_printf(struct hist_entry *he, struct hist_entry *pair,
1353b10c78c5SJin Yao struct perf_hpp *hpp, int width)
1354b10c78c5SJin Yao {
1355b10c78c5SJin Yao struct block_hist *bh = container_of(he, struct block_hist, he);
1356b10c78c5SJin Yao struct block_hist *bh_pair = container_of(pair, struct block_hist, he);
1357b10c78c5SJin Yao struct hist_entry *block_he;
1358b10c78c5SJin Yao struct block_info *bi;
1359b10c78c5SJin Yao char buf[128];
1360b10c78c5SJin Yao char *start_line, *end_line;
1361b10c78c5SJin Yao
1362b10c78c5SJin Yao block_he = hists__get_entry(&bh_pair->block_hists, bh->block_idx);
1363b10c78c5SJin Yao if (!block_he) {
1364b10c78c5SJin Yao hpp->skip = true;
1365b10c78c5SJin Yao return 0;
1366b10c78c5SJin Yao }
1367b10c78c5SJin Yao
1368b10c78c5SJin Yao /*
1369b10c78c5SJin Yao * Avoid printing the warning "addr2line_init failed for ..."
1370b10c78c5SJin Yao */
1371b10c78c5SJin Yao symbol_conf.disable_add2line_warn = true;
1372b10c78c5SJin Yao
1373b10c78c5SJin Yao bi = block_he->block_info;
1374b10c78c5SJin Yao
1375b10c78c5SJin Yao start_line = map__srcline(he->ms.map, bi->sym->start + bi->start,
1376b10c78c5SJin Yao he->ms.sym);
1377b10c78c5SJin Yao
1378b10c78c5SJin Yao end_line = map__srcline(he->ms.map, bi->sym->start + bi->end,
1379b10c78c5SJin Yao he->ms.sym);
1380b10c78c5SJin Yao
1381922db21dSArnaldo Carvalho de Melo if (start_line != SRCLINE_UNKNOWN &&
1382922db21dSArnaldo Carvalho de Melo end_line != SRCLINE_UNKNOWN) {
1383b10c78c5SJin Yao scnprintf(buf, sizeof(buf), "[%s -> %s] %4ld",
1384b10c78c5SJin Yao start_line, end_line, block_he->diff.cycles);
1385b10c78c5SJin Yao } else {
1386b10c78c5SJin Yao scnprintf(buf, sizeof(buf), "[%7lx -> %7lx] %4ld",
1387b10c78c5SJin Yao bi->start, bi->end, block_he->diff.cycles);
1388b10c78c5SJin Yao }
1389b10c78c5SJin Yao
1390625db36eSIan Rogers zfree_srcline(&start_line);
1391625db36eSIan Rogers zfree_srcline(&end_line);
1392b10c78c5SJin Yao
1393b10c78c5SJin Yao return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1394b10c78c5SJin Yao }
1395b10c78c5SJin Yao
__hpp__color_compare(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he,int comparison_method)139601f10bc8SRamkumar Ramachandra static int __hpp__color_compare(struct perf_hpp_fmt *fmt,
139701f10bc8SRamkumar Ramachandra struct perf_hpp *hpp, struct hist_entry *he,
139801f10bc8SRamkumar Ramachandra int comparison_method)
139901f10bc8SRamkumar Ramachandra {
140001f10bc8SRamkumar Ramachandra struct diff_hpp_fmt *dfmt =
140101f10bc8SRamkumar Ramachandra container_of(fmt, struct diff_hpp_fmt, fmt);
140201f10bc8SRamkumar Ramachandra struct hist_entry *pair = get_pair_fmt(he, dfmt);
140301f10bc8SRamkumar Ramachandra double diff;
1404a5846e21SRamkumar Ramachandra s64 wdiff;
140501f10bc8SRamkumar Ramachandra char pfmt[20] = " ";
140601f10bc8SRamkumar Ramachandra
1407b10c78c5SJin Yao if (!pair) {
1408b10c78c5SJin Yao if (comparison_method == COMPUTE_CYCLES) {
1409b10c78c5SJin Yao struct block_hist *bh;
1410b10c78c5SJin Yao
1411b10c78c5SJin Yao bh = container_of(he, struct block_hist, he);
1412b10c78c5SJin Yao if (bh->block_idx)
1413b10c78c5SJin Yao hpp->skip = true;
1414b10c78c5SJin Yao }
1415b10c78c5SJin Yao
1416ec3d07cbSNamhyung Kim goto no_print;
1417b10c78c5SJin Yao }
141801f10bc8SRamkumar Ramachandra
141901f10bc8SRamkumar Ramachandra switch (comparison_method) {
142001f10bc8SRamkumar Ramachandra case COMPUTE_DELTA:
142101f10bc8SRamkumar Ramachandra if (pair->diff.computed)
142201f10bc8SRamkumar Ramachandra diff = pair->diff.period_ratio_delta;
142301f10bc8SRamkumar Ramachandra else
142401f10bc8SRamkumar Ramachandra diff = compute_delta(he, pair);
142501f10bc8SRamkumar Ramachandra
142601f10bc8SRamkumar Ramachandra scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1);
142701f10bc8SRamkumar Ramachandra return percent_color_snprintf(hpp->buf, hpp->size,
142801f10bc8SRamkumar Ramachandra pfmt, diff);
14291f513b2cSRamkumar Ramachandra case COMPUTE_RATIO:
14301f513b2cSRamkumar Ramachandra if (he->dummy)
14311f513b2cSRamkumar Ramachandra goto dummy_print;
14321f513b2cSRamkumar Ramachandra if (pair->diff.computed)
14331f513b2cSRamkumar Ramachandra diff = pair->diff.period_ratio;
14341f513b2cSRamkumar Ramachandra else
14351f513b2cSRamkumar Ramachandra diff = compute_ratio(he, pair);
14361f513b2cSRamkumar Ramachandra
14371f513b2cSRamkumar Ramachandra scnprintf(pfmt, 20, "%%%d.6f", dfmt->header_width);
14381f513b2cSRamkumar Ramachandra return value_color_snprintf(hpp->buf, hpp->size,
14391f513b2cSRamkumar Ramachandra pfmt, diff);
1440a5846e21SRamkumar Ramachandra case COMPUTE_WEIGHTED_DIFF:
1441a5846e21SRamkumar Ramachandra if (he->dummy)
1442a5846e21SRamkumar Ramachandra goto dummy_print;
1443a5846e21SRamkumar Ramachandra if (pair->diff.computed)
1444a5846e21SRamkumar Ramachandra wdiff = pair->diff.wdiff;
1445a5846e21SRamkumar Ramachandra else
1446a5846e21SRamkumar Ramachandra wdiff = compute_wdiff(he, pair);
1447a5846e21SRamkumar Ramachandra
1448a5846e21SRamkumar Ramachandra scnprintf(pfmt, 20, "%%14ld", dfmt->header_width);
1449a5846e21SRamkumar Ramachandra return color_snprintf(hpp->buf, hpp->size,
1450a5846e21SRamkumar Ramachandra get_percent_color(wdiff),
1451a5846e21SRamkumar Ramachandra pfmt, wdiff);
1452b10c78c5SJin Yao case COMPUTE_CYCLES:
1453b10c78c5SJin Yao return cycles_printf(he, pair, hpp, dfmt->header_width);
145401f10bc8SRamkumar Ramachandra default:
145501f10bc8SRamkumar Ramachandra BUG_ON(1);
145601f10bc8SRamkumar Ramachandra }
145701f10bc8SRamkumar Ramachandra dummy_print:
145801f10bc8SRamkumar Ramachandra return scnprintf(hpp->buf, hpp->size, "%*s",
1459ec3d07cbSNamhyung Kim dfmt->header_width, "N/A");
1460ec3d07cbSNamhyung Kim no_print:
1461ec3d07cbSNamhyung Kim return scnprintf(hpp->buf, hpp->size, "%*s",
146201f10bc8SRamkumar Ramachandra dfmt->header_width, pfmt);
146301f10bc8SRamkumar Ramachandra }
146401f10bc8SRamkumar Ramachandra
hpp__color_delta(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)146501f10bc8SRamkumar Ramachandra static int hpp__color_delta(struct perf_hpp_fmt *fmt,
146601f10bc8SRamkumar Ramachandra struct perf_hpp *hpp, struct hist_entry *he)
146701f10bc8SRamkumar Ramachandra {
146801f10bc8SRamkumar Ramachandra return __hpp__color_compare(fmt, hpp, he, COMPUTE_DELTA);
146901f10bc8SRamkumar Ramachandra }
147001f10bc8SRamkumar Ramachandra
hpp__color_ratio(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)14711f513b2cSRamkumar Ramachandra static int hpp__color_ratio(struct perf_hpp_fmt *fmt,
14721f513b2cSRamkumar Ramachandra struct perf_hpp *hpp, struct hist_entry *he)
14731f513b2cSRamkumar Ramachandra {
14741f513b2cSRamkumar Ramachandra return __hpp__color_compare(fmt, hpp, he, COMPUTE_RATIO);
14751f513b2cSRamkumar Ramachandra }
14761f513b2cSRamkumar Ramachandra
hpp__color_wdiff(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)1477a5846e21SRamkumar Ramachandra static int hpp__color_wdiff(struct perf_hpp_fmt *fmt,
1478a5846e21SRamkumar Ramachandra struct perf_hpp *hpp, struct hist_entry *he)
1479a5846e21SRamkumar Ramachandra {
1480a5846e21SRamkumar Ramachandra return __hpp__color_compare(fmt, hpp, he, COMPUTE_WEIGHTED_DIFF);
1481a5846e21SRamkumar Ramachandra }
1482a5846e21SRamkumar Ramachandra
hpp__color_cycles(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)1483b10c78c5SJin Yao static int hpp__color_cycles(struct perf_hpp_fmt *fmt,
1484b10c78c5SJin Yao struct perf_hpp *hpp, struct hist_entry *he)
1485b10c78c5SJin Yao {
1486b10c78c5SJin Yao return __hpp__color_compare(fmt, hpp, he, COMPUTE_CYCLES);
1487b10c78c5SJin Yao }
1488b10c78c5SJin Yao
all_zero(unsigned long * vals,int len)1489cebf7d51SJin Yao static int all_zero(unsigned long *vals, int len)
1490cebf7d51SJin Yao {
1491cebf7d51SJin Yao int i;
1492cebf7d51SJin Yao
1493cebf7d51SJin Yao for (i = 0; i < len; i++)
1494cebf7d51SJin Yao if (vals[i] != 0)
1495cebf7d51SJin Yao return 0;
1496cebf7d51SJin Yao return 1;
1497cebf7d51SJin Yao }
1498cebf7d51SJin Yao
print_cycles_spark(char * bf,int size,unsigned long * svals,u64 n)1499cebf7d51SJin Yao static int print_cycles_spark(char *bf, int size, unsigned long *svals, u64 n)
1500cebf7d51SJin Yao {
1501cebf7d51SJin Yao int printed;
1502cebf7d51SJin Yao
1503cebf7d51SJin Yao if (n <= 1)
1504cebf7d51SJin Yao return 0;
1505cebf7d51SJin Yao
1506cebf7d51SJin Yao if (n > NUM_SPARKS)
1507cebf7d51SJin Yao n = NUM_SPARKS;
1508cebf7d51SJin Yao if (all_zero(svals, n))
1509cebf7d51SJin Yao return 0;
1510cebf7d51SJin Yao
1511cebf7d51SJin Yao printed = print_spark(bf, size, svals, n);
1512cebf7d51SJin Yao printed += scnprintf(bf + printed, size - printed, " ");
1513cebf7d51SJin Yao return printed;
1514cebf7d51SJin Yao }
1515cebf7d51SJin Yao
hpp__color_cycles_hist(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)1516cebf7d51SJin Yao static int hpp__color_cycles_hist(struct perf_hpp_fmt *fmt,
1517cebf7d51SJin Yao struct perf_hpp *hpp, struct hist_entry *he)
1518cebf7d51SJin Yao {
1519cebf7d51SJin Yao struct diff_hpp_fmt *dfmt =
1520cebf7d51SJin Yao container_of(fmt, struct diff_hpp_fmt, fmt);
1521cebf7d51SJin Yao struct hist_entry *pair = get_pair_fmt(he, dfmt);
1522cebf7d51SJin Yao struct block_hist *bh = container_of(he, struct block_hist, he);
1523cebf7d51SJin Yao struct block_hist *bh_pair;
1524cebf7d51SJin Yao struct hist_entry *block_he;
1525cebf7d51SJin Yao char spark[32], buf[128];
1526cebf7d51SJin Yao double r;
1527cebf7d51SJin Yao int ret, pad;
1528cebf7d51SJin Yao
1529cebf7d51SJin Yao if (!pair) {
1530cebf7d51SJin Yao if (bh->block_idx)
1531cebf7d51SJin Yao hpp->skip = true;
1532cebf7d51SJin Yao
1533cebf7d51SJin Yao goto no_print;
1534cebf7d51SJin Yao }
1535cebf7d51SJin Yao
1536cebf7d51SJin Yao bh_pair = container_of(pair, struct block_hist, he);
1537cebf7d51SJin Yao
1538cebf7d51SJin Yao block_he = hists__get_entry(&bh_pair->block_hists, bh->block_idx);
1539cebf7d51SJin Yao if (!block_he) {
1540cebf7d51SJin Yao hpp->skip = true;
1541cebf7d51SJin Yao goto no_print;
1542cebf7d51SJin Yao }
1543cebf7d51SJin Yao
1544cebf7d51SJin Yao ret = print_cycles_spark(spark, sizeof(spark), block_he->diff.svals,
1545cebf7d51SJin Yao block_he->diff.stats.n);
1546cebf7d51SJin Yao
1547cebf7d51SJin Yao r = rel_stddev_stats(stddev_stats(&block_he->diff.stats),
1548cebf7d51SJin Yao avg_stats(&block_he->diff.stats));
1549cebf7d51SJin Yao
1550cebf7d51SJin Yao if (ret) {
1551cebf7d51SJin Yao /*
1552cebf7d51SJin Yao * Padding spaces if number of sparks less than NUM_SPARKS
1553cebf7d51SJin Yao * otherwise the output is not aligned.
1554cebf7d51SJin Yao */
1555cebf7d51SJin Yao pad = NUM_SPARKS - ((ret - 1) / 3);
1556cebf7d51SJin Yao scnprintf(buf, sizeof(buf), "%s%5.1f%% %s", "\u00B1", r, spark);
1557cebf7d51SJin Yao ret = scnprintf(hpp->buf, hpp->size, "%*s",
1558cebf7d51SJin Yao dfmt->header_width, buf);
1559cebf7d51SJin Yao
1560cebf7d51SJin Yao if (pad) {
1561cebf7d51SJin Yao ret += scnprintf(hpp->buf + ret, hpp->size - ret,
1562cebf7d51SJin Yao "%-*s", pad, " ");
1563cebf7d51SJin Yao }
1564cebf7d51SJin Yao
1565cebf7d51SJin Yao return ret;
1566cebf7d51SJin Yao }
1567cebf7d51SJin Yao
1568cebf7d51SJin Yao no_print:
1569cebf7d51SJin Yao return scnprintf(hpp->buf, hpp->size, "%*s",
1570cebf7d51SJin Yao dfmt->header_width, " ");
1571cebf7d51SJin Yao }
1572cebf7d51SJin Yao
1573345dc0b4SJiri Olsa static void
hpp__entry_unpair(struct hist_entry * he,int idx,char * buf,size_t size)1574345dc0b4SJiri Olsa hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
1575345dc0b4SJiri Olsa {
1576345dc0b4SJiri Olsa switch (idx) {
1577345dc0b4SJiri Olsa case PERF_HPP_DIFF__PERIOD_BASELINE:
1578345dc0b4SJiri Olsa scnprintf(buf, size, "%" PRIu64, he->stat.period);
15797aaf6b35SJiri Olsa break;
1580345dc0b4SJiri Olsa
1581345dc0b4SJiri Olsa default:
15827aaf6b35SJiri Olsa break;
1583345dc0b4SJiri Olsa }
1584345dc0b4SJiri Olsa }
1585345dc0b4SJiri Olsa
1586345dc0b4SJiri Olsa static void
hpp__entry_pair(struct hist_entry * he,struct hist_entry * pair,int idx,char * buf,size_t size)1587345dc0b4SJiri Olsa hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
1588345dc0b4SJiri Olsa int idx, char *buf, size_t size)
1589345dc0b4SJiri Olsa {
1590345dc0b4SJiri Olsa double diff;
1591345dc0b4SJiri Olsa double ratio;
1592345dc0b4SJiri Olsa s64 wdiff;
1593345dc0b4SJiri Olsa
1594345dc0b4SJiri Olsa switch (idx) {
1595345dc0b4SJiri Olsa case PERF_HPP_DIFF__DELTA:
1596a1668c25SNamhyung Kim case PERF_HPP_DIFF__DELTA_ABS:
1597345dc0b4SJiri Olsa if (pair->diff.computed)
1598345dc0b4SJiri Olsa diff = pair->diff.period_ratio_delta;
1599345dc0b4SJiri Olsa else
1600ef358e6dSJiri Olsa diff = compute_delta(he, pair);
1601345dc0b4SJiri Olsa
1602345dc0b4SJiri Olsa scnprintf(buf, size, "%+4.2F%%", diff);
160381d5f958SJiri Olsa break;
1604345dc0b4SJiri Olsa
1605345dc0b4SJiri Olsa case PERF_HPP_DIFF__RATIO:
1606345dc0b4SJiri Olsa /* No point for ratio number if we are dummy.. */
1607ec3d07cbSNamhyung Kim if (he->dummy) {
1608ec3d07cbSNamhyung Kim scnprintf(buf, size, "N/A");
1609345dc0b4SJiri Olsa break;
1610ec3d07cbSNamhyung Kim }
1611345dc0b4SJiri Olsa
1612345dc0b4SJiri Olsa if (pair->diff.computed)
1613345dc0b4SJiri Olsa ratio = pair->diff.period_ratio;
1614345dc0b4SJiri Olsa else
1615ef358e6dSJiri Olsa ratio = compute_ratio(he, pair);
1616345dc0b4SJiri Olsa
1617345dc0b4SJiri Olsa if (ratio > 0.0)
1618345dc0b4SJiri Olsa scnprintf(buf, size, "%14.6F", ratio);
1619345dc0b4SJiri Olsa break;
1620345dc0b4SJiri Olsa
1621345dc0b4SJiri Olsa case PERF_HPP_DIFF__WEIGHTED_DIFF:
1622345dc0b4SJiri Olsa /* No point for wdiff number if we are dummy.. */
1623ec3d07cbSNamhyung Kim if (he->dummy) {
1624ec3d07cbSNamhyung Kim scnprintf(buf, size, "N/A");
1625345dc0b4SJiri Olsa break;
1626ec3d07cbSNamhyung Kim }
1627345dc0b4SJiri Olsa
1628345dc0b4SJiri Olsa if (pair->diff.computed)
1629345dc0b4SJiri Olsa wdiff = pair->diff.wdiff;
1630345dc0b4SJiri Olsa else
1631ef358e6dSJiri Olsa wdiff = compute_wdiff(he, pair);
1632345dc0b4SJiri Olsa
1633345dc0b4SJiri Olsa if (wdiff != 0)
1634345dc0b4SJiri Olsa scnprintf(buf, size, "%14ld", wdiff);
1635345dc0b4SJiri Olsa break;
1636345dc0b4SJiri Olsa
1637345dc0b4SJiri Olsa case PERF_HPP_DIFF__FORMULA:
1638ef358e6dSJiri Olsa formula_fprintf(he, pair, buf, size);
1639345dc0b4SJiri Olsa break;
1640345dc0b4SJiri Olsa
1641345dc0b4SJiri Olsa case PERF_HPP_DIFF__PERIOD:
1642345dc0b4SJiri Olsa scnprintf(buf, size, "%" PRIu64, pair->stat.period);
1643345dc0b4SJiri Olsa break;
1644345dc0b4SJiri Olsa
16457aaf6b35SJiri Olsa default:
16467aaf6b35SJiri Olsa BUG_ON(1);
16478284bbeaSZou Wei }
1648345dc0b4SJiri Olsa }
1649345dc0b4SJiri Olsa
165022aeb7f5SJiri Olsa static void
__hpp__entry_global(struct hist_entry * he,struct diff_hpp_fmt * dfmt,char * buf,size_t size)165122aeb7f5SJiri Olsa __hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt,
165222aeb7f5SJiri Olsa char *buf, size_t size)
165322aeb7f5SJiri Olsa {
16545f3f8d3bSJiri Olsa struct hist_entry *pair = get_pair_fmt(he, dfmt);
165522aeb7f5SJiri Olsa int idx = dfmt->idx;
1656345dc0b4SJiri Olsa
1657345dc0b4SJiri Olsa /* baseline is special */
1658345dc0b4SJiri Olsa if (idx == PERF_HPP_DIFF__BASELINE)
1659345dc0b4SJiri Olsa hpp__entry_baseline(he, buf, size);
1660345dc0b4SJiri Olsa else {
1661345dc0b4SJiri Olsa if (pair)
1662345dc0b4SJiri Olsa hpp__entry_pair(he, pair, idx, buf, size);
1663345dc0b4SJiri Olsa else
1664345dc0b4SJiri Olsa hpp__entry_unpair(he, idx, buf, size);
1665345dc0b4SJiri Olsa }
1666345dc0b4SJiri Olsa }
1667345dc0b4SJiri Olsa
hpp__entry_global(struct perf_hpp_fmt * _fmt,struct perf_hpp * hpp,struct hist_entry * he)1668345dc0b4SJiri Olsa static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
1669345dc0b4SJiri Olsa struct hist_entry *he)
1670345dc0b4SJiri Olsa {
1671345dc0b4SJiri Olsa struct diff_hpp_fmt *dfmt =
1672345dc0b4SJiri Olsa container_of(_fmt, struct diff_hpp_fmt, fmt);
1673345dc0b4SJiri Olsa char buf[MAX_COL_WIDTH] = " ";
1674345dc0b4SJiri Olsa
167522aeb7f5SJiri Olsa __hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH);
1676345dc0b4SJiri Olsa
1677345dc0b4SJiri Olsa if (symbol_conf.field_sep)
1678345dc0b4SJiri Olsa return scnprintf(hpp->buf, hpp->size, "%s", buf);
1679345dc0b4SJiri Olsa else
1680345dc0b4SJiri Olsa return scnprintf(hpp->buf, hpp->size, "%*s",
1681345dc0b4SJiri Olsa dfmt->header_width, buf);
1682345dc0b4SJiri Olsa }
1683345dc0b4SJiri 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)168494a0793dSNamhyung Kim static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
168574bb43f2SJiri Olsa struct hists *hists __maybe_unused,
168629659ab4SJiri Olsa int line __maybe_unused,
168729659ab4SJiri Olsa int *span __maybe_unused)
1688345dc0b4SJiri Olsa {
1689345dc0b4SJiri Olsa struct diff_hpp_fmt *dfmt =
1690345dc0b4SJiri Olsa container_of(fmt, struct diff_hpp_fmt, fmt);
1691345dc0b4SJiri Olsa
1692345dc0b4SJiri Olsa BUG_ON(!dfmt->header);
1693345dc0b4SJiri Olsa return scnprintf(hpp->buf, hpp->size, dfmt->header);
1694345dc0b4SJiri Olsa }
1695345dc0b4SJiri Olsa
hpp__width(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp __maybe_unused,struct hists * hists __maybe_unused)1696345dc0b4SJiri Olsa static int hpp__width(struct perf_hpp_fmt *fmt,
169794a0793dSNamhyung Kim struct perf_hpp *hpp __maybe_unused,
1698da1b0407SJiri Olsa struct hists *hists __maybe_unused)
1699345dc0b4SJiri Olsa {
1700345dc0b4SJiri Olsa struct diff_hpp_fmt *dfmt =
1701345dc0b4SJiri Olsa container_of(fmt, struct diff_hpp_fmt, fmt);
1702345dc0b4SJiri Olsa
1703345dc0b4SJiri Olsa BUG_ON(dfmt->header_width <= 0);
1704345dc0b4SJiri Olsa return dfmt->header_width;
1705345dc0b4SJiri Olsa }
1706345dc0b4SJiri Olsa
init_header(struct data__file * d,struct diff_hpp_fmt * dfmt)170722aeb7f5SJiri Olsa static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt)
1708345dc0b4SJiri Olsa {
1709345dc0b4SJiri Olsa #define MAX_HEADER_NAME 100
1710345dc0b4SJiri Olsa char buf_indent[MAX_HEADER_NAME];
1711345dc0b4SJiri Olsa char buf[MAX_HEADER_NAME];
1712345dc0b4SJiri Olsa const char *header = NULL;
1713345dc0b4SJiri Olsa int width = 0;
1714345dc0b4SJiri Olsa
1715345dc0b4SJiri Olsa BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX);
1716345dc0b4SJiri Olsa header = columns[dfmt->idx].name;
1717345dc0b4SJiri Olsa width = columns[dfmt->idx].width;
1718345dc0b4SJiri Olsa
1719345dc0b4SJiri Olsa /* Only our defined HPP fmts should appear here. */
1720345dc0b4SJiri Olsa BUG_ON(!header);
1721345dc0b4SJiri Olsa
172222aeb7f5SJiri Olsa if (data__files_cnt > 2)
172322aeb7f5SJiri Olsa scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx);
172422aeb7f5SJiri Olsa
1725345dc0b4SJiri Olsa #define NAME (data__files_cnt > 2 ? buf : header)
1726345dc0b4SJiri Olsa dfmt->header_width = width;
1727345dc0b4SJiri Olsa width = (int) strlen(NAME);
1728345dc0b4SJiri Olsa if (dfmt->header_width < width)
1729345dc0b4SJiri Olsa dfmt->header_width = width;
1730345dc0b4SJiri Olsa
1731345dc0b4SJiri Olsa scnprintf(buf_indent, MAX_HEADER_NAME, "%*s",
1732345dc0b4SJiri Olsa dfmt->header_width, NAME);
1733345dc0b4SJiri Olsa
1734345dc0b4SJiri Olsa dfmt->header = strdup(buf_indent);
1735345dc0b4SJiri Olsa #undef MAX_HEADER_NAME
1736345dc0b4SJiri Olsa #undef NAME
1737345dc0b4SJiri Olsa }
1738345dc0b4SJiri Olsa
data__hpp_register(struct data__file * d,int idx)1739c818b498SJiri Olsa static void data__hpp_register(struct data__file *d, int idx)
1740345dc0b4SJiri Olsa {
1741c818b498SJiri Olsa struct diff_hpp_fmt *dfmt = &d->fmt[idx];
1742c818b498SJiri Olsa struct perf_hpp_fmt *fmt = &dfmt->fmt;
1743345dc0b4SJiri Olsa
1744c818b498SJiri Olsa dfmt->idx = idx;
1745c818b498SJiri Olsa
1746c818b498SJiri Olsa fmt->header = hpp__header;
1747c818b498SJiri Olsa fmt->width = hpp__width;
1748c818b498SJiri Olsa fmt->entry = hpp__entry_global;
1749e7024fc3SNamhyung Kim fmt->cmp = hist_entry__cmp_nop;
1750e7024fc3SNamhyung Kim fmt->collapse = hist_entry__cmp_nop;
1751c818b498SJiri Olsa
1752c818b498SJiri Olsa /* TODO more colors */
175301f10bc8SRamkumar Ramachandra switch (idx) {
175401f10bc8SRamkumar Ramachandra case PERF_HPP_DIFF__BASELINE:
1755c818b498SJiri Olsa fmt->color = hpp__color_baseline;
1756e7024fc3SNamhyung Kim fmt->sort = hist_entry__cmp_baseline;
175701f10bc8SRamkumar Ramachandra break;
175801f10bc8SRamkumar Ramachandra case PERF_HPP_DIFF__DELTA:
175901f10bc8SRamkumar Ramachandra fmt->color = hpp__color_delta;
1760e7024fc3SNamhyung Kim fmt->sort = hist_entry__cmp_delta;
176101f10bc8SRamkumar Ramachandra break;
17621f513b2cSRamkumar Ramachandra case PERF_HPP_DIFF__RATIO:
17631f513b2cSRamkumar Ramachandra fmt->color = hpp__color_ratio;
1764e7024fc3SNamhyung Kim fmt->sort = hist_entry__cmp_ratio;
17651f513b2cSRamkumar Ramachandra break;
1766a5846e21SRamkumar Ramachandra case PERF_HPP_DIFF__WEIGHTED_DIFF:
1767a5846e21SRamkumar Ramachandra fmt->color = hpp__color_wdiff;
1768e7024fc3SNamhyung Kim fmt->sort = hist_entry__cmp_wdiff;
1769a5846e21SRamkumar Ramachandra break;
1770a1668c25SNamhyung Kim case PERF_HPP_DIFF__DELTA_ABS:
1771a1668c25SNamhyung Kim fmt->color = hpp__color_delta;
1772a1668c25SNamhyung Kim fmt->sort = hist_entry__cmp_delta_abs;
1773a1668c25SNamhyung Kim break;
1774b10c78c5SJin Yao case PERF_HPP_DIFF__CYCLES:
1775b10c78c5SJin Yao fmt->color = hpp__color_cycles;
1776b10c78c5SJin Yao fmt->sort = hist_entry__cmp_nop;
1777b10c78c5SJin Yao break;
1778cebf7d51SJin Yao case PERF_HPP_DIFF__CYCLES_HIST:
1779cebf7d51SJin Yao fmt->color = hpp__color_cycles_hist;
1780cebf7d51SJin Yao fmt->sort = hist_entry__cmp_nop;
1781cebf7d51SJin Yao break;
178201f10bc8SRamkumar Ramachandra default:
1783e7024fc3SNamhyung Kim fmt->sort = hist_entry__cmp_nop;
178401f10bc8SRamkumar Ramachandra break;
178501f10bc8SRamkumar Ramachandra }
1786c818b498SJiri Olsa
178722aeb7f5SJiri Olsa init_header(d, dfmt);
1788c818b498SJiri Olsa perf_hpp__column_register(fmt);
1789e7024fc3SNamhyung Kim perf_hpp__register_sort_field(fmt);
1790345dc0b4SJiri Olsa }
1791345dc0b4SJiri Olsa
ui_init(void)1792566b5cfbSNamhyung Kim static int ui_init(void)
1793345dc0b4SJiri Olsa {
1794c818b498SJiri Olsa struct data__file *d;
1795566b5cfbSNamhyung Kim struct perf_hpp_fmt *fmt;
1796c818b498SJiri Olsa int i;
1797c818b498SJiri Olsa
1798c818b498SJiri Olsa data__for_each_file(i, d) {
1799c818b498SJiri Olsa
1800345dc0b4SJiri Olsa /*
18014d39c89fSIngo Molnar * Baseline or compute related columns:
1802c818b498SJiri Olsa *
1803c818b498SJiri Olsa * PERF_HPP_DIFF__BASELINE
1804c818b498SJiri Olsa * PERF_HPP_DIFF__DELTA
1805c818b498SJiri Olsa * PERF_HPP_DIFF__RATIO
1806c818b498SJiri Olsa * PERF_HPP_DIFF__WEIGHTED_DIFF
1807cebf7d51SJin Yao * PERF_HPP_DIFF__CYCLES
1808345dc0b4SJiri Olsa */
1809c818b498SJiri Olsa data__hpp_register(d, i ? compute_2_hpp[compute] :
1810c818b498SJiri Olsa PERF_HPP_DIFF__BASELINE);
18111d77822eSJiri Olsa
1812cebf7d51SJin Yao if (cycles_hist && i)
1813cebf7d51SJin Yao data__hpp_register(d, PERF_HPP_DIFF__CYCLES_HIST);
1814cebf7d51SJin Yao
1815c818b498SJiri Olsa /*
1816c818b498SJiri Olsa * And the rest:
1817c818b498SJiri Olsa *
1818c818b498SJiri Olsa * PERF_HPP_DIFF__FORMULA
1819c818b498SJiri Olsa * PERF_HPP_DIFF__PERIOD
1820c818b498SJiri Olsa * PERF_HPP_DIFF__PERIOD_BASELINE
1821c818b498SJiri Olsa */
1822c818b498SJiri Olsa if (show_formula && i)
1823c818b498SJiri Olsa data__hpp_register(d, PERF_HPP_DIFF__FORMULA);
1824ed279da2SJiri Olsa
1825c818b498SJiri Olsa if (show_period)
1826c818b498SJiri Olsa data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD :
1827c818b498SJiri Olsa PERF_HPP_DIFF__PERIOD_BASELINE);
182861949b21SJiri Olsa }
1829566b5cfbSNamhyung Kim
1830566b5cfbSNamhyung Kim if (!sort_compute)
1831566b5cfbSNamhyung Kim return 0;
1832566b5cfbSNamhyung Kim
1833566b5cfbSNamhyung Kim /*
1834566b5cfbSNamhyung Kim * Prepend an fmt to sort on columns at 'sort_compute' first.
1835566b5cfbSNamhyung Kim * This fmt is added only to the sort list but not to the
1836566b5cfbSNamhyung Kim * output fields list.
1837566b5cfbSNamhyung Kim *
1838566b5cfbSNamhyung Kim * Note that this column (data) can be compared twice - one
1839566b5cfbSNamhyung Kim * for this 'sort_compute' fmt and another for the normal
1840566b5cfbSNamhyung Kim * diff_hpp_fmt. But it shouldn't a problem as most entries
1841566b5cfbSNamhyung Kim * will be sorted out by first try or baseline and comparing
1842566b5cfbSNamhyung Kim * is not a costly operation.
1843566b5cfbSNamhyung Kim */
1844566b5cfbSNamhyung Kim fmt = zalloc(sizeof(*fmt));
1845566b5cfbSNamhyung Kim if (fmt == NULL) {
1846566b5cfbSNamhyung Kim pr_err("Memory allocation failed\n");
1847566b5cfbSNamhyung Kim return -1;
1848566b5cfbSNamhyung Kim }
1849566b5cfbSNamhyung Kim
1850566b5cfbSNamhyung Kim fmt->cmp = hist_entry__cmp_nop;
1851566b5cfbSNamhyung Kim fmt->collapse = hist_entry__cmp_nop;
1852566b5cfbSNamhyung Kim
1853566b5cfbSNamhyung Kim switch (compute) {
1854566b5cfbSNamhyung Kim case COMPUTE_DELTA:
1855566b5cfbSNamhyung Kim fmt->sort = hist_entry__cmp_delta_idx;
1856566b5cfbSNamhyung Kim break;
1857566b5cfbSNamhyung Kim case COMPUTE_RATIO:
1858566b5cfbSNamhyung Kim fmt->sort = hist_entry__cmp_ratio_idx;
1859566b5cfbSNamhyung Kim break;
1860566b5cfbSNamhyung Kim case COMPUTE_WEIGHTED_DIFF:
1861566b5cfbSNamhyung Kim fmt->sort = hist_entry__cmp_wdiff_idx;
1862566b5cfbSNamhyung Kim break;
1863a1668c25SNamhyung Kim case COMPUTE_DELTA_ABS:
1864a1668c25SNamhyung Kim fmt->sort = hist_entry__cmp_delta_abs_idx;
1865a1668c25SNamhyung Kim break;
186699150a1fSJin Yao case COMPUTE_CYCLES:
186799150a1fSJin Yao /*
186899150a1fSJin Yao * Should set since 'fmt->sort' is called without
186999150a1fSJin Yao * checking valid during sorting
187099150a1fSJin Yao */
187199150a1fSJin Yao fmt->sort = hist_entry__cmp_nop;
187299150a1fSJin Yao break;
1873566b5cfbSNamhyung Kim default:
1874566b5cfbSNamhyung Kim BUG_ON(1);
1875566b5cfbSNamhyung Kim }
1876566b5cfbSNamhyung Kim
1877a1c9f97fSNamhyung Kim perf_hpp__prepend_sort_field(fmt);
1878566b5cfbSNamhyung Kim return 0;
18791d77822eSJiri Olsa }
18801d77822eSJiri Olsa
data_init(int argc,const char ** argv)1881ec308426SJiri Olsa static int data_init(int argc, const char **argv)
188286a9eee0SArnaldo Carvalho de Melo {
1883ec308426SJiri Olsa struct data__file *d;
1884ec308426SJiri Olsa static const char *defaults[] = {
1885ec308426SJiri Olsa "perf.data.old",
1886ec308426SJiri Olsa "perf.data",
1887ec308426SJiri Olsa };
188822aeb7f5SJiri Olsa bool use_default = true;
1889ec308426SJiri Olsa int i;
1890ec308426SJiri Olsa
1891ec308426SJiri Olsa data__files_cnt = 2;
1892ec308426SJiri Olsa
189386a9eee0SArnaldo Carvalho de Melo if (argc) {
189422aeb7f5SJiri Olsa if (argc == 1)
1895ec308426SJiri Olsa defaults[1] = argv[0];
189622aeb7f5SJiri Olsa else {
189722aeb7f5SJiri Olsa data__files_cnt = argc;
189822aeb7f5SJiri Olsa use_default = false;
189922aeb7f5SJiri Olsa }
1900d8d9608fSDongsheng Yang } else if (perf_guest) {
1901ec308426SJiri Olsa defaults[0] = "perf.data.host";
1902ec308426SJiri Olsa defaults[1] = "perf.data.guest";
190386a9eee0SArnaldo Carvalho de Melo }
190486a9eee0SArnaldo Carvalho de Melo
19055f3f8d3bSJiri Olsa if (sort_compute >= (unsigned int) data__files_cnt) {
19065f3f8d3bSJiri Olsa pr_err("Order option out of limit.\n");
19075f3f8d3bSJiri Olsa return -EINVAL;
19085f3f8d3bSJiri Olsa }
19095f3f8d3bSJiri Olsa
1910ec308426SJiri Olsa data__files = zalloc(sizeof(*data__files) * data__files_cnt);
1911ec308426SJiri Olsa if (!data__files)
1912ec308426SJiri Olsa return -ENOMEM;
1913ec308426SJiri Olsa
1914ec308426SJiri Olsa data__for_each_file(i, d) {
19158ceb41d7SJiri Olsa struct perf_data *data = &d->data;
1916f5fc1412SJiri Olsa
19172d4f2799SJiri Olsa data->path = use_default ? defaults[i] : argv[i];
1918*681f34d5SLu Hongfei data->mode = PERF_DATA_MODE_READ;
1919*681f34d5SLu Hongfei data->force = force;
1920f5fc1412SJiri Olsa
1921ec308426SJiri Olsa d->idx = i;
1922ec308426SJiri Olsa }
1923ec308426SJiri Olsa
1924ec308426SJiri Olsa return 0;
1925ec308426SJiri Olsa }
1926ec308426SJiri Olsa
diff__config(const char * var,const char * value,void * cb __maybe_unused)1927d49dd15dSNamhyung Kim static int diff__config(const char *var, const char *value,
1928d49dd15dSNamhyung Kim void *cb __maybe_unused)
1929d49dd15dSNamhyung Kim {
1930d49dd15dSNamhyung Kim if (!strcmp(var, "diff.order")) {
193125ce4bb8SArnaldo Carvalho de Melo int ret;
193225ce4bb8SArnaldo Carvalho de Melo if (perf_config_int(&ret, var, value) < 0)
193325ce4bb8SArnaldo Carvalho de Melo return -1;
193425ce4bb8SArnaldo Carvalho de Melo sort_compute = ret;
1935d49dd15dSNamhyung Kim return 0;
1936d49dd15dSNamhyung Kim }
19374b35994aSNamhyung Kim if (!strcmp(var, "diff.compute")) {
19384b35994aSNamhyung Kim if (!strcmp(value, "delta")) {
19394b35994aSNamhyung Kim compute = COMPUTE_DELTA;
19404b35994aSNamhyung Kim } else if (!strcmp(value, "delta-abs")) {
19414b35994aSNamhyung Kim compute = COMPUTE_DELTA_ABS;
19424b35994aSNamhyung Kim } else if (!strcmp(value, "ratio")) {
19434b35994aSNamhyung Kim compute = COMPUTE_RATIO;
19444b35994aSNamhyung Kim } else if (!strcmp(value, "wdiff")) {
19454b35994aSNamhyung Kim compute = COMPUTE_WEIGHTED_DIFF;
19464b35994aSNamhyung Kim } else {
19474b35994aSNamhyung Kim pr_err("Invalid compute method: %s\n", value);
19484b35994aSNamhyung Kim return -1;
19494b35994aSNamhyung Kim }
19504b35994aSNamhyung Kim }
1951d49dd15dSNamhyung Kim
1952d49dd15dSNamhyung Kim return 0;
1953d49dd15dSNamhyung Kim }
1954d49dd15dSNamhyung Kim
cmd_diff(int argc,const char ** argv)1955b0ad8ea6SArnaldo Carvalho de Melo int cmd_diff(int argc, const char **argv)
1956ec308426SJiri Olsa {
19579ab1f508SKan Liang int ret = hists__init();
19589ab1f508SKan Liang
19599ab1f508SKan Liang if (ret < 0)
19609ab1f508SKan Liang return ret;
19619ab1f508SKan Liang
1962d49dd15dSNamhyung Kim perf_config(diff__config, NULL);
1963d49dd15dSNamhyung Kim
1964ec308426SJiri Olsa argc = parse_options(argc, argv, options, diff_usage, 0);
1965ec308426SJiri Olsa
196663b42fceSNamhyung Kim if (quiet)
196763b42fceSNamhyung Kim perf_quiet_option();
196863b42fceSNamhyung Kim
1969cebf7d51SJin Yao if (cycles_hist && (compute != COMPUTE_CYCLES))
1970cebf7d51SJin Yao usage_with_options(diff_usage, options);
1971cebf7d51SJin Yao
19722a09a84cSJin Yao if (pdiff.stream)
19732a09a84cSJin Yao compute = COMPUTE_STREAM;
19742a09a84cSJin Yao
197599150a1fSJin Yao symbol__annotation_init();
197699150a1fSJin Yao
19770a7e6d1bSNamhyung Kim if (symbol__init(NULL) < 0)
1978655000e7SArnaldo Carvalho de Melo return -1;
1979655000e7SArnaldo Carvalho de Melo
1980ec308426SJiri Olsa if (data_init(argc, argv) < 0)
1981ec308426SJiri Olsa return -1;
1982ec308426SJiri Olsa
198330d81553SJin Yao if (check_file_brstack() < 0)
198430d81553SJin Yao return -1;
198530d81553SJin Yao
19862a09a84cSJin Yao if ((compute == COMPUTE_CYCLES || compute == COMPUTE_STREAM)
19872a09a84cSJin Yao && !pdiff.has_br_stack) {
198899150a1fSJin Yao return -1;
19892a09a84cSJin Yao }
199099150a1fSJin Yao
19912a09a84cSJin Yao if (compute == COMPUTE_STREAM) {
19922a09a84cSJin Yao symbol_conf.show_branchflag_count = true;
19932a09a84cSJin Yao symbol_conf.disable_add2line_warn = true;
19942a09a84cSJin Yao callchain_param.mode = CHAIN_FLAT;
19952a09a84cSJin Yao callchain_param.key = CCKEY_SRCLINE;
19962a09a84cSJin Yao callchain_param.branch_callstack = 1;
19972a09a84cSJin Yao symbol_conf.use_callchain = true;
19982a09a84cSJin Yao callchain_register_param(&callchain_param);
19992a09a84cSJin Yao sort_order = "srcline,symbol,dso";
20002a09a84cSJin Yao } else {
2001566b5cfbSNamhyung Kim if (ui_init() < 0)
2002566b5cfbSNamhyung Kim return -1;
20031d77822eSJiri Olsa
2004512ae1bdSNamhyung Kim sort__mode = SORT_MODE__DIFF;
20052a09a84cSJin Yao }
2006512ae1bdSNamhyung Kim
200740184c46SNamhyung Kim if (setup_sorting(NULL) < 0)
200855309985SNamhyung Kim usage_with_options(diff_usage, options);
200955309985SNamhyung Kim
201086a9eee0SArnaldo Carvalho de Melo setup_pager();
2011c351c281SArnaldo Carvalho de Melo
201208e71542SNamhyung Kim sort__setup_elide(NULL);
2013c351c281SArnaldo Carvalho de Melo
201486a9eee0SArnaldo Carvalho de Melo return __cmd_diff();
201586a9eee0SArnaldo Carvalho de Melo }
2016