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