use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::{Mutex, OnceLock};
use super::{HwStamp, TelemetryConfig, TelemetryHooks, TelemetryMode, TelemetrySink};
#[cfg(feature = "cuda")]
use super::BaracudaStructureKeyProvider;
#[cfg(not(feature = "cuda"))]
use super::NullStructureKeyProvider;
use fuel_ir::DeviceLocation;
const MODE_OFF: u8 = 0;
const MODE_COARSE: u8 = 1;
const MODE_DETAILED: u8 = 2;
fn mode_to_u8(m: TelemetryMode) -> u8 {
match m {
TelemetryMode::Off => MODE_OFF,
TelemetryMode::Coarse => MODE_COARSE,
TelemetryMode::Detailed => MODE_DETAILED,
}
}
fn u8_to_mode(v: u8) -> TelemetryMode {
match v {
MODE_COARSE => TelemetryMode::Coarse,
MODE_DETAILED => TelemetryMode::Detailed,
_ => TelemetryMode::Off,
}
}
struct GlobalTelemetry {
mode: AtomicU8,
sink: Mutex<TelemetrySink>,
}
static TELEMETRY: OnceLock<GlobalTelemetry> = OnceLock::new();
fn global() -> &'static GlobalTelemetry {
TELEMETRY.get_or_init(|| GlobalTelemetry {
mode: AtomicU8::new(MODE_OFF),
sink: Mutex::new(TelemetrySink::new()),
})
}
pub fn enable(mode: TelemetryMode) {
global().mode.store(mode_to_u8(mode), Ordering::Relaxed);
}
pub fn disable() {
global().mode.store(MODE_OFF, Ordering::Relaxed);
}
pub fn current_mode() -> TelemetryMode {
u8_to_mode(global().mode.load(Ordering::Relaxed))
}
pub fn is_enabled() -> bool {
current_mode().is_enabled()
}
pub(crate) fn sink() -> &'static Mutex<TelemetrySink> {
&global().sink
}
pub fn reset() {
if let Ok(mut s) = global().sink.lock() {
*s = TelemetrySink::new();
}
}
pub fn flush_to(dir: &Path) -> std::io::Result<(usize, usize)> {
let s = global()
.sink
.lock()
.map_err(|_| std::io::Error::other("telemetry sink lock poisoned"))?;
s.flush_all(dir)
}
pub fn flush() -> Option<std::io::Result<(usize, usize)>> {
default_telemetry_dir().map(|d| flush_to(&d))
}
pub fn default_telemetry_dir() -> Option<PathBuf> {
crate::judge_report_path::default_report_path()
.and_then(|p| p.parent().map(|d| d.to_path_buf()))
}
static HW_STAMPS: OnceLock<Vec<(DeviceLocation, HwStamp)>> = OnceLock::new();
fn hw_stamps() -> &'static Vec<(DeviceLocation, HwStamp)> {
HW_STAMPS.get_or_init(|| {
fuel_hardware::probe::ProbeReport::probe_all()
.devices
.iter()
.map(|d| (d.location, HwStamp::from_descriptor(d)))
.collect()
})
}
pub(crate) fn hw_stamp_for(device: DeviceLocation) -> HwStamp {
hw_stamps()
.iter()
.find(|(loc, _)| *loc == device)
.map(|(_, s)| s.clone())
.unwrap_or_else(|| HwStamp {
compute_capability: None,
hardware_sku: format!("{device:?}"),
driver_version: "unknown".into(),
})
}
pub struct TelemetryInstall {
config: TelemetryConfig,
#[cfg(feature = "cuda")]
provider: BaracudaStructureKeyProvider,
#[cfg(not(feature = "cuda"))]
provider: NullStructureKeyProvider,
hw: HwStamp,
enabled: bool,
}
impl TelemetryInstall {
pub fn new(device: DeviceLocation) -> Self {
let mode = current_mode();
Self {
config: TelemetryConfig {
mode,
out_path: None,
},
#[cfg(feature = "cuda")]
provider: BaracudaStructureKeyProvider,
#[cfg(not(feature = "cuda"))]
provider: NullStructureKeyProvider,
hw: hw_stamp_for(device),
enabled: mode.is_enabled(),
}
}
pub fn hooks(&self) -> Option<TelemetryHooks<'_>> {
if !self.enabled {
return None;
}
Some(TelemetryHooks {
config: &self.config,
sink: sink(),
provider: &self.provider,
hw: self.hw.clone(),
})
}
}
#[cfg(test)]
mod tests {
use super::super::{
Candidate, DispatchRecord, ImplId, MissRecord, StructureKeyToken, TELEMETRY_SCHEMA_VERSION,
};
use super::*;
use fuel_ir::dispatch::OpKind;
use fuel_ir::{BackendId, DType};
fn impl_id(src: &str) -> ImplId {
ImplId {
backend: BackendId::Cpu,
op: OpKind::AddElementwise,
dtypes: vec![DType::F32, DType::F32, DType::F32],
kernel_source: src.into(),
kernel_revision_hash: 0,
}
}
fn cpu_hw() -> HwStamp {
HwStamp {
compute_capability: None,
hardware_sku: "test-cpu".into(),
driver_version: "n/a".into(),
}
}
#[test]
fn opt_in_state_machine_and_explicit_flush() {
enable(TelemetryMode::Coarse);
assert_eq!(current_mode(), TelemetryMode::Coarse);
assert!(is_enabled());
enable(TelemetryMode::Detailed);
assert_eq!(current_mode(), TelemetryMode::Detailed);
disable();
assert_eq!(current_mode(), TelemetryMode::Off);
assert!(!is_enabled());
let uniq = format!("mm:telemetry-test:{:?}", std::thread::current().id());
{
let mut s = sink().lock().expect("sink");
s.record_dispatch(DispatchRecord {
schema: TELEMETRY_SCHEMA_VERSION,
structure_key: Some(StructureKeyToken::new(uniq.clone())),
chosen: impl_id("portable-cpu"),
candidates: vec![Candidate {
impl_id: impl_id("portable-cpu"),
latency_ns: Some(41_230),
}],
count: 1,
hw: cpu_hw(),
});
s.record_miss(MissRecord {
schema: TELEMETRY_SCHEMA_VERSION,
wanted: StructureKeyToken::new(uniq.clone()),
fallback: impl_id("baracuda-generic-strided"),
count: 1,
hw: cpu_hw(),
});
}
let dir = tempfile::tempdir().expect("tempdir");
let (misses, dispatches) = flush_to(dir.path()).expect("flush_to");
assert!(misses >= 1 && dispatches >= 1, "at least our two lines");
let disp =
std::fs::read_to_string(dir.path().join("dispatches.jsonl")).expect("dispatches");
let miss = std::fs::read_to_string(dir.path().join("misses.jsonl")).expect("misses");
let ours = disp
.lines()
.filter_map(|l| serde_json::from_str::<DispatchRecord>(l).ok())
.find(|r| r.structure_key.as_ref().map(|t| t.0.as_str()) == Some(uniq.as_str()))
.expect("our dispatch record is present in the flushed feed");
assert_eq!(ours.chosen, impl_id("portable-cpu"));
assert_eq!(ours.candidates[0].latency_ns, Some(41_230));
assert!(
miss.lines()
.filter_map(|l| serde_json::from_str::<MissRecord>(l).ok())
.any(|r| r.wanted.0 == uniq),
"our miss record is present in the flushed feed",
);
}
#[test]
fn cpu_hw_stamp_has_no_compute_capability() {
let stamp = hw_stamp_for(DeviceLocation::Cpu);
assert_eq!(
stamp.compute_capability, None,
"a CPU realize has no CUDA compute capability",
);
}
#[test]
fn default_telemetry_dir_matches_the_profile_cache_dir() {
match default_telemetry_dir() {
Some(dir) => {
let report =
crate::judge_report_path::default_report_path().expect("report path present");
assert_eq!(Some(dir.as_path()), report.parent());
}
None => assert!(
crate::judge_report_path::default_report_path().is_none(),
"default_telemetry_dir() is a plain projection of the Judge report \
dir: it may only be None when the report path is also None",
),
}
}
}