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