perf annotate-data: Handle macro fusion on x86
authorNamhyung Kim <namhyung@kernel.org>
Wed, 17 Jan 2024 06:26:50 +0000 (22:26 -0800)
committerNamhyung Kim <namhyung@kernel.org>
Mon, 22 Jan 2024 20:08:19 +0000 (12:08 -0800)
When a sample was come from a conditional branch without a memory
operand, it could be due to a macro fusion with a previous instruction.
So it needs to check the memory operand in the previous one.

This improves the stat like below:

  Annotate data type stats:
  total 294, ok 147 (50.0%), bad 147 (50.0%)
  -----------------------------------------------------------
          30 : no_sym
          32 : no_mem_ops
          71 : no_var
           6 : no_typeinfo
           8 : bad_offset

Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Link: https://lore.kernel.org/r/20240117062657.985479-3-namhyung@kernel.org
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/util/annotate.c

index 8d761be1a102fce0e20c7a1f216c20b9a04224dc..0ec42e85ca5c9032bbbd0a4355d4a395a840f1b9 100644 (file)
@@ -3751,6 +3751,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
                return NULL;
        }
 
+retry:
        istat = annotate_data_stat(&ann_insn_stat, dl->ins.name);
        if (istat == NULL) {
                ann_data_stat.no_insn++;
@@ -3767,7 +3768,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
                if (!op_loc->mem_ref)
                        continue;
 
-               /* Recalculate IP since it can be changed due to LOCK prefix */
+               /* Recalculate IP because of LOCK prefix or insn fusion */
                ip = ms->sym->start + dl->al.offset;
 
                mem_type = find_data_type(ms, ip, op_loc->reg, op_loc->offset);
@@ -3786,6 +3787,20 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
                return mem_type;
        }
 
+       /*
+        * Some instructions can be fused and the actual memory access came
+        * from the previous instruction.
+        */
+       if (dl->al.offset > 0) {
+               struct disasm_line *prev_dl;
+
+               prev_dl = list_prev_entry(dl, al.node);
+               if (ins__is_fused(arch, prev_dl->ins.name, dl->ins.name)) {
+                       dl = prev_dl;
+                       goto retry;
+               }
+       }
+
        ann_data_stat.no_mem_ops++;
        istat->bad++;
        return NULL;