2017-03-09 17:35:50

by Taeung Song

[permalink] [raw]
Subject: [PATCH v3 0/7] perf annotate: Fixes & Introduce --source-only and new source code view

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


2017-03-09 17:37:37

by Taeung Song

[permalink] [raw]
Subject: [PATCH v3 1/7] perf annotate: Use build-id dir when reading link name

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 <[email protected]>
Cc: Jiri Olsa <[email protected]>
Signed-off-by: Taeung Song <[email protected]>
---
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

2017-03-09 17:37:35

by Taeung Song

[permalink] [raw]
Subject: [PATCH v3 3/7] perf annotate: Fix missing setting nr samples on source_line

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 <[email protected]>
Cc: Jiri Olsa <[email protected]>
Signed-off-by: Taeung Song <[email protected]>
---
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

2017-03-09 17:38:42

by Taeung Song

[permalink] [raw]
Subject: [PATCH v3 5/7] perf annotate: Get correct line numbers matched with addr

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 <[email protected]>
Cc: Jiri Olsa <[email protected]>
Signed-off-by: Taeung Song <[email protected]>
---
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

2017-03-09 17:38:41

by Taeung Song

[permalink] [raw]
Subject: [PATCH v3 2/7] perf annotate: Avoid division by zero when calculating percent

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 <[email protected]>
Cc: Jiri Olsa <[email protected]>
Signed-off-by: Taeung Song <[email protected]>
---
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

2017-03-09 17:38:39

by Taeung Song

[permalink] [raw]
Subject: [PATCH v3 4/7] perf annotate: More exactly grep -v in symbol__disassemble()

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 <[email protected]>
Cc: Jiri Olsa <[email protected]>
Signed-off-by: Taeung Song <[email protected]>
---
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

2017-03-09 17:43:36

by Taeung Song

[permalink] [raw]
Subject: [PATCH v3 7/7] perf annotate: Support the new source code view for TUI

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 <[email protected]>
Cc: Jiri Olsa <[email protected]>
Signed-off-by: Taeung Song <[email protected]>
---
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

2017-03-09 17:45:12

by Taeung Song

[permalink] [raw]
Subject: [PATCH v3 6/7] perf annotate: Introduce --source-only option

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 <[email protected]>
Cc: Jiri Olsa <[email protected]>
Signed-off-by: Taeung Song <[email protected]>
---
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