1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
5 * Parts came from builtin-annotate.c, see those files for further
13 #include "util.h" // hex_width()
28 #include "debuginfo.h"
30 #include "annotate-data.h"
33 #include "bpf-event.h"
34 #include "bpf-utils.h"
35 #include "block-range.h"
37 #include "dwarf-regs.h"
38 #include "util/event.h"
39 #include "util/sharded_mutex.h"
40 #include "arch/common.h"
41 #include "namespaces.h"
46 #include <linux/bitops.h>
47 #include <linux/kernel.h>
48 #include <linux/string.h>
49 #include <linux/zalloc.h>
50 #include <subcmd/parse-options.h>
51 #include <subcmd/run-command.h>
54 /* FIXME: For the HE_COLORSET */
55 #include "ui/browser.h"
58 * FIXME: Using the same values as slang.h,
59 * but that header may not be available everywhere
61 #define LARROW_CHAR ((unsigned char)',')
62 #define RARROW_CHAR ((unsigned char)'+')
63 #define DARROW_CHAR ((unsigned char)'.')
64 #define UARROW_CHAR ((unsigned char)'-')
66 #include <linux/ctype.h>
68 /* global annotation options */
69 struct annotation_options annotate_opts
;
71 /* Data type collection debug statistics */
72 struct annotated_data_stat ann_data_stat
;
73 LIST_HEAD(ann_insn_stat
);
75 /* Pseudo data types */
76 struct annotated_data_type stackop_type
= {
78 .type_name
= (char *)"(stack operation)",
79 .children
= LIST_HEAD_INIT(stackop_type
.self
.children
),
83 struct annotated_data_type canary_type
= {
85 .type_name
= (char *)"(stack canary)",
86 .children
= LIST_HEAD_INIT(canary_type
.self
.children
),
90 /* symbol histogram: key = offset << 16 | evsel->core.idx */
91 static size_t sym_hist_hash(long key
, void *ctx __maybe_unused
)
93 return (key
>> 16) + (key
& 0xffff);
96 static bool sym_hist_equal(long key1
, long key2
, void *ctx __maybe_unused
)
101 static struct annotated_source
*annotated_source__new(void)
103 struct annotated_source
*src
= zalloc(sizeof(*src
));
106 INIT_LIST_HEAD(&src
->source
);
111 static __maybe_unused
void annotated_source__delete(struct annotated_source
*src
)
113 struct hashmap_entry
*cur
;
120 hashmap__for_each_entry(src
->samples
, cur
, bkt
)
122 hashmap__free(src
->samples
);
124 zfree(&src
->histograms
);
128 static int annotated_source__alloc_histograms(struct annotated_source
*src
,
131 src
->nr_histograms
= nr_hists
;
132 src
->histograms
= calloc(nr_hists
, sizeof(*src
->histograms
));
134 if (src
->histograms
== NULL
)
137 src
->samples
= hashmap__new(sym_hist_hash
, sym_hist_equal
, NULL
);
138 if (src
->samples
== NULL
)
139 zfree(&src
->histograms
);
141 return src
->histograms
? 0 : -1;
144 void symbol__annotate_zero_histograms(struct symbol
*sym
)
146 struct annotation
*notes
= symbol__annotation(sym
);
148 annotation__lock(notes
);
149 if (notes
->src
!= NULL
) {
150 memset(notes
->src
->histograms
, 0,
151 notes
->src
->nr_histograms
* sizeof(*notes
->src
->histograms
));
152 hashmap__clear(notes
->src
->samples
);
154 if (notes
->branch
&& notes
->branch
->cycles_hist
) {
155 memset(notes
->branch
->cycles_hist
, 0,
156 symbol__size(sym
) * sizeof(struct cyc_hist
));
158 annotation__unlock(notes
);
161 static int __symbol__account_cycles(struct cyc_hist
*ch
,
163 unsigned offset
, unsigned cycles
,
167 * For now we can only account one basic block per
168 * final jump. But multiple could be overlapping.
169 * Always account the longest one. So when
170 * a shorter one has been already seen throw it away.
172 * We separately always account the full cycles.
174 ch
[offset
].num_aggr
++;
175 ch
[offset
].cycles_aggr
+= cycles
;
177 if (cycles
> ch
[offset
].cycles_max
)
178 ch
[offset
].cycles_max
= cycles
;
180 if (ch
[offset
].cycles_min
) {
181 if (cycles
&& cycles
< ch
[offset
].cycles_min
)
182 ch
[offset
].cycles_min
= cycles
;
184 ch
[offset
].cycles_min
= cycles
;
186 if (!have_start
&& ch
[offset
].have_start
)
188 if (ch
[offset
].num
) {
189 if (have_start
&& (!ch
[offset
].have_start
||
190 ch
[offset
].start
> start
)) {
191 ch
[offset
].have_start
= 0;
192 ch
[offset
].cycles
= 0;
194 if (ch
[offset
].reset
< 0xffff)
196 } else if (have_start
&&
197 ch
[offset
].start
< start
)
201 if (ch
[offset
].num
< NUM_SPARKS
)
202 ch
[offset
].cycles_spark
[ch
[offset
].num
] = cycles
;
204 ch
[offset
].have_start
= have_start
;
205 ch
[offset
].start
= start
;
206 ch
[offset
].cycles
+= cycles
;
211 static int __symbol__inc_addr_samples(struct map_symbol
*ms
,
212 struct annotated_source
*src
, int evidx
, u64 addr
,
213 struct perf_sample
*sample
)
215 struct symbol
*sym
= ms
->sym
;
219 struct sym_hist_entry
*entry
;
221 pr_debug3("%s: addr=%#" PRIx64
"\n", __func__
, map__unmap_ip(ms
->map
, addr
));
223 if ((addr
< sym
->start
|| addr
>= sym
->end
) &&
224 (addr
!= sym
->end
|| sym
->start
!= sym
->end
)) {
225 pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64
", addr=%#" PRIx64
", end=%#" PRIx64
"\n",
226 __func__
, __LINE__
, sym
->name
, sym
->start
, addr
, sym
->end
);
230 offset
= addr
- sym
->start
;
231 h
= annotated_source__histogram(src
, evidx
);
233 pr_debug("%s(%d): ENOMEM! sym->name=%s, start=%#" PRIx64
", addr=%#" PRIx64
", end=%#" PRIx64
", func: %d\n",
234 __func__
, __LINE__
, sym
->name
, sym
->start
, addr
, sym
->end
, sym
->type
== STT_FUNC
);
238 hash_key
= offset
<< 16 | evidx
;
239 if (!hashmap__find(src
->samples
, hash_key
, &entry
)) {
240 entry
= zalloc(sizeof(*entry
));
244 if (hashmap__add(src
->samples
, hash_key
, entry
) < 0)
249 h
->period
+= sample
->period
;
251 entry
->period
+= sample
->period
;
253 pr_debug3("%#" PRIx64
" %s: period++ [addr: %#" PRIx64
", %#" PRIx64
254 ", evidx=%d] => nr_samples: %" PRIu64
", period: %" PRIu64
"\n",
255 sym
->start
, sym
->name
, addr
, addr
- sym
->start
, evidx
,
256 entry
->nr_samples
, entry
->period
);
260 struct annotated_branch
*annotation__get_branch(struct annotation
*notes
)
265 if (notes
->branch
== NULL
)
266 notes
->branch
= zalloc(sizeof(*notes
->branch
));
268 return notes
->branch
;
271 static struct annotated_branch
*symbol__find_branch_hist(struct symbol
*sym
,
272 unsigned int br_cntr_nr
)
274 struct annotation
*notes
= symbol__annotation(sym
);
275 struct annotated_branch
*branch
;
276 const size_t size
= symbol__size(sym
);
278 branch
= annotation__get_branch(notes
);
282 if (branch
->cycles_hist
== NULL
) {
283 branch
->cycles_hist
= calloc(size
, sizeof(struct cyc_hist
));
284 if (!branch
->cycles_hist
)
288 if (br_cntr_nr
&& branch
->br_cntr
== NULL
) {
289 branch
->br_cntr
= calloc(br_cntr_nr
* size
, sizeof(u64
));
290 if (!branch
->br_cntr
)
297 struct annotated_source
*symbol__hists(struct symbol
*sym
, int nr_hists
)
299 struct annotation
*notes
= symbol__annotation(sym
);
301 if (notes
->src
== NULL
) {
302 notes
->src
= annotated_source__new();
303 if (notes
->src
== NULL
)
305 goto alloc_histograms
;
308 if (notes
->src
->histograms
== NULL
) {
310 annotated_source__alloc_histograms(notes
->src
, nr_hists
);
316 static int symbol__inc_addr_samples(struct map_symbol
*ms
,
317 struct evsel
*evsel
, u64 addr
,
318 struct perf_sample
*sample
)
320 struct symbol
*sym
= ms
->sym
;
321 struct annotated_source
*src
;
325 src
= symbol__hists(sym
, evsel
->evlist
->core
.nr_entries
);
326 return src
? __symbol__inc_addr_samples(ms
, src
, evsel
->core
.idx
, addr
, sample
) : 0;
329 static int symbol__account_br_cntr(struct annotated_branch
*branch
,
334 unsigned int br_cntr_nr
= evsel__leader(evsel
)->br_cntr_nr
;
335 unsigned int base
= evsel__leader(evsel
)->br_cntr_idx
;
336 unsigned int off
= offset
* evsel
->evlist
->nr_br_cntr
;
337 u64
*branch_br_cntr
= branch
->br_cntr
;
338 unsigned int i
, mask
, width
;
340 if (!br_cntr
|| !branch_br_cntr
)
343 perf_env__find_br_cntr_info(evsel__env(evsel
), NULL
, &width
);
344 mask
= (1L << width
) - 1;
345 for (i
= 0; i
< br_cntr_nr
; i
++) {
346 u64 cntr
= (br_cntr
>> i
* width
) & mask
;
348 branch_br_cntr
[off
+ i
+ base
] += cntr
;
350 branch_br_cntr
[off
+ i
+ base
] |= ANNOTATION__BR_CNTR_SATURATED_FLAG
;
356 static int symbol__account_cycles(u64 addr
, u64 start
, struct symbol
*sym
,
357 unsigned cycles
, struct evsel
*evsel
,
360 struct annotated_branch
*branch
;
366 branch
= symbol__find_branch_hist(sym
, evsel
->evlist
->nr_br_cntr
);
369 if (addr
< sym
->start
|| addr
>= sym
->end
)
373 if (start
< sym
->start
|| start
>= sym
->end
)
378 offset
= addr
- sym
->start
;
379 ret
= __symbol__account_cycles(branch
->cycles_hist
,
380 start
? start
- sym
->start
: 0,
387 return symbol__account_br_cntr(branch
, evsel
, offset
, br_cntr
);
390 int addr_map_symbol__account_cycles(struct addr_map_symbol
*ams
,
391 struct addr_map_symbol
*start
,
403 * Only set start when IPC can be computed. We can only
404 * compute it when the basic block is completely in a single
406 * Special case the case when the jump is elsewhere, but
407 * it starts on the function start.
410 (start
->ms
.sym
== ams
->ms
.sym
||
412 start
->addr
== ams
->ms
.sym
->start
+ map__start(ams
->ms
.map
))))
413 saddr
= start
->al_addr
;
415 pr_debug2("BB with bad start: addr %"PRIx64
" start %"PRIx64
" sym %"PRIx64
" saddr %"PRIx64
"\n",
417 start
? start
->addr
: 0,
418 ams
->ms
.sym
? ams
->ms
.sym
->start
+ map__start(ams
->ms
.map
) : 0,
420 err
= symbol__account_cycles(ams
->al_addr
, saddr
, ams
->ms
.sym
, cycles
, evsel
, br_cntr
);
422 pr_debug2("account_cycles failed %d\n", err
);
426 struct annotation_line
*annotated_source__get_line(struct annotated_source
*src
,
429 struct annotation_line
*al
;
431 list_for_each_entry(al
, &src
->source
, node
) {
432 if (al
->offset
== offset
)
438 static unsigned annotation__count_insn(struct annotation
*notes
, u64 start
, u64 end
)
440 struct annotation_line
*al
;
443 al
= annotated_source__get_line(notes
->src
, start
);
447 list_for_each_entry_from(al
, ¬es
->src
->source
, node
) {
448 if (al
->offset
== -1)
450 if ((u64
)al
->offset
> end
)
457 static void annotated_branch__delete(struct annotated_branch
*branch
)
460 zfree(&branch
->cycles_hist
);
461 free(branch
->br_cntr
);
466 static void annotation__count_and_fill(struct annotation
*notes
, u64 start
, u64 end
, struct cyc_hist
*ch
)
469 unsigned int cover_insn
= 0;
471 n_insn
= annotation__count_insn(notes
, start
, end
);
472 if (n_insn
&& ch
->num
&& ch
->cycles
) {
473 struct annotation_line
*al
;
474 struct annotated_branch
*branch
;
475 float ipc
= n_insn
/ ((double)ch
->cycles
/ (double)ch
->num
);
477 /* Hide data when there are too many overlaps. */
478 if (ch
->reset
>= 0x7fff)
481 al
= annotated_source__get_line(notes
->src
, start
);
485 list_for_each_entry_from(al
, ¬es
->src
->source
, node
) {
486 if (al
->offset
== -1)
488 if ((u64
)al
->offset
> end
)
490 if (al
->cycles
&& al
->cycles
->ipc
== 0.0) {
491 al
->cycles
->ipc
= ipc
;
496 branch
= annotation__get_branch(notes
);
497 if (cover_insn
&& branch
) {
498 branch
->hit_cycles
+= ch
->cycles
;
499 branch
->hit_insn
+= n_insn
* ch
->num
;
500 branch
->cover_insn
+= cover_insn
;
505 static int annotation__compute_ipc(struct annotation
*notes
, size_t size
,
508 unsigned int br_cntr_nr
= evsel
->evlist
->nr_br_cntr
;
512 if (!notes
->branch
|| !notes
->branch
->cycles_hist
)
515 notes
->branch
->total_insn
= annotation__count_insn(notes
, 0, size
- 1);
516 notes
->branch
->hit_cycles
= 0;
517 notes
->branch
->hit_insn
= 0;
518 notes
->branch
->cover_insn
= 0;
520 annotation__lock(notes
);
521 for (offset
= size
- 1; offset
>= 0; --offset
) {
524 ch
= ¬es
->branch
->cycles_hist
[offset
];
525 if (ch
&& ch
->cycles
) {
526 struct annotation_line
*al
;
528 al
= annotated_source__get_line(notes
->src
, offset
);
529 if (al
&& al
->cycles
== NULL
) {
530 al
->cycles
= zalloc(sizeof(*al
->cycles
));
531 if (al
->cycles
== NULL
) {
537 annotation__count_and_fill(notes
, ch
->start
, offset
, ch
);
538 if (al
&& ch
->num_aggr
) {
539 al
->cycles
->avg
= ch
->cycles_aggr
/ ch
->num_aggr
;
540 al
->cycles
->max
= ch
->cycles_max
;
541 al
->cycles
->min
= ch
->cycles_min
;
543 if (al
&& notes
->branch
->br_cntr
) {
545 al
->br_cntr
= calloc(br_cntr_nr
, sizeof(u64
));
551 al
->num_aggr
= ch
->num_aggr
;
552 al
->br_cntr_nr
= br_cntr_nr
;
554 memcpy(al
->br_cntr
, ¬es
->branch
->br_cntr
[offset
* br_cntr_nr
],
555 br_cntr_nr
* sizeof(u64
));
561 while (++offset
< (s64
)size
) {
562 struct cyc_hist
*ch
= ¬es
->branch
->cycles_hist
[offset
];
564 if (ch
&& ch
->cycles
) {
565 struct annotation_line
*al
;
567 al
= annotated_source__get_line(notes
->src
, offset
);
576 annotation__unlock(notes
);
580 int addr_map_symbol__inc_samples(struct addr_map_symbol
*ams
, struct perf_sample
*sample
,
583 return symbol__inc_addr_samples(&ams
->ms
, evsel
, ams
->al_addr
, sample
);
586 int hist_entry__inc_addr_samples(struct hist_entry
*he
, struct perf_sample
*sample
,
587 struct evsel
*evsel
, u64 ip
)
589 return symbol__inc_addr_samples(&he
->ms
, evsel
, ip
, sample
);
593 void annotation__exit(struct annotation
*notes
)
595 annotated_source__delete(notes
->src
);
596 annotated_branch__delete(notes
->branch
);
599 static struct sharded_mutex
*sharded_mutex
;
601 static void annotation__init_sharded_mutex(void)
603 /* As many mutexes as there are CPUs. */
604 sharded_mutex
= sharded_mutex__new(cpu__max_present_cpu().cpu
);
607 static size_t annotation__hash(const struct annotation
*notes
)
609 return (size_t)notes
;
612 static struct mutex
*annotation__get_mutex(const struct annotation
*notes
)
614 static pthread_once_t once
= PTHREAD_ONCE_INIT
;
616 pthread_once(&once
, annotation__init_sharded_mutex
);
620 return sharded_mutex__get_mutex(sharded_mutex
, annotation__hash(notes
));
623 void annotation__lock(struct annotation
*notes
)
624 NO_THREAD_SAFETY_ANALYSIS
626 struct mutex
*mutex
= annotation__get_mutex(notes
);
632 void annotation__unlock(struct annotation
*notes
)
633 NO_THREAD_SAFETY_ANALYSIS
635 struct mutex
*mutex
= annotation__get_mutex(notes
);
641 bool annotation__trylock(struct annotation
*notes
)
643 struct mutex
*mutex
= annotation__get_mutex(notes
);
648 return mutex_trylock(mutex
);
651 void annotation_line__add(struct annotation_line
*al
, struct list_head
*head
)
653 list_add_tail(&al
->node
, head
);
656 struct annotation_line
*
657 annotation_line__next(struct annotation_line
*pos
, struct list_head
*head
)
659 list_for_each_entry_continue(pos
, head
, node
)
660 if (pos
->offset
>= 0)
666 static const char *annotate__address_color(struct block_range
*br
)
668 double cov
= block_range__coverage(br
);
671 /* mark red for >75% coverage */
673 return PERF_COLOR_RED
;
675 /* mark dull for <1% coverage */
677 return PERF_COLOR_NORMAL
;
680 return PERF_COLOR_MAGENTA
;
683 static const char *annotate__asm_color(struct block_range
*br
)
685 double cov
= block_range__coverage(br
);
688 /* mark dull for <1% coverage */
690 return PERF_COLOR_NORMAL
;
693 return PERF_COLOR_BLUE
;
696 static void annotate__branch_printf(struct block_range
*br
, u64 addr
)
698 bool emit_comment
= true;
704 if (br
->is_target
&& br
->start
== addr
) {
705 struct block_range
*branch
= br
;
709 * Find matching branch to our target.
711 while (!branch
->is_branch
)
712 branch
= block_range__next(branch
);
714 p
= 100 *(double)br
->entry
/ branch
->coverage
;
718 emit_comment
= false;
723 * The percentage of coverage joined at this target in relation
724 * to the next branch.
726 printf(" +%.2f%%", p
);
730 if (br
->is_branch
&& br
->end
== addr
) {
731 double p
= 100*(double)br
->taken
/ br
->coverage
;
735 emit_comment
= false;
740 * The percentage of coverage leaving at this branch, and
741 * its prediction ratio.
743 printf(" -%.2f%% (p:%.2f%%)", p
, 100*(double)br
->pred
/ br
->taken
);
748 static int disasm_line__print(struct disasm_line
*dl
, u64 start
, int addr_fmt_width
)
750 s64 offset
= dl
->al
.offset
;
751 const u64 addr
= start
+ offset
;
752 struct block_range
*br
;
754 br
= block_range__find(addr
);
755 color_fprintf(stdout
, annotate__address_color(br
), " %*" PRIx64
":", addr_fmt_width
, addr
);
756 color_fprintf(stdout
, annotate__asm_color(br
), "%s", dl
->al
.line
);
757 annotate__branch_printf(br
, addr
);
762 annotation_line__print(struct annotation_line
*al
, struct symbol
*sym
, u64 start
,
763 struct evsel
*evsel
, u64 len
, int min_pcnt
, int printed
,
764 int max_lines
, struct annotation_line
*queue
, int addr_fmt_width
,
767 struct disasm_line
*dl
= container_of(al
, struct disasm_line
, al
);
768 struct annotation
*notes
= symbol__annotation(sym
);
769 static const char *prev_line
;
771 if (al
->offset
!= -1) {
772 double max_percent
= 0.0;
773 int i
, nr_percent
= 1;
776 for (i
= 0; i
< al
->data_nr
; i
++) {
779 percent
= annotation_data__percent(&al
->data
[i
],
782 if (percent
> max_percent
)
783 max_percent
= percent
;
786 if (al
->data_nr
> nr_percent
)
787 nr_percent
= al
->data_nr
;
789 if (max_percent
< min_pcnt
)
792 if (max_lines
&& printed
>= max_lines
)
796 list_for_each_entry_from(queue
, ¬es
->src
->source
, node
) {
799 annotation_line__print(queue
, sym
, start
, evsel
, len
,
800 0, 0, 1, NULL
, addr_fmt_width
,
805 color
= get_percent_color(max_percent
);
807 for (i
= 0; i
< nr_percent
; i
++) {
808 struct annotation_data
*data
= &al
->data
[i
];
811 percent
= annotation_data__percent(data
, percent_type
);
812 color
= get_percent_color(percent
);
814 if (symbol_conf
.show_total_period
)
815 color_fprintf(stdout
, color
, " %11" PRIu64
,
817 else if (symbol_conf
.show_nr_samples
)
818 color_fprintf(stdout
, color
, " %7" PRIu64
,
819 data
->he
.nr_samples
);
821 color_fprintf(stdout
, color
, " %7.2f", percent
);
826 disasm_line__print(dl
, start
, addr_fmt_width
);
829 * Also color the filename and line if needed, with
830 * the same color than the percentage. Don't print it
831 * twice for close colored addr with the same filename:line
834 if (!prev_line
|| strcmp(prev_line
, al
->path
)) {
835 color_fprintf(stdout
, color
, " // %s", al
->path
);
836 prev_line
= al
->path
;
841 } else if (max_lines
&& printed
>= max_lines
)
844 int width
= annotation__pcnt_width(notes
);
850 printf(" %*s:\n", width
, " ");
852 printf(" %*s: %-*d %s\n", width
, " ", addr_fmt_width
, al
->line_nr
, al
->line
);
858 static void calc_percent(struct annotation
*notes
,
860 struct annotation_data
*data
,
863 struct hists
*hists
= evsel__hists(evsel
);
864 int evidx
= evsel
->core
.idx
;
865 struct sym_hist
*sym_hist
= annotation__histogram(notes
, evidx
);
866 unsigned int hits
= 0;
869 while (offset
< end
) {
870 struct sym_hist_entry
*entry
;
872 entry
= annotated_source__hist_entry(notes
->src
, evidx
, offset
);
874 hits
+= entry
->nr_samples
;
875 period
+= entry
->period
;
880 if (sym_hist
->nr_samples
) {
881 data
->he
.period
= period
;
882 data
->he
.nr_samples
= hits
;
883 data
->percent
[PERCENT_HITS_LOCAL
] = 100.0 * hits
/ sym_hist
->nr_samples
;
886 if (hists
->stats
.nr_non_filtered_samples
)
887 data
->percent
[PERCENT_HITS_GLOBAL
] = 100.0 * hits
/ hists
->stats
.nr_non_filtered_samples
;
889 if (sym_hist
->period
)
890 data
->percent
[PERCENT_PERIOD_LOCAL
] = 100.0 * period
/ sym_hist
->period
;
892 if (hists
->stats
.total_period
)
893 data
->percent
[PERCENT_PERIOD_GLOBAL
] = 100.0 * period
/ hists
->stats
.total_period
;
896 static void annotation__calc_percent(struct annotation
*notes
,
897 struct evsel
*leader
, s64 len
)
899 struct annotation_line
*al
, *next
;
902 list_for_each_entry(al
, ¬es
->src
->source
, node
) {
906 if (al
->offset
== -1)
909 next
= annotation_line__next(al
, ¬es
->src
->source
);
910 end
= next
? next
->offset
: len
;
912 for_each_group_evsel(evsel
, leader
) {
913 struct annotation_data
*data
;
915 BUG_ON(i
>= al
->data_nr
);
917 if (symbol_conf
.skip_empty
&&
918 evsel__hists(evsel
)->stats
.nr_samples
== 0)
921 data
= &al
->data
[i
++];
923 calc_percent(notes
, evsel
, data
, al
->offset
, end
);
928 void symbol__calc_percent(struct symbol
*sym
, struct evsel
*evsel
)
930 struct annotation
*notes
= symbol__annotation(sym
);
932 annotation__calc_percent(notes
, evsel
, symbol__size(sym
));
935 static int evsel__get_arch(struct evsel
*evsel
, struct arch
**parch
)
937 struct perf_env
*env
= evsel__env(evsel
);
938 const char *arch_name
= perf_env__arch(env
);
947 *parch
= arch
= arch__find(arch_name
);
949 pr_err("%s: unsupported arch %s\n", __func__
, arch_name
);
954 err
= arch
->init(arch
, env
? env
->cpuid
: NULL
);
956 pr_err("%s: failed to initialize %s arch priv area\n",
957 __func__
, arch
->name
);
964 int symbol__annotate(struct map_symbol
*ms
, struct evsel
*evsel
,
967 struct symbol
*sym
= ms
->sym
;
968 struct annotation
*notes
= symbol__annotation(sym
);
969 struct annotate_args args
= {
971 .options
= &annotate_opts
,
973 struct arch
*arch
= NULL
;
976 err
= evsel__get_arch(evsel
, &arch
);
983 if (notes
->src
&& !list_empty(¬es
->src
->source
))
989 if (notes
->src
== NULL
) {
990 notes
->src
= annotated_source__new();
991 if (notes
->src
== NULL
)
996 if (evsel__is_group_event(evsel
)) {
999 for_each_group_evsel(pos
, evsel
) {
1000 if (symbol_conf
.skip_empty
&&
1001 evsel__hists(pos
)->stats
.nr_samples
== 0)
1006 notes
->src
->nr_events
= nr
? nr
: 1;
1008 if (annotate_opts
.full_addr
)
1009 notes
->src
->start
= map__objdump_2mem(ms
->map
, ms
->sym
->start
);
1011 notes
->src
->start
= map__rip_2objdump(ms
->map
, ms
->sym
->start
);
1013 return symbol__disassemble(sym
, &args
);
1016 static void insert_source_line(struct rb_root
*root
, struct annotation_line
*al
)
1018 struct annotation_line
*iter
;
1019 struct rb_node
**p
= &root
->rb_node
;
1020 struct rb_node
*parent
= NULL
;
1021 unsigned int percent_type
= annotate_opts
.percent_type
;
1024 while (*p
!= NULL
) {
1026 iter
= rb_entry(parent
, struct annotation_line
, rb_node
);
1028 ret
= strcmp(iter
->path
, al
->path
);
1030 for (i
= 0; i
< al
->data_nr
; i
++) {
1031 iter
->data
[i
].percent_sum
+= annotation_data__percent(&al
->data
[i
],
1040 p
= &(*p
)->rb_right
;
1043 for (i
= 0; i
< al
->data_nr
; i
++) {
1044 al
->data
[i
].percent_sum
= annotation_data__percent(&al
->data
[i
],
1048 rb_link_node(&al
->rb_node
, parent
, p
);
1049 rb_insert_color(&al
->rb_node
, root
);
1052 static int cmp_source_line(struct annotation_line
*a
, struct annotation_line
*b
)
1056 for (i
= 0; i
< a
->data_nr
; i
++) {
1057 if (a
->data
[i
].percent_sum
== b
->data
[i
].percent_sum
)
1059 return a
->data
[i
].percent_sum
> b
->data
[i
].percent_sum
;
1065 static void __resort_source_line(struct rb_root
*root
, struct annotation_line
*al
)
1067 struct annotation_line
*iter
;
1068 struct rb_node
**p
= &root
->rb_node
;
1069 struct rb_node
*parent
= NULL
;
1071 while (*p
!= NULL
) {
1073 iter
= rb_entry(parent
, struct annotation_line
, rb_node
);
1075 if (cmp_source_line(al
, iter
))
1078 p
= &(*p
)->rb_right
;
1081 rb_link_node(&al
->rb_node
, parent
, p
);
1082 rb_insert_color(&al
->rb_node
, root
);
1085 static void resort_source_line(struct rb_root
*dest_root
, struct rb_root
*src_root
)
1087 struct annotation_line
*al
;
1088 struct rb_node
*node
;
1090 node
= rb_first(src_root
);
1092 struct rb_node
*next
;
1094 al
= rb_entry(node
, struct annotation_line
, rb_node
);
1095 next
= rb_next(node
);
1096 rb_erase(node
, src_root
);
1098 __resort_source_line(dest_root
, al
);
1103 static void print_summary(struct rb_root
*root
, const char *filename
)
1105 struct annotation_line
*al
;
1106 struct rb_node
*node
;
1108 printf("\nSorted summary for file %s\n", filename
);
1109 printf("----------------------------------------------\n\n");
1111 if (RB_EMPTY_ROOT(root
)) {
1112 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN
);
1116 node
= rb_first(root
);
1118 double percent
, percent_max
= 0.0;
1123 al
= rb_entry(node
, struct annotation_line
, rb_node
);
1124 for (i
= 0; i
< al
->data_nr
; i
++) {
1125 percent
= al
->data
[i
].percent_sum
;
1126 color
= get_percent_color(percent
);
1127 color_fprintf(stdout
, color
, " %7.2f", percent
);
1129 if (percent
> percent_max
)
1130 percent_max
= percent
;
1134 color
= get_percent_color(percent_max
);
1135 color_fprintf(stdout
, color
, " %s\n", path
);
1137 node
= rb_next(node
);
1141 static void symbol__annotate_hits(struct symbol
*sym
, struct evsel
*evsel
)
1143 int evidx
= evsel
->core
.idx
;
1144 struct annotation
*notes
= symbol__annotation(sym
);
1145 struct sym_hist
*h
= annotation__histogram(notes
, evidx
);
1146 u64 len
= symbol__size(sym
), offset
;
1148 for (offset
= 0; offset
< len
; ++offset
) {
1149 struct sym_hist_entry
*entry
;
1151 entry
= annotated_source__hist_entry(notes
->src
, evidx
, offset
);
1152 if (entry
&& entry
->nr_samples
!= 0)
1153 printf("%*" PRIx64
": %" PRIu64
"\n", BITS_PER_LONG
/ 2,
1154 sym
->start
+ offset
, entry
->nr_samples
);
1156 printf("%*s: %" PRIu64
"\n", BITS_PER_LONG
/ 2, "h->nr_samples", h
->nr_samples
);
1159 static int annotated_source__addr_fmt_width(struct list_head
*lines
, u64 start
)
1162 struct annotation_line
*line
;
1164 list_for_each_entry_reverse(line
, lines
, node
) {
1165 if (line
->offset
!= -1)
1166 return scnprintf(bf
, sizeof(bf
), "%" PRIx64
, start
+ line
->offset
);
1172 int symbol__annotate_printf(struct map_symbol
*ms
, struct evsel
*evsel
)
1174 struct map
*map
= ms
->map
;
1175 struct symbol
*sym
= ms
->sym
;
1176 struct dso
*dso
= map__dso(map
);
1178 const char *d_filename
;
1179 const char *evsel_name
= evsel__name(evsel
);
1180 struct annotation
*notes
= symbol__annotation(sym
);
1181 struct sym_hist
*h
= annotation__histogram(notes
, evsel
->core
.idx
);
1182 struct annotation_line
*pos
, *queue
= NULL
;
1183 struct annotation_options
*opts
= &annotate_opts
;
1184 u64 start
= map__rip_2objdump(map
, sym
->start
);
1185 int printed
= 2, queue_len
= 0, addr_fmt_width
;
1187 bool context
= opts
->context
;
1189 int width
= annotation__pcnt_width(notes
);
1190 int graph_dotted_len
;
1193 filename
= strdup(dso__long_name(dso
));
1197 if (opts
->full_path
)
1198 d_filename
= filename
;
1200 d_filename
= basename(filename
);
1202 len
= symbol__size(sym
);
1204 if (evsel__is_group_event(evsel
)) {
1205 evsel__group_desc(evsel
, buf
, sizeof(buf
));
1209 graph_dotted_len
= printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64
" samples, "
1211 width
, width
, symbol_conf
.show_total_period
? "Period" :
1212 symbol_conf
.show_nr_samples
? "Samples" : "Percent",
1213 d_filename
, evsel_name
, h
->nr_samples
,
1214 percent_type_str(opts
->percent_type
));
1216 printf("%-*.*s----\n",
1217 graph_dotted_len
, graph_dotted_len
, graph_dotted_line
);
1220 symbol__annotate_hits(sym
, evsel
);
1222 addr_fmt_width
= annotated_source__addr_fmt_width(¬es
->src
->source
, start
);
1224 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
1227 if (context
&& queue
== NULL
) {
1232 err
= annotation_line__print(pos
, sym
, start
, evsel
, len
,
1233 opts
->min_pcnt
, printed
, opts
->max_lines
,
1234 queue
, addr_fmt_width
, opts
->percent_type
);
1240 printed
+= queue_len
;
1246 /* filtered by max_lines */
1252 * Filtered by min_pcnt or non IP lines when
1257 if (queue_len
== context
)
1258 queue
= list_entry(queue
->node
.next
, typeof(*queue
), node
);
1270 static void FILE__set_percent_color(void *fp __maybe_unused
,
1271 double percent __maybe_unused
,
1272 bool current __maybe_unused
)
1276 static int FILE__set_jumps_percent_color(void *fp __maybe_unused
,
1277 int nr __maybe_unused
, bool current __maybe_unused
)
1282 static int FILE__set_color(void *fp __maybe_unused
, int color __maybe_unused
)
1287 static void FILE__printf(void *fp
, const char *fmt
, ...)
1291 va_start(args
, fmt
);
1292 vfprintf(fp
, fmt
, args
);
1296 static void FILE__write_graph(void *fp
, int graph
)
1301 case DARROW_CHAR
: s
= "↓"; break;
1302 case UARROW_CHAR
: s
= "↑"; break;
1303 case LARROW_CHAR
: s
= "←"; break;
1304 case RARROW_CHAR
: s
= "→"; break;
1305 default: s
= "?"; break;
1311 static int symbol__annotate_fprintf2(struct symbol
*sym
, FILE *fp
)
1313 struct annotation
*notes
= symbol__annotation(sym
);
1314 struct annotation_write_ops wops
= {
1317 .set_color
= FILE__set_color
,
1318 .set_percent_color
= FILE__set_percent_color
,
1319 .set_jumps_percent_color
= FILE__set_jumps_percent_color
,
1320 .printf
= FILE__printf
,
1321 .write_graph
= FILE__write_graph
,
1323 struct annotation_line
*al
;
1325 list_for_each_entry(al
, ¬es
->src
->source
, node
) {
1326 if (annotation_line__filter(al
))
1328 annotation_line__write(al
, notes
, &wops
);
1330 wops
.first_line
= false;
1336 int map_symbol__annotation_dump(struct map_symbol
*ms
, struct evsel
*evsel
)
1338 const char *ev_name
= evsel__name(evsel
);
1344 if (asprintf(&filename
, "%s.annotation", ms
->sym
->name
) < 0)
1347 fp
= fopen(filename
, "w");
1349 goto out_free_filename
;
1351 if (evsel__is_group_event(evsel
)) {
1352 evsel__group_desc(evsel
, buf
, sizeof(buf
));
1356 fprintf(fp
, "%s() %s\nEvent: %s\n\n",
1357 ms
->sym
->name
, dso__long_name(map__dso(ms
->map
)), ev_name
);
1358 symbol__annotate_fprintf2(ms
->sym
, fp
);
1367 void symbol__annotate_zero_histogram(struct symbol
*sym
, int evidx
)
1369 struct annotation
*notes
= symbol__annotation(sym
);
1370 struct sym_hist
*h
= annotation__histogram(notes
, evidx
);
1372 memset(h
, 0, sizeof(*notes
->src
->histograms
) * notes
->src
->nr_histograms
);
1375 void symbol__annotate_decay_histogram(struct symbol
*sym
, int evidx
)
1377 struct annotation
*notes
= symbol__annotation(sym
);
1378 struct sym_hist
*h
= annotation__histogram(notes
, evidx
);
1379 struct annotation_line
*al
;
1382 list_for_each_entry(al
, ¬es
->src
->source
, node
) {
1383 struct sym_hist_entry
*entry
;
1385 if (al
->offset
== -1)
1388 entry
= annotated_source__hist_entry(notes
->src
, evidx
, al
->offset
);
1392 entry
->nr_samples
= entry
->nr_samples
* 7 / 8;
1393 h
->nr_samples
+= entry
->nr_samples
;
1397 void annotated_source__purge(struct annotated_source
*as
)
1399 struct annotation_line
*al
, *n
;
1401 list_for_each_entry_safe(al
, n
, &as
->source
, node
) {
1402 list_del_init(&al
->node
);
1403 disasm_line__free(disasm_line(al
));
1407 static size_t disasm_line__fprintf(struct disasm_line
*dl
, FILE *fp
)
1411 if (dl
->al
.offset
== -1)
1412 return fprintf(fp
, "%s\n", dl
->al
.line
);
1414 printed
= fprintf(fp
, "%#" PRIx64
" %s", dl
->al
.offset
, dl
->ins
.name
);
1416 if (dl
->ops
.raw
[0] != '\0') {
1417 printed
+= fprintf(fp
, "%.*s %s\n", 6 - (int)printed
, " ",
1421 return printed
+ fprintf(fp
, "\n");
1424 size_t disasm__fprintf(struct list_head
*head
, FILE *fp
)
1426 struct disasm_line
*pos
;
1429 list_for_each_entry(pos
, head
, al
.node
)
1430 printed
+= disasm_line__fprintf(pos
, fp
);
1435 bool disasm_line__is_valid_local_jump(struct disasm_line
*dl
, struct symbol
*sym
)
1437 if (!dl
|| !dl
->ins
.ops
|| !ins__is_jump(&dl
->ins
) ||
1438 !disasm_line__has_local_offset(dl
) || dl
->ops
.target
.offset
< 0 ||
1439 dl
->ops
.target
.offset
>= (s64
)symbol__size(sym
))
1446 annotation__mark_jump_targets(struct annotation
*notes
, struct symbol
*sym
)
1448 struct annotation_line
*al
;
1450 /* PLT symbols contain external offsets */
1451 if (strstr(sym
->name
, "@plt"))
1454 list_for_each_entry(al
, ¬es
->src
->source
, node
) {
1455 struct disasm_line
*dl
;
1456 struct annotation_line
*target
;
1458 dl
= disasm_line(al
);
1460 if (!disasm_line__is_valid_local_jump(dl
, sym
))
1463 target
= annotated_source__get_line(notes
->src
,
1464 dl
->ops
.target
.offset
);
1466 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
1467 * have to adjust to the previous offset?
1472 if (++target
->jump_sources
> notes
->src
->max_jump_sources
)
1473 notes
->src
->max_jump_sources
= target
->jump_sources
;
1477 static void annotation__set_index(struct annotation
*notes
)
1479 struct annotation_line
*al
;
1480 struct annotated_source
*src
= notes
->src
;
1482 src
->widths
.max_line_len
= 0;
1483 src
->nr_entries
= 0;
1484 src
->nr_asm_entries
= 0;
1486 list_for_each_entry(al
, &src
->source
, node
) {
1487 size_t line_len
= strlen(al
->line
);
1489 if (src
->widths
.max_line_len
< line_len
)
1490 src
->widths
.max_line_len
= line_len
;
1491 al
->idx
= src
->nr_entries
++;
1492 if (al
->offset
!= -1)
1493 al
->idx_asm
= src
->nr_asm_entries
++;
1499 static inline int width_jumps(int n
)
1508 static int annotation__max_ins_name(struct annotation
*notes
)
1510 int max_name
= 0, len
;
1511 struct annotation_line
*al
;
1513 list_for_each_entry(al
, ¬es
->src
->source
, node
) {
1514 if (al
->offset
== -1)
1517 len
= strlen(disasm_line(al
)->ins
.name
);
1526 annotation__init_column_widths(struct annotation
*notes
, struct symbol
*sym
)
1528 notes
->src
->widths
.addr
= notes
->src
->widths
.target
=
1529 notes
->src
->widths
.min_addr
= hex_width(symbol__size(sym
));
1530 notes
->src
->widths
.max_addr
= hex_width(sym
->end
);
1531 notes
->src
->widths
.jumps
= width_jumps(notes
->src
->max_jump_sources
);
1532 notes
->src
->widths
.max_ins_name
= annotation__max_ins_name(notes
);
1535 void annotation__update_column_widths(struct annotation
*notes
)
1537 if (annotate_opts
.use_offset
)
1538 notes
->src
->widths
.target
= notes
->src
->widths
.min_addr
;
1539 else if (annotate_opts
.full_addr
)
1540 notes
->src
->widths
.target
= BITS_PER_LONG
/ 4;
1542 notes
->src
->widths
.target
= notes
->src
->widths
.max_addr
;
1544 notes
->src
->widths
.addr
= notes
->src
->widths
.target
;
1546 if (annotate_opts
.show_nr_jumps
)
1547 notes
->src
->widths
.addr
+= notes
->src
->widths
.jumps
+ 1;
1550 void annotation__toggle_full_addr(struct annotation
*notes
, struct map_symbol
*ms
)
1552 annotate_opts
.full_addr
= !annotate_opts
.full_addr
;
1554 if (annotate_opts
.full_addr
)
1555 notes
->src
->start
= map__objdump_2mem(ms
->map
, ms
->sym
->start
);
1557 notes
->src
->start
= map__rip_2objdump(ms
->map
, ms
->sym
->start
);
1559 annotation__update_column_widths(notes
);
1562 static void annotation__calc_lines(struct annotation
*notes
, struct map_symbol
*ms
,
1563 struct rb_root
*root
)
1565 struct annotation_line
*al
;
1566 struct rb_root tmp_root
= RB_ROOT
;
1568 list_for_each_entry(al
, ¬es
->src
->source
, node
) {
1569 double percent_max
= 0.0;
1573 for (i
= 0; i
< al
->data_nr
; i
++) {
1576 percent
= annotation_data__percent(&al
->data
[i
],
1577 annotate_opts
.percent_type
);
1579 if (percent
> percent_max
)
1580 percent_max
= percent
;
1583 if (percent_max
<= 0.5)
1586 addr
= map__rip_2objdump(ms
->map
, ms
->sym
->start
);
1587 al
->path
= get_srcline(map__dso(ms
->map
), addr
+ al
->offset
, NULL
,
1588 false, true, ms
->sym
->start
+ al
->offset
);
1589 insert_source_line(&tmp_root
, al
);
1592 resort_source_line(root
, &tmp_root
);
1595 static void symbol__calc_lines(struct map_symbol
*ms
, struct rb_root
*root
)
1597 struct annotation
*notes
= symbol__annotation(ms
->sym
);
1599 annotation__calc_lines(notes
, ms
, root
);
1602 int symbol__tty_annotate2(struct map_symbol
*ms
, struct evsel
*evsel
)
1604 struct dso
*dso
= map__dso(ms
->map
);
1605 struct symbol
*sym
= ms
->sym
;
1606 struct rb_root source_line
= RB_ROOT
;
1607 struct hists
*hists
= evsel__hists(evsel
);
1611 err
= symbol__annotate2(ms
, evsel
, NULL
);
1615 dso__set_annotate_warned(dso
);
1616 symbol__strerror_disassemble(ms
, err
, msg
, sizeof(msg
));
1617 ui__error("Couldn't annotate %s:\n%s", sym
->name
, msg
);
1621 if (annotate_opts
.print_lines
) {
1622 srcline_full_filename
= annotate_opts
.full_path
;
1623 symbol__calc_lines(ms
, &source_line
);
1624 print_summary(&source_line
, dso__long_name(dso
));
1627 hists__scnprintf_title(hists
, buf
, sizeof(buf
));
1628 fprintf(stdout
, "%s, [percent: %s]\n%s() %s\n",
1629 buf
, percent_type_str(annotate_opts
.percent_type
), sym
->name
, dso__long_name(dso
));
1630 symbol__annotate_fprintf2(sym
, stdout
);
1632 annotated_source__purge(symbol__annotation(sym
)->src
);
1637 int symbol__tty_annotate(struct map_symbol
*ms
, struct evsel
*evsel
)
1639 struct dso
*dso
= map__dso(ms
->map
);
1640 struct symbol
*sym
= ms
->sym
;
1641 struct rb_root source_line
= RB_ROOT
;
1644 err
= symbol__annotate(ms
, evsel
, NULL
);
1648 dso__set_annotate_warned(dso
);
1649 symbol__strerror_disassemble(ms
, err
, msg
, sizeof(msg
));
1650 ui__error("Couldn't annotate %s:\n%s", sym
->name
, msg
);
1654 symbol__calc_percent(sym
, evsel
);
1656 if (annotate_opts
.print_lines
) {
1657 srcline_full_filename
= annotate_opts
.full_path
;
1658 symbol__calc_lines(ms
, &source_line
);
1659 print_summary(&source_line
, dso__long_name(dso
));
1662 symbol__annotate_printf(ms
, evsel
);
1664 annotated_source__purge(symbol__annotation(sym
)->src
);
1669 bool ui__has_annotation(void)
1671 return use_browser
== 1 && perf_hpp_list
.sym
;
1675 static double annotation_line__max_percent(struct annotation_line
*al
,
1676 unsigned int percent_type
)
1678 double percent_max
= 0.0;
1681 for (i
= 0; i
< al
->data_nr
; i
++) {
1684 percent
= annotation_data__percent(&al
->data
[i
],
1687 if (percent
> percent_max
)
1688 percent_max
= percent
;
1694 static void disasm_line__write(struct disasm_line
*dl
, struct annotation
*notes
,
1695 void *obj
, char *bf
, size_t size
,
1696 void (*obj__printf
)(void *obj
, const char *fmt
, ...),
1697 void (*obj__write_graph
)(void *obj
, int graph
))
1699 if (dl
->ins
.ops
&& dl
->ins
.ops
->scnprintf
) {
1700 if (ins__is_jump(&dl
->ins
)) {
1703 if (dl
->ops
.target
.outside
)
1705 fwd
= dl
->ops
.target
.offset
> dl
->al
.offset
;
1706 obj__write_graph(obj
, fwd
? DARROW_CHAR
: UARROW_CHAR
);
1707 obj__printf(obj
, " ");
1708 } else if (ins__is_call(&dl
->ins
)) {
1710 obj__write_graph(obj
, RARROW_CHAR
);
1711 obj__printf(obj
, " ");
1712 } else if (ins__is_ret(&dl
->ins
)) {
1713 obj__write_graph(obj
, LARROW_CHAR
);
1714 obj__printf(obj
, " ");
1716 obj__printf(obj
, " ");
1719 obj__printf(obj
, " ");
1722 disasm_line__scnprintf(dl
, bf
, size
, !annotate_opts
.use_offset
,
1723 notes
->src
->widths
.max_ins_name
);
1726 static void ipc_coverage_string(char *bf
, int size
, struct annotation
*notes
)
1728 double ipc
= 0.0, coverage
= 0.0;
1729 struct annotated_branch
*branch
= annotation__get_branch(notes
);
1731 if (branch
&& branch
->hit_cycles
)
1732 ipc
= branch
->hit_insn
/ ((double)branch
->hit_cycles
);
1734 if (branch
&& branch
->total_insn
) {
1735 coverage
= branch
->cover_insn
* 100.0 /
1736 ((double)branch
->total_insn
);
1739 scnprintf(bf
, size
, "(Average IPC: %.2f, IPC Coverage: %.1f%%)",
1743 int annotation_br_cntr_abbr_list(char **str
, struct evsel
*evsel
, bool header
)
1748 if (evsel
->evlist
->nr_br_cntr
<= 0)
1751 strbuf_init(&sb
, /*hint=*/ 0);
1753 if (header
&& strbuf_addf(&sb
, "# Branch counter abbr list:\n"))
1756 evlist__for_each_entry(evsel
->evlist
, pos
) {
1757 if (!(pos
->core
.attr
.branch_sample_type
& PERF_SAMPLE_BRANCH_COUNTERS
))
1759 if (header
&& strbuf_addf(&sb
, "#"))
1762 if (strbuf_addf(&sb
, " %s = %s\n", pos
->name
, pos
->abbr_name
))
1766 if (header
&& strbuf_addf(&sb
, "#"))
1768 if (strbuf_addf(&sb
, " '-' No event occurs\n"))
1771 if (header
&& strbuf_addf(&sb
, "#"))
1773 if (strbuf_addf(&sb
, " '+' Event occurrences may be lost due to branch counter saturated\n"))
1776 *str
= strbuf_detach(&sb
, NULL
);
1780 strbuf_release(&sb
);
1784 /* Assume the branch counter saturated at 3 */
1785 #define ANNOTATION_BR_CNTR_SATURATION 3
1787 int annotation_br_cntr_entry(char **str
, int br_cntr_nr
,
1788 u64
*br_cntr
, int num_aggr
,
1789 struct evsel
*evsel
)
1791 struct evsel
*pos
= evsel
? evlist__first(evsel
->evlist
) : NULL
;
1792 bool saturated
= false;
1793 int i
, j
, avg
, used
;
1796 strbuf_init(&sb
, /*hint=*/ 0);
1797 for (i
= 0; i
< br_cntr_nr
; i
++) {
1799 avg
= ceil((double)(br_cntr
[i
] & ~ANNOTATION__BR_CNTR_SATURATED_FLAG
) /
1803 * A histogram with the abbr name is displayed by default.
1804 * With -v, the exact number of branch counter is displayed.
1807 evlist__for_each_entry_from(evsel
->evlist
, pos
) {
1808 if ((pos
->core
.attr
.branch_sample_type
& PERF_SAMPLE_BRANCH_COUNTERS
) &&
1809 (pos
->br_cntr_idx
== i
))
1812 if (strbuf_addstr(&sb
, pos
->abbr_name
))
1816 if (strbuf_addstr(&sb
, "=-"))
1819 if (strbuf_addf(&sb
, "=%d", avg
))
1822 if (br_cntr
[i
] & ANNOTATION__BR_CNTR_SATURATED_FLAG
) {
1823 if (strbuf_addch(&sb
, '+'))
1826 if (strbuf_addch(&sb
, ' '))
1830 if ((i
< br_cntr_nr
- 1) && strbuf_addch(&sb
, ','))
1835 if (strbuf_addch(&sb
, '|'))
1839 if (strbuf_addch(&sb
, '-'))
1843 evlist__for_each_entry_from(evsel
->evlist
, pos
) {
1844 if ((pos
->core
.attr
.branch_sample_type
& PERF_SAMPLE_BRANCH_COUNTERS
) &&
1845 (pos
->br_cntr_idx
== i
))
1848 if (br_cntr
[i
] & ANNOTATION__BR_CNTR_SATURATED_FLAG
)
1851 for (j
= 0; j
< avg
; j
++, used
++) {
1852 /* Print + if the number of logged events > 3 */
1853 if (j
>= ANNOTATION_BR_CNTR_SATURATION
) {
1857 if (strbuf_addstr(&sb
, pos
->abbr_name
))
1862 if (strbuf_addch(&sb
, '+'))
1866 pos
= list_next_entry(pos
, core
.node
);
1869 for (j
= used
; j
< ANNOTATION_BR_CNTR_SATURATION
+ 1; j
++) {
1870 if (strbuf_addch(&sb
, ' '))
1875 if (!verbose
&& strbuf_addch(&sb
, br_cntr_nr
? '|' : ' '))
1878 *str
= strbuf_detach(&sb
, NULL
);
1882 strbuf_release(&sb
);
1886 static void __annotation_line__write(struct annotation_line
*al
, struct annotation
*notes
,
1887 bool first_line
, bool current_entry
, bool change_color
, int width
,
1888 void *obj
, unsigned int percent_type
,
1889 int (*obj__set_color
)(void *obj
, int color
),
1890 void (*obj__set_percent_color
)(void *obj
, double percent
, bool current
),
1891 int (*obj__set_jumps_percent_color
)(void *obj
, int nr
, bool current
),
1892 void (*obj__printf
)(void *obj
, const char *fmt
, ...),
1893 void (*obj__write_graph
)(void *obj
, int graph
))
1896 double percent_max
= annotation_line__max_percent(al
, percent_type
);
1897 int pcnt_width
= annotation__pcnt_width(notes
),
1898 cycles_width
= annotation__cycles_width(notes
);
1899 bool show_title
= false;
1903 if (first_line
&& (al
->offset
== -1 || percent_max
== 0.0)) {
1904 if (notes
->branch
&& al
->cycles
) {
1905 if (al
->cycles
->ipc
== 0.0 && al
->cycles
->avg
== 0)
1911 if (al
->offset
!= -1 && percent_max
!= 0.0) {
1914 for (i
= 0; i
< al
->data_nr
; i
++) {
1917 percent
= annotation_data__percent(&al
->data
[i
], percent_type
);
1919 obj__set_percent_color(obj
, percent
, current_entry
);
1920 if (symbol_conf
.show_total_period
) {
1921 obj__printf(obj
, "%11" PRIu64
" ", al
->data
[i
].he
.period
);
1922 } else if (symbol_conf
.show_nr_samples
) {
1923 obj__printf(obj
, "%7" PRIu64
" ",
1924 al
->data
[i
].he
.nr_samples
);
1926 obj__printf(obj
, "%7.2f ", percent
);
1930 obj__set_percent_color(obj
, 0, current_entry
);
1933 obj__printf(obj
, "%-*s", pcnt_width
, " ");
1935 obj__printf(obj
, "%-*s", pcnt_width
,
1936 symbol_conf
.show_total_period
? "Period" :
1937 symbol_conf
.show_nr_samples
? "Samples" : "Percent");
1941 if (notes
->branch
) {
1942 if (al
->cycles
&& al
->cycles
->ipc
)
1943 obj__printf(obj
, "%*.2f ", ANNOTATION__IPC_WIDTH
- 1, al
->cycles
->ipc
);
1944 else if (!show_title
)
1945 obj__printf(obj
, "%*s", ANNOTATION__IPC_WIDTH
, " ");
1947 obj__printf(obj
, "%*s ", ANNOTATION__IPC_WIDTH
- 1, "IPC");
1949 if (!annotate_opts
.show_minmax_cycle
) {
1950 if (al
->cycles
&& al
->cycles
->avg
)
1951 obj__printf(obj
, "%*" PRIu64
" ",
1952 ANNOTATION__CYCLES_WIDTH
- 1, al
->cycles
->avg
);
1953 else if (!show_title
)
1954 obj__printf(obj
, "%*s",
1955 ANNOTATION__CYCLES_WIDTH
, " ");
1957 obj__printf(obj
, "%*s ",
1958 ANNOTATION__CYCLES_WIDTH
- 1,
1964 scnprintf(str
, sizeof(str
),
1965 "%" PRIu64
"(%" PRIu64
"/%" PRIu64
")",
1966 al
->cycles
->avg
, al
->cycles
->min
,
1969 obj__printf(obj
, "%*s ",
1970 ANNOTATION__MINMAX_CYCLES_WIDTH
- 1,
1972 } else if (!show_title
)
1973 obj__printf(obj
, "%*s",
1974 ANNOTATION__MINMAX_CYCLES_WIDTH
,
1977 obj__printf(obj
, "%*s ",
1978 ANNOTATION__MINMAX_CYCLES_WIDTH
- 1,
1982 if (annotate_opts
.show_br_cntr
) {
1984 obj__printf(obj
, "%*s ",
1985 ANNOTATION__BR_CNTR_WIDTH
,
1990 if (!annotation_br_cntr_entry(&buf
, al
->br_cntr_nr
, al
->br_cntr
,
1991 al
->num_aggr
, al
->evsel
)) {
1992 obj__printf(obj
, "%*s ", ANNOTATION__BR_CNTR_WIDTH
, buf
);
1998 if (show_title
&& !*al
->line
) {
1999 ipc_coverage_string(bf
, sizeof(bf
), notes
);
2000 obj__printf(obj
, "%*s", ANNOTATION__AVG_IPC_WIDTH
, bf
);
2004 obj__printf(obj
, " ");
2007 obj__printf(obj
, "%-*s", width
- pcnt_width
- cycles_width
, " ");
2008 else if (al
->offset
== -1) {
2009 if (al
->line_nr
&& annotate_opts
.show_linenr
)
2010 printed
= scnprintf(bf
, sizeof(bf
), "%-*d ",
2011 notes
->src
->widths
.addr
+ 1, al
->line_nr
);
2013 printed
= scnprintf(bf
, sizeof(bf
), "%-*s ",
2014 notes
->src
->widths
.addr
, " ");
2015 obj__printf(obj
, bf
);
2016 obj__printf(obj
, "%-*s", width
- printed
- pcnt_width
- cycles_width
+ 1, al
->line
);
2018 u64 addr
= al
->offset
;
2021 if (!annotate_opts
.use_offset
)
2022 addr
+= notes
->src
->start
;
2024 if (!annotate_opts
.use_offset
) {
2025 printed
= scnprintf(bf
, sizeof(bf
), "%" PRIx64
": ", addr
);
2027 if (al
->jump_sources
&&
2028 annotate_opts
.offset_level
>= ANNOTATION__OFFSET_JUMP_TARGETS
) {
2029 if (annotate_opts
.show_nr_jumps
) {
2031 printed
= scnprintf(bf
, sizeof(bf
), "%*d ",
2032 notes
->src
->widths
.jumps
,
2034 prev
= obj__set_jumps_percent_color(obj
, al
->jump_sources
,
2036 obj__printf(obj
, bf
);
2037 obj__set_color(obj
, prev
);
2040 printed
= scnprintf(bf
, sizeof(bf
), "%*" PRIx64
": ",
2041 notes
->src
->widths
.target
, addr
);
2042 } else if (ins__is_call(&disasm_line(al
)->ins
) &&
2043 annotate_opts
.offset_level
>= ANNOTATION__OFFSET_CALL
) {
2045 } else if (annotate_opts
.offset_level
== ANNOTATION__MAX_OFFSET_LEVEL
) {
2048 printed
= scnprintf(bf
, sizeof(bf
), "%-*s ",
2049 notes
->src
->widths
.addr
, " ");
2054 color
= obj__set_color(obj
, HE_COLORSET_ADDR
);
2055 obj__printf(obj
, bf
);
2057 obj__set_color(obj
, color
);
2059 disasm_line__write(disasm_line(al
), notes
, obj
, bf
, sizeof(bf
), obj__printf
, obj__write_graph
);
2061 obj__printf(obj
, "%-*s", width
- pcnt_width
- cycles_width
- 3 - printed
, bf
);
2066 void annotation_line__write(struct annotation_line
*al
, struct annotation
*notes
,
2067 struct annotation_write_ops
*wops
)
2069 __annotation_line__write(al
, notes
, wops
->first_line
, wops
->current_entry
,
2070 wops
->change_color
, wops
->width
, wops
->obj
,
2071 annotate_opts
.percent_type
,
2072 wops
->set_color
, wops
->set_percent_color
,
2073 wops
->set_jumps_percent_color
, wops
->printf
,
2077 int symbol__annotate2(struct map_symbol
*ms
, struct evsel
*evsel
,
2078 struct arch
**parch
)
2080 struct symbol
*sym
= ms
->sym
;
2081 struct annotation
*notes
= symbol__annotation(sym
);
2082 size_t size
= symbol__size(sym
);
2085 err
= symbol__annotate(ms
, evsel
, parch
);
2089 symbol__calc_percent(sym
, evsel
);
2091 annotation__set_index(notes
);
2092 annotation__mark_jump_targets(notes
, sym
);
2094 err
= annotation__compute_ipc(notes
, size
, evsel
);
2098 annotation__init_column_widths(notes
, sym
);
2099 annotation__update_column_widths(notes
);
2105 static int annotation__config(const char *var
, const char *value
, void *data
)
2107 struct annotation_options
*opt
= data
;
2109 if (!strstarts(var
, "annotate."))
2112 if (!strcmp(var
, "annotate.offset_level")) {
2113 perf_config_u8(&opt
->offset_level
, "offset_level", value
);
2115 if (opt
->offset_level
> ANNOTATION__MAX_OFFSET_LEVEL
)
2116 opt
->offset_level
= ANNOTATION__MAX_OFFSET_LEVEL
;
2117 else if (opt
->offset_level
< ANNOTATION__MIN_OFFSET_LEVEL
)
2118 opt
->offset_level
= ANNOTATION__MIN_OFFSET_LEVEL
;
2119 } else if (!strcmp(var
, "annotate.disassemblers")) {
2120 opt
->disassemblers_str
= strdup(value
);
2121 if (!opt
->disassemblers_str
) {
2122 pr_err("Not enough memory for annotate.disassemblers\n");
2125 } else if (!strcmp(var
, "annotate.hide_src_code")) {
2126 opt
->hide_src_code
= perf_config_bool("hide_src_code", value
);
2127 } else if (!strcmp(var
, "annotate.jump_arrows")) {
2128 opt
->jump_arrows
= perf_config_bool("jump_arrows", value
);
2129 } else if (!strcmp(var
, "annotate.show_linenr")) {
2130 opt
->show_linenr
= perf_config_bool("show_linenr", value
);
2131 } else if (!strcmp(var
, "annotate.show_nr_jumps")) {
2132 opt
->show_nr_jumps
= perf_config_bool("show_nr_jumps", value
);
2133 } else if (!strcmp(var
, "annotate.show_nr_samples")) {
2134 symbol_conf
.show_nr_samples
= perf_config_bool("show_nr_samples",
2136 } else if (!strcmp(var
, "annotate.show_total_period")) {
2137 symbol_conf
.show_total_period
= perf_config_bool("show_total_period",
2139 } else if (!strcmp(var
, "annotate.use_offset")) {
2140 opt
->use_offset
= perf_config_bool("use_offset", value
);
2141 } else if (!strcmp(var
, "annotate.disassembler_style")) {
2142 opt
->disassembler_style
= strdup(value
);
2143 if (!opt
->disassembler_style
) {
2144 pr_err("Not enough memory for annotate.disassembler_style\n");
2147 } else if (!strcmp(var
, "annotate.objdump")) {
2148 opt
->objdump_path
= strdup(value
);
2149 if (!opt
->objdump_path
) {
2150 pr_err("Not enough memory for annotate.objdump\n");
2153 } else if (!strcmp(var
, "annotate.addr2line")) {
2154 symbol_conf
.addr2line_path
= strdup(value
);
2155 if (!symbol_conf
.addr2line_path
) {
2156 pr_err("Not enough memory for annotate.addr2line\n");
2159 } else if (!strcmp(var
, "annotate.demangle")) {
2160 symbol_conf
.demangle
= perf_config_bool("demangle", value
);
2161 } else if (!strcmp(var
, "annotate.demangle_kernel")) {
2162 symbol_conf
.demangle_kernel
= perf_config_bool("demangle_kernel", value
);
2164 pr_debug("%s variable unknown, ignoring...", var
);
2170 void annotation_options__init(void)
2172 struct annotation_options
*opt
= &annotate_opts
;
2174 memset(opt
, 0, sizeof(*opt
));
2176 /* Default values. */
2177 opt
->use_offset
= true;
2178 opt
->jump_arrows
= true;
2179 opt
->annotate_src
= true;
2180 opt
->offset_level
= ANNOTATION__OFFSET_JUMP_TARGETS
;
2181 opt
->percent_type
= PERCENT_PERIOD_LOCAL
;
2184 void annotation_options__exit(void)
2186 zfree(&annotate_opts
.disassembler_style
);
2187 zfree(&annotate_opts
.objdump_path
);
2190 void annotation_config__init(void)
2192 perf_config(annotation__config
, &annotate_opts
);
2195 static unsigned int parse_percent_type(char *str1
, char *str2
)
2197 unsigned int type
= (unsigned int) -1;
2199 if (!strcmp("period", str1
)) {
2200 if (!strcmp("local", str2
))
2201 type
= PERCENT_PERIOD_LOCAL
;
2202 else if (!strcmp("global", str2
))
2203 type
= PERCENT_PERIOD_GLOBAL
;
2206 if (!strcmp("hits", str1
)) {
2207 if (!strcmp("local", str2
))
2208 type
= PERCENT_HITS_LOCAL
;
2209 else if (!strcmp("global", str2
))
2210 type
= PERCENT_HITS_GLOBAL
;
2216 int annotate_parse_percent_type(const struct option
*opt __maybe_unused
, const char *_str
,
2217 int unset __maybe_unused
)
2223 str1
= strdup(_str
);
2227 str2
= strchr(str1
, '-');
2233 type
= parse_percent_type(str1
, str2
);
2234 if (type
== (unsigned int) -1)
2235 type
= parse_percent_type(str2
, str1
);
2236 if (type
!= (unsigned int) -1) {
2237 annotate_opts
.percent_type
= type
;
2246 int annotate_check_args(void)
2248 struct annotation_options
*args
= &annotate_opts
;
2250 if (args
->prefix_strip
&& !args
->prefix
) {
2251 pr_err("--prefix-strip requires --prefix\n");
2258 * Get register number and access offset from the given instruction.
2259 * It assumes AT&T x86 asm format like OFFSET(REG). Maybe it needs
2260 * to revisit the format when it handles different architecture.
2261 * Fills @reg and @offset when return 0.
2263 static int extract_reg_offset(struct arch
*arch
, const char *str
,
2264 struct annotated_op_loc
*op_loc
)
2269 if (arch
->objdump
.register_char
== 0)
2273 * It should start from offset, but it's possible to skip 0
2274 * in the asm. So 0(%rax) should be same as (%rax).
2276 * However, it also start with a segment select register like
2277 * %gs:0x18(%rbx). In that case it should skip the part.
2279 if (*str
== arch
->objdump
.register_char
) {
2280 if (arch__is(arch
, "x86")) {
2281 /* FIXME: Handle other segment registers */
2282 if (!strncmp(str
, "%gs:", 4))
2283 op_loc
->segment
= INSN_SEG_X86_GS
;
2286 while (*str
&& !isdigit(*str
) &&
2287 *str
!= arch
->objdump
.memory_ref_char
)
2291 op_loc
->offset
= strtol(str
, &p
, 0);
2293 p
= strchr(p
, arch
->objdump
.register_char
);
2297 regname
= strdup(p
);
2298 if (regname
== NULL
)
2301 op_loc
->reg1
= get_dwarf_regnum(regname
, arch
->e_machine
, arch
->e_flags
);
2304 /* Get the second register */
2305 if (op_loc
->multi_regs
) {
2306 p
= strchr(p
+ 1, arch
->objdump
.register_char
);
2310 regname
= strdup(p
);
2311 if (regname
== NULL
)
2314 op_loc
->reg2
= get_dwarf_regnum(regname
, arch
->e_machine
, arch
->e_flags
);
2321 * annotate_get_insn_location - Get location of instruction
2322 * @arch: the architecture info
2323 * @dl: the target instruction
2324 * @loc: a buffer to save the data
2326 * Get detailed location info (register and offset) in the instruction.
2327 * It needs both source and target operand and whether it accesses a
2328 * memory location. The offset field is meaningful only when the
2329 * corresponding mem flag is set. The reg2 field is meaningful only
2330 * when multi_regs flag is set.
2332 * Some examples on x86:
2334 * mov (%rax), %rcx # src_reg1 = rax, src_mem = 1, src_offset = 0
2335 * # dst_reg1 = rcx, dst_mem = 0
2337 * mov 0x18, %r8 # src_reg1 = -1, src_mem = 0
2338 * # dst_reg1 = r8, dst_mem = 0
2340 * mov %rsi, 8(%rbx,%rcx,4) # src_reg1 = rsi, src_mem = 0, src_multi_regs = 0
2341 * # dst_reg1 = rbx, dst_reg2 = rcx, dst_mem = 1
2342 * # dst_multi_regs = 1, dst_offset = 8
2344 int annotate_get_insn_location(struct arch
*arch
, struct disasm_line
*dl
,
2345 struct annotated_insn_loc
*loc
)
2347 struct ins_operands
*ops
;
2348 struct annotated_op_loc
*op_loc
;
2351 if (ins__is_lock(&dl
->ins
))
2352 ops
= dl
->ops
.locked
.ops
;
2359 memset(loc
, 0, sizeof(*loc
));
2361 for_each_insn_op_loc(loc
, i
, op_loc
) {
2362 const char *insn_str
= ops
->source
.raw
;
2363 bool multi_regs
= ops
->source
.multi_regs
;
2364 bool mem_ref
= ops
->source
.mem_ref
;
2366 if (i
== INSN_OP_TARGET
) {
2367 insn_str
= ops
->target
.raw
;
2368 multi_regs
= ops
->target
.multi_regs
;
2369 mem_ref
= ops
->target
.mem_ref
;
2372 /* Invalidate the register by default */
2376 if (insn_str
== NULL
) {
2377 if (!arch__is(arch
, "powerpc"))
2382 * For powerpc, call get_powerpc_regs function which extracts the
2383 * required fields for op_loc, ie reg1, reg2, offset from the
2386 if (arch__is(arch
, "powerpc")) {
2387 op_loc
->mem_ref
= mem_ref
;
2388 op_loc
->multi_regs
= multi_regs
;
2389 get_powerpc_regs(dl
->raw
.raw_insn
, !i
, op_loc
);
2390 } else if (strchr(insn_str
, arch
->objdump
.memory_ref_char
)) {
2391 op_loc
->mem_ref
= true;
2392 op_loc
->multi_regs
= multi_regs
;
2393 extract_reg_offset(arch
, insn_str
, op_loc
);
2397 if (arch__is(arch
, "x86")) {
2398 /* FIXME: Handle other segment registers */
2399 if (!strncmp(insn_str
, "%gs:", 4)) {
2400 op_loc
->segment
= INSN_SEG_X86_GS
;
2401 op_loc
->offset
= strtol(insn_str
+ 4,
2403 if (p
&& p
!= insn_str
+ 4)
2409 s
= strdup(insn_str
);
2413 if (*s
== arch
->objdump
.register_char
)
2414 op_loc
->reg1
= get_dwarf_regnum(s
, arch
->e_machine
, arch
->e_flags
);
2415 else if (*s
== arch
->objdump
.imm_char
) {
2416 op_loc
->offset
= strtol(s
+ 1, &p
, 0);
2417 if (p
&& p
!= s
+ 1)
2427 static struct disasm_line
*find_disasm_line(struct symbol
*sym
, u64 ip
,
2430 struct disasm_line
*dl
;
2431 struct annotation
*notes
;
2433 notes
= symbol__annotation(sym
);
2435 list_for_each_entry(dl
, ¬es
->src
->source
, al
.node
) {
2436 if (dl
->al
.offset
== -1)
2439 if (sym
->start
+ dl
->al
.offset
== ip
) {
2441 * llvm-objdump places "lock" in a separate line and
2442 * in that case, we want to get the next line.
2444 if (ins__is_lock(&dl
->ins
) &&
2445 *dl
->ops
.raw
== '\0' && allow_update
) {
2455 static struct annotated_item_stat
*annotate_data_stat(struct list_head
*head
,
2458 struct annotated_item_stat
*istat
;
2460 list_for_each_entry(istat
, head
, list
) {
2461 if (!strcmp(istat
->name
, name
))
2465 istat
= zalloc(sizeof(*istat
));
2469 istat
->name
= strdup(name
);
2470 if ((istat
->name
== NULL
) || (!strlen(istat
->name
))) {
2475 list_add_tail(&istat
->list
, head
);
2479 static bool is_stack_operation(struct arch
*arch
, struct disasm_line
*dl
)
2481 if (arch__is(arch
, "x86")) {
2482 if (!strncmp(dl
->ins
.name
, "push", 4) ||
2483 !strncmp(dl
->ins
.name
, "pop", 3) ||
2484 !strncmp(dl
->ins
.name
, "call", 4) ||
2485 !strncmp(dl
->ins
.name
, "ret", 3))
2492 static bool is_stack_canary(struct arch
*arch
, struct annotated_op_loc
*loc
)
2494 /* On x86_64, %gs:40 is used for stack canary */
2495 if (arch__is(arch
, "x86")) {
2496 if (loc
->segment
== INSN_SEG_X86_GS
&& loc
->imm
&&
2504 static struct disasm_line
*
2505 annotation__prev_asm_line(struct annotation
*notes
, struct disasm_line
*curr
)
2507 struct list_head
*sources
= ¬es
->src
->source
;
2508 struct disasm_line
*prev
;
2510 if (curr
== list_first_entry(sources
, struct disasm_line
, al
.node
))
2513 prev
= list_prev_entry(curr
, al
.node
);
2514 while (prev
->al
.offset
== -1 &&
2515 prev
!= list_first_entry(sources
, struct disasm_line
, al
.node
))
2516 prev
= list_prev_entry(prev
, al
.node
);
2518 if (prev
->al
.offset
== -1)
2524 static struct disasm_line
*
2525 annotation__next_asm_line(struct annotation
*notes
, struct disasm_line
*curr
)
2527 struct list_head
*sources
= ¬es
->src
->source
;
2528 struct disasm_line
*next
;
2530 if (curr
== list_last_entry(sources
, struct disasm_line
, al
.node
))
2533 next
= list_next_entry(curr
, al
.node
);
2534 while (next
->al
.offset
== -1 &&
2535 next
!= list_last_entry(sources
, struct disasm_line
, al
.node
))
2536 next
= list_next_entry(next
, al
.node
);
2538 if (next
->al
.offset
== -1)
2544 u64
annotate_calc_pcrel(struct map_symbol
*ms
, u64 ip
, int offset
,
2545 struct disasm_line
*dl
)
2547 struct annotation
*notes
;
2548 struct disasm_line
*next
;
2551 notes
= symbol__annotation(ms
->sym
);
2553 * PC-relative addressing starts from the next instruction address
2554 * But the IP is for the current instruction. Since disasm_line
2555 * doesn't have the instruction size, calculate it using the next
2556 * disasm_line. If it's the last one, we can use symbol's end
2559 next
= annotation__next_asm_line(notes
, dl
);
2561 addr
= ms
->sym
->end
+ offset
;
2563 addr
= ip
+ (next
->al
.offset
- dl
->al
.offset
) + offset
;
2565 return map__rip_2objdump(ms
->map
, addr
);
2568 static struct debuginfo_cache
{
2570 struct debuginfo
*dbg
;
2573 void debuginfo_cache__delete(void)
2575 dso__put(di_cache
.dso
);
2576 di_cache
.dso
= NULL
;
2578 debuginfo__delete(di_cache
.dbg
);
2579 di_cache
.dbg
= NULL
;
2583 * hist_entry__get_data_type - find data type for given hist entry
2586 * This function first annotates the instruction at @he->ip and extracts
2587 * register and offset info from it. Then it searches the DWARF debug
2588 * info to get a variable and type information using the address, register,
2591 struct annotated_data_type
*hist_entry__get_data_type(struct hist_entry
*he
)
2593 struct map_symbol
*ms
= &he
->ms
;
2594 struct evsel
*evsel
= hists_to_evsel(he
->hists
);
2596 struct disasm_line
*dl
;
2597 struct annotated_insn_loc loc
;
2598 struct annotated_op_loc
*op_loc
;
2599 struct annotated_data_type
*mem_type
;
2600 struct annotated_item_stat
*istat
;
2604 ann_data_stat
.total
++;
2606 if (ms
->map
== NULL
|| ms
->sym
== NULL
) {
2607 ann_data_stat
.no_sym
++;
2611 if (!symbol_conf
.init_annotation
) {
2612 ann_data_stat
.no_sym
++;
2617 * di_cache holds a pair of values, but code below assumes
2618 * di_cache.dso can be compared/updated and di_cache.dbg can be
2619 * read/updated independently from each other. That assumption only
2620 * holds in single threaded code.
2622 assert(perf_singlethreaded
);
2624 if (map__dso(ms
->map
) != di_cache
.dso
) {
2625 dso__put(di_cache
.dso
);
2626 di_cache
.dso
= dso__get(map__dso(ms
->map
));
2628 debuginfo__delete(di_cache
.dbg
);
2629 di_cache
.dbg
= debuginfo__new(dso__long_name(di_cache
.dso
));
2632 if (di_cache
.dbg
== NULL
) {
2633 ann_data_stat
.no_dbginfo
++;
2637 /* Make sure it has the disasm of the function */
2638 if (symbol__annotate(ms
, evsel
, &arch
) < 0) {
2639 ann_data_stat
.no_insn
++;
2644 * Get a disasm to extract the location from the insn.
2645 * This is too slow...
2647 dl
= find_disasm_line(ms
->sym
, ip
, /*allow_update=*/true);
2649 ann_data_stat
.no_insn
++;
2654 istat
= annotate_data_stat(&ann_insn_stat
, dl
->ins
.name
);
2655 if (istat
== NULL
) {
2656 ann_data_stat
.no_insn
++;
2660 if (annotate_get_insn_location(arch
, dl
, &loc
) < 0) {
2661 ann_data_stat
.no_insn_ops
++;
2666 if (is_stack_operation(arch
, dl
)) {
2668 he
->mem_type_off
= 0;
2669 return &stackop_type
;
2672 for_each_insn_op_loc(&loc
, i
, op_loc
) {
2673 struct data_loc_info dloc
= {
2675 .thread
= he
->thread
,
2677 /* Recalculate IP for LOCK prefix or insn fusion */
2678 .ip
= ms
->sym
->start
+ dl
->al
.offset
,
2679 .cpumode
= he
->cpumode
,
2684 if (!op_loc
->mem_ref
&& op_loc
->segment
== INSN_SEG_NONE
)
2687 /* Recalculate IP because of LOCK prefix or insn fusion */
2688 ip
= ms
->sym
->start
+ dl
->al
.offset
;
2690 /* PC-relative addressing */
2691 if (op_loc
->reg1
== DWARF_REG_PC
) {
2692 dloc
.var_addr
= annotate_calc_pcrel(ms
, dloc
.ip
,
2693 op_loc
->offset
, dl
);
2696 /* This CPU access in kernel - pretend PC-relative addressing */
2697 if (dso__kernel(map__dso(ms
->map
)) && arch__is(arch
, "x86") &&
2698 op_loc
->segment
== INSN_SEG_X86_GS
&& op_loc
->imm
) {
2699 dloc
.var_addr
= op_loc
->offset
;
2700 op_loc
->reg1
= DWARF_REG_PC
;
2703 mem_type
= find_data_type(&dloc
);
2705 if (mem_type
== NULL
&& is_stack_canary(arch
, op_loc
)) {
2707 he
->mem_type_off
= 0;
2708 return &canary_type
;
2716 if (symbol_conf
.annotate_data_sample
) {
2717 annotated_data_type__update_samples(mem_type
, evsel
,
2722 he
->mem_type_off
= dloc
.type_offset
;
2727 * Some instructions can be fused and the actual memory access came
2728 * from the previous instruction.
2730 if (dl
->al
.offset
> 0) {
2731 struct annotation
*notes
;
2732 struct disasm_line
*prev_dl
;
2734 notes
= symbol__annotation(ms
->sym
);
2735 prev_dl
= annotation__prev_asm_line(notes
, dl
);
2737 if (prev_dl
&& ins__is_fused(arch
, prev_dl
->ins
.name
, dl
->ins
.name
)) {
2743 ann_data_stat
.no_mem_ops
++;
2748 /* Basic block traversal (BFS) data structure */
2749 struct basic_block_data
{
2750 struct list_head queue
;
2751 struct list_head visited
;
2755 * During the traversal, it needs to know the parent block where the current
2756 * block block started from. Note that single basic block can be parent of
2757 * two child basic blocks (in case of condition jump).
2759 struct basic_block_link
{
2760 struct list_head node
;
2761 struct basic_block_link
*parent
;
2762 struct annotated_basic_block
*bb
;
2765 /* Check any of basic block in the list already has the offset */
2766 static bool basic_block_has_offset(struct list_head
*head
, s64 offset
)
2768 struct basic_block_link
*link
;
2770 list_for_each_entry(link
, head
, node
) {
2771 s64 begin_offset
= link
->bb
->begin
->al
.offset
;
2772 s64 end_offset
= link
->bb
->end
->al
.offset
;
2774 if (begin_offset
<= offset
&& offset
<= end_offset
)
2780 static bool is_new_basic_block(struct basic_block_data
*bb_data
,
2781 struct disasm_line
*dl
)
2783 s64 offset
= dl
->al
.offset
;
2785 if (basic_block_has_offset(&bb_data
->visited
, offset
))
2787 if (basic_block_has_offset(&bb_data
->queue
, offset
))
2792 /* Add a basic block starting from dl and link it to the parent */
2793 static int add_basic_block(struct basic_block_data
*bb_data
,
2794 struct basic_block_link
*parent
,
2795 struct disasm_line
*dl
)
2797 struct annotated_basic_block
*bb
;
2798 struct basic_block_link
*link
;
2803 if (!is_new_basic_block(bb_data
, dl
))
2806 bb
= zalloc(sizeof(*bb
));
2812 INIT_LIST_HEAD(&bb
->list
);
2814 link
= malloc(sizeof(*link
));
2821 link
->parent
= parent
;
2822 list_add_tail(&link
->node
, &bb_data
->queue
);
2826 /* Returns true when it finds the target in the current basic block */
2827 static bool process_basic_block(struct basic_block_data
*bb_data
,
2828 struct basic_block_link
*link
,
2829 struct symbol
*sym
, u64 target
)
2831 struct disasm_line
*dl
, *next_dl
, *last_dl
;
2832 struct annotation
*notes
= symbol__annotation(sym
);
2835 dl
= link
->bb
->begin
;
2836 /* Check if it's already visited */
2837 if (basic_block_has_offset(&bb_data
->visited
, dl
->al
.offset
))
2840 last_dl
= list_last_entry(¬es
->src
->source
,
2841 struct disasm_line
, al
.node
);
2842 if (last_dl
->al
.offset
== -1)
2843 last_dl
= annotation__prev_asm_line(notes
, last_dl
);
2845 if (last_dl
== NULL
)
2848 list_for_each_entry_from(dl
, ¬es
->src
->source
, al
.node
) {
2849 /* Skip comment or debug info line */
2850 if (dl
->al
.offset
== -1)
2852 /* Found the target instruction */
2853 if (sym
->start
+ dl
->al
.offset
== target
) {
2857 /* End of the function, finish the block */
2860 /* 'return' instruction finishes the block */
2861 if (ins__is_ret(&dl
->ins
))
2863 /* normal instructions are part of the basic block */
2864 if (!ins__is_jump(&dl
->ins
))
2866 /* jump to a different function, tail call or return */
2867 if (dl
->ops
.target
.outside
)
2869 /* jump instruction creates new basic block(s) */
2870 next_dl
= find_disasm_line(sym
, sym
->start
+ dl
->ops
.target
.offset
,
2871 /*allow_update=*/false);
2873 add_basic_block(bb_data
, link
, next_dl
);
2876 * FIXME: determine conditional jumps properly.
2877 * Conditional jumps create another basic block with the
2880 if (!strstr(dl
->ins
.name
, "jmp")) {
2881 next_dl
= annotation__next_asm_line(notes
, dl
);
2883 add_basic_block(bb_data
, link
, next_dl
);
2893 * It founds a target basic block, build a proper linked list of basic blocks
2894 * by following the link recursively.
2896 static void link_found_basic_blocks(struct basic_block_link
*link
,
2897 struct list_head
*head
)
2900 struct basic_block_link
*parent
= link
->parent
;
2902 list_move(&link
->bb
->list
, head
);
2903 list_del(&link
->node
);
2910 static void delete_basic_blocks(struct basic_block_data
*bb_data
)
2912 struct basic_block_link
*link
, *tmp
;
2914 list_for_each_entry_safe(link
, tmp
, &bb_data
->queue
, node
) {
2915 list_del(&link
->node
);
2920 list_for_each_entry_safe(link
, tmp
, &bb_data
->visited
, node
) {
2921 list_del(&link
->node
);
2928 * annotate_get_basic_blocks - Get basic blocks for given address range
2929 * @sym: symbol to annotate
2930 * @src: source address
2931 * @dst: destination address
2932 * @head: list head to save basic blocks
2934 * This function traverses disasm_lines from @src to @dst and save them in a
2935 * list of annotated_basic_block to @head. It uses BFS to find the shortest
2936 * path between two. The basic_block_link is to maintain parent links so
2937 * that it can build a list of blocks from the start.
2939 int annotate_get_basic_blocks(struct symbol
*sym
, s64 src
, s64 dst
,
2940 struct list_head
*head
)
2942 struct basic_block_data bb_data
= {
2943 .queue
= LIST_HEAD_INIT(bb_data
.queue
),
2944 .visited
= LIST_HEAD_INIT(bb_data
.visited
),
2946 struct basic_block_link
*link
;
2947 struct disasm_line
*dl
;
2950 dl
= find_disasm_line(sym
, src
, /*allow_update=*/false);
2954 if (add_basic_block(&bb_data
, /*parent=*/NULL
, dl
) < 0)
2957 /* Find shortest path from src to dst using BFS */
2958 while (!list_empty(&bb_data
.queue
)) {
2959 link
= list_first_entry(&bb_data
.queue
, struct basic_block_link
, node
);
2961 if (process_basic_block(&bb_data
, link
, sym
, dst
)) {
2962 link_found_basic_blocks(link
, head
);
2966 list_move(&link
->node
, &bb_data
.visited
);
2968 delete_basic_blocks(&bb_data
);