All of lore.kernel.org
 help / color / mirror / Atom feed
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
To: Lin Ming <ming.m.lin@intel.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>,
	Peter Zijlstra <peterz@infradead.org>,
	Frederic Weisbecker <fweisbec@gmail.com>,
	LKML <linux-kernel@vger.kernel.org>,
	"2nddept-manager@sdl.hitachi.co.jp" 
	<2nddept-manager@sdl.hitachi.co.jp>
Subject: Re: [RFC PATCH] perf report: add sort by file lines
Date: Tue, 29 Mar 2011 18:46:16 +0900	[thread overview]
Message-ID: <4D91AA68.1040704@hitachi.com> (raw)
In-Reply-To: <1301391136.14111.98.camel@minggr.sh.intel.com>

(2011/03/29 18:32), Lin Ming wrote:
> Hi, all
> 
> This patch adds sort by file lines using dwarf debug info.
> 
> In order to add perf tool support for my load latency patches,
> I asked a question about data variable symbols.
> http://marc.info/?l=linux-kernel&m=129736540309559&w=2 
> 
> Peter suggested to reverse map the reported IP (PEBS + fixup)
> to a data access using dwarf info.
> So I wrote this patch to see if the direction is right.

Good work! :)
Hmm, this seems to require my series of patches which introduce
debuginfo object, which wraps strongly libdw dependent Dwarf/Dwfl
objects and allows us to export debuginfo object even if no libdw
support.
I'll post the series soon!

> 
> On Fri, Feb 11, 2011 at 3:17 AM, Peter Zijlstra <peterz@infradead.org> wrote:
>> Another way is to reverse map the reported IP (PEBS + fixup) to a data
>> access using the dwarf info. That would also work for dynamically
>> allocated data structures.
>>
>> (clearly you'd loose variable things like which entry in an array, but
>> you should still be able to identify the structure members)
>>
> 
> $ ./perf report --stdio -k ~/vmlinux -s comm,dso,symbol,line
> 
> # Overhead      Command      Shared Object            Symbol                                           Line
> # ........  ...........  ..................  ...............  ..............................................
> 
>      0.99%          cc1  [kernel.kallsyms]   [k] check_bytes  /opt/linux-2.6/mm/slub.c:511                         
>      0.84%       fixdep  [kernel.kallsyms]   [k] check_bytes  /opt/linux-2.6/mm/slub.c:510                         
>      0.79%       fixdep  [kernel.kallsyms]   [k] check_bytes  /opt/linux-2.6/mm/slub.c:511                         
>      0.74%          cc1  [kernel.kallsyms]   [k] check_bytes  /opt/linux-2.6/mm/slub.c:513                         
>      0.71%       fixdep  [kernel.kallsyms]   [k] check_bytes  /opt/linux-2.6/mm/slub.c:513                         
>      0.71%          cc1  [kernel.kallsyms]   [k] page_fault   /opt/linux-2.6/arch/x86/kernel/entry_64.S:1336       
>      0.69%          cc1  cc1                 [.] 0x5ec3a3     0x5ec3a3                                             
>      0.67%          cc1  [kernel.kallsyms]   [k] clear_page_c /opt/linux-2.6/arch/x86/lib/clear_page_64.S:12  
> 
> 
> Signed-off-by: Lin Ming <ming.m.lin@intel.com>
> ---
>  tools/perf/util/hist.c   |   71 ++++++++++++++++++++++++++++++++++++++-------
>  tools/perf/util/hist.h   |    4 ++
>  tools/perf/util/sort.c   |   44 ++++++++++++++++++++++++++--
>  tools/perf/util/sort.h   |    3 ++
>  tools/perf/util/symbol.c |    4 ++
>  tools/perf/util/symbol.h |    2 +
>  6 files changed, 114 insertions(+), 14 deletions(-)
> 
> diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
> index 627a02e..c1e95e4 100644
> --- a/tools/perf/util/hist.c
> +++ b/tools/perf/util/hist.c
> @@ -17,6 +17,38 @@ struct callchain_param	callchain_param = {
>  	.min_percent = 0.5
>  };
>  
> +static Dwarf_Line *hists__dwarf_line(struct map *map, u64 rip)
> +{
> +	Dwarf_Die cudie;
> +	Dwarf_Line *line = NULL;
> +	u64 ip;
> +
> +	if (!map || !map->dso || !map->dso->dwarf)
> +		return NULL;
> +
> +	ip = map->unmap_ip(map, rip);
> +	if (dwarf_addrdie(map->dso->dwarf, (Dwarf_Addr)ip, &cudie))
> +		line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)ip);
> +
> +	return line;
> +}
> +
> +int hists__line(Dwarf_Line *line, char *buf, int len)
> +{
> +	int ret;
> +	const char *file;
> +	int lineno;
> +
> +	if (!line || !buf)
> +		return 0;
> +
> +	file = dwarf_linesrc(line, NULL, NULL);   
> +	dwarf_lineno(line, &lineno);
> +	ret = snprintf(buf, len, "%s:%d", file, lineno);
> +
> +	return ret;
> +}
> +
>  u16 hists__col_len(struct hists *self, enum hist_column col)
>  {
>  	return self->col_len[col];
> @@ -44,21 +76,25 @@ static void hists__reset_col_len(struct hists *self)
>  		hists__set_col_len(self, col, 0);
>  }
>  
> +static void hists__set_unresolved_col_len(struct hists *self, enum hist_column col)
> +{
> +	const unsigned int unresolved_col_width = BITS_PER_LONG / 4 + 2;
> +
> +	if (hists__col_len(self, col) < unresolved_col_width &&
> +	    !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
> +	    !symbol_conf.dso_list)
> +		hists__set_col_len(self, col,
> +				   unresolved_col_width);
> +}
> +
>  static void hists__calc_col_len(struct hists *self, struct hist_entry *h)
>  {
>  	u16 len;
>  
>  	if (h->ms.sym)
> -		hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen);
> -	else {
> -		const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
> -
> -		if (hists__col_len(self, HISTC_DSO) < unresolved_col_width &&
> -		    !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
> -		    !symbol_conf.dso_list)
> -			hists__set_col_len(self, HISTC_DSO,
> -					   unresolved_col_width);
> -	}
> +		hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen + 4);
> +	else
> +		hists__set_unresolved_col_len(self, HISTC_DSO);
>  
>  	len = thread__comm_len(h->thread);
>  	if (hists__new_col_len(self, HISTC_COMM, len))
> @@ -68,6 +104,15 @@ static void hists__calc_col_len(struct hists *self, struct hist_entry *h)
>  		len = dso__name_len(h->ms.map->dso);
>  		hists__new_col_len(self, HISTC_DSO, len);
>  	}
> +
> +	if (!h->line)
> +		hists__set_unresolved_col_len(self, HISTC_LINE);
> +	else {
> +		char tmp[BUFSIZ];
> +
> +		len = hists__line(h->line, tmp, BUFSIZ);
> +		hists__new_col_len(self, HISTC_LINE, len);
> +	}
>  }
>  
>  static void hist_entry__add_cpumode_period(struct hist_entry *self,
> @@ -103,8 +148,11 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
>  	if (self != NULL) {
>  		*self = *template;
>  		self->nr_events = 1;
> -		if (self->ms.map)
> +		if (self->ms.map) {
>  			self->ms.map->referenced = true;
> +
> +			self->line = hists__dwarf_line(self->ms.map, self->ip); 
> +		}
>  		if (symbol_conf.use_callchain)
>  			callchain_init(self->callchain);
>  	}
> @@ -142,6 +190,7 @@ struct hist_entry *__hists__add_entry(struct hists *self,
>  		},
>  		.cpu	= al->cpu,
>  		.ip	= al->addr,
> +		.line	= hists__dwarf_line(al->map, al->addr),
>  		.level	= al->level,
>  		.period	= period,
>  		.parent = sym_parent,
> diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
> index 3beb97c..07e0f04 100644
> --- a/tools/perf/util/hist.h
> +++ b/tools/perf/util/hist.h
> @@ -3,6 +3,7 @@
>  
>  #include <linux/types.h>
>  #include "callchain.h"
> +#include <elfutils/libdw.h>
>  
>  extern struct callchain_param callchain_param;
>  
> @@ -39,6 +40,7 @@ enum hist_column {
>  	HISTC_COMM,
>  	HISTC_PARENT,
>  	HISTC_CPU,
> +	HISTC_LINE,
>  	HISTC_NR_COLS, /* Last entry */
>  };
>  
> @@ -85,6 +87,8 @@ u16 hists__col_len(struct hists *self, enum hist_column col);
>  void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
>  bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len);
>  
> +int hists__line(Dwarf_Line *line, char *buf, int len);
> +
>  struct perf_evlist;
>  
>  #ifdef NO_NEWT_SUPPORT
> diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
> index f44fa54..cfbdb6c 100644
> --- a/tools/perf/util/sort.c
> +++ b/tools/perf/util/sort.c
> @@ -27,6 +27,9 @@ static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
>  				       size_t size, unsigned int width);
>  static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
>  				    size_t size, unsigned int width);
> +static int hist_entry__line_snprintf(struct hist_entry *self, char *bf,
> +				    size_t size, unsigned int width);
> +
>  
>  struct sort_entry sort_thread = {
>  	.se_header	= "Command:  Pid",
> @@ -71,6 +74,13 @@ struct sort_entry sort_cpu = {
>  	.se_width_idx	= HISTC_CPU,
>  };
>  
> +struct sort_entry sort_line = {
> +	.se_header      = "Line",
> +	.se_cmp	        = sort__line_cmp,
> +	.se_snprintf    = hist_entry__line_snprintf,
> +	.se_width_idx	= HISTC_LINE,
> +};
> +
>  struct sort_dimension {
>  	const char		*name;
>  	struct sort_entry	*entry;
> @@ -84,6 +94,7 @@ static struct sort_dimension sort_dimensions[] = {
>  	{ .name = "symbol",	.entry = &sort_sym,	},
>  	{ .name = "parent",	.entry = &sort_parent,	},
>  	{ .name = "cpu",	.entry = &sort_cpu,	},
> +	{ .name = "line",	.entry = &sort_line,	},
>  };
>  
>  int64_t cmp_null(void *l, void *r)
> @@ -190,7 +201,7 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
>  }
>  
>  static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
> -				    size_t size, unsigned int width __used)
> +				    size_t size, unsigned int width)
>  {
>  	size_t ret = 0;
>  
> @@ -202,11 +213,11 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
>  
>  	ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
>  	if (self->ms.sym)
> -		ret += repsep_snprintf(bf + ret, size - ret, "%s",
> +		ret += repsep_snprintf(bf + ret, size - ret, "%-*s", width - 4,
>  				       self->ms.sym->name);
>  	else
>  		ret += repsep_snprintf(bf + ret, size - ret, "%-#*llx",
> -				       BITS_PER_LONG / 4, self->ip);
> +				       width - 4, self->ip);
>  
>  	return ret;
>  }
> @@ -266,6 +277,31 @@ static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
>  	return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
>  }
>  
> +
> +/* --sort line */
> +
> +int64_t
> +sort__line_cmp(struct hist_entry *left, struct hist_entry *right)
> +{
> +	if (!left->line || !right->line)
> +		return (int64_t)(left->ip - right->ip);
> +
> +	return (unsigned long)left->line - (unsigned long)right->line;
> +}
> +
> +static int hist_entry__line_snprintf(struct hist_entry *self, char *bf,
> +				       size_t size, unsigned int width)
> +{
> +	char buf[BUFSIZ];
> +
> +	if (!self->line)
> +		return repsep_snprintf(bf, size, "%-#*llx", width, self->ip);
> +
> +	hists__line(self->line, buf, BUFSIZ);
> +
> +	return repsep_snprintf(bf, size, "%-*s", width, buf);
> +}
> +
>  int sort_dimension__add(const char *tok)
>  {
>  	unsigned int i;
> @@ -307,6 +343,8 @@ int sort_dimension__add(const char *tok)
>  				sort__first_dimension = SORT_PARENT;
>  			else if (!strcmp(sd->name, "cpu"))
>  				sort__first_dimension = SORT_CPU;
> +			else if (!strcmp(sd->name, "line"))
> +				sort__first_dimension = SORT_LINE;
>  		}
>  
>  		list_add_tail(&sd->entry->list, &hist_entry__sort_list);
> diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
> index 0b91053..d2a4424 100644
> --- a/tools/perf/util/sort.h
> +++ b/tools/perf/util/sort.h
> @@ -53,6 +53,7 @@ struct hist_entry {
>  	u64			period_guest_us;
>  	struct map_symbol	ms;
>  	struct thread		*thread;
> +	Dwarf_Line		*line;
>  	u64			ip;
>  	s32			cpu;
>  	u32			nr_events;
> @@ -80,6 +81,7 @@ enum sort_type {
>  	SORT_SYM,
>  	SORT_PARENT,
>  	SORT_CPU,
> +	SORT_LINE,
>  };
>  
>  /*
> @@ -116,6 +118,7 @@ extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
>  extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
>  extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
>  int64_t sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right);
> +int64_t sort__line_cmp(struct hist_entry *left, struct hist_entry *right);
>  extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
>  extern int sort_dimension__add(const char *);
>  void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> index 17df793..ddaf396 100644
> --- a/tools/perf/util/symbol.c
> +++ b/tools/perf/util/symbol.c
> @@ -240,6 +240,8 @@ void dso__delete(struct dso *self)
>  		free((char *)self->short_name);
>  	if (self->lname_alloc)
>  		free(self->long_name);
> +	if (self->dwarf)
> +		dwarf_end(self->dwarf);
>  	free(self);
>  }
>  
> @@ -1052,6 +1054,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
>  	int nr = 0;
>  	size_t opdidx = 0;
>  
> +	self->dwarf = dwarf_begin(fd, DWARF_C_READ);
> +
>  	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
>  	if (elf == NULL) {
>  		pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
> diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
> index 713b0b4..e07b907 100644
> --- a/tools/perf/util/symbol.h
> +++ b/tools/perf/util/symbol.h
> @@ -8,6 +8,7 @@
>  #include <linux/list.h>
>  #include <linux/rbtree.h>
>  #include <stdio.h>
> +#include <elfutils/libdw.h>
>  
>  #ifdef HAVE_CPLUS_DEMANGLE
>  extern char *cplus_demangle(const char *, int);
> @@ -135,6 +136,7 @@ struct dso {
>  	struct list_head node;
>  	struct rb_root	 symbols[MAP__NR_TYPES];
>  	struct rb_root	 symbol_names[MAP__NR_TYPES];
> +	Dwarf		 *dwarf;
>  	enum dso_kernel_type	kernel;
>  	u8		 adjust_symbols:1;
>  	u8		 has_build_id:1;
> 
> 


-- 
Masami HIRAMATSU
2nd Dept. Linux Technology Center
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

  reply	other threads:[~2011-03-29  9:46 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-03-29  9:32 [RFC PATCH] perf report: add sort by file lines Lin Ming
2011-03-29  9:46 ` Masami Hiramatsu [this message]
2011-03-29  9:54 ` Peter Zijlstra
2011-03-29 16:45   ` Lin Ming
2011-03-29 17:03     ` Peter Zijlstra
2011-03-29 17:06       ` Peter Zijlstra
2011-03-29 17:08         ` Peter Zijlstra
2011-03-29 17:45           ` Arnaldo Carvalho de Melo
2011-03-30  1:04             ` Masami Hiramatsu
2011-03-30  2:18               ` Arnaldo Carvalho de Melo
2011-03-31  6:57               ` Lin Ming
2011-04-01 10:48                 ` Masami Hiramatsu
2011-03-31  8:45               ` Lin Ming
2011-03-31 13:46                 ` Arnaldo Carvalho de Melo
2011-03-31 14:19                   ` Lin Ming
2011-03-31 15:35                     ` Arnaldo Carvalho de Melo
2011-03-31 14:01                 ` Peter Zijlstra
2011-03-31 14:34                   ` Lin Ming
2011-03-31 14:51                     ` Lin Ming
2011-03-31 16:28                     ` Peter Zijlstra
2011-03-31 16:32                       ` Peter Zijlstra
2011-04-01 13:02                         ` Lin Ming
2011-04-01 13:48                           ` Peter Zijlstra
2011-04-01 10:44                       ` Masami Hiramatsu
2011-04-01 11:05                         ` Peter Zijlstra
2011-04-01 13:22                           ` Lin Ming
2011-04-01 13:49                             ` Peter Zijlstra
2011-04-01 13:57                               ` Lin Ming

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4D91AA68.1040704@hitachi.com \
    --to=masami.hiramatsu.pt@hitachi.com \
    --cc=2nddept-manager@sdl.hitachi.co.jp \
    --cc=acme@redhat.com \
    --cc=fweisbec@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ming.m.lin@intel.com \
    --cc=peterz@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.