cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

builtin-diff.c (47121B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * builtin-diff.c
      4 *
      5 * Builtin diff command: Analyze two perf.data input files, look up and read
      6 * DSOs and symbol information, sort them and produce a diff.
      7 */
      8#include "builtin.h"
      9#include "perf.h"
     10
     11#include "util/debug.h"
     12#include "util/event.h"
     13#include "util/hist.h"
     14#include "util/evsel.h"
     15#include "util/evlist.h"
     16#include "util/session.h"
     17#include "util/tool.h"
     18#include "util/sort.h"
     19#include "util/srcline.h"
     20#include "util/symbol.h"
     21#include "util/data.h"
     22#include "util/config.h"
     23#include "util/time-utils.h"
     24#include "util/annotate.h"
     25#include "util/map.h"
     26#include "util/spark.h"
     27#include "util/block-info.h"
     28#include "util/stream.h"
     29#include <linux/err.h>
     30#include <linux/zalloc.h>
     31#include <subcmd/pager.h>
     32#include <subcmd/parse-options.h>
     33
     34#include <errno.h>
     35#include <inttypes.h>
     36#include <stdlib.h>
     37#include <math.h>
     38
     39struct perf_diff {
     40	struct perf_tool		 tool;
     41	const char			*time_str;
     42	struct perf_time_interval	*ptime_range;
     43	int				 range_size;
     44	int				 range_num;
     45	bool				 has_br_stack;
     46	bool				 stream;
     47};
     48
     49/* Diff command specific HPP columns. */
     50enum {
     51	PERF_HPP_DIFF__BASELINE,
     52	PERF_HPP_DIFF__PERIOD,
     53	PERF_HPP_DIFF__PERIOD_BASELINE,
     54	PERF_HPP_DIFF__DELTA,
     55	PERF_HPP_DIFF__RATIO,
     56	PERF_HPP_DIFF__WEIGHTED_DIFF,
     57	PERF_HPP_DIFF__FORMULA,
     58	PERF_HPP_DIFF__DELTA_ABS,
     59	PERF_HPP_DIFF__CYCLES,
     60	PERF_HPP_DIFF__CYCLES_HIST,
     61
     62	PERF_HPP_DIFF__MAX_INDEX
     63};
     64
     65struct diff_hpp_fmt {
     66	struct perf_hpp_fmt	 fmt;
     67	int			 idx;
     68	char			*header;
     69	int			 header_width;
     70};
     71
     72struct data__file {
     73	struct perf_session	*session;
     74	struct perf_data	 data;
     75	int			 idx;
     76	struct hists		*hists;
     77	struct evlist_streams	*evlist_streams;
     78	struct diff_hpp_fmt	 fmt[PERF_HPP_DIFF__MAX_INDEX];
     79};
     80
     81static struct data__file *data__files;
     82static int data__files_cnt;
     83
     84#define data__for_each_file_start(i, d, s)	\
     85	for (i = s, d = &data__files[s];	\
     86	     i < data__files_cnt;		\
     87	     i++, d = &data__files[i])
     88
     89#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
     90#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
     91
     92static bool force;
     93static bool show_period;
     94static bool show_formula;
     95static bool show_baseline_only;
     96static bool cycles_hist;
     97static unsigned int sort_compute = 1;
     98
     99static s64 compute_wdiff_w1;
    100static s64 compute_wdiff_w2;
    101
    102static const char		*cpu_list;
    103static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
    104
    105enum {
    106	COMPUTE_DELTA,
    107	COMPUTE_RATIO,
    108	COMPUTE_WEIGHTED_DIFF,
    109	COMPUTE_DELTA_ABS,
    110	COMPUTE_CYCLES,
    111	COMPUTE_MAX,
    112	COMPUTE_STREAM,	/* After COMPUTE_MAX to avoid use current compute arrays */
    113};
    114
    115const char *compute_names[COMPUTE_MAX] = {
    116	[COMPUTE_DELTA] = "delta",
    117	[COMPUTE_DELTA_ABS] = "delta-abs",
    118	[COMPUTE_RATIO] = "ratio",
    119	[COMPUTE_WEIGHTED_DIFF] = "wdiff",
    120	[COMPUTE_CYCLES] = "cycles",
    121};
    122
    123static int compute = COMPUTE_DELTA_ABS;
    124
    125static int compute_2_hpp[COMPUTE_MAX] = {
    126	[COMPUTE_DELTA]		= PERF_HPP_DIFF__DELTA,
    127	[COMPUTE_DELTA_ABS]	= PERF_HPP_DIFF__DELTA_ABS,
    128	[COMPUTE_RATIO]		= PERF_HPP_DIFF__RATIO,
    129	[COMPUTE_WEIGHTED_DIFF]	= PERF_HPP_DIFF__WEIGHTED_DIFF,
    130	[COMPUTE_CYCLES]	= PERF_HPP_DIFF__CYCLES,
    131};
    132
    133#define MAX_COL_WIDTH 70
    134
    135static struct header_column {
    136	const char *name;
    137	int width;
    138} columns[PERF_HPP_DIFF__MAX_INDEX] = {
    139	[PERF_HPP_DIFF__BASELINE] = {
    140		.name  = "Baseline",
    141	},
    142	[PERF_HPP_DIFF__PERIOD] = {
    143		.name  = "Period",
    144		.width = 14,
    145	},
    146	[PERF_HPP_DIFF__PERIOD_BASELINE] = {
    147		.name  = "Base period",
    148		.width = 14,
    149	},
    150	[PERF_HPP_DIFF__DELTA] = {
    151		.name  = "Delta",
    152		.width = 7,
    153	},
    154	[PERF_HPP_DIFF__DELTA_ABS] = {
    155		.name  = "Delta Abs",
    156		.width = 7,
    157	},
    158	[PERF_HPP_DIFF__RATIO] = {
    159		.name  = "Ratio",
    160		.width = 14,
    161	},
    162	[PERF_HPP_DIFF__WEIGHTED_DIFF] = {
    163		.name  = "Weighted diff",
    164		.width = 14,
    165	},
    166	[PERF_HPP_DIFF__FORMULA] = {
    167		.name  = "Formula",
    168		.width = MAX_COL_WIDTH,
    169	},
    170	[PERF_HPP_DIFF__CYCLES] = {
    171		.name  = "[Program Block Range] Cycles Diff",
    172		.width = 70,
    173	},
    174	[PERF_HPP_DIFF__CYCLES_HIST] = {
    175		.name  = "stddev/Hist",
    176		.width = NUM_SPARKS + 9,
    177	}
    178};
    179
    180static int setup_compute_opt_wdiff(char *opt)
    181{
    182	char *w1_str = opt;
    183	char *w2_str;
    184
    185	int ret = -EINVAL;
    186
    187	if (!opt)
    188		goto out;
    189
    190	w2_str = strchr(opt, ',');
    191	if (!w2_str)
    192		goto out;
    193
    194	*w2_str++ = 0x0;
    195	if (!*w2_str)
    196		goto out;
    197
    198	compute_wdiff_w1 = strtol(w1_str, NULL, 10);
    199	compute_wdiff_w2 = strtol(w2_str, NULL, 10);
    200
    201	if (!compute_wdiff_w1 || !compute_wdiff_w2)
    202		goto out;
    203
    204	pr_debug("compute wdiff w1(%" PRId64 ") w2(%" PRId64 ")\n",
    205		  compute_wdiff_w1, compute_wdiff_w2);
    206
    207	ret = 0;
    208
    209 out:
    210	if (ret)
    211		pr_err("Failed: wrong weight data, use 'wdiff:w1,w2'\n");
    212
    213	return ret;
    214}
    215
    216static int setup_compute_opt(char *opt)
    217{
    218	if (compute == COMPUTE_WEIGHTED_DIFF)
    219		return setup_compute_opt_wdiff(opt);
    220
    221	if (opt) {
    222		pr_err("Failed: extra option specified '%s'", opt);
    223		return -EINVAL;
    224	}
    225
    226	return 0;
    227}
    228
    229static int setup_compute(const struct option *opt, const char *str,
    230			 int unset __maybe_unused)
    231{
    232	int *cp = (int *) opt->value;
    233	char *cstr = (char *) str;
    234	char buf[50];
    235	unsigned i;
    236	char *option;
    237
    238	if (!str) {
    239		*cp = COMPUTE_DELTA;
    240		return 0;
    241	}
    242
    243	option = strchr(str, ':');
    244	if (option) {
    245		unsigned len = option++ - str;
    246
    247		/*
    248		 * The str data are not writeable, so we need
    249		 * to use another buffer.
    250		 */
    251
    252		/* No option value is longer. */
    253		if (len >= sizeof(buf))
    254			return -EINVAL;
    255
    256		strncpy(buf, str, len);
    257		buf[len] = 0x0;
    258		cstr = buf;
    259	}
    260
    261	for (i = 0; i < COMPUTE_MAX; i++)
    262		if (!strcmp(cstr, compute_names[i])) {
    263			*cp = i;
    264			return setup_compute_opt(option);
    265		}
    266
    267	pr_err("Failed: '%s' is not computation method "
    268	       "(use 'delta','ratio' or 'wdiff')\n", str);
    269	return -EINVAL;
    270}
    271
    272static double period_percent(struct hist_entry *he, u64 period)
    273{
    274	u64 total = hists__total_period(he->hists);
    275
    276	return (period * 100.0) / total;
    277}
    278
    279static double compute_delta(struct hist_entry *he, struct hist_entry *pair)
    280{
    281	double old_percent = period_percent(he, he->stat.period);
    282	double new_percent = period_percent(pair, pair->stat.period);
    283
    284	pair->diff.period_ratio_delta = new_percent - old_percent;
    285	pair->diff.computed = true;
    286	return pair->diff.period_ratio_delta;
    287}
    288
    289static double compute_ratio(struct hist_entry *he, struct hist_entry *pair)
    290{
    291	double old_period = he->stat.period ?: 1;
    292	double new_period = pair->stat.period;
    293
    294	pair->diff.computed = true;
    295	pair->diff.period_ratio = new_period / old_period;
    296	return pair->diff.period_ratio;
    297}
    298
    299static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
    300{
    301	u64 old_period = he->stat.period;
    302	u64 new_period = pair->stat.period;
    303
    304	pair->diff.computed = true;
    305	pair->diff.wdiff = new_period * compute_wdiff_w2 -
    306			   old_period * compute_wdiff_w1;
    307
    308	return pair->diff.wdiff;
    309}
    310
    311static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
    312			 char *buf, size_t size)
    313{
    314	u64 he_total = he->hists->stats.total_period;
    315	u64 pair_total = pair->hists->stats.total_period;
    316
    317	if (symbol_conf.filter_relative) {
    318		he_total = he->hists->stats.total_non_filtered_period;
    319		pair_total = pair->hists->stats.total_non_filtered_period;
    320	}
    321	return scnprintf(buf, size,
    322			 "(%" PRIu64 " * 100 / %" PRIu64 ") - "
    323			 "(%" PRIu64 " * 100 / %" PRIu64 ")",
    324			 pair->stat.period, pair_total,
    325			 he->stat.period, he_total);
    326}
    327
    328static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
    329			 char *buf, size_t size)
    330{
    331	double old_period = he->stat.period;
    332	double new_period = pair->stat.period;
    333
    334	return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
    335}
    336
    337static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
    338			 char *buf, size_t size)
    339{
    340	u64 old_period = he->stat.period;
    341	u64 new_period = pair->stat.period;
    342
    343	return scnprintf(buf, size,
    344		  "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
    345		  new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
    346}
    347
    348static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
    349			   char *buf, size_t size)
    350{
    351	switch (compute) {
    352	case COMPUTE_DELTA:
    353	case COMPUTE_DELTA_ABS:
    354		return formula_delta(he, pair, buf, size);
    355	case COMPUTE_RATIO:
    356		return formula_ratio(he, pair, buf, size);
    357	case COMPUTE_WEIGHTED_DIFF:
    358		return formula_wdiff(he, pair, buf, size);
    359	default:
    360		BUG_ON(1);
    361	}
    362
    363	return -1;
    364}
    365
    366static void *block_hist_zalloc(size_t size)
    367{
    368	struct block_hist *bh;
    369
    370	bh = zalloc(size + sizeof(*bh));
    371	if (!bh)
    372		return NULL;
    373
    374	return &bh->he;
    375}
    376
    377static void block_hist_free(void *he)
    378{
    379	struct block_hist *bh;
    380
    381	bh = container_of(he, struct block_hist, he);
    382	hists__delete_entries(&bh->block_hists);
    383	free(bh);
    384}
    385
    386struct hist_entry_ops block_hist_ops = {
    387	.new    = block_hist_zalloc,
    388	.free   = block_hist_free,
    389};
    390
    391static int diff__process_sample_event(struct perf_tool *tool,
    392				      union perf_event *event,
    393				      struct perf_sample *sample,
    394				      struct evsel *evsel,
    395				      struct machine *machine)
    396{
    397	struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool);
    398	struct addr_location al;
    399	struct hists *hists = evsel__hists(evsel);
    400	struct hist_entry_iter iter = {
    401		.evsel	= evsel,
    402		.sample	= sample,
    403		.ops	= &hist_iter_normal,
    404	};
    405	int ret = -1;
    406
    407	if (perf_time__ranges_skip_sample(pdiff->ptime_range, pdiff->range_num,
    408					  sample->time)) {
    409		return 0;
    410	}
    411
    412	if (machine__resolve(machine, &al, sample) < 0) {
    413		pr_warning("problem processing %d event, skipping it.\n",
    414			   event->header.type);
    415		return -1;
    416	}
    417
    418	if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) {
    419		ret = 0;
    420		goto out_put;
    421	}
    422
    423	switch (compute) {
    424	case COMPUTE_CYCLES:
    425		if (!hists__add_entry_ops(hists, &block_hist_ops, &al, NULL,
    426					  NULL, NULL, sample, true)) {
    427			pr_warning("problem incrementing symbol period, "
    428				   "skipping event\n");
    429			goto out_put;
    430		}
    431
    432		hist__account_cycles(sample->branch_stack, &al, sample, false,
    433				     NULL);
    434		break;
    435
    436	case COMPUTE_STREAM:
    437		if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH,
    438					 NULL)) {
    439			pr_debug("problem adding hist entry, skipping event\n");
    440			goto out_put;
    441		}
    442		break;
    443
    444	default:
    445		if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample,
    446				      true)) {
    447			pr_warning("problem incrementing symbol period, "
    448				   "skipping event\n");
    449			goto out_put;
    450		}
    451	}
    452
    453	/*
    454	 * The total_period is updated here before going to the output
    455	 * tree since normally only the baseline hists will call
    456	 * hists__output_resort() and precompute needs the total
    457	 * period in order to sort entries by percentage delta.
    458	 */
    459	hists->stats.total_period += sample->period;
    460	if (!al.filtered)
    461		hists->stats.total_non_filtered_period += sample->period;
    462	ret = 0;
    463out_put:
    464	addr_location__put(&al);
    465	return ret;
    466}
    467
    468static struct perf_diff pdiff = {
    469	.tool = {
    470		.sample	= diff__process_sample_event,
    471		.mmap	= perf_event__process_mmap,
    472		.mmap2	= perf_event__process_mmap2,
    473		.comm	= perf_event__process_comm,
    474		.exit	= perf_event__process_exit,
    475		.fork	= perf_event__process_fork,
    476		.lost	= perf_event__process_lost,
    477		.namespaces = perf_event__process_namespaces,
    478		.cgroup = perf_event__process_cgroup,
    479		.ordered_events = true,
    480		.ordering_requires_timestamps = true,
    481	},
    482};
    483
    484static struct evsel *evsel_match(struct evsel *evsel,
    485				      struct evlist *evlist)
    486{
    487	struct evsel *e;
    488
    489	evlist__for_each_entry(evlist, e) {
    490		if (evsel__match2(evsel, e))
    491			return e;
    492	}
    493
    494	return NULL;
    495}
    496
    497static void evlist__collapse_resort(struct evlist *evlist)
    498{
    499	struct evsel *evsel;
    500
    501	evlist__for_each_entry(evlist, evsel) {
    502		struct hists *hists = evsel__hists(evsel);
    503
    504		hists__collapse_resort(hists, NULL);
    505	}
    506}
    507
    508static struct data__file *fmt_to_data_file(struct perf_hpp_fmt *fmt)
    509{
    510	struct diff_hpp_fmt *dfmt = container_of(fmt, struct diff_hpp_fmt, fmt);
    511	void *ptr = dfmt - dfmt->idx;
    512	struct data__file *d = container_of(ptr, struct data__file, fmt);
    513
    514	return d;
    515}
    516
    517static struct hist_entry*
    518get_pair_data(struct hist_entry *he, struct data__file *d)
    519{
    520	if (hist_entry__has_pairs(he)) {
    521		struct hist_entry *pair;
    522
    523		list_for_each_entry(pair, &he->pairs.head, pairs.node)
    524			if (pair->hists == d->hists)
    525				return pair;
    526	}
    527
    528	return NULL;
    529}
    530
    531static struct hist_entry*
    532get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)
    533{
    534	struct data__file *d = fmt_to_data_file(&dfmt->fmt);
    535
    536	return get_pair_data(he, d);
    537}
    538
    539static void hists__baseline_only(struct hists *hists)
    540{
    541	struct rb_root_cached *root;
    542	struct rb_node *next;
    543
    544	if (hists__has(hists, need_collapse))
    545		root = &hists->entries_collapsed;
    546	else
    547		root = hists->entries_in;
    548
    549	next = rb_first_cached(root);
    550	while (next != NULL) {
    551		struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
    552
    553		next = rb_next(&he->rb_node_in);
    554		if (!hist_entry__next_pair(he)) {
    555			rb_erase_cached(&he->rb_node_in, root);
    556			hist_entry__delete(he);
    557		}
    558	}
    559}
    560
    561static int64_t block_cycles_diff_cmp(struct hist_entry *left,
    562				     struct hist_entry *right)
    563{
    564	bool pairs_left  = hist_entry__has_pairs(left);
    565	bool pairs_right = hist_entry__has_pairs(right);
    566	s64 l, r;
    567
    568	if (!pairs_left && !pairs_right)
    569		return 0;
    570
    571	l = llabs(left->diff.cycles);
    572	r = llabs(right->diff.cycles);
    573	return r - l;
    574}
    575
    576static int64_t block_sort(struct perf_hpp_fmt *fmt __maybe_unused,
    577			  struct hist_entry *left, struct hist_entry *right)
    578{
    579	return block_cycles_diff_cmp(right, left);
    580}
    581
    582static void init_block_hist(struct block_hist *bh)
    583{
    584	__hists__init(&bh->block_hists, &bh->block_list);
    585	perf_hpp_list__init(&bh->block_list);
    586
    587	INIT_LIST_HEAD(&bh->block_fmt.list);
    588	INIT_LIST_HEAD(&bh->block_fmt.sort_list);
    589	bh->block_fmt.cmp = block_info__cmp;
    590	bh->block_fmt.sort = block_sort;
    591	perf_hpp_list__register_sort_field(&bh->block_list,
    592					   &bh->block_fmt);
    593	bh->valid = true;
    594}
    595
    596static struct hist_entry *get_block_pair(struct hist_entry *he,
    597					 struct hists *hists_pair)
    598{
    599	struct rb_root_cached *root = hists_pair->entries_in;
    600	struct rb_node *next = rb_first_cached(root);
    601	int64_t cmp;
    602
    603	while (next != NULL) {
    604		struct hist_entry *he_pair = rb_entry(next, struct hist_entry,
    605						      rb_node_in);
    606
    607		next = rb_next(&he_pair->rb_node_in);
    608
    609		cmp = __block_info__cmp(he_pair, he);
    610		if (!cmp)
    611			return he_pair;
    612	}
    613
    614	return NULL;
    615}
    616
    617static void init_spark_values(unsigned long *svals, int num)
    618{
    619	for (int i = 0; i < num; i++)
    620		svals[i] = 0;
    621}
    622
    623static void update_spark_value(unsigned long *svals, int num,
    624			       struct stats *stats, u64 val)
    625{
    626	int n = stats->n;
    627
    628	if (n < num)
    629		svals[n] = val;
    630}
    631
    632static void compute_cycles_diff(struct hist_entry *he,
    633				struct hist_entry *pair)
    634{
    635	pair->diff.computed = true;
    636	if (pair->block_info->num && he->block_info->num) {
    637		pair->diff.cycles =
    638			pair->block_info->cycles_aggr / pair->block_info->num_aggr -
    639			he->block_info->cycles_aggr / he->block_info->num_aggr;
    640
    641		if (!cycles_hist)
    642			return;
    643
    644		init_stats(&pair->diff.stats);
    645		init_spark_values(pair->diff.svals, NUM_SPARKS);
    646
    647		for (int i = 0; i < pair->block_info->num; i++) {
    648			u64 val;
    649
    650			if (i >= he->block_info->num || i >= NUM_SPARKS)
    651				break;
    652
    653			val = llabs(pair->block_info->cycles_spark[i] -
    654				     he->block_info->cycles_spark[i]);
    655
    656			update_spark_value(pair->diff.svals, NUM_SPARKS,
    657					   &pair->diff.stats, val);
    658			update_stats(&pair->diff.stats, val);
    659		}
    660	}
    661}
    662
    663static void block_hists_match(struct hists *hists_base,
    664			      struct hists *hists_pair)
    665{
    666	struct rb_root_cached *root = hists_base->entries_in;
    667	struct rb_node *next = rb_first_cached(root);
    668
    669	while (next != NULL) {
    670		struct hist_entry *he = rb_entry(next, struct hist_entry,
    671						 rb_node_in);
    672		struct hist_entry *pair = get_block_pair(he, hists_pair);
    673
    674		next = rb_next(&he->rb_node_in);
    675
    676		if (pair) {
    677			hist_entry__add_pair(pair, he);
    678			compute_cycles_diff(he, pair);
    679		}
    680	}
    681}
    682
    683static void hists__precompute(struct hists *hists)
    684{
    685	struct rb_root_cached *root;
    686	struct rb_node *next;
    687
    688	if (hists__has(hists, need_collapse))
    689		root = &hists->entries_collapsed;
    690	else
    691		root = hists->entries_in;
    692
    693	next = rb_first_cached(root);
    694	while (next != NULL) {
    695		struct block_hist *bh, *pair_bh;
    696		struct hist_entry *he, *pair;
    697		struct data__file *d;
    698		int i;
    699
    700		he   = rb_entry(next, struct hist_entry, rb_node_in);
    701		next = rb_next(&he->rb_node_in);
    702
    703		if (compute == COMPUTE_CYCLES) {
    704			bh = container_of(he, struct block_hist, he);
    705			init_block_hist(bh);
    706			block_info__process_sym(he, bh, NULL, 0);
    707		}
    708
    709		data__for_each_file_new(i, d) {
    710			pair = get_pair_data(he, d);
    711			if (!pair)
    712				continue;
    713
    714			switch (compute) {
    715			case COMPUTE_DELTA:
    716			case COMPUTE_DELTA_ABS:
    717				compute_delta(he, pair);
    718				break;
    719			case COMPUTE_RATIO:
    720				compute_ratio(he, pair);
    721				break;
    722			case COMPUTE_WEIGHTED_DIFF:
    723				compute_wdiff(he, pair);
    724				break;
    725			case COMPUTE_CYCLES:
    726				pair_bh = container_of(pair, struct block_hist,
    727						       he);
    728				init_block_hist(pair_bh);
    729				block_info__process_sym(pair, pair_bh, NULL, 0);
    730
    731				bh = container_of(he, struct block_hist, he);
    732
    733				if (bh->valid && pair_bh->valid) {
    734					block_hists_match(&bh->block_hists,
    735							  &pair_bh->block_hists);
    736					hists__output_resort(&pair_bh->block_hists,
    737							     NULL);
    738				}
    739				break;
    740			default:
    741				BUG_ON(1);
    742			}
    743		}
    744	}
    745}
    746
    747static int64_t cmp_doubles(double l, double r)
    748{
    749	if (l > r)
    750		return -1;
    751	else if (l < r)
    752		return 1;
    753	else
    754		return 0;
    755}
    756
    757static int64_t
    758__hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
    759			int c)
    760{
    761	switch (c) {
    762	case COMPUTE_DELTA:
    763	{
    764		double l = left->diff.period_ratio_delta;
    765		double r = right->diff.period_ratio_delta;
    766
    767		return cmp_doubles(l, r);
    768	}
    769	case COMPUTE_DELTA_ABS:
    770	{
    771		double l = fabs(left->diff.period_ratio_delta);
    772		double r = fabs(right->diff.period_ratio_delta);
    773
    774		return cmp_doubles(l, r);
    775	}
    776	case COMPUTE_RATIO:
    777	{
    778		double l = left->diff.period_ratio;
    779		double r = right->diff.period_ratio;
    780
    781		return cmp_doubles(l, r);
    782	}
    783	case COMPUTE_WEIGHTED_DIFF:
    784	{
    785		s64 l = left->diff.wdiff;
    786		s64 r = right->diff.wdiff;
    787
    788		return r - l;
    789	}
    790	default:
    791		BUG_ON(1);
    792	}
    793
    794	return 0;
    795}
    796
    797static int64_t
    798hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
    799			int c, int sort_idx)
    800{
    801	bool pairs_left  = hist_entry__has_pairs(left);
    802	bool pairs_right = hist_entry__has_pairs(right);
    803	struct hist_entry *p_right, *p_left;
    804
    805	if (!pairs_left && !pairs_right)
    806		return 0;
    807
    808	if (!pairs_left || !pairs_right)
    809		return pairs_left ? -1 : 1;
    810
    811	p_left  = get_pair_data(left,  &data__files[sort_idx]);
    812	p_right = get_pair_data(right, &data__files[sort_idx]);
    813
    814	if (!p_left && !p_right)
    815		return 0;
    816
    817	if (!p_left || !p_right)
    818		return p_left ? -1 : 1;
    819
    820	/*
    821	 * We have 2 entries of same kind, let's
    822	 * make the data comparison.
    823	 */
    824	return __hist_entry__cmp_compute(p_left, p_right, c);
    825}
    826
    827static int64_t
    828hist_entry__cmp_compute_idx(struct hist_entry *left, struct hist_entry *right,
    829			    int c, int sort_idx)
    830{
    831	struct hist_entry *p_right, *p_left;
    832
    833	p_left  = get_pair_data(left,  &data__files[sort_idx]);
    834	p_right = get_pair_data(right, &data__files[sort_idx]);
    835
    836	if (!p_left && !p_right)
    837		return 0;
    838
    839	if (!p_left || !p_right)
    840		return p_left ? -1 : 1;
    841
    842	if (c != COMPUTE_DELTA && c != COMPUTE_DELTA_ABS) {
    843		/*
    844		 * The delta can be computed without the baseline, but
    845		 * others are not.  Put those entries which have no
    846		 * values below.
    847		 */
    848		if (left->dummy && right->dummy)
    849			return 0;
    850
    851		if (left->dummy || right->dummy)
    852			return left->dummy ? 1 : -1;
    853	}
    854
    855	return __hist_entry__cmp_compute(p_left, p_right, c);
    856}
    857
    858static int64_t
    859hist_entry__cmp_nop(struct perf_hpp_fmt *fmt __maybe_unused,
    860		    struct hist_entry *left __maybe_unused,
    861		    struct hist_entry *right __maybe_unused)
    862{
    863	return 0;
    864}
    865
    866static int64_t
    867hist_entry__cmp_baseline(struct perf_hpp_fmt *fmt __maybe_unused,
    868			 struct hist_entry *left, struct hist_entry *right)
    869{
    870	if (left->stat.period == right->stat.period)
    871		return 0;
    872	return left->stat.period > right->stat.period ? 1 : -1;
    873}
    874
    875static int64_t
    876hist_entry__cmp_delta(struct perf_hpp_fmt *fmt,
    877		      struct hist_entry *left, struct hist_entry *right)
    878{
    879	struct data__file *d = fmt_to_data_file(fmt);
    880
    881	return hist_entry__cmp_compute(right, left, COMPUTE_DELTA, d->idx);
    882}
    883
    884static int64_t
    885hist_entry__cmp_delta_abs(struct perf_hpp_fmt *fmt,
    886		      struct hist_entry *left, struct hist_entry *right)
    887{
    888	struct data__file *d = fmt_to_data_file(fmt);
    889
    890	return hist_entry__cmp_compute(right, left, COMPUTE_DELTA_ABS, d->idx);
    891}
    892
    893static int64_t
    894hist_entry__cmp_ratio(struct perf_hpp_fmt *fmt,
    895		      struct hist_entry *left, struct hist_entry *right)
    896{
    897	struct data__file *d = fmt_to_data_file(fmt);
    898
    899	return hist_entry__cmp_compute(right, left, COMPUTE_RATIO, d->idx);
    900}
    901
    902static int64_t
    903hist_entry__cmp_wdiff(struct perf_hpp_fmt *fmt,
    904		      struct hist_entry *left, struct hist_entry *right)
    905{
    906	struct data__file *d = fmt_to_data_file(fmt);
    907
    908	return hist_entry__cmp_compute(right, left, COMPUTE_WEIGHTED_DIFF, d->idx);
    909}
    910
    911static int64_t
    912hist_entry__cmp_delta_idx(struct perf_hpp_fmt *fmt __maybe_unused,
    913			  struct hist_entry *left, struct hist_entry *right)
    914{
    915	return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA,
    916					   sort_compute);
    917}
    918
    919static int64_t
    920hist_entry__cmp_delta_abs_idx(struct perf_hpp_fmt *fmt __maybe_unused,
    921			      struct hist_entry *left, struct hist_entry *right)
    922{
    923	return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA_ABS,
    924					   sort_compute);
    925}
    926
    927static int64_t
    928hist_entry__cmp_ratio_idx(struct perf_hpp_fmt *fmt __maybe_unused,
    929			  struct hist_entry *left, struct hist_entry *right)
    930{
    931	return hist_entry__cmp_compute_idx(right, left, COMPUTE_RATIO,
    932					   sort_compute);
    933}
    934
    935static int64_t
    936hist_entry__cmp_wdiff_idx(struct perf_hpp_fmt *fmt __maybe_unused,
    937			  struct hist_entry *left, struct hist_entry *right)
    938{
    939	return hist_entry__cmp_compute_idx(right, left, COMPUTE_WEIGHTED_DIFF,
    940					   sort_compute);
    941}
    942
    943static void hists__process(struct hists *hists)
    944{
    945	if (show_baseline_only)
    946		hists__baseline_only(hists);
    947
    948	hists__precompute(hists);
    949	hists__output_resort(hists, NULL);
    950
    951	if (compute == COMPUTE_CYCLES)
    952		symbol_conf.report_block = true;
    953
    954	hists__fprintf(hists, !quiet, 0, 0, 0, stdout,
    955		       !symbol_conf.use_callchain);
    956}
    957
    958static void data__fprintf(void)
    959{
    960	struct data__file *d;
    961	int i;
    962
    963	fprintf(stdout, "# Data files:\n");
    964
    965	data__for_each_file(i, d)
    966		fprintf(stdout, "#  [%d] %s %s\n",
    967			d->idx, d->data.path,
    968			!d->idx ? "(Baseline)" : "");
    969
    970	fprintf(stdout, "#\n");
    971}
    972
    973static void data_process(void)
    974{
    975	struct evlist *evlist_base = data__files[0].session->evlist;
    976	struct evsel *evsel_base;
    977	bool first = true;
    978
    979	evlist__for_each_entry(evlist_base, evsel_base) {
    980		struct hists *hists_base = evsel__hists(evsel_base);
    981		struct data__file *d;
    982		int i;
    983
    984		data__for_each_file_new(i, d) {
    985			struct evlist *evlist = d->session->evlist;
    986			struct evsel *evsel;
    987			struct hists *hists;
    988
    989			evsel = evsel_match(evsel_base, evlist);
    990			if (!evsel)
    991				continue;
    992
    993			hists = evsel__hists(evsel);
    994			d->hists = hists;
    995
    996			hists__match(hists_base, hists);
    997
    998			if (!show_baseline_only)
    999				hists__link(hists_base, hists);
   1000		}
   1001
   1002		if (!quiet) {
   1003			fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
   1004				evsel__name(evsel_base));
   1005		}
   1006
   1007		first = false;
   1008
   1009		if (verbose > 0 || ((data__files_cnt > 2) && !quiet))
   1010			data__fprintf();
   1011
   1012		/* Don't sort callchain for perf diff */
   1013		evsel__reset_sample_bit(evsel_base, CALLCHAIN);
   1014
   1015		hists__process(hists_base);
   1016	}
   1017}
   1018
   1019static int process_base_stream(struct data__file *data_base,
   1020			       struct data__file *data_pair,
   1021			       const char *title __maybe_unused)
   1022{
   1023	struct evlist *evlist_base = data_base->session->evlist;
   1024	struct evlist *evlist_pair = data_pair->session->evlist;
   1025	struct evsel *evsel_base, *evsel_pair;
   1026	struct evsel_streams *es_base, *es_pair;
   1027
   1028	evlist__for_each_entry(evlist_base, evsel_base) {
   1029		evsel_pair = evsel_match(evsel_base, evlist_pair);
   1030		if (!evsel_pair)
   1031			continue;
   1032
   1033		es_base = evsel_streams__entry(data_base->evlist_streams,
   1034					       evsel_base->core.idx);
   1035		if (!es_base)
   1036			return -1;
   1037
   1038		es_pair = evsel_streams__entry(data_pair->evlist_streams,
   1039					       evsel_pair->core.idx);
   1040		if (!es_pair)
   1041			return -1;
   1042
   1043		evsel_streams__match(es_base, es_pair);
   1044		evsel_streams__report(es_base, es_pair);
   1045	}
   1046
   1047	return 0;
   1048}
   1049
   1050static void stream_process(void)
   1051{
   1052	/*
   1053	 * Stream comparison only supports two data files.
   1054	 * perf.data.old and perf.data. data__files[0] is perf.data.old,
   1055	 * data__files[1] is perf.data.
   1056	 */
   1057	process_base_stream(&data__files[0], &data__files[1],
   1058			    "# Output based on old perf data:\n#\n");
   1059}
   1060
   1061static void data__free(struct data__file *d)
   1062{
   1063	int col;
   1064
   1065	if (d->evlist_streams)
   1066		evlist_streams__delete(d->evlist_streams);
   1067
   1068	for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
   1069		struct diff_hpp_fmt *fmt = &d->fmt[col];
   1070
   1071		zfree(&fmt->header);
   1072	}
   1073}
   1074
   1075static int abstime_str_dup(char **pstr)
   1076{
   1077	char *str = NULL;
   1078
   1079	if (pdiff.time_str && strchr(pdiff.time_str, ':')) {
   1080		str = strdup(pdiff.time_str);
   1081		if (!str)
   1082			return -ENOMEM;
   1083	}
   1084
   1085	*pstr = str;
   1086	return 0;
   1087}
   1088
   1089static int parse_absolute_time(struct data__file *d, char **pstr)
   1090{
   1091	char *p = *pstr;
   1092	int ret;
   1093
   1094	/*
   1095	 * Absolute timestamp for one file has the format: a.b,c.d
   1096	 * For multiple files, the format is: a.b,c.d:a.b,c.d
   1097	 */
   1098	p = strchr(*pstr, ':');
   1099	if (p) {
   1100		if (p == *pstr) {
   1101			pr_err("Invalid time string\n");
   1102			return -EINVAL;
   1103		}
   1104
   1105		*p = 0;
   1106		p++;
   1107		if (*p == 0) {
   1108			pr_err("Invalid time string\n");
   1109			return -EINVAL;
   1110		}
   1111	}
   1112
   1113	ret = perf_time__parse_for_ranges(*pstr, d->session,
   1114					  &pdiff.ptime_range,
   1115					  &pdiff.range_size,
   1116					  &pdiff.range_num);
   1117	if (ret < 0)
   1118		return ret;
   1119
   1120	if (!p || *p == 0)
   1121		*pstr = NULL;
   1122	else
   1123		*pstr = p;
   1124
   1125	return ret;
   1126}
   1127
   1128static int parse_percent_time(struct data__file *d)
   1129{
   1130	int ret;
   1131
   1132	ret = perf_time__parse_for_ranges(pdiff.time_str, d->session,
   1133					  &pdiff.ptime_range,
   1134					  &pdiff.range_size,
   1135					  &pdiff.range_num);
   1136	return ret;
   1137}
   1138
   1139static int parse_time_str(struct data__file *d, char *abstime_ostr,
   1140			   char **pabstime_tmp)
   1141{
   1142	int ret = 0;
   1143
   1144	if (abstime_ostr)
   1145		ret = parse_absolute_time(d, pabstime_tmp);
   1146	else if (pdiff.time_str)
   1147		ret = parse_percent_time(d);
   1148
   1149	return ret;
   1150}
   1151
   1152static int check_file_brstack(void)
   1153{
   1154	struct data__file *d;
   1155	bool has_br_stack;
   1156	int i;
   1157
   1158	data__for_each_file(i, d) {
   1159		d->session = perf_session__new(&d->data, &pdiff.tool);
   1160		if (IS_ERR(d->session)) {
   1161			pr_err("Failed to open %s\n", d->data.path);
   1162			return PTR_ERR(d->session);
   1163		}
   1164
   1165		has_br_stack = perf_header__has_feat(&d->session->header,
   1166						     HEADER_BRANCH_STACK);
   1167		perf_session__delete(d->session);
   1168		if (!has_br_stack)
   1169			return 0;
   1170	}
   1171
   1172	/* Set only all files having branch stacks */
   1173	pdiff.has_br_stack = true;
   1174	return 0;
   1175}
   1176
   1177static int __cmd_diff(void)
   1178{
   1179	struct data__file *d;
   1180	int ret, i;
   1181	char *abstime_ostr, *abstime_tmp;
   1182
   1183	ret = abstime_str_dup(&abstime_ostr);
   1184	if (ret)
   1185		return ret;
   1186
   1187	abstime_tmp = abstime_ostr;
   1188	ret = -EINVAL;
   1189
   1190	data__for_each_file(i, d) {
   1191		d->session = perf_session__new(&d->data, &pdiff.tool);
   1192		if (IS_ERR(d->session)) {
   1193			ret = PTR_ERR(d->session);
   1194			pr_err("Failed to open %s\n", d->data.path);
   1195			goto out_delete;
   1196		}
   1197
   1198		if (pdiff.time_str) {
   1199			ret = parse_time_str(d, abstime_ostr, &abstime_tmp);
   1200			if (ret < 0)
   1201				goto out_delete;
   1202		}
   1203
   1204		if (cpu_list) {
   1205			ret = perf_session__cpu_bitmap(d->session, cpu_list,
   1206						       cpu_bitmap);
   1207			if (ret < 0)
   1208				goto out_delete;
   1209		}
   1210
   1211		ret = perf_session__process_events(d->session);
   1212		if (ret) {
   1213			pr_err("Failed to process %s\n", d->data.path);
   1214			goto out_delete;
   1215		}
   1216
   1217		evlist__collapse_resort(d->session->evlist);
   1218
   1219		if (pdiff.ptime_range)
   1220			zfree(&pdiff.ptime_range);
   1221
   1222		if (compute == COMPUTE_STREAM) {
   1223			d->evlist_streams = evlist__create_streams(
   1224						d->session->evlist, 5);
   1225			if (!d->evlist_streams) {
   1226				ret = -ENOMEM;
   1227				goto out_delete;
   1228			}
   1229		}
   1230	}
   1231
   1232	if (compute == COMPUTE_STREAM)
   1233		stream_process();
   1234	else
   1235		data_process();
   1236
   1237 out_delete:
   1238	data__for_each_file(i, d) {
   1239		if (!IS_ERR(d->session))
   1240			perf_session__delete(d->session);
   1241		data__free(d);
   1242	}
   1243
   1244	free(data__files);
   1245
   1246	if (pdiff.ptime_range)
   1247		zfree(&pdiff.ptime_range);
   1248
   1249	if (abstime_ostr)
   1250		free(abstime_ostr);
   1251
   1252	return ret;
   1253}
   1254
   1255static const char * const diff_usage[] = {
   1256	"perf diff [<options>] [old_file] [new_file]",
   1257	NULL,
   1258};
   1259
   1260static const struct option options[] = {
   1261	OPT_INCR('v', "verbose", &verbose,
   1262		    "be more verbose (show symbol address, etc)"),
   1263	OPT_BOOLEAN('q', "quiet", &quiet, "Do not show any message"),
   1264	OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
   1265		    "Show only items with match in baseline"),
   1266	OPT_CALLBACK('c', "compute", &compute,
   1267		     "delta,delta-abs,ratio,wdiff:w1,w2 (default delta-abs),cycles",
   1268		     "Entries differential computation selection",
   1269		     setup_compute),
   1270	OPT_BOOLEAN('p', "period", &show_period,
   1271		    "Show period values."),
   1272	OPT_BOOLEAN('F', "formula", &show_formula,
   1273		    "Show formula."),
   1274	OPT_BOOLEAN(0, "cycles-hist", &cycles_hist,
   1275		    "Show cycles histogram and standard deviation "
   1276		    "- WARNING: use only with -c cycles."),
   1277	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
   1278		    "dump raw trace in ASCII"),
   1279	OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
   1280	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
   1281		   "file", "kallsyms pathname"),
   1282	OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
   1283		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
   1284	OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
   1285		   "only consider symbols in these dsos"),
   1286	OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
   1287		   "only consider symbols in these comms"),
   1288	OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
   1289		   "only consider these symbols"),
   1290	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
   1291		   "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
   1292		   " Please refer the man page for the complete list."),
   1293	OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator",
   1294		   "separator for columns, no spaces will be added between "
   1295		   "columns '.' is reserved."),
   1296	OPT_CALLBACK(0, "symfs", NULL, "directory",
   1297		     "Look for files with symbols relative to this directory",
   1298		     symbol__config_symfs),
   1299	OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
   1300	OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
   1301		     "How to display percentage of filtered entries", parse_filter_percentage),
   1302	OPT_STRING(0, "time", &pdiff.time_str, "str",
   1303		   "Time span (time percent or absolute timestamp)"),
   1304	OPT_STRING(0, "cpu", &cpu_list, "cpu", "list of cpus to profile"),
   1305	OPT_STRING(0, "pid", &symbol_conf.pid_list_str, "pid[,pid...]",
   1306		   "only consider symbols in these pids"),
   1307	OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
   1308		   "only consider symbols in these tids"),
   1309	OPT_BOOLEAN(0, "stream", &pdiff.stream,
   1310		    "Enable hot streams comparison."),
   1311	OPT_END()
   1312};
   1313
   1314static double baseline_percent(struct hist_entry *he)
   1315{
   1316	u64 total = hists__total_period(he->hists);
   1317
   1318	return 100.0 * he->stat.period / total;
   1319}
   1320
   1321static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
   1322			       struct perf_hpp *hpp, struct hist_entry *he)
   1323{
   1324	struct diff_hpp_fmt *dfmt =
   1325		container_of(fmt, struct diff_hpp_fmt, fmt);
   1326	double percent = baseline_percent(he);
   1327	char pfmt[20] = " ";
   1328
   1329	if (!he->dummy) {
   1330		scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1);
   1331		return percent_color_snprintf(hpp->buf, hpp->size,
   1332					      pfmt, percent);
   1333	} else
   1334		return scnprintf(hpp->buf, hpp->size, "%*s",
   1335				 dfmt->header_width, pfmt);
   1336}
   1337
   1338static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
   1339{
   1340	double percent = baseline_percent(he);
   1341	const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
   1342	int ret = 0;
   1343
   1344	if (!he->dummy)
   1345		ret = scnprintf(buf, size, fmt, percent);
   1346
   1347	return ret;
   1348}
   1349
   1350static int cycles_printf(struct hist_entry *he, struct hist_entry *pair,
   1351			 struct perf_hpp *hpp, int width)
   1352{
   1353	struct block_hist *bh = container_of(he, struct block_hist, he);
   1354	struct block_hist *bh_pair = container_of(pair, struct block_hist, he);
   1355	struct hist_entry *block_he;
   1356	struct block_info *bi;
   1357	char buf[128];
   1358	char *start_line, *end_line;
   1359
   1360	block_he = hists__get_entry(&bh_pair->block_hists, bh->block_idx);
   1361	if (!block_he) {
   1362		hpp->skip = true;
   1363		return 0;
   1364	}
   1365
   1366	/*
   1367	 * Avoid printing the warning "addr2line_init failed for ..."
   1368	 */
   1369	symbol_conf.disable_add2line_warn = true;
   1370
   1371	bi = block_he->block_info;
   1372
   1373	start_line = map__srcline(he->ms.map, bi->sym->start + bi->start,
   1374				  he->ms.sym);
   1375
   1376	end_line = map__srcline(he->ms.map, bi->sym->start + bi->end,
   1377				he->ms.sym);
   1378
   1379	if ((strncmp(start_line, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0) &&
   1380	    (strncmp(end_line, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0)) {
   1381		scnprintf(buf, sizeof(buf), "[%s -> %s] %4ld",
   1382			  start_line, end_line, block_he->diff.cycles);
   1383	} else {
   1384		scnprintf(buf, sizeof(buf), "[%7lx -> %7lx] %4ld",
   1385			  bi->start, bi->end, block_he->diff.cycles);
   1386	}
   1387
   1388	free_srcline(start_line);
   1389	free_srcline(end_line);
   1390
   1391	return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
   1392}
   1393
   1394static int __hpp__color_compare(struct perf_hpp_fmt *fmt,
   1395				struct perf_hpp *hpp, struct hist_entry *he,
   1396				int comparison_method)
   1397{
   1398	struct diff_hpp_fmt *dfmt =
   1399		container_of(fmt, struct diff_hpp_fmt, fmt);
   1400	struct hist_entry *pair = get_pair_fmt(he, dfmt);
   1401	double diff;
   1402	s64 wdiff;
   1403	char pfmt[20] = " ";
   1404
   1405	if (!pair) {
   1406		if (comparison_method == COMPUTE_CYCLES) {
   1407			struct block_hist *bh;
   1408
   1409			bh = container_of(he, struct block_hist, he);
   1410			if (bh->block_idx)
   1411				hpp->skip = true;
   1412		}
   1413
   1414		goto no_print;
   1415	}
   1416
   1417	switch (comparison_method) {
   1418	case COMPUTE_DELTA:
   1419		if (pair->diff.computed)
   1420			diff = pair->diff.period_ratio_delta;
   1421		else
   1422			diff = compute_delta(he, pair);
   1423
   1424		scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1);
   1425		return percent_color_snprintf(hpp->buf, hpp->size,
   1426					pfmt, diff);
   1427	case COMPUTE_RATIO:
   1428		if (he->dummy)
   1429			goto dummy_print;
   1430		if (pair->diff.computed)
   1431			diff = pair->diff.period_ratio;
   1432		else
   1433			diff = compute_ratio(he, pair);
   1434
   1435		scnprintf(pfmt, 20, "%%%d.6f", dfmt->header_width);
   1436		return value_color_snprintf(hpp->buf, hpp->size,
   1437					pfmt, diff);
   1438	case COMPUTE_WEIGHTED_DIFF:
   1439		if (he->dummy)
   1440			goto dummy_print;
   1441		if (pair->diff.computed)
   1442			wdiff = pair->diff.wdiff;
   1443		else
   1444			wdiff = compute_wdiff(he, pair);
   1445
   1446		scnprintf(pfmt, 20, "%%14ld", dfmt->header_width);
   1447		return color_snprintf(hpp->buf, hpp->size,
   1448				get_percent_color(wdiff),
   1449				pfmt, wdiff);
   1450	case COMPUTE_CYCLES:
   1451		return cycles_printf(he, pair, hpp, dfmt->header_width);
   1452	default:
   1453		BUG_ON(1);
   1454	}
   1455dummy_print:
   1456	return scnprintf(hpp->buf, hpp->size, "%*s",
   1457			dfmt->header_width, "N/A");
   1458no_print:
   1459	return scnprintf(hpp->buf, hpp->size, "%*s",
   1460			dfmt->header_width, pfmt);
   1461}
   1462
   1463static int hpp__color_delta(struct perf_hpp_fmt *fmt,
   1464			struct perf_hpp *hpp, struct hist_entry *he)
   1465{
   1466	return __hpp__color_compare(fmt, hpp, he, COMPUTE_DELTA);
   1467}
   1468
   1469static int hpp__color_ratio(struct perf_hpp_fmt *fmt,
   1470			struct perf_hpp *hpp, struct hist_entry *he)
   1471{
   1472	return __hpp__color_compare(fmt, hpp, he, COMPUTE_RATIO);
   1473}
   1474
   1475static int hpp__color_wdiff(struct perf_hpp_fmt *fmt,
   1476			struct perf_hpp *hpp, struct hist_entry *he)
   1477{
   1478	return __hpp__color_compare(fmt, hpp, he, COMPUTE_WEIGHTED_DIFF);
   1479}
   1480
   1481static int hpp__color_cycles(struct perf_hpp_fmt *fmt,
   1482			     struct perf_hpp *hpp, struct hist_entry *he)
   1483{
   1484	return __hpp__color_compare(fmt, hpp, he, COMPUTE_CYCLES);
   1485}
   1486
   1487static int all_zero(unsigned long *vals, int len)
   1488{
   1489	int i;
   1490
   1491	for (i = 0; i < len; i++)
   1492		if (vals[i] != 0)
   1493			return 0;
   1494	return 1;
   1495}
   1496
   1497static int print_cycles_spark(char *bf, int size, unsigned long *svals, u64 n)
   1498{
   1499	int printed;
   1500
   1501	if (n <= 1)
   1502		return 0;
   1503
   1504	if (n > NUM_SPARKS)
   1505		n = NUM_SPARKS;
   1506	if (all_zero(svals, n))
   1507		return 0;
   1508
   1509	printed = print_spark(bf, size, svals, n);
   1510	printed += scnprintf(bf + printed, size - printed, " ");
   1511	return printed;
   1512}
   1513
   1514static int hpp__color_cycles_hist(struct perf_hpp_fmt *fmt,
   1515			    struct perf_hpp *hpp, struct hist_entry *he)
   1516{
   1517	struct diff_hpp_fmt *dfmt =
   1518		container_of(fmt, struct diff_hpp_fmt, fmt);
   1519	struct hist_entry *pair = get_pair_fmt(he, dfmt);
   1520	struct block_hist *bh = container_of(he, struct block_hist, he);
   1521	struct block_hist *bh_pair;
   1522	struct hist_entry *block_he;
   1523	char spark[32], buf[128];
   1524	double r;
   1525	int ret, pad;
   1526
   1527	if (!pair) {
   1528		if (bh->block_idx)
   1529			hpp->skip = true;
   1530
   1531		goto no_print;
   1532	}
   1533
   1534	bh_pair = container_of(pair, struct block_hist, he);
   1535
   1536	block_he = hists__get_entry(&bh_pair->block_hists, bh->block_idx);
   1537	if (!block_he) {
   1538		hpp->skip = true;
   1539		goto no_print;
   1540	}
   1541
   1542	ret = print_cycles_spark(spark, sizeof(spark), block_he->diff.svals,
   1543				 block_he->diff.stats.n);
   1544
   1545	r = rel_stddev_stats(stddev_stats(&block_he->diff.stats),
   1546			     avg_stats(&block_he->diff.stats));
   1547
   1548	if (ret) {
   1549		/*
   1550		 * Padding spaces if number of sparks less than NUM_SPARKS
   1551		 * otherwise the output is not aligned.
   1552		 */
   1553		pad = NUM_SPARKS - ((ret - 1) / 3);
   1554		scnprintf(buf, sizeof(buf), "%s%5.1f%% %s", "\u00B1", r, spark);
   1555		ret = scnprintf(hpp->buf, hpp->size, "%*s",
   1556				dfmt->header_width, buf);
   1557
   1558		if (pad) {
   1559			ret += scnprintf(hpp->buf + ret, hpp->size - ret,
   1560					 "%-*s", pad, " ");
   1561		}
   1562
   1563		return ret;
   1564	}
   1565
   1566no_print:
   1567	return scnprintf(hpp->buf, hpp->size, "%*s",
   1568			dfmt->header_width, " ");
   1569}
   1570
   1571static void
   1572hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
   1573{
   1574	switch (idx) {
   1575	case PERF_HPP_DIFF__PERIOD_BASELINE:
   1576		scnprintf(buf, size, "%" PRIu64, he->stat.period);
   1577		break;
   1578
   1579	default:
   1580		break;
   1581	}
   1582}
   1583
   1584static void
   1585hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
   1586		int idx, char *buf, size_t size)
   1587{
   1588	double diff;
   1589	double ratio;
   1590	s64 wdiff;
   1591
   1592	switch (idx) {
   1593	case PERF_HPP_DIFF__DELTA:
   1594	case PERF_HPP_DIFF__DELTA_ABS:
   1595		if (pair->diff.computed)
   1596			diff = pair->diff.period_ratio_delta;
   1597		else
   1598			diff = compute_delta(he, pair);
   1599
   1600		scnprintf(buf, size, "%+4.2F%%", diff);
   1601		break;
   1602
   1603	case PERF_HPP_DIFF__RATIO:
   1604		/* No point for ratio number if we are dummy.. */
   1605		if (he->dummy) {
   1606			scnprintf(buf, size, "N/A");
   1607			break;
   1608		}
   1609
   1610		if (pair->diff.computed)
   1611			ratio = pair->diff.period_ratio;
   1612		else
   1613			ratio = compute_ratio(he, pair);
   1614
   1615		if (ratio > 0.0)
   1616			scnprintf(buf, size, "%14.6F", ratio);
   1617		break;
   1618
   1619	case PERF_HPP_DIFF__WEIGHTED_DIFF:
   1620		/* No point for wdiff number if we are dummy.. */
   1621		if (he->dummy) {
   1622			scnprintf(buf, size, "N/A");
   1623			break;
   1624		}
   1625
   1626		if (pair->diff.computed)
   1627			wdiff = pair->diff.wdiff;
   1628		else
   1629			wdiff = compute_wdiff(he, pair);
   1630
   1631		if (wdiff != 0)
   1632			scnprintf(buf, size, "%14ld", wdiff);
   1633		break;
   1634
   1635	case PERF_HPP_DIFF__FORMULA:
   1636		formula_fprintf(he, pair, buf, size);
   1637		break;
   1638
   1639	case PERF_HPP_DIFF__PERIOD:
   1640		scnprintf(buf, size, "%" PRIu64, pair->stat.period);
   1641		break;
   1642
   1643	default:
   1644		BUG_ON(1);
   1645	}
   1646}
   1647
   1648static void
   1649__hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt,
   1650		    char *buf, size_t size)
   1651{
   1652	struct hist_entry *pair = get_pair_fmt(he, dfmt);
   1653	int idx = dfmt->idx;
   1654
   1655	/* baseline is special */
   1656	if (idx == PERF_HPP_DIFF__BASELINE)
   1657		hpp__entry_baseline(he, buf, size);
   1658	else {
   1659		if (pair)
   1660			hpp__entry_pair(he, pair, idx, buf, size);
   1661		else
   1662			hpp__entry_unpair(he, idx, buf, size);
   1663	}
   1664}
   1665
   1666static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
   1667			     struct hist_entry *he)
   1668{
   1669	struct diff_hpp_fmt *dfmt =
   1670		container_of(_fmt, struct diff_hpp_fmt, fmt);
   1671	char buf[MAX_COL_WIDTH] = " ";
   1672
   1673	__hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH);
   1674
   1675	if (symbol_conf.field_sep)
   1676		return scnprintf(hpp->buf, hpp->size, "%s", buf);
   1677	else
   1678		return scnprintf(hpp->buf, hpp->size, "%*s",
   1679				 dfmt->header_width, buf);
   1680}
   1681
   1682static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
   1683		       struct hists *hists __maybe_unused,
   1684		       int line __maybe_unused,
   1685		       int *span __maybe_unused)
   1686{
   1687	struct diff_hpp_fmt *dfmt =
   1688		container_of(fmt, struct diff_hpp_fmt, fmt);
   1689
   1690	BUG_ON(!dfmt->header);
   1691	return scnprintf(hpp->buf, hpp->size, dfmt->header);
   1692}
   1693
   1694static int hpp__width(struct perf_hpp_fmt *fmt,
   1695		      struct perf_hpp *hpp __maybe_unused,
   1696		      struct hists *hists __maybe_unused)
   1697{
   1698	struct diff_hpp_fmt *dfmt =
   1699		container_of(fmt, struct diff_hpp_fmt, fmt);
   1700
   1701	BUG_ON(dfmt->header_width <= 0);
   1702	return dfmt->header_width;
   1703}
   1704
   1705static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt)
   1706{
   1707#define MAX_HEADER_NAME 100
   1708	char buf_indent[MAX_HEADER_NAME];
   1709	char buf[MAX_HEADER_NAME];
   1710	const char *header = NULL;
   1711	int width = 0;
   1712
   1713	BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX);
   1714	header = columns[dfmt->idx].name;
   1715	width  = columns[dfmt->idx].width;
   1716
   1717	/* Only our defined HPP fmts should appear here. */
   1718	BUG_ON(!header);
   1719
   1720	if (data__files_cnt > 2)
   1721		scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx);
   1722
   1723#define NAME (data__files_cnt > 2 ? buf : header)
   1724	dfmt->header_width = width;
   1725	width = (int) strlen(NAME);
   1726	if (dfmt->header_width < width)
   1727		dfmt->header_width = width;
   1728
   1729	scnprintf(buf_indent, MAX_HEADER_NAME, "%*s",
   1730		  dfmt->header_width, NAME);
   1731
   1732	dfmt->header = strdup(buf_indent);
   1733#undef MAX_HEADER_NAME
   1734#undef NAME
   1735}
   1736
   1737static void data__hpp_register(struct data__file *d, int idx)
   1738{
   1739	struct diff_hpp_fmt *dfmt = &d->fmt[idx];
   1740	struct perf_hpp_fmt *fmt = &dfmt->fmt;
   1741
   1742	dfmt->idx = idx;
   1743
   1744	fmt->header = hpp__header;
   1745	fmt->width  = hpp__width;
   1746	fmt->entry  = hpp__entry_global;
   1747	fmt->cmp    = hist_entry__cmp_nop;
   1748	fmt->collapse = hist_entry__cmp_nop;
   1749
   1750	/* TODO more colors */
   1751	switch (idx) {
   1752	case PERF_HPP_DIFF__BASELINE:
   1753		fmt->color = hpp__color_baseline;
   1754		fmt->sort  = hist_entry__cmp_baseline;
   1755		break;
   1756	case PERF_HPP_DIFF__DELTA:
   1757		fmt->color = hpp__color_delta;
   1758		fmt->sort  = hist_entry__cmp_delta;
   1759		break;
   1760	case PERF_HPP_DIFF__RATIO:
   1761		fmt->color = hpp__color_ratio;
   1762		fmt->sort  = hist_entry__cmp_ratio;
   1763		break;
   1764	case PERF_HPP_DIFF__WEIGHTED_DIFF:
   1765		fmt->color = hpp__color_wdiff;
   1766		fmt->sort  = hist_entry__cmp_wdiff;
   1767		break;
   1768	case PERF_HPP_DIFF__DELTA_ABS:
   1769		fmt->color = hpp__color_delta;
   1770		fmt->sort  = hist_entry__cmp_delta_abs;
   1771		break;
   1772	case PERF_HPP_DIFF__CYCLES:
   1773		fmt->color = hpp__color_cycles;
   1774		fmt->sort  = hist_entry__cmp_nop;
   1775		break;
   1776	case PERF_HPP_DIFF__CYCLES_HIST:
   1777		fmt->color = hpp__color_cycles_hist;
   1778		fmt->sort  = hist_entry__cmp_nop;
   1779		break;
   1780	default:
   1781		fmt->sort  = hist_entry__cmp_nop;
   1782		break;
   1783	}
   1784
   1785	init_header(d, dfmt);
   1786	perf_hpp__column_register(fmt);
   1787	perf_hpp__register_sort_field(fmt);
   1788}
   1789
   1790static int ui_init(void)
   1791{
   1792	struct data__file *d;
   1793	struct perf_hpp_fmt *fmt;
   1794	int i;
   1795
   1796	data__for_each_file(i, d) {
   1797
   1798		/*
   1799		 * Baseline or compute related columns:
   1800		 *
   1801		 *   PERF_HPP_DIFF__BASELINE
   1802		 *   PERF_HPP_DIFF__DELTA
   1803		 *   PERF_HPP_DIFF__RATIO
   1804		 *   PERF_HPP_DIFF__WEIGHTED_DIFF
   1805		 *   PERF_HPP_DIFF__CYCLES
   1806		 */
   1807		data__hpp_register(d, i ? compute_2_hpp[compute] :
   1808					  PERF_HPP_DIFF__BASELINE);
   1809
   1810		if (cycles_hist && i)
   1811			data__hpp_register(d, PERF_HPP_DIFF__CYCLES_HIST);
   1812
   1813		/*
   1814		 * And the rest:
   1815		 *
   1816		 * PERF_HPP_DIFF__FORMULA
   1817		 * PERF_HPP_DIFF__PERIOD
   1818		 * PERF_HPP_DIFF__PERIOD_BASELINE
   1819		 */
   1820		if (show_formula && i)
   1821			data__hpp_register(d, PERF_HPP_DIFF__FORMULA);
   1822
   1823		if (show_period)
   1824			data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD :
   1825						  PERF_HPP_DIFF__PERIOD_BASELINE);
   1826	}
   1827
   1828	if (!sort_compute)
   1829		return 0;
   1830
   1831	/*
   1832	 * Prepend an fmt to sort on columns at 'sort_compute' first.
   1833	 * This fmt is added only to the sort list but not to the
   1834	 * output fields list.
   1835	 *
   1836	 * Note that this column (data) can be compared twice - one
   1837	 * for this 'sort_compute' fmt and another for the normal
   1838	 * diff_hpp_fmt.  But it shouldn't a problem as most entries
   1839	 * will be sorted out by first try or baseline and comparing
   1840	 * is not a costly operation.
   1841	 */
   1842	fmt = zalloc(sizeof(*fmt));
   1843	if (fmt == NULL) {
   1844		pr_err("Memory allocation failed\n");
   1845		return -1;
   1846	}
   1847
   1848	fmt->cmp      = hist_entry__cmp_nop;
   1849	fmt->collapse = hist_entry__cmp_nop;
   1850
   1851	switch (compute) {
   1852	case COMPUTE_DELTA:
   1853		fmt->sort = hist_entry__cmp_delta_idx;
   1854		break;
   1855	case COMPUTE_RATIO:
   1856		fmt->sort = hist_entry__cmp_ratio_idx;
   1857		break;
   1858	case COMPUTE_WEIGHTED_DIFF:
   1859		fmt->sort = hist_entry__cmp_wdiff_idx;
   1860		break;
   1861	case COMPUTE_DELTA_ABS:
   1862		fmt->sort = hist_entry__cmp_delta_abs_idx;
   1863		break;
   1864	case COMPUTE_CYCLES:
   1865		/*
   1866		 * Should set since 'fmt->sort' is called without
   1867		 * checking valid during sorting
   1868		 */
   1869		fmt->sort = hist_entry__cmp_nop;
   1870		break;
   1871	default:
   1872		BUG_ON(1);
   1873	}
   1874
   1875	perf_hpp__prepend_sort_field(fmt);
   1876	return 0;
   1877}
   1878
   1879static int data_init(int argc, const char **argv)
   1880{
   1881	struct data__file *d;
   1882	static const char *defaults[] = {
   1883		"perf.data.old",
   1884		"perf.data",
   1885	};
   1886	bool use_default = true;
   1887	int i;
   1888
   1889	data__files_cnt = 2;
   1890
   1891	if (argc) {
   1892		if (argc == 1)
   1893			defaults[1] = argv[0];
   1894		else {
   1895			data__files_cnt = argc;
   1896			use_default = false;
   1897		}
   1898	} else if (perf_guest) {
   1899		defaults[0] = "perf.data.host";
   1900		defaults[1] = "perf.data.guest";
   1901	}
   1902
   1903	if (sort_compute >= (unsigned int) data__files_cnt) {
   1904		pr_err("Order option out of limit.\n");
   1905		return -EINVAL;
   1906	}
   1907
   1908	data__files = zalloc(sizeof(*data__files) * data__files_cnt);
   1909	if (!data__files)
   1910		return -ENOMEM;
   1911
   1912	data__for_each_file(i, d) {
   1913		struct perf_data *data = &d->data;
   1914
   1915		data->path  = use_default ? defaults[i] : argv[i];
   1916		data->mode  = PERF_DATA_MODE_READ,
   1917		data->force = force,
   1918
   1919		d->idx  = i;
   1920	}
   1921
   1922	return 0;
   1923}
   1924
   1925static int diff__config(const char *var, const char *value,
   1926			void *cb __maybe_unused)
   1927{
   1928	if (!strcmp(var, "diff.order")) {
   1929		int ret;
   1930		if (perf_config_int(&ret, var, value) < 0)
   1931			return -1;
   1932		sort_compute = ret;
   1933		return 0;
   1934	}
   1935	if (!strcmp(var, "diff.compute")) {
   1936		if (!strcmp(value, "delta")) {
   1937			compute = COMPUTE_DELTA;
   1938		} else if (!strcmp(value, "delta-abs")) {
   1939			compute = COMPUTE_DELTA_ABS;
   1940		} else if (!strcmp(value, "ratio")) {
   1941			compute = COMPUTE_RATIO;
   1942		} else if (!strcmp(value, "wdiff")) {
   1943			compute = COMPUTE_WEIGHTED_DIFF;
   1944		} else {
   1945			pr_err("Invalid compute method: %s\n", value);
   1946			return -1;
   1947		}
   1948	}
   1949
   1950	return 0;
   1951}
   1952
   1953int cmd_diff(int argc, const char **argv)
   1954{
   1955	int ret = hists__init();
   1956
   1957	if (ret < 0)
   1958		return ret;
   1959
   1960	perf_config(diff__config, NULL);
   1961
   1962	argc = parse_options(argc, argv, options, diff_usage, 0);
   1963
   1964	if (quiet)
   1965		perf_quiet_option();
   1966
   1967	if (cycles_hist && (compute != COMPUTE_CYCLES))
   1968		usage_with_options(diff_usage, options);
   1969
   1970	if (pdiff.stream)
   1971		compute = COMPUTE_STREAM;
   1972
   1973	symbol__annotation_init();
   1974
   1975	if (symbol__init(NULL) < 0)
   1976		return -1;
   1977
   1978	if (data_init(argc, argv) < 0)
   1979		return -1;
   1980
   1981	if (check_file_brstack() < 0)
   1982		return -1;
   1983
   1984	if ((compute == COMPUTE_CYCLES || compute == COMPUTE_STREAM)
   1985	    && !pdiff.has_br_stack) {
   1986		return -1;
   1987	}
   1988
   1989	if (compute == COMPUTE_STREAM) {
   1990		symbol_conf.show_branchflag_count = true;
   1991		symbol_conf.disable_add2line_warn = true;
   1992		callchain_param.mode = CHAIN_FLAT;
   1993		callchain_param.key = CCKEY_SRCLINE;
   1994		callchain_param.branch_callstack = 1;
   1995		symbol_conf.use_callchain = true;
   1996		callchain_register_param(&callchain_param);
   1997		sort_order = "srcline,symbol,dso";
   1998	} else {
   1999		if (ui_init() < 0)
   2000			return -1;
   2001
   2002		sort__mode = SORT_MODE__DIFF;
   2003	}
   2004
   2005	if (setup_sorting(NULL) < 0)
   2006		usage_with_options(diff_usage, options);
   2007
   2008	setup_pager();
   2009
   2010	sort__setup_elide(NULL);
   2011
   2012	return __cmd_diff();
   2013}