1 #[allow(unused)] 2 use anyhow::{bail, Result}; 3 4 cfg_if::cfg_if! { 5 if #[cfg(all(feature = "profiling", target_os = "linux"))] { 6 mod jitdump; 7 pub use jitdump::new as new_jitdump; 8 } else { 9 pub fn new_jitdump() -> Result<Box<dyn ProfilingAgent>> { 10 if cfg!(feature = "profiling") { 11 bail!("jitdump is not supported on this platform"); 12 } else { 13 bail!("jitdump support disabled at compile time"); 14 } 15 } 16 } 17 } 18 19 cfg_if::cfg_if! { 20 if #[cfg(unix)] { 21 mod perfmap; 22 pub use perfmap::new as new_perfmap; 23 } else { 24 pub fn new_perfmap() -> Result<Box<dyn ProfilingAgent>> { 25 bail!("perfmap support not supported on this platform"); 26 } 27 } 28 } 29 30 cfg_if::cfg_if! { 31 // Note: VTune support is disabled on windows mingw because the ittapi crate doesn't compile 32 // there; see also https://github.com/bytecodealliance/wasmtime/pull/4003 for rationale. 33 if #[cfg(all(feature = "profiling", target_arch = "x86_64", not(any(target_os = "android", all(target_os = "windows", target_env = "gnu")))))] { 34 mod vtune; 35 pub use vtune::new as new_vtune; 36 } else { 37 pub fn new_vtune() -> Result<Box<dyn ProfilingAgent>> { 38 if cfg!(feature = "profiling") { 39 bail!("VTune is not supported on this platform."); 40 } else { 41 bail!("VTune support disabled at compile time."); 42 } 43 } 44 } 45 } 46 47 /// Common interface for profiling tools. 48 pub trait ProfilingAgent: Send + Sync + 'static { 49 fn register_function(&self, name: &str, addr: *const u8, size: usize); 50 51 fn register_module(&self, code: &[u8], custom_name: &dyn Fn(usize) -> Option<String>) { 52 use object::{File, Object as _, ObjectSection, ObjectSymbol, SectionKind, SymbolKind}; 53 54 let image = match File::parse(code) { 55 Ok(image) => image, 56 Err(_) => return, 57 }; 58 59 let text_base = match image.sections().find(|s| s.kind() == SectionKind::Text) { 60 Some(section) => match section.data() { 61 Ok(data) => data.as_ptr() as usize, 62 Err(_) => return, 63 }, 64 None => return, 65 }; 66 67 for sym in image.symbols() { 68 if !sym.is_definition() { 69 continue; 70 } 71 if sym.kind() != SymbolKind::Text { 72 continue; 73 } 74 let address = sym.address(); 75 let size = sym.size(); 76 if size == 0 { 77 continue; 78 } 79 if let Ok(name) = sym.name() { 80 let addr = text_base + address as usize; 81 let owned; 82 let name = match custom_name(address as usize) { 83 Some(name) => { 84 owned = name; 85 &owned 86 } 87 None => name, 88 }; 89 self.register_function(name, addr as *const u8, size as usize); 90 } 91 } 92 } 93 } 94 95 pub fn new_null() -> Box<dyn ProfilingAgent> { 96 Box::new(NullProfilerAgent) 97 } 98 99 #[derive(Debug, Default, Clone, Copy)] 100 struct NullProfilerAgent; 101 102 impl ProfilingAgent for NullProfilerAgent { 103 fn register_function(&self, _name: &str, _addr: *const u8, _size: usize) {} 104 fn register_module(&self, _code: &[u8], _custom_name: &dyn Fn(usize) -> Option<String>) {} 105 } 106