diff options
Diffstat (limited to 'tools/perf/builtin-diff.c')
| -rw-r--r-- | tools/perf/builtin-diff.c | 248 | 
1 files changed, 157 insertions, 91 deletions
| diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 1fd96c13f199..74aada554b12 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -390,6 +390,15 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)  	}  } +static struct data__file *fmt_to_data_file(struct perf_hpp_fmt *fmt) +{ +	struct diff_hpp_fmt *dfmt = container_of(fmt, struct diff_hpp_fmt, fmt); +	void *ptr = dfmt - dfmt->idx; +	struct data__file *d = container_of(ptr, struct data__file, fmt); + +	return d; +} +  static struct hist_entry*  get_pair_data(struct hist_entry *he, struct data__file *d)  { @@ -407,8 +416,7 @@ get_pair_data(struct hist_entry *he, struct data__file *d)  static struct hist_entry*  get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)  { -	void *ptr = dfmt - dfmt->idx; -	struct data__file *d = container_of(ptr, struct data__file, fmt); +	struct data__file *d = fmt_to_data_file(&dfmt->fmt);  	return get_pair_data(he, d);  } @@ -430,7 +438,7 @@ static void hists__baseline_only(struct hists *hists)  		next = rb_next(&he->rb_node_in);  		if (!hist_entry__next_pair(he)) {  			rb_erase(&he->rb_node_in, root); -			hist_entry__free(he); +			hist_entry__delete(he);  		}  	}  } @@ -448,26 +456,30 @@ static void hists__precompute(struct hists *hists)  	next = rb_first(root);  	while (next != NULL) {  		struct hist_entry *he, *pair; +		struct data__file *d; +		int i;  		he   = rb_entry(next, struct hist_entry, rb_node_in);  		next = rb_next(&he->rb_node_in); -		pair = get_pair_data(he, &data__files[sort_compute]); -		if (!pair) -			continue; +		data__for_each_file_new(i, d) { +			pair = get_pair_data(he, d); +			if (!pair) +				continue; -		switch (compute) { -		case COMPUTE_DELTA: -			compute_delta(he, pair); -			break; -		case COMPUTE_RATIO: -			compute_ratio(he, pair); -			break; -		case COMPUTE_WEIGHTED_DIFF: -			compute_wdiff(he, pair); -			break; -		default: -			BUG_ON(1); +			switch (compute) { +			case COMPUTE_DELTA: +				compute_delta(he, pair); +				break; +			case COMPUTE_RATIO: +				compute_ratio(he, pair); +				break; +			case COMPUTE_WEIGHTED_DIFF: +				compute_wdiff(he, pair); +				break; +			default: +				BUG_ON(1); +			}  		}  	}  } @@ -517,7 +529,7 @@ __hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,  static int64_t  hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, -			int c) +			int c, int sort_idx)  {  	bool pairs_left  = hist_entry__has_pairs(left);  	bool pairs_right = hist_entry__has_pairs(right); @@ -529,8 +541,8 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,  	if (!pairs_left || !pairs_right)  		return pairs_left ? -1 : 1; -	p_left  = get_pair_data(left,  &data__files[sort_compute]); -	p_right = get_pair_data(right, &data__files[sort_compute]); +	p_left  = get_pair_data(left,  &data__files[sort_idx]); +	p_right = get_pair_data(right, &data__files[sort_idx]);  	if (!p_left && !p_right)  		return 0; @@ -546,90 +558,102 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,  }  static int64_t -hist_entry__cmp_nop(struct hist_entry *left __maybe_unused, +hist_entry__cmp_compute_idx(struct hist_entry *left, struct hist_entry *right, +			    int c, int sort_idx) +{ +	struct hist_entry *p_right, *p_left; + +	p_left  = get_pair_data(left,  &data__files[sort_idx]); +	p_right = get_pair_data(right, &data__files[sort_idx]); + +	if (!p_left && !p_right) +		return 0; + +	if (!p_left || !p_right) +		return p_left ? -1 : 1; + +	if (c != COMPUTE_DELTA) { +		/* +		 * The delta can be computed without the baseline, but +		 * others are not.  Put those entries which have no +		 * values below. +		 */ +		if (left->dummy && right->dummy) +			return 0; + +		if (left->dummy || right->dummy) +			return left->dummy ? 1 : -1; +	} + +	return __hist_entry__cmp_compute(p_left, p_right, c); +} + +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)  {  	return 0;  }  static int64_t -hist_entry__cmp_baseline(struct hist_entry *left, struct hist_entry *right) +hist_entry__cmp_baseline(struct perf_hpp_fmt *fmt __maybe_unused, +			 struct hist_entry *left, struct hist_entry *right)  { -	if (sort_compute) -		return 0; -  	if (left->stat.period == right->stat.period)  		return 0;  	return left->stat.period > right->stat.period ? 1 : -1;  }  static int64_t -hist_entry__cmp_delta(struct hist_entry *left, struct hist_entry *right) +hist_entry__cmp_delta(struct perf_hpp_fmt *fmt, +		      struct hist_entry *left, struct hist_entry *right)  { -	return hist_entry__cmp_compute(right, left, COMPUTE_DELTA); +	struct data__file *d = fmt_to_data_file(fmt); + +	return hist_entry__cmp_compute(right, left, COMPUTE_DELTA, d->idx);  }  static int64_t -hist_entry__cmp_ratio(struct hist_entry *left, struct hist_entry *right) +hist_entry__cmp_ratio(struct perf_hpp_fmt *fmt, +		      struct hist_entry *left, struct hist_entry *right)  { -	return hist_entry__cmp_compute(right, left, COMPUTE_RATIO); +	struct data__file *d = fmt_to_data_file(fmt); + +	return hist_entry__cmp_compute(right, left, COMPUTE_RATIO, d->idx);  }  static int64_t -hist_entry__cmp_wdiff(struct hist_entry *left, struct hist_entry *right) +hist_entry__cmp_wdiff(struct perf_hpp_fmt *fmt, +		      struct hist_entry *left, struct hist_entry *right)  { -	return hist_entry__cmp_compute(right, left, COMPUTE_WEIGHTED_DIFF); +	struct data__file *d = fmt_to_data_file(fmt); + +	return hist_entry__cmp_compute(right, left, COMPUTE_WEIGHTED_DIFF, d->idx);  } -static void insert_hist_entry_by_compute(struct rb_root *root, -					 struct hist_entry *he, -					 int c) +static int64_t +hist_entry__cmp_delta_idx(struct perf_hpp_fmt *fmt __maybe_unused, +			  struct hist_entry *left, struct hist_entry *right)  { -	struct rb_node **p = &root->rb_node; -	struct rb_node *parent = NULL; -	struct hist_entry *iter; - -	while (*p != NULL) { -		parent = *p; -		iter = rb_entry(parent, struct hist_entry, rb_node); -		if (hist_entry__cmp_compute(he, iter, c) < 0) -			p = &(*p)->rb_left; -		else -			p = &(*p)->rb_right; -	} - -	rb_link_node(&he->rb_node, parent, p); -	rb_insert_color(&he->rb_node, root); +	return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA, +					   sort_compute);  } -static void hists__compute_resort(struct hists *hists) +static int64_t +hist_entry__cmp_ratio_idx(struct perf_hpp_fmt *fmt __maybe_unused, +			  struct hist_entry *left, struct hist_entry *right)  { -	struct rb_root *root; -	struct rb_node *next; - -	if (sort__need_collapse) -		root = &hists->entries_collapsed; -	else -		root = hists->entries_in; - -	hists->entries = RB_ROOT; -	next = rb_first(root); - -	hists__reset_stats(hists); -	hists__reset_col_len(hists); - -	while (next != NULL) { -		struct hist_entry *he; - -		he = rb_entry(next, struct hist_entry, rb_node_in); -		next = rb_next(&he->rb_node_in); - -		insert_hist_entry_by_compute(&hists->entries, he, compute); -		hists__inc_stats(hists, he); +	return hist_entry__cmp_compute_idx(right, left, COMPUTE_RATIO, +					   sort_compute); +} -		if (!he->filtered) -			hists__calc_col_len(hists, he); -	} +static int64_t +hist_entry__cmp_wdiff_idx(struct perf_hpp_fmt *fmt __maybe_unused, +			  struct hist_entry *left, struct hist_entry *right) +{ +	return hist_entry__cmp_compute_idx(right, left, COMPUTE_WEIGHTED_DIFF, +					   sort_compute);  }  static void hists__process(struct hists *hists) @@ -637,12 +661,8 @@ static void hists__process(struct hists *hists)  	if (show_baseline_only)  		hists__baseline_only(hists); -	if (sort_compute) { -		hists__precompute(hists); -		hists__compute_resort(hists); -	} else { -		hists__output_resort(hists, NULL); -	} +	hists__precompute(hists); +	hists__output_resort(hists, NULL);  	hists__fprintf(hists, true, 0, 0, 0, stdout);  } @@ -841,7 +861,7 @@ static int __hpp__color_compare(struct perf_hpp_fmt *fmt,  	char pfmt[20] = " ";  	if (!pair) -		goto dummy_print; +		goto no_print;  	switch (comparison_method) {  	case COMPUTE_DELTA: @@ -850,8 +870,6 @@ static int __hpp__color_compare(struct perf_hpp_fmt *fmt,  		else  			diff = compute_delta(he, pair); -		if (fabs(diff) < 0.01) -			goto dummy_print;  		scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1);  		return percent_color_snprintf(hpp->buf, hpp->size,  					pfmt, diff); @@ -883,6 +901,9 @@ static int __hpp__color_compare(struct perf_hpp_fmt *fmt,  	}  dummy_print:  	return scnprintf(hpp->buf, hpp->size, "%*s", +			dfmt->header_width, "N/A"); +no_print: +	return scnprintf(hpp->buf, hpp->size, "%*s",  			dfmt->header_width, pfmt);  } @@ -932,14 +953,15 @@ hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,  		else  			diff = compute_delta(he, pair); -		if (fabs(diff) >= 0.01) -			scnprintf(buf, size, "%+4.2F%%", diff); +		scnprintf(buf, size, "%+4.2F%%", diff);  		break;  	case PERF_HPP_DIFF__RATIO:  		/* No point for ratio number if we are dummy.. */ -		if (he->dummy) +		if (he->dummy) { +			scnprintf(buf, size, "N/A");  			break; +		}  		if (pair->diff.computed)  			ratio = pair->diff.period_ratio; @@ -952,8 +974,10 @@ hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,  	case PERF_HPP_DIFF__WEIGHTED_DIFF:  		/* No point for wdiff number if we are dummy.. */ -		if (he->dummy) +		if (he->dummy) { +			scnprintf(buf, size, "N/A");  			break; +		}  		if (pair->diff.computed)  			wdiff = pair->diff.wdiff; @@ -1105,9 +1129,10 @@ static void data__hpp_register(struct data__file *d, int idx)  	perf_hpp__register_sort_field(fmt);  } -static void ui_init(void) +static int ui_init(void)  {  	struct data__file *d; +	struct perf_hpp_fmt *fmt;  	int i;  	data__for_each_file(i, d) { @@ -1137,6 +1162,46 @@ static void ui_init(void)  			data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD :  						  PERF_HPP_DIFF__PERIOD_BASELINE);  	} + +	if (!sort_compute) +		return 0; + +	/* +	 * Prepend an fmt to sort on columns at 'sort_compute' first. +	 * This fmt is added only to the sort list but not to the +	 * output fields list. +	 * +	 * Note that this column (data) can be compared twice - one +	 * for this 'sort_compute' fmt and another for the normal +	 * diff_hpp_fmt.  But it shouldn't a problem as most entries +	 * will be sorted out by first try or baseline and comparing +	 * is not a costly operation. +	 */ +	fmt = zalloc(sizeof(*fmt)); +	if (fmt == NULL) { +		pr_err("Memory allocation failed\n"); +		return -1; +	} + +	fmt->cmp      = hist_entry__cmp_nop; +	fmt->collapse = hist_entry__cmp_nop; + +	switch (compute) { +	case COMPUTE_DELTA: +		fmt->sort = hist_entry__cmp_delta_idx; +		break; +	case COMPUTE_RATIO: +		fmt->sort = hist_entry__cmp_ratio_idx; +		break; +	case COMPUTE_WEIGHTED_DIFF: +		fmt->sort = hist_entry__cmp_wdiff_idx; +		break; +	default: +		BUG_ON(1); +	} + +	list_add(&fmt->sort_list, &perf_hpp__sort_list); +	return 0;  }  static int data_init(int argc, const char **argv) @@ -1202,7 +1267,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)  	if (data_init(argc, argv) < 0)  		return -1; -	ui_init(); +	if (ui_init() < 0) +		return -1;  	sort__mode = SORT_MODE__DIFF; |