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

Commit 98a3b32c authored by Stephane Eranian's avatar Stephane Eranian Committed by Arnaldo Carvalho de Melo
Browse files

perf tools: Add mem access sampling core support



This patch adds the sorting and histogram support
functions to enable profiling of memory accesses.

The following sorting orders are added:
 - symbol_daddr: data address symbol (or raw address)
 - dso_daddr: data address shared object
 - locked: access uses locked transaction
 - tlb : TLB access
 - mem : memory level of the access (L1, L2, L3, RAM, ...)
 - snoop: access snoop mode

Signed-off-by: default avatarStephane Eranian <eranian@google.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1359040242-8269-12-git-send-email-eranian@google.com


[ committer note: changed to cope with fc5871ed, the move of methods to
  machine.[ch], and the rename of dsrc to data_src, to match the change
  made in the PERF_SAMPLE_DSRC in a previous patch. ]
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 05484298
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ struct perf_sample {
	u64 weight;
	u32 cpu;
	u32 raw_size;
	u64 data_src;
	void *raw_data;
	struct ip_callchain *callchain;
	struct branch_stack *branch_stack;
@@ -98,6 +99,13 @@ struct perf_sample {
	struct stack_dump user_stack;
};

#define PERF_MEM_DATA_SRC_NONE \
	(PERF_MEM_S(OP, NA) |\
	 PERF_MEM_S(LVL, NA) |\
	 PERF_MEM_S(SNOOP, NA) |\
	 PERF_MEM_S(LOCK, NA) |\
	 PERF_MEM_S(TLB, NA))

struct build_id_event {
	struct perf_event_header header;
	pid_t			 pid;
+6 −0
Original line number Diff line number Diff line
@@ -1177,6 +1177,12 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
		array++;
	}

	data->data_src = PERF_MEM_DATA_SRC_NONE;
	if (type & PERF_SAMPLE_DATA_SRC) {
		data->data_src = *array;
		array++;
	}

	return 0;
}

+83 −3
Original line number Diff line number Diff line
@@ -67,12 +67,16 @@ static void hists__set_unres_dso_col_len(struct hists *hists, int dso)
void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
{
	const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
	int symlen;
	u16 len;

	if (h->ms.sym)
		hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4);
	else
	else {
		symlen = unresolved_col_width + 4 + 2;
		hists__new_col_len(hists, HISTC_SYMBOL, symlen);
		hists__set_unres_dso_col_len(hists, HISTC_DSO);
	}

	len = thread__comm_len(h->thread);
	if (hists__new_col_len(hists, HISTC_COMM, len))
@@ -87,7 +91,6 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
		hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);

	if (h->branch_info) {
		int symlen;
		/*
		 * +4 accounts for '[x] ' priv level info
		 * +2 account of 0x prefix on raw addresses
@@ -116,6 +119,42 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
			hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
		}
	}

	if (h->mem_info) {
		/*
		 * +4 accounts for '[x] ' priv level info
		 * +2 account of 0x prefix on raw addresses
		 */
		if (h->mem_info->daddr.sym) {
			symlen = (int)h->mem_info->daddr.sym->namelen + 4
			       + unresolved_col_width + 2;
			hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
					   symlen);
		} else {
			symlen = unresolved_col_width + 4 + 2;
			hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
					   symlen);
		}
		if (h->mem_info->daddr.map) {
			symlen = dso__name_len(h->mem_info->daddr.map->dso);
			hists__new_col_len(hists, HISTC_MEM_DADDR_DSO,
					   symlen);
		} else {
			symlen = unresolved_col_width + 4 + 2;
			hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
		}
	} else {
		symlen = unresolved_col_width + 4 + 2;
		hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen);
		hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
	}

	hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
	hists__new_col_len(hists, HISTC_MEM_TLB, 22);
	hists__new_col_len(hists, HISTC_MEM_SNOOP, 12);
	hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3);
	hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
	hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
}

void hists__output_recalc_col_len(struct hists *hists, int max_rows)
@@ -158,6 +197,7 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he,
static void he_stat__add_period(struct he_stat *he_stat, u64 period,
				u64 weight)
{

	he_stat->period		+= period;
	he_stat->weight		+= weight;
	he_stat->nr_events	+= 1;
@@ -243,7 +283,7 @@ void hists__decay_entries_threaded(struct hists *hists,
static struct hist_entry *hist_entry__new(struct hist_entry *template)
{
	size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
	struct hist_entry *he = malloc(sizeof(*he) + callchain_size);
	struct hist_entry *he = zalloc(sizeof(*he) + callchain_size);

	if (he != NULL) {
		*he = *template;
@@ -258,6 +298,13 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
				he->branch_info->to.map->referenced = true;
		}

		if (he->mem_info) {
			if (he->mem_info->iaddr.map)
				he->mem_info->iaddr.map->referenced = true;
			if (he->mem_info->daddr.map)
				he->mem_info->daddr.map->referenced = true;
		}

		if (symbol_conf.use_callchain)
			callchain_init(he->callchain);

@@ -346,6 +393,36 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
	return he;
}

struct hist_entry *__hists__add_mem_entry(struct hists *self,
					  struct addr_location *al,
					  struct symbol *sym_parent,
					  struct mem_info *mi,
					  u64 period,
					  u64 weight)
{
	struct hist_entry entry = {
		.thread	= al->thread,
		.ms = {
			.map	= al->map,
			.sym	= al->sym,
		},
		.stat = {
			.period	= period,
			.weight = weight,
			.nr_events = 1,
		},
		.cpu	= al->cpu,
		.ip	= al->addr,
		.level	= al->level,
		.parent = sym_parent,
		.filtered = symbol__parent_filter(sym_parent),
		.hists = self,
		.mem_info = mi,
		.branch_info = NULL,
	};
	return add_hist_entry(self, &entry, al, period, weight);
}

struct hist_entry *__hists__add_branch_entry(struct hists *self,
					     struct addr_location *al,
					     struct symbol *sym_parent,
@@ -371,6 +448,7 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
		.filtered = symbol__parent_filter(sym_parent),
		.branch_info = bi,
		.hists	= self,
		.mem_info = NULL,
	};

	return add_hist_entry(self, &entry, al, period, weight);
@@ -398,6 +476,8 @@ struct hist_entry *__hists__add_entry(struct hists *self,
		.parent = sym_parent,
		.filtered = symbol__parent_filter(sym_parent),
		.hists	= self,
		.branch_info = NULL,
		.mem_info = NULL,
	};

	return add_hist_entry(self, &entry, al, period, weight);
+13 −0
Original line number Diff line number Diff line
@@ -51,6 +51,12 @@ enum hist_column {
	HISTC_SRCLINE,
	HISTC_LOCAL_WEIGHT,
	HISTC_GLOBAL_WEIGHT,
	HISTC_MEM_DADDR_SYMBOL,
	HISTC_MEM_DADDR_DSO,
	HISTC_MEM_LOCKED,
	HISTC_MEM_TLB,
	HISTC_MEM_LVL,
	HISTC_MEM_SNOOP,
	HISTC_NR_COLS, /* Last entry */
};

@@ -90,6 +96,13 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
					     u64 period,
					     u64 weight);

struct hist_entry *__hists__add_mem_entry(struct hists *self,
					  struct addr_location *al,
					  struct symbol *sym_parent,
					  struct mem_info *mi,
					  u64 period,
					  u64 weight);

void hists__output_resort(struct hists *self);
void hists__output_resort_threaded(struct hists *hists);
void hists__collapse_resort(struct hists *self);
+32 −0
Original line number Diff line number Diff line
@@ -1097,6 +1097,38 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread,
	ams->map = al.map;
}

static void ip__resolve_data(struct machine *machine, struct thread *thread,
			     u8 m, struct addr_map_symbol *ams, u64 addr)
{
	struct addr_location al;

	memset(&al, 0, sizeof(al));

	thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, &al,
				   NULL);
	ams->addr = addr;
	ams->al_addr = al.addr;
	ams->sym = al.sym;
	ams->map = al.map;
}

struct mem_info *machine__resolve_mem(struct machine *machine,
				      struct thread *thr,
				      struct perf_sample *sample,
				      u8 cpumode)
{
	struct mem_info *mi = zalloc(sizeof(*mi));

	if (!mi)
		return NULL;

	ip__resolve_ams(machine, thr, &mi->iaddr, sample->ip);
	ip__resolve_data(machine, thr, cpumode, &mi->daddr, sample->addr);
	mi->data_src.val = sample->data_src;

	return mi;
}

struct branch_info *machine__resolve_bstack(struct machine *machine,
					    struct thread *thr,
					    struct branch_stack *bs)
Loading