[PATCH 23/48] perf annotate: Add --insn-stat option for debugging

From: Namhyung Kim
Date: Wed Oct 11 2023 - 23:54:05 EST


This is for a debugging purpose. It'd be useful to see per-instrucion
level success/failure stats.

$ perf annotate --data-type --insn-stat
Annotate Instruction stats
total 264, ok 143 (54.2%), bad 121 (45.8%)

Name : Good Bad
-----------------------------------------------------------
movq : 45 31
movl : 22 11
popq : 0 19
cmpl : 16 3
addq : 8 7
cmpq : 11 3
cmpxchgl : 3 7
cmpxchgq : 8 0
incl : 3 3
movzbl : 4 2
incq : 4 2
decl : 6 0
...

Signed-off-by: Namhyung Kim <namhyung@xxxxxxxxxx>
---
tools/perf/builtin-annotate.c | 41 +++++++++++++++++++++++++++++++++++
tools/perf/util/annotate.c | 39 +++++++++++++++++++++++++++++++++
tools/perf/util/annotate.h | 8 +++++++
3 files changed, 88 insertions(+)

diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 645acaba63f1..a01d5e162466 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -59,6 +59,7 @@ struct perf_annotate {
bool group_set;
bool data_type;
bool type_stat;
+ bool insn_stat;
float min_percent;
const char *sym_hist_filter;
const char *cpu_list;
@@ -390,6 +391,42 @@ static void print_annotate_data_stat(struct annotated_data_stat *s)
#undef PRINT_STAT
}

+static void print_annotate_item_stat(struct list_head *head, const char *title)
+{
+ struct annotated_item_stat *istat, *pos, *iter;
+ int total_good, total_bad, total;
+ int sum1, sum2;
+ LIST_HEAD(tmp);
+
+ /* sort the list by count */
+ list_splice_init(head, &tmp);
+ total_good = total_bad = 0;
+
+ list_for_each_entry_safe(istat, pos, &tmp, list) {
+ total_good += istat->good;
+ total_bad += istat->bad;
+ sum1 = istat->good + istat->bad;
+
+ list_for_each_entry(iter, head, list) {
+ sum2 = iter->good + iter->bad;
+ if (sum1 > sum2)
+ break;
+ }
+ list_move_tail(&istat->list, &iter->list);
+ }
+ total = total_good + total_bad;
+
+ printf("Annotate %s stats\n", title);
+ printf("total %d, ok %d (%.1f%%), bad %d (%.1f%%)\n\n", total,
+ total_good, 100.0 * total_good / (total ?: 1),
+ total_bad, 100.0 * total_bad / (total ?: 1));
+ printf(" %-10s: %5s %5s\n", "Name", "Good", "Bad");
+ printf("-----------------------------------------------------------\n");
+ list_for_each_entry(istat, head, list)
+ printf(" %-10s: %5d %5d\n", istat->name, istat->good, istat->bad);
+ printf("\n");
+}
+
static void hists__find_annotations(struct hists *hists,
struct evsel *evsel,
struct perf_annotate *ann)
@@ -399,6 +436,8 @@ static void hists__find_annotations(struct hists *hists,

if (ann->type_stat)
print_annotate_data_stat(&ann_data_stat);
+ if (ann->insn_stat)
+ print_annotate_item_stat(&ann_insn_stat, "Instruction");

while (nd) {
struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
@@ -700,6 +739,8 @@ int cmd_annotate(int argc, const char **argv)
"Show data type annotate for the memory accesses"),
OPT_BOOLEAN(0, "type-stat", &annotate.type_stat,
"Show stats for the data type annotation"),
+ OPT_BOOLEAN(0, "insn-stat", &annotate.insn_stat,
+ "Show instruction stats for the data type annotation"),
OPT_END()
};
int ret;
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 72b867001e22..3f3cc7ae751f 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -100,6 +100,8 @@ static struct ins_ops nop_ops;
static struct ins_ops lock_ops;
static struct ins_ops ret_ops;

+LIST_HEAD(ann_insn_stat);
+
static int arch__grow_instructions(struct arch *arch)
{
struct ins *new_instructions;
@@ -3628,6 +3630,30 @@ static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip)
return NULL;
}

+static struct annotated_item_stat *annotate_data_stat(struct list_head *head,
+ const char *name)
+{
+ struct annotated_item_stat *istat;
+
+ list_for_each_entry(istat, head, list) {
+ if (!strcmp(istat->name, name))
+ return istat;
+ }
+
+ istat = zalloc(sizeof(*istat));
+ if (istat == NULL)
+ return NULL;
+
+ istat->name = strdup(name);
+ if (istat->name == NULL) {
+ free(istat);
+ return NULL;
+ }
+
+ list_add_tail(&istat->list, head);
+ return istat;
+}
+
/**
* hist_entry__get_data_type - find data type for given hist entry
* @he: hist entry
@@ -3646,6 +3672,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
struct annotated_insn_loc loc;
struct annotated_op_loc *op_loc;
struct annotated_data_type *mem_type;
+ struct annotated_item_stat *istat;
u64 ip = he->ip;
int i;

@@ -3674,8 +3701,15 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
return NULL;
}

+ istat = annotate_data_stat(&ann_insn_stat, dl->ins.name);
+ if (istat == NULL) {
+ ann_data_stat.no_insn++;
+ return NULL;
+ }
+
if (annotate_get_insn_location(arch, dl, &loc) < 0) {
ann_data_stat.no_insn_ops++;
+ istat->bad++;
return NULL;
}

@@ -3684,6 +3718,10 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
continue;

mem_type = find_data_type(ms, ip, op_loc->reg, op_loc->offset);
+ if (mem_type)
+ istat->good++;
+ else
+ istat->bad++;

if (symbol_conf.annotate_data_sample) {
annotated_data_type__update_samples(mem_type, evsel,
@@ -3696,5 +3734,6 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
}

ann_data_stat.no_mem_ops++;
+ istat->bad++;
return NULL;
}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 299b4a18e804..5bb831445cbe 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -477,4 +477,12 @@ int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl,
/* Returns a data type from the sample instruction (if any) */
struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he);

+struct annotated_item_stat {
+ struct list_head list;
+ char *name;
+ int good;
+ int bad;
+};
+extern struct list_head ann_insn_stat;
+
#endif /* __PERF_ANNOTATE_H */
--
2.42.0.655.g421f12c284-goog