Skip to content

Commit aa032a0

Browse files
Initial perf jitdump implementation (#33893)
Fixes mono/mono#17024 Co-authored-by: fanyang-mono <fanyang-mono@users.noreply.github.com>
1 parent c2466ee commit aa032a0

File tree

5 files changed

+198
-0
lines changed

5 files changed

+198
-0
lines changed

src/mono/configure.ac

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,12 @@ fi
755755
# for mono/metadata/debug-symfile.c
756756
AC_CHECK_HEADERS(elf.h)
757757

758+
# for perf jit dump support
759+
AC_CHECK_HEADERS(sys/mman.h)
760+
if test "x$host_linux" = "xyes" -a x$ac_cv_header_sys_mman_h = xyes -a x$ac_cv_header_elf_h = xyes -a x$ac_cv_header_sys_syscall_h = xyes; then
761+
AC_DEFINE(ENABLE_JIT_DUMP, 1, [Enable jit dump support on Linux])
762+
fi
763+
758764
# for support
759765
AC_CHECK_HEADERS(poll.h)
760766
AC_CHECK_HEADERS(sys/poll.h)

src/mono/mono/mini/driver.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1622,7 +1622,12 @@ mini_usage (void)
16221622
" --debugger-agent=options Enable the debugger agent\n"
16231623
" --profile[=profiler] Runs in profiling mode with the specified profiler module\n"
16241624
" --trace[=EXPR] Enable tracing, use --help-trace for details\n"
1625+
#ifdef __linux__
16251626
" --jitmap Output a jit method map to /tmp/perf-PID.map\n"
1627+
#endif
1628+
#ifdef ENABLE_JIT_DUMP
1629+
" --jitdump Output a jitdump file to /tmp/jit-PID.dump\n"
1630+
#endif
16261631
" --help-devel Shows more options available to developers\n"
16271632
"\n"
16281633
"Runtime:\n"
@@ -2342,6 +2347,10 @@ mono_main (int argc, char* argv[])
23422347
forced_version = &argv [i][10];
23432348
} else if (strcmp (argv [i], "--jitmap") == 0) {
23442349
mono_enable_jit_map ();
2350+
#ifdef ENABLE_JIT_DUMP
2351+
} else if (strcmp (argv [i], "--jitdump") == 0) {
2352+
mono_enable_jit_dump ();
2353+
#endif
23452354
} else if (strcmp (argv [i], "--profile") == 0) {
23462355
mini_add_profiler_argument (NULL);
23472356
} else if (strncmp (argv [i], "--profile=", 10) == 0) {

src/mono/mono/mini/mini-runtime.c

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,6 +1925,183 @@ mono_jit_map_is_enabled (void)
19251925

19261926
#endif
19271927

1928+
#ifdef ENABLE_JIT_DUMP
1929+
#include <sys/mman.h>
1930+
#include <sys/syscall.h>
1931+
#include <elf.h>
1932+
1933+
static FILE *perf_dump_file;
1934+
static mono_mutex_t perf_dump_mutex;
1935+
static void *perf_dump_mmap_addr = MAP_FAILED;
1936+
static guint32 perf_dump_pid;
1937+
1938+
enum {
1939+
JIT_DUMP_MAGIC = 0x4A695444,
1940+
JIT_DUMP_VERSION = 2,
1941+
#if HOST_X86
1942+
ELF_MACHINE = EM_386,
1943+
#elif HOST_AMD64
1944+
ELF_MACHINE = EM_X86_64,
1945+
#elif HOST_ARM
1946+
ELF_MACHINE = EM_ARM,
1947+
#elif HOST_ARM64
1948+
ELF_MACHINE = EM_AARCH64,
1949+
#endif
1950+
JIT_CODE_LOAD = 0
1951+
};
1952+
typedef struct
1953+
{
1954+
guint32 magic;
1955+
guint32 version;
1956+
guint32 total_size;
1957+
guint32 elf_mach;
1958+
guint32 pad1;
1959+
guint32 pid;
1960+
guint64 timestamp;
1961+
guint64 flags;
1962+
} FileHeader;
1963+
typedef struct
1964+
{
1965+
guint32 id;
1966+
guint32 total_size;
1967+
guint64 timestamp;
1968+
} RecordHeader;
1969+
typedef struct
1970+
{
1971+
RecordHeader header;
1972+
guint32 pid;
1973+
guint32 tid;
1974+
guint64 vma;
1975+
guint64 code_addr;
1976+
guint64 code_size;
1977+
guint64 code_index;
1978+
// Null terminated function name
1979+
// Native code
1980+
} JitCodeLoadRecord;
1981+
1982+
static void add_file_header_info (FileHeader *header);
1983+
static guint64 get_time_stamp_ns (void);
1984+
static void add_basic_JitCodeLoadRecord_info (JitCodeLoadRecord *record);
1985+
1986+
void
1987+
mono_enable_jit_dump (void)
1988+
{
1989+
if (perf_dump_pid == 0)
1990+
perf_dump_pid = getpid();
1991+
1992+
if (!perf_dump_file) {
1993+
char name [64];
1994+
FileHeader header;
1995+
memset (&header, 0, sizeof (header));
1996+
1997+
mono_os_mutex_init (&perf_dump_mutex);
1998+
mono_os_mutex_lock (&perf_dump_mutex);
1999+
2000+
g_snprintf (name, sizeof (name), "/tmp/jit-%d.dump", perf_dump_pid);
2001+
unlink (name);
2002+
perf_dump_file = fopen (name, "w");
2003+
2004+
add_file_header_info (&header);
2005+
if (perf_dump_file) {
2006+
fwrite (&header, sizeof (header), 1, perf_dump_file);
2007+
//This informs perf of the presence of the jitdump file and support for the feature.​
2008+
perf_dump_mmap_addr = mmap (NULL, sizeof (header), PROT_READ | PROT_EXEC, MAP_PRIVATE, fileno (perf_dump_file), 0);
2009+
}
2010+
2011+
mono_os_mutex_unlock (&perf_dump_mutex);
2012+
}
2013+
}
2014+
2015+
static void
2016+
add_file_header_info (FileHeader *header)
2017+
{
2018+
header->magic = JIT_DUMP_MAGIC;
2019+
header->version = JIT_DUMP_VERSION;
2020+
header->total_size = sizeof (header);
2021+
header->elf_mach = ELF_MACHINE;
2022+
header->pad1 = 0;
2023+
header->pid = perf_dump_pid;
2024+
header->timestamp = get_time_stamp_ns ();
2025+
header->flags = 0;
2026+
}
2027+
2028+
static guint64
2029+
get_time_stamp_ns (void)
2030+
{
2031+
struct timespec ts;
2032+
int result = clock_gettime (CLOCK_MONOTONIC, &ts);
2033+
return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
2034+
}
2035+
2036+
void
2037+
mono_emit_jit_dump (MonoJitInfo *jinfo, gpointer code)
2038+
{
2039+
static uint64_t code_index;
2040+
2041+
if (perf_dump_file) {
2042+
JitCodeLoadRecord record;
2043+
size_t nameLen = strlen (jinfo->d.method->name);
2044+
memset (&record, 0, sizeof (record));
2045+
2046+
add_basic_JitCodeLoadRecord_info (&record);
2047+
record.header.total_size = sizeof (record) + nameLen + 1 + jinfo->code_size;
2048+
record.vma = (guint64)jinfo->code_start;
2049+
record.code_addr = (guint64)jinfo->code_start;
2050+
record.code_size = (guint64)jinfo->code_size;
2051+
2052+
mono_os_mutex_lock (&perf_dump_mutex);
2053+
2054+
record.code_index = ++code_index;
2055+
2056+
// TODO: write debugInfo and unwindInfo immediately before the JitCodeLoadRecord (while lock is held).
2057+
2058+
record.header.timestamp = get_time_stamp_ns ();
2059+
2060+
fwrite (&record, sizeof (record), 1, perf_dump_file);
2061+
fwrite (jinfo->d.method->name, nameLen + 1, 1, perf_dump_file);
2062+
fwrite (code, jinfo->code_size, 1, perf_dump_file);
2063+
2064+
mono_os_mutex_unlock (&perf_dump_mutex);
2065+
}
2066+
}
2067+
2068+
static void
2069+
add_basic_JitCodeLoadRecord_info (JitCodeLoadRecord *record)
2070+
{
2071+
record->header.id = JIT_CODE_LOAD;
2072+
record->header.timestamp = get_time_stamp_ns ();
2073+
record->pid = perf_dump_pid;
2074+
record->tid = syscall (SYS_gettid);
2075+
}
2076+
2077+
void
2078+
mono_jit_dump_cleanup (void)
2079+
{
2080+
if (perf_dump_mmap_addr != MAP_FAILED)
2081+
munmap (perf_dump_mmap_addr, sizeof(FileHeader));
2082+
if (perf_dump_file)
2083+
fclose (perf_dump_file);
2084+
}
2085+
2086+
#else
2087+
2088+
void
2089+
mono_enable_jit_dump (void)
2090+
{
2091+
}
2092+
2093+
void
2094+
mono_emit_jit_dump (MonoJitInfo *jinfo, gpointer code)
2095+
{
2096+
}
2097+
2098+
void
2099+
mono_jit_dump_cleanup (void)
2100+
{
2101+
}
2102+
2103+
#endif
2104+
19282105
static void
19292106
no_gsharedvt_in_wrapper (void)
19302107
{
@@ -4775,6 +4952,7 @@ mini_cleanup (MonoDomain *domain)
47754952
g_printf ("Printing runtime stats at shutdown\n");
47764953
mono_runtime_print_stats ();
47774954
jit_stats_cleanup ();
4955+
mono_jit_dump_cleanup ();
47784956
}
47794957
#else
47804958
void

src/mono/mono/mini/mini-runtime.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,10 @@ gboolean mono_jit_map_is_enabled (void);
517517
#define mono_jit_map_is_enabled() (0)
518518
#endif
519519

520+
void mono_enable_jit_dump (void);
521+
void mono_emit_jit_dump (MonoJitInfo *jinfo, gpointer code);
522+
void mono_jit_dump_cleanup (void);
523+
520524
/*
521525
* Per-OS implementation functions.
522526
*/

src/mono/mono/mini/mini.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4171,6 +4171,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
41714171
mini_patch_llvm_jit_callees (target_domain, method, code);
41724172
#ifndef DISABLE_JIT
41734173
mono_emit_jit_map (jinfo);
4174+
mono_emit_jit_dump (jinfo, code);
41744175
#endif
41754176
mono_domain_unlock (target_domain);
41764177

0 commit comments

Comments
 (0)