use std::process::Command;
pub(super) struct NvidiaSmiResult {
pub used_bytes: u64,
pub total_bytes: u64,
}
pub(super) fn query(idx: u32) -> Option<NvidiaSmiResult> {
let cmd_result = Command::new("nvidia-smi")
.args([
"--query-gpu=memory.used,memory.total",
"--format=csv,noheader,nounits",
])
.arg(format!("--id={idx}"))
.output();
let output = match cmd_result {
Ok(o) if o.status.success() => o,
#[cfg(feature = "debug-output")]
Ok(o) => {
let stderr = String::from_utf8_lossy(&o.stderr);
eprintln!(
"[nvidia-smi debug] subprocess for idx={idx} exited with {} \
(stderr trimmed: {:?})",
o.status,
stderr.trim(),
);
return None;
}
#[cfg(not(feature = "debug-output"))]
Ok(_) => return None,
#[cfg(feature = "debug-output")]
Err(e) => {
eprintln!("[nvidia-smi debug] failed to spawn for idx={idx}: {e}");
return None;
}
#[cfg(not(feature = "debug-output"))]
Err(_) => return None,
};
let stdout = String::from_utf8_lossy(&output.stdout);
#[allow(clippy::question_mark)]
let Some(line_raw) = stdout.lines().next() else {
#[cfg(feature = "debug-output")]
eprintln!("[nvidia-smi debug] empty stdout for idx={idx}");
return None;
};
let line = line_raw.trim();
let mut parts = line.split(',');
let used_str = parts.next().map(str::trim)?;
let total_str = parts.next().map(str::trim)?;
let used_mb: u64 = match used_str.parse() {
Ok(v) => v,
#[cfg(feature = "debug-output")]
Err(e) => {
eprintln!("[nvidia-smi debug] failed to parse used '{used_str}' for idx={idx}: {e}");
return None;
}
#[cfg(not(feature = "debug-output"))]
Err(_) => return None,
};
let total_mb: u64 = match total_str.parse() {
Ok(v) => v,
#[cfg(feature = "debug-output")]
Err(e) => {
eprintln!("[nvidia-smi debug] failed to parse total '{total_str}' for idx={idx}: {e}");
return None;
}
#[cfg(not(feature = "debug-output"))]
Err(_) => return None,
};
let used_bytes = used_mb.saturating_mul(1_048_576);
let total_bytes = total_mb.saturating_mul(1_048_576);
#[cfg(feature = "debug-output")]
eprintln!(
"[nvidia-smi debug] idx={idx}: used={used_mb}MiB total={total_mb}MiB \
({used_bytes} / {total_bytes} bytes)"
);
Some(NvidiaSmiResult {
used_bytes,
total_bytes,
})
}