From: Andi Kleen <ak@linux.intel.com>
To: linux-perf-users@vger.kernel.org
Cc: changbin.du@huawei.com, adrian.hunter@intel.com,
Andi Kleen <ak@linux.intel.com>
Subject: [PATCH 2/2] perf, capstone: Support capstone for -F +brstackinsn
Date: Tue, 27 Feb 2024 15:48:05 -0800 [thread overview]
Message-ID: <20240227234806.82694-2-ak@linux.intel.com> (raw)
In-Reply-To: <20240227234806.82694-1-ak@linux.intel.com>
Support capstone output for the -F +brstackinsn branch dump.
It is only enabled when -F +disasm is specified.
This was possible before with --xed, but now also allow
it for users that don't have xed using the builtin capstone support.
Before:
perf record -b emacs -Q --batch '()'
perf script -F +brstackinsn
...
emacs 55778 1814366.755945: 151564 cycles:P: 7f0ab2d17192 intel_check_word.constprop.0+0x162 (/usr/lib64/ld-linux-x86-64.s> intel_check_word.constprop.0+237:
00007f0ab2d1711d insn: 75 e6 # PRED 3 cycles [3]
00007f0ab2d17105 insn: 73 51
00007f0ab2d17107 insn: 48 89 c1
00007f0ab2d1710a insn: 48 39 ca
00007f0ab2d1710d insn: 73 96
00007f0ab2d1710f insn: 48 8d 04 11
00007f0ab2d17113 insn: 48 d1 e8
00007f0ab2d17116 insn: 49 8d 34 c1
00007f0ab2d1711a insn: 44 3a 06
00007f0ab2d1711d insn: 75 e6 # PRED 3 cycles [6] 3.00 IPC
00007f0ab2d17105 insn: 73 51 # PRED 1 cycles [7] 1.00 IPC
00007f0ab2d17158 insn: 48 8d 50 01
00007f0ab2d1715c insn: eb 92 # PRED 1 cycles [8] 2.00 IPC
00007f0ab2d170f0 insn: 48 39 ca
00007f0ab2d170f3 insn: 73 b0 # PRED 1 cycles [9] 2.00 IPC
After (perf must be compiled with capstone):
perf script -F +brstackinsn,+disasm
...
emacs 55778 1814366.755945: 151564 cycles:P: 7f0ab2d17192 intel_check_word.constprop.0+0x162 (/usr/lib64/ld-linux-x86-64.s> intel_check_word.constprop.0+237:
00007f0ab2d1711d jne intel_check_word.constprop.0+0xd5 # PRED 3 cycles [3]
00007f0ab2d17105 jae intel_check_word.constprop.0+0x128
00007f0ab2d17107 movq %rax, %rcx
00007f0ab2d1710a cmpq %rcx, %rdx
00007f0ab2d1710d jae intel_check_word.constprop.0+0x75
00007f0ab2d1710f leaq (%rcx, %rdx), %rax
00007f0ab2d17113 shrq $1, %rax
00007f0ab2d17116 leaq (%r9, %rax, 8), %rsi
00007f0ab2d1711a cmpb (%rsi), %r8b
00007f0ab2d1711d jne intel_check_word.constprop.0+0xd5 # PRED 3 cycles [6] 3.00 IPC
00007f0ab2d17105 jae intel_check_word.constprop.0+0x128 # PRED 1 cycles [7] 1.00 IPC
00007f0ab2d17158 leaq 1(%rax), %rdx
00007f0ab2d1715c jmp intel_check_word.constprop.0+0xc0 # PRED 1 cycles [8] 2.00 IPC
00007f0ab2d170f0 cmpq %rcx, %rdx
00007f0ab2d170f3 jae intel_check_word.constprop.0+0x75 # PRED 1 cycles [9] 2.00 IPC
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
tools/perf/builtin-script.c | 23 +++++++++++++---
tools/perf/util/dump-insn.h | 1 +
tools/perf/util/print_insn.c | 52 ++++++++++++++++++++++++++++++++++++
tools/perf/util/print_insn.h | 3 +++
4 files changed, 75 insertions(+), 4 deletions(-)
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 37088cc0ff1b..f18bcf61be8b 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1162,6 +1162,20 @@ static int print_srccode(struct thread *thread, u8 cpumode, uint64_t addr)
return ret;
}
+static const char *any_dump_insn(struct perf_event_attr *attr,
+ struct perf_insn *x, uint64_t ip,
+ u8 *inbuf, int inlen, int *lenp)
+{
+#ifdef HAVE_LIBCAPSTONE_SUPPORT
+ if (PRINT_FIELD(DISASM)) {
+ const char *p = cs_dump_insn(x, ip, inbuf, inlen, lenp);
+ if (p)
+ return p;
+ }
+#endif
+ return dump_insn(x, ip, inbuf, inlen, lenp);
+}
+
static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,
struct perf_insn *x, u8 *inbuf, int len,
int insn, FILE *fp, int *total_cycles,
@@ -1170,7 +1184,7 @@ static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,
{
int ilen = 0;
int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t", ip,
- dump_insn(x, ip, inbuf, len, &ilen));
+ any_dump_insn(attr, x, ip, inbuf, len, &ilen));
if (PRINT_FIELD(BRSTACKINSNLEN))
printed += fprintf(fp, "ilen: %d\t", ilen);
@@ -1262,6 +1276,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
nr = max_blocks + 1;
x.thread = thread;
+ x.machine = machine;
x.cpu = sample->cpu;
printed += fprintf(fp, "%c", '\n');
@@ -1313,7 +1328,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
} else {
ilen = 0;
printed += fprintf(fp, "\t%016" PRIx64 "\t%s", ip,
- dump_insn(&x, ip, buffer + off, len - off, &ilen));
+ any_dump_insn(attr, &x, ip, buffer + off, len - off, &ilen));
if (PRINT_FIELD(BRSTACKINSNLEN))
printed += fprintf(fp, "\tilen: %d", ilen);
printed += fprintf(fp, "\n");
@@ -1361,7 +1376,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
goto out;
ilen = 0;
printed += fprintf(fp, "\t%016" PRIx64 "\t%s", sample->ip,
- dump_insn(&x, sample->ip, buffer, len, &ilen));
+ any_dump_insn(attr, &x, sample->ip, buffer, len, &ilen));
if (PRINT_FIELD(BRSTACKINSNLEN))
printed += fprintf(fp, "\tilen: %d", ilen);
printed += fprintf(fp, "\n");
@@ -1372,7 +1387,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
for (off = 0; off <= end - start; off += ilen) {
ilen = 0;
printed += fprintf(fp, "\t%016" PRIx64 "\t%s", start + off,
- dump_insn(&x, start + off, buffer + off, len - off, &ilen));
+ any_dump_insn(attr, &x, start + off, buffer + off, len - off, &ilen));
if (PRINT_FIELD(BRSTACKINSNLEN))
printed += fprintf(fp, "\tilen: %d", ilen);
printed += fprintf(fp, "\n");
diff --git a/tools/perf/util/dump-insn.h b/tools/perf/util/dump-insn.h
index 650125061530..4a7797dd6d09 100644
--- a/tools/perf/util/dump-insn.h
+++ b/tools/perf/util/dump-insn.h
@@ -11,6 +11,7 @@ struct thread;
struct perf_insn {
/* Initialized by callers: */
struct thread *thread;
+ struct machine *machine;
u8 cpumode;
bool is64bit;
int cpu;
diff --git a/tools/perf/util/print_insn.c b/tools/perf/util/print_insn.c
index bd7a95e64ce5..35785ab22c07 100644
--- a/tools/perf/util/print_insn.c
+++ b/tools/perf/util/print_insn.c
@@ -12,6 +12,7 @@
#include "machine.h"
#include "thread.h"
#include "print_insn.h"
+#include "dump-insn.h"
#include "map.h"
#include "dso.h"
@@ -71,6 +72,57 @@ static int capstone_init(struct machine *machine, csh *cs_handle, bool is64)
return 0;
}
+static void dump_insn_x86(struct thread *thread, cs_insn *insn, struct perf_insn *x)
+{
+ struct addr_location al;
+ bool printed = false;
+
+ if (insn->detail && insn->detail->x86.op_count == 1) {
+ cs_x86_op *op = &insn->detail->x86.operands[0];
+
+ addr_location__init(&al);
+ if (op->type == X86_OP_IMM &&
+ thread__find_symbol(thread, x->cpumode, op->imm, &al) &&
+ al.sym &&
+ al.addr < al.sym->end) {
+ snprintf(x->out, sizeof(x->out), "%s %s+%#" PRIx64 " [%#" PRIx64 "]", insn[0].mnemonic,
+ al.sym->name, al.addr - al.sym->start, op->imm);
+ printed = true;
+ }
+ addr_location__exit(&al);
+ }
+
+ if (!printed)
+ snprintf(x->out, sizeof(x->out), "%s %s", insn[0].mnemonic, insn[0].op_str);
+}
+
+const char *cs_dump_insn(struct perf_insn *x, uint64_t ip,
+ u8 *inbuf, int inlen, int *lenp)
+{
+ int ret;
+ int count;
+ cs_insn *insn;
+ csh cs_handle;
+
+ ret = capstone_init(x->machine, &cs_handle, x->is64bit);
+ if (ret < 0)
+ return NULL;
+
+ count = cs_disasm(cs_handle, (uint8_t *)inbuf, inlen, ip, 1, &insn);
+ if (count > 0) {
+ if (machine__normalized_is(x->machine, "x86"))
+ dump_insn_x86(x->thread, &insn[0], x);
+ else
+ snprintf(x->out, sizeof(x->out), "%s %s",
+ insn[0].mnemonic, insn[0].op_str);
+ *lenp = insn->size;
+ cs_free(insn, count);
+ } else {
+ return NULL;
+ }
+ return x->out;
+}
+
static size_t print_insn_x86(struct perf_sample *sample, struct thread *thread,
cs_insn *insn, FILE *fp)
{
diff --git a/tools/perf/util/print_insn.h b/tools/perf/util/print_insn.h
index 465bdcfcc2fd..135d78322f71 100644
--- a/tools/perf/util/print_insn.h
+++ b/tools/perf/util/print_insn.h
@@ -8,9 +8,12 @@
struct perf_sample;
struct thread;
struct machine;
+struct perf_insn;
size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread *thread,
struct machine *machine, FILE *fp);
size_t sample__fprintf_insn_raw(struct perf_sample *sample, FILE *fp);
+const char *cs_dump_insn(struct perf_insn *x, uint64_t ip,
+ u8 *inbuf, int inlen, int *lenp);
#endif /* PERF_PRINT_INSN_H */
--
2.43.0
next prev parent reply other threads:[~2024-02-27 23:48 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-27 23:48 [PATCH 1/2] perf, capstone: Support 32bit code under 64bit OS Andi Kleen
2024-02-27 23:48 ` Andi Kleen [this message]
2024-02-28 11:05 ` [PATCH 2/2] perf, capstone: Support capstone for -F +brstackinsn Changbin Du
2024-02-28 23:26 ` Andi Kleen
2024-02-28 11:00 ` [PATCH 1/2] perf, capstone: Support 32bit code under 64bit OS Changbin Du
2024-02-28 23:29 ` Andi Kleen
2024-02-28 11:42 ` Adrian Hunter
2024-02-28 23:30 ` Andi Kleen
2024-02-29 7:02 ` Adrian Hunter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240227234806.82694-2-ak@linux.intel.com \
--to=ak@linux.intel.com \
--cc=adrian.hunter@intel.com \
--cc=changbin.du@huawei.com \
--cc=linux-perf-users@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.