Commit 61a9741e authored by Namhyung Kim's avatar Namhyung Kim Committed by Arnaldo Carvalho de Melo

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: default avatarNamhyung Kim <namhyung@kernel.org>
Tested-by: default avatarArnaldo 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.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 227ad323
...@@ -162,6 +162,9 @@ include::itrace.txt[] ...@@ -162,6 +162,9 @@ include::itrace.txt[]
that case it'd show annotation for the type only, otherwise it'd show that case it'd show annotation for the type only, otherwise it'd show
all data types it finds. all data types it finds.
--type-stat::
Show stats for the data type annotation.
SEE ALSO SEE ALSO
-------- --------
......
...@@ -57,6 +57,7 @@ struct perf_annotate { ...@@ -57,6 +57,7 @@ struct perf_annotate {
bool has_br_stack; bool has_br_stack;
bool group_set; bool group_set;
bool data_type; bool data_type;
bool type_stat;
float min_percent; float min_percent;
const char *sym_hist_filter; const char *sym_hist_filter;
const char *cpu_list; const char *cpu_list;
...@@ -396,6 +397,43 @@ static void print_annotated_data_type(struct annotated_data_type *mem_type, ...@@ -396,6 +397,43 @@ static void print_annotated_data_type(struct annotated_data_type *mem_type,
printf(";\n"); printf(";\n");
} }
static void print_annotate_data_stat(struct annotated_data_stat *s)
{
#define PRINT_STAT(fld) if (s->fld) printf("%10d : %s\n", s->fld, #fld)
int bad = s->no_sym +
s->no_insn +
s->no_insn_ops +
s->no_mem_ops +
s->no_reg +
s->no_dbginfo +
s->no_cuinfo +
s->no_var +
s->no_typeinfo +
s->invalid_size +
s->bad_offset;
int ok = s->total - bad;
printf("Annotate data type stats:\n");
printf("total %d, ok %d (%.1f%%), bad %d (%.1f%%)\n",
s->total, ok, 100.0 * ok / (s->total ?: 1), bad, 100.0 * bad / (s->total ?: 1));
printf("-----------------------------------------------------------\n");
PRINT_STAT(no_sym);
PRINT_STAT(no_insn);
PRINT_STAT(no_insn_ops);
PRINT_STAT(no_mem_ops);
PRINT_STAT(no_reg);
PRINT_STAT(no_dbginfo);
PRINT_STAT(no_cuinfo);
PRINT_STAT(no_var);
PRINT_STAT(no_typeinfo);
PRINT_STAT(invalid_size);
PRINT_STAT(bad_offset);
printf("\n");
#undef PRINT_STAT
}
static void hists__find_annotations(struct hists *hists, static void hists__find_annotations(struct hists *hists,
struct evsel *evsel, struct evsel *evsel,
struct perf_annotate *ann) struct perf_annotate *ann)
...@@ -403,6 +441,9 @@ static void hists__find_annotations(struct hists *hists, ...@@ -403,6 +441,9 @@ static void hists__find_annotations(struct hists *hists,
struct rb_node *nd = rb_first_cached(&hists->entries), *next; struct rb_node *nd = rb_first_cached(&hists->entries), *next;
int key = K_RIGHT; int key = K_RIGHT;
if (ann->type_stat)
print_annotate_data_stat(&ann_data_stat);
while (nd) { while (nd) {
struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
struct annotation *notes; struct annotation *notes;
...@@ -749,7 +790,8 @@ int cmd_annotate(int argc, const char **argv) ...@@ -749,7 +790,8 @@ int cmd_annotate(int argc, const char **argv)
OPT_CALLBACK_OPTARG(0, "data-type", &annotate, NULL, "name", OPT_CALLBACK_OPTARG(0, "data-type", &annotate, NULL, "name",
"Show data type annotate for the memory accesses", "Show data type annotate for the memory accesses",
parse_data_type), parse_data_type),
OPT_BOOLEAN(0, "type-stat", &annotate.type_stat,
"Show stats for the data type annotation"),
OPT_END() OPT_END()
}; };
int ret; int ret;
......
...@@ -199,6 +199,7 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset) ...@@ -199,6 +199,7 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset)
/* Get the type of the variable */ /* Get the type of the variable */
if (die_get_real_type(var_die, type_die) == NULL) { if (die_get_real_type(var_die, type_die) == NULL) {
pr_debug("variable has no type\n"); pr_debug("variable has no type\n");
ann_data_stat.no_typeinfo++;
return -1; return -1;
} }
...@@ -209,18 +210,21 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset) ...@@ -209,18 +210,21 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset)
if (dwarf_tag(type_die) != DW_TAG_pointer_type || if (dwarf_tag(type_die) != DW_TAG_pointer_type ||
die_get_real_type(type_die, type_die) == NULL) { die_get_real_type(type_die, type_die) == NULL) {
pr_debug("no pointer or no type\n"); pr_debug("no pointer or no type\n");
ann_data_stat.no_typeinfo++;
return -1; return -1;
} }
/* Get the size of the actual type */ /* Get the size of the actual type */
if (dwarf_aggregate_size(type_die, &size) < 0) { if (dwarf_aggregate_size(type_die, &size) < 0) {
pr_debug("type size is unknown\n"); pr_debug("type size is unknown\n");
ann_data_stat.invalid_size++;
return -1; return -1;
} }
/* Minimal sanity check */ /* Minimal sanity check */
if ((unsigned)offset >= size) { if ((unsigned)offset >= size) {
pr_debug("offset: %d is bigger than size: %" PRIu64 "\n", offset, size); pr_debug("offset: %d is bigger than size: %" PRIu64 "\n", offset, size);
ann_data_stat.bad_offset++;
return -1; return -1;
} }
...@@ -239,6 +243,7 @@ static int find_data_type_die(struct debuginfo *di, u64 pc, ...@@ -239,6 +243,7 @@ static int find_data_type_die(struct debuginfo *di, u64 pc,
/* Get a compile_unit for this address */ /* Get a compile_unit for this address */
if (!find_cu_die(di, pc, &cu_die)) { if (!find_cu_die(di, pc, &cu_die)) {
pr_debug("cannot find CU for address %" PRIx64 "\n", pc); pr_debug("cannot find CU for address %" PRIx64 "\n", pc);
ann_data_stat.no_cuinfo++;
return -1; return -1;
} }
...@@ -253,9 +258,12 @@ static int find_data_type_die(struct debuginfo *di, u64 pc, ...@@ -253,9 +258,12 @@ static int find_data_type_die(struct debuginfo *di, u64 pc,
/* Found a variable, see if it's correct */ /* Found a variable, see if it's correct */
ret = check_variable(&var_die, type_die, offset); ret = check_variable(&var_die, type_die, offset);
break; goto out;
} }
if (ret < 0)
ann_data_stat.no_var++;
out:
free(scopes); free(scopes);
return ret; return ret;
} }
......
...@@ -70,6 +70,37 @@ struct annotated_data_type { ...@@ -70,6 +70,37 @@ struct annotated_data_type {
extern struct annotated_data_type unknown_type; extern struct annotated_data_type unknown_type;
/**
* struct annotated_data_stat - Debug statistics
* @total: Total number of entry
* @no_sym: No symbol or map found
* @no_insn: Failed to get disasm line
* @no_insn_ops: The instruction has no operands
* @no_mem_ops: The instruction has no memory operands
* @no_reg: Failed to extract a register from the operand
* @no_dbginfo: The binary has no debug information
* @no_cuinfo: Failed to find a compile_unit
* @no_var: Failed to find a matching variable
* @no_typeinfo: Failed to get a type info for the variable
* @invalid_size: Failed to get a size info of the type
* @bad_offset: The access offset is out of the type
*/
struct annotated_data_stat {
int total;
int no_sym;
int no_insn;
int no_insn_ops;
int no_mem_ops;
int no_reg;
int no_dbginfo;
int no_cuinfo;
int no_var;
int no_typeinfo;
int invalid_size;
int bad_offset;
};
extern struct annotated_data_stat ann_data_stat;
#ifdef HAVE_DWARF_SUPPORT #ifdef HAVE_DWARF_SUPPORT
/* Returns data type at the location (ip, reg, offset) */ /* Returns data type at the location (ip, reg, offset) */
......
...@@ -103,6 +103,9 @@ static struct ins_ops nop_ops; ...@@ -103,6 +103,9 @@ static struct ins_ops nop_ops;
static struct ins_ops lock_ops; static struct ins_ops lock_ops;
static struct ins_ops ret_ops; static struct ins_ops ret_ops;
/* Data type collection debug statistics */
struct annotated_data_stat ann_data_stat;
static int arch__grow_instructions(struct arch *arch) static int arch__grow_instructions(struct arch *arch)
{ {
struct ins *new_instructions; struct ins *new_instructions;
...@@ -3683,14 +3686,22 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) ...@@ -3683,14 +3686,22 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
u64 ip = he->ip; u64 ip = he->ip;
int i; int i;
if (ms->map == NULL || ms->sym == NULL) ann_data_stat.total++;
if (ms->map == NULL || ms->sym == NULL) {
ann_data_stat.no_sym++;
return NULL; return NULL;
}
if (!symbol_conf.init_annotation) if (!symbol_conf.init_annotation) {
ann_data_stat.no_sym++;
return NULL; return NULL;
}
if (evsel__get_arch(evsel, &arch) < 0) if (evsel__get_arch(evsel, &arch) < 0) {
ann_data_stat.no_insn++;
return NULL; return NULL;
}
/* Make sure it runs objdump to get disasm of the function */ /* Make sure it runs objdump to get disasm of the function */
symbol__ensure_annotate(ms, evsel); symbol__ensure_annotate(ms, evsel);
...@@ -3700,11 +3711,15 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) ...@@ -3700,11 +3711,15 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
* This is too slow... * This is too slow...
*/ */
dl = find_disasm_line(ms->sym, ip); dl = find_disasm_line(ms->sym, ip);
if (dl == NULL) if (dl == NULL) {
ann_data_stat.no_insn++;
return NULL; return NULL;
}
if (annotate_get_insn_location(arch, dl, &loc) < 0) if (annotate_get_insn_location(arch, dl, &loc) < 0) {
ann_data_stat.no_insn_ops++;
return NULL; return NULL;
}
for_each_insn_op_loc(&loc, i, op_loc) { for_each_insn_op_loc(&loc, i, op_loc) {
if (!op_loc->mem_ref) if (!op_loc->mem_ref)
...@@ -3721,5 +3736,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) ...@@ -3721,5 +3736,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
he->mem_type_off = op_loc->offset; he->mem_type_off = op_loc->offset;
return mem_type; return mem_type;
} }
ann_data_stat.no_mem_ops++;
return NULL; return NULL;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment