diff options
Diffstat (limited to 'tools/perf/ui')
| -rw-r--r-- | tools/perf/ui/browser.c | 14 | ||||
| -rw-r--r-- | tools/perf/ui/browser.h | 38 | ||||
| -rw-r--r-- | tools/perf/ui/browsers/annotate.c | 24 | ||||
| -rw-r--r-- | tools/perf/ui/browsers/header.c | 127 | ||||
| -rw-r--r-- | tools/perf/ui/browsers/hists.c | 444 | ||||
| -rw-r--r-- | tools/perf/ui/browsers/map.c | 40 | ||||
| -rw-r--r-- | tools/perf/ui/browsers/map.h | 2 | ||||
| -rw-r--r-- | tools/perf/ui/browsers/scripts.c | 11 | ||||
| -rw-r--r-- | tools/perf/ui/gtk/annotate.c | 13 | ||||
| -rw-r--r-- | tools/perf/ui/gtk/browser.c | 2 | ||||
| -rw-r--r-- | tools/perf/ui/gtk/gtk.h | 22 | ||||
| -rw-r--r-- | tools/perf/ui/gtk/hists.c | 155 | ||||
| -rw-r--r-- | tools/perf/ui/gtk/progress.c | 20 | ||||
| -rw-r--r-- | tools/perf/ui/gtk/setup.c | 2 | ||||
| -rw-r--r-- | tools/perf/ui/gtk/util.c | 7 | ||||
| -rw-r--r-- | tools/perf/ui/hist.c | 463 | ||||
| -rw-r--r-- | tools/perf/ui/progress.c | 32 | ||||
| -rw-r--r-- | tools/perf/ui/progress.h | 21 | ||||
| -rw-r--r-- | tools/perf/ui/setup.c | 63 | ||||
| -rw-r--r-- | tools/perf/ui/stdio/hist.c | 121 | ||||
| -rw-r--r-- | tools/perf/ui/tui/progress.c | 18 | ||||
| -rw-r--r-- | tools/perf/ui/tui/setup.c | 3 | ||||
| -rw-r--r-- | tools/perf/ui/tui/tui.h | 6 | ||||
| -rw-r--r-- | tools/perf/ui/tui/util.c | 19 | ||||
| -rw-r--r-- | tools/perf/ui/ui.h | 14 | 
25 files changed, 1103 insertions, 578 deletions
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index bbc782e364b..3ccf6e14f89 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c @@ -194,7 +194,7 @@ int ui_browser__warning(struct ui_browser *browser, int timeout,  		ui_helpline__vpush(format, args);  		va_end(args);  	} else { -		while ((key == ui__question_window("Warning!", text, +		while ((key = ui__question_window("Warning!", text,  						   "Press any key...",  						   timeout)) == K_RESIZE)  			ui_browser__handle_resize(browser); @@ -256,8 +256,7 @@ int ui_browser__show(struct ui_browser *browser, const char *title,  	__ui_browser__show_title(browser, title);  	browser->title = title; -	free(browser->helpline); -	browser->helpline = NULL; +	zfree(&browser->helpline);  	va_start(ap, helpline);  	err = vasprintf(&browser->helpline, helpline, ap); @@ -268,12 +267,11 @@ int ui_browser__show(struct ui_browser *browser, const char *title,  	return err ? 0 : -1;  } -void ui_browser__hide(struct ui_browser *browser __maybe_unused) +void ui_browser__hide(struct ui_browser *browser)  {  	pthread_mutex_lock(&ui__lock);  	ui_helpline__pop(); -	free(browser->helpline); -	browser->helpline = NULL; +	zfree(&browser->helpline);  	pthread_mutex_unlock(&ui__lock);  } @@ -569,7 +567,7 @@ void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)  		browser->top = browser->top + browser->top_idx + offset;  		break;  	case SEEK_END: -		browser->top = browser->top + browser->nr_entries + offset; +		browser->top = browser->top + browser->nr_entries - 1 + offset;  		break;  	default:  		return; @@ -680,7 +678,7 @@ static void __ui_browser__line_arrow_down(struct ui_browser *browser,  	if (end >= browser->top_idx + browser->height)  		end_row = browser->height - 1;  	else -		end_row = end - browser->top_idx;; +		end_row = end - browser->top_idx;  	ui_browser__gotorc(browser, row, column);  	SLsmg_draw_vline(end_row - row + 1); diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h index 404ff66a3e3..03d4d6295f1 100644 --- a/tools/perf/ui/browser.h +++ b/tools/perf/ui/browser.h @@ -1,9 +1,7 @@  #ifndef _PERF_UI_BROWSER_H_  #define _PERF_UI_BROWSER_H_ 1 -#include <stdbool.h> -#include <sys/types.h> -#include "../types.h" +#include <linux/types.h>  #define HE_COLORSET_TOP		50  #define HE_COLORSET_MEDIUM	51 @@ -21,32 +19,32 @@ struct ui_browser {  	void	      *priv;  	const char    *title;  	char	      *helpline; -	unsigned int  (*refresh)(struct ui_browser *self); -	void	      (*write)(struct ui_browser *self, void *entry, int row); -	void	      (*seek)(struct ui_browser *self, off_t offset, int whence); -	bool	      (*filter)(struct ui_browser *self, void *entry); +	unsigned int  (*refresh)(struct ui_browser *browser); +	void	      (*write)(struct ui_browser *browser, void *entry, int row); +	void	      (*seek)(struct ui_browser *browser, off_t offset, int whence); +	bool	      (*filter)(struct ui_browser *browser, void *entry);  	u32	      nr_entries;  	bool	      navkeypressed;  	bool	      use_navkeypressed;  };  int  ui_browser__set_color(struct ui_browser *browser, int color); -void ui_browser__set_percent_color(struct ui_browser *self, +void ui_browser__set_percent_color(struct ui_browser *browser,  				   double percent, bool current); -bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row); -void ui_browser__refresh_dimensions(struct ui_browser *self); -void ui_browser__reset_index(struct ui_browser *self); +bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row); +void ui_browser__refresh_dimensions(struct ui_browser *browser); +void ui_browser__reset_index(struct ui_browser *browser); -void ui_browser__gotorc(struct ui_browser *self, int y, int x); +void ui_browser__gotorc(struct ui_browser *browser, int y, int x);  void ui_browser__write_graph(struct ui_browser *browser, int graph);  void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,  			      u64 start, u64 end);  void __ui_browser__show_title(struct ui_browser *browser, const char *title);  void ui_browser__show_title(struct ui_browser *browser, const char *title); -int ui_browser__show(struct ui_browser *self, const char *title, +int ui_browser__show(struct ui_browser *browser, const char *title,  		     const char *helpline, ...); -void ui_browser__hide(struct ui_browser *self); -int ui_browser__refresh(struct ui_browser *self); +void ui_browser__hide(struct ui_browser *browser); +int ui_browser__refresh(struct ui_browser *browser);  int ui_browser__run(struct ui_browser *browser, int delay_secs);  void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);  void ui_browser__handle_resize(struct ui_browser *browser); @@ -59,15 +57,17 @@ int ui_browser__help_window(struct ui_browser *browser, const char *text);  bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);  int ui_browser__input_window(const char *title, const char *text, char *input,  			     const char *exit_msg, int delay_sec); +struct perf_session_env; +int tui__header_window(struct perf_session_env *env);  void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);  unsigned int ui_browser__argv_refresh(struct ui_browser *browser); -void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); -unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); +void ui_browser__rb_tree_seek(struct ui_browser *browser, off_t offset, int whence); +unsigned int ui_browser__rb_tree_refresh(struct ui_browser *browser); -void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence); -unsigned int ui_browser__list_head_refresh(struct ui_browser *self); +void ui_browser__list_head_seek(struct ui_browser *browser, off_t offset, int whence); +unsigned int ui_browser__list_head_refresh(struct ui_browser *browser);  void ui_browser__init(void);  void annotate_browser__init(void); diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 08545ae4699..f0697a3aede 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -442,35 +442,37 @@ static bool annotate_browser__callq(struct annotate_browser *browser,  {  	struct map_symbol *ms = browser->b.priv;  	struct disasm_line *dl = browser->selection; -	struct symbol *sym = ms->sym;  	struct annotation *notes; -	struct symbol *target; -	u64 ip; +	struct addr_map_symbol target = { +		.map = ms->map, +		.addr = map__objdump_2mem(ms->map, dl->ops.target.addr), +	};  	char title[SYM_TITLE_MAX_SIZE];  	if (!ins__is_call(dl->ins))  		return false; -	ip = ms->map->map_ip(ms->map, dl->ops.target.addr); -	target = map__find_symbol(ms->map, ip, NULL); -	if (target == NULL) { +	if (map_groups__find_ams(&target, NULL) || +	    map__rip_2objdump(target.map, target.map->map_ip(target.map, +							     target.addr)) != +	    dl->ops.target.addr) {  		ui_helpline__puts("The called function was not found.");  		return true;  	} -	notes = symbol__annotation(target); +	notes = symbol__annotation(target.sym);  	pthread_mutex_lock(¬es->lock); -	if (notes->src == NULL && symbol__alloc_hist(target) < 0) { +	if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {  		pthread_mutex_unlock(¬es->lock);  		ui__warning("Not enough memory for annotating '%s' symbol!\n", -			    target->name); +			    target.sym->name);  		return true;  	}  	pthread_mutex_unlock(¬es->lock); -	symbol__tui_annotate(target, ms->map, evsel, hbt); -	sym_title(sym, ms->map, title, sizeof(title)); +	symbol__tui_annotate(target.sym, target.map, evsel, hbt); +	sym_title(ms->sym, ms->map, title, sizeof(title));  	ui_browser__show_title(&browser->b, title);  	return true;  } diff --git a/tools/perf/ui/browsers/header.c b/tools/perf/ui/browsers/header.c new file mode 100644 index 00000000000..89c16b98861 --- /dev/null +++ b/tools/perf/ui/browsers/header.c @@ -0,0 +1,127 @@ +#include "util/cache.h" +#include "util/debug.h" +#include "ui/browser.h" +#include "ui/ui.h" +#include "ui/util.h" +#include "ui/libslang.h" +#include "util/header.h" +#include "util/session.h" + +static void ui_browser__argv_write(struct ui_browser *browser, +				   void *entry, int row) +{ +	char **arg = entry; +	char *str = *arg; +	char empty[] = " "; +	bool current_entry = ui_browser__is_current_entry(browser, row); +	unsigned long offset = (unsigned long)browser->priv; + +	if (offset >= strlen(str)) +		str = empty; +	else +		str = str + offset; + +	ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : +						       HE_COLORSET_NORMAL); + +	slsmg_write_nstring(str, browser->width); +} + +static int list_menu__run(struct ui_browser *menu) +{ +	int key; +	unsigned long offset; +	const char help[] = +	"h/?/F1        Show this window\n" +	"UP/DOWN/PGUP\n" +	"PGDN/SPACE\n" +	"LEFT/RIGHT    Navigate\n" +	"q/ESC/CTRL+C  Exit browser"; + +	if (ui_browser__show(menu, "Header information", "Press 'q' to exit") < 0) +		return -1; + +	while (1) { +		key = ui_browser__run(menu, 0); + +		switch (key) { +		case K_RIGHT: +			offset = (unsigned long)menu->priv; +			offset += 10; +			menu->priv = (void *)offset; +			continue; +		case K_LEFT: +			offset = (unsigned long)menu->priv; +			if (offset >= 10) +				offset -= 10; +			menu->priv = (void *)offset; +			continue; +		case K_F1: +		case 'h': +		case '?': +			ui_browser__help_window(menu, help); +			continue; +		case K_ESC: +		case 'q': +		case CTRL('c'): +			key = -1; +			break; +		default: +			continue; +		} + +		break; +	} + +	ui_browser__hide(menu); +	return key; +} + +static int ui__list_menu(int argc, char * const argv[]) +{ +	struct ui_browser menu = { +		.entries    = (void *)argv, +		.refresh    = ui_browser__argv_refresh, +		.seek	    = ui_browser__argv_seek, +		.write	    = ui_browser__argv_write, +		.nr_entries = argc, +	}; + +	return list_menu__run(&menu); +} + +int tui__header_window(struct perf_session_env *env) +{ +	int i, argc = 0; +	char **argv; +	struct perf_session *session; +	char *ptr, *pos; +	size_t size; +	FILE *fp = open_memstream(&ptr, &size); + +	session = container_of(env, struct perf_session, header.env); +	perf_header__fprintf_info(session, fp, true); +	fclose(fp); + +	for (pos = ptr, argc = 0; (pos = strchr(pos, '\n')) != NULL; pos++) +		argc++; + +	argv = calloc(argc + 1, sizeof(*argv)); +	if (argv == NULL) +		goto out; + +	argv[0] = pos = ptr; +	for (i = 1; (pos = strchr(pos, '\n')) != NULL; i++) { +		*pos++ = '\0'; +		argv[i] = pos; +	} + +	BUG_ON(i != argc + 1); + +	ui__list_menu(argc, argv); + +out: +	free(argv); +	free(ptr); +	return 0; +} 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; diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c index 95c7cfb8f2c..b11639f3368 100644 --- a/tools/perf/ui/browsers/map.c +++ b/tools/perf/ui/browsers/map.c @@ -18,30 +18,30 @@ struct map_browser {  	u8		  addrlen;  }; -static void map_browser__write(struct ui_browser *self, void *nd, int row) +static void map_browser__write(struct ui_browser *browser, void *nd, int row)  {  	struct symbol *sym = rb_entry(nd, struct symbol, rb_node); -	struct map_browser *mb = container_of(self, struct map_browser, b); -	bool current_entry = ui_browser__is_current_entry(self, row); +	struct map_browser *mb = container_of(browser, struct map_browser, b); +	bool current_entry = ui_browser__is_current_entry(browser, row);  	int width; -	ui_browser__set_percent_color(self, 0, current_entry); +	ui_browser__set_percent_color(browser, 0, current_entry);  	slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",  		     mb->addrlen, sym->start, mb->addrlen, sym->end,  		     sym->binding == STB_GLOBAL ? 'g' :  		     sym->binding == STB_LOCAL  ? 'l' : 'w'); -	width = self->width - ((mb->addrlen * 2) + 4); +	width = browser->width - ((mb->addrlen * 2) + 4);  	if (width > 0)  		slsmg_write_nstring(sym->name, width);  }  /* FIXME uber-kludgy, see comment on cmd_report... */ -static u32 *symbol__browser_index(struct symbol *self) +static u32 *symbol__browser_index(struct symbol *browser)  { -	return ((void *)self) - sizeof(struct rb_node) - sizeof(u32); +	return ((void *)browser) - sizeof(struct rb_node) - sizeof(u32);  } -static int map_browser__search(struct map_browser *self) +static int map_browser__search(struct map_browser *browser)  {  	char target[512];  	struct symbol *sym; @@ -53,37 +53,37 @@ static int map_browser__search(struct map_browser *self)  	if (target[0] == '0' && tolower(target[1]) == 'x') {  		u64 addr = strtoull(target, NULL, 16); -		sym = map__find_symbol(self->map, addr, NULL); +		sym = map__find_symbol(browser->map, addr, NULL);  	} else -		sym = map__find_symbol_by_name(self->map, target, NULL); +		sym = map__find_symbol_by_name(browser->map, target, NULL);  	if (sym != NULL) {  		u32 *idx = symbol__browser_index(sym); -		self->b.top = &sym->rb_node; -		self->b.index = self->b.top_idx = *idx; +		browser->b.top = &sym->rb_node; +		browser->b.index = browser->b.top_idx = *idx;  	} else  		ui_helpline__fpush("%s not found!", target);  	return 0;  } -static int map_browser__run(struct map_browser *self) +static int map_browser__run(struct map_browser *browser)  {  	int key; -	if (ui_browser__show(&self->b, self->map->dso->long_name, +	if (ui_browser__show(&browser->b, browser->map->dso->long_name,  			     "Press <- or ESC to exit, %s / to search",  			     verbose ? "" : "restart with -v to use") < 0)  		return -1;  	while (1) { -		key = ui_browser__run(&self->b, 0); +		key = ui_browser__run(&browser->b, 0);  		switch (key) {  		case '/':  			if (verbose) -				map_browser__search(self); +				map_browser__search(browser);  		default:  			break;                  case K_LEFT: @@ -94,20 +94,20 @@ static int map_browser__run(struct map_browser *self)  		}  	}  out: -	ui_browser__hide(&self->b); +	ui_browser__hide(&browser->b);  	return key;  } -int map__browse(struct map *self) +int map__browse(struct map *map)  {  	struct map_browser mb = {  		.b = { -			.entries = &self->dso->symbols[self->type], +			.entries = &map->dso->symbols[map->type],  			.refresh = ui_browser__rb_tree_refresh,  			.seek	 = ui_browser__rb_tree_seek,  			.write	 = map_browser__write,  		}, -		.map = self, +		.map = map,  	};  	struct rb_node *nd;  	char tmp[BITS_PER_LONG / 4]; diff --git a/tools/perf/ui/browsers/map.h b/tools/perf/ui/browsers/map.h index df8581a43e1..2d58e4b3eb6 100644 --- a/tools/perf/ui/browsers/map.h +++ b/tools/perf/ui/browsers/map.h @@ -2,5 +2,5 @@  #define _PERF_UI_MAP_BROWSER_H_ 1  struct map; -int map__browse(struct map *self); +int map__browse(struct map *map);  #endif /* _PERF_UI_MAP_BROWSER_H_ */ diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c index 12f009e61e9..402d2bd30b0 100644 --- a/tools/perf/ui/browsers/scripts.c +++ b/tools/perf/ui/browsers/scripts.c @@ -84,22 +84,22 @@ static void script_browser__write(struct ui_browser *browser,  	slsmg_write_nstring(sline->line, browser->width);  } -static int script_browser__run(struct perf_script_browser *self) +static int script_browser__run(struct perf_script_browser *browser)  {  	int key; -	if (ui_browser__show(&self->b, self->script_name, +	if (ui_browser__show(&browser->b, browser->script_name,  			     "Press <- or ESC to exit") < 0)  		return -1;  	while (1) { -		key = ui_browser__run(&self->b, 0); +		key = ui_browser__run(&browser->b, 0);  		/* We can add some special key handling here if needed */  		break;  	} -	ui_browser__hide(&self->b); +	ui_browser__hide(&browser->b);  	return key;  } @@ -173,8 +173,7 @@ int script_browse(const char *script_opt)  	if (script.b.width > AVERAGE_LINE_LEN)  		script.b.width = AVERAGE_LINE_LEN; -	if (line) -		free(line); +	free(line);  	pclose(fp);  	script.nr_lines = nr_entries; diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index f538794615d..9c7ff8d31b2 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -154,9 +154,9 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,  	return 0;  } -int symbol__gtk_annotate(struct symbol *sym, struct map *map, -			 struct perf_evsel *evsel, -			 struct hist_browser_timer *hbt) +static int symbol__gtk_annotate(struct symbol *sym, struct map *map, +				struct perf_evsel *evsel, +				struct hist_browser_timer *hbt)  {  	GtkWidget *window;  	GtkWidget *notebook; @@ -226,6 +226,13 @@ int symbol__gtk_annotate(struct symbol *sym, struct map *map,  	return 0;  } +int hist_entry__gtk_annotate(struct hist_entry *he, +			     struct perf_evsel *evsel, +			     struct hist_browser_timer *hbt) +{ +	return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt); +} +  void perf_gtk__show_annotations(void)  {  	GtkWidget *window; diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c index c95012cdb43..c24d9122129 100644 --- a/tools/perf/ui/gtk/browser.c +++ b/tools/perf/ui/gtk/browser.c @@ -43,7 +43,7 @@ const char *perf_gtk__get_percent_color(double percent)  	return NULL;  } -#ifdef HAVE_GTK_INFO_BAR +#ifdef HAVE_GTK_INFO_BAR_SUPPORT  GtkWidget *perf_gtk__setup_info_bar(void)  {  	GtkWidget *info_bar; diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h index 3d96785ef15..0a9173ff9a6 100644 --- a/tools/perf/ui/gtk/gtk.h +++ b/tools/perf/ui/gtk/gtk.h @@ -12,7 +12,7 @@ struct perf_gtk_context {  	GtkWidget *main_window;  	GtkWidget *notebook; -#ifdef HAVE_GTK_INFO_BAR +#ifdef HAVE_GTK_INFO_BAR_SUPPORT  	GtkWidget *info_bar;  	GtkWidget *message_label;  #endif @@ -20,6 +20,9 @@ struct perf_gtk_context {  	guint statbar_ctx_id;  }; +int perf_gtk__init(void); +void perf_gtk__exit(bool wait_for_ok); +  extern struct perf_gtk_context *pgctx;  static inline bool perf_gtk__is_active_context(struct perf_gtk_context *ctx) @@ -31,7 +34,7 @@ struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window);  int perf_gtk__deactivate_context(struct perf_gtk_context **ctx);  void perf_gtk__init_helpline(void); -void perf_gtk__init_progress(void); +void gtk_ui_progress__init(void);  void perf_gtk__init_hpp(void);  void perf_gtk__signal(int sig); @@ -39,7 +42,7 @@ void perf_gtk__resize_window(GtkWidget *window);  const char *perf_gtk__get_percent_color(double percent);  GtkWidget *perf_gtk__setup_statusbar(void); -#ifdef HAVE_GTK_INFO_BAR +#ifdef HAVE_GTK_INFO_BAR_SUPPORT  GtkWidget *perf_gtk__setup_info_bar(void);  #else  static inline GtkWidget *perf_gtk__setup_info_bar(void) @@ -48,4 +51,17 @@ static inline GtkWidget *perf_gtk__setup_info_bar(void)  }  #endif +struct perf_evsel; +struct perf_evlist; +struct hist_entry; +struct hist_browser_timer; + +int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, +				  struct hist_browser_timer *hbt, +				  float min_pcnt); +int hist_entry__gtk_annotate(struct hist_entry *he, +			     struct perf_evsel *evsel, +			     struct hist_browser_timer *hbt); +void perf_gtk__show_annotations(void); +  #endif /* _PERF_GTK_H_ */ diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 2ca66cc1160..6ca60e482cd 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -8,16 +8,24 @@  #define MAX_COLUMNS			32 -static int __percent_color_snprintf(char *buf, size_t size, double percent) +static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)  {  	int ret = 0; +	va_list args; +	double percent;  	const char *markup; +	char *buf = hpp->buf; +	size_t size = hpp->size; + +	va_start(args, fmt); +	percent = va_arg(args, double); +	va_end(args);  	markup = perf_gtk__get_percent_color(percent);  	if (markup)  		ret += scnprintf(buf, size, markup); -	ret += scnprintf(buf + ret, size - ret, " %6.2f%%", percent); +	ret += scnprintf(buf + ret, size - ret, fmt, percent);  	if (markup)  		ret += scnprintf(buf + ret, size - ret, "</span>"); @@ -25,66 +33,6 @@ static int __percent_color_snprintf(char *buf, size_t size, double percent)  	return ret;  } - -static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he, -			    u64 (*get_field)(struct hist_entry *)) -{ -	int ret; -	double percent = 0.0; -	struct hists *hists = he->hists; -	struct perf_evsel *evsel = hists_to_evsel(hists); - -	if (hists->stats.total_period) -		percent = 100.0 * get_field(he) / hists->stats.total_period; - -	ret = __percent_color_snprintf(hpp->buf, hpp->size, percent); - -	if (perf_evsel__is_group_event(evsel)) { -		int prev_idx, idx_delta; -		struct hist_entry *pair; -		int nr_members = evsel->nr_members; - -		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; - -			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 -				 */ -				ret += __percent_color_snprintf(hpp->buf + ret, -								hpp->size - ret, -								0.0); -			} - -			percent = 100.0 * period / total; -			ret += __percent_color_snprintf(hpp->buf + ret, -							hpp->size - ret, -							percent); - -			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 -			 */ -			ret += __percent_color_snprintf(hpp->buf + ret, -							hpp->size - ret, -							0.0); -		} -	} -	return ret; -} -  #define __HPP_COLOR_PERCENT_FN(_type, _field)					\  static u64 he_get_##_field(struct hist_entry *he)				\  {										\ @@ -95,7 +43,22 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,  				       struct perf_hpp *hpp,			\  				       struct hist_entry *he)			\  {										\ -	return __hpp__color_fmt(hpp, he, he_get_##_field);			\ +	return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%",			\ +			  __percent_color_snprintf, true);			\ +} + +#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)				\ +static u64 he_get_acc_##_field(struct hist_entry *he)				\ +{										\ +	return he->stat_acc->_field;						\ +}										\ +										\ +static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,	\ +				       struct perf_hpp *hpp,			\ +				       struct hist_entry *he)			\ +{										\ +	return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%",		\ +			      __percent_color_snprintf, true);			\  }  __HPP_COLOR_PERCENT_FN(overhead, period) @@ -103,14 +66,13 @@ __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  void perf_gtk__init_hpp(void)  { -	perf_hpp__init(); -  	perf_hpp__format[PERF_HPP__OVERHEAD].color =  				perf_gtk__hpp_color_overhead;  	perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = @@ -121,6 +83,8 @@ void perf_gtk__init_hpp(void)  				perf_gtk__hpp_color_overhead_guest_sys;  	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =  				perf_gtk__hpp_color_overhead_guest_us; +	perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color = +				perf_gtk__hpp_color_overhead_acc;  }  static void callchain_list__sym_name(struct callchain_list *cl, @@ -204,7 +168,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,  	struct perf_hpp_fmt *fmt;  	GType col_types[MAX_COLUMNS];  	GtkCellRenderer *renderer; -	struct sort_entry *se;  	GtkTreeStore *store;  	struct rb_node *nd;  	GtkWidget *view; @@ -216,7 +179,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,  	struct perf_hpp hpp = {  		.buf		= s,  		.size		= sizeof(s), -		.ptr		= hists_to_evsel(hists),  	};  	nr_cols = 0; @@ -224,16 +186,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,  	perf_hpp__for_each_format(fmt)  		col_types[nr_cols++] = G_TYPE_STRING; -	list_for_each_entry(se, &hist_entry__sort_list, list) { -		if (se->elide) -			continue; - -		if (se == &sort_sym) -			sym_col = nr_cols; - -		col_types[nr_cols++] = G_TYPE_STRING; -	} -  	store = gtk_tree_store_newv(nr_cols, col_types);  	view = gtk_tree_view_new(); @@ -243,21 +195,21 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,  	col_idx = 0;  	perf_hpp__for_each_format(fmt) { -		fmt->header(fmt, &hpp); +		if (perf_hpp__should_skip(fmt)) +			continue; -		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -							    -1, ltrim(s), -							    renderer, "markup", -							    col_idx++, NULL); -	} +		/* +		 * XXX no way to determine where symcol column is.. +		 *     Just use last column for now. +		 */ +		if (perf_hpp__is_sort_entry(fmt)) +			sym_col = col_idx; -	list_for_each_entry(se, &hist_entry__sort_list, list) { -		if (se->elide) -			continue; +		fmt->header(fmt, &hpp, hists_to_evsel(hists));  		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -							    -1, se->se_header, -							    renderer, "text", +							    -1, ltrim(s), +							    renderer, "markup",  							    col_idx++, NULL);  	} @@ -280,12 +232,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,  	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {  		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);  		GtkTreeIter iter; -		float percent = h->stat.period * 100.0 / -					hists->stats.total_period; +		u64 total = hists__total_period(h->hists); +		float percent;  		if (h->filtered)  			continue; +		percent = hist_entry__get_percent_limit(h);  		if (percent < min_pcnt)  			continue; @@ -294,6 +247,9 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,  		col_idx = 0;  		perf_hpp__for_each_format(fmt) { +			if (perf_hpp__should_skip(fmt)) +				continue; +  			if (fmt->color)  				fmt->color(fmt, &hpp, h);  			else @@ -302,23 +258,10 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,  			gtk_tree_store_set(store, &iter, col_idx++, s, -1);  		} -		list_for_each_entry(se, &hist_entry__sort_list, list) { -			if (se->elide) -				continue; - -			se->se_snprintf(h, s, ARRAY_SIZE(s), -					hists__col_len(hists, se->se_width_idx)); - -			gtk_tree_store_set(store, &iter, col_idx++, s, -1); -		} -  		if (symbol_conf.use_callchain && sort__has_sym) { -			u64 total; -  			if (callchain_param.mode == CHAIN_GRAPH_REL) -				total = h->stat.period; -			else -				total = hists->stats.total_period; +				total = symbol_conf.cumulate_callchain ? +					h->stat_acc->period : h->stat.period;  			perf_gtk__add_callchain(&h->sorted_chain, store, &iter,  						sym_col, total); @@ -375,7 +318,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,  	gtk_container_add(GTK_CONTAINER(window), vbox); -	list_for_each_entry(pos, &evlist->entries, node) { +	evlist__for_each(evlist, pos) {  		struct hists *hists = &pos->hists;  		const char *evname = perf_evsel__name(pos);  		GtkWidget *scrolled_window; diff --git a/tools/perf/ui/gtk/progress.c b/tools/perf/ui/gtk/progress.c index 482bcf3df9b..b656655fbc3 100644 --- a/tools/perf/ui/gtk/progress.c +++ b/tools/perf/ui/gtk/progress.c @@ -7,14 +7,14 @@  static GtkWidget *dialog;  static GtkWidget *progress; -static void gtk_progress_update(u64 curr, u64 total, const char *title) +static void gtk_ui_progress__update(struct ui_progress *p)  { -	double fraction = total ? 1.0 * curr / total : 0.0; +	double fraction = p->total ? 1.0 * p->curr / p->total : 0.0;  	char buf[1024];  	if (dialog == NULL) {  		GtkWidget *vbox = gtk_vbox_new(TRUE, 5); -		GtkWidget *label = gtk_label_new(title); +		GtkWidget *label = gtk_label_new(p->title);  		dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);  		progress = gtk_progress_bar_new(); @@ -32,7 +32,7 @@ static void gtk_progress_update(u64 curr, u64 total, const char *title)  	}  	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), fraction); -	snprintf(buf, sizeof(buf), "%"PRIu64" / %"PRIu64, curr, total); +	snprintf(buf, sizeof(buf), "%"PRIu64" / %"PRIu64, p->curr, p->total);  	gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), buf);  	/* we didn't call gtk_main yet, so do it manually */ @@ -40,7 +40,7 @@ static void gtk_progress_update(u64 curr, u64 total, const char *title)  		gtk_main_iteration();  } -static void gtk_progress_finish(void) +static void gtk_ui_progress__finish(void)  {  	/* this will also destroy all of its children */  	gtk_widget_destroy(dialog); @@ -48,12 +48,12 @@ static void gtk_progress_finish(void)  	dialog = NULL;  } -static struct ui_progress gtk_progress_fns = { -	.update		= gtk_progress_update, -	.finish		= gtk_progress_finish, +static struct ui_progress_ops gtk_ui_progress__ops = { +	.update		= gtk_ui_progress__update, +	.finish		= gtk_ui_progress__finish,  }; -void perf_gtk__init_progress(void) +void gtk_ui_progress__init(void)  { -	progress_fns = >k_progress_fns; +	ui_progress__ops = >k_ui_progress__ops;  } diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c index 6c2dd2e423f..1d57676f821 100644 --- a/tools/perf/ui/gtk/setup.c +++ b/tools/perf/ui/gtk/setup.c @@ -8,7 +8,7 @@ int perf_gtk__init(void)  {  	perf_error__register(&perf_gtk_eops);  	perf_gtk__init_helpline(); -	perf_gtk__init_progress(); +	gtk_ui_progress__init();  	perf_gtk__init_hpp();  	return gtk_init_check(NULL, NULL) ? 0 : -1; diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c index c06942a41c7..52e7fc48af9 100644 --- a/tools/perf/ui/gtk/util.c +++ b/tools/perf/ui/gtk/util.c @@ -23,8 +23,7 @@ int perf_gtk__deactivate_context(struct perf_gtk_context **ctx)  	if (!perf_gtk__is_active_context(*ctx))  		return -1; -	free(*ctx); -	*ctx = NULL; +	zfree(ctx);  	return 0;  } @@ -53,7 +52,7 @@ static int perf_gtk__error(const char *format, va_list args)  	return 0;  } -#ifdef HAVE_GTK_INFO_BAR +#ifdef HAVE_GTK_INFO_BAR_SUPPORT  static int perf_gtk__warning_info_bar(const char *format, va_list args)  {  	char *msg; @@ -105,7 +104,7 @@ static int perf_gtk__warning_statusbar(const char *format, va_list args)  struct perf_error_ops perf_gtk_eops = {  	.error		= perf_gtk__error, -#ifdef HAVE_GTK_INFO_BAR +#ifdef HAVE_GTK_INFO_BAR_SUPPORT  	.warning	= perf_gtk__warning_info_bar,  #else  	.warning	= perf_gtk__warning_statusbar, diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 0a193281eba..498adb23c02 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -8,27 +8,33 @@  /* hist period print (hpp) functions */ -typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...); - -static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, -		      u64 (*get_field)(struct hist_entry *), -		      const char *fmt, hpp_snprint_fn print_fn, -		      bool fmt_percent) +#define hpp__call_print_fn(hpp, fn, fmt, ...)			\ +({								\ +	int __ret = fn(hpp, fmt, ##__VA_ARGS__);		\ +	advance_hpp(hpp, __ret);				\ +	__ret;							\ +}) + +int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, +	       hpp_field_fn get_field, const char *fmt, +	       hpp_snprint_fn print_fn, bool fmt_percent)  {  	int ret;  	struct hists *hists = he->hists;  	struct perf_evsel *evsel = hists_to_evsel(hists); +	char *buf = hpp->buf; +	size_t size = hpp->size;  	if (fmt_percent) {  		double percent = 0.0; +		u64 total = hists__total_period(hists); -		if (hists->stats.total_period) -			percent = 100.0 * get_field(he) / -				  hists->stats.total_period; +		if (total) +			percent = 100.0 * get_field(he) / total; -		ret = print_fn(hpp->buf, hpp->size, fmt, percent); +		ret = hpp__call_print_fn(hpp, print_fn, fmt, percent);  	} else -		ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he)); +		ret = hpp__call_print_fn(hpp, print_fn, fmt, get_field(he));  	if (perf_evsel__is_group_event(evsel)) {  		int prev_idx, idx_delta; @@ -39,7 +45,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,  		list_for_each_entry(pair, &he->pairs.head, pairs.node) {  			u64 period = get_field(pair); -			u64 total = pair->hists->stats.total_period; +			u64 total = hists__total_period(pair->hists);  			if (!total)  				continue; @@ -52,16 +58,22 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,  				 * zero-fill group members in the middle which  				 * have no sample  				 */ -				ret += print_fn(hpp->buf + ret, hpp->size - ret, -						fmt, 0); +				if (fmt_percent) { +					ret += hpp__call_print_fn(hpp, print_fn, +								  fmt, 0.0); +				} else { +					ret += hpp__call_print_fn(hpp, print_fn, +								  fmt, 0ULL); +				}  			} -			if (fmt_percent) -				ret += print_fn(hpp->buf + ret, hpp->size - ret, -						fmt, 100.0 * period / total); -			else -				ret += print_fn(hpp->buf + ret, hpp->size - ret, -						fmt, period); +			if (fmt_percent) { +				ret += hpp__call_print_fn(hpp, print_fn, fmt, +							  100.0 * period / total); +			} else { +				ret += hpp__call_print_fn(hpp, print_fn, fmt, +							  period); +			}  			prev_idx = perf_evsel__group_idx(evsel);  		} @@ -72,41 +84,166 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,  			/*  			 * zero-fill group members at last which have no sample  			 */ -			ret += print_fn(hpp->buf + ret, hpp->size - ret, -					fmt, 0); +			if (fmt_percent) { +				ret += hpp__call_print_fn(hpp, print_fn, +							  fmt, 0.0); +			} else { +				ret += hpp__call_print_fn(hpp, print_fn, +							  fmt, 0ULL); +			}  		}  	} + +	/* +	 * Restore original buf and size as it's where caller expects +	 * the result will be saved. +	 */ +	hpp->buf = buf; +	hpp->size = size; + +	return ret; +} + +int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he, +		   hpp_field_fn get_field, const char *fmt, +		   hpp_snprint_fn print_fn, bool fmt_percent) +{ +	if (!symbol_conf.cumulate_callchain) { +		return snprintf(hpp->buf, hpp->size, "%*s", +				fmt_percent ? 8 : 12, "N/A"); +	} + +	return __hpp__fmt(hpp, he, get_field, fmt, print_fn, fmt_percent); +} + +static int field_cmp(u64 field_a, u64 field_b) +{ +	if (field_a > field_b) +		return 1; +	if (field_a < field_b) +		return -1; +	return 0; +} + +static int __hpp__sort(struct hist_entry *a, struct hist_entry *b, +		       hpp_field_fn get_field) +{ +	s64 ret; +	int i, nr_members; +	struct perf_evsel *evsel; +	struct hist_entry *pair; +	u64 *fields_a, *fields_b; + +	ret = field_cmp(get_field(a), get_field(b)); +	if (ret || !symbol_conf.event_group) +		return ret; + +	evsel = hists_to_evsel(a->hists); +	if (!perf_evsel__is_group_event(evsel)) +		return ret; + +	nr_members = evsel->nr_members; +	fields_a = calloc(sizeof(*fields_a), nr_members); +	fields_b = calloc(sizeof(*fields_b), nr_members); + +	if (!fields_a || !fields_b) +		goto out; + +	list_for_each_entry(pair, &a->pairs.head, pairs.node) { +		evsel = hists_to_evsel(pair->hists); +		fields_a[perf_evsel__group_idx(evsel)] = get_field(pair); +	} + +	list_for_each_entry(pair, &b->pairs.head, pairs.node) { +		evsel = hists_to_evsel(pair->hists); +		fields_b[perf_evsel__group_idx(evsel)] = get_field(pair); +	} + +	for (i = 1; i < nr_members; i++) { +		ret = field_cmp(fields_a[i], fields_b[i]); +		if (ret) +			break; +	} + +out: +	free(fields_a); +	free(fields_b); + +	return ret; +} + +static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b, +			   hpp_field_fn get_field) +{ +	s64 ret = 0; + +	if (symbol_conf.cumulate_callchain) { +		/* +		 * Put caller above callee when they have equal period. +		 */ +		ret = field_cmp(get_field(a), get_field(b)); +		if (ret) +			return ret; + +		ret = b->callchain->max_depth - a->callchain->max_depth; +	}  	return ret;  }  #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) 		\  static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused,	\ -			       struct perf_hpp *hpp)			\ +			       struct perf_hpp *hpp,			\ +			       struct perf_evsel *evsel)		\  {									\  	int len = _min_width;						\  									\ -	if (symbol_conf.event_group) {					\ -		struct perf_evsel *evsel = hpp->ptr;			\ -									\ +	if (symbol_conf.event_group)					\  		len = max(len, evsel->nr_members * _unit_width);	\ -	}								\ +									\  	return scnprintf(hpp->buf, hpp->size, "%*s", len, _str);	\  }  #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) 			\  static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused,	\ -			      struct perf_hpp *hpp __maybe_unused)	\ +			      struct perf_hpp *hpp __maybe_unused,	\ +			      struct perf_evsel *evsel)			\  {									\  	int len = _min_width;						\  									\ -	if (symbol_conf.event_group) {					\ -		struct perf_evsel *evsel = hpp->ptr;			\ -									\ +	if (symbol_conf.event_group)					\  		len = max(len, evsel->nr_members * _unit_width);	\ -	}								\ +									\  	return len;							\  } +static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) +{ +	va_list args; +	ssize_t ssize = hpp->size; +	double percent; +	int ret; + +	va_start(args, fmt); +	percent = va_arg(args, double); +	ret = value_color_snprintf(hpp->buf, hpp->size, fmt, percent); +	va_end(args); + +	return (ret >= ssize) ? (ssize - 1) : ret; +} + +static int hpp_entry_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) +{ +	va_list args; +	ssize_t ssize = hpp->size; +	int ret; + +	va_start(args, fmt); +	ret = vsnprintf(hpp->buf, hpp->size, fmt, args); +	va_end(args); + +	return (ret >= ssize) ? (ssize - 1) : ret; +} +  #define __HPP_COLOR_PERCENT_FN(_type, _field)					\  static u64 he_get_##_field(struct hist_entry *he)				\  {										\ @@ -117,7 +254,7 @@ static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,		\  			      struct perf_hpp *hpp, struct hist_entry *he) 	\  {										\  	return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%",			\ -			  (hpp_snprint_fn)percent_color_snprintf, true);	\ +			  hpp_color_scnprintf, true);				\  }  #define __HPP_ENTRY_PERCENT_FN(_type, _field)					\ @@ -126,7 +263,41 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,		\  {										\  	const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%";		\  	return __hpp__fmt(hpp, he, he_get_##_field, fmt,			\ -			  scnprintf, true);					\ +			  hpp_entry_scnprintf, true);				\ +} + +#define __HPP_SORT_FN(_type, _field)						\ +static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b)	\ +{										\ +	return __hpp__sort(a, b, he_get_##_field);				\ +} + +#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)				\ +static u64 he_get_acc_##_field(struct hist_entry *he)				\ +{										\ +	return he->stat_acc->_field;						\ +}										\ +										\ +static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,		\ +			      struct perf_hpp *hpp, struct hist_entry *he) 	\ +{										\ +	return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%",		\ +			      hpp_color_scnprintf, true);			\ +} + +#define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field)				\ +static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,		\ +			      struct perf_hpp *hpp, struct hist_entry *he) 	\ +{										\ +	const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%";		\ +	return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, fmt,		\ +			      hpp_entry_scnprintf, true);			\ +} + +#define __HPP_SORT_ACC_FN(_type, _field)					\ +static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b)	\ +{										\ +	return __hpp__sort_acc(a, b, he_get_acc_##_field);			\  }  #define __HPP_ENTRY_RAW_FN(_type, _field)					\ @@ -139,43 +310,85 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,		\  			      struct perf_hpp *hpp, struct hist_entry *he) 	\  {										\  	const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64;	\ -	return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false);	\ +	return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt,			\ +			  hpp_entry_scnprintf, false);				\  } +#define __HPP_SORT_RAW_FN(_type, _field)					\ +static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b)	\ +{										\ +	return __hpp__sort(a, b, he_get_raw_##_field);				\ +} + +  #define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width)	\  __HPP_HEADER_FN(_type, _str, _min_width, _unit_width)			\  __HPP_WIDTH_FN(_type, _min_width, _unit_width)				\  __HPP_COLOR_PERCENT_FN(_type, _field)					\ -__HPP_ENTRY_PERCENT_FN(_type, _field) +__HPP_ENTRY_PERCENT_FN(_type, _field)					\ +__HPP_SORT_FN(_type, _field) + +#define HPP_PERCENT_ACC_FNS(_type, _str, _field, _min_width, _unit_width)\ +__HPP_HEADER_FN(_type, _str, _min_width, _unit_width)			\ +__HPP_WIDTH_FN(_type, _min_width, _unit_width)				\ +__HPP_COLOR_ACC_PERCENT_FN(_type, _field)				\ +__HPP_ENTRY_ACC_PERCENT_FN(_type, _field)				\ +__HPP_SORT_ACC_FN(_type, _field)  #define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width)	\  __HPP_HEADER_FN(_type, _str, _min_width, _unit_width)			\  __HPP_WIDTH_FN(_type, _min_width, _unit_width)				\ -__HPP_ENTRY_RAW_FN(_type, _field) +__HPP_ENTRY_RAW_FN(_type, _field)					\ +__HPP_SORT_RAW_FN(_type, _field) +__HPP_HEADER_FN(overhead_self, "Self", 8, 8)  HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)  HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)  HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)  HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)  HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) +HPP_PERCENT_ACC_FNS(overhead_acc, "Children", period, 8, 8)  HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)  HPP_RAW_FNS(period, "Period", period, 12, 12) +static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused, +			    struct hist_entry *b __maybe_unused) +{ +	return 0; +} +  #define HPP__COLOR_PRINT_FNS(_name)			\  	{						\  		.header	= hpp__header_ ## _name,	\  		.width	= hpp__width_ ## _name,		\  		.color	= hpp__color_ ## _name,		\ -		.entry	= hpp__entry_ ## _name		\ +		.entry	= hpp__entry_ ## _name,		\ +		.cmp	= hpp__nop_cmp,			\ +		.collapse = hpp__nop_cmp,		\ +		.sort	= hpp__sort_ ## _name,		\ +	} + +#define HPP__COLOR_ACC_PRINT_FNS(_name)			\ +	{						\ +		.header	= hpp__header_ ## _name,	\ +		.width	= hpp__width_ ## _name,		\ +		.color	= hpp__color_ ## _name,		\ +		.entry	= hpp__entry_ ## _name,		\ +		.cmp	= hpp__nop_cmp,			\ +		.collapse = hpp__nop_cmp,		\ +		.sort	= hpp__sort_ ## _name,		\  	}  #define HPP__PRINT_FNS(_name)				\  	{						\  		.header	= hpp__header_ ## _name,	\  		.width	= hpp__width_ ## _name,		\ -		.entry	= hpp__entry_ ## _name		\ +		.entry	= hpp__entry_ ## _name,		\ +		.cmp	= hpp__nop_cmp,			\ +		.collapse = hpp__nop_cmp,		\ +		.sort	= hpp__sort_ ## _name,		\  	}  struct perf_hpp_fmt perf_hpp__format[] = { @@ -184,28 +397,63 @@ struct perf_hpp_fmt perf_hpp__format[] = {  	HPP__COLOR_PRINT_FNS(overhead_us),  	HPP__COLOR_PRINT_FNS(overhead_guest_sys),  	HPP__COLOR_PRINT_FNS(overhead_guest_us), +	HPP__COLOR_ACC_PRINT_FNS(overhead_acc),  	HPP__PRINT_FNS(samples),  	HPP__PRINT_FNS(period)  };  LIST_HEAD(perf_hpp__list); +LIST_HEAD(perf_hpp__sort_list);  #undef HPP__COLOR_PRINT_FNS +#undef HPP__COLOR_ACC_PRINT_FNS  #undef HPP__PRINT_FNS  #undef HPP_PERCENT_FNS +#undef HPP_PERCENT_ACC_FNS  #undef HPP_RAW_FNS  #undef __HPP_HEADER_FN  #undef __HPP_WIDTH_FN  #undef __HPP_COLOR_PERCENT_FN  #undef __HPP_ENTRY_PERCENT_FN +#undef __HPP_COLOR_ACC_PERCENT_FN +#undef __HPP_ENTRY_ACC_PERCENT_FN  #undef __HPP_ENTRY_RAW_FN +#undef __HPP_SORT_FN +#undef __HPP_SORT_ACC_FN +#undef __HPP_SORT_RAW_FN  void perf_hpp__init(void)  { +	struct list_head *list; +	int i; + +	for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { +		struct perf_hpp_fmt *fmt = &perf_hpp__format[i]; + +		INIT_LIST_HEAD(&fmt->list); + +		/* sort_list may be linked by setup_sorting() */ +		if (fmt->sort_list.next == NULL) +			INIT_LIST_HEAD(&fmt->sort_list); +	} + +	/* +	 * If user specified field order, no need to setup default fields. +	 */ +	if (field_order) +		return; + +	if (symbol_conf.cumulate_callchain) { +		perf_hpp__column_enable(PERF_HPP__OVERHEAD_ACC); + +		perf_hpp__format[PERF_HPP__OVERHEAD].header = +						hpp__header_overhead_self; +	} +  	perf_hpp__column_enable(PERF_HPP__OVERHEAD);  	if (symbol_conf.show_cpu_utilization) { @@ -223,6 +471,17 @@ void perf_hpp__init(void)  	if (symbol_conf.show_total_period)  		perf_hpp__column_enable(PERF_HPP__PERIOD); + +	/* prepend overhead field for backward compatiblity.  */ +	list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list; +	if (list_empty(list)) +		list_add(list, &perf_hpp__sort_list); + +	if (symbol_conf.cumulate_callchain) { +		list = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC].sort_list; +		if (list_empty(list)) +			list_add(list, &perf_hpp__sort_list); +	}  }  void perf_hpp__column_register(struct perf_hpp_fmt *format) @@ -230,29 +489,110 @@ void perf_hpp__column_register(struct perf_hpp_fmt *format)  	list_add_tail(&format->list, &perf_hpp__list);  } +void perf_hpp__column_unregister(struct perf_hpp_fmt *format) +{ +	list_del(&format->list); +} + +void perf_hpp__register_sort_field(struct perf_hpp_fmt *format) +{ +	list_add_tail(&format->sort_list, &perf_hpp__sort_list); +} +  void perf_hpp__column_enable(unsigned col)  {  	BUG_ON(col >= PERF_HPP__MAX_INDEX);  	perf_hpp__column_register(&perf_hpp__format[col]);  } -int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, -			      struct hists *hists) +void perf_hpp__column_disable(unsigned col)  { -	const char *sep = symbol_conf.field_sep; -	struct sort_entry *se; -	int ret = 0; +	BUG_ON(col >= PERF_HPP__MAX_INDEX); +	perf_hpp__column_unregister(&perf_hpp__format[col]); +} + +void perf_hpp__cancel_cumulate(void) +{ +	if (field_order) +		return; + +	perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC); +	perf_hpp__format[PERF_HPP__OVERHEAD].header = hpp__header_overhead; +} -	list_for_each_entry(se, &hist_entry__sort_list, list) { -		if (se->elide) +void perf_hpp__setup_output_field(void) +{ +	struct perf_hpp_fmt *fmt; + +	/* append sort keys to output field */ +	perf_hpp__for_each_sort_list(fmt) { +		if (!list_empty(&fmt->list))  			continue; -		ret += scnprintf(s + ret, size - ret, "%s", sep ?: "  "); -		ret += se->se_snprintf(he, s + ret, size - ret, -				       hists__col_len(hists, se->se_width_idx)); +		/* +		 * sort entry fields are dynamically created, +		 * so they can share a same sort key even though +		 * the list is empty. +		 */ +		if (perf_hpp__is_sort_entry(fmt)) { +			struct perf_hpp_fmt *pos; + +			perf_hpp__for_each_format(pos) { +				if (perf_hpp__same_sort_entry(pos, fmt)) +					goto next; +			} +		} + +		perf_hpp__column_register(fmt); +next: +		continue;  	} +} -	return ret; +void perf_hpp__append_sort_keys(void) +{ +	struct perf_hpp_fmt *fmt; + +	/* append output fields to sort keys */ +	perf_hpp__for_each_format(fmt) { +		if (!list_empty(&fmt->sort_list)) +			continue; + +		/* +		 * sort entry fields are dynamically created, +		 * so they can share a same sort key even though +		 * the list is empty. +		 */ +		if (perf_hpp__is_sort_entry(fmt)) { +			struct perf_hpp_fmt *pos; + +			perf_hpp__for_each_sort_list(pos) { +				if (perf_hpp__same_sort_entry(pos, fmt)) +					goto next; +			} +		} + +		perf_hpp__register_sort_field(fmt); +next: +		continue; +	} +} + +void perf_hpp__reset_output_field(void) +{ +	struct perf_hpp_fmt *fmt, *tmp; + +	/* reset output fields */ +	perf_hpp__for_each_format_safe(fmt, tmp) { +		list_del_init(&fmt->list); +		list_del_init(&fmt->sort_list); +	} + +	/* reset sort keys */ +	perf_hpp__for_each_sort_list_safe(fmt, tmp) { +		list_del_init(&fmt->list); +		list_del_init(&fmt->sort_list); +	}  }  /* @@ -261,24 +601,23 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,  unsigned int hists__sort_list_width(struct hists *hists)  {  	struct perf_hpp_fmt *fmt; -	struct sort_entry *se; -	int i = 0, ret = 0; -	struct perf_hpp dummy_hpp = { -		.ptr	= hists_to_evsel(hists), -	}; +	int ret = 0; +	bool first = true; +	struct perf_hpp dummy_hpp;  	perf_hpp__for_each_format(fmt) { -		if (i) +		if (perf_hpp__should_skip(fmt)) +			continue; + +		if (first) +			first = false; +		else  			ret += 2; -		ret += fmt->width(fmt, &dummy_hpp); +		ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));  	} -	list_for_each_entry(se, &hist_entry__sort_list, list) -		if (!se->elide) -			ret += 2 + hists__col_len(hists, se->se_width_idx); - -	if (verbose) /* Addr + origin */ +	if (verbose && sort__has_sym) /* Addr + origin */  		ret += 3 + BITS_PER_LONG / 4;  	return ret; diff --git a/tools/perf/ui/progress.c b/tools/perf/ui/progress.c index 3ec695607a4..a0f24c7115c 100644 --- a/tools/perf/ui/progress.c +++ b/tools/perf/ui/progress.c @@ -1,26 +1,38 @@  #include "../cache.h"  #include "progress.h" -static void nop_progress_update(u64 curr __maybe_unused, -				u64 total __maybe_unused, -				const char *title __maybe_unused) +static void null_progress__update(struct ui_progress *p __maybe_unused)  {  } -static struct ui_progress default_progress_fns = +static struct ui_progress_ops null_progress__ops =  { -	.update		= nop_progress_update, +	.update = null_progress__update,  }; -struct ui_progress *progress_fns = &default_progress_fns; +struct ui_progress_ops *ui_progress__ops = &null_progress__ops; -void ui_progress__update(u64 curr, u64 total, const char *title) +void ui_progress__update(struct ui_progress *p, u64 adv)  { -	return progress_fns->update(curr, total, title); +	p->curr += adv; + +	if (p->curr >= p->next) { +		p->next += p->step; +		ui_progress__ops->update(p); +	} +} + +void ui_progress__init(struct ui_progress *p, u64 total, const char *title) +{ +	p->curr = 0; +	p->next = p->step = total / 16; +	p->total = total; +	p->title = title; +  }  void ui_progress__finish(void)  { -	if (progress_fns->finish) -		progress_fns->finish(); +	if (ui_progress__ops->finish) +		ui_progress__ops->finish();  } diff --git a/tools/perf/ui/progress.h b/tools/perf/ui/progress.h index 257cc224f9c..f34f89eb607 100644 --- a/tools/perf/ui/progress.h +++ b/tools/perf/ui/progress.h @@ -1,18 +1,23 @@  #ifndef _PERF_UI_PROGRESS_H_  #define _PERF_UI_PROGRESS_H_ 1 -#include <../types.h> +#include <linux/types.h> +void ui_progress__finish(void); +   struct ui_progress { -	void (*update)(u64, u64, const char *); -	void (*finish)(void); +	const char *title; +	u64 curr, next, step, total;  }; +  +void ui_progress__init(struct ui_progress *p, u64 total, const char *title); +void ui_progress__update(struct ui_progress *p, u64 adv); -extern struct ui_progress *progress_fns; - -void ui_progress__init(void); +struct ui_progress_ops { +	void (*update)(struct ui_progress *p); +	void (*finish)(void); +}; -void ui_progress__update(u64 curr, u64 total, const char *title); -void ui_progress__finish(void); +extern struct ui_progress_ops *ui_progress__ops;  #endif diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index 47d9a571f26..ba51fa8a117 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c @@ -1,10 +1,64 @@  #include <pthread.h> +#include <dlfcn.h>  #include "../util/cache.h"  #include "../util/debug.h"  #include "../util/hist.h"  pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; +void *perf_gtk_handle; + +#ifdef HAVE_GTK2_SUPPORT +static int setup_gtk_browser(void) +{ +	int (*perf_ui_init)(void); + +	if (perf_gtk_handle) +		return 0; + +	perf_gtk_handle = dlopen(PERF_GTK_DSO, RTLD_LAZY); +	if (perf_gtk_handle == NULL) { +		char buf[PATH_MAX]; +		scnprintf(buf, sizeof(buf), "%s/%s", LIBDIR, PERF_GTK_DSO); +		perf_gtk_handle = dlopen(buf, RTLD_LAZY); +	} +	if (perf_gtk_handle == NULL) +		return -1; + +	perf_ui_init = dlsym(perf_gtk_handle, "perf_gtk__init"); +	if (perf_ui_init == NULL) +		goto out_close; + +	if (perf_ui_init() == 0) +		return 0; + +out_close: +	dlclose(perf_gtk_handle); +	return -1; +} + +static void exit_gtk_browser(bool wait_for_ok) +{ +	void (*perf_ui_exit)(bool); + +	if (perf_gtk_handle == NULL) +		return; + +	perf_ui_exit = dlsym(perf_gtk_handle, "perf_gtk__exit"); +	if (perf_ui_exit == NULL) +		goto out_close; + +	perf_ui_exit(wait_for_ok); + +out_close: +	dlclose(perf_gtk_handle); + +	perf_gtk_handle = NULL; +} +#else +static inline int setup_gtk_browser(void) { return -1; } +static inline void exit_gtk_browser(bool wait_for_ok __maybe_unused) {} +#endif  void setup_browser(bool fallback_to_pager)  { @@ -17,8 +71,11 @@ void setup_browser(bool fallback_to_pager)  	switch (use_browser) {  	case 2: -		if (perf_gtk__init() == 0) +		if (setup_gtk_browser() == 0)  			break; +		printf("GTK browser requested but could not find %s\n", +		       PERF_GTK_DSO); +		sleep(1);  		/* fall through */  	case 1:  		use_browser = 1; @@ -29,8 +86,6 @@ void setup_browser(bool fallback_to_pager)  		use_browser = 0;  		if (fallback_to_pager)  			setup_pager(); - -		perf_hpp__init();  		break;  	}  } @@ -39,7 +94,7 @@ void exit_browser(bool wait_for_ok)  {  	switch (use_browser) {  	case 2: -		perf_gtk__exit(wait_for_ok); +		exit_gtk_browser(wait_for_ok);  		break;  	case 1: diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 194e2f42ff5..90122abd372 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -183,7 +183,8 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,  			 * the symbol. No need to print it otherwise it appears as  			 * displayed twice.  			 */ -			if (!i++ && sort__first_dimension == SORT_SYM) +			if (!i++ && field_order == NULL && +			    sort_order && !prefixcmp(sort_order, "sym"))  				continue;  			if (!printed) {  				ret += callchain__fprintf_left_margin(fp, left_margin); @@ -213,20 +214,19 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,  	return ret;  } -static size_t __callchain__fprintf_flat(FILE *fp, -					struct callchain_node *self, +static size_t __callchain__fprintf_flat(FILE *fp, struct callchain_node *node,  					u64 total_samples)  {  	struct callchain_list *chain;  	size_t ret = 0; -	if (!self) +	if (!node)  		return 0; -	ret += __callchain__fprintf_flat(fp, self->parent, total_samples); +	ret += __callchain__fprintf_flat(fp, node->parent, total_samples); -	list_for_each_entry(chain, &self->val, list) { +	list_for_each_entry(chain, &node->val, list) {  		if (chain->ip >= PERF_CONTEXT_MAX)  			continue;  		if (chain->ms.sym) @@ -239,15 +239,14 @@ static size_t __callchain__fprintf_flat(FILE *fp,  	return ret;  } -static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *self, +static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,  				      u64 total_samples)  {  	size_t ret = 0;  	u32 entries_printed = 0; -	struct rb_node *rb_node;  	struct callchain_node *chain; +	struct rb_node *rb_node = rb_first(tree); -	rb_node = rb_first(self);  	while (rb_node) {  		double percent; @@ -272,7 +271,9 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,  {  	switch (callchain_param.mode) {  	case CHAIN_GRAPH_REL: -		return callchain__fprintf_graph(fp, &he->sorted_chain, he->stat.period, +		return callchain__fprintf_graph(fp, &he->sorted_chain, +						symbol_conf.cumulate_callchain ? +						he->stat_acc->period : he->stat.period,  						left_margin);  		break;  	case CHAIN_GRAPH_ABS: @@ -298,25 +299,24 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,  	int left_margin = 0;  	u64 total_period = hists->stats.total_period; -	if (sort__first_dimension == SORT_COMM) { -		struct sort_entry *se = list_first_entry(&hist_entry__sort_list, -							 typeof(*se), list); -		left_margin = hists__col_len(hists, se->se_width_idx); -		left_margin -= thread__comm_len(he->thread); -	} +	if (field_order == NULL && (sort_order == NULL || +				    !prefixcmp(sort_order, "comm"))) { +		struct perf_hpp_fmt *fmt; -	return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); -} +		perf_hpp__for_each_format(fmt) { +			if (!perf_hpp__is_sort_entry(fmt)) +				continue; -static inline void advance_hpp(struct perf_hpp *hpp, int inc) -{ -	hpp->buf  += inc; -	hpp->size -= inc; +			/* must be 'comm' sort entry */ +			left_margin = fmt->width(fmt, NULL, hists_to_evsel(hists)); +			left_margin -= thread__comm_len(he->thread); +			break; +		} +	} +	return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);  } -static int hist_entry__period_snprintf(struct perf_hpp *hpp, -				       struct hist_entry *he, -				       bool color) +static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)  {  	const char *sep = symbol_conf.field_sep;  	struct perf_hpp_fmt *fmt; @@ -328,6 +328,9 @@ static int hist_entry__period_snprintf(struct perf_hpp *hpp,  		return 0;  	perf_hpp__for_each_format(fmt) { +		if (perf_hpp__should_skip(fmt)) +			continue; +  		/*  		 * If there's no field_sep, we still need  		 * to display initial '  '. @@ -338,7 +341,7 @@ static int hist_entry__period_snprintf(struct perf_hpp *hpp,  		} else  			first = false; -		if (color && fmt->color) +		if (perf_hpp__use_color() && fmt->color)  			ret = fmt->color(fmt, hpp, he);  		else  			ret = fmt->entry(fmt, hpp, he); @@ -358,13 +361,11 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,  		.buf		= bf,  		.size		= size,  	}; -	bool color = !symbol_conf.field_sep;  	if (size == 0 || size > bfsz)  		size = hpp.size = bfsz; -	ret = hist_entry__period_snprintf(&hpp, he, color); -	hist_entry__sort_snprintf(he, bf + ret, size - ret, hists); +	hist_entry__snprintf(he, &hpp);  	ret = fprintf(fp, "%s\n", bf); @@ -378,18 +379,15 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,  		      int max_cols, float min_pcnt, FILE *fp)  {  	struct perf_hpp_fmt *fmt; -	struct sort_entry *se;  	struct rb_node *nd;  	size_t ret = 0;  	unsigned int width;  	const char *sep = symbol_conf.field_sep; -	const char *col_width = symbol_conf.col_width_list_str;  	int nr_rows = 0;  	char bf[96];  	struct perf_hpp dummy_hpp = {  		.buf	= bf,  		.size	= sizeof(bf), -		.ptr	= hists_to_evsel(hists),  	};  	bool first = true;  	size_t linesz; @@ -397,43 +395,28 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,  	init_rem_hits(); + +	perf_hpp__for_each_format(fmt) +		perf_hpp__reset_width(fmt, hists); +  	if (!show_header)  		goto print_entries;  	fprintf(fp, "# ");  	perf_hpp__for_each_format(fmt) { +		if (perf_hpp__should_skip(fmt)) +			continue; +  		if (!first)  			fprintf(fp, "%s", sep ?: "  ");  		else  			first = false; -		fmt->header(fmt, &dummy_hpp); +		fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));  		fprintf(fp, "%s", bf);  	} -	list_for_each_entry(se, &hist_entry__sort_list, list) { -		if (se->elide) -			continue; -		if (sep) { -			fprintf(fp, "%c%s", *sep, se->se_header); -			continue; -		} -		width = strlen(se->se_header); -		if (symbol_conf.col_width_list_str) { -			if (col_width) { -				hists__set_col_len(hists, se->se_width_idx, -						   atoi(col_width)); -				col_width = strchr(col_width, ','); -				if (col_width) -					++col_width; -			} -		} -		if (!hists__new_col_len(hists, se->se_width_idx, width)) -			width = hists__col_len(hists, se->se_width_idx); -		fprintf(fp, "  %*s", width, se->se_header); -	} -  	fprintf(fp, "\n");  	if (max_rows && ++nr_rows >= max_rows)  		goto out; @@ -448,26 +431,15 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,  	perf_hpp__for_each_format(fmt) {  		unsigned int i; +		if (perf_hpp__should_skip(fmt)) +			continue; +  		if (!first)  			fprintf(fp, "%s", sep ?: "  ");  		else  			first = false; -		width = fmt->width(fmt, &dummy_hpp); -		for (i = 0; i < width; i++) -			fprintf(fp, "."); -	} - -	list_for_each_entry(se, &hist_entry__sort_list, list) { -		unsigned int i; - -		if (se->elide) -			continue; - -		fprintf(fp, "  "); -		width = hists__col_len(hists, se->se_width_idx); -		if (width == 0) -			width = strlen(se->se_header); +		width = fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));  		for (i = 0; i < width; i++)  			fprintf(fp, ".");  	} @@ -482,6 +454,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,  print_entries:  	linesz = hists__sort_list_width(hists) + 3 + 1; +	linesz += perf_hpp__color_overhead();  	line = malloc(linesz);  	if (line == NULL) {  		ret = -1; @@ -490,12 +463,12 @@ print_entries:  	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {  		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;  		if (h->filtered)  			continue; +		percent = hist_entry__get_percent_limit(h);  		if (percent < min_pcnt)  			continue; @@ -505,7 +478,7 @@ print_entries:  			break;  		if (h->ms.map == NULL && verbose > 1) { -			__map_groups__fprintf_maps(&h->thread->mg, +			__map_groups__fprintf_maps(h->thread->mg,  						   MAP__FUNCTION, verbose, fp);  			fprintf(fp, "%.10s end\n", graph_dotted_line);  		} @@ -513,7 +486,7 @@ print_entries:  	free(line);  out: -	free(rem_sq_bracket); +	zfree(&rem_sq_bracket);  	return ret;  } diff --git a/tools/perf/ui/tui/progress.c b/tools/perf/ui/tui/progress.c index 6c2184d53cb..c61d14b101e 100644 --- a/tools/perf/ui/tui/progress.c +++ b/tools/perf/ui/tui/progress.c @@ -2,9 +2,10 @@  #include "../progress.h"  #include "../libslang.h"  #include "../ui.h" +#include "tui.h"  #include "../browser.h" -static void tui_progress__update(u64 curr, u64 total, const char *title) +static void tui_progress__update(struct ui_progress *p)  {  	int bar, y;  	/* @@ -14,29 +15,30 @@ static void tui_progress__update(u64 curr, u64 total, const char *title)  	if (use_browser <= 0)  		return; -	if (total == 0) +	if (p->total == 0)  		return; -	ui__refresh_dimensions(true); +	ui__refresh_dimensions(false);  	pthread_mutex_lock(&ui__lock);  	y = SLtt_Screen_Rows / 2 - 2;  	SLsmg_set_color(0);  	SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols);  	SLsmg_gotorc(y++, 1); -	SLsmg_write_string((char *)title); +	SLsmg_write_string((char *)p->title); +	SLsmg_fill_region(y, 1, 1, SLtt_Screen_Cols - 2, ' ');  	SLsmg_set_color(HE_COLORSET_SELECTED); -	bar = ((SLtt_Screen_Cols - 2) * curr) / total; +	bar = ((SLtt_Screen_Cols - 2) * p->curr) / p->total;  	SLsmg_fill_region(y, 1, 1, bar, ' ');  	SLsmg_refresh();  	pthread_mutex_unlock(&ui__lock);  } -static struct ui_progress tui_progress_fns = +static struct ui_progress_ops tui_progress__ops =  {  	.update		= tui_progress__update,  }; -void ui_progress__init(void) +void tui_progress__init(void)  { -	progress_fns = &tui_progress_fns; +	ui_progress__ops = &tui_progress__ops;  } diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c index b9401482d11..2f612562978 100644 --- a/tools/perf/ui/tui/setup.c +++ b/tools/perf/ui/tui/setup.c @@ -9,6 +9,7 @@  #include "../util.h"  #include "../libslang.h"  #include "../keysyms.h" +#include "tui.h"  static volatile int ui__need_resize; @@ -119,7 +120,7 @@ int ui__init(void)  	ui_helpline__init();  	ui_browser__init(); -	ui_progress__init(); +	tui_progress__init();  	signal(SIGSEGV, ui__signal);  	signal(SIGFPE, ui__signal); diff --git a/tools/perf/ui/tui/tui.h b/tools/perf/ui/tui/tui.h new file mode 100644 index 00000000000..18961c7b6ec --- /dev/null +++ b/tools/perf/ui/tui/tui.h @@ -0,0 +1,6 @@ +#ifndef _PERF_TUI_H_ +#define _PERF_TUI_H_ 1 + +void tui_progress__init(void); + +#endif /* _PERF_TUI_H_ */ diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c index 092902e30ce..bf890f72fe8 100644 --- a/tools/perf/ui/tui/util.c +++ b/tools/perf/ui/tui/util.c @@ -92,6 +92,8 @@ int ui_browser__input_window(const char *title, const char *text, char *input,  		t = sep + 1;  	} +	pthread_mutex_lock(&ui__lock); +  	max_len += 2;  	nr_lines += 8;  	y = SLtt_Screen_Rows / 2 - nr_lines / 2; @@ -120,13 +122,19 @@ int ui_browser__input_window(const char *title, const char *text, char *input,  	SLsmg_write_nstring((char *)exit_msg, max_len);  	SLsmg_refresh(); +	pthread_mutex_unlock(&ui__lock); +  	x += 2;  	len = 0;  	key = ui__getch(delay_secs);  	while (key != K_TIMER && key != K_ENTER && key != K_ESC) { +		pthread_mutex_lock(&ui__lock); +  		if (key == K_BKSPC) { -			if (len == 0) +			if (len == 0) { +				pthread_mutex_unlock(&ui__lock);  				goto next_key; +			}  			SLsmg_gotorc(y, x + --len);  			SLsmg_write_char(' ');  		} else { @@ -136,6 +144,8 @@ int ui_browser__input_window(const char *title, const char *text, char *input,  		}  		SLsmg_refresh(); +		pthread_mutex_unlock(&ui__lock); +  		/* XXX more graceful overflow handling needed */  		if (len == sizeof(buf) - 1) {  			ui_helpline__push("maximum size of symbol name reached!"); @@ -174,6 +184,8 @@ int ui__question_window(const char *title, const char *text,  		t = sep + 1;  	} +	pthread_mutex_lock(&ui__lock); +  	max_len += 2;  	nr_lines += 4;  	y = SLtt_Screen_Rows / 2 - nr_lines / 2, @@ -195,6 +207,9 @@ int ui__question_window(const char *title, const char *text,  	SLsmg_gotorc(y + nr_lines - 1, x);  	SLsmg_write_nstring((char *)exit_msg, max_len);  	SLsmg_refresh(); + +	pthread_mutex_unlock(&ui__lock); +  	return ui__getch(delay_secs);  } @@ -215,9 +230,7 @@ static int __ui__warning(const char *title, const char *format, va_list args)  	if (vasprintf(&s, format, args) > 0) {  		int key; -		pthread_mutex_lock(&ui__lock);  		key = ui__question_window(title, s, "Press any key...", 0); -		pthread_mutex_unlock(&ui__lock);  		free(s);  		return key;  	} diff --git a/tools/perf/ui/ui.h b/tools/perf/ui/ui.h index 70cb0d4eb8a..ab88383f8be 100644 --- a/tools/perf/ui/ui.h +++ b/tools/perf/ui/ui.h @@ -6,13 +6,14 @@  #include <linux/compiler.h>  extern pthread_mutex_t ui__lock; +extern void *perf_gtk_handle;  extern int use_browser;  void setup_browser(bool fallback_to_pager);  void exit_browser(bool wait_for_ok); -#ifdef SLANG_SUPPORT +#ifdef HAVE_SLANG_SUPPORT  int ui__init(void);  void ui__exit(bool wait_for_ok);  #else @@ -23,17 +24,6 @@ static inline int ui__init(void)  static inline void ui__exit(bool wait_for_ok __maybe_unused) {}  #endif -#ifdef GTK2_SUPPORT -int perf_gtk__init(void); -void perf_gtk__exit(bool wait_for_ok); -#else -static inline int perf_gtk__init(void) -{ -	return -1; -} -static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {} -#endif -  void ui__refresh_dimensions(bool force);  #endif /* _PERF_UI_H_ */  | 
