Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef __PERF_ANNOTATE_H
0003 #define __PERF_ANNOTATE_H
0004 
0005 #include <stdbool.h>
0006 #include <stdint.h>
0007 #include <stdio.h>
0008 #include <linux/types.h>
0009 #include <linux/list.h>
0010 #include <linux/rbtree.h>
0011 #include <pthread.h>
0012 #include <asm/bug.h>
0013 #include "symbol_conf.h"
0014 #include "spark.h"
0015 
0016 struct hist_browser_timer;
0017 struct hist_entry;
0018 struct ins_ops;
0019 struct map;
0020 struct map_symbol;
0021 struct addr_map_symbol;
0022 struct option;
0023 struct perf_sample;
0024 struct evsel;
0025 struct symbol;
0026 
0027 struct ins {
0028     const char     *name;
0029     struct ins_ops *ops;
0030 };
0031 
0032 struct ins_operands {
0033     char    *raw;
0034     char    *raw_comment;
0035     char    *raw_func_start;
0036     struct {
0037         char    *raw;
0038         char    *name;
0039         struct symbol *sym;
0040         u64 addr;
0041         s64 offset;
0042         bool    offset_avail;
0043         bool    outside;
0044     } target;
0045     union {
0046         struct {
0047             char    *raw;
0048             char    *name;
0049             u64 addr;
0050         } source;
0051         struct {
0052             struct ins      ins;
0053             struct ins_operands *ops;
0054         } locked;
0055     };
0056 };
0057 
0058 struct arch;
0059 
0060 struct ins_ops {
0061     void (*free)(struct ins_operands *ops);
0062     int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms);
0063     int (*scnprintf)(struct ins *ins, char *bf, size_t size,
0064              struct ins_operands *ops, int max_ins_name);
0065 };
0066 
0067 bool ins__is_jump(const struct ins *ins);
0068 bool ins__is_call(const struct ins *ins);
0069 bool ins__is_ret(const struct ins *ins);
0070 bool ins__is_lock(const struct ins *ins);
0071 int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name);
0072 bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2);
0073 
0074 #define ANNOTATION__IPC_WIDTH 6
0075 #define ANNOTATION__CYCLES_WIDTH 6
0076 #define ANNOTATION__MINMAX_CYCLES_WIDTH 19
0077 #define ANNOTATION__AVG_IPC_WIDTH 36
0078 #define ANNOTATION_DUMMY_LEN    256
0079 
0080 struct annotation_options {
0081     bool hide_src_code,
0082          use_offset,
0083          jump_arrows,
0084          print_lines,
0085          full_path,
0086          show_linenr,
0087          show_fileloc,
0088          show_nr_jumps,
0089          show_minmax_cycle,
0090          show_asm_raw,
0091          annotate_src;
0092     u8   offset_level;
0093     int  min_pcnt;
0094     int  max_lines;
0095     int  context;
0096     const char *objdump_path;
0097     const char *disassembler_style;
0098     const char *prefix;
0099     const char *prefix_strip;
0100     unsigned int percent_type;
0101 };
0102 
0103 enum {
0104     ANNOTATION__OFFSET_JUMP_TARGETS = 1,
0105     ANNOTATION__OFFSET_CALL,
0106     ANNOTATION__MAX_OFFSET_LEVEL,
0107 };
0108 
0109 #define ANNOTATION__MIN_OFFSET_LEVEL ANNOTATION__OFFSET_JUMP_TARGETS
0110 
0111 extern struct annotation_options annotation__default_options;
0112 
0113 struct annotation;
0114 
0115 struct sym_hist_entry {
0116     u64     nr_samples;
0117     u64     period;
0118 };
0119 
0120 enum {
0121     PERCENT_HITS_LOCAL,
0122     PERCENT_HITS_GLOBAL,
0123     PERCENT_PERIOD_LOCAL,
0124     PERCENT_PERIOD_GLOBAL,
0125     PERCENT_MAX,
0126 };
0127 
0128 struct annotation_data {
0129     double           percent[PERCENT_MAX];
0130     double           percent_sum;
0131     struct sym_hist_entry    he;
0132 };
0133 
0134 struct annotation_line {
0135     struct list_head     node;
0136     struct rb_node       rb_node;
0137     s64          offset;
0138     char            *line;
0139     int          line_nr;
0140     char            *fileloc;
0141     int          jump_sources;
0142     float            ipc;
0143     u64          cycles;
0144     u64          cycles_max;
0145     u64          cycles_min;
0146     char            *path;
0147     u32          idx;
0148     int          idx_asm;
0149     int          data_nr;
0150     struct annotation_data   data[];
0151 };
0152 
0153 struct disasm_line {
0154     struct ins       ins;
0155     struct ins_operands  ops;
0156 
0157     /* This needs to be at the end. */
0158     struct annotation_line   al;
0159 };
0160 
0161 static inline double annotation_data__percent(struct annotation_data *data,
0162                           unsigned int which)
0163 {
0164     return which < PERCENT_MAX ? data->percent[which] : -1;
0165 }
0166 
0167 static inline const char *percent_type_str(unsigned int type)
0168 {
0169     static const char *str[PERCENT_MAX] = {
0170         "local hits",
0171         "global hits",
0172         "local period",
0173         "global period",
0174     };
0175 
0176     if (WARN_ON(type >= PERCENT_MAX))
0177         return "N/A";
0178 
0179     return str[type];
0180 }
0181 
0182 static inline struct disasm_line *disasm_line(struct annotation_line *al)
0183 {
0184     return al ? container_of(al, struct disasm_line, al) : NULL;
0185 }
0186 
0187 /*
0188  * Is this offset in the same function as the line it is used?
0189  * asm functions jump to other functions, for instance.
0190  */
0191 static inline bool disasm_line__has_local_offset(const struct disasm_line *dl)
0192 {
0193     return dl->ops.target.offset_avail && !dl->ops.target.outside;
0194 }
0195 
0196 /*
0197  * Can we draw an arrow from the jump to its target, for instance? I.e.
0198  * is the jump and its target in the same function?
0199  */
0200 bool disasm_line__is_valid_local_jump(struct disasm_line *dl, struct symbol *sym);
0201 
0202 void disasm_line__free(struct disasm_line *dl);
0203 struct annotation_line *
0204 annotation_line__next(struct annotation_line *pos, struct list_head *head);
0205 
0206 struct annotation_write_ops {
0207     bool first_line, current_entry, change_color;
0208     int  width;
0209     void *obj;
0210     int  (*set_color)(void *obj, int color);
0211     void (*set_percent_color)(void *obj, double percent, bool current);
0212     int  (*set_jumps_percent_color)(void *obj, int nr, bool current);
0213     void (*printf)(void *obj, const char *fmt, ...);
0214     void (*write_graph)(void *obj, int graph);
0215 };
0216 
0217 void annotation_line__write(struct annotation_line *al, struct annotation *notes,
0218                 struct annotation_write_ops *ops,
0219                 struct annotation_options *opts);
0220 
0221 int __annotation__scnprintf_samples_period(struct annotation *notes,
0222                        char *bf, size_t size,
0223                        struct evsel *evsel,
0224                        bool show_freq);
0225 
0226 int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name);
0227 size_t disasm__fprintf(struct list_head *head, FILE *fp);
0228 void symbol__calc_percent(struct symbol *sym, struct evsel *evsel);
0229 
0230 struct sym_hist {
0231     u64           nr_samples;
0232     u64           period;
0233     struct sym_hist_entry addr[];
0234 };
0235 
0236 struct cyc_hist {
0237     u64 start;
0238     u64 cycles;
0239     u64 cycles_aggr;
0240     u64 cycles_max;
0241     u64 cycles_min;
0242     s64 cycles_spark[NUM_SPARKS];
0243     u32 num;
0244     u32 num_aggr;
0245     u8  have_start;
0246     /* 1 byte padding */
0247     u16 reset;
0248 };
0249 
0250 /** struct annotated_source - symbols with hits have this attached as in sannotation
0251  *
0252  * @histograms: Array of addr hit histograms per event being monitored
0253  * nr_histograms: This may not be the same as evsel->evlist->core.nr_entries if
0254  *        we have more than a group in a evlist, where we will want
0255  *        to see each group separately, that is why symbol__annotate2()
0256  *        sets src->nr_histograms to evsel->nr_members.
0257  * @lines: If 'print_lines' is specified, per source code line percentages
0258  * @source: source parsed from a disassembler like objdump -dS
0259  * @cyc_hist: Average cycles per basic block
0260  *
0261  * lines is allocated, percentages calculated and all sorted by percentage
0262  * when the annotation is about to be presented, so the percentages are for
0263  * one of the entries in the histogram array, i.e. for the event/counter being
0264  * presented. It is deallocated right after symbol__{tui,tty,etc}_annotate
0265  * returns.
0266  */
0267 struct annotated_source {
0268     struct list_head   source;
0269     int            nr_histograms;
0270     size_t         sizeof_sym_hist;
0271     struct cyc_hist    *cycles_hist;
0272     struct sym_hist    *histograms;
0273 };
0274 
0275 struct annotation {
0276     pthread_mutex_t     lock;
0277     u64         max_coverage;
0278     u64         start;
0279     u64         hit_cycles;
0280     u64         hit_insn;
0281     unsigned int        total_insn;
0282     unsigned int        cover_insn;
0283     struct annotation_options *options;
0284     struct annotation_line  **offsets;
0285     int         nr_events;
0286     int         max_jump_sources;
0287     int         nr_entries;
0288     int         nr_asm_entries;
0289     u16         max_line_len;
0290     struct {
0291         u8      addr;
0292         u8      jumps;
0293         u8      target;
0294         u8      min_addr;
0295         u8      max_addr;
0296         u8      max_ins_name;
0297     } widths;
0298     bool            have_cycles;
0299     struct annotated_source *src;
0300 };
0301 
0302 void annotation__init(struct annotation *notes);
0303 void annotation__exit(struct annotation *notes);
0304 
0305 static inline int annotation__cycles_width(struct annotation *notes)
0306 {
0307     if (notes->have_cycles && notes->options->show_minmax_cycle)
0308         return ANNOTATION__IPC_WIDTH + ANNOTATION__MINMAX_CYCLES_WIDTH;
0309 
0310     return notes->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0;
0311 }
0312 
0313 static inline int annotation__pcnt_width(struct annotation *notes)
0314 {
0315     return (symbol_conf.show_total_period ? 12 : 7) * notes->nr_events;
0316 }
0317 
0318 static inline bool annotation_line__filter(struct annotation_line *al, struct annotation *notes)
0319 {
0320     return notes->options->hide_src_code && al->offset == -1;
0321 }
0322 
0323 void annotation__set_offsets(struct annotation *notes, s64 size);
0324 void annotation__compute_ipc(struct annotation *notes, size_t size);
0325 void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym);
0326 void annotation__update_column_widths(struct annotation *notes);
0327 void annotation__init_column_widths(struct annotation *notes, struct symbol *sym);
0328 
0329 static inline struct sym_hist *annotated_source__histogram(struct annotated_source *src, int idx)
0330 {
0331     return ((void *)src->histograms) + (src->sizeof_sym_hist * idx);
0332 }
0333 
0334 static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx)
0335 {
0336     return annotated_source__histogram(notes->src, idx);
0337 }
0338 
0339 static inline struct annotation *symbol__annotation(struct symbol *sym)
0340 {
0341     return (void *)sym - symbol_conf.priv_size;
0342 }
0343 
0344 int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample,
0345                  struct evsel *evsel);
0346 
0347 int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
0348                     struct addr_map_symbol *start,
0349                     unsigned cycles);
0350 
0351 int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample,
0352                  struct evsel *evsel, u64 addr);
0353 
0354 struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists);
0355 void symbol__annotate_zero_histograms(struct symbol *sym);
0356 
0357 int symbol__annotate(struct map_symbol *ms,
0358              struct evsel *evsel,
0359              struct annotation_options *options,
0360              struct arch **parch);
0361 int symbol__annotate2(struct map_symbol *ms,
0362               struct evsel *evsel,
0363               struct annotation_options *options,
0364               struct arch **parch);
0365 
0366 enum symbol_disassemble_errno {
0367     SYMBOL_ANNOTATE_ERRNO__SUCCESS      = 0,
0368 
0369     /*
0370      * Choose an arbitrary negative big number not to clash with standard
0371      * errno since SUS requires the errno has distinct positive values.
0372      * See 'Issue 6' in the link below.
0373      *
0374      * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
0375      */
0376     __SYMBOL_ANNOTATE_ERRNO__START      = -10000,
0377 
0378     SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX   = __SYMBOL_ANNOTATE_ERRNO__START,
0379     SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF,
0380     SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING,
0381     SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_REGEXP,
0382     SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE,
0383     SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF,
0384 
0385     __SYMBOL_ANNOTATE_ERRNO__END,
0386 };
0387 
0388 int symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, size_t buflen);
0389 
0390 int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel,
0391                 struct annotation_options *options);
0392 void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
0393 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
0394 void annotated_source__purge(struct annotated_source *as);
0395 
0396 int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel,
0397                 struct annotation_options *opts);
0398 
0399 bool ui__has_annotation(void);
0400 
0401 int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts);
0402 
0403 int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts);
0404 
0405 #ifdef HAVE_SLANG_SUPPORT
0406 int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
0407              struct hist_browser_timer *hbt,
0408              struct annotation_options *opts);
0409 #else
0410 static inline int symbol__tui_annotate(struct map_symbol *ms __maybe_unused,
0411                 struct evsel *evsel  __maybe_unused,
0412                 struct hist_browser_timer *hbt __maybe_unused,
0413                 struct annotation_options *opts __maybe_unused)
0414 {
0415     return 0;
0416 }
0417 #endif
0418 
0419 void annotation_config__init(struct annotation_options *opt);
0420 
0421 int annotate_parse_percent_type(const struct option *opt, const char *_str,
0422                 int unset);
0423 
0424 int annotate_check_args(struct annotation_options *args);
0425 
0426 #endif  /* __PERF_ANNOTATE_H */