From: vandersonmr <vandersonmr2@gmail.com>
To: qemu-devel@nongnu.org
Cc: Paolo Bonzini <pbonzini@redhat.com>,
Riku Voipio <riku.voipio@iki.fi>,
vandersonmr <vandersonmr2@gmail.com>,
Laurent Vivier <laurent@vivier.eu>,
Richard Henderson <rth@twiddle.net>
Subject: [Qemu-devel] [PATCH v1 1/2] accel/tcg: adding integration with linux perf
Date: Wed, 14 Aug 2019 23:37:24 -0300 [thread overview]
Message-ID: <20190815023725.2659-2-vandersonmr2@gmail.com> (raw)
In-Reply-To: <20190815023725.2659-1-vandersonmr2@gmail.com>
This commit adds support to Linux Perf in order
to be able to analyze qemu jitted code and
also to able to see the TBs PC in it.
Signed-off-by: Vanderson M. do Rosario <vandersonmr2@gmail.com>
---
accel/tcg/Makefile.objs | 1 +
accel/tcg/perf/Makefile.objs | 1 +
accel/tcg/perf/jitdump.c | 180 +++++++++++++++++++++++++++++++++++
accel/tcg/perf/jitdump.h | 19 ++++
accel/tcg/translate-all.c | 12 +++
include/qemu-common.h | 3 +
linux-user/main.c | 7 ++
qemu-options.hx | 12 +++
8 files changed, 235 insertions(+)
create mode 100644 accel/tcg/perf/Makefile.objs
create mode 100644 accel/tcg/perf/jitdump.c
create mode 100644 accel/tcg/perf/jitdump.h
diff --git a/accel/tcg/Makefile.objs b/accel/tcg/Makefile.objs
index d381a02f34..f393a7438f 100644
--- a/accel/tcg/Makefile.objs
+++ b/accel/tcg/Makefile.objs
@@ -3,6 +3,7 @@ obj-$(CONFIG_SOFTMMU) += cputlb.o
obj-y += tcg-runtime.o tcg-runtime-gvec.o
obj-y += cpu-exec.o cpu-exec-common.o translate-all.o
obj-y += translator.o
+obj-y += perf/
obj-$(CONFIG_USER_ONLY) += user-exec.o
obj-$(call lnot,$(CONFIG_SOFTMMU)) += user-exec-stub.o
diff --git a/accel/tcg/perf/Makefile.objs b/accel/tcg/perf/Makefile.objs
new file mode 100644
index 0000000000..f82fba35e5
--- /dev/null
+++ b/accel/tcg/perf/Makefile.objs
@@ -0,0 +1 @@
+obj-y += jitdump.o
diff --git a/accel/tcg/perf/jitdump.c b/accel/tcg/perf/jitdump.c
new file mode 100644
index 0000000000..6f4c0911c2
--- /dev/null
+++ b/accel/tcg/perf/jitdump.c
@@ -0,0 +1,180 @@
+#ifdef __linux__
+
+#include <stdint.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/syscall.h>
+#include <elf.h>
+
+#include "jitdump.h"
+#include "qemu-common.h"
+
+struct jitheader {
+ uint32_t magic; /* characters "jItD" */
+ uint32_t version; /* header version */
+ uint32_t total_size;/* total size of header */
+ uint32_t elf_mach; /* elf mach target */
+ uint32_t pad1; /* reserved */
+ uint32_t pid; /* JIT process id */
+ uint64_t timestamp; /* timestamp */
+ uint64_t flags; /* flags */
+};
+
+enum jit_record_type {
+ JIT_CODE_LOAD = 0,
+ JIT_CODE_MOVE = 1,
+ JIT_CODE_DEBUG_INFO = 2,
+ JIT_CODE_CLOSE = 3,
+
+ JIT_CODE_MAX,
+};
+
+/* record prefix (mandatory in each record) */
+struct jr_prefix {
+ uint32_t id;
+ uint32_t total_size;
+ uint64_t timestamp;
+};
+
+struct jr_code_load {
+ struct jr_prefix p;
+
+ uint32_t pid;
+ uint32_t tid;
+ uint64_t vma;
+ uint64_t code_addr;
+ uint64_t code_size;
+ uint64_t code_index;
+};
+
+struct jr_code_close {
+ struct jr_prefix p;
+};
+
+struct jr_code_move {
+ struct jr_prefix p;
+
+ uint32_t pid;
+ uint32_t tid;
+ uint64_t vma;
+ uint64_t old_code_addr;
+ uint64_t new_code_addr;
+ uint64_t code_size;
+ uint64_t code_index;
+};
+
+FILE *dumpfile;
+void *perf_marker;
+
+static uint64_t get_timestamp(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
+ fprintf(stderr, "No support for CLOCK_MONOTONIC! -perf cannot be used!\n");
+ exit(1);
+ }
+ return (uint64_t) ts.tv_sec * 1000000000 + ts.tv_nsec;
+}
+
+static uint32_t get_e_machine(void)
+{
+ uint32_t e_machine = EM_NONE;
+ Elf64_Ehdr elf_header;
+ FILE *exe = fopen("/proc/self/exe", "r");
+
+ if (exe == NULL) {
+ return e_machine;
+ }
+
+ if (fread(&elf_header, sizeof(Elf64_Ehdr), 1, exe) != 1) {
+ goto end;
+ }
+
+ e_machine = elf_header.e_machine;
+
+end:
+ fclose(exe);
+ return e_machine;
+}
+
+void start_jitdump_file(void)
+{
+ GString *dumpfile_name = g_string_new(NULL);;
+ g_string_printf(dumpfile_name, "./jit-%d.dump", getpid());
+ dumpfile = fopen(dumpfile_name->str, "w+");
+
+ perf_marker = mmap(NULL, sysconf(_SC_PAGESIZE),
+ PROT_READ | PROT_EXEC,
+ MAP_PRIVATE,
+ fileno(dumpfile), 0);
+
+ if (perf_marker == MAP_FAILED) {
+ printf("Failed to create mmap marker file for perf %d\n", fileno(dumpfile));
+ fclose(dumpfile);
+ return;
+ }
+
+ g_string_free(dumpfile_name, TRUE);
+
+ struct jitheader *header = g_new0(struct jitheader, 1);
+ header->magic = 0x4A695444;
+ header->version = 1;
+ header->elf_mach = get_e_machine();
+ header->total_size = sizeof(struct jitheader);
+ header->pid = getpid();
+ header->timestamp = get_timestamp();
+
+ fwrite(header, header->total_size, 1, dumpfile);
+
+ free(header);
+ fflush(dumpfile);
+}
+
+void append_load_in_jitdump_file(TranslationBlock *tb)
+{
+ GString *func_name = g_string_new(NULL);
+ g_string_printf(func_name, "TB virt:0x"TARGET_FMT_lx"%c", tb->pc, '\0');
+
+ struct jr_code_load *load_event = g_new0(struct jr_code_load, 1);
+ load_event->p.id = JIT_CODE_LOAD;
+ load_event->p.total_size = sizeof(struct jr_code_load) + func_name->len + tb->tc.size;
+ load_event->p.timestamp = get_timestamp();
+ load_event->pid = getpid();
+ load_event->tid = syscall(SYS_gettid);
+ load_event->vma = tb->pc;
+ load_event->code_addr = (uint64_t) tb->tc.ptr;
+ load_event->code_size = tb->tc.size;
+ load_event->code_index = tb->pc;
+
+ fwrite(load_event, sizeof(struct jr_code_load), 1, dumpfile);
+ fwrite(func_name->str, func_name->len, 1, dumpfile);
+ fwrite(tb->tc.ptr, tb->tc.size, 1, dumpfile);
+
+ g_string_free(func_name, TRUE);
+ free(load_event);
+ fflush(dumpfile);
+}
+
+void close_jitdump_file(void)
+{
+ fclose(dumpfile);
+ if (perf_marker != MAP_FAILED) {
+ munmap(perf_marker, sysconf(_SC_PAGESIZE));
+ }
+}
+
+bool is_jitdump_enabled;
+
+void jitdump_enable(void)
+{
+ is_jitdump_enabled = true;
+}
+
+bool jitdump_enabled(void)
+{
+ return is_jitdump_enabled;
+}
+
+#endif
diff --git a/accel/tcg/perf/jitdump.h b/accel/tcg/perf/jitdump.h
new file mode 100644
index 0000000000..12c0991b04
--- /dev/null
+++ b/accel/tcg/perf/jitdump.h
@@ -0,0 +1,19 @@
+#ifdef __linux__
+#ifndef JITDUMP_H
+#define JITDUMP_H
+
+#include "qemu/osdep.h"
+
+#include "disas/disas.h"
+#include "exec/exec-all.h"
+
+void start_jitdump_file(void);
+
+void append_load_in_jitdump_file(TranslationBlock *tb);
+void append_move_in_jitdump_file(TranslationBlock *tb);
+
+void close_jitdump_file(void);
+
+#endif
+
+#endif
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 5d1e08b169..0a4211d3d2 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -58,6 +58,8 @@
#include "sysemu/cpus.h"
#include "sysemu/tcg.h"
+#include "perf/jitdump.h"
+
/* #define DEBUG_TB_INVALIDATE */
/* #define DEBUG_TB_FLUSH */
/* make various TB consistency checks */
@@ -1148,6 +1150,11 @@ void tcg_exec_init(unsigned long tb_size)
cpu_gen_init();
page_init();
tb_htable_init();
+#ifdef __linux__
+ if (jitdump_enabled()) {
+ start_jitdump_file();
+ }
+#endif
code_gen_alloc(tb_size);
#if defined(CONFIG_SOFTMMU)
/* There's no guest base to take into account, so go ahead and
@@ -1877,6 +1884,11 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
return existing_tb;
}
tcg_tb_insert(tb);
+#ifdef __linux__
+ if (jitdump_enabled()) {
+ append_load_in_jitdump_file(tb);
+ }
+#endif
return tb;
}
diff --git a/include/qemu-common.h b/include/qemu-common.h
index 0235cd3b91..bd564a9e5c 100644
--- a/include/qemu-common.h
+++ b/include/qemu-common.h
@@ -130,4 +130,7 @@ void page_size_init(void);
* returned. */
bool dump_in_progress(void);
+void jitdump_enable(void);
+bool jitdump_enabled(void);
+
#endif
diff --git a/linux-user/main.c b/linux-user/main.c
index 8ffc525195..6521cf0c68 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -378,6 +378,11 @@ static void handle_arg_strace(const char *arg)
do_strace = 1;
}
+static void handle_arg_perf(const char *arg)
+{
+ jitdump_enable();
+}
+
static void handle_arg_version(const char *arg)
{
printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION
@@ -443,6 +448,8 @@ static const struct qemu_argument arg_table[] = {
"", "Seed for pseudo-random number generator"},
{"trace", "QEMU_TRACE", true, handle_arg_trace,
"", "[[enable=]<pattern>][,events=<file>][,file=<file>]"},
+ {"perf", "QEMU_PERF", false, handle_arg_perf,
+ "", "dump jitdump files to help linux perf JIT code visualization"},
{"version", "QEMU_VERSION", false, handle_arg_version,
"", "display version information and exit"},
{NULL, NULL, false, NULL, NULL, NULL}
diff --git a/qemu-options.hx b/qemu-options.hx
index 9621e934c0..1c26eeeb9c 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4147,6 +4147,18 @@ STEXI
Enable FIPS 140-2 compliance mode.
ETEXI
+#ifdef __linux__
+DEF("perf", 0, QEMU_OPTION_perf,
+ "-perf dump jitdump files to help linux perf JIT code visualization\n",
+ QEMU_ARCH_ALL)
+#endif
+STEXI
+@item -perf
+@findex -perf
+Dumps jitdump files to help linux perf JIT code visualization
+ETEXI
+
+
HXCOMM Deprecated by -machine accel=tcg property
DEF("no-kvm", 0, QEMU_OPTION_no_kvm, "", QEMU_ARCH_I386)
--
2.22.0
next prev parent reply other threads:[~2019-08-15 3:00 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-08-15 2:37 [Qemu-devel] [PATCH v1 0/2] Integrating qemu to Linux Perf vandersonmr
2019-08-15 2:37 ` vandersonmr [this message]
2019-08-15 14:40 ` [Qemu-devel] [PATCH v1 1/2] accel/tcg: adding integration with linux perf Stefan Hajnoczi
2019-08-15 16:17 ` Alex Bennée
2019-08-22 14:41 ` Stefan Hajnoczi
2019-08-21 19:01 ` Vanderson Martins do Rosario
2019-08-22 14:44 ` Stefan Hajnoczi
2019-08-15 2:37 ` [Qemu-devel] [PATCH v1 2/2] tb-stats: adding TBStatistics info into perf dump vandersonmr
2019-08-15 16:19 ` Alex Bennée
2019-08-15 9:14 ` [Qemu-devel] [PATCH v1 0/2] Integrating qemu to Linux Perf no-reply
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=20190815023725.2659-2-vandersonmr2@gmail.com \
--to=vandersonmr2@gmail.com \
--cc=laurent@vivier.eu \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=riku.voipio@iki.fi \
--cc=rth@twiddle.net \
/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.