use std::fmt::Write;
use std::path::Path;
use crate::context::Context;
use crate::libtorch::detect;
use crate::util::system;
pub fn run(json: bool) {
let ctx = Context::resolve();
let root = &ctx.root;
if json {
print_json(root, &ctx);
} else {
print_report(root, &ctx);
}
}
fn print_report(root: &Path, ctx: &Context) {
println!("floDl Diagnostics");
println!("=================");
println!();
println!("Context: {}", ctx.label());
println!();
println!("System");
let cpu = system::cpu_model().unwrap_or_else(|| "Unknown".into());
let threads = system::cpu_threads();
let ram_gb = system::ram_total_gb();
println!(" CPU: {} ({} threads, {}GB RAM)", cpu, threads, ram_gb);
if let Some(os) = system::os_version() {
println!(" OS: {}", os);
}
if system::is_inside_docker() {
println!(" Docker: yes (running inside container)");
} else {
match system::docker_version() {
Some(v) => println!(" Docker: {}", v),
None => println!(" Docker: not found"),
}
}
println!();
println!("CUDA");
let devices = system::detect_gpus();
if !devices.is_empty() {
if let Some(driver) = system::nvidia_driver_version() {
println!(" Driver: {}", driver);
}
println!(" Devices: {}", devices.len());
for d in &devices {
let vram_gb = d.total_memory_mb / 1024;
println!(
" [{}] {} -- {}, {}GB VRAM",
d.index,
d.name,
d.sm_version(),
vram_gb
);
}
} else {
println!(" No CUDA devices available");
}
println!();
println!("libtorch");
match detect::read_active(root) {
Some(info) => {
println!(" Active: {}", info.path);
if let Some(v) = &info.torch_version {
println!(" Version: {}", v);
}
if let Some(c) = &info.cuda_version {
println!(" CUDA: {}", c);
}
if let Some(a) = &info.archs {
println!(" Archs: {}", a);
}
if let Some(s) = &info.source {
println!(" Source: {}", s);
}
}
None => {
println!(" No active variant (run `fdl setup`)");
}
}
let variants = detect::list_variants(root);
if !variants.is_empty() {
println!(" Variants: {}", variants.join(", "));
}
println!();
if !devices.is_empty() {
println!("Compatibility");
if let Some(info) = detect::read_active(root) {
let archs = info.archs.as_deref().unwrap_or("");
let mut all_ok = true;
for d in &devices {
if detect::arch_compatible(d, archs) {
println!(
" GPU {} ({}, {}): OK",
d.index,
d.short_name(),
d.sm_version()
);
} else {
all_ok = false;
let arch_str = format!("{}.{}", d.sm_major, d.sm_minor);
println!(
" GPU {} ({}, {}): MISSING -- arch {} not in [{}]",
d.index,
d.short_name(),
d.sm_version(),
arch_str,
archs
);
}
}
if all_ok {
println!();
println!(" All GPUs compatible with active libtorch.");
}
} else {
println!(" Cannot check -- no active libtorch variant.");
}
println!();
}
}
fn print_json(root: &Path, ctx: &Context) {
let mut b = String::with_capacity(2048);
b.push('{');
let _ = write!(
b,
"\"context\":{{\"mode\":\"{}\",\"root\":\"{}\"}}",
if ctx.is_project { "project" } else { "global" },
system::escape_json(&ctx.root.display().to_string())
);
let cpu = system::cpu_model().unwrap_or_else(|| "Unknown".into());
let _ = write!(
b,
",\"system\":{{\"cpu\":\"{}\",\"threads\":{},\"ram_gb\":{}",
system::escape_json(&cpu),
system::cpu_threads(),
system::ram_total_gb()
);
if let Some(os) = system::os_version() {
let _ = write!(b, ",\"os\":\"{}\"", system::escape_json(&os));
}
if system::is_inside_docker() {
b.push_str(",\"docker\":\"container\"");
} else if let Some(docker) = system::docker_version() {
let _ = write!(b, ",\"docker\":\"{}\"", system::escape_json(&docker));
}
b.push('}');
let devices = system::detect_gpus();
let archs = detect::read_active(root)
.and_then(|info| info.archs)
.unwrap_or_default();
b.push_str(",\"gpus\":[");
for (i, d) in devices.iter().enumerate() {
if i > 0 {
b.push(',');
}
let compatible = detect::arch_compatible(d, &archs);
let _ = write!(
b,
"{{\"index\":{},\"name\":\"{}\",\"sm\":\"{}\",\"vram_bytes\":{},\"arch_compatible\":{}}}",
d.index,
system::escape_json(&d.name),
d.sm_version(),
d.vram_bytes(),
compatible
);
}
b.push(']');
b.push_str(",\"libtorch\":");
match detect::read_active(root) {
Some(info) => {
let _ = write!(b, "{{\"path\":\"{}\"", system::escape_json(&info.path));
if let Some(v) = &info.torch_version {
let _ = write!(b, ",\"version\":\"{}\"", system::escape_json(v));
}
if let Some(c) = &info.cuda_version {
let _ = write!(b, ",\"cuda\":\"{}\"", system::escape_json(c));
}
if let Some(a) = &info.archs {
let _ = write!(b, ",\"archs\":\"{}\"", system::escape_json(a));
}
if let Some(s) = &info.source {
let _ = write!(b, ",\"source\":\"{}\"", system::escape_json(s));
}
b.push('}');
}
None => b.push_str("null"),
}
b.push('}');
println!("{}", b);
}