All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/7] perf annotate: Fixes & Introduce --source-only and new source code view
@ 2017-03-09 17:35 Taeung Song
  2017-03-09 17:35 ` [PATCH v3 1/7] perf annotate: Use build-id dir when reading link name Taeung Song
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Taeung Song @ 2017-03-09 17:35 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: linux-kernel, Jiri Olsa, Namhyung Kim, Ingo Molnar,
	Peter Zijlstra, Wang Nan, Masami Hiramatsu, Taeung Song

Hi,

Currently perf-annotate have several problems, limitaions and needs
regaring line numbers and source code view.

  - Wrong line numbers on perf-annotate (both stdio and TUI)
  - Wrong sum of overhead(percent) matching source lines
  - Limitaions because of a dependence of 'objdump -S'
  - A need of source code only view with overhead
    for new view point for performance

So I'll handle them by this patchset.

First of all, fix several bugs regarding perf-annotate.
And Introduce --source-only option that show source code with overhead
and the new source code view for TUI.

I think --source-only and the new source code view
can provide a new view point for performance on source code level
(and I think the view is a precheck before asm level and
more readble than asm+src mixed view.)

I'd appreciate it, if you give some feedback to me.

Thanks,
Taeung

v3:
- fix mistakes about a leak or missing handing exception of v2 (Namhyung)
- fix several bugs about perf-annotate
- keep "mixed" annotation and add new --source-only option
- remove hide_src_code config for TUI

v2:
- contains the new source code view (Namhyung)

P.S.
I'm making patches for 'fold/unfold parts of asm per a line' on the new source code view.
If you agree the new source code view, I keep going to do!

Taeung Song (7):
  perf annotate: Use build-id dir when reading link name
  perf annotate: Avoid division by zero when calculating percent
  perf annotate: Fix missing setting nr samples on source_line
  perf annotate: More exactly grep -v in symbol__disassemble()
  perf annotate: Get correct line numbers matched with addr
  perf annotate: Introduce --source-only option
  perf annotate: Support the new source code view for TUI

 tools/perf/Documentation/perfconfig.example |   1 -
 tools/perf/builtin-annotate.c               |   2 +
 tools/perf/ui/browsers/annotate.c           | 238 ++++++++++++++------
 tools/perf/util/annotate.c                  | 328 +++++++++++++++++++++++++++-
 tools/perf/util/annotate.h                  |  31 ++-
 tools/perf/util/symbol.c                    |   1 +
 tools/perf/util/symbol.h                    |   1 +
 7 files changed, 518 insertions(+), 84 deletions(-)

-- 
2.7.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 1/7] perf annotate: Use build-id dir when reading link name
  2017-03-09 17:35 [PATCH v3 0/7] perf annotate: Fixes & Introduce --source-only and new source code view Taeung Song
@ 2017-03-09 17:35 ` Taeung Song
  2017-03-09 17:35 ` [PATCH v3 2/7] perf annotate: Avoid division by zero when calculating percent Taeung Song
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Taeung Song @ 2017-03-09 17:35 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: linux-kernel, Jiri Olsa, Namhyung Kim, Ingo Molnar,
	Peter Zijlstra, Wang Nan, Masami Hiramatsu, Taeung Song,
	Jiri Olsa

In dso__disassemble_filename() when reading link name
from a build-id file, it is failed each time
because a build-id file gotten from dso__build_id_filename()
is not symbolic link.

So use build-id directory path instead of a build-id file name.

For example, if build-id file name gotten from
dso__build_id_filename() is as below,

  /root/.debug/.build-id/4f/75c7d197c951659d1c1b8b5fd49bcdf8f3f8b1/elf

instead of the above build-id file name,
use the build-id dir path that is a symbolic link as below.

  /root/.debug/.build-id/4f/75c7d197c951659d1c1b8b5fd49bcdf8f3f8b1

Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
 tools/perf/util/annotate.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 273f21f..fc91c6b 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -1307,6 +1307,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
 {
 	char linkname[PATH_MAX];
 	char *build_id_filename;
+	char *build_id_path = NULL;
 
 	if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
 	    !dso__is_kcore(dso))
@@ -1322,8 +1323,14 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
 		goto fallback;
 	}
 
+	build_id_path = strdup(filename);
+	if (!build_id_path)
+		return -1;
+
+	dirname(build_id_path);
+
 	if (dso__is_kcore(dso) ||
-	    readlink(filename, linkname, sizeof(linkname)) < 0 ||
+	    readlink(build_id_path, linkname, sizeof(linkname)) < 0 ||
 	    strstr(linkname, DSO__NAME_KALLSYMS) ||
 	    access(filename, R_OK)) {
 fallback:
@@ -1335,6 +1342,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
 		__symbol__join_symfs(filename, filename_size, dso->long_name);
 	}
 
+	free(build_id_path);
 	return 0;
 }
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 2/7] perf annotate: Avoid division by zero when calculating percent
  2017-03-09 17:35 [PATCH v3 0/7] perf annotate: Fixes & Introduce --source-only and new source code view Taeung Song
  2017-03-09 17:35 ` [PATCH v3 1/7] perf annotate: Use build-id dir when reading link name Taeung Song
@ 2017-03-09 17:35 ` Taeung Song
  2017-03-09 17:35 ` [PATCH v3 3/7] perf annotate: Fix missing setting nr samples on source_line Taeung Song
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Taeung Song @ 2017-03-09 17:35 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: linux-kernel, Jiri Olsa, Namhyung Kim, Ingo Molnar,
	Peter Zijlstra, Wang Nan, Masami Hiramatsu, Taeung Song,
	Jiri Olsa

Currently perf-annotate with --print-line can print
-nan(0x8000000000000) because of division by zero
when calculating percent.

So if a sum of samples is zero, skip calculating percent.

Before:

    $ perf annotate --stdio -l

Sorted summary for file /home/taeung/workspace/a.out
----------------------------------------------

   32.89    -nan    7.04 a.c:38
   25.14    -nan    0.00 a.c:34
   16.26    -nan   56.34 a.c:31
   15.88    -nan    1.41 a.c:37
    5.67    -nan    0.00 a.c:39
    1.13    -nan   35.21 a.c:26
    0.95    -nan    0.00 a.c:44
    0.57    -nan    0.00 a.c:32
 Percent                 |      Source code & Disassembly of a.out for cycles (529 samples)
-----------------------------------------------------------------------------------------
                         :
...

 a.c:26    0.57    -nan    4.23 :         40081a:       mov    %edi,-0x24(%rbp)
 a.c:26    0.00    -nan    9.86 :         40081d:       mov    %rsi,-0x30(%rbp)

...

After:

    $ perf annotate --stdio -l

Sorted summary for file /home/taeung/workspace/a.out
----------------------------------------------

   32.89    0.00    7.04 a.c:38
   25.14    0.00    0.00 a.c:34
   16.26    0.00   56.34 a.c:31
   15.88    0.00    1.41 a.c:37
    5.67    0.00    0.00 a.c:39
    1.13    0.00   35.21 a.c:26
    0.95    0.00    0.00 a.c:44
    0.57    0.00    0.00 a.c:32
 Percent                 |      Source code & Disassembly of old for cycles (529 samples)
-----------------------------------------------------------------------------------------
                         :
...

a.c:26    0.57    0.00    4.23 :         40081a:       mov    %edi,-0x24(%rbp)
a.c:26    0.00    0.00    9.86 :         40081d:       mov    %rsi,-0x30(%rbp)

...

Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
 tools/perf/util/annotate.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index fc91c6b..9bb43cd 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -1665,11 +1665,15 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
 		src_line->nr_pcnt = nr_pcnt;
 
 		for (k = 0; k < nr_pcnt; k++) {
+			double percent = 0.0;
+
 			h = annotation__histogram(notes, evidx + k);
-			src_line->samples[k].percent = 100.0 * h->addr[i] / h->sum;
+			if (h->sum)
+				percent = 100.0 * h->addr[i] / h->sum;
 
-			if (src_line->samples[k].percent > percent_max)
-				percent_max = src_line->samples[k].percent;
+			if (percent > percent_max)
+				percent_max = percent;
+			src_line->samples[k].percent = percent;
 		}
 
 		if (percent_max <= 0.5)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 3/7] perf annotate: Fix missing setting nr samples on source_line
  2017-03-09 17:35 [PATCH v3 0/7] perf annotate: Fixes & Introduce --source-only and new source code view Taeung Song
  2017-03-09 17:35 ` [PATCH v3 1/7] perf annotate: Use build-id dir when reading link name Taeung Song
  2017-03-09 17:35 ` [PATCH v3 2/7] perf annotate: Avoid division by zero when calculating percent Taeung Song
@ 2017-03-09 17:35 ` Taeung Song
  2017-03-09 17:35 ` [PATCH v3 4/7] perf annotate: More exactly grep -v in symbol__disassemble() Taeung Song
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Taeung Song @ 2017-03-09 17:35 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: linux-kernel, Jiri Olsa, Namhyung Kim, Ingo Molnar,
	Peter Zijlstra, Wang Nan, Masami Hiramatsu, Taeung Song,
	Jiri Olsa

If using --show-total-period with -l,
disasm__calc_percent() use a 'samples' array of source_line.
But samples[evidx].nr is always zero so print 0 values as below.

Before:
    $ perf annotate --stdio -l --show-total-period
...
       0 :        400816:       push   %rbp
       0 :        400817:       mov    %rsp,%rbp
       0 :        40081a:       mov    %edi,-0x24(%rbp)
       0 :        40081d:       mov    %rsi,-0x30(%rbp)
       0 :        400821:       mov    -0x24(%rbp),%eax
       0 :        400824:       mov    -0x30(%rbp),%rdx
       0 :        400828:       mov    (%rdx),%esi
       0 :        40082a:       mov    $0x0,%edx
...

The reason is that in symbol__get_source_line() did't set
number of samples into a memeber variable 'nr' of samples
of source_line.

So fix it for correct number of samples
when using --show-total-period option as below.

After:
    $ perf annotate --stdio -l --show-total-period
...
       3 :        400816:       push   %rbp
       4 :        400817:       mov    %rsp,%rbp
       0 :        40081a:       mov    %edi,-0x24(%rbp)
       0 :        40081d:       mov    %rsi,-0x30(%rbp)
       1 :        400821:       mov    -0x24(%rbp),%eax
       2 :        400824:       mov    -0x30(%rbp),%rdx
       0 :        400828:       mov    (%rdx),%esi
       1 :        40082a:       mov    $0x0,%edx
...

Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
 tools/perf/util/annotate.c | 6 ++++--
 tools/perf/util/annotate.h | 2 +-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 9bb43cd..63130ec 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -1659,7 +1659,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
 	start = map__rip_2objdump(map, sym->start);
 
 	for (i = 0; i < len; i++) {
-		u64 offset;
+		u64 offset, nr_samples;
 		double percent_max = 0.0;
 
 		src_line->nr_pcnt = nr_pcnt;
@@ -1668,12 +1668,14 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
 			double percent = 0.0;
 
 			h = annotation__histogram(notes, evidx + k);
+			nr_samples = h->addr[i];
 			if (h->sum)
-				percent = 100.0 * h->addr[i] / h->sum;
+				percent = 100.0 * nr_samples / h->sum;
 
 			if (percent > percent_max)
 				percent_max = percent;
 			src_line->samples[k].percent = percent;
+			src_line->samples[k].nr = nr_samples;
 		}
 
 		if (percent_max <= 0.5)
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 09776b5..948aa8e 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -98,7 +98,7 @@ struct cyc_hist {
 struct source_line_samples {
 	double		percent;
 	double		percent_sum;
-	double          nr;
+	u64		nr;
 };
 
 struct source_line {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 4/7] perf annotate: More exactly grep -v in symbol__disassemble()
  2017-03-09 17:35 [PATCH v3 0/7] perf annotate: Fixes & Introduce --source-only and new source code view Taeung Song
                   ` (2 preceding siblings ...)
  2017-03-09 17:35 ` [PATCH v3 3/7] perf annotate: Fix missing setting nr samples on source_line Taeung Song
@ 2017-03-09 17:35 ` Taeung Song
  2017-03-09 17:35 ` [PATCH v3 5/7] perf annotate: Get correct line numbers matched with addr Taeung Song
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Taeung Song @ 2017-03-09 17:35 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: linux-kernel, Jiri Olsa, Namhyung Kim, Ingo Molnar,
	Peter Zijlstra, Wang Nan, Masami Hiramatsu, Taeung Song,
	Jiri Olsa

To remove the first line containing file name and file format as below,

    $ objdump -l -d -S -C /home/taeung/a.out | head -2

    /home/taeung/a.out:     file format elf64-x86-64

currently perf-annotate use objdump with grep -v "file name".
But it cause a side effect eliminating filename:linenr of
output of 'objdump -l' so fix it.

Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
 tools/perf/util/annotate.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 63130ec..e49eb7e 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -1443,7 +1443,7 @@ int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_na
 	snprintf(command, sizeof(command),
 		 "%s %s%s --start-address=0x%016" PRIx64
 		 " --stop-address=0x%016" PRIx64
-		 " -l -d %s %s -C %s 2>/dev/null|grep -v %s|expand",
+		 " -l -d %s %s -C %s 2>/dev/null|grep -v %s: |expand",
 		 objdump_path ? objdump_path : "objdump",
 		 disassembler_style ? "-M " : "",
 		 disassembler_style ? disassembler_style : "",
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 5/7] perf annotate: Get correct line numbers matched with addr
  2017-03-09 17:35 [PATCH v3 0/7] perf annotate: Fixes & Introduce --source-only and new source code view Taeung Song
                   ` (3 preceding siblings ...)
  2017-03-09 17:35 ` [PATCH v3 4/7] perf annotate: More exactly grep -v in symbol__disassemble() Taeung Song
@ 2017-03-09 17:35 ` Taeung Song
  2017-03-09 17:35 ` [PATCH v3 6/7] perf annotate: Introduce --source-only option Taeung Song
  2017-03-09 17:35 ` [PATCH v3 7/7] perf annotate: Support the new source code view for TUI Taeung Song
  6 siblings, 0 replies; 8+ messages in thread
From: Taeung Song @ 2017-03-09 17:35 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: linux-kernel, Jiri Olsa, Namhyung Kim, Ingo Molnar,
	Peter Zijlstra, Wang Nan, Masami Hiramatsu, Taeung Song,
	Jiri Olsa

Currently perf-annotate show wrong line numbers.

For example,
Actual source code is as below

...
  21 };
  22
  23 unsigned int limited_wgt;
  24
  25 unsigned int get_cond_maxprice(int wgt)
  26 {
...

However, the output of perf-annotate is as below.

  4   Disassembly of section .text:

  6   0000000000400966 <get_cond_maxprice>:
  7   get_cond_maxprice():
  26  };

  28  unsigned int limited_wgt;

  30  unsigned int get_cond_maxprice(int wgt)
  31  {

So remove the wrong way counting line numbers
and match correct line numbers to each addr of asm lines

Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
 tools/perf/util/annotate.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index e49eb7e..a50d949 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -823,11 +823,11 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line,
 	if (dl != NULL) {
 		dl->offset = offset;
 		dl->line = strdup(line);
-		dl->line_nr = line_nr;
 		if (dl->line == NULL)
 			goto out_delete;
 
 		if (offset != -1) {
+			dl->line_nr = line_nr;
 			if (disasm_line__parse(dl->line, &dl->ins.name, &dl->ops.raw) < 0)
 				goto out_free_line;
 
@@ -1207,7 +1207,6 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
 
 	dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, arch, map);
 	free(line);
-	(*line_nr)++;
 
 	if (dl == NULL)
 		return -1;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 6/7] perf annotate: Introduce --source-only option
  2017-03-09 17:35 [PATCH v3 0/7] perf annotate: Fixes & Introduce --source-only and new source code view Taeung Song
                   ` (4 preceding siblings ...)
  2017-03-09 17:35 ` [PATCH v3 5/7] perf annotate: Get correct line numbers matched with addr Taeung Song
@ 2017-03-09 17:35 ` Taeung Song
  2017-03-09 17:35 ` [PATCH v3 7/7] perf annotate: Support the new source code view for TUI Taeung Song
  6 siblings, 0 replies; 8+ messages in thread
From: Taeung Song @ 2017-03-09 17:35 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: linux-kernel, Jiri Olsa, Namhyung Kim, Ingo Molnar,
	Peter Zijlstra, Wang Nan, Masami Hiramatsu, Taeung Song,
	Jiri Olsa

Currently there is an asm view that can show
parts of source code lines with --source option.

But I think it is nice to add the new view with
--source-only into perf-annotate.
The option can show acutal source code per symbol(function)
with overhead using new struct source_code.

I think this view can be more readable than previous source
code view and be the new view point for performance
for a precheck before assembly code level.

For example, if target symbol is 'hex2u64' of util/util.c

Before:

    $ perf annotate --stdio -s hex2u64
 Percent |      Source code & Disassembly of perf for cycles:ppp (42 samples)
-----------------------------------------------------------------------------
...
         :      int hex2u64(const char *ptr, u64 *long_val)
         :      {
    0.00 :        53feb3:       push   %rbp
    2.38 :        53feb4:       mov    %rsp,%rbp
    0.00 :        53feb7:       sub    $0x30,%rsp
    0.00 :        53febb:       callq  4248b0 <pthread_attr_setdetachstate@plt+0x10>
    0.00 :        53fec0:       mov    %rdi,-0x28(%rbp)
    0.00 :        53fec4:       mov    %rsi,-0x30(%rbp)
    0.00 :        53fec8:       mov    %fs:0x28,%rax
    0.00 :        53fed1:       mov    %rax,-0x8(%rbp)
    0.00 :        53fed5:       xor    %eax,%eax
         :              const char *p = ptr;
    2.38 :        53fed7:       mov    -0x28(%rbp),%rax
    0.00 :        53fedb:       mov    %rax,-0x10(%rbp)
...

After:

    $ perf annotate --source-only --stdio -s hex2u64
 Percent |      Source code of util.c for cycles:ppp (42 samples)
-----------------------------------------------------------------
    0.00 : 354   * While we find nice hex chars, build a long_val.
    0.00 : 355   * Return number of chars processed.
    0.00 : 356   */
    0.00 : 357  int hex2u64(const char *ptr, u64 *long_val)
    2.38 : 358  {
    2.38 : 359          const char *p = ptr;
    0.00 : 360          *long_val = 0;
    0.00 : 361
   30.95 : 362          while (*p) {
   23.81 : 363                  const int hex_val = hex(*p);
    0.00 : 364
   14.29 : 365                  if (hex_val < 0)
    0.00 : 366                          break;
    0.00 : 367
   26.19 : 368                  *long_val = (*long_val << 4) | hex_val;
    0.00 : 369                  p++;
    0.00 : 370          }
    0.00 : 371
    0.00 : 372          return p - ptr;
    0.00 : 373  }

Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
 tools/perf/builtin-annotate.c     |   2 +
 tools/perf/ui/browsers/annotate.c |   5 -
 tools/perf/util/annotate.c        | 299 +++++++++++++++++++++++++++++++++++++-
 tools/perf/util/annotate.h        |  22 +++
 tools/perf/util/symbol.c          |   1 +
 tools/perf/util/symbol.h          |   1 +
 6 files changed, 321 insertions(+), 9 deletions(-)

diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 4f52d85..93365e1 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -432,6 +432,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
 		     symbol__config_symfs),
 	OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
 		    "Interleave source code with assembly code (default)"),
+	OPT_BOOLEAN(0, "source-only", &symbol_conf.annotate_src_only,
+		    "Display source code for each symbol"),
 	OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
 		    "Display raw encoding of assembly instructions (default)"),
 	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index ba36aac..03b2012 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -11,11 +11,6 @@
 #include "../../util/config.h"
 #include <pthread.h>
 
-struct disasm_line_samples {
-	double		percent;
-	u64		nr;
-};
-
 #define IPC_WIDTH 6
 #define CYCLES_WIDTH 6
 
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index a50d949..7d1c7cc 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -1357,6 +1357,273 @@ static const char *annotate__norm_arch(const char *arch_name)
 	return normalize_arch((char *)arch_name);
 }
 
+static int parse_srcline(char *srcline, char **path, int *line_nr)
+{
+	char *sep;
+
+	if (srcline == NULL || !strcmp(srcline, SRCLINE_UNKNOWN))
+		return -1;
+
+	sep = strchr(srcline, ':');
+	if (sep) {
+		*sep = '\0';
+		*path = srcline;
+		*line_nr = strtoul(++sep, NULL, 0);
+	} else
+		return -1;
+
+	return 0;
+}
+
+static void code_line__free(struct code_line *cl)
+{
+	zfree(&cl->line);
+	zfree(&cl->matched_dl_arr);
+	zfree(&cl->samples_sum);
+	free(cl);
+}
+
+static void code_lines__free(struct list_head *code_lines)
+{
+	struct code_line *pos, *tmp;
+
+	if (list_empty(code_lines))
+		return;
+
+	list_for_each_entry_safe(pos, tmp, code_lines, node) {
+		list_del_init(&pos->node);
+		code_line__free(pos);
+	}
+}
+
+static int symbol__free_source_code(struct symbol *sym)
+{
+	struct annotation *notes = symbol__annotation(sym);
+	struct source_code *code = notes->src->code;
+
+	if (code == NULL)
+		return -1;
+
+	code_lines__free(&code->lines);
+	zfree(&code->path);
+	zfree(&notes->src->code);
+	return 0;
+}
+
+static void code_line__sum_samples(struct code_line *cl, struct disasm_line *dl,
+				   struct annotation *notes, struct perf_evsel *evsel)
+{
+	int i;
+	u64 nr_samples;
+	struct sym_hist *h;
+	struct source_code *code = notes->src->code;
+
+	for (i = 0; i < code->nr_events; i++) {
+		double percent = 0.0;
+
+		h = annotation__histogram(notes, evsel->idx + i);
+		nr_samples = h->addr[dl->offset];
+		if (h->sum)
+			percent = 100.0 * nr_samples / h->sum;
+
+		cl->samples_sum[i].percent += percent;
+		cl->samples_sum[i].nr += nr_samples;
+	}
+}
+
+static void source_code__print(struct code_line *cl, int nr_events,
+			       struct annotation *notes, struct perf_evsel *evsel)
+{
+	int i;
+	const char *color;
+	double percent, max_percent = 0.0;
+
+	for (i = 0; i < cl->nr_matched_dl; i++) {
+		code_line__sum_samples(cl, cl->matched_dl_arr[i], notes, evsel);
+	}
+
+	for (i = 0; i < nr_events; i++) {
+		percent = cl->samples_sum[i].percent;
+		color = get_percent_color(percent);
+		if (max_percent < percent)
+			max_percent = percent;
+
+		if (symbol_conf.show_total_period)
+			color_fprintf(stdout, color, " %7" PRIu64,
+				      cl->samples_sum[i].nr);
+		else
+			color_fprintf(stdout, color, " %7.2f", percent);
+	}
+	color = get_percent_color(max_percent);
+	color_fprintf(stdout, color, " : %d	%s\n",
+		      cl->line_nr, cl->line);
+}
+
+static int code_line__match_with_dl(struct code_line *cl, struct list_head *disasm_lines)
+{
+	int nr_dl = 0;
+	struct disasm_line *pos, **tmp, **matched_dl_arr;
+	size_t allocated = sizeof(struct disasm_line **);
+
+	matched_dl_arr = zalloc(allocated);
+	if (!matched_dl_arr)
+		return -1;
+
+	list_for_each_entry(pos, disasm_lines, node) {
+		if (pos->line_nr == cl->line_nr) {
+			if (nr_dl > 0) {
+				tmp = realloc(matched_dl_arr, allocated * (nr_dl + 1));
+				if (!tmp) {
+					free(matched_dl_arr);
+					return -1;
+				}
+				matched_dl_arr = tmp;
+			}
+			matched_dl_arr[nr_dl++] = pos;
+		}
+	}
+
+	cl->matched_dl_arr = matched_dl_arr;
+	cl->nr_matched_dl = nr_dl;
+	return 0;
+}
+
+static struct code_line *code_line__new(char *line, int linenr, int nr_events)
+{
+	struct code_line *cl = zalloc(sizeof(*cl));
+
+	if (!cl)
+		return NULL;
+
+	cl->line_nr = linenr;
+	cl->line = strdup(line);
+	cl->samples_sum =
+		zalloc(sizeof(struct disasm_line_samples) * nr_events);
+	if (!cl->samples_sum)
+		zfree(&cl);
+
+	return cl;
+}
+
+static int source_code__collect(struct source_code *code,
+				struct annotation *notes,
+				char *path, char* d_name,
+				int start_linenr, int end_linenr)
+{
+	int ret = -1, linenr = 0;
+	char *line = NULL, *parsed_line;
+	size_t len;
+	FILE *file;
+	struct stat srcfile_st, objfile_st;
+	struct code_line *cl;
+
+	if (stat(path, &srcfile_st) < 0)
+		return -1;
+	else {
+		if (stat(d_name, &objfile_st) < 0)
+			return -1;
+		if (srcfile_st.st_mtime > objfile_st.st_mtime) {
+			pr_err("Source file is more recent than when recording"
+				   ": %s\n", path);
+			pr_err("  (try 'perf record' again after recompiling"
+			       " the source file or with 'perf buildid-cache -r')\n");
+			return -1;
+		}
+	}
+
+	file = fopen(path, "r");
+	if (!file)
+		return -1;
+
+	if (srcline_full_filename)
+		code->path = strdup(path);
+	else
+		code->path = strdup(basename(path));
+
+	INIT_LIST_HEAD(&code->lines);
+	while (!feof(file)) {
+		if (getline(&line, &len, file) < 0)
+			goto out_err;
+
+		if (++linenr < start_linenr)
+			continue;
+
+		parsed_line = rtrim(line);
+		cl = code_line__new(parsed_line, linenr, code->nr_events);
+		if (!cl)
+			goto out_err;
+		if (code_line__match_with_dl(cl, &notes->src->source) < 0)
+			goto out_err;
+
+		list_add_tail(&cl->node, &code->lines);
+		if (linenr == end_linenr) {
+			ret = 0;
+			goto out;
+		}
+	}
+out_err:
+	code_lines__free(&code->lines);
+out:
+	free(line);
+	fclose(file);
+	return ret;
+}
+
+static int symbol__get_source_code(struct symbol *sym, struct map *map,
+				   struct perf_evsel *evsel)
+{
+	struct annotation *notes = symbol__annotation(sym);
+	struct source_code *code;
+	bool tmp;
+	u64 start = map__rip_2objdump(map, sym->start);
+	u64 end = map__rip_2objdump(map, sym->end - 1);
+	int start_linenr, end_linenr, ret = -1;
+	char *path, *start_srcline = NULL, *end_srcline = NULL;
+	char *d_name = map->dso->symsrc_filename;
+
+	if (!d_name)
+		return -1;
+
+	tmp = srcline_full_filename;
+	srcline_full_filename = true;
+	start_srcline = get_srcline(map->dso, start, NULL, false);
+	end_srcline = get_srcline(map->dso, end, NULL, false);
+	srcline_full_filename = tmp;
+
+	if (parse_srcline(start_srcline, &path, &start_linenr) < 0)
+		goto out;
+	if (parse_srcline(end_srcline, &path, &end_linenr) < 0)
+		goto out;
+
+	code = zalloc(sizeof(struct source_code));
+	if (code == NULL)
+		goto out;
+
+	if (perf_evsel__is_group_event(evsel))
+		code->nr_events = evsel->nr_members;
+	else
+		code->nr_events = 1;
+
+	/* To read a function header for the sym */
+	if (start_linenr > 4)
+		start_linenr -= 4;
+	else
+		start_linenr = 1;
+
+	if (source_code__collect(code, notes, path, d_name,
+				 start_linenr, end_linenr) < 0) {
+		zfree(&code);
+		goto out;
+	}
+
+	ret = 0;
+	notes->src->code = code;
+out:
+	free_srcline(start_srcline);
+	free_srcline(end_srcline);
+	return ret;
+}
+
 int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_name, size_t privsize)
 {
 	struct dso *dso = map->dso;
@@ -1497,7 +1764,6 @@ int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_na
 
 	if (nline == 0)
 		pr_err("No output from %s\n", command);
-
 	/*
 	 * kallsyms does not have symbol sizes so there may a nop at the end.
 	 * Remove it.
@@ -1755,6 +2021,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
 	struct sym_hist *h = annotation__histogram(notes, evsel->idx);
 	struct disasm_line *pos, *queue = NULL;
 	u64 start = map__rip_2objdump(map, sym->start);
+	bool src_code_only = false;
 	int printed = 2, queue_len = 0;
 	int more = 0;
 	u64 len;
@@ -1775,8 +2042,14 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
 	if (perf_evsel__is_group_event(evsel))
 		width *= evsel->nr_members;
 
-	graph_dotted_len = printf(" %-*.*s|	Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n",
-	       width, width, "Percent", d_filename, evsel_name, h->sum);
+	if (symbol_conf.annotate_src_only && notes->src->has_src_code)
+		src_code_only = true;
+
+	graph_dotted_len = printf(" %-*.*s|	%s of %s for %s (%" PRIu64 " samples)\n",
+				  width, width, "Percent",
+				  src_code_only ? "Source code" : "Source code & Disassembly",
+				  src_code_only ? notes->src->code->path : d_filename,
+				  evsel_name, h->sum);
 
 	printf("%-*.*s----\n",
 	       graph_dotted_len, graph_dotted_len, graph_dotted_line);
@@ -1784,6 +2057,16 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
 	if (verbose > 0)
 		symbol__annotate_hits(sym, evsel);
 
+	if (src_code_only) {
+		struct source_code *code = notes->src->code;
+		struct code_line *cl;
+
+		list_for_each_entry(cl, &code->lines, node)
+			source_code__print(cl, code->nr_events, notes, evsel);
+
+		goto out;
+	}
+
 	list_for_each_entry(pos, &notes->src->source, node) {
 		if (context && queue == NULL) {
 			queue = pos;
@@ -1820,7 +2103,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
 			break;
 		}
 	}
-
+out:
+	printf("\n");
 	free(filename);
 
 	return more;
@@ -1890,6 +2174,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
 			 bool full_paths, int min_pcnt, int max_lines)
 {
 	struct dso *dso = map->dso;
+	struct annotation *notes = symbol__annotation(sym);
 	struct rb_root source_line = RB_ROOT;
 	u64 len;
 
@@ -1904,11 +2189,17 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
 		print_summary(&source_line, dso->long_name);
 	}
 
+	if (symbol_conf.annotate_src_only &&
+	    symbol__get_source_code(sym, map, evsel) == 0)
+		notes->src->has_src_code = true;
+
 	symbol__annotate_printf(sym, map, evsel, full_paths,
 				min_pcnt, max_lines, 0);
 	if (print_lines)
 		symbol__free_source_line(sym, len);
 
+	if (notes->src->has_src_code)
+		symbol__free_source_code(sym);
 	disasm__purge(&symbol__annotation(sym)->src->source);
 
 	return 0;
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 948aa8e..dd7ddae 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -56,6 +56,11 @@ int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *
 
 struct annotation;
 
+struct disasm_line_samples {
+	double		percent;
+	u64		nr;
+};
+
 struct disasm_line {
 	struct list_head    node;
 	s64		    offset;
@@ -95,6 +100,21 @@ struct cyc_hist {
 	u16	reset;
 };
 
+struct code_line {
+	struct list_head    node;
+	int		    line_nr;
+	char		    *line;
+	int		    nr_matched_dl;
+	struct disasm_line  **matched_dl_arr;
+	struct disasm_line_samples *samples_sum;
+};
+
+struct source_code {
+	char		 *path;
+	int		 nr_events;
+	struct list_head lines;
+};
+
 struct source_line_samples {
 	double		percent;
 	double		percent_sum;
@@ -123,7 +143,9 @@ struct source_line {
  */
 struct annotated_source {
 	struct list_head   source;
+	struct source_code *code;
 	struct source_line *lines;
+	bool   		   has_src_code;
 	int    		   nr_histograms;
 	size_t		   sizeof_sym_hist;
 	struct cyc_hist	   *cycles_hist;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 70e389b..71228bd 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -35,6 +35,7 @@ struct symbol_conf symbol_conf = {
 	.use_modules		= true,
 	.try_vmlinux_path	= true,
 	.annotate_src		= true,
+	.annotate_src_only	= false,
 	.demangle		= true,
 	.demangle_kernel	= false,
 	.cumulate_callchain	= true,
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 6c358b7..190be1d 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -108,6 +108,7 @@ struct symbol_conf {
 			kptr_restrict,
 			annotate_asm_raw,
 			annotate_src,
+			annotate_src_only,
 			event_group,
 			demangle,
 			demangle_kernel,
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 7/7] perf annotate: Support the new source code view for TUI
  2017-03-09 17:35 [PATCH v3 0/7] perf annotate: Fixes & Introduce --source-only and new source code view Taeung Song
                   ` (5 preceding siblings ...)
  2017-03-09 17:35 ` [PATCH v3 6/7] perf annotate: Introduce --source-only option Taeung Song
@ 2017-03-09 17:35 ` Taeung Song
  6 siblings, 0 replies; 8+ messages in thread
From: Taeung Song @ 2017-03-09 17:35 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: linux-kernel, Jiri Olsa, Namhyung Kim, Ingo Molnar,
	Peter Zijlstra, Wang Nan, Masami Hiramatsu, Taeung Song,
	Jiri Olsa

To make source code view more readable,
add the new source code view for TUI
instead of confusing mixed source code & dissambly view.

This view can show source code per symbol(function).
and it can be toggled by a 's' key.
And support 'k' and 't' key for line numbers and total period.

For example, if target symbol is 'hex2u64' of util/util.c

Before:

       |    Disassembly of section .text:
       |
       |    000000000053ef9e <hex2u64>:
       |    hex2u64():
       |    /*
       |     * While we find nice hex chars, build a long_val.
       |     * Return number of chars processed.
       |     */
       |    int hex2u64(const char *ptr, u64 *long_val)
       |    {
       |      push   %rbp
  1.79 |      mov    %rsp,%rbp
       |      sub    $0x30,%rsp

After:

       |     * While we find nice hex chars, build a long_val.
       |     * Return number of chars processed.
       |     */
       |    int hex2u64(const char *ptr, u64 *long_val)
  1.79 |    {
       |        const char *p = ptr;
       |        *long_val = 0;
       |
 28.57 |        while (*p) {
 30.36 |                const int hex_val = hex(*p);
       |
 12.50 |                if (hex_val < 0)
       |                        break;
       |
 23.21 |                *long_val = (*long_val << 4) | hex_val;
       |                p++;
       |        }
       |
  1.79 |        return p - ptr;

Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
 tools/perf/Documentation/perfconfig.example |   1 -
 tools/perf/ui/browsers/annotate.c           | 233 ++++++++++++++++++++--------
 tools/perf/util/annotate.c                  |  10 +-
 tools/perf/util/annotate.h                  |   7 +
 4 files changed, 180 insertions(+), 71 deletions(-)

diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example
index 2b477c1..c9fc41b 100644
--- a/tools/perf/Documentation/perfconfig.example
+++ b/tools/perf/Documentation/perfconfig.example
@@ -23,7 +23,6 @@
 [annotate]
 
 	# Defaults
-	hide_src_code = false
 	use_offset = true
 	jump_arrows = true
 	show_nr_jumps = false
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 03b2012..ac01d75 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -27,8 +27,7 @@ struct browser_disasm_line {
 };
 
 static struct annotate_browser_opt {
-	bool hide_src_code,
-	     use_offset,
+	bool use_offset,
 	     jump_arrows,
 	     show_linenr,
 	     show_nr_jumps,
@@ -39,7 +38,7 @@ static struct annotate_browser_opt {
 };
 
 struct annotate_browser {
-	struct ui_browser b;
+	struct ui_browser b, cb;
 	struct rb_root	  entries;
 	struct rb_node	  *curr_hot;
 	struct disasm_line  *selection;
@@ -52,6 +51,7 @@ struct annotate_browser {
 	int		    nr_jumps;
 	bool		    searching_backwards;
 	bool		    have_cycles;
+	bool		    has_src_code;
 	u8		    addr_width;
 	u8		    jumps_width;
 	u8		    target_width;
@@ -68,12 +68,9 @@ static inline struct browser_disasm_line *disasm_line__browser(struct disasm_lin
 static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
 				void *entry)
 {
-	if (annotate_browser__opts.hide_src_code) {
-		struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
-		return dl->offset == -1;
-	}
+	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
 
-	return false;
+	return dl->offset == -1;
 }
 
 static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
@@ -104,15 +101,61 @@ static int annotate_browser__pcnt_width(struct annotate_browser *ab)
 	return w;
 }
 
+static void annotate_code_browser__write(struct ui_browser *browser, void *entry, int row)
+{
+	struct annotate_browser *ab = container_of(browser, struct annotate_browser, cb);
+	struct code_line *cl = list_entry(entry, struct code_line, node);
+	bool current_entry = ui_browser__is_current_entry(browser, row);
+	int i, printed;
+	double percent, max_percent = 0.0;
+	char line[256];
+
+	for (i = 0; i < ab->nr_events; i++) {
+		if (cl->samples_sum[i].percent > max_percent)
+			max_percent = cl->samples_sum[i].percent;
+	}
+
+	for (i = 0; i < ab->nr_events; i++) {
+		if (max_percent == 0.0) {
+			ui_browser__set_percent_color(browser, 0, current_entry);
+			ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
+			break;
+		}
+
+		percent = cl->samples_sum[i].percent;
+		ui_browser__set_percent_color(browser, percent, current_entry);
+
+		if (annotate_browser__opts.show_total_period)
+			ui_browser__printf(browser, "%6" PRIu64 " ",
+					   cl->samples_sum[i].nr);
+		else
+			ui_browser__printf(browser, "%6.2f ", percent);
+
+		if (max_percent < percent)
+			max_percent = percent;
+	}
+
+	SLsmg_write_char(' ');
+
+	if (annotate_browser__opts.show_linenr)
+		printed = scnprintf(line, sizeof(line), "%-*d ",
+				    ab->addr_width + 2, cl->line_nr);
+	else
+		printed = scnprintf(line, sizeof(line), "%*s  ",
+				    ab->addr_width, " ");
+
+	ui_browser__write_nstring(browser, line, printed);
+	ui_browser__write_nstring(browser, cl->line, browser->width);
+}
+
 static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
 {
 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
 	struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
 	struct browser_disasm_line *bdl = disasm_line__browser(dl);
 	bool current_entry = ui_browser__is_current_entry(browser, row);
-	bool change_color = (!annotate_browser__opts.hide_src_code &&
-			     (!current_entry || (browser->use_navkeypressed &&
-					         !browser->navkeypressed)));
+	bool change_color = !current_entry || (browser->use_navkeypressed &&
+					       !browser->navkeypressed);
 	int width = browser->width, printed;
 	int i, pcnt_width = annotate_browser__pcnt_width(ab);
 	double percent_max = 0.0;
@@ -271,19 +314,25 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
 	bcursor = disasm_line__browser(cursor);
 	btarget = disasm_line__browser(target);
 
-	if (annotate_browser__opts.hide_src_code) {
-		from = bcursor->idx_asm;
-		to = btarget->idx_asm;
-	} else {
-		from = (u64)bcursor->idx;
-		to = (u64)btarget->idx;
-	}
+	from = bcursor->idx_asm;
+	to = btarget->idx_asm;
 
 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
 	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
 				 from, to);
 }
 
+static unsigned int annotate_code_browser__refresh(struct ui_browser *browser)
+{
+	struct annotate_browser *ab = container_of(browser, struct annotate_browser, cb);
+	int ret = ui_browser__list_head_refresh(browser);
+	int pcnt_width = annotate_browser__pcnt_width(ab);
+
+	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
+	__ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
+	return ret;
+}
+
 static unsigned int annotate_browser__refresh(struct ui_browser *browser)
 {
 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
@@ -364,12 +413,37 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser,
 	bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
 	pos = ((struct disasm_line *)bpos) - 1;
 	idx = bpos->idx;
-	if (annotate_browser__opts.hide_src_code)
-		idx = bpos->idx_asm;
+	idx = bpos->idx_asm;
 	annotate_browser__set_top(browser, pos, idx);
 	browser->curr_hot = nd;
 }
 
+static void annotate_code_browser__calc_percent(struct annotate_browser *browser,
+						struct perf_evsel *evsel)
+{
+	int i;
+	struct map_symbol *ms = browser->b.priv;
+	struct symbol *sym = ms->sym;
+	struct annotation *notes = symbol__annotation(sym);
+	struct code_line *cl;
+	struct list_head *code_lines = browser->cb.entries;
+
+	pthread_mutex_lock(&notes->lock);
+
+	list_for_each_entry(cl, code_lines, node) {
+		for (i = 0; i < browser->nr_events; i++) {
+			cl->samples_sum[i].percent = 0.0;
+			cl->samples_sum[i].nr = 0;
+		}
+
+		for (i = 0; i < cl->nr_matched_dl; i++) {
+			code_line__sum_samples(cl, cl->matched_dl_arr[i], notes, evsel);
+		}
+	}
+
+	pthread_mutex_unlock(&notes->lock);
+}
+
 static void annotate_browser__calc_percent(struct annotate_browser *browser,
 					   struct perf_evsel *evsel)
 {
@@ -422,45 +496,6 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
 	browser->curr_hot = rb_last(&browser->entries);
 }
 
-static bool annotate_browser__toggle_source(struct annotate_browser *browser)
-{
-	struct disasm_line *dl;
-	struct browser_disasm_line *bdl;
-	off_t offset = browser->b.index - browser->b.top_idx;
-
-	browser->b.seek(&browser->b, offset, SEEK_CUR);
-	dl = list_entry(browser->b.top, struct disasm_line, node);
-	bdl = disasm_line__browser(dl);
-
-	if (annotate_browser__opts.hide_src_code) {
-		if (bdl->idx_asm < offset)
-			offset = bdl->idx;
-
-		browser->b.nr_entries = browser->nr_entries;
-		annotate_browser__opts.hide_src_code = false;
-		browser->b.seek(&browser->b, -offset, SEEK_CUR);
-		browser->b.top_idx = bdl->idx - offset;
-		browser->b.index = bdl->idx;
-	} else {
-		if (bdl->idx_asm < 0) {
-			ui_helpline__puts("Only available for assembly lines.");
-			browser->b.seek(&browser->b, -offset, SEEK_CUR);
-			return false;
-		}
-
-		if (bdl->idx_asm < offset)
-			offset = bdl->idx_asm;
-
-		browser->b.nr_entries = browser->nr_asm_entries;
-		annotate_browser__opts.hide_src_code = true;
-		browser->b.seek(&browser->b, -offset, SEEK_CUR);
-		browser->b.top_idx = bdl->idx_asm - offset;
-		browser->b.index = bdl->idx_asm;
-	}
-
-	return true;
-}
-
 static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
 {
 	ui_browser__reset_index(&browser->b);
@@ -696,6 +731,54 @@ static void annotate_browser__update_addr_width(struct annotate_browser *browser
 		browser->addr_width += browser->jumps_width + 1;
 }
 
+static int annotate_code_browser__run(struct annotate_browser *browser,
+				      struct perf_evsel *evsel, int delay_secs)
+{
+	int key;
+
+	if (ui_browser__show(&browser->cb, browser->cb.title, ui_helpline__current) < 0)
+		return -1;
+	annotate_code_browser__calc_percent(browser, evsel);
+
+	while (1) {
+
+		key = ui_browser__run(&browser->cb, delay_secs);
+		if (delay_secs != 0) {
+			annotate_code_browser__calc_percent(browser, evsel);
+		}
+
+		switch (key) {
+		case K_F1:
+		case 'h':
+			ui_browser__help_window(&browser->cb,
+		"UP/DOWN/PGUP\n"
+		"PGDN/SPACE    Navigate\n"
+		"q/ESC/CTRL+C  Return to dissembly view\n\n"
+		"s             Toggle source code view\n"
+		"t             Toggle total period view\n"
+		"k             Toggle line numbers\n");
+			continue;
+		case 't':
+			annotate_browser__opts.show_total_period =
+				!annotate_browser__opts.show_total_period;
+			continue;
+		case 'k':
+			annotate_browser__opts.show_linenr =
+				!annotate_browser__opts.show_linenr;
+			continue;
+		case 's':
+		case K_LEFT:
+		case K_ESC:
+		case 'q':
+		case CTRL('c'):
+			return 0;
+		default:
+			continue;
+		}
+	}
+	return 0;
+}
+
 static int annotate_browser__run(struct annotate_browser *browser,
 				 struct perf_evsel *evsel,
 				 struct hist_browser_timer *hbt)
@@ -775,7 +858,6 @@ static int annotate_browser__run(struct annotate_browser *browser,
 		"s             Toggle source code view\n"
 		"t             Toggle total period view\n"
 		"/             Search string\n"
-		"k             Toggle line numbers\n"
 		"r             Run available scripts\n"
 		"?             Search string backwards\n");
 			continue;
@@ -792,8 +874,11 @@ static int annotate_browser__run(struct annotate_browser *browser,
 			nd = browser->curr_hot;
 			break;
 		case 's':
-			if (annotate_browser__toggle_source(browser))
-				ui_helpline__puts(help);
+			if (browser->has_src_code) {
+				browser->cb.title = title;
+				annotate_code_browser__run(browser, evsel, delay_secs);
+			} else
+				ui_helpline__puts("No source code for the symbol");
 			continue;
 		case 'o':
 			annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
@@ -1095,9 +1180,27 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
 	browser.b.entries = &notes->src->source,
 	browser.b.width += 18; /* Percentage */
 
-	if (annotate_browser__opts.hide_src_code)
-		annotate_browser__init_asm_mode(&browser);
+	if (symbol__get_source_code(sym, map, evsel) == 0) {
+		struct source_code *code = notes->src->code;
+		struct code_line *cl;
+
+		browser.has_src_code = true;
+		browser.cb.refresh = annotate_code_browser__refresh;
+		browser.cb.seek = ui_browser__list_head_seek;
+		browser.cb.write = annotate_code_browser__write;
+		browser.cb.use_navkeypressed = true;
+		browser.cb.entries = &code->lines;
+
+		list_for_each_entry(cl, &code->lines, node) {
+			size_t line_len = strlen(cl->line);
+
+			if (browser.cb.width < line_len)
+				browser.cb.width = line_len;
+			browser.cb.nr_entries++;
+		}
+	}
 
+	annotate_browser__init_asm_mode(&browser);
 	annotate_browser__update_addr_width(&browser);
 
 	ret = annotate_browser__run(&browser, evsel, hbt);
@@ -1105,6 +1208,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
 		list_del(&pos->node);
 		disasm_line__free(pos);
 	}
+	symbol__free_source_code(sym);
 
 out_free_offsets:
 	free(browser.offsets);
@@ -1121,7 +1225,6 @@ static struct annotate_config {
 	const char *name;
 	bool *value;
 } annotate__configs[] = {
-	ANNOTATE_CFG(hide_src_code),
 	ANNOTATE_CFG(jump_arrows),
 	ANNOTATE_CFG(show_linenr),
 	ANNOTATE_CFG(show_nr_jumps),
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 7d1c7cc..d8a3a50 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -1396,7 +1396,7 @@ static void code_lines__free(struct list_head *code_lines)
 	}
 }
 
-static int symbol__free_source_code(struct symbol *sym)
+int symbol__free_source_code(struct symbol *sym)
 {
 	struct annotation *notes = symbol__annotation(sym);
 	struct source_code *code = notes->src->code;
@@ -1410,8 +1410,8 @@ static int symbol__free_source_code(struct symbol *sym)
 	return 0;
 }
 
-static void code_line__sum_samples(struct code_line *cl, struct disasm_line *dl,
-				   struct annotation *notes, struct perf_evsel *evsel)
+void code_line__sum_samples(struct code_line *cl, struct disasm_line *dl,
+			    struct annotation *notes, struct perf_evsel *evsel)
 {
 	int i;
 	u64 nr_samples;
@@ -1569,8 +1569,8 @@ static int source_code__collect(struct source_code *code,
 	return ret;
 }
 
-static int symbol__get_source_code(struct symbol *sym, struct map *map,
-				   struct perf_evsel *evsel)
+int symbol__get_source_code(struct symbol *sym, struct map *map,
+			    struct perf_evsel *evsel)
 {
 	struct annotation *notes = symbol__annotation(sym);
 	struct source_code *code;
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index dd7ddae..e125eca 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -109,6 +109,9 @@ struct code_line {
 	struct disasm_line_samples *samples_sum;
 };
 
+void code_line__sum_samples(struct code_line *cl, struct disasm_line *dl,
+			    struct annotation *notes, struct perf_evsel *evsel);
+
 struct source_code {
 	char		 *path;
 	int		 nr_events;
@@ -180,6 +183,10 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr);
 int symbol__alloc_hist(struct symbol *sym);
 void symbol__annotate_zero_histograms(struct symbol *sym);
 
+int symbol__free_source_code(struct symbol *sym);
+int symbol__get_source_code(struct symbol *sym, struct map *map,
+			    struct perf_evsel *evsel);
+
 int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_name, size_t privsize);
 
 enum symbol_disassemble_errno {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2017-03-09 17:45 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-09 17:35 [PATCH v3 0/7] perf annotate: Fixes & Introduce --source-only and new source code view Taeung Song
2017-03-09 17:35 ` [PATCH v3 1/7] perf annotate: Use build-id dir when reading link name Taeung Song
2017-03-09 17:35 ` [PATCH v3 2/7] perf annotate: Avoid division by zero when calculating percent Taeung Song
2017-03-09 17:35 ` [PATCH v3 3/7] perf annotate: Fix missing setting nr samples on source_line Taeung Song
2017-03-09 17:35 ` [PATCH v3 4/7] perf annotate: More exactly grep -v in symbol__disassemble() Taeung Song
2017-03-09 17:35 ` [PATCH v3 5/7] perf annotate: Get correct line numbers matched with addr Taeung Song
2017-03-09 17:35 ` [PATCH v3 6/7] perf annotate: Introduce --source-only option Taeung Song
2017-03-09 17:35 ` [PATCH v3 7/7] perf annotate: Support the new source code view for TUI Taeung Song

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.