#![allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::indexing_slicing,
clippy::cast_possible_truncation,
clippy::cast_precision_loss,
clippy::cast_sign_loss,
clippy::as_conversions,
clippy::missing_docs_in_private_items,
clippy::missing_panics_doc,
missing_docs
)]
use candle_core::{DType, Device, Tensor};
use candle_mi::{MemoryReport, MemorySnapshot};
use serial_test::serial;
fn cuda_device() -> Option<Device> {
Device::cuda_if_available(0).ok().filter(Device::is_cuda)
}
#[test]
fn cpu_snapshot_is_ram_only() {
let snap = MemorySnapshot::now(&Device::Cpu).unwrap();
assert!(snap.ram_bytes > 0, "process RSS should be non-zero");
assert!(snap.ram_mb() > 0.0, "RAM in MB should be positive");
assert!(snap.vram_bytes.is_none(), "CPU should report no VRAM used");
assert!(
snap.vram_total_bytes.is_none(),
"CPU should report no VRAM total"
);
assert!(
snap.vram_per_process.is_none(),
"CPU should report no VRAM qualifier"
);
assert!(snap.gpu_name.is_none(), "CPU should report no GPU name");
assert!(snap.vram_mb().is_none(), "CPU should report no VRAM MB");
}
#[test]
#[ignore = "requires a CUDA device; run with --features memory,cuda -- --ignored"]
#[serial]
fn cuda_snapshot_is_sane() {
let Some(device) = cuda_device() else {
eprintln!("SKIP: no CUDA device available");
return;
};
let snap = MemorySnapshot::now(&device).unwrap();
assert!(snap.ram_bytes > 0, "process RSS should be non-zero");
if let Some(total) = snap.vram_total_bytes {
assert!(total > 0, "device VRAM total should be positive");
if let Some(used) = snap.vram_bytes {
assert!(
used <= total,
"used VRAM {used} must not exceed total {total}"
);
}
if let Some(reserved) = snap.vram_reserved_bytes {
assert!(
reserved < total,
"reserved VRAM {reserved} must be a subset of total {total}"
);
}
}
println!(
"CUDA snapshot: ram={:.0} MB, vram={:?} MB / total={:?} MB \
(reserved={:?} MB), per_process={:?}, gpu={:?}",
snap.ram_mb(),
snap.vram_mb().map(|v| v as u64),
snap.vram_total_bytes.map(|t| t / 1_048_576),
snap.vram_reserved_bytes.map(|r| r / 1_048_576),
snap.vram_per_process,
snap.gpu_name,
);
}
#[test]
#[ignore = "requires a CUDA device; run with --features memory,cuda -- --ignored"]
#[serial]
fn cuda_allocation_is_visible_in_vram() {
let Some(device) = cuda_device() else {
eprintln!("SKIP: no CUDA device available");
return;
};
candle_mi::sync_and_trim_gpu(&device);
let before = MemorySnapshot::now(&device).unwrap();
let n_elems = 128 * 1024 * 1024; let big = Tensor::zeros(n_elems, DType::F32, &device).unwrap();
let after = MemorySnapshot::now(&device).unwrap();
let report = MemoryReport::new(before, after);
match report.vram_delta_mb() {
Some(delta) => {
assert!(
delta > 256.0,
"expected >256 MB VRAM increase for a 512 MiB allocation, got {delta:.0} MB"
);
println!("VRAM delta for 512 MiB allocation: {delta:.0} MB");
}
None => {
eprintln!("SKIP assert: VRAM not measurable on this system");
}
}
drop(big);
candle_mi::sync_and_trim_gpu(&device);
}