614 lines · 15.0 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0#include <inttypes.h>#include <string.h>#include <linux/zalloc.h>#include <sys/ttydefaults.h> #include "ui/browser.h"#include "ui/helpline.h"#include "ui/keysyms.h"#include "ui/ui.h"#include "util/annotate.h"#include "util/annotate-data.h"#include "util/evsel.h"#include "util/evlist.h"#include "util/sort.h" #define FOLDED_SIGN  '+'#define UNFOLD_SIGN  '-'#define NOCHLD_SIGN  ' ' struct browser_entry {	struct list_head node;	struct annotated_member *data;	struct type_hist_entry *hists;	struct browser_entry *parent;	struct list_head children;	int indent;  /*indentation level, starts from 0 */	int nr_entries; /* # of visible entries: self + descendents */	bool folded;  /* only can be false when it has children */}; struct annotated_data_browser {	struct ui_browser b;	struct list_head entries;	struct browser_entry *curr;	int nr_events;}; static struct annotated_data_browser *get_browser(struct ui_browser *uib){	return container_of(uib, struct annotated_data_browser, b);} static void update_hist_entry(struct type_hist_entry *dst,			      struct type_hist_entry *src){	dst->nr_samples += src->nr_samples;	dst->period += src->period;} static int get_member_overhead(struct annotated_data_type *adt,			       struct browser_entry *entry,			       struct evsel *leader){	struct annotated_member *member = entry->data;	int i, k; 	for (i = 0; i < member->size; i++) {		struct type_hist *h;		struct evsel *evsel;		int offset = member->offset + i; 		k = 0;		for_each_group_evsel(evsel, leader) {			if (symbol_conf.skip_empty &&			    evsel__hists(evsel)->stats.nr_samples == 0)				continue; 			h = adt->histograms[evsel->core.idx];			update_hist_entry(&entry->hists[k++], &h->addr[offset]);		}	}	return 0;} static int add_child_entries(struct annotated_data_browser *browser,			     struct browser_entry *parent,			     struct annotated_data_type *adt,			     struct annotated_member *member,			     struct evsel *evsel, int indent){	struct annotated_member *pos;	struct browser_entry *entry;	struct list_head *parent_list; 	entry = zalloc(sizeof(*entry));	if (entry == NULL)		return -1; 	entry->hists = calloc(browser->nr_events, sizeof(*entry->hists));	if (entry->hists == NULL) {		free(entry);		return -1;	} 	entry->data = member;	entry->parent = parent;	entry->indent = indent;	if (get_member_overhead(adt, entry, evsel) < 0) {		free(entry);		return -1;	} 	INIT_LIST_HEAD(&entry->children);	if (parent)		parent_list = &parent->children;	else		parent_list = &browser->entries; 	list_add_tail(&entry->node, parent_list); 	list_for_each_entry(pos, &member->children, node) {		int nr = add_child_entries(browser, entry, adt, pos, evsel,					   indent + 1);		if (nr < 0)			return nr;	} 	/* add an entry for the closing bracket ("}") */	if (!list_empty(&member->children)) {		struct browser_entry *bracket; 		bracket = zalloc(sizeof(*bracket));		if (bracket == NULL)			return -1; 		bracket->indent = indent;		bracket->parent = entry;		bracket->folded = true;		bracket->nr_entries = 1; 		INIT_LIST_HEAD(&bracket->children);		list_add_tail(&bracket->node, &entry->children);	} 	/* fold child entries by default */	entry->folded = true;	entry->nr_entries = 1;	return 0;} static u32 count_visible_entries(struct annotated_data_browser *browser){	int nr = 0;	struct browser_entry *entry; 	list_for_each_entry(entry, &browser->entries, node)		nr += entry->nr_entries; 	return nr;} static int annotated_data_browser__collect_entries(struct annotated_data_browser *browser){	struct hist_entry *he = browser->b.priv;	struct annotated_data_type *adt = he->mem_type;	struct evsel *evsel = hists_to_evsel(he->hists); 	INIT_LIST_HEAD(&browser->entries); 	add_child_entries(browser, /*parent=*/NULL, adt, &adt->self, evsel,			  /*indent=*/0); 	browser->b.entries = &browser->entries;	browser->b.nr_entries = count_visible_entries(browser);	return 0;} static void annotated_data_browser__delete_entries(struct annotated_data_browser *browser){	struct browser_entry *pos, *tmp; 	list_for_each_entry_safe(pos, tmp, &browser->entries, node) {		list_del_init(&pos->node);		zfree(&pos->hists);		free(pos);	}} static struct browser_entry *get_first_child(struct browser_entry *entry){	if (list_empty(&entry->children))		return NULL; 	return list_first_entry(&entry->children, struct browser_entry, node);} static struct browser_entry *get_last_child(struct browser_entry *entry){	if (list_empty(&entry->children))		return NULL; 	return list_last_entry(&entry->children, struct browser_entry, node);} static bool is_first_child(struct browser_entry *entry){	/* This will be checked in a different way */	if (entry->parent == NULL)		return false; 	return get_first_child(entry->parent) == entry;} static bool is_last_child(struct browser_entry *entry){	/* This will be checked in a different way */	if (entry->parent == NULL)		return false; 	return get_last_child(entry->parent) == entry;} static struct browser_entry *browser__prev_entry(struct ui_browser *uib,						 struct browser_entry *entry){	struct annotated_data_browser *browser = get_browser(uib);	struct browser_entry *first; 	first = list_first_entry(&browser->entries, struct browser_entry, node); 	while (entry != first) {		if (is_first_child(entry))			entry = entry->parent;		else {			entry = list_prev_entry(entry, node);			while (!entry->folded)				entry = get_last_child(entry);		} 		if (!uib->filter || !uib->filter(uib, &entry->node))			return entry;	}	return first;} static struct browser_entry *browser__next_entry(struct ui_browser *uib,						 struct browser_entry *entry){	struct annotated_data_browser *browser = get_browser(uib);	struct browser_entry *last; 	last = list_last_entry(&browser->entries, struct browser_entry, node);	while (!last->folded)		last = get_last_child(last); 	while (entry != last) {		if (!entry->folded)			entry = get_first_child(entry);		else {			while (is_last_child(entry))				entry = entry->parent; 			entry = list_next_entry(entry, node);		} 		if (!uib->filter || !uib->filter(uib, &entry->node))			return entry;	}	return last;} static void browser__seek(struct ui_browser *uib, off_t offset, int whence){	struct annotated_data_browser *browser = get_browser(uib);	struct browser_entry *entry; 	if (uib->nr_entries == 0)		return; 	switch (whence) {	case SEEK_SET:		entry = list_first_entry(&browser->entries, typeof(*entry), node);		if (uib->filter && uib->filter(uib, &entry->node))			entry = browser__next_entry(uib, entry);		break;	case SEEK_CUR:		entry = list_entry(uib->top, typeof(*entry), node);		break;	case SEEK_END:		entry = list_last_entry(&browser->entries, typeof(*entry), node);		while (!entry->folded)			entry = get_last_child(entry);		if (uib->filter && uib->filter(uib, &entry->node))			entry = browser__prev_entry(uib, entry);		break;	default:		return;	} 	assert(entry != NULL); 	if (offset > 0) {		while (offset-- != 0)			entry = browser__next_entry(uib, entry);	} else {		while (offset++ != 0)			entry = browser__prev_entry(uib, entry);	} 	uib->top = &entry->node;} static unsigned int browser__refresh(struct ui_browser *uib){	struct annotated_data_browser *browser = get_browser(uib);	struct browser_entry *entry, *next;	int row = 0; 	if (uib->top == NULL || uib->top == uib->entries)		browser__seek(uib, SEEK_SET, 0); 	entry = list_entry(uib->top, typeof(*entry), node); 	while (true) {		if (!uib->filter || !uib->filter(uib, &entry->node)) {			ui_browser__gotorc(uib, row, 0);			uib->write(uib, entry, row);			if (uib->top_idx + row == uib->index)				browser->curr = entry;			if (++row == uib->rows)				break;		}		next = browser__next_entry(uib, entry);		if (next == entry)			break; 		entry = next;	} 	return row;} static int browser__show(struct ui_browser *uib){	struct hist_entry *he = uib->priv;	struct annotated_data_type *adt = he->mem_type;	struct annotated_data_browser *browser = get_browser(uib);	const char *help = "Press 'h' for help on key bindings";	char title[256]; 	snprintf(title, sizeof(title), "Annotate type: '%s' (%d samples)",		 adt->self.type_name, he->stat.nr_events); 	if (ui_browser__show(uib, title, help) < 0)		return -1; 	/* second line header */	ui_browser__gotorc_title(uib, 0, 0);	ui_browser__set_color(uib, HE_COLORSET_ROOT); 	if (symbol_conf.show_total_period)		strcpy(title, "Period");	else if (symbol_conf.show_nr_samples)		strcpy(title, "Samples");	else		strcpy(title, "Percent"); 	ui_browser__printf(uib, "%*s %10s %10s %10s  %s",			   2 + 11 * (browser->nr_events - 1), "",			   title, "Offset", "Size", "Field");	ui_browser__write_nstring(uib, "", uib->width);	return 0;} static void browser__write_overhead(struct ui_browser *uib,				    struct type_hist *total,				    struct type_hist_entry *hist, int row){	u64 period = hist->period;	double percent = total->period ? (100.0 * period / total->period) : 0;	bool current = ui_browser__is_current_entry(uib, row);	int nr_samples = 0; 	ui_browser__set_percent_color(uib, percent, current); 	if (symbol_conf.show_total_period)		ui_browser__printf(uib, " %10" PRIu64, period);	else if (symbol_conf.show_nr_samples)		ui_browser__printf(uib, " %10d", nr_samples);	else		ui_browser__printf(uib, " %10.2f", percent); 	ui_browser__set_percent_color(uib, 0, current);} static void browser__write(struct ui_browser *uib, void *entry, int row){	struct annotated_data_browser *browser = get_browser(uib);	struct browser_entry *be = entry;	struct annotated_member *member = be->data;	struct hist_entry *he = uib->priv;	struct annotated_data_type *adt = he->mem_type;	struct evsel *leader = hists_to_evsel(he->hists);	struct evsel *evsel;	int idx = 0;	bool current = ui_browser__is_current_entry(uib, row); 	if (member == NULL) {		/* print the closing bracket */		ui_browser__set_percent_color(uib, 0, current);		ui_browser__printf(uib, "%c ", NOCHLD_SIGN);		ui_browser__write_nstring(uib, "", 11 * browser->nr_events);		ui_browser__printf(uib, " %10s %10s  %*s};",				   "", "", be->indent * 4, "");		ui_browser__write_nstring(uib, "", uib->width);		return;	} 	ui_browser__set_percent_color(uib, 0, current); 	if (!list_empty(&be->children))		ui_browser__printf(uib, "%c ", be->folded ? FOLDED_SIGN : UNFOLD_SIGN);	else		ui_browser__printf(uib, "%c ", NOCHLD_SIGN); 	/* print the number */	for_each_group_evsel(evsel, leader) {		struct type_hist *h = adt->histograms[evsel->core.idx]; 		if (symbol_conf.skip_empty &&		    evsel__hists(evsel)->stats.nr_samples == 0)			continue; 		browser__write_overhead(uib, h, &be->hists[idx++], row);	} 	/* print type info */	if (be->indent == 0 && !member->var_name) {		ui_browser__printf(uib, " %#10x %#10x  %s%s",				   member->offset, member->size,				   member->type_name,				   list_empty(&member->children) || be->folded? ";" : " {");	} else {		ui_browser__printf(uib, " %#10x %#10x  %*s%s\t%s%s",				   member->offset, member->size,				   be->indent * 4, "", member->type_name,				   member->var_name ?: "",				   list_empty(&member->children) || be->folded ? ";" : " {");	}	/* fill the rest */	ui_browser__write_nstring(uib, "", uib->width);} static void annotated_data_browser__fold(struct annotated_data_browser *browser,					 struct browser_entry *entry,					 bool recursive){	struct browser_entry *child; 	if (list_empty(&entry->children))		return;	if (entry->folded && !recursive)		return; 	if (recursive) {		list_for_each_entry(child, &entry->children, node)			annotated_data_browser__fold(browser, child, true);	} 	entry->nr_entries = 1;	entry->folded = true;} static void annotated_data_browser__unfold(struct annotated_data_browser *browser,					   struct browser_entry *entry,					   bool recursive){	struct browser_entry *child;	int nr_entries; 	if (list_empty(&entry->children))		return;	if (!entry->folded && !recursive)		return; 	nr_entries = 1; /* for self */	list_for_each_entry(child, &entry->children, node) {		if (recursive)			annotated_data_browser__unfold(browser, child, true); 		nr_entries += child->nr_entries;	} 	entry->nr_entries = nr_entries;	entry->folded = false;} static void annotated_data_browser__toggle_fold(struct annotated_data_browser *browser,						bool recursive){	struct browser_entry *curr = browser->curr;	struct browser_entry *parent; 	parent = curr->parent;	while (parent) {		parent->nr_entries -= curr->nr_entries;		parent = parent->parent;	}	browser->b.nr_entries -= curr->nr_entries;

Lines 1–500 of 614.