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.
new() -> Result<Box<dyn ProfilingAgent>>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 {
register_function(&self, name: &str, code: &[u8])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