All of lore.kernel.org
 help / color / mirror / Atom feed
From: Arnaldo Carvalho de Melo <acme@kernel.org>
To: Jin Yao <yao.jin@linux.intel.com>
Cc: jolsa@kernel.org, Linux-kernel@vger.kernel.org,
	ak@linux.intel.com, kan.liang@intel.com, milian.wolff@kdab.com,
	yao.jin@intel.com
Subject: Re: [PATCH v5 2/5] perf report: Find the inline stack for a given address
Date: Fri, 24 Mar 2017 15:37:37 -0300	[thread overview]
Message-ID: <20170324183737.GD5148@kernel.org> (raw)
In-Reply-To: <1489700547-7260-3-git-send-email-yao.jin@linux.intel.com>

Em Fri, Mar 17, 2017 at 05:42:24AM +0800, Jin Yao escreveu:
> It would be useful for perf to support a mode to query the
> inline stack for a given callgraph address. This would simplify
> finding the right code in code that does a lot of inlining.
> 
> The srcline.c has contained the code which supports to translate
> the address to filename:line_nr. This patch just extends the
> function to let it support getting the inline stacks.
> 
> It introduces the inline_list which will store the inline
> function result (filename:line_nr and funcname).
> 
> Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
> Tested-by: Milian Wolff <milian.wolff@kdab.com>
> ---
>  tools/perf/util/srcline.c    | 169 +++++++++++++++++++++++++++++++++++++++++--
>  tools/perf/util/symbol-elf.c |   5 ++
>  tools/perf/util/symbol.h     |   2 +
>  tools/perf/util/util.h       |  16 ++++
>  4 files changed, 187 insertions(+), 5 deletions(-)
> 
> diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
> index 2953c9f..f9d4b47 100644
> --- a/tools/perf/util/srcline.c
> +++ b/tools/perf/util/srcline.c
> @@ -7,6 +7,7 @@
>  #include "util/dso.h"
>  #include "util/util.h"
>  #include "util/debug.h"
> +#include "util/callchain.h"
>  
>  #include "symbol.h"
>  
> @@ -30,6 +31,41 @@ static const char *dso__name(struct dso *dso)
>  	return dso_name;
>  }
>  
> +static int inline_list__append(char *filename, char *funcname, int line_nr,
> +			       struct inline_node *node, struct dso *dso)
> +{
> +	struct inline_list *ilist;
> +	char *demangled;
> +
> +	ilist = zalloc(sizeof(*ilist));
> +	if (ilist == NULL)
> +		return -1;
> +
> +	ilist->filename = filename;
> +	ilist->line_nr = line_nr;
> +
> +	demangled = dso__demangle_sym(dso, 0, funcname);
> +	if (demangled == NULL) {
> +		ilist->funcname = funcname;
> +	} else {
> +		ilist->funcname = demangled;
> +		if (funcname != NULL)
> +			free(funcname);

free() can be fed NULL, I'll simplify this thus

> +	}
> +
> +	list_add_tail(&ilist->list, &node->val);
> +
> +	return 0;
> +}
> +
> +static void inline_list__reverse(struct inline_node *node)
> +{
> +	struct inline_list *ilist, *n;
> +
> +	list_for_each_entry_safe_reverse(ilist, n, &node->val, list)
> +		list_move_tail(&ilist->list, &node->val);
> +}
> +
>  #ifdef HAVE_LIBBFD_SUPPORT
>  
>  /*
> @@ -171,7 +207,7 @@ static void addr2line_cleanup(struct a2l_data *a2l)
>  
>  static int addr2line(const char *dso_name, u64 addr,
>  		     char **file, unsigned int *line, struct dso *dso,
> -		     bool unwind_inlines)
> +		     bool unwind_inlines, struct inline_node *node)
>  {
>  	int ret = 0;
>  	struct a2l_data *a2l = dso->a2l;
> @@ -196,8 +232,21 @@ static int addr2line(const char *dso_name, u64 addr,
>  
>  		while (bfd_find_inliner_info(a2l->abfd, &a2l->filename,
>  					     &a2l->funcname, &a2l->line) &&
> -		       cnt++ < MAX_INLINE_NEST)
> -			;
> +		       cnt++ < MAX_INLINE_NEST) {
> +
> +			if (node != NULL) {
> +				if (inline_list__append(strdup(a2l->filename),
> +							strdup(a2l->funcname),
> +							a2l->line, node,
> +							dso) != 0)
> +					return 0;
> +			}
> +		}
> +
> +		if ((node != NULL) &&
> +		    (callchain_param.order != ORDER_CALLEE)) {
> +			inline_list__reverse(node);
> +		}
>  	}
>  
>  	if (a2l->found && a2l->filename) {
> @@ -223,6 +272,35 @@ void dso__free_a2l(struct dso *dso)
>  	dso->a2l = NULL;
>  }
>  
> +static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
> +	struct dso *dso)
> +{
> +	char *file = NULL;
> +	unsigned int line = 0;
> +	struct inline_node *node;
> +
> +	node = zalloc(sizeof(*node));
> +	if (node == NULL) {
> +		perror("not enough memory for the inline node");
> +		return NULL;
> +	}
> +
> +	INIT_LIST_HEAD(&node->val);
> +	node->addr = addr;
> +
> +	if (!addr2line(dso_name, addr, &file, &line, dso, TRUE, node))
> +		goto out_free_inline_node;
> +
> +	if (list_empty(&node->val))
> +		goto out_free_inline_node;
> +
> +	return node;
> +
> +out_free_inline_node:
> +	inline_node__delete(node);
> +	return NULL;
> +}
> +
>  #else /* HAVE_LIBBFD_SUPPORT */
>  
>  static int filename_split(char *filename, unsigned int *line_nr)
> @@ -249,7 +327,8 @@ static int filename_split(char *filename, unsigned int *line_nr)
>  static int addr2line(const char *dso_name, u64 addr,
>  		     char **file, unsigned int *line_nr,
>  		     struct dso *dso __maybe_unused,
> -		     bool unwind_inlines __maybe_unused)
> +		     bool unwind_inlines __maybe_unused,
> +		     struct inline_node *node __maybe_unused)
>  {
>  	FILE *fp;
>  	char cmd[PATH_MAX];
> @@ -288,6 +367,57 @@ void dso__free_a2l(struct dso *dso __maybe_unused)
>  {
>  }
>  
> +static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
> +	struct dso *dso __maybe_unused)
> +{
> +	FILE *fp;
> +	char cmd[PATH_MAX];
> +	struct inline_node *node;
> +	char *filename = NULL;
> +	size_t len;
> +	unsigned int line_nr = 0;
> +
> +	scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i %016"PRIx64,
> +		  dso_name, addr);
> +
> +	fp = popen(cmd, "r");
> +	if (fp == NULL) {
> +		pr_err("popen failed for %s\n", dso_name);
> +		return NULL;
> +	}
> +
> +	node = zalloc(sizeof(*node));
> +	if (node == NULL) {
> +		perror("not enough memory for the inline node");
> +		goto out;
> +	}
> +
> +	INIT_LIST_HEAD(&node->val);
> +	node->addr = addr;
> +
> +	while (getline(&filename, &len, fp) != -1) {
> +		if (filename_split(filename, &line_nr) != 1) {
> +			free(filename);
> +			goto out;
> +		}
> +
> +		if (inline_list__append(filename, NULL, line_nr, node) != 0)
> +			goto out;
> +
> +		filename = NULL;
> +	}
> +
> +out:
> +	pclose(fp);
> +
> +	if (list_empty(&node->val)) {
> +		inline_node__delete(node);
> +		return NULL;
> +	}
> +
> +	return node;
> +}
> +
>  #endif /* HAVE_LIBBFD_SUPPORT */
>  
>  /*
> @@ -311,7 +441,7 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
>  	if (dso_name == NULL)
>  		goto out;
>  
> -	if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines))
> +	if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines, NULL))
>  		goto out;
>  
>  	if (asprintf(&srcline, "%s:%u",
> @@ -351,3 +481,32 @@ char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
>  {
>  	return __get_srcline(dso, addr, sym, show_sym, false);
>  }
> +
> +struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr)
> +{
> +	const char *dso_name;
> +
> +	dso_name = dso__name(dso);
> +	if (dso_name == NULL)
> +		return NULL;
> +
> +	return addr2inlines(dso_name, addr, dso);
> +}
> +
> +void inline_node__delete(struct inline_node *node)
> +{
> +	struct inline_list *ilist, *tmp;
> +
> +	list_for_each_entry_safe(ilist, tmp, &node->val, list) {
> +		list_del_init(&ilist->list);
> +		if (ilist->filename != NULL)
> +			free(ilist->filename);
> +
> +		if (ilist->funcname != NULL)
> +			free(ilist->funcname);
> +
> +		free(ilist);
> +	}
> +
> +	free(node);
> +}
> diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
> index 4e59dde..3a1dda3 100644
> --- a/tools/perf/util/symbol-elf.c
> +++ b/tools/perf/util/symbol-elf.c
> @@ -390,6 +390,11 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *
>  	return 0;
>  }
>  
> +char *dso__demangle_sym(struct dso *dso, int kmodule, char *elf_name)
> +{
> +	return demangle_sym(dso, kmodule, elf_name);
> +}
> +
>  /*
>   * Align offset to 4 bytes as needed for note name and descriptor data.
>   */
> diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
> index 6c358b7..8adf045 100644
> --- a/tools/perf/util/symbol.h
> +++ b/tools/perf/util/symbol.h
> @@ -305,6 +305,8 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
>  int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss,
>  				struct map *map);
>  
> +char *dso__demangle_sym(struct dso *dso, int kmodule, char *elf_name);
> +
>  void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel);
>  void symbols__insert(struct rb_root *symbols, struct symbol *sym);
>  void symbols__fixup_duplicate(struct rb_root *symbols);
> diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
> index b2cfa47..cc0700d 100644
> --- a/tools/perf/util/util.h
> +++ b/tools/perf/util/util.h
> @@ -364,4 +364,20 @@ int is_printable_array(char *p, unsigned int len);
>  int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz);
>  
>  int unit_number__scnprintf(char *buf, size_t size, u64 n);
> +
> +struct inline_list {
> +	char			*filename;
> +	char			*funcname;
> +	unsigned int		line_nr;
> +	struct list_head	list;
> +};
> +
> +struct inline_node {
> +	u64			addr;
> +	struct list_head	val;
> +};
> +
> +struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr);
> +void inline_node__delete(struct inline_node *node);
> +
>  #endif /* GIT_COMPAT_UTIL_H */
> -- 
> 2.7.4

  reply	other threads:[~2017-03-24 18:37 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-03-16 21:42 [PATCH v5 0/5] perf report: Show inline stack Jin Yao
2017-03-16 21:42 ` [PATCH v5 1/5] perf report: Refactor common code in srcline.c Jin Yao
2017-03-16 21:42 ` [PATCH v5 2/5] perf report: Find the inline stack for a given address Jin Yao
2017-03-24 18:37   ` Arnaldo Carvalho de Melo [this message]
2017-03-25  7:18   ` Ravi Bangoria
2017-03-25 12:45     ` Jin, Yao
2017-03-16 21:42 ` [PATCH v5 3/5] perf report: Create new inline option Jin Yao
2017-03-16 21:42 ` [PATCH v5 4/5] perf report: Show inline stack for stdio mode Jin Yao
2017-03-16 21:42 ` [PATCH v5 5/5] perf report: Show inline stack for browser mode Jin Yao
2017-03-18 16:41 ` [PATCH v5 0/5] perf report: Show inline stack Milian Wolff
2017-03-24 19:01   ` Arnaldo Carvalho de Melo
2017-03-24 19:24     ` Arnaldo Carvalho de Melo
2017-03-25  0:20       ` Jin, Yao

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=20170324183737.GD5148@kernel.org \
    --to=acme@kernel.org \
    --cc=Linux-kernel@vger.kernel.org \
    --cc=ak@linux.intel.com \
    --cc=jolsa@kernel.org \
    --cc=kan.liang@intel.com \
    --cc=milian.wolff@kdab.com \
    --cc=yao.jin@intel.com \
    --cc=yao.jin@linux.intel.com \
    /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.