diff options
Diffstat (limited to 'tools/perf/ui/browsers/hists.c')
| -rw-r--r-- | tools/perf/ui/browsers/hists.c | 444 | 
1 files changed, 241 insertions, 203 deletions
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 7ef36c36047..04a229aa5c0 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -17,6 +17,7 @@  #include "../util.h"  #include "../ui.h"  #include "map.h" +#include "annotate.h"  struct hist_browser {  	struct ui_browser   b; @@ -26,13 +27,35 @@ struct hist_browser {  	int		     print_seq;  	bool		     show_dso;  	float		     min_pcnt; -	u64		     nr_pcnt_entries; +	u64		     nr_non_filtered_entries; +	u64		     nr_callchain_rows;  };  extern void hist_browser__init_hpp(void);  static int hists__browser_title(struct hists *hists, char *bf, size_t size,  				const char *ev_name); +static void hist_browser__update_nr_entries(struct hist_browser *hb); + +static struct rb_node *hists__filter_entries(struct rb_node *nd, +					     float min_pcnt); + +static bool hist_browser__has_filter(struct hist_browser *hb) +{ +	return hists__has_filter(hb->hists) || hb->min_pcnt; +} + +static u32 hist_browser__nr_entries(struct hist_browser *hb) +{ +	u32 nr_entries; + +	if (hist_browser__has_filter(hb)) +		nr_entries = hb->nr_non_filtered_entries; +	else +		nr_entries = hb->hists->nr_entries; + +	return nr_entries + hb->nr_callchain_rows; +}  static void hist_browser__refresh_dimensions(struct hist_browser *browser)  { @@ -43,7 +66,14 @@ static void hist_browser__refresh_dimensions(struct hist_browser *browser)  static void hist_browser__reset(struct hist_browser *browser)  { -	browser->b.nr_entries = browser->hists->nr_entries; +	/* +	 * The hists__remove_entry_filter() already folds non-filtered +	 * entries so we can assume it has 0 callchain rows. +	 */ +	browser->nr_callchain_rows = 0; + +	hist_browser__update_nr_entries(browser); +	browser->b.nr_entries = hist_browser__nr_entries(browser);  	hist_browser__refresh_dimensions(browser);  	ui_browser__reset_index(&browser->b);  } @@ -198,14 +228,16 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)  		struct hist_entry *he = browser->he_selection;  		hist_entry__init_have_children(he); -		browser->hists->nr_entries -= he->nr_rows; +		browser->b.nr_entries -= he->nr_rows; +		browser->nr_callchain_rows -= he->nr_rows;  		if (he->ms.unfolded)  			he->nr_rows = callchain__count_rows(&he->sorted_chain);  		else  			he->nr_rows = 0; -		browser->hists->nr_entries += he->nr_rows; -		browser->b.nr_entries = browser->hists->nr_entries; + +		browser->b.nr_entries += he->nr_rows; +		browser->nr_callchain_rows += he->nr_rows;  		return true;  	} @@ -280,23 +312,27 @@ static void hist_entry__set_folding(struct hist_entry *he, bool unfold)  		he->nr_rows = 0;  } -static void hists__set_folding(struct hists *hists, bool unfold) +static void +__hist_browser__set_folding(struct hist_browser *browser, bool unfold)  {  	struct rb_node *nd; +	struct hists *hists = browser->hists; -	hists->nr_entries = 0; - -	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { +	for (nd = rb_first(&hists->entries); +	     (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; +	     nd = rb_next(nd)) {  		struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);  		hist_entry__set_folding(he, unfold); -		hists->nr_entries += 1 + he->nr_rows; +		browser->nr_callchain_rows += he->nr_rows;  	}  }  static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)  { -	hists__set_folding(browser->hists, unfold); -	browser->b.nr_entries = browser->hists->nr_entries; +	browser->nr_callchain_rows = 0; +	__hist_browser__set_folding(browser, unfold); + +	browser->b.nr_entries = hist_browser__nr_entries(browser);  	/* Go to the start, we may be way after valid entries after a collapse */  	ui_browser__reset_index(&browser->b);  } @@ -310,8 +346,6 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)  		"Or reduce the sampling frequency.");  } -static void hist_browser__update_pcnt_entries(struct hist_browser *hb); -  static int hist_browser__run(struct hist_browser *browser, const char *ev_name,  			     struct hist_browser_timer *hbt)  { @@ -320,9 +354,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,  	int delay_secs = hbt ? hbt->refresh : 0;  	browser->b.entries = &browser->hists->entries; -	browser->b.nr_entries = browser->hists->nr_entries; -	if (browser->min_pcnt) -		browser->b.nr_entries = browser->nr_pcnt_entries; +	browser->b.nr_entries = hist_browser__nr_entries(browser);  	hist_browser__refresh_dimensions(browser);  	hists__browser_title(browser->hists, title, sizeof(title), ev_name); @@ -339,13 +371,10 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,  			u64 nr_entries;  			hbt->timer(hbt->arg); -			if (browser->min_pcnt) { -				hist_browser__update_pcnt_entries(browser); -				nr_entries = browser->nr_pcnt_entries; -			} else { -				nr_entries = browser->hists->nr_entries; -			} +			if (hist_browser__has_filter(browser)) +				hist_browser__update_nr_entries(browser); +			nr_entries = hist_browser__nr_entries(browser);  			ui_browser__update_nr_entries(&browser->b, nr_entries);  			if (browser->hists->stats.nr_lost_warned != @@ -587,99 +616,27 @@ struct hpp_arg {  	bool current_entry;  }; -static int __hpp__color_callchain(struct hpp_arg *arg) +static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)  { -	if (!symbol_conf.use_callchain) -		return 0; - -	slsmg_printf("%c ", arg->folded_sign); -	return 2; -} - -static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he, -			    u64 (*get_field)(struct hist_entry *), -			    int (*callchain_cb)(struct hpp_arg *)) -{ -	int ret = 0; -	double percent = 0.0; -	struct hists *hists = he->hists;  	struct hpp_arg *arg = hpp->ptr; +	int ret; +	va_list args; +	double percent; -	if (hists->stats.total_period) -		percent = 100.0 * get_field(he) / hists->stats.total_period; +	va_start(args, fmt); +	percent = va_arg(args, double); +	va_end(args);  	ui_browser__set_percent_color(arg->b, percent, arg->current_entry); -	if (callchain_cb) -		ret += callchain_cb(arg); - -	ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); +	ret = scnprintf(hpp->buf, hpp->size, fmt, percent);  	slsmg_printf("%s", hpp->buf); -	if (symbol_conf.event_group) { -		int prev_idx, idx_delta; -		struct perf_evsel *evsel = hists_to_evsel(hists); -		struct hist_entry *pair; -		int nr_members = evsel->nr_members; - -		if (nr_members <= 1) -			goto out; - -		prev_idx = perf_evsel__group_idx(evsel); - -		list_for_each_entry(pair, &he->pairs.head, pairs.node) { -			u64 period = get_field(pair); -			u64 total = pair->hists->stats.total_period; - -			if (!total) -				continue; - -			evsel = hists_to_evsel(pair->hists); -			idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1; - -			while (idx_delta--) { -				/* -				 * zero-fill group members in the middle which -				 * have no sample -				 */ -				ui_browser__set_percent_color(arg->b, 0.0, -							arg->current_entry); -				ret += scnprintf(hpp->buf, hpp->size, -						 " %6.2f%%", 0.0); -				slsmg_printf("%s", hpp->buf); -			} - -			percent = 100.0 * period / total; -			ui_browser__set_percent_color(arg->b, percent, -						      arg->current_entry); -			ret += scnprintf(hpp->buf, hpp->size, -					 " %6.2f%%", percent); -			slsmg_printf("%s", hpp->buf); - -			prev_idx = perf_evsel__group_idx(evsel); -		} - -		idx_delta = nr_members - prev_idx - 1; - -		while (idx_delta--) { -			/* -			 * zero-fill group members at last which have no sample -			 */ -			ui_browser__set_percent_color(arg->b, 0.0, -						      arg->current_entry); -			ret += scnprintf(hpp->buf, hpp->size, -					 " %6.2f%%", 0.0); -			slsmg_printf("%s", hpp->buf); -		} -	} -out: -	if (!arg->current_entry || !arg->b->navkeypressed) -		ui_browser__set_color(arg->b, HE_COLORSET_NORMAL); - +	advance_hpp(hpp, ret);  	return ret;  } -#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb)			\ +#define __HPP_COLOR_PERCENT_FN(_type, _field)				\  static u64 __hpp_get_##_field(struct hist_entry *he)			\  {									\  	return he->stat._field;						\ @@ -690,21 +647,43 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\  				struct perf_hpp *hpp,			\  				struct hist_entry *he)			\  {									\ -	return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb);	\ +	return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%",	\ +			  __hpp__slsmg_color_printf, true);		\ +} + +#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)			\ +static u64 __hpp_get_acc_##_field(struct hist_entry *he)		\ +{									\ +	return he->stat_acc->_field;					\ +}									\ +									\ +static int								\ +hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ +				struct perf_hpp *hpp,			\ +				struct hist_entry *he)			\ +{									\ +	if (!symbol_conf.cumulate_callchain) {				\ +		int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A");	\ +		slsmg_printf("%s", hpp->buf);				\ +									\ +		return ret;						\ +	}								\ +	return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%",	\ +			  __hpp__slsmg_color_printf, true);		\  } -__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain) -__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL) -__HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL) -__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL) -__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL) +__HPP_COLOR_PERCENT_FN(overhead, period) +__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) +__HPP_COLOR_PERCENT_FN(overhead_us, period_us) +__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) +__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) +__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)  #undef __HPP_COLOR_PERCENT_FN +#undef __HPP_COLOR_ACC_PERCENT_FN  void hist_browser__init_hpp(void)  { -	perf_hpp__init(); -  	perf_hpp__format[PERF_HPP__OVERHEAD].color =  				hist_browser__hpp_color_overhead;  	perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = @@ -715,6 +694,8 @@ void hist_browser__init_hpp(void)  				hist_browser__hpp_color_overhead_guest_sys;  	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =  				hist_browser__hpp_color_overhead_guest_us; +	perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color = +				hist_browser__hpp_color_overhead_acc;  }  static int hist_browser__show_entry(struct hist_browser *browser, @@ -742,7 +723,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,  	if (row_offset == 0) {  		struct hpp_arg arg = { -			.b 		= &browser->b, +			.b		= &browser->b,  			.folded_sign	= folded_sign,  			.current_entry	= current_entry,  		}; @@ -755,11 +736,27 @@ static int hist_browser__show_entry(struct hist_browser *browser,  		ui_browser__gotorc(&browser->b, row, 0);  		perf_hpp__for_each_format(fmt) { -			if (!first) { +			if (perf_hpp__should_skip(fmt)) +				continue; + +			if (current_entry && browser->b.navkeypressed) { +				ui_browser__set_color(&browser->b, +						      HE_COLORSET_SELECTED); +			} else { +				ui_browser__set_color(&browser->b, +						      HE_COLORSET_NORMAL); +			} + +			if (first) { +				if (symbol_conf.use_callchain) { +					slsmg_printf("%c ", folded_sign); +					width -= 2; +				} +				first = false; +			} else {  				slsmg_printf("  ");  				width -= 2;  			} -			first = false;  			if (fmt->color) {  				width -= fmt->color(fmt, &hpp, entry); @@ -773,8 +770,8 @@ static int hist_browser__show_entry(struct hist_browser *browser,  		if (!browser->b.navkeypressed)  			width += 1; -		hist_entry__sort_snprintf(entry, s, sizeof(s), browser->hists); -		slsmg_write_nstring(s, width); +		slsmg_write_nstring("", width); +  		++row;  		++printed;  	} else @@ -811,12 +808,12 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)  	for (nd = browser->top; nd; nd = rb_next(nd)) {  		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); -		float percent = h->stat.period * 100.0 / -					hb->hists->stats.total_period; +		float percent;  		if (h->filtered)  			continue; +		percent = hist_entry__get_percent_limit(h);  		if (percent < hb->min_pcnt)  			continue; @@ -829,18 +826,13 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)  }  static struct rb_node *hists__filter_entries(struct rb_node *nd, -					     struct hists *hists,  					     float min_pcnt)  {  	while (nd != NULL) {  		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); -		float percent = h->stat.period * 100.0 / -					hists->stats.total_period; - -		if (percent < min_pcnt) -			return NULL; +		float percent = hist_entry__get_percent_limit(h); -		if (!h->filtered) +		if (!h->filtered && percent >= min_pcnt)  			return nd;  		nd = rb_next(nd); @@ -850,13 +842,11 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd,  }  static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, -						  struct hists *hists,  						  float min_pcnt)  {  	while (nd != NULL) {  		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); -		float percent = h->stat.period * 100.0 / -					hists->stats.total_period; +		float percent = hist_entry__get_percent_limit(h);  		if (!h->filtered && percent >= min_pcnt)  			return nd; @@ -885,14 +875,14 @@ static void ui_browser__hists_seek(struct ui_browser *browser,  	switch (whence) {  	case SEEK_SET:  		nd = hists__filter_entries(rb_first(browser->entries), -					   hb->hists, hb->min_pcnt); +					   hb->min_pcnt);  		break;  	case SEEK_CUR:  		nd = browser->top;  		goto do_offset;  	case SEEK_END:  		nd = hists__filter_prev_entries(rb_last(browser->entries), -						hb->hists, hb->min_pcnt); +						hb->min_pcnt);  		first = false;  		break;  	default: @@ -935,8 +925,7 @@ do_offset:  					break;  				}  			} -			nd = hists__filter_entries(rb_next(nd), hb->hists, -						   hb->min_pcnt); +			nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);  			if (nd == NULL)  				break;  			--offset; @@ -969,7 +958,7 @@ do_offset:  				}  			} -			nd = hists__filter_prev_entries(rb_prev(nd), hb->hists, +			nd = hists__filter_prev_entries(rb_prev(nd),  							hb->min_pcnt);  			if (nd == NULL)  				break; @@ -1108,27 +1097,35 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,  				       struct hist_entry *he, FILE *fp)  {  	char s[8192]; -	double percent;  	int printed = 0;  	char folded_sign = ' '; +	struct perf_hpp hpp = { +		.buf = s, +		.size = sizeof(s), +	}; +	struct perf_hpp_fmt *fmt; +	bool first = true; +	int ret;  	if (symbol_conf.use_callchain)  		folded_sign = hist_entry__folded(he); -	hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists); -	percent = (he->stat.period * 100.0) / browser->hists->stats.total_period; -  	if (symbol_conf.use_callchain)  		printed += fprintf(fp, "%c ", folded_sign); -	printed += fprintf(fp, " %5.2f%%", percent); - -	if (symbol_conf.show_nr_samples) -		printed += fprintf(fp, " %11u", he->stat.nr_events); +	perf_hpp__for_each_format(fmt) { +		if (perf_hpp__should_skip(fmt)) +			continue; -	if (symbol_conf.show_total_period) -		printed += fprintf(fp, " %12" PRIu64, he->stat.period); +		if (!first) { +			ret = scnprintf(hpp.buf, hpp.size, "  "); +			advance_hpp(&hpp, ret); +		} else +			first = false; +		ret = fmt->entry(fmt, &hpp, he); +		advance_hpp(&hpp, ret); +	}  	printed += fprintf(fp, "%s\n", rtrim(s));  	if (folded_sign == '-') @@ -1140,7 +1137,6 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,  static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)  {  	struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), -						   browser->hists,  						   browser->min_pcnt);  	int printed = 0; @@ -1148,8 +1144,7 @@ static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)  		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);  		printed += hist_browser__fprintf_entry(browser, h, fp); -		nd = hists__filter_entries(rb_next(nd), browser->hists, -					   browser->min_pcnt); +		nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);  	}  	return printed; @@ -1231,6 +1226,11 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,  	char buf[512];  	size_t buflen = sizeof(buf); +	if (symbol_conf.filter_relative) { +		nr_samples = hists->stats.nr_non_filtered_samples; +		nr_events = hists->stats.total_non_filtered_period; +	} +  	if (perf_evsel__is_group_event(evsel)) {  		struct perf_evsel *pos; @@ -1238,8 +1238,13 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,  		ev_name = buf;  		for_each_group_member(pos, evsel) { -			nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; -			nr_events += pos->hists.stats.total_period; +			if (symbol_conf.filter_relative) { +				nr_samples += pos->hists.stats.nr_non_filtered_samples; +				nr_events += pos->hists.stats.total_non_filtered_period; +			} else { +				nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; +				nr_events += pos->hists.stats.total_period; +			}  		}  	} @@ -1255,7 +1260,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,  	if (thread)  		printed += scnprintf(bf + printed, size - printed,  				    ", Thread: %s(%d)", -				    (thread->comm_set ? thread->comm : ""), +				     (thread->comm_set ? thread__comm_str(thread) : ""),  				    thread->tid);  	if (dso)  		printed += scnprintf(bf + printed, size - printed, @@ -1267,10 +1272,8 @@ static inline void free_popup_options(char **options, int n)  {  	int i; -	for (i = 0; i < n; ++i) { -		free(options[i]); -		options[i] = NULL; -	} +	for (i = 0; i < n; ++i) +		zfree(&options[i]);  }  /* Check whether the browser is for 'top' or 'report' */ @@ -1329,7 +1332,7 @@ static int switch_data_file(void)  			abs_path[nr_options] = strdup(path);  			if (!abs_path[nr_options]) { -				free(options[nr_options]); +				zfree(&options[nr_options]);  				ui__warning("Can't search all data files due to memory shortage.\n");  				fclose(file);  				break; @@ -1368,18 +1371,22 @@ close_file_and_continue:  	return ret;  } -static void hist_browser__update_pcnt_entries(struct hist_browser *hb) +static void hist_browser__update_nr_entries(struct hist_browser *hb)  {  	u64 nr_entries = 0;  	struct rb_node *nd = rb_first(&hb->hists->entries); -	while (nd) { +	if (hb->min_pcnt == 0) { +		hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries; +		return; +	} + +	while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {  		nr_entries++; -		nd = hists__filter_entries(rb_next(nd), hb->hists, -					   hb->min_pcnt); +		nd = rb_next(nd);  	} -	hb->nr_pcnt_entries = nr_entries; +	hb->nr_non_filtered_entries = nr_entries;  }  static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, @@ -1400,12 +1407,43 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,  	char script_opt[64];  	int delay_secs = hbt ? hbt->refresh : 0; +#define HIST_BROWSER_HELP_COMMON					\ +	"h/?/F1        Show this window\n"				\ +	"UP/DOWN/PGUP\n"						\ +	"PGDN/SPACE    Navigate\n"					\ +	"q/ESC/CTRL+C  Exit browser\n\n"				\ +	"For multiple event sessions:\n\n"				\ +	"TAB/UNTAB     Switch events\n\n"				\ +	"For symbolic views (--sort has sym):\n\n"			\ +	"->            Zoom into DSO/Threads & Annotate current symbol\n" \ +	"<-            Zoom out\n"					\ +	"a             Annotate current symbol\n"			\ +	"C             Collapse all callchains\n"			\ +	"d             Zoom into current DSO\n"				\ +	"E             Expand all callchains\n"				\ +	"F             Toggle percentage of filtered entries\n"		\ + +	/* help messages are sorted by lexical order of the hotkey */ +	const char report_help[] = HIST_BROWSER_HELP_COMMON +	"i             Show header information\n" +	"P             Print histograms to perf.hist.N\n" +	"r             Run available scripts\n" +	"s             Switch to another data file in PWD\n" +	"t             Zoom into current Thread\n" +	"V             Verbose (DSO names in callchains, etc)\n" +	"/             Filter symbol by name"; +	const char top_help[] = HIST_BROWSER_HELP_COMMON +	"P             Print histograms to perf.hist.N\n" +	"t             Zoom into current Thread\n" +	"V             Verbose (DSO names in callchains, etc)\n" +	"/             Filter symbol by name"; +  	if (browser == NULL)  		return -1;  	if (min_pcnt) {  		browser->min_pcnt = min_pcnt; -		hist_browser__update_pcnt_entries(browser); +		hist_browser__update_nr_entries(browser);  	}  	fstack = pstack__new(2); @@ -1484,29 +1522,19 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,  			if (is_report_browser(hbt))  				goto do_data_switch;  			continue; +		case 'i': +			/* env->arch is NULL for live-mode (i.e. perf top) */ +			if (env->arch) +				tui__header_window(env); +			continue; +		case 'F': +			symbol_conf.filter_relative ^= 1; +			continue;  		case K_F1:  		case 'h':  		case '?':  			ui_browser__help_window(&browser->b, -					"h/?/F1        Show this window\n" -					"UP/DOWN/PGUP\n" -					"PGDN/SPACE    Navigate\n" -					"q/ESC/CTRL+C  Exit browser\n\n" -					"For multiple event sessions:\n\n" -					"TAB/UNTAB Switch events\n\n" -					"For symbolic views (--sort has sym):\n\n" -					"->            Zoom into DSO/Threads & Annotate current symbol\n" -					"<-            Zoom out\n" -					"a             Annotate current symbol\n" -					"C             Collapse all callchains\n" -					"E             Expand all callchains\n" -					"d             Zoom into current DSO\n" -					"t             Zoom into current Thread\n" -					"r             Run available scripts('perf report' only)\n" -					"s             Switch to another data file in PWD ('perf report' only)\n" -					"P             Print histograms to perf.hist.N\n" -					"V             Verbose (DSO names in callchains, etc)\n" -					"/             Filter symbol by name"); +				is_report_browser(hbt) ? report_help : top_help);  			continue;  		case K_ENTER:  		case K_RIGHT: @@ -1566,19 +1594,24 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,  					 bi->to.sym->name) > 0)  				annotate_t = nr_options++;  		} else { -  			if (browser->selection != NULL &&  			    browser->selection->sym != NULL && -			    !browser->selection->map->dso->annotate_warned && -				asprintf(&options[nr_options], "Annotate %s", -					 browser->selection->sym->name) > 0) -				annotate = nr_options++; +			    !browser->selection->map->dso->annotate_warned) { +				struct annotation *notes; + +				notes = symbol__annotation(browser->selection->sym); + +				if (notes->src && +				    asprintf(&options[nr_options], "Annotate %s", +						 browser->selection->sym->name) > 0) +					annotate = nr_options++; +			}  		}  		if (thread != NULL &&  		    asprintf(&options[nr_options], "Zoom %s %s(%d) thread",  			     (browser->hists->thread_filter ? "out of" : "into"), -			     (thread->comm_set ? thread->comm : ""), +			     (thread->comm_set ? thread__comm_str(thread) : ""),  			     thread->tid) > 0)  			zoom_thread = nr_options++; @@ -1598,7 +1631,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,  			struct symbol *sym;  			if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]", -				browser->he_selection->thread->comm) > 0) +				     thread__comm_str(browser->he_selection->thread)) > 0)  				scripts_comm = nr_options++;  			sym = browser->he_selection->ms.sym; @@ -1629,6 +1662,7 @@ retry_popup_menu:  		if (choice == annotate || choice == annotate_t || choice == annotate_f) {  			struct hist_entry *he; +			struct annotation *notes;  			int err;  do_annotate:  			if (!objdump_path && perf_session_env__lookup_objdump(env)) @@ -1652,6 +1686,10 @@ do_annotate:  				he->ms.map = he->branch_info->to.map;  			} +			notes = symbol__annotation(he->ms.sym); +			if (!notes->src) +				continue; +  			/*  			 * Don't let this be freed, say, by hists__decay_entry.  			 */ @@ -1679,14 +1717,14 @@ zoom_dso:  zoom_out_dso:  				ui_helpline__pop();  				browser->hists->dso_filter = NULL; -				sort_dso.elide = false; +				perf_hpp__set_elide(HISTC_DSO, false);  			} else {  				if (dso == NULL)  					continue;  				ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",  						   dso->kernel ? "the Kernel" : dso->short_name);  				browser->hists->dso_filter = dso; -				sort_dso.elide = true; +				perf_hpp__set_elide(HISTC_DSO, true);  				pstack__push(fstack, &browser->hists->dso_filter);  			}  			hists__filter_by_dso(hists); @@ -1698,13 +1736,13 @@ zoom_thread:  zoom_out_thread:  				ui_helpline__pop();  				browser->hists->thread_filter = NULL; -				sort_thread.elide = false; +				perf_hpp__set_elide(HISTC_THREAD, false);  			} else {  				ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", -						   thread->comm_set ? thread->comm : "", +						   thread->comm_set ? thread__comm_str(thread) : "",  						   thread->tid);  				browser->hists->thread_filter = thread; -				sort_thread.elide = true; +				perf_hpp__set_elide(HISTC_THREAD, false);  				pstack__push(fstack, &browser->hists->thread_filter);  			}  			hists__filter_by_thread(hists); @@ -1717,7 +1755,7 @@ do_scripts:  			memset(script_opt, 0, 64);  			if (choice == scripts_comm) -				sprintf(script_opt, " -c %s ", browser->he_selection->thread->comm); +				sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));  			if (choice == scripts_symbol)  				sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name); @@ -1847,15 +1885,15 @@ browse_hists:  			switch (key) {  			case K_TAB:  				if (pos->node.next == &evlist->entries) -					pos = list_entry(evlist->entries.next, struct perf_evsel, node); +					pos = perf_evlist__first(evlist);  				else -					pos = list_entry(pos->node.next, struct perf_evsel, node); +					pos = perf_evsel__next(pos);  				goto browse_hists;  			case K_UNTAB:  				if (pos->node.prev == &evlist->entries) -					pos = list_entry(evlist->entries.prev, struct perf_evsel, node); +					pos = perf_evlist__last(evlist);  				else -					pos = list_entry(pos->node.prev, struct perf_evsel, node); +					pos = perf_evsel__prev(pos);  				goto browse_hists;  			case K_ESC:  				if (!ui_browser__dialog_yesno(&menu->b, @@ -1889,7 +1927,7 @@ out:  	return key;  } -static bool filter_group_entries(struct ui_browser *self __maybe_unused, +static bool filter_group_entries(struct ui_browser *browser __maybe_unused,  				 void *entry)  {  	struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); @@ -1923,7 +1961,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,  	ui_helpline__push("Press ESC to exit"); -	list_for_each_entry(pos, &evlist->entries, node) { +	evlist__for_each(evlist, pos) {  		const char *ev_name = perf_evsel__name(pos);  		size_t line_len = strlen(ev_name) + 7; @@ -1943,8 +1981,7 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,  single_entry:  	if (nr_entries == 1) { -		struct perf_evsel *first = list_entry(evlist->entries.next, -						      struct perf_evsel, node); +		struct perf_evsel *first = perf_evlist__first(evlist);  		const char *ev_name = perf_evsel__name(first);  		return perf_evsel__hists_browse(first, nr_entries, help, @@ -1956,9 +1993,10 @@ single_entry:  		struct perf_evsel *pos;  		nr_entries = 0; -		list_for_each_entry(pos, &evlist->entries, node) +		evlist__for_each(evlist, pos) {  			if (perf_evsel__is_group_leader(pos))  				nr_entries++; +		}  		if (nr_entries == 1)  			goto single_entry;  | 
