Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1609148 > unrolled thread

[PATCH v6 0/5] perf report: Show inline stack

Started byJin Yao <yao.jin@linux.intel.com>
First post2017-03-25 13:40 +0100
Last post2017-03-25 13:40 +0100
Articles 2 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [PATCH v6 0/5] perf report: Show inline stack Jin Yao <yao.jin@linux.intel.com> - 2017-03-25 13:40 +0100
    [PATCH v6 4/5] perf report: Show inline stack for stdio mode Jin Yao <yao.jin@linux.intel.com> - 2017-03-25 13:40 +0100

#1609148 — [PATCH v6 0/5] perf report: Show inline stack

FromJin Yao <yao.jin@linux.intel.com>
Date2017-03-25 13:40 +0100
Subject[PATCH v6 0/5] perf report: Show inline stack
Message-ID<toT98-LB-3@gated-at.bofh.it>
v6:
Ravi reported a build error that was:

util/srcline.c: In function ‘addr2inlines’:
util/srcline.c:403:7: error: too few arguments to function ‘inline_list__append’
   if (inline_list__append(filename, NULL, line_nr, node) != 0)
       ^
util/srcline.c:34:12: note: declared here
 static int inline_list__append(char *filename, char *funcname, int line_nr,
            ^
util/srcline.c: At top level:
util/srcline.c:60:13: error: ‘inline_list__reverse’ defined but not used [-Werror=unused-function]
 static void inline_list__reverse(struct inline_node *node)
             ^
cc1: all warnings being treated as errors
mv: cannot stat ‘util/.srcline.o.tmp’: No such file or directory

The error happens when BFD lib is not enabled in build environment.
The patch series should be improved for better compatibility for this case.

So in v6, these patches are changed.

  perf report: Find the inline stack for a given address
  perf report: Show inline stack for stdio mode
  perf report: Show inline stack for browser mode

Without BFD, the inlined function name is not supported even "-g function" set.
It's only filename:line_nr printing.

Following patches are not changed.

  perf report: Refactor common code in srcline.c
  perf report: Create new inline option

v5: Update according to Milian Wolff's comments. It groups by address
    (then display file/ line), or by function (then display function name).

    For example:

    1. Show inlined function name
       perf report --stdio -g function --inline

       0.69%     0.00%  inline   ld-2.23.so           [.] dl_main
              |
              ---dl_main
                 |
                  --0.56%--_dl_relocate_object
                           _dl_relocate_object (inline)
                           elf_dynamic_do_Rela (inline)

     2. Show the file/line information
        perf report --stdio -g address --inline

        0.69%     0.00%  inline   ld-2.23.so           [.] _dl_start_user
              |
              ---_dl_start_user .:0
                 _dl_start rtld.c:307
                 /build/glibc-GKVZIf/glibc-2.23/elf/rtld.c:413 (inline)
                 _dl_sysdep_start dl-sysdep.c:250
                 |
                  --0.56%--dl_main rtld.c:2076

    2 patches are updated according to this change.
    perf report: Show inline stack in browser mode
    perf report: Show inline stack in stdio mode

    3 patches are not changed.
    perf report: Find the inline stack for a given address
    perf report: Refactor common code in srcline.c
    perf report: Create new inline option

v4: Remove the options "--inline-line" and "--inline-name". Just use
    a new option "--inline" to print the inline function information.
    The policy is if the inline function name can be resolved then
    print the name in priority. If the name can't be resolved, then
    print the source line number.

    For example:
    perf report --stdio --inline

    0.69%     0.00%  inline   ld-2.23.so           [.] dl_main
           |
           ---dl_main
              |
               --0.56%--_dl_relocate_object
                         |
                         ---_dl_relocate_object (inline)
                            elf_dynamic_do_Rela (inline)

    Following 3 patches are updated according to this change.
    perf report: Show inline stack in browser mode
    perf report: Show inline stack in stdio mode
    perf report: Create new inline option

    Following are not changed.
    perf report: Find the inline stack for a given address
    perf report: Refactor common code in srcline.c

v3: Iterate on RIPs of all callchain entries to check if the RIP is in
    inline functions.

    Reverse the order of the inliner printout if necessary.

    Provide new options "--inline-line" / "--inline-name" to print
    inline function name or print inline function source line.

v2: Thanks so much for Arnaldo's comments!
    The modifications are:

    1. Divide v1 patch "perf report: Find the inline stack for a
       given address" into 2 patches:
       a. perf report: Refactor common code in srcline.c
       b. perf report: Find the inline stack for a given address

       Some function names are changed:
       dso_name_get -> dso__name
       ilist_apend -> inline_list__append
       get_inline_node -> dso__parse_addr_inlines
       free_inline_node -> inline_node__delete

    2. Since the function name are changed, update following patches
       accordingly.
       a. perf report: Show inline stack in stdio mode
       b. perf report: Show inline stack in browser mode

    3. Rebase to latest perf/core branch. This patch is impacted.
       a. perf report: Create a new option "--inline"

v1: Initial post

It would be useful for perf to support a mode to query the
inline stack for callgraph addresses. This would simplify
finding the right code in code that does a lot of inlining.

For example, the c code:

static inline void f3(void)
{
        int i;
        for (i = 0; i < 1000;) {

                if(i%2)
                        i++;
                else
                        i++;
        }
        printf("hello f3\n");   /* D */
}

/* < CALLCHAIN: f2 <- f1 > */
static inline void f2(void)
{
        int i;
        for (i = 0; i < 100; i++) {
                f3();   /* C */
        }
}

/* < CALLCHAIN: f1 <- main > */
static inline void f1(void)
{
        int i;
        for (i = 0; i < 100; i++) {
                f2();   /* B */
        }
}

/* < CALLCHAIN: main <- TOP > */
int main()
{
        struct timeval tv;
        time_t start, end;

        gettimeofday(&tv, NULL);
        start = end = tv.tv_sec;
        while((end - start) < 5) {
                f1();   /* A */
                gettimeofday(&tv, NULL);
                end = tv.tv_sec;
        }
        return 0;
}

The printed inline stack is:

0.05%  test2    test2              [.] main
       |
       ---/home/perf-dev/lck-2867/test/test2.c:27 (inline)
          /home/perf-dev/lck-2867/test/test2.c:35 (inline)
          /home/perf-dev/lck-2867/test/test2.c:45 (inline)
          /home/perf-dev/lck-2867/test/test2.c:61 (inline)

I tag A/B/C/D in above c code to indicate the source line,
actually the inline stack is equal to:

0.05%  test2    test2              [.] main
       |
       ---D
          C
          B
          A

Jin Yao (5):
  perf report: Refactor common code in srcline.c
  perf report: Find the inline stack for a given address
  perf report: Introduce --inline option
  perf report: Show inline stack for stdio mode
  perf report: Show inline stack for browser mode

 tools/perf/Documentation/perf-report.txt |   4 +
 tools/perf/builtin-report.c              |   2 +
 tools/perf/ui/browsers/hists.c           | 180 +++++++++++++++++++++--
 tools/perf/ui/stdio/hist.c               |  85 ++++++++++-
 tools/perf/util/hist.c                   |   5 +
 tools/perf/util/sort.h                   |   1 +
 tools/perf/util/srcline.c                | 235 +++++++++++++++++++++++++++----
 tools/perf/util/symbol-elf.c             |   5 +
 tools/perf/util/symbol-minimal.c         |   7 +
 tools/perf/util/symbol.h                 |   5 +-
 tools/perf/util/util.h                   |  16 +++
 11 files changed, 507 insertions(+), 38 deletions(-)

-- 
2.7.4

[toc] | [next] | [standalone]


#1609149 — [PATCH v6 4/5] perf report: Show inline stack for stdio mode

FromJin Yao <yao.jin@linux.intel.com>
Date2017-03-25 13:40 +0100
Subject[PATCH v6 4/5] perf report: Show inline stack for stdio mode
Message-ID<toT98-LB-15@gated-at.bofh.it>
In reply to#1609148
If the address belongs to an inlined function, the source information
back to the first non-inlined function will be printed.

For example:

1. Show inlined function name
   perf report --stdio -g function --inline

     0.69%     0.00%  inline   ld-2.23.so           [.] dl_main
            |
            ---dl_main
               |
                --0.56%--_dl_relocate_object
                          _dl_relocate_object (inline)
                          elf_dynamic_do_Rela (inline)

2. Show the file/line information
   perf report --stdio -g address --inline

     0.69%     0.00%  inline   ld-2.23.so           [.] _dl_start_user
            |
            ---_dl_start_user .:0
               _dl_start rtld.c:307
               /build/glibc-GKVZIf/glibc-2.23/elf/rtld.c:413 (inline)
               _dl_sysdep_start dl-sysdep.c:250
               |
                --0.56%--dl_main rtld.c:2076

Committer tests:

  # perf record --call-graph dwarf ~/bin/perf stat usleep 1

 Performance counter stats for 'usleep 1':

          0.443020      task-clock (msec)         #    0.449 CPUs utilized
                 1      context-switches          #    0.002 M/sec
                 0      cpu-migrations            #    0.000 K/sec
                52      page-faults               #    0.117 M/sec
         1,049,423      cycles                    #    2.369 GHz
           801,456      instructions              #    0.76  insn per cycle
           155,609      branches                  #  351.246 M/sec
             7,026      branch-misses             #    4.52% of all branches

       0.000987570 seconds time elapsed

  [ perf record: Woken up 2 times to write data ]
  [ perf record: Captured and wrote 0.553 MB perf.data (66 samples) ]
  # perf report --stdio --inline fs__get_mountpoint
  <SNIP>
     1.73%     0.00%  perf     perf           [.] fs__get_mountpoint
            |
            ---fs__get_mountpoint
               fs__get_mountpoint (inline)
               fs__check_mounts (inline)
               __statfs
               entry_SYSCALL_64
               sys_statfs
               SYSC_statfs
               user_statfs
               user_path_at_empty
               filename_lookup
               path_lookupat
               link_path_walk
               inode_permission
               __inode_permission
               kernfs_iop_permission
               kernfs_refresh_inode
               security_inode_notifysecctx
               selinux_inode_notifysecctx
               selinux_inode_setsecurity
               security_context_to_sid
               security_context_to_sid_core
               string_to_context_struct
               symcmp

Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Milian Wolff <milian.wolff@kdab.com>
---
 tools/perf/ui/stdio/hist.c | 85 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 84 insertions(+), 1 deletion(-)

diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 668f4ae..6128f48 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -17,6 +17,66 @@ static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
 	return ret;
 }
 
+static size_t inline__fprintf(struct map *map, u64 ip, int left_margin,
+			      int depth, int depth_mask, FILE *fp)
+{
+	struct dso *dso;
+	struct inline_node *node;
+	struct inline_list *ilist;
+	int ret = 0, i;
+
+	if (map == NULL)
+		return 0;
+
+	dso = map->dso;
+	if (dso == NULL)
+		return 0;
+
+	if (dso->kernel != DSO_TYPE_USER)
+		return 0;
+
+	node = dso__parse_addr_inlines(dso,
+				       map__rip_2objdump(map, ip));
+	if (node == NULL)
+		return 0;
+
+	list_for_each_entry(ilist, &node->val, list) {
+		if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
+			ret += callchain__fprintf_left_margin(fp, left_margin);
+
+			for (i = 0; i < depth; i++) {
+				if (depth_mask & (1 << i))
+					ret += fprintf(fp, "|");
+				else
+					ret += fprintf(fp, " ");
+				ret += fprintf(fp, "          ");
+			}
+
+			if (callchain_param.key == CCKEY_ADDRESS) {
+				if (ilist->filename != NULL)
+					ret += fprintf(fp, "%s:%d (inline)",
+						       ilist->filename,
+						       ilist->line_nr);
+				else
+					ret += fprintf(fp, "??");
+			} else if (ilist->funcname != NULL)
+				ret += fprintf(fp, "%s (inline)",
+					       ilist->funcname);
+			else if (ilist->filename != NULL)
+				ret += fprintf(fp, "%s:%d (inline)",
+					       ilist->filename,
+					       ilist->line_nr);
+			else
+				ret += fprintf(fp, "??");
+
+			ret += fprintf(fp, "\n");
+		}
+	}
+
+	inline_node__delete(node);
+	return ret;
+}
+
 static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
 					  int left_margin)
 {
@@ -78,6 +138,10 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node,
 	fputs(str, fp);
 	fputc('\n', fp);
 	free(alloc_str);
+
+	if (symbol_conf.inline_name)
+		ret += inline__fprintf(chain->ms.map, chain->ip,
+				       left_margin, depth, depth_mask, fp);
 	return ret;
 }
 
@@ -229,6 +293,7 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
 			if (!i++ && field_order == NULL &&
 			    sort_order && !prefixcmp(sort_order, "sym"))
 				continue;
+
 			if (!printed) {
 				ret += callchain__fprintf_left_margin(fp, left_margin);
 				ret += fprintf(fp, "|\n");
@@ -251,6 +316,13 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
 
 			if (++entries_printed == callchain_param.print_limit)
 				break;
+
+			if (symbol_conf.inline_name)
+				ret += inline__fprintf(chain->ms.map,
+						       chain->ip,
+						       left_margin,
+						       0, 0,
+						       fp);
 		}
 		root = &cnode->rb_root;
 	}
@@ -529,6 +601,8 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
 			       bool use_callchain)
 {
 	int ret;
+	int callchain_ret = 0;
+	int inline_ret = 0;
 	struct perf_hpp hpp = {
 		.buf		= bf,
 		.size		= size,
@@ -547,7 +621,16 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
 	ret = fprintf(fp, "%s\n", bf);
 
 	if (use_callchain)
-		ret += hist_entry_callchain__fprintf(he, total_period, 0, fp);
+		callchain_ret = hist_entry_callchain__fprintf(he, total_period,
+							      0, fp);
+
+	if (callchain_ret == 0 && symbol_conf.inline_name) {
+		inline_ret = inline__fprintf(he->ms.map, he->ip, 0, 0, 0, fp);
+		ret += inline_ret;
+		if (inline_ret > 0)
+			ret += fprintf(fp, "\n");
+	} else
+		ret += callchain_ret;
 
 	return ret;
 }
-- 
2.7.4

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web