use crate::prelude::*;
use crate::profiling_agent::ProfilingAgent;
use std::fs::OpenOptions;
use std::io::{self, Write};
use std::process;
use std::{fs::File, sync::Mutex};
static PERFMAP_FILE: Mutex<Option<File>> = Mutex::new(None);
struct PerfMapAgent;
pub fn new() -> Result<Box<dyn ProfilingAgent>> {
let mut file = PERFMAP_FILE.lock().unwrap();
if file.is_none() {
let filename = format!("/tmp/perf-{}.map", process::id());
*file = Some(
OpenOptions::new()
.append(true)
.write(true)
.create(true)
.open(&filename)?,
);
}
Ok(Box::new(PerfMapAgent))
}
impl PerfMapAgent {
fn make_line(writer: &mut File, name: &str, code: &[u8]) -> io::Result<()> {
let sanitized_name = name.replace('\n', "_").replace('\r', "_");
let line = format!("{:p} {:x} {sanitized_name}\n", code.as_ptr(), code.len());
writer.write_all(line.as_bytes())?;
Ok(())
}
}
impl ProfilingAgent for PerfMapAgent {
fn register_function(&self, name: &str, code: &[u8]) {
let mut file = PERFMAP_FILE.lock().unwrap();
let file = file.as_mut().unwrap();
if let Err(err) = Self::make_line(file, name, code) {
eprintln!("Error when writing import trampoline info to the perf map file: {err}");
}
}
}