1 use crate::prelude::*; 2 use crate::profiling_agent::ProfilingAgent; 3 use std::io::{self, BufWriter, Write}; 4 use std::process; 5 use std::{fs::File, sync::Mutex}; 6 7 /// Process-wide perf map file. Perf only reads a unique file per process. 8 static PERFMAP_FILE: Mutex<Option<BufWriter<File>>> = Mutex::new(None); 9 10 /// Interface for driving the creation of jitdump files 11 struct PerfMapAgent; 12 13 /// Initialize a JitDumpAgent and write out the header. 14 pub fn new() -> Result<Box<dyn ProfilingAgent>> { 15 let mut file = PERFMAP_FILE.lock().unwrap(); 16 if file.is_none() { 17 let filename = format!("/tmp/perf-{}.map", process::id()); 18 *file = Some(BufWriter::new(File::create(filename)?)); 19 } 20 Ok(Box::new(PerfMapAgent)) 21 } 22 23 impl PerfMapAgent { 24 fn make_line( 25 writer: &mut dyn Write, 26 name: &str, 27 addr: *const u8, 28 len: usize, 29 ) -> io::Result<()> { 30 // Format is documented here: https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt 31 // Try our best to sanitize the name, since wasm allows for any utf8 string in there. 32 let sanitized_name = name.replace('\n', "_").replace('\r', "_"); 33 write!(writer, "{:x} {:x} {}\n", addr as usize, len, sanitized_name)?; 34 writer.flush()?; 35 Ok(()) 36 } 37 } 38 39 impl ProfilingAgent for PerfMapAgent { 40 fn register_function(&self, name: &str, addr: *const u8, size: usize) { 41 let mut file = PERFMAP_FILE.lock().unwrap(); 42 let file = file.as_mut().unwrap(); 43 if let Err(err) = Self::make_line(file, name, addr, size) { 44 eprintln!("Error when writing import trampoline info to the perf map file: {err}"); 45 } 46 } 47 } 48