xref: /openbmc/linux/tools/perf/builtin-diff.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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