wasmtime/profiling_agent/
jitdump.rs

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
14use crate::prelude::*;
15use crate::profiling_agent::ProfilingAgent;
16use object::elf;
17use std::process;
18use std::sync::Mutex;
19use target_lexicon::Architecture;
20use wasmtime_jit_debug::perf_jitdump::*;
21
22/// Interface for driving the creation of jitdump files
23struct JitDumpAgent {
24    pid: u32,
25}
26
27/// Process-wide JIT dump file. Perf only accepts a unique file per process, in the injection step.
28static JITDUMP_FILE: Mutex<Option<JitDumpFile>> = Mutex::new(None);
29
30/// Initialize a JitDumpAgent and write out the header.
31pub 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
52impl 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        #[allow(trivial_numeric_casts)]
58        let tid = rustix::thread::gettid().as_raw_nonzero().get() as u32;
59        if let Err(err) = jitdump_file.dump_code_load_record(&name, code, timestamp, self.pid, tid)
60        {
61            println!("Jitdump: write_code_load_failed_record failed: {err:?}\n");
62        }
63    }
64}