Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b5387528 authored by Roberto Agostino Vitillo's avatar Roberto Agostino Vitillo Committed by Ingo Molnar
Browse files

perf tools: Add code to support PERF_SAMPLE_BRANCH_STACK



This patch adds:

 - ability to parse samples with PERF_SAMPLE_BRANCH_STACK
 - sort on branches (dso_from, symbol_from, dso_to, symbol_to, mispredict)
 - build histograms on branches

Signed-off-by: default avatarRoberto Agostino Vitillo <ravitillo@lbl.gov>
Signed-off-by: default avatarStephane Eranian <eranian@google.com>
Cc: peterz@infradead.org
Cc: acme@redhat.com
Cc: robert.richter@amd.com
Cc: ming.m.lin@intel.com
Cc: andi@firstfloor.org
Cc: asharma@fb.com
Cc: vweaver1@eecs.utk.edu
Cc: khandual@linux.vnet.ibm.com
Cc: dsahern@gmail.com
Link: http://lkml.kernel.org/r/1328826068-11713-12-git-send-email-eranian@google.com


Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent d010b332
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -179,6 +179,23 @@ struct ip_callchain {
	u64 ips[0];
};

struct branch_flags {
	u64 mispred:1;
	u64 predicted:1;
	u64 reserved:62;
};

struct branch_entry {
	u64				from;
	u64				to;
	struct branch_flags flags;
};

struct branch_stack {
	u64				nr;
	struct branch_entry	entries[0];
};

extern bool perf_host, perf_guest;
extern const char perf_version_string[];

+1 −0
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ struct perf_sample {
	u32 raw_size;
	void *raw_data;
	struct ip_callchain *callchain;
	struct branch_stack *branch_stack;
};

#define BUILD_ID_SIZE 20
+10 −0
Original line number Diff line number Diff line
@@ -576,6 +576,16 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
		data->raw_data = (void *) pdata;
	}

	if (type & PERF_SAMPLE_BRANCH_STACK) {
		u64 sz;

		data->branch_stack = (struct branch_stack *)array;
		array++; /* nr */

		sz = data->branch_stack->nr * sizeof(struct branch_entry);
		sz /= sizeof(u64);
		array += sz;
	}
	return 0;
}

+95 −27
Original line number Diff line number Diff line
@@ -50,22 +50,26 @@ static void hists__reset_col_len(struct hists *hists)
		hists__set_col_len(hists, col, 0);
}

static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
static void hists__set_unres_dso_col_len(struct hists *hists, int dso)
{
	u16 len;

	if (h->ms.sym)
		hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen);
	else {
	const unsigned int unresolved_col_width = BITS_PER_LONG / 4;

		if (hists__col_len(hists, HISTC_DSO) < unresolved_col_width &&
	if (hists__col_len(hists, dso) < unresolved_col_width &&
	    !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
	    !symbol_conf.dso_list)
			hists__set_col_len(hists, HISTC_DSO,
					   unresolved_col_width);
		hists__set_col_len(hists, dso, unresolved_col_width);
}

static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
{
	const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
	u16 len;

	if (h->ms.sym)
		hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4);
	else
		hists__set_unres_dso_col_len(hists, HISTC_DSO);

	len = thread__comm_len(h->thread);
	if (hists__new_col_len(hists, HISTC_COMM, len))
		hists__set_col_len(hists, HISTC_THREAD, len + 6);
@@ -74,6 +78,37 @@ static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
		len = dso__name_len(h->ms.map->dso);
		hists__new_col_len(hists, HISTC_DSO, len);
	}

	if (h->branch_info) {
		int symlen;
		/*
		 * +4 accounts for '[x] ' priv level info
		 * +2 account of 0x prefix on raw addresses
		 */
		if (h->branch_info->from.sym) {
			symlen = (int)h->branch_info->from.sym->namelen + 4;
			hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);

			symlen = dso__name_len(h->branch_info->from.map->dso);
			hists__new_col_len(hists, HISTC_DSO_FROM, symlen);
		} else {
			symlen = unresolved_col_width + 4 + 2;
			hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
			hists__set_unres_dso_col_len(hists, HISTC_DSO_FROM);
		}

		if (h->branch_info->to.sym) {
			symlen = (int)h->branch_info->to.sym->namelen + 4;
			hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);

			symlen = dso__name_len(h->branch_info->to.map->dso);
			hists__new_col_len(hists, HISTC_DSO_TO, symlen);
		} else {
			symlen = unresolved_col_width + 4 + 2;
			hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
			hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
		}
	}
}

static void hist_entry__add_cpumode_period(struct hist_entry *he,
@@ -195,26 +230,14 @@ static u8 symbol__parent_filter(const struct symbol *parent)
	return 0;
}

struct hist_entry *__hists__add_entry(struct hists *hists,
static struct hist_entry *add_hist_entry(struct hists *hists,
				      struct hist_entry *entry,
				      struct addr_location *al,
				      struct symbol *sym_parent, u64 period)
				      u64 period)
{
	struct rb_node **p;
	struct rb_node *parent = NULL;
	struct hist_entry *he;
	struct hist_entry entry = {
		.thread	= al->thread,
		.ms = {
			.map	= al->map,
			.sym	= al->sym,
		},
		.cpu	= al->cpu,
		.ip	= al->addr,
		.level	= al->level,
		.period	= period,
		.parent = sym_parent,
		.filtered = symbol__parent_filter(sym_parent),
	};
	int cmp;

	pthread_mutex_lock(&hists->lock);
@@ -225,7 +248,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
		parent = *p;
		he = rb_entry(parent, struct hist_entry, rb_node_in);

		cmp = hist_entry__cmp(&entry, he);
		cmp = hist_entry__cmp(entry, he);

		if (!cmp) {
			he->period += period;
@@ -239,7 +262,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
			p = &(*p)->rb_right;
	}

	he = hist_entry__new(&entry);
	he = hist_entry__new(entry);
	if (!he)
		goto out_unlock;

@@ -252,6 +275,51 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
	return he;
}

struct hist_entry *__hists__add_branch_entry(struct hists *self,
					     struct addr_location *al,
					     struct symbol *sym_parent,
					     struct branch_info *bi,
					     u64 period)
{
	struct hist_entry entry = {
		.thread	= al->thread,
		.ms = {
			.map	= bi->to.map,
			.sym	= bi->to.sym,
		},
		.cpu	= al->cpu,
		.ip	= bi->to.addr,
		.level	= al->level,
		.period	= period,
		.parent = sym_parent,
		.filtered = symbol__parent_filter(sym_parent),
		.branch_info = bi,
	};

	return add_hist_entry(self, &entry, al, period);
}

struct hist_entry *__hists__add_entry(struct hists *self,
				      struct addr_location *al,
				      struct symbol *sym_parent, u64 period)
{
	struct hist_entry entry = {
		.thread	= al->thread,
		.ms = {
			.map	= al->map,
			.sym	= al->sym,
		},
		.cpu	= al->cpu,
		.ip	= al->addr,
		.level	= al->level,
		.period	= period,
		.parent = sym_parent,
		.filtered = symbol__parent_filter(sym_parent),
	};

	return add_hist_entry(self, &entry, al, period);
}

int64_t
hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
{
+11 −0
Original line number Diff line number Diff line
@@ -42,6 +42,11 @@ enum hist_column {
	HISTC_COMM,
	HISTC_PARENT,
	HISTC_CPU,
	HISTC_MISPREDICT,
	HISTC_SYMBOL_FROM,
	HISTC_SYMBOL_TO,
	HISTC_DSO_FROM,
	HISTC_DSO_TO,
	HISTC_NR_COLS, /* Last entry */
};

@@ -74,6 +79,12 @@ int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
			 struct hists *hists);
void hist_entry__free(struct hist_entry *);

struct hist_entry *__hists__add_branch_entry(struct hists *self,
					     struct addr_location *al,
					     struct symbol *sym_parent,
					     struct branch_info *bi,
					     u64 period);

void hists__output_resort(struct hists *self);
void hists__output_resort_threaded(struct hists *hists);
void hists__collapse_resort(struct hists *self);
Loading