brintos

brintos / linux-shallow public Read only

0
0
Text · 22.4 KiB · e549199 Raw
949 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <inttypes.h>3#include <math.h>4#include <stdlib.h>5#include <string.h>6#include <linux/compiler.h>7 8#include "../util/callchain.h"9#include "../util/debug.h"10#include "../util/hist.h"11#include "../util/sort.h"12#include "../util/evsel.h"13#include "../util/evlist.h"14#include "../util/thread.h"15#include "../util/util.h"16 17/* hist period print (hpp) functions */18 19#define hpp__call_print_fn(hpp, fn, fmt, ...)			\20({								\21	int __ret = fn(hpp, fmt, ##__VA_ARGS__);		\22	advance_hpp(hpp, __ret);				\23	__ret;							\24})25 26static int __hpp__fmt_print(struct perf_hpp *hpp, struct hists *hists, u64 val,27			    int nr_samples, const char *fmt, int len,28			    hpp_snprint_fn print_fn, enum perf_hpp_fmt_type fmtype)29{30	if (fmtype == PERF_HPP_FMT_TYPE__PERCENT) {31		double percent = 0.0;32		u64 total = hists__total_period(hists);33 34		if (total)35			percent = 100.0 * val / total;36 37		return hpp__call_print_fn(hpp, print_fn, fmt, len, percent);38	}39 40	if (fmtype == PERF_HPP_FMT_TYPE__AVERAGE) {41		double avg = nr_samples ? (1.0 * val / nr_samples) : 0;42 43		return hpp__call_print_fn(hpp, print_fn, fmt, len, avg);44	}45 46	return hpp__call_print_fn(hpp, print_fn, fmt, len, val);47}48 49struct hpp_fmt_value {50	struct hists *hists;51	u64 val;52	int samples;53};54 55static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,56		      hpp_field_fn get_field, const char *fmt, int len,57		      hpp_snprint_fn print_fn, enum perf_hpp_fmt_type fmtype)58{59	int ret = 0;60	struct hists *hists = he->hists;61	struct evsel *evsel = hists_to_evsel(hists);62	struct evsel *pos;63	char *buf = hpp->buf;64	size_t size = hpp->size;65	int i = 0, nr_members = 1;66	struct hpp_fmt_value *values;67 68	if (evsel__is_group_event(evsel))69		nr_members = evsel->core.nr_members;70 71	values = calloc(nr_members, sizeof(*values));72	if (values == NULL)73		return 0;74 75	values[0].hists = evsel__hists(evsel);76	values[0].val = get_field(he);77	values[0].samples = he->stat.nr_events;78 79	if (evsel__is_group_event(evsel)) {80		struct hist_entry *pair;81 82		for_each_group_member(pos, evsel)83			values[++i].hists = evsel__hists(pos);84 85		list_for_each_entry(pair, &he->pairs.head, pairs.node) {86			for (i = 0; i < nr_members; i++) {87				if (values[i].hists != pair->hists)88					continue;89 90				values[i].val = get_field(pair);91				values[i].samples = pair->stat.nr_events;92				break;93			}94		}95	}96 97	for (i = 0; i < nr_members; i++) {98		if (symbol_conf.skip_empty &&99		    values[i].hists->stats.nr_samples == 0)100			continue;101 102		ret += __hpp__fmt_print(hpp, values[i].hists, values[i].val,103					values[i].samples, fmt, len,104					print_fn, fmtype);105	}106 107	free(values);108 109	/*110	 * Restore original buf and size as it's where caller expects111	 * the result will be saved.112	 */113	hpp->buf = buf;114	hpp->size = size;115 116	return ret;117}118 119int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,120	     struct hist_entry *he, hpp_field_fn get_field,121	     const char *fmtstr, hpp_snprint_fn print_fn,122	     enum perf_hpp_fmt_type fmtype)123{124	int len = fmt->user_len ?: fmt->len;125 126	if (symbol_conf.field_sep) {127		return __hpp__fmt(hpp, he, get_field, fmtstr, 1,128				  print_fn, fmtype);129	}130 131	if (fmtype == PERF_HPP_FMT_TYPE__PERCENT)132		len -= 2; /* 2 for a space and a % sign */133	else134		len -= 1;135 136	return  __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmtype);137}138 139int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,140		 struct hist_entry *he, hpp_field_fn get_field,141		 const char *fmtstr, hpp_snprint_fn print_fn,142		 enum perf_hpp_fmt_type fmtype)143{144	if (!symbol_conf.cumulate_callchain) {145		int len = fmt->user_len ?: fmt->len;146		return snprintf(hpp->buf, hpp->size, " %*s", len - 1, "N/A");147	}148 149	return hpp__fmt(fmt, hpp, he, get_field, fmtstr, print_fn, fmtype);150}151 152static int field_cmp(u64 field_a, u64 field_b)153{154	if (field_a > field_b)155		return 1;156	if (field_a < field_b)157		return -1;158	return 0;159}160 161static int hist_entry__new_pair(struct hist_entry *a, struct hist_entry *b,162				hpp_field_fn get_field, int nr_members,163				u64 **fields_a, u64 **fields_b)164{165	u64 *fa = calloc(nr_members, sizeof(*fa)),166	    *fb = calloc(nr_members, sizeof(*fb));167	struct hist_entry *pair;168 169	if (!fa || !fb)170		goto out_free;171 172	list_for_each_entry(pair, &a->pairs.head, pairs.node) {173		struct evsel *evsel = hists_to_evsel(pair->hists);174		fa[evsel__group_idx(evsel)] = get_field(pair);175	}176 177	list_for_each_entry(pair, &b->pairs.head, pairs.node) {178		struct evsel *evsel = hists_to_evsel(pair->hists);179		fb[evsel__group_idx(evsel)] = get_field(pair);180	}181 182	*fields_a = fa;183	*fields_b = fb;184	return 0;185out_free:186	free(fa);187	free(fb);188	*fields_a = *fields_b = NULL;189	return -1;190}191 192static int __hpp__group_sort_idx(struct hist_entry *a, struct hist_entry *b,193				 hpp_field_fn get_field, int idx)194{195	struct evsel *evsel = hists_to_evsel(a->hists);196	u64 *fields_a, *fields_b;197	int cmp, nr_members, ret, i;198 199	cmp = field_cmp(get_field(a), get_field(b));200	if (!evsel__is_group_event(evsel))201		return cmp;202 203	nr_members = evsel->core.nr_members;204	if (idx < 1 || idx >= nr_members)205		return cmp;206 207	ret = hist_entry__new_pair(a, b, get_field, nr_members, &fields_a, &fields_b);208	if (ret) {209		ret = cmp;210		goto out;211	}212 213	ret = field_cmp(fields_a[idx], fields_b[idx]);214	if (ret)215		goto out;216 217	for (i = 1; i < nr_members; i++) {218		if (i != idx) {219			ret = field_cmp(fields_a[i], fields_b[i]);220			if (ret)221				goto out;222		}223	}224 225out:226	free(fields_a);227	free(fields_b);228 229	return ret;230}231 232static int __hpp__sort(struct hist_entry *a, struct hist_entry *b,233		       hpp_field_fn get_field)234{235	s64 ret;236	int i, nr_members;237	struct evsel *evsel;238	u64 *fields_a, *fields_b;239 240	if (symbol_conf.group_sort_idx && symbol_conf.event_group) {241		return __hpp__group_sort_idx(a, b, get_field,242					     symbol_conf.group_sort_idx);243	}244 245	ret = field_cmp(get_field(a), get_field(b));246	if (ret || !symbol_conf.event_group)247		return ret;248 249	evsel = hists_to_evsel(a->hists);250	if (!evsel__is_group_event(evsel))251		return ret;252 253	nr_members = evsel->core.nr_members;254	i = hist_entry__new_pair(a, b, get_field, nr_members, &fields_a, &fields_b);255	if (i)256		goto out;257 258	for (i = 1; i < nr_members; i++) {259		ret = field_cmp(fields_a[i], fields_b[i]);260		if (ret)261			break;262	}263 264out:265	free(fields_a);266	free(fields_b);267 268	return ret;269}270 271static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,272			   hpp_field_fn get_field)273{274	s64 ret = 0;275 276	if (symbol_conf.cumulate_callchain) {277		/*278		 * Put caller above callee when they have equal period.279		 */280		ret = field_cmp(get_field(a), get_field(b));281		if (ret)282			return ret;283 284		if ((a->thread == NULL ? NULL : RC_CHK_ACCESS(a->thread)) !=285		    (b->thread == NULL ? NULL : RC_CHK_ACCESS(b->thread)) ||286		    !hist_entry__has_callchains(a) || !symbol_conf.use_callchain)287			return 0;288 289		ret = b->callchain->max_depth - a->callchain->max_depth;290		if (callchain_param.order == ORDER_CALLER)291			ret = -ret;292	}293	return ret;294}295 296static int hpp__width_fn(struct perf_hpp_fmt *fmt,297			 struct perf_hpp *hpp __maybe_unused,298			 struct hists *hists)299{300	int len = fmt->user_len ?: fmt->len;301	struct evsel *evsel = hists_to_evsel(hists);302 303	if (symbol_conf.event_group) {304		int nr = 0;305		struct evsel *pos;306 307		for_each_group_evsel(pos, evsel) {308			if (!symbol_conf.skip_empty ||309			    evsel__hists(pos)->stats.nr_samples)310				nr++;311		}312 313		len = max(len, nr * fmt->len);314	}315 316	if (len < (int)strlen(fmt->name))317		len = strlen(fmt->name);318 319	return len;320}321 322static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,323			  struct hists *hists, int line __maybe_unused,324			  int *span __maybe_unused)325{326	int len = hpp__width_fn(fmt, hpp, hists);327	return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);328}329 330int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)331{332	va_list args;333	ssize_t ssize = hpp->size;334	double percent;335	int ret, len;336 337	va_start(args, fmt);338	len = va_arg(args, int);339	percent = va_arg(args, double);340	ret = percent_color_len_snprintf(hpp->buf, hpp->size, fmt, len, percent);341	va_end(args);342 343	return (ret >= ssize) ? (ssize - 1) : ret;344}345 346static int hpp_entry_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)347{348	va_list args;349	ssize_t ssize = hpp->size;350	int ret;351 352	va_start(args, fmt);353	ret = vsnprintf(hpp->buf, hpp->size, fmt, args);354	va_end(args);355 356	return (ret >= ssize) ? (ssize - 1) : ret;357}358 359#define __HPP_COLOR_PERCENT_FN(_type, _field)					\360static u64 he_get_##_field(struct hist_entry *he)				\361{										\362	return he->stat._field;							\363}										\364										\365static int hpp__color_##_type(struct perf_hpp_fmt *fmt,				\366			      struct perf_hpp *hpp, struct hist_entry *he) 	\367{										\368	return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%",		\369			hpp_color_scnprintf, PERF_HPP_FMT_TYPE__PERCENT);	\370}371 372#define __HPP_ENTRY_PERCENT_FN(_type, _field)					\373static int hpp__entry_##_type(struct perf_hpp_fmt *fmt,				\374			      struct perf_hpp *hpp, struct hist_entry *he) 	\375{										\376	return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%",		\377			hpp_entry_scnprintf, PERF_HPP_FMT_TYPE__PERCENT);	\378}379 380#define __HPP_SORT_FN(_type, _field)						\381static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, 	\382				 struct hist_entry *a, struct hist_entry *b) 	\383{										\384	return __hpp__sort(a, b, he_get_##_field);				\385}386 387#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)				\388static u64 he_get_acc_##_field(struct hist_entry *he)				\389{										\390	return he->stat_acc->_field;						\391}										\392										\393static int hpp__color_##_type(struct perf_hpp_fmt *fmt,				\394			      struct perf_hpp *hpp, struct hist_entry *he) 	\395{										\396	return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", 	\397			    hpp_color_scnprintf, PERF_HPP_FMT_TYPE__PERCENT);	\398}399 400#define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field)				\401static int hpp__entry_##_type(struct perf_hpp_fmt *fmt,				\402			      struct perf_hpp *hpp, struct hist_entry *he) 	\403{										\404	return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%",	\405			    hpp_entry_scnprintf, PERF_HPP_FMT_TYPE__PERCENT);	\406}407 408#define __HPP_SORT_ACC_FN(_type, _field)					\409static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, 	\410				 struct hist_entry *a, struct hist_entry *b) 	\411{										\412	return __hpp__sort_acc(a, b, he_get_acc_##_field);			\413}414 415#define __HPP_ENTRY_RAW_FN(_type, _field)					\416static u64 he_get_raw_##_field(struct hist_entry *he)				\417{										\418	return he->stat._field;							\419}										\420										\421static int hpp__entry_##_type(struct perf_hpp_fmt *fmt,				\422			      struct perf_hpp *hpp, struct hist_entry *he) 	\423{										\424	return hpp__fmt(fmt, hpp, he, he_get_raw_##_field, " %*"PRIu64, 	\425			hpp_entry_scnprintf, PERF_HPP_FMT_TYPE__RAW);		\426}427 428#define __HPP_SORT_RAW_FN(_type, _field)					\429static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, 	\430				 struct hist_entry *a, struct hist_entry *b) 	\431{										\432	return __hpp__sort(a, b, he_get_raw_##_field);				\433}434 435#define __HPP_ENTRY_AVERAGE_FN(_type, _field)					\436static u64 he_get_##_field(struct hist_entry *he)				\437{										\438	return he->stat._field;							\439}										\440										\441static int hpp__entry_##_type(struct perf_hpp_fmt *fmt,				\442			      struct perf_hpp *hpp, struct hist_entry *he) 	\443{										\444	return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.1f",		\445			hpp_entry_scnprintf, PERF_HPP_FMT_TYPE__AVERAGE);	\446}447 448#define __HPP_SORT_AVERAGE_FN(_type, _field)					\449static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, 	\450				 struct hist_entry *a, struct hist_entry *b) 	\451{										\452	return __hpp__sort(a, b, he_get_##_field);				\453}454 455 456#define HPP_PERCENT_FNS(_type, _field)					\457__HPP_COLOR_PERCENT_FN(_type, _field)					\458__HPP_ENTRY_PERCENT_FN(_type, _field)					\459__HPP_SORT_FN(_type, _field)460 461#define HPP_PERCENT_ACC_FNS(_type, _field)				\462__HPP_COLOR_ACC_PERCENT_FN(_type, _field)				\463__HPP_ENTRY_ACC_PERCENT_FN(_type, _field)				\464__HPP_SORT_ACC_FN(_type, _field)465 466#define HPP_RAW_FNS(_type, _field)					\467__HPP_ENTRY_RAW_FN(_type, _field)					\468__HPP_SORT_RAW_FN(_type, _field)469 470#define HPP_AVERAGE_FNS(_type, _field)					\471__HPP_ENTRY_AVERAGE_FN(_type, _field)					\472__HPP_SORT_AVERAGE_FN(_type, _field)473 474HPP_PERCENT_FNS(overhead, period)475HPP_PERCENT_FNS(overhead_sys, period_sys)476HPP_PERCENT_FNS(overhead_us, period_us)477HPP_PERCENT_FNS(overhead_guest_sys, period_guest_sys)478HPP_PERCENT_FNS(overhead_guest_us, period_guest_us)479HPP_PERCENT_ACC_FNS(overhead_acc, period)480 481HPP_RAW_FNS(samples, nr_events)482HPP_RAW_FNS(period, period)483 484HPP_AVERAGE_FNS(weight1, weight1)485HPP_AVERAGE_FNS(weight2, weight2)486HPP_AVERAGE_FNS(weight3, weight3)487 488static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,489			    struct hist_entry *a __maybe_unused,490			    struct hist_entry *b __maybe_unused)491{492	return 0;493}494 495static bool perf_hpp__is_hpp_entry(struct perf_hpp_fmt *a)496{497	return a->header == hpp__header_fn;498}499 500static bool hpp__equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)501{502	if (!perf_hpp__is_hpp_entry(a) || !perf_hpp__is_hpp_entry(b))503		return false;504 505	return a->idx == b->idx;506}507 508#define HPP__COLOR_PRINT_FNS(_name, _fn, _idx)		\509	{						\510		.name   = _name,			\511		.header	= hpp__header_fn,		\512		.width	= hpp__width_fn,		\513		.color	= hpp__color_ ## _fn,		\514		.entry	= hpp__entry_ ## _fn,		\515		.cmp	= hpp__nop_cmp,			\516		.collapse = hpp__nop_cmp,		\517		.sort	= hpp__sort_ ## _fn,		\518		.idx	= PERF_HPP__ ## _idx,		\519		.equal	= hpp__equal,			\520	}521 522#define HPP__COLOR_ACC_PRINT_FNS(_name, _fn, _idx)	\523	{						\524		.name   = _name,			\525		.header	= hpp__header_fn,		\526		.width	= hpp__width_fn,		\527		.color	= hpp__color_ ## _fn,		\528		.entry	= hpp__entry_ ## _fn,		\529		.cmp	= hpp__nop_cmp,			\530		.collapse = hpp__nop_cmp,		\531		.sort	= hpp__sort_ ## _fn,		\532		.idx	= PERF_HPP__ ## _idx,		\533		.equal	= hpp__equal,			\534	}535 536#define HPP__PRINT_FNS(_name, _fn, _idx)		\537	{						\538		.name   = _name,			\539		.header	= hpp__header_fn,		\540		.width	= hpp__width_fn,		\541		.entry	= hpp__entry_ ## _fn,		\542		.cmp	= hpp__nop_cmp,			\543		.collapse = hpp__nop_cmp,		\544		.sort	= hpp__sort_ ## _fn,		\545		.idx	= PERF_HPP__ ## _idx,		\546		.equal	= hpp__equal,			\547	}548 549struct perf_hpp_fmt perf_hpp__format[] = {550	HPP__COLOR_PRINT_FNS("Overhead", overhead, OVERHEAD),551	HPP__COLOR_PRINT_FNS("sys", overhead_sys, OVERHEAD_SYS),552	HPP__COLOR_PRINT_FNS("usr", overhead_us, OVERHEAD_US),553	HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys, OVERHEAD_GUEST_SYS),554	HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us, OVERHEAD_GUEST_US),555	HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc, OVERHEAD_ACC),556	HPP__PRINT_FNS("Samples", samples, SAMPLES),557	HPP__PRINT_FNS("Period", period, PERIOD),558	HPP__PRINT_FNS("Weight1", weight1, WEIGHT1),559	HPP__PRINT_FNS("Weight2", weight2, WEIGHT2),560	HPP__PRINT_FNS("Weight3", weight3, WEIGHT3),561};562 563struct perf_hpp_list perf_hpp_list = {564	.fields	= LIST_HEAD_INIT(perf_hpp_list.fields),565	.sorts	= LIST_HEAD_INIT(perf_hpp_list.sorts),566	.nr_header_lines = 1,567};568 569#undef HPP__COLOR_PRINT_FNS570#undef HPP__COLOR_ACC_PRINT_FNS571#undef HPP__PRINT_FNS572 573#undef HPP_PERCENT_FNS574#undef HPP_PERCENT_ACC_FNS575#undef HPP_RAW_FNS576#undef HPP_AVERAGE_FNS577 578#undef __HPP_HEADER_FN579#undef __HPP_WIDTH_FN580#undef __HPP_COLOR_PERCENT_FN581#undef __HPP_ENTRY_PERCENT_FN582#undef __HPP_COLOR_ACC_PERCENT_FN583#undef __HPP_ENTRY_ACC_PERCENT_FN584#undef __HPP_ENTRY_RAW_FN585#undef __HPP_ENTRY_AVERAGE_FN586#undef __HPP_SORT_FN587#undef __HPP_SORT_ACC_FN588#undef __HPP_SORT_RAW_FN589#undef __HPP_SORT_AVERAGE_FN590 591static void fmt_free(struct perf_hpp_fmt *fmt)592{593	/*594	 * At this point fmt should be completely595	 * unhooked, if not it's a bug.596	 */597	BUG_ON(!list_empty(&fmt->list));598	BUG_ON(!list_empty(&fmt->sort_list));599 600	if (fmt->free)601		fmt->free(fmt);602}603 604void perf_hpp__init(void)605{606	int i;607 608	for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {609		struct perf_hpp_fmt *fmt = &perf_hpp__format[i];610 611		INIT_LIST_HEAD(&fmt->list);612 613		/* sort_list may be linked by setup_sorting() */614		if (fmt->sort_list.next == NULL)615			INIT_LIST_HEAD(&fmt->sort_list);616	}617 618	/*619	 * If user specified field order, no need to setup default fields.620	 */621	if (is_strict_order(field_order))622		return;623 624	if (symbol_conf.cumulate_callchain) {625		hpp_dimension__add_output(PERF_HPP__OVERHEAD_ACC);626		perf_hpp__format[PERF_HPP__OVERHEAD].name = "Self";627	}628 629	hpp_dimension__add_output(PERF_HPP__OVERHEAD);630 631	if (symbol_conf.show_cpu_utilization) {632		hpp_dimension__add_output(PERF_HPP__OVERHEAD_SYS);633		hpp_dimension__add_output(PERF_HPP__OVERHEAD_US);634 635		if (perf_guest) {636			hpp_dimension__add_output(PERF_HPP__OVERHEAD_GUEST_SYS);637			hpp_dimension__add_output(PERF_HPP__OVERHEAD_GUEST_US);638		}639	}640 641	if (symbol_conf.show_nr_samples)642		hpp_dimension__add_output(PERF_HPP__SAMPLES);643 644	if (symbol_conf.show_total_period)645		hpp_dimension__add_output(PERF_HPP__PERIOD);646}647 648void perf_hpp_list__column_register(struct perf_hpp_list *list,649				    struct perf_hpp_fmt *format)650{651	list_add_tail(&format->list, &list->fields);652}653 654void perf_hpp_list__register_sort_field(struct perf_hpp_list *list,655					struct perf_hpp_fmt *format)656{657	list_add_tail(&format->sort_list, &list->sorts);658}659 660void perf_hpp_list__prepend_sort_field(struct perf_hpp_list *list,661				       struct perf_hpp_fmt *format)662{663	list_add(&format->sort_list, &list->sorts);664}665 666static void perf_hpp__column_unregister(struct perf_hpp_fmt *format)667{668	list_del_init(&format->list);669	fmt_free(format);670}671 672void perf_hpp__cancel_cumulate(void)673{674	struct perf_hpp_fmt *fmt, *acc, *ovh, *tmp;675 676	if (is_strict_order(field_order))677		return;678 679	ovh = &perf_hpp__format[PERF_HPP__OVERHEAD];680	acc = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC];681 682	perf_hpp_list__for_each_format_safe(&perf_hpp_list, fmt, tmp) {683		if (acc->equal(acc, fmt)) {684			perf_hpp__column_unregister(fmt);685			continue;686		}687 688		if (ovh->equal(ovh, fmt))689			fmt->name = "Overhead";690	}691}692 693static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)694{695	return a->equal && a->equal(a, b);696}697 698void perf_hpp__setup_output_field(struct perf_hpp_list *list)699{700	struct perf_hpp_fmt *fmt;701 702	/* append sort keys to output field */703	perf_hpp_list__for_each_sort_list(list, fmt) {704		struct perf_hpp_fmt *pos;705 706		/* skip sort-only fields ("sort_compute" in perf diff) */707		if (!fmt->entry && !fmt->color)708			continue;709 710		perf_hpp_list__for_each_format(list, pos) {711			if (fmt_equal(fmt, pos))712				goto next;713		}714 715		perf_hpp__column_register(fmt);716next:717		continue;718	}719}720 721void perf_hpp__append_sort_keys(struct perf_hpp_list *list)722{723	struct perf_hpp_fmt *fmt;724 725	/* append output fields to sort keys */726	perf_hpp_list__for_each_format(list, fmt) {727		struct perf_hpp_fmt *pos;728 729		perf_hpp_list__for_each_sort_list(list, pos) {730			if (fmt_equal(fmt, pos))731				goto next;732		}733 734		perf_hpp__register_sort_field(fmt);735next:736		continue;737	}738}739 740 741void perf_hpp__reset_output_field(struct perf_hpp_list *list)742{743	struct perf_hpp_fmt *fmt, *tmp;744 745	/* reset output fields */746	perf_hpp_list__for_each_format_safe(list, fmt, tmp) {747		list_del_init(&fmt->list);748		list_del_init(&fmt->sort_list);749		fmt_free(fmt);750	}751 752	/* reset sort keys */753	perf_hpp_list__for_each_sort_list_safe(list, fmt, tmp) {754		list_del_init(&fmt->list);755		list_del_init(&fmt->sort_list);756		fmt_free(fmt);757	}758}759 760/*761 * See hists__fprintf to match the column widths762 */763unsigned int hists__sort_list_width(struct hists *hists)764{765	struct perf_hpp_fmt *fmt;766	int ret = 0;767	bool first = true;768	struct perf_hpp dummy_hpp;769 770	hists__for_each_format(hists, fmt) {771		if (perf_hpp__should_skip(fmt, hists))772			continue;773 774		if (first)775			first = false;776		else777			ret += 2;778 779		ret += fmt->width(fmt, &dummy_hpp, hists);780	}781 782	if (verbose > 0 && hists__has(hists, sym)) /* Addr + origin */783		ret += 3 + BITS_PER_LONG / 4;784 785	return ret;786}787 788unsigned int hists__overhead_width(struct hists *hists)789{790	struct perf_hpp_fmt *fmt;791	int ret = 0;792	bool first = true;793	struct perf_hpp dummy_hpp;794 795	hists__for_each_format(hists, fmt) {796		if (perf_hpp__is_sort_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))797			break;798 799		if (first)800			first = false;801		else802			ret += 2;803 804		ret += fmt->width(fmt, &dummy_hpp, hists);805	}806 807	return ret;808}809 810void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)811{812	if (perf_hpp__is_sort_entry(fmt))813		return perf_hpp__reset_sort_width(fmt, hists);814 815	if (perf_hpp__is_dynamic_entry(fmt))816		return;817 818	BUG_ON(fmt->idx >= PERF_HPP__MAX_INDEX);819 820	switch (fmt->idx) {821	case PERF_HPP__OVERHEAD:822	case PERF_HPP__OVERHEAD_SYS:823	case PERF_HPP__OVERHEAD_US:824	case PERF_HPP__OVERHEAD_ACC:825		fmt->len = 8;826		break;827 828	case PERF_HPP__OVERHEAD_GUEST_SYS:829	case PERF_HPP__OVERHEAD_GUEST_US:830		fmt->len = 9;831		break;832 833	case PERF_HPP__SAMPLES:834	case PERF_HPP__PERIOD:835		fmt->len = 12;836		break;837 838	case PERF_HPP__WEIGHT1:839	case PERF_HPP__WEIGHT2:840	case PERF_HPP__WEIGHT3:841		fmt->len = 8;842		break;843 844	default:845		break;846	}847}848 849void hists__reset_column_width(struct hists *hists)850{851	struct perf_hpp_fmt *fmt;852	struct perf_hpp_list_node *node;853 854	hists__for_each_format(hists, fmt)855		perf_hpp__reset_width(fmt, hists);856 857	/* hierarchy entries have their own hpp list */858	list_for_each_entry(node, &hists->hpp_formats, list) {859		perf_hpp_list__for_each_format(&node->hpp, fmt)860			perf_hpp__reset_width(fmt, hists);861	}862}863 864void perf_hpp__set_user_width(const char *width_list_str)865{866	struct perf_hpp_fmt *fmt;867	const char *ptr = width_list_str;868 869	perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {870		char *p;871 872		int len = strtol(ptr, &p, 10);873		fmt->user_len = len;874 875		if (*p == ',')876			ptr = p + 1;877		else878			break;879	}880}881 882static int add_hierarchy_fmt(struct hists *hists, struct perf_hpp_fmt *fmt)883{884	struct perf_hpp_list_node *node = NULL;885	struct perf_hpp_fmt *fmt_copy;886	bool found = false;887	bool skip = perf_hpp__should_skip(fmt, hists);888 889	list_for_each_entry(node, &hists->hpp_formats, list) {890		if (node->level == fmt->level) {891			found = true;892			break;893		}894	}895 896	if (!found) {897		node = malloc(sizeof(*node));898		if (node == NULL)899			return -1;900 901		node->skip = skip;902		node->level = fmt->level;903		perf_hpp_list__init(&node->hpp);904 905		hists->nr_hpp_node++;906		list_add_tail(&node->list, &hists->hpp_formats);907	}908 909	fmt_copy = perf_hpp_fmt__dup(fmt);910	if (fmt_copy == NULL)911		return -1;912 913	if (!skip)914		node->skip = false;915 916	list_add_tail(&fmt_copy->list, &node->hpp.fields);917	list_add_tail(&fmt_copy->sort_list, &node->hpp.sorts);918 919	return 0;920}921 922int perf_hpp__setup_hists_formats(struct perf_hpp_list *list,923				  struct evlist *evlist)924{925	struct evsel *evsel;926	struct perf_hpp_fmt *fmt;927	struct hists *hists;928	int ret;929 930	if (!symbol_conf.report_hierarchy)931		return 0;932 933	evlist__for_each_entry(evlist, evsel) {934		hists = evsel__hists(evsel);935 936		perf_hpp_list__for_each_sort_list(list, fmt) {937			if (perf_hpp__is_dynamic_entry(fmt) &&938			    !perf_hpp__defined_dynamic_entry(fmt, hists))939				continue;940 941			ret = add_hierarchy_fmt(hists, fmt);942			if (ret < 0)943				return ret;944		}945	}946 947	return 0;948}949