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(writer: &mut dyn Write, name: &str, code: &[u8]) -> io::Result<()> { 25 // Format is documented here: https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt 26 // Try our best to sanitize the name, since wasm allows for any utf8 string in there. 27 let sanitized_name = name.replace('\n', "_").replace('\r', "_"); 28 write!( 29 writer, 30 "{:p} {:x} {}\n", 31 code.as_ptr(), 32 code.len(), 33 sanitized_name 34 )?; 35 writer.flush()?; 36 Ok(()) 37 } 38 } 39 40 impl ProfilingAgent for PerfMapAgent { 41 fn register_function(&self, name: &str, code: &[u8]) { 42 let mut file = PERFMAP_FILE.lock().unwrap(); 43 let file = file.as_mut().unwrap(); 44 if let Err(err) = Self::make_line(file, name, code) { 45 eprintln!("Error when writing import trampoline info to the perf map file: {err}"); 46 } 47 } 48 } 49