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