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 15 struct ins_ops; 16 17 struct ins { 18 const char *name; 19 struct ins_ops *ops; 20 }; 21 22 struct 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 46 struct arch; 47 48 struct 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 55 bool ins__is_jump(const struct ins *ins); 56 bool ins__is_call(const struct ins *ins); 57 bool ins__is_ret(const struct ins *ins); 58 bool ins__is_lock(const struct ins *ins); 59 int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); 60 bool 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 66 struct 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 87 enum { 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 95 extern struct annotation_options annotation__default_options; 96 97 struct annotation; 98 99 struct sym_hist_entry { 100 u64 nr_samples; 101 u64 period; 102 }; 103 104 struct annotation_data { 105 double percent; 106 double percent_sum; 107 struct sym_hist_entry he; 108 }; 109 110 struct 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 129 struct 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 137 static 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 */ 146 static 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 */ 155 bool disasm_line__is_valid_local_jump(struct disasm_line *dl, struct symbol *sym); 156 157 void disasm_line__free(struct disasm_line *dl); 158 struct annotation_line * 159 annotation_line__next(struct annotation_line *pos, struct list_head *head); 160 161 struct 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 172 double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes); 173 void annotation_line__write(struct annotation_line *al, struct annotation *notes, 174 struct annotation_write_ops *ops); 175 176 int __annotation__scnprintf_samples_period(struct annotation *notes, 177 char *bf, size_t size, 178 struct perf_evsel *evsel, 179 bool show_freq); 180 181 static 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 188 int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); 189 size_t disasm__fprintf(struct list_head *head, FILE *fp); 190 void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); 191 192 struct sym_hist { 193 u64 nr_samples; 194 u64 period; 195 struct sym_hist_entry addr[0]; 196 }; 197 198 struct 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 */ 228 struct 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 236 struct 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 259 static 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 267 static inline int annotation__pcnt_width(struct annotation *notes) 268 { 269 return (notes->options->show_total_period ? 12 : 7) * notes->nr_events; 270 } 271 272 static 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 277 void annotation__set_offsets(struct annotation *notes, s64 size); 278 void annotation__compute_ipc(struct annotation *notes, size_t size); 279 void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym); 280 void annotation__update_column_widths(struct annotation *notes); 281 void annotation__init_column_widths(struct annotation *notes, struct symbol *sym); 282 283 static 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 288 static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) 289 { 290 return annotated_source__histogram(notes->src, idx); 291 } 292 293 static inline struct annotation *symbol__annotation(struct symbol *sym) 294 { 295 return (void *)sym - symbol_conf.priv_size; 296 } 297 298 int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, 299 struct perf_evsel *evsel); 300 301 int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, 302 struct addr_map_symbol *start, 303 unsigned cycles); 304 305 int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, 306 struct perf_evsel *evsel, u64 addr); 307 308 struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists); 309 void symbol__annotate_zero_histograms(struct symbol *sym); 310 311 int 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); 315 int symbol__annotate2(struct symbol *sym, struct map *map, 316 struct perf_evsel *evsel, 317 struct annotation_options *options, 318 struct arch **parch); 319 320 enum 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 337 int symbol__strerror_disassemble(struct symbol *sym, struct map *map, 338 int errnum, char *buf, size_t buflen); 339 340 int symbol__annotate_printf(struct symbol *sym, struct map *map, 341 struct perf_evsel *evsel, 342 struct annotation_options *options); 343 int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp); 344 void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); 345 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); 346 void annotated_source__purge(struct annotated_source *as); 347 348 int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel); 349 350 bool ui__has_annotation(void); 351 352 int symbol__tty_annotate(struct symbol *sym, struct map *map, 353 struct perf_evsel *evsel, struct annotation_options *opts); 354 355 int symbol__tty_annotate2(struct symbol *sym, struct map *map, 356 struct perf_evsel *evsel, struct annotation_options *opts); 357 358 #ifdef HAVE_SLANG_SUPPORT 359 int 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 364 static 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 374 void annotation_config__init(void); 375 376 #endif /* __PERF_ANNOTATE_H */ 377