From: Jin Yao <yao.jin@linux.intel.com>
To: acme@kernel.org, jolsa@kernel.org
Cc: Linux-kernel@vger.kernel.org, ak@linux.intel.com,
kan.liang@intel.com, yao.jin@linux.intel.com
Subject: [PATCH v2 2/5] perf report: Find the inline stack for a given address
Date: Wed, 7 Dec 2016 21:30:21 +0800 [thread overview]
Message-ID: <1481117424-20673-3-git-send-email-yao.jin@linux.intel.com> (raw)
In-Reply-To: <1481117424-20673-1-git-send-email-yao.jin@linux.intel.com>
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 (format is filename:line_nr).
Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
---
tools/perf/util/srcline.c | 139 ++++++++++++++++++++++++++++++++++++++++++++--
tools/perf/util/util.h | 14 +++++
2 files changed, 148 insertions(+), 5 deletions(-)
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index 2953c9f..84be07d 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -30,6 +30,22 @@ static const char *dso__name(struct dso *dso)
return dso_name;
}
+static int inline_list__append(char *filename, int line_nr,
+ struct inline_node *node)
+{
+ struct inline_list *ilist;
+
+ ilist = zalloc(sizeof(*ilist));
+ if (ilist == NULL)
+ return -1;
+
+ ilist->filename = filename;
+ ilist->line_nr = line_nr;
+ list_add_tail(&ilist->list, &node->val);
+
+ return 0;
+}
+
#ifdef HAVE_LIBBFD_SUPPORT
/*
@@ -171,7 +187,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 +212,14 @@ 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),
+ a2l->line, node) != 0)
+ return 0;
+ }
+ }
}
if (a2l->found && a2l->filename) {
@@ -223,6 +245,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)) {
+ inline_node__free(node);
+ return NULL;
+ }
+
+ if (list_empty(&node->val)) {
+ inline_node__free(node);
+ return NULL;
+ }
+
+ return node;
+}
+
#else /* HAVE_LIBBFD_SUPPORT */
static int filename_split(char *filename, unsigned int *line_nr)
@@ -249,7 +300,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 +340,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, line_nr, node) != 0)
+ goto out;
+
+ filename = NULL;
+ }
+
+out:
+ pclose(fp);
+
+ if (list_empty(&node->val)) {
+ inline_node__free(node);
+ return NULL;
+ }
+
+ return node;
+}
+
#endif /* HAVE_LIBBFD_SUPPORT */
/*
@@ -311,7 +414,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 +454,29 @@ char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
{
return __get_srcline(dso, addr, sym, show_sym, false);
}
+
+struct inline_node *inline__node(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__free(struct inline_node *node)
+{
+ struct inline_list *ilist, *tmp;
+
+ list_for_each_entry_safe(ilist, tmp, &node->val, list) {
+ list_del(&ilist->list);
+ if (ilist->filename != NULL)
+ free(ilist->filename);
+
+ free(ilist);
+ }
+
+ free(node);
+}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 1d639e3..74b7db0 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -363,4 +363,18 @@ int is_printable_array(char *p, unsigned int len);
int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz);
+struct inline_list {
+ char *filename;
+ unsigned int line_nr;
+ struct list_head list;
+};
+
+struct inline_node {
+ u64 addr;
+ struct list_head val;
+};
+
+struct inline_node *inline__node(struct dso *dso, u64 addr);
+void inline_node__free(struct inline_node *node);
+
#endif /* GIT_COMPAT_UTIL_H */
--
2.7.4
next prev parent reply other threads:[~2016-12-07 5:31 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-12-07 13:30 [PATCH v2 0/5] perf report: Show inline stack Jin Yao
2016-12-07 5:38 ` Jin, Yao
2016-12-07 14:30 ` Arnaldo Carvalho de Melo
2016-12-08 0:41 ` Jin, Yao
2016-12-07 13:30 ` [PATCH v2 1/5] perf report: Refactor common code in srcline.c Jin Yao
2016-12-07 13:30 ` Jin Yao [this message]
2016-12-07 13:30 ` [PATCH v2 3/5] perf report: Create a new option "--inline" Jin Yao
2016-12-07 13:30 ` [PATCH v2 4/5] perf report: Show inline stack in stdio mode Jin Yao
2016-12-07 13:30 ` [PATCH v2 5/5] perf report: Show inline stack in browser mode 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=1481117424-20673-3-git-send-email-yao.jin@linux.intel.com \
--to=yao.jin@linux.intel.com \
--cc=Linux-kernel@vger.kernel.org \
--cc=acme@kernel.org \
--cc=ak@linux.intel.com \
--cc=jolsa@kernel.org \
--cc=kan.liang@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.