1 //! Support for jitdump files which can be used by perf for profiling jitted code. 2 //! Spec definitions for the output format is as described here: 3 //! <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jitdump-specification.txt> 4 //! 5 //! Usage Example: 6 //! Record 7 //! sudo perf record -k 1 -e instructions:u target/debug/wasmtime -g --profile=jitdump test.wasm 8 //! Combine 9 //! sudo perf inject -v -j -i perf.data -o perf.jit.data 10 //! Report 11 //! sudo perf report -i perf.jit.data -F+period,srcline 12 //! Note: For descriptive results, the WASM file being executed should contain dwarf debug data 13 14 use crate::prelude::*; 15 use crate::profiling_agent::ProfilingAgent; 16 use object::elf; 17 use std::process; 18 use std::sync::Mutex; 19 use target_lexicon::Architecture; 20 use wasmtime_jit_debug::perf_jitdump::*; 21 22 /// Interface for driving the creation of jitdump files 23 struct JitDumpAgent { 24 pid: u32, 25 } 26 27 /// Process-wide JIT dump file. Perf only accepts a unique file per process, in the injection step. 28 static JITDUMP_FILE: Mutex<Option<JitDumpFile>> = Mutex::new(None); 29 30 /// Initialize a JitDumpAgent and write out the header. 31 pub fn new() -> Result<Box<dyn ProfilingAgent>> { 32 let mut jitdump_file = JITDUMP_FILE.lock().unwrap(); 33 34 if jitdump_file.is_none() { 35 let filename = format!("./jit-{}.dump", process::id()); 36 let e_machine = match target_lexicon::HOST.architecture { 37 Architecture::X86_64 => elf::EM_X86_64 as u32, 38 Architecture::X86_32(_) => elf::EM_386 as u32, 39 Architecture::Arm(_) => elf::EM_ARM as u32, 40 Architecture::Aarch64(_) => elf::EM_AARCH64 as u32, 41 Architecture::S390x => elf::EM_S390 as u32, 42 _ => unimplemented!("unrecognized architecture"), 43 }; 44 *jitdump_file = Some(JitDumpFile::new(filename, e_machine)?); 45 } 46 47 Ok(Box::new(JitDumpAgent { 48 pid: std::process::id(), 49 })) 50 } 51 52 impl ProfilingAgent for JitDumpAgent { 53 fn register_function(&self, name: &str, code: &[u8]) { 54 let mut jitdump_file = JITDUMP_FILE.lock().unwrap(); 55 let jitdump_file = jitdump_file.as_mut().unwrap(); 56 let timestamp = jitdump_file.get_time_stamp(); 57 let tid = rustix::thread::gettid() 58 .as_raw_nonzero() 59 .get() 60 .cast_unsigned(); 61 if let Err(err) = jitdump_file.dump_code_load_record(&name, code, timestamp, self.pid, tid) 62 { 63 println!("Jitdump: write_code_load_failed_record failed: {err:?}\n"); 64 } 65 } 66 } 67