Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf annotate: Add --type-stat option for debugging

The --type-stat option is to be used with --data-type and to print
detailed failure reasons for the data type annotation.

$ perf annotate --data-type --type-stat
Annotate data type stats:
total 294, ok 116 (39.5%), bad 178 (60.5%)
-----------------------------------------------------------
30 : no_sym
40 : no_insn_ops
33 : no_mem_ops
63 : no_var
4 : no_typeinfo
8 : bad_offset

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: linux-toolchains@vger.kernel.org
Cc: linux-trace-devel@vger.kernel.org
Link: https://lore.kernel.org/r/20231213001323.718046-17-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Namhyung Kim and committed by
Arnaldo Carvalho de Melo
61a9741e 227ad323

+109 -8
+3
tools/perf/Documentation/perf-annotate.txt
··· 162 162 that case it'd show annotation for the type only, otherwise it'd show 163 163 all data types it finds. 164 164 165 + --type-stat:: 166 + Show stats for the data type annotation. 167 + 165 168 166 169 SEE ALSO 167 170 --------
+43 -1
tools/perf/builtin-annotate.c
··· 57 57 bool has_br_stack; 58 58 bool group_set; 59 59 bool data_type; 60 + bool type_stat; 60 61 float min_percent; 61 62 const char *sym_hist_filter; 62 63 const char *cpu_list; ··· 397 396 printf(";\n"); 398 397 } 399 398 399 + static void print_annotate_data_stat(struct annotated_data_stat *s) 400 + { 401 + #define PRINT_STAT(fld) if (s->fld) printf("%10d : %s\n", s->fld, #fld) 402 + 403 + int bad = s->no_sym + 404 + s->no_insn + 405 + s->no_insn_ops + 406 + s->no_mem_ops + 407 + s->no_reg + 408 + s->no_dbginfo + 409 + s->no_cuinfo + 410 + s->no_var + 411 + s->no_typeinfo + 412 + s->invalid_size + 413 + s->bad_offset; 414 + int ok = s->total - bad; 415 + 416 + printf("Annotate data type stats:\n"); 417 + printf("total %d, ok %d (%.1f%%), bad %d (%.1f%%)\n", 418 + s->total, ok, 100.0 * ok / (s->total ?: 1), bad, 100.0 * bad / (s->total ?: 1)); 419 + printf("-----------------------------------------------------------\n"); 420 + PRINT_STAT(no_sym); 421 + PRINT_STAT(no_insn); 422 + PRINT_STAT(no_insn_ops); 423 + PRINT_STAT(no_mem_ops); 424 + PRINT_STAT(no_reg); 425 + PRINT_STAT(no_dbginfo); 426 + PRINT_STAT(no_cuinfo); 427 + PRINT_STAT(no_var); 428 + PRINT_STAT(no_typeinfo); 429 + PRINT_STAT(invalid_size); 430 + PRINT_STAT(bad_offset); 431 + printf("\n"); 432 + 433 + #undef PRINT_STAT 434 + } 435 + 400 436 static void hists__find_annotations(struct hists *hists, 401 437 struct evsel *evsel, 402 438 struct perf_annotate *ann) 403 439 { 404 440 struct rb_node *nd = rb_first_cached(&hists->entries), *next; 405 441 int key = K_RIGHT; 442 + 443 + if (ann->type_stat) 444 + print_annotate_data_stat(&ann_data_stat); 406 445 407 446 while (nd) { 408 447 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); ··· 790 749 OPT_CALLBACK_OPTARG(0, "data-type", &annotate, NULL, "name", 791 750 "Show data type annotate for the memory accesses", 792 751 parse_data_type), 793 - 752 + OPT_BOOLEAN(0, "type-stat", &annotate.type_stat, 753 + "Show stats for the data type annotation"), 794 754 OPT_END() 795 755 }; 796 756 int ret;
+9 -1
tools/perf/util/annotate-data.c
··· 199 199 /* Get the type of the variable */ 200 200 if (die_get_real_type(var_die, type_die) == NULL) { 201 201 pr_debug("variable has no type\n"); 202 + ann_data_stat.no_typeinfo++; 202 203 return -1; 203 204 } 204 205 ··· 210 209 if (dwarf_tag(type_die) != DW_TAG_pointer_type || 211 210 die_get_real_type(type_die, type_die) == NULL) { 212 211 pr_debug("no pointer or no type\n"); 212 + ann_data_stat.no_typeinfo++; 213 213 return -1; 214 214 } 215 215 216 216 /* Get the size of the actual type */ 217 217 if (dwarf_aggregate_size(type_die, &size) < 0) { 218 218 pr_debug("type size is unknown\n"); 219 + ann_data_stat.invalid_size++; 219 220 return -1; 220 221 } 221 222 222 223 /* Minimal sanity check */ 223 224 if ((unsigned)offset >= size) { 224 225 pr_debug("offset: %d is bigger than size: %" PRIu64 "\n", offset, size); 226 + ann_data_stat.bad_offset++; 225 227 return -1; 226 228 } 227 229 ··· 243 239 /* Get a compile_unit for this address */ 244 240 if (!find_cu_die(di, pc, &cu_die)) { 245 241 pr_debug("cannot find CU for address %" PRIx64 "\n", pc); 242 + ann_data_stat.no_cuinfo++; 246 243 return -1; 247 244 } 248 245 ··· 258 253 259 254 /* Found a variable, see if it's correct */ 260 255 ret = check_variable(&var_die, type_die, offset); 261 - break; 256 + goto out; 262 257 } 258 + if (ret < 0) 259 + ann_data_stat.no_var++; 263 260 261 + out: 264 262 free(scopes); 265 263 return ret; 266 264 }
+31
tools/perf/util/annotate-data.h
··· 70 70 71 71 extern struct annotated_data_type unknown_type; 72 72 73 + /** 74 + * struct annotated_data_stat - Debug statistics 75 + * @total: Total number of entry 76 + * @no_sym: No symbol or map found 77 + * @no_insn: Failed to get disasm line 78 + * @no_insn_ops: The instruction has no operands 79 + * @no_mem_ops: The instruction has no memory operands 80 + * @no_reg: Failed to extract a register from the operand 81 + * @no_dbginfo: The binary has no debug information 82 + * @no_cuinfo: Failed to find a compile_unit 83 + * @no_var: Failed to find a matching variable 84 + * @no_typeinfo: Failed to get a type info for the variable 85 + * @invalid_size: Failed to get a size info of the type 86 + * @bad_offset: The access offset is out of the type 87 + */ 88 + struct annotated_data_stat { 89 + int total; 90 + int no_sym; 91 + int no_insn; 92 + int no_insn_ops; 93 + int no_mem_ops; 94 + int no_reg; 95 + int no_dbginfo; 96 + int no_cuinfo; 97 + int no_var; 98 + int no_typeinfo; 99 + int invalid_size; 100 + int bad_offset; 101 + }; 102 + extern struct annotated_data_stat ann_data_stat; 103 + 73 104 #ifdef HAVE_DWARF_SUPPORT 74 105 75 106 /* Returns data type at the location (ip, reg, offset) */
+23 -6
tools/perf/util/annotate.c
··· 103 103 static struct ins_ops lock_ops; 104 104 static struct ins_ops ret_ops; 105 105 106 + /* Data type collection debug statistics */ 107 + struct annotated_data_stat ann_data_stat; 108 + 106 109 static int arch__grow_instructions(struct arch *arch) 107 110 { 108 111 struct ins *new_instructions; ··· 3686 3683 u64 ip = he->ip; 3687 3684 int i; 3688 3685 3689 - if (ms->map == NULL || ms->sym == NULL) 3690 - return NULL; 3686 + ann_data_stat.total++; 3691 3687 3692 - if (!symbol_conf.init_annotation) 3688 + if (ms->map == NULL || ms->sym == NULL) { 3689 + ann_data_stat.no_sym++; 3693 3690 return NULL; 3691 + } 3694 3692 3695 - if (evsel__get_arch(evsel, &arch) < 0) 3693 + if (!symbol_conf.init_annotation) { 3694 + ann_data_stat.no_sym++; 3696 3695 return NULL; 3696 + } 3697 + 3698 + if (evsel__get_arch(evsel, &arch) < 0) { 3699 + ann_data_stat.no_insn++; 3700 + return NULL; 3701 + } 3697 3702 3698 3703 /* Make sure it runs objdump to get disasm of the function */ 3699 3704 symbol__ensure_annotate(ms, evsel); ··· 3711 3700 * This is too slow... 3712 3701 */ 3713 3702 dl = find_disasm_line(ms->sym, ip); 3714 - if (dl == NULL) 3703 + if (dl == NULL) { 3704 + ann_data_stat.no_insn++; 3715 3705 return NULL; 3706 + } 3716 3707 3717 - if (annotate_get_insn_location(arch, dl, &loc) < 0) 3708 + if (annotate_get_insn_location(arch, dl, &loc) < 0) { 3709 + ann_data_stat.no_insn_ops++; 3718 3710 return NULL; 3711 + } 3719 3712 3720 3713 for_each_insn_op_loc(&loc, i, op_loc) { 3721 3714 if (!op_loc->mem_ref) ··· 3736 3721 he->mem_type_off = op_loc->offset; 3737 3722 return mem_type; 3738 3723 } 3724 + 3725 + ann_data_stat.no_mem_ops++; 3739 3726 return NULL; 3740 3727 }