use super::profiler::{
CargoFlamegraphProfiler, DtraceProfiler, PerfProfiler, ProfileError, ProfileRequest,
ProfileResult, Profiler,
};
use std::process::Command;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DetectedProfiler {
Perf,
Dtrace,
CargoFlamegraph,
}
impl DetectedProfiler {
pub fn name(&self) -> &'static str {
match self {
DetectedProfiler::Perf => "perf + inferno",
DetectedProfiler::Dtrace => "dtrace + inferno",
DetectedProfiler::CargoFlamegraph => "cargo-flamegraph",
}
}
pub fn capture(&self, request: &ProfileRequest) -> Result<ProfileResult, ProfileError> {
match self {
DetectedProfiler::Perf => PerfProfiler.capture(request),
DetectedProfiler::Dtrace => DtraceProfiler.capture(request),
DetectedProfiler::CargoFlamegraph => CargoFlamegraphProfiler.capture(request),
}
}
}
pub fn detect_profiler() -> Option<DetectedProfiler> {
if cfg!(target_os = "linux") && is_command_available("perf") && has_inferno() {
return Some(DetectedProfiler::Perf);
}
if cfg!(target_os = "macos") && is_command_available("dtrace") && has_inferno() {
return Some(DetectedProfiler::Dtrace);
}
if is_command_available("cargo-flamegraph") || has_cargo_flamegraph_subcommand() {
return Some(DetectedProfiler::CargoFlamegraph);
}
None
}
fn is_command_available(name: &str) -> bool {
Command::new(name)
.arg("--version")
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.is_ok()
}
fn has_inferno() -> bool {
is_command_available("inferno-flamegraph")
}
fn has_cargo_flamegraph_subcommand() -> bool {
Command::new("cargo")
.args(["flamegraph", "--help"])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.is_ok_and(|s| s.success())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn detected_profiler_name_is_human_readable() {
assert_eq!(DetectedProfiler::Perf.name(), "perf + inferno");
assert_eq!(DetectedProfiler::Dtrace.name(), "dtrace + inferno");
assert_eq!(DetectedProfiler::CargoFlamegraph.name(), "cargo-flamegraph");
}
#[test]
fn is_command_available_returns_false_for_nonexistent() {
assert!(!is_command_available("perfgate-nonexistent-tool-xyz-12345"));
}
#[test]
fn detect_profiler_does_not_panic() {
let _result = detect_profiler();
}
#[test]
fn detected_profiler_variants_are_distinct() {
assert_ne!(DetectedProfiler::Perf, DetectedProfiler::Dtrace);
assert_ne!(DetectedProfiler::Perf, DetectedProfiler::CargoFlamegraph);
assert_ne!(DetectedProfiler::Dtrace, DetectedProfiler::CargoFlamegraph);
}
}