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