Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DYNAREC] Implement perf map #2212

Merged
merged 2 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,11 @@ The GDBJIT debugging support, only available with the compilation option GDBJIT=
* 1 : Dynarec will generate GDBJIT debuginfo.
* 2 : Dynarec will generate detailed GDBJIT debuginfo with internal state.

#### BOX64_DYNAREC_PERFMAP *
Dynarec generate map file for Linux perf tool.
* 0 : Dynarec will not generate perf map. (Default)
* 1 : Dynarec will generate perf map.

#### BOX64_DYNAREC_MISSING *
Dynarec print the missing opcodes
* 0 : not print the missing opcode (Default, unless DYNAREC_LOG>=1 or DYNAREC_DUMP>=1 is used)
Expand Down
7 changes: 7 additions & 0 deletions docs/box64.pod
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,13 @@ The GDBJIT debugging support, only available with the compilation option GDBJIT=
* 1 : Dynarec will generate GDBJIT debuginfo.
* 2 : Dynarec will generate detailed GDBJIT debuginfo with internal state.

=item B<BOX64_DYNAREC_PERFMAP>=I<0|1>

Dynarec generate map file for Linux perf tool.

* 0 : Dynarec will not generate perf map. (Default)
* 1 : Dynarec will generate perf map.

=item B<BOX64_SSE_FLUSHTO0>=I<0|1>

Handling of SSE Flush to 0 flags
Expand Down
29 changes: 29 additions & 0 deletions src/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
#include <linux/auxvec.h>
#include <asm/hwcap.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif

#include "build_info.h"
Expand Down Expand Up @@ -99,6 +102,8 @@ uintptr_t box64_dynarec_test_start = 0;
uintptr_t box64_dynarec_test_end = 0;
int box64_dynarec_gdbjit = 0;
int box64_dynarec_df = 1;
int box64_dynarec_perf_map = 0;
int box64_dynarec_perf_map_fd = -1;
#ifdef ARM64
int arm64_asimd = 0;
int arm64_aes = 0;
Expand Down Expand Up @@ -912,6 +917,15 @@ void LoadLogEnv()
if (box64_dynarec_gdbjit)
printf_log(LOG_INFO, "Dynarec will generate debuginfo for gdbjit\n");
}
p = getenv("BOX64_DYNAREC_PERFMAP");
if (p) {
if (strlen(p) == 1) {
if (p[0] >= '0' && p[0] <= '1')
box64_dynarec_perf_map = p[0] - '0';
}
if (box64_dynarec_perf_map)
printf_log(LOG_INFO, "Dynarec will generate map file for Linux perf tool\n");
}
p = getenv("BOX64_DYNAREC_DF");
if(p) {
if(strlen(p)==1) {
Expand Down Expand Up @@ -2526,6 +2540,14 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf

*emulator = emu;

#ifdef DYNAREC
if (box64_dynarec_perf_map) {
char pathname[32];
snprintf(pathname, sizeof(pathname), "/tmp/perf-%d.map", getpid());
box64_dynarec_perf_map_fd = open(pathname, O_CREAT | O_RDWR | O_APPEND, S_IRUSR | S_IWUSR);
}
#endif

return 0;
}

Expand Down Expand Up @@ -2565,5 +2587,12 @@ int emulate(x64emu_t* emu, elfheader_t* elf_header)
}
#endif

#ifdef DYNAREC
if (box64_dynarec_perf_map && box64_dynarec_perf_map_fd != -1) {
close(box64_dynarec_perf_map_fd);
box64_dynarec_perf_map_fd = -1;
}
#endif

return ret;
}
5 changes: 4 additions & 1 deletion src/dynarec/arm64/dynarec_arm64_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,7 @@ static register_mapping_t register_mappings[] = {

void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex)
{
if (!box64_dynarec_dump && !box64_dynarec_gdbjit) return;
if (!box64_dynarec_dump && !box64_dynarec_gdbjit && !box64_dynarec_perf_map) return;

static char buf[512];
int length = sprintf(buf, "barrier=%d state=%d/%d/%d(%d:%d->%d:%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d)",
Expand Down Expand Up @@ -849,6 +849,9 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
}
dyn->gdbjit_block = GdbJITBlockAddLine(dyn->gdbjit_block, (dyn->native_start + dyn->insts[ninst].address), inst_name);
}
if (box64_dynarec_perf_map && box64_dynarec_perf_map_fd != -1) {
writePerfMap(dyn->insts[ninst].x64.addr, dyn->native_start + dyn->insts[ninst].address, dyn->insts[ninst].size / 4);
}
}

void print_opcode(dynarec_native_t* dyn, int ninst, uint32_t opcode)
Expand Down
10 changes: 10 additions & 0 deletions src/dynarec/dynarec_native.c
Original file line number Diff line number Diff line change
Expand Up @@ -841,3 +841,13 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
//block->done = 1;
return (void*)block;
}

void writePerfMap(uintptr_t func_addr, uintptr_t code_addr, size_t code_size)
{
char pbuf[128];
uint64_t sz = 0;
uintptr_t start = 0;
const char* symbname = FindNearestSymbolName(FindElfAddress(my_context, func_addr), (void*)func_addr, &start, &sz);
snprintf(pbuf, sizeof(pbuf), "0x%lx %ld %s\n", code_addr, code_size, symbname);
write(box64_dynarec_perf_map_fd, pbuf, strlen(pbuf));
}
8 changes: 6 additions & 2 deletions src/dynarec/la64/dynarec_la64_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "custommem.h"
#include "bridge.h"
#include "gdbjit.h"
#include "elfloader.h"

#define XMM0 0
#define XMM8 16
Expand Down Expand Up @@ -331,7 +332,7 @@ static register_mapping_t register_mappings[] = {

void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex)
{
if (!box64_dynarec_dump && !box64_dynarec_gdbjit) return;
if (!box64_dynarec_dump && !box64_dynarec_gdbjit && !box64_dynarec_perf_map) return;

static char buf[512];
int length = sprintf(buf, "barrier=%d state=%d/%d(%d), %s=%X/%X, use=%X, need=%X/%X, fuse=%d, sm=%d(%d/%d)",
Expand Down Expand Up @@ -397,6 +398,9 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
}
dyn->gdbjit_block = GdbJITBlockAddLine(dyn->gdbjit_block, (dyn->native_start + dyn->insts[ninst].address), inst_name);
}
if (box64_dynarec_perf_map && box64_dynarec_perf_map_fd != -1) {
writePerfMap(dyn->insts[ninst].x64.addr, dyn->native_start + dyn->insts[ninst].address, dyn->insts[ninst].size / 4);
}
}

// will go badly if address is unaligned
Expand Down Expand Up @@ -522,4 +526,4 @@ void get_free_scratch(dynarec_la64_t* dyn, int ninst, uint8_t* tmp1, uint8_t* tm
*tmp1 = tmp[0];
*tmp2 = tmp[1];
*tmp3 = tmp[2];
}
}
5 changes: 4 additions & 1 deletion src/dynarec/rv64/dynarec_rv64_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ static register_mapping_t register_mappings[] = {

void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex)
{
if (!box64_dynarec_dump && !box64_dynarec_gdbjit) return;
if (!box64_dynarec_dump && !box64_dynarec_gdbjit && !box64_dynarec_perf_map) return;

static char buf[512];
int length = sprintf(buf, "barrier=%d state=%d/%d(%d), %s=%X/%X, use=%X, need=%X/%X, fuse=%d, sm=%d(%d/%d), sew@entry=%d, sew@exit=%d",
Expand Down Expand Up @@ -772,6 +772,9 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
}
dyn->gdbjit_block = GdbJITBlockAddLine(dyn->gdbjit_block, (dyn->native_start + dyn->insts[ninst].address), inst_name);
}
if (box64_dynarec_perf_map && box64_dynarec_perf_map_fd != -1) {
writePerfMap(dyn->insts[ninst].x64.addr, dyn->native_start + dyn->insts[ninst].address, dyn->insts[ninst].size / 4);
}
}

void print_opcode(dynarec_native_t* dyn, int ninst, uint32_t opcode)
Expand Down
2 changes: 2 additions & 0 deletions src/include/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ extern int box64_dynarec_missing;
extern int box64_dynarec_aligned_atomics;
extern int box64_dynarec_nativeflags;
extern int box64_dynarec_df;
extern int box64_dynarec_perf_map;
extern int box64_dynarec_perf_map_fd;
#ifdef ARM64
extern int arm64_asimd;
extern int arm64_aes;
Expand Down
4 changes: 3 additions & 1 deletion src/include/dynarec_native.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@ void addInst(instsize_t* insts, size_t* size, int x64_size, int native_size);
void CancelBlock64(int need_lock);
void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bits);

#endif //__DYNAREC_ARM_H_
void writePerfMap(uintptr_t func_addr, uintptr_t code_addr, size_t code_size);

#endif //__DYNAREC_ARM_H_
Loading