@@ -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+
19282105static void
19292106no_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
47804958void
0 commit comments