linux/tools/perf/util/annotate.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#ifndef __PERF_ANNOTATE_H
   3#define __PERF_ANNOTATE_H
   4
   5#include <stdbool.h>
   6#include <stdint.h>
   7#include <linux/types.h>
   8#include "symbol.h"
   9#include "hist.h"
  10#include "sort.h"
  11#include <linux/list.h>
  12#include <linux/rbtree.h>
  13#include <pthread.h>
  14
  15struct ins_ops;
  16
  17struct ins {
  18        const char     *name;
  19        struct ins_ops *ops;
  20};
  21
  22struct ins_operands {
  23        char    *raw;
  24        struct {
  25                char    *raw;
  26                char    *name;
  27                struct symbol *sym;
  28                u64     addr;
  29                s64     offset;
  30                bool    offset_avail;
  31                bool    outside;
  32        } target;
  33        union {
  34                struct {
  35                        char    *raw;
  36                        char    *name;
  37                        u64     addr;
  38                } source;
  39                struct {
  40                        struct ins          ins;
  41                        struct ins_operands *ops;
  42                } locked;
  43        };
  44};
  45
  46struct arch;
  47
  48struct ins_ops {
  49        void (*free)(struct ins_operands *ops);
  50        int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms);
  51        int (*scnprintf)(struct ins *ins, char *bf, size_t size,
  52                         struct ins_operands *ops);
  53};
  54
  55bool ins__is_jump(const struct ins *ins);
  56bool ins__is_call(const struct ins *ins);
  57bool ins__is_ret(const struct ins *ins);
  58bool ins__is_lock(const struct ins *ins);
  59int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops);
  60bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2);
  61
  62#define ANNOTATION__IPC_WIDTH 6
  63#define ANNOTATION__CYCLES_WIDTH 6
  64
  65struct annotation_options {
  66        bool hide_src_code,
  67             use_offset,
  68             jump_arrows,
  69             show_linenr,
  70             show_nr_jumps,
  71             show_nr_samples,
  72             show_total_period;
  73        u8   offset_level;
  74};
  75
  76enum {
  77        ANNOTATION__OFFSET_JUMP_TARGETS = 1,
  78        ANNOTATION__OFFSET_CALL,
  79        ANNOTATION__MAX_OFFSET_LEVEL,
  80};
  81
  82#define ANNOTATION__MIN_OFFSET_LEVEL ANNOTATION__OFFSET_JUMP_TARGETS
  83
  84extern struct annotation_options annotation__default_options;
  85
  86struct annotation;
  87
  88struct sym_hist_entry {
  89        u64             nr_samples;
  90        u64             period;
  91};
  92
  93struct annotation_data {
  94        double                   percent;
  95        double                   percent_sum;
  96        struct sym_hist_entry    he;
  97};
  98
  99struct annotation_line {
 100        struct list_head         node;
 101        struct rb_node           rb_node;
 102        s64                      offset;
 103        char                    *line;
 104        int                      line_nr;
 105        int                      jump_sources;
 106        float                    ipc;
 107        u64                      cycles;
 108        size_t                   privsize;
 109        char                    *path;
 110        u32                      idx;
 111        int                      idx_asm;
 112        int                      samples_nr;
 113        struct annotation_data   samples[0];
 114};
 115
 116struct disasm_line {
 117        struct ins               ins;
 118        struct ins_operands      ops;
 119
 120        /* This needs to be at the end. */
 121        struct annotation_line   al;
 122};
 123
 124static inline struct disasm_line *disasm_line(struct annotation_line *al)
 125{
 126        return al ? container_of(al, struct disasm_line, al) : NULL;
 127}
 128
 129/*
 130 * Is this offset in the same function as the line it is used?
 131 * asm functions jump to other functions, for instance.
 132 */
 133static inline bool disasm_line__has_local_offset(const struct disasm_line *dl)
 134{
 135        return dl->ops.target.offset_avail && !dl->ops.target.outside;
 136}
 137
 138/*
 139 * Can we draw an arrow from the jump to its target, for instance? I.e.
 140 * is the jump and its target in the same function?
 141 */
 142bool disasm_line__is_valid_local_jump(struct disasm_line *dl, struct symbol *sym);
 143
 144void disasm_line__free(struct disasm_line *dl);
 145struct annotation_line *
 146annotation_line__next(struct annotation_line *pos, struct list_head *head);
 147
 148struct annotation_write_ops {
 149        bool first_line, current_entry, change_color;
 150        int  width;
 151        void *obj;
 152        int  (*set_color)(void *obj, int color);
 153        void (*set_percent_color)(void *obj, double percent, bool current);
 154        int  (*set_jumps_percent_color)(void *obj, int nr, bool current);
 155        void (*printf)(void *obj, const char *fmt, ...);
 156        void (*write_graph)(void *obj, int graph);
 157};
 158
 159double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes);
 160void annotation_line__write(struct annotation_line *al, struct annotation *notes,
 161                            struct annotation_write_ops *ops);
 162
 163int __annotation__scnprintf_samples_period(struct annotation *notes,
 164                                           char *bf, size_t size,
 165                                           struct perf_evsel *evsel,
 166                                           bool show_freq);
 167
 168static inline int annotation__scnprintf_samples_period(struct annotation *notes,
 169                                                       char *bf, size_t size,
 170                                                       struct perf_evsel *evsel)
 171{
 172        return __annotation__scnprintf_samples_period(notes, bf, size, evsel, true);
 173}
 174
 175int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
 176size_t disasm__fprintf(struct list_head *head, FILE *fp);
 177void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel);
 178
 179struct sym_hist {
 180        u64                   nr_samples;
 181        u64                   period;
 182        struct sym_hist_entry addr[0];
 183};
 184
 185struct cyc_hist {
 186        u64     start;
 187        u64     cycles;
 188        u64     cycles_aggr;
 189        u32     num;
 190        u32     num_aggr;
 191        u8      have_start;
 192        /* 1 byte padding */
 193        u16     reset;
 194};
 195
 196/** struct annotated_source - symbols with hits have this attached as in sannotation
 197 *
 198 * @histogram: Array of addr hit histograms per event being monitored
 199 * @lines: If 'print_lines' is specified, per source code line percentages
 200 * @source: source parsed from a disassembler like objdump -dS
 201 * @cyc_hist: Average cycles per basic block
 202 *
 203 * lines is allocated, percentages calculated and all sorted by percentage
 204 * when the annotation is about to be presented, so the percentages are for
 205 * one of the entries in the histogram array, i.e. for the event/counter being
 206 * presented. It is deallocated right after symbol__{tui,tty,etc}_annotate
 207 * returns.
 208 */
 209struct annotated_source {
 210        struct list_head   source;
 211        int                nr_histograms;
 212        size_t             sizeof_sym_hist;
 213        struct cyc_hist    *cycles_hist;
 214        struct sym_hist    histograms[0];
 215};
 216
 217struct annotation {
 218        pthread_mutex_t         lock;
 219        u64                     max_coverage;
 220        u64                     start;
 221        struct annotation_options *options;
 222        struct annotation_line  **offsets;
 223        int                     nr_events;
 224        int                     nr_jumps;
 225        int                     max_jump_sources;
 226        int                     nr_entries;
 227        int                     nr_asm_entries;
 228        u16                     max_line_len;
 229        struct {
 230                u8              addr;
 231                u8              jumps;
 232                u8              target;
 233                u8              min_addr;
 234                u8              max_addr;
 235        } widths;
 236        bool                    have_cycles;
 237        struct annotated_source *src;
 238};
 239
 240static inline int annotation__cycles_width(struct annotation *notes)
 241{
 242        return notes->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0;
 243}
 244
 245static inline int annotation__pcnt_width(struct annotation *notes)
 246{
 247        return (notes->options->show_total_period ? 12 : 7) * notes->nr_events;
 248}
 249
 250static inline bool annotation_line__filter(struct annotation_line *al, struct annotation *notes)
 251{
 252        return notes->options->hide_src_code && al->offset == -1;
 253}
 254
 255void annotation__set_offsets(struct annotation *notes, s64 size);
 256void annotation__compute_ipc(struct annotation *notes, size_t size);
 257void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym);
 258void annotation__update_column_widths(struct annotation *notes);
 259void annotation__init_column_widths(struct annotation *notes, struct symbol *sym);
 260
 261static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx)
 262{
 263        return (((void *)&notes->src->histograms) +
 264                (notes->src->sizeof_sym_hist * idx));
 265}
 266
 267static inline struct annotation *symbol__annotation(struct symbol *sym)
 268{
 269        return (void *)sym - symbol_conf.priv_size;
 270}
 271
 272int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample,
 273                                 int evidx);
 274
 275int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
 276                                    struct addr_map_symbol *start,
 277                                    unsigned cycles);
 278
 279int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample,
 280                                 int evidx, u64 addr);
 281
 282int symbol__alloc_hist(struct symbol *sym);
 283void symbol__annotate_zero_histograms(struct symbol *sym);
 284
 285int symbol__annotate(struct symbol *sym, struct map *map,
 286                     struct perf_evsel *evsel, size_t privsize,
 287                     struct arch **parch);
 288int symbol__annotate2(struct symbol *sym, struct map *map,
 289                      struct perf_evsel *evsel,
 290                      struct annotation_options *options,
 291                      struct arch **parch);
 292
 293enum symbol_disassemble_errno {
 294        SYMBOL_ANNOTATE_ERRNO__SUCCESS          = 0,
 295
 296        /*
 297         * Choose an arbitrary negative big number not to clash with standard
 298         * errno since SUS requires the errno has distinct positive values.
 299         * See 'Issue 6' in the link below.
 300         *
 301         * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
 302         */
 303        __SYMBOL_ANNOTATE_ERRNO__START          = -10000,
 304
 305        SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX       = __SYMBOL_ANNOTATE_ERRNO__START,
 306
 307        __SYMBOL_ANNOTATE_ERRNO__END,
 308};
 309
 310int symbol__strerror_disassemble(struct symbol *sym, struct map *map,
 311                                 int errnum, char *buf, size_t buflen);
 312
 313int symbol__annotate_printf(struct symbol *sym, struct map *map,
 314                            struct perf_evsel *evsel, bool full_paths,
 315                            int min_pcnt, int max_lines, int context);
 316int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp);
 317void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
 318void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
 319void annotated_source__purge(struct annotated_source *as);
 320
 321int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel);
 322
 323bool ui__has_annotation(void);
 324
 325int symbol__tty_annotate(struct symbol *sym, struct map *map,
 326                         struct perf_evsel *evsel, bool print_lines,
 327                         bool full_paths, int min_pcnt, int max_lines);
 328
 329int symbol__tty_annotate2(struct symbol *sym, struct map *map,
 330                          struct perf_evsel *evsel, bool print_lines,
 331                          bool full_paths);
 332
 333#ifdef HAVE_SLANG_SUPPORT
 334int symbol__tui_annotate(struct symbol *sym, struct map *map,
 335                         struct perf_evsel *evsel,
 336                         struct hist_browser_timer *hbt);
 337#else
 338static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
 339                                struct map *map __maybe_unused,
 340                                struct perf_evsel *evsel  __maybe_unused,
 341                                struct hist_browser_timer *hbt
 342                                __maybe_unused)
 343{
 344        return 0;
 345}
 346#endif
 347
 348extern const char       *disassembler_style;
 349
 350void annotation_config__init(void);
 351
 352#endif  /* __PERF_ANNOTATE_H */
 353