### Quick Start: Get Process Memory Snapshot Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/index.html This snippet demonstrates how to get a memory snapshot of the current process, including RAM usage and optional GPU device information. It requires the 'hypomnesis' crate to be included in your project. ```rust let snap = hypomnesis::Snapshot::now(0)?; println!("RAM: {} bytes", snap.ram_bytes); if let Some(dev) = snap.gpu_device { println!("GPU 0: {:?}, free {} of {} bytes", dev.name, dev.free_bytes, dev.total_bytes); } ``` -------------------------------- ### Run print_demo example Source: https://docs.rs/hypomnesis/0.1.0/src/print_demo/print_demo.rs.html Example of how to run the print_demo example with different feature flags. ```rust cargo run --features report --example print_demo ``` ```rust cargo run --features "report debug-output" --example print_demo ``` -------------------------------- ### Example Usage of a Public Function Source: https://docs.rs/hypomnesis/0.1.0/scrape-examples-help.html An example in examples/ex.rs demonstrating how to call a documented function from another crate. ```rust // examples/ex.rs fn main() { a_crate::a_func(); } ``` -------------------------------- ### Handling file metadata operations with and_then Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/error/type.Result.html Shows how to use `and_then` to chain fallible operations like getting file metadata and its modification time. Useful for sequences of I/O operations. ```rust use std::{io::ErrorKind, path::Path}; // Note: on Windows "/" maps to "C:\" let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified()); assert!(root_modified_time.is_ok()); let should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified()); assert!(should_fail.is_err()); assert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound); ``` -------------------------------- ### Get Per-Process GPU Memory Info (DXGI) Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/gpu/mod.rs.html Retrieves per-process GPU memory usage using the DXGI backend on Windows. This is the primary WDDM-aware source. ```rust #[cfg(all(windows, feature = "dxgi"))] if let Some(d) = dxgi::query(device_index) { return Ok(ProcessGpuInfo { used_bytes: d.current_usage, is_per_process: true, source: GpuQuerySource::Dxgi, }); } ``` -------------------------------- ### Safely get Ok value (nightly) Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/error/type.Result.html Returns the contained Ok value, guaranteed not to panic. Useful as a maintainability safeguard. ```rust fn only_good_news() -> Result { Ok("this is fine".into()) } let s: String = only_good_news().into_ok(); println!("{s}"); ``` -------------------------------- ### Get GPU Device Info Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/gpu/fn.device_info.html Retrieves detailed information for a specific GPU by its index. Prioritizes NVML, falls back to DXGI on Windows, and then nvidia-smi. Ensure the index is within the valid range of available GPUs. ```rust pub fn device_info(index: u32) -> Result ``` -------------------------------- ### Get Process RSS in Bytes Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/ram/fn.process_rss.html Query the current process's resident set size (RSS) in bytes. Returns the per-process resident-set figure as reported by the operating system. On Linux, this reads from /proc/self/status. ```rust pub fn process_rss() -> Result ``` -------------------------------- ### Get Device-Wide GPU Memory Info (nvidia-smi fallback) Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/gpu/mod.rs.html As a fallback, retrieves device-wide GPU memory usage using nvidia-smi. This source cannot break down usage per process, so `is_per_process` is set to false. ```rust #[cfg(feature = "nvidia-smi-fallback")] if let Some(result) = nvidia_smi::query(device_index) { return Ok(ProcessGpuInfo { used_bytes: result.used_bytes, is_per_process: false, source: GpuQuerySource::NvidiaSmi, }); } ``` -------------------------------- ### Iterating and Calculating Sum with Result Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/error/type.Result.html Shows how to use the `sum` method on an iterator of `Result` values. The operation returns an `Err` if a negative element is encountered, otherwise it returns the `Ok` sum. This example uses a closure to define the mapping and error condition. ```rust let f = |&x: &i32| if x < 0 { Err("Negative element found") } else { Ok(x) }; let v = vec![1, 2]; let res: Result = v.iter().map(f).sum(); assert_eq!(res, Ok(3)); ``` ```rust let v = vec![1, -2]; let res: Result = v.iter().map(f).sum(); assert_eq!(res, Err("Negative element found")); ``` -------------------------------- ### Get NVIDIA GPU Count Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/gpu/fn.device_count.html Retrieves the number of NVIDIA GPUs visible to the system using NVML or DXGI. Ensure NVML is installed and accessible, or on Windows, that DXGI can enumerate NVIDIA adapters. ```rust use hypomnesis::gpu::device_count; fn main() { match device_count() { Ok(count) => println!("Found {} NVIDIA GPUs.", count), Err(e) => eprintln!("Error getting GPU count: {}", e), } } ``` -------------------------------- ### Recommended expect Message Style for Environment Variables Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/error/type.Result.html Demonstrates a recommended style for expect messages, focusing on the expected state of the environment. This improves clarity when panicking due to missing or incorrect environment variables. ```rust let path = std::env::var("IMPORTANT_PATH") .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); ``` -------------------------------- ### Main function for print_demo Source: https://docs.rs/hypomnesis/0.1.0/src/print_demo/print_demo.rs.html Captures memory snapshots before and after an allocation, then prints the memory delta and before/after reports. The allocation is kept alive to ensure the 'after' snapshot reflects it. ```rust use hypomnesis::{MemoryReport, Snapshot}; #[allow(clippy::expect_used)] fn main() { println!("--- hypomnesis print_demo ---"); let before = Snapshot::now(0).expect("Snapshot::now failed"); // Allocate ~50 MiB on the heap to produce a visible RAM delta. // Use vec![0_u8; ...] (zeroed allocation) so the OS commits pages. let hold: Vec = vec![0_u8; 50 * 1024 * 1024]; let after = Snapshot::now(0).expect("Snapshot::now failed"); let report = MemoryReport::new(before, after); println!("--- print_delta ---"); report.print_delta("alloc 50 MiB"); println!("--- print_before_after ---"); report.print_before_after("alloc 50 MiB"); println!("--- format_delta (returned as String, no newline added by us) ---"); print!("{}", report.format_delta("alloc 50 MiB")); println!("--- format_before_after (returned as String, no newline added by us) ---"); print!("{}", report.format_before_after("alloc 50 MiB")); // Keep the allocation alive until here so the after-snapshot still // reflects it (otherwise the optimizer could elide `hold`). drop(hold); } ``` -------------------------------- ### NVML Function Type Aliases Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/gpu/nvml.rs.html Type aliases for NVML function signatures, including initialization, shutdown, getting device handles by index, and getting memory information. ```rust type NvmlDevice = *mut std::ffi::c_void; type NvmlInitFn = unsafe extern "C" fn() -> u32; type NvmlShutdownFn = unsafe extern "C" fn() -> u32; type NvmlDeviceGetHandleByIndexFn = unsafe extern "C" fn(u32, *mut NvmlDevice) -> u32; type NvmlDeviceGetMemoryInfoFn = unsafe extern "C" fn(NvmlDevice, *mut NvmlMemoryInfo) -> u32; ``` -------------------------------- ### Public Function Definition Source: https://docs.rs/hypomnesis/0.1.0/scrape-examples-help.html A public function defined in src/lib.rs that can be used as a target for scraped examples. ```rust // src/lib.rs pub fn a_func() {} ``` -------------------------------- ### Query RSS on Windows Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/ram.rs.html This function queries the Resident Set Size (RSS) on Windows by calling the `K32GetProcessMemoryInfo` Windows API. It initializes the necessary structures and handles potential errors from the API call. ```Rust /// Query `RSS` on Windows via `K32GetProcessMemoryInfo`. #[cfg(target_os = "windows")] #[allow(unsafe_code)] fn windows_rss() -> Result { let mut counters = win_ffi::ProcessMemoryCounters { cb: 0, page_fault_count: 0, peak_working_set_size: 0, working_set_size: 0, quota_peak_paged_pool_usage: 0, quota_paged_pool_usage: 0, quota_peak_non_paged_pool_usage: 0, quota_non_paged_pool_usage: 0, pagefile_usage: 0, peak_pagefile_usage: 0, }; // CAST: usize → u32, struct size is 80 bytes on x64 — fits in u32 #[allow(clippy::as_conversions, clippy::cast_possible_truncation)] let cb = std::mem::size_of::() as u32; counters.cb = cb; let handle = win_ffi::GetCurrentProcess(); // SAFETY: K32GetProcessMemoryInfo writes into the stack-allocated // `counters` struct, which is correctly sized (the cb field above is // set to the struct's byte size). The process handle from // GetCurrentProcess is a pseudo-handle that is always valid for the // lifetime of the process. let ok = unsafe { win_ffi::K32GetProcessMemoryInfo(handle, &raw mut counters, cb) }; if ok != 0 { ``` -------------------------------- ### into Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/snapshot/struct.Snapshot.html Converts the current instance into another type. ```APIDOC ## fn into(self) -> U ### Description Calls `U::from(self)`. This conversion is determined by the implementation of `From for U`. ### Method fn ### Parameters - **self** (T) - Description: The value to convert. ``` -------------------------------- ### Get VRAM Qualifier When No GPU Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/report.rs.html Ensures an empty VRAM qualifier string is returned when no GPU is detected. ```rust let snap = snapshot_no_gpu(100); let report = MemoryReport::new(snap.clone(), snap); assert_eq!(report.vram_qualifier(), ""); ``` -------------------------------- ### Converting Result to Option with Ok value Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/error/type.Result.html Shows how to use the `ok` method to convert a `Result` into an `Option`, consuming the original Result. If the Result is Ok, it returns Some(T); otherwise, it returns None. ```Rust let x: Result = Ok(2); assert_eq!(x.ok(), Some(2)); ``` -------------------------------- ### Get VRAM Qualifier Device Wide Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/report.rs.html Determines the VRAM qualifier string when VRAM usage is tracked device-wide. ```rust let snap = snapshot_with(100, Some(500), false, 1000, None); let report = MemoryReport::new(snap.clone(), snap); assert_eq!(report.vram_qualifier(), " [device-wide]"); ``` -------------------------------- ### Safely get Err value (nightly) Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/error/type.Result.html Returns the contained Err value, guaranteed not to panic. Useful as a maintainability safeguard. ```rust fn only_bad_news() -> Result { Err("Oops, it failed".into()) } let error: String = only_bad_news().into_err(); println!("{error}"); ``` -------------------------------- ### Bounds Check Device Index (DXGI) Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/gpu/mod.rs.html Performs a bounds check on the device index using the DXGI backend on Windows. Returns an error if the index is out of range. ```rust #[cfg(all(windows, feature = "dxgi"))] if let Some(count) = dxgi::device_count() { return if index >= count { Err(HypomnesisError::DeviceIndexOutOfRange { index, count }) } else { Ok(()) }; } ``` -------------------------------- ### Test: Snapshot Construction with Full GPU Details Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/snapshot.rs.html Tests the construction of a `Snapshot` with complete GPU information, including used VRAM and total GPU memory. ```rust #[test] fn snapshot_constructs_with_full_gpu() { let snap = make_snapshot(1_048_576, Some(500 * 1_048_576), true, 16_384 * 1_048_576); assert_eq!(snap.ram_bytes, 1_048_576); assert_eq!(snap.gpu.as_ref().unwrap().used_bytes, 500 * 1_048_576); assert!(snap.gpu.as_ref().unwrap().is_per_process); assert_eq!( snap.gpu_device.as_ref().unwrap().total_bytes, 16_384 * 1_048_576 ); } ``` -------------------------------- ### from Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/snapshot/struct.Snapshot.html Creates a new instance of the type from the given argument. ```APIDOC ## fn from(t: T) -> T ### Description Returns the argument unchanged. ### Method fn ### Parameters - **t** (T) - Description: The value to convert. ``` -------------------------------- ### Get VRAM Qualifier Per Process Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/report.rs.html Determines the VRAM qualifier string when VRAM usage is tracked per process. ```rust let snap = snapshot_with(100, Some(500), true, 1000, None); let report = MemoryReport::new(snap.clone(), snap); assert_eq!(report.vram_qualifier(), " [per-process]"); ``` -------------------------------- ### Test Helper: Build Snapshot Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/snapshot.rs.html A helper function to construct `Snapshot` instances for testing. It conditionally sets GPU information based on provided VRAM usage and total GPU memory. ```rust /// Build a `Snapshot` for tests. Sets `gpu` only when `vram_used` is /// `Some`; sets `gpu_device` only when `total` is non-zero. fn make_snapshot( ram: u64, vram_used: Option, is_per_process: bool, total: u64, ) -> Snapshot { Snapshot { ram_bytes: ram, gpu: vram_used.map(|used| ProcessGpuInfo { used_bytes: used, is_per_process, source: if is_per_process { GpuQuerySource::Nvml } else { GpuQuerySource::NvidiaSmi }, }), gpu_device: if total > 0 { Some(GpuDeviceInfo { index: 0, name: None, total_bytes: total, free_bytes: total.saturating_sub(vram_used.unwrap_or(0)) , used_bytes: vram_used.unwrap_or(0), }) } else { None }, } } ``` -------------------------------- ### Get VRAM Usage in Megabytes Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/snapshot/struct.Snapshot.html Retrieves the per-process VRAM usage in megabytes, if available. Returns None when GPU information is not accessible. ```rust pub fn vram_mb(&self) -> Option ``` -------------------------------- ### into_ok Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/error/type.Result.html Returns the contained Ok value, but never panics. This is an experimental API. ```APIDOC ## into_ok ### Description Returns the contained `Ok` value, but never panics. Unlike `unwrap`, this method is known to never panic on the result types it is implemented for. Therefore, it can be used instead of `unwrap` as a maintainability safeguard that will fail to compile if the error type of the `Result` is later changed to an error that can actually occur. ### Method `into_ok()` ### Parameters None ### Request Example ```rust fn only_good_news() -> Result { Ok("this is fine".into()) } let s: String = only_good_news().into_ok(); println!("{s}"); ``` ### Response #### Success Response - `T`: The contained `Ok` value. #### Response Example ```rust "this is fine" ``` ``` -------------------------------- ### Get RAM Usage in Megabytes Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/snapshot/struct.Snapshot.html Retrieves the process resident set size (RSS) in megabytes. This is a convenience method for accessing RAM usage. ```rust pub fn ram_mb(&self) -> f64 ``` -------------------------------- ### Create a New Snapshot Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/snapshot/struct.Snapshot.html Captures a fresh snapshot of process RAM and GPU memory for a given device index. RAM measurement is always performed; GPU measurement failures are non-fatal. ```rust let before = Snapshot::now(0).expect("Snapshot::now failed"); // Allocate ~50 MiB on the heap to produce a visible RAM delta. // Use vec![0_u8; ...] (zeroed allocation) so the OS commits pages. let hold: Vec = vec![0_u8; 50 * 1024 * 1024]; let after = Snapshot::now(0).expect("Snapshot::now failed"); let report = MemoryReport::new(before, after); println!("--- print_delta ---"); report.print_delta("alloc 50 MiB"); println!("--- print_before_after ---"); report.print_before_after("alloc 50 MiB"); println!("--- format_delta (returned as String, no newline added by us) ---"); print!("{}", report.format_delta("alloc 50 MiB")); println!("--- format_before_after (returned as String, no newline added by us) ---"); print!("{}", report.format_before_after("alloc 50 MiB")); // Keep the allocation alive until here so the after-snapshot still // reflects it (otherwise the optimizer could elide `hold`). drop(hold); ``` -------------------------------- ### Format Before and After With VRAM and GPU Name Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/report.rs.html Formats a detailed report showing before and after memory states, including RAM, VRAM, VRAM qualifier, and GPU name. ```rust let before = snapshot_with( 100 * 1_048_576, Some(500 * 1_048_576), true, 16_384 * 1_048_576, Some("NVIDIA Test GPU"), ); let after = snapshot_with( 200 * 1_048_576, Some(1_000 * 1_048_576), true, 16_384 * 1_048_576, Some("NVIDIA Test GPU"), ); let report = MemoryReport::new(before, after); let s = report.format_before_after("model_load"); assert_eq!( s, " model_load: RAM 100 MB → 200 MB (+100 MB)\n \n model_load: VRAM 500 MB → 1000 MB (+500 MB / 16384 MB) [per-process] [NVIDIA Test GPU]\n" ); ``` -------------------------------- ### Rust: Verify print_before_after does not panic Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/report.rs.html This snippet shows how to use `print_before_after` from `MemoryReport` to confirm it operates without panicking. It involves generating a snapshot and initializing a `MemoryReport`. ```rust fn print_before_after_does_not_panic() { let snap = snapshot_with(100, Some(200), true, 1000, None); let report = MemoryReport::new(snap.clone(), snap); report.print_before_after("smoke"); } ``` -------------------------------- ### Get Per-Process GPU Memory Info (NVML) Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/gpu/mod.rs.html Retrieves per-process GPU memory usage using the NVML backend. This is primarily for Linux and may not work for compute processes on Windows under WDDM. ```rust #[cfg(feature = "nvml")] if let Some(snap) = nvml::query(device_index) && let Some(used) = snap.process_used_bytes { return Ok(ProcessGpuInfo { used_bytes: used, is_per_process: true, source: GpuQuerySource::Nvml, }); } ``` -------------------------------- ### Format Two-Line Before/After Summary Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/report.rs.html Formats a two-line summary comparing 'before' and 'after' states for both RAM and VRAM. Includes absolute values and deltas. The VRAM line is only included if VRAM data is present in both snapshots. ```rust pub fn format_before_after(&self, label: &str) -> String { let mut out = format!( " {label}: RAM {:.0} MB → {:.0} MB ({:+.0} MB)\n", self.before.ram_mb(), self.after.ram_mb(), self.ram_delta_mb(), ); if let (Some(before), Some(after)) = (self.before.vram_mb(), self.after.vram_mb()) { // CAST: u64 → f64, byte count for MiB conversion (fits in f64 mantissa). #[allow(clippy::cast_precision_loss, clippy::as_conversions)] let total = self.after.gpu_device.as_ref().map_or(String::new(), |d| { format!(" / {:.0} MB", d.total_bytes as f64 / 1_048_576.0) }); let qualifier = self.vram_qualifier(); // BORROW: explicit and_then + map_or + format — gpu_device.name is // Option; we need an owned String for the suffix. let gpu = self .after .gpu_device .as_ref() .and_then(|d| d.name.as_deref()) .map_or(String::new(), |name| format!(" [{name}]")); let line2 = format!( ``` -------------------------------- ### print_before_after Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/report/struct.MemoryReport.html Prints a two-line summary comparing memory usage before and after an event to standard output. This method delegates to `format_before_after` and prints the exact same string. ```APIDOC ## pub fn print_before_after(&self, label: &str) ### Description Print a two-line `before → after` summary to stdout. Delegates to `Self::format_before_after`; the printed string is byte-for-byte identical to the formatted return value. ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Method - Not applicable (method call) ### Endpoint - Not applicable (method call) ### Request Example ```rust report.print_before_after("alloc 50 MiB"); ``` ### Response #### Success Response - Prints to stdout. #### Response Example ``` before: 10.00 MiB, after: 60.00 MiB (alloc 50 MiB) ``` ``` -------------------------------- ### Get GPU Device Count Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/gpu/mod.rs.html Retrieves the number of visible NVIDIA GPUs. On Windows, it prioritizes NVML and falls back to DXGI if NVML is unavailable. Returns an error if no enumeration backend is enabled or succeeds. ```rust pub fn device_count() -> Result { #[cfg(feature = "nvml")] if let Some(count) = nvml::device_count() { return Ok(count); } #[cfg(all(windows, feature = "dxgi"))] if let Some(count) = dxgi::device_count() { return Ok(count); } // nvidia-smi fallback for device_count is intentionally not wired — // counting via `nvidia-smi -L` is more brittle than NVML/DXGI and // adds a subprocess invocation for what's typically a metadata call. Err(HypomnesisError::NoGpuSource) } ``` -------------------------------- ### Test: Snapshot Construction with No GPU Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/snapshot.rs.html Verifies that a `Snapshot` is correctly constructed when no GPU information is available. ```rust #[test] fn snapshot_constructs_with_no_gpu() { let snap = make_snapshot(0, None, false, 0); assert_eq!(snap.ram_bytes, 0); assert!(snap.gpu.is_none()); assert!(snap.gpu_device.is_none()); } ``` -------------------------------- ### ok Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/error/type.Result.html Converts from `Result` to `Option`, consuming the Result. Errors are converted to `None`. ```APIDOC ## ok ### Description Converts from `Result` to `Option`, consuming the Result. Errors are converted to `None`. ### Method `ok` ### Response - `Option` - `Some(T)` if the result was `Ok`, `None` if it was `Err`. ### Request Example ```rust let x: Result = Ok(2); assert_eq!(x.ok(), Some(2)); let x: Result = Err("Nothing here"); assert_eq!(x.ok(), None); ``` ``` -------------------------------- ### Get NVIDIA GPU Device Count Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/gpu/nvml.rs.html Retrieves the number of NVIDIA GPUs visible to the NVML library. Returns None if NVML cannot be loaded or if the device count retrieval fails. This function is used by the public `device_count()` dispatcher and for bounds-checking device indices. ```rust /// Number of NVIDIA GPUs visible to `NVML`. /// /// Returns `None` if `NVML` can't be loaded or `nvmlDeviceGetCount_v2` /// fails. Used by the public `device_count()` dispatcher and (when /// available) for bounds-checking `idx` in `device_info`. #[allow(unsafe_code)] pub(super) fn device_count() -> Option { // SAFETY: same justifications as in `query`. let lib = unsafe { libloading::Library::new(NVML_LIB_PATH) }.ok()?; // SAFETY: same — symbol names match the documented NVML C API. let init: libloading::Symbol<'_, NvmlInitFn> = unsafe { lib.get(b"nvmlInit_v2\0") }.ok()?; let shutdown: libloading::Symbol<'_, NvmlShutdownFn> = unsafe { lib.get(b"nvmlShutdown\0") }.ok()?; let get_count: libloading::Symbol<'_, NvmlDeviceGetCountFn> = unsafe { lib.get(b"nvmlDeviceGetCount_v2\0") }.ok()?; // SAFETY: nvmlInit_v2 is reentrant + thread-safe. let ret = unsafe { init() }; if ret != NVML_SUCCESS { #[cfg(feature = "debug-output")] eprintln!("[NVML debug] nvmlInit_v2 returned {ret} in device_count"); return None; } let mut count: u32 = 0; // SAFETY: nvmlDeviceGetCount_v2 writes one u32 to the caller-provided pointer. let ret = unsafe { get_count(&raw mut count) }; // SAFETY: nvmlShutdown balances the matched nvmlInit_v2. unsafe { shutdown() }; if ret == NVML_SUCCESS { #[cfg(feature = "debug-output")] eprintln!("[NVML debug] device_count = {count}"); Some(count) } else { #[cfg(feature = "debug-output")] eprintln!("[NVML debug] nvmlDeviceGetCount_v2 returned {ret}"); None } } ``` -------------------------------- ### Unwrap Ok value Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/error/type.Result.html Demonstrates unwrapping an Ok value. Panics if the value is an Err. ```rust let x: Result = Ok(2); assert_eq!(x.unwrap(), 2); ``` -------------------------------- ### Iterating and Calculating Product with Result Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/error/type.Result.html Demonstrates how to use the `product` method on an iterator of `Result` values. If any element fails to parse, the entire operation returns an `Err`. Otherwise, it returns the `Ok` value of the product. ```rust let nums = vec!["5", "10", "1", "2"]; let total: Result = nums.iter().map(|w| w.parse::()).product(); assert_eq!(total, Ok(100)); ``` ```rust let nums = vec!["5", "10", "one", "2"]; let total: Result = nums.iter().map(|w| w.parse::()).product(); assert!(total.is_err()); ``` -------------------------------- ### Helper to build Snapshot with GPU data Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/report.rs.html A test helper function to construct a `Snapshot` struct with specified RAM, VRAM, and GPU device information. It determines the `GpuQuerySource` based on whether the VRAM reading is per-process. ```Rust /// Build a Snapshot for delta/qualifier/format tests. fn snapshot_with( ram: u64, vram_used: Option, is_per_process: bool, total: u64, name: Option<&str>, ) -> Snapshot { Snapshot { ram_bytes: ram, gpu: vram_used.map(|used| ProcessGpuInfo { used_bytes: used, is_per_process, source: if is_per_process { GpuQuerySource::Nvml } else { GpuQuerySource::NvidiaSmi }, }), gpu_device: Some(GpuDeviceInfo { index: 0, name: name.map(str::to_owned), total_bytes: total, free_bytes: total.saturating_sub(vram_used.unwrap_or(0)), used_bytes: vram_used.unwrap_or(0), }), } } ``` -------------------------------- ### clone_to_uninit Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/snapshot/struct.Snapshot.html Performs copy-assignment from `self` to `dest`. This is a nightly-only experimental API. ```APIDOC ## unsafe fn clone_to_uninit(&self, dest: *mut u8) ### Description Performs copy-assignment from `self` to `dest`. ### Method unsafe fn ### Parameters - **dest** (*mut u8) - Description: Pointer to the destination memory location. ### Note This is a nightly-only experimental API. ``` -------------------------------- ### MemoryReport::format_before_after Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/report/struct.MemoryReport.html Formats a two-line summary comparing the 'before' and 'after' states of RAM and VRAM usage into a String. This provides a detailed view of memory changes. ```APIDOC ## MemoryReport::format_before_after ### Description Formats a two-line `before → after` summary as an owned `String`. Line 1 details RAM changes, and Line 2 (if VRAM data is present in both snapshots) details VRAM changes. ### Signature `pub fn format_before_after(&self, label: &str) -> String` ### Parameters * `label`: `&str` - A label to prepend to the summary string. ### Returns * `String` - A formatted string comparing the before and after memory states. ``` -------------------------------- ### Print two-line before/after summary Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/report.rs.html Prints a two-line summary showing memory usage before and after the change to standard output. This function delegates to `format_before_after`. ```Rust /// Print a two-line `before → after` summary to stdout. /// /// Delegates to [`Self::format_before_after`]; the printed string /// is byte-for-byte identical to the formatted return value. pub fn print_before_after(&self, label: &str) { print!("{}", self.format_before_after(label)); } ``` -------------------------------- ### Create a new memory snapshot Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/snapshot.rs.html Captures current process RAM and GPU memory usage for a specified device index. GPU measurement failures are handled gracefully by setting fields to `None`. Errors can occur if RAM query fails or if reading `/proc/self/status` fails on Linux. ```rust pub fn now(device_index: u32) -> Result { let ram_bytes = crate::ram::process_rss()?; let gpu = crate::gpu::process_gpu_info(device_index).ok(); let gpu_device = crate::gpu::device_info(device_index).ok(); Ok(Self { ram_bytes, gpu, gpu_device, }) } ``` -------------------------------- ### Snapshot::now Source: https://docs.rs/hypomnesis/0.1.0/index.html Captures a snapshot of the current process's RAM and optionally GPU memory usage. This is the primary method for obtaining memory metrics. ```APIDOC ## Snapshot::now ### Description Captures a snapshot of the current process's RAM and optionally GPU memory usage. This is the primary method for obtaining memory metrics. ### Method Rust function call ### Parameters * `gpu_query_source` (u32) - Optional - A value indicating how to query GPU information. Defaults to querying all available sources. ### Response Returns a `Result` containing a `Snapshot` on success, or a `HypomnesisError` on failure. #### Success Response - `Snapshot` - An object containing RAM and optional GPU memory information. - `ram_bytes` (u64) - The amount of RAM used by the process in bytes. - `gpu_device` (Option) - Information about the GPU device, if available. - `name` (String) - The name of the GPU device. - `free_bytes` (u64) - The amount of free VRAM on the GPU in bytes. - `total_bytes` (u64) - The total VRAM available on the GPU in bytes. ### Request Example ```rust let snap = hypomnesis::Snapshot::now(0)?; println!("RAM: {} bytes", snap.ram_bytes); if let Some(dev) = snap.gpu_device { println!("GPU 0: {:?}, free {} of {} bytes", dev.name, dev.free_bytes, dev.total_bytes); } ``` ``` -------------------------------- ### Spawn nvidia-smi Command Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/gpu/nvidia_smi.rs.html Constructs and executes the `nvidia-smi` command to query memory usage for a specific GPU index. Handles potential errors during command execution and checks for success. ```rust let cmd_result = Command::new("nvidia-smi") .args([ "--query-gpu=memory.used,memory.total", "--format=csv,noheader,nounits", ]) .arg(format!("--id={idx}")) .output(); ``` -------------------------------- ### device_info Source: https://docs.rs/hypomnesis/0.1.0/index.html Retrieves detailed information about a specific GPU device. ```APIDOC ## device_info ### Description Retrieves detailed information about a specific GPU device. ### Method Rust function call ### Parameters * `device_index` (usize) - The index of the GPU device to query. ### Response Returns a `Result` containing `GpuDeviceInfo` on success, or a `HypomnesisError` on failure. ``` -------------------------------- ### Create MemoryReport Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/report/struct.MemoryReport.html Constructs a MemoryReport from two Snapshot instances. This is the primary way to create a report object. ```rust 19fn main() { 20 println!("--- hypomnesis print_demo ---"); 21 22 let before = Snapshot::now(0).expect("Snapshot::now failed"); 23 24 // Allocate ~50 MiB on the heap to produce a visible RAM delta. 25 // Use vec![0_u8; ...] (zeroed allocation) so the OS commits pages. 26 let hold: Vec = vec![0_u8; 50 * 1024 * 1024]; 27 28 let after = Snapshot::now(0).expect("Snapshot::now failed"); 29 let report = MemoryReport::new(before, after); 30 31 println!("--- print_delta ---"); 32 report.print_delta("alloc 50 MiB"); 33 34 println!("--- print_before_after ---"); 35 report.print_before_after("alloc 50 MiB"); 36 37 println!("--- format_delta (returned as String, no newline added by us) ---"); 38 print!("{}", report.format_delta("alloc 50 MiB")); 39 40 println!("--- format_before_after (returned as String, no newline added by us) ---"); 41 print!("{}", report.format_before_after("alloc 50 MiB")); 42 43 // Keep the allocation alive until here so the after-snapshot still 44 // reflects it (otherwise the optimizer could elide `hold`). 45 drop(hold); 46} ``` -------------------------------- ### Helper to build Snapshot with no GPU data Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/report.rs.html A test helper function to construct a `Snapshot` struct with only RAM information, setting GPU-related fields to `None`. ```Rust /// Build a Snapshot with no GPU data at all. fn snapshot_no_gpu(ram: u64) -> Snapshot { Snapshot { ram_bytes: ram, gpu: None, gpu_device: None, } } ``` -------------------------------- ### Bounds Check Device Index (NVML) Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/gpu/mod.rs.html Performs a bounds check on the device index using the NVML backend. Returns an error if the index is out of range. ```rust #[cfg(feature = "nvml")] if let Some(count) = nvml::device_count() { return if index >= count { Err(HypomnesisError::DeviceIndexOutOfRange { index, count }) } else { Ok(()) }; } ``` -------------------------------- ### device_info Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/gpu/index.html Retrieves device-wide information for a specific GPU index, using NVML-canonical ordering. ```APIDOC ## device_info ### Description Device-wide info for a specific GPU index (`NVML`-canonical ordering). ### Method Not applicable (function call) ### Endpoint Not applicable (function call) ### Parameters #### Path Parameters - **index** (integer) - Required - The index of the GPU to query. ### Response - **info** (object) - Device-specific information. ``` -------------------------------- ### Snapshot::ram_mb Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/snapshot/struct.Snapshot.html Calculates the process's Resident Set Size (RSS) usage in megabytes. ```APIDOC ## pub fn ram_mb(&self) -> f64 ### Description `RAM` (`RSS`) usage as megabytes (`bytes / 1_048_576`). ### Parameters - **self** (&Self) - Required - A reference to the Snapshot instance. ### Returns f64 - The RAM usage in megabytes. ``` -------------------------------- ### Test: RAM MB Conversion for Zero Bytes Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/snapshot.rs.html Verifies that `ram_mb()` returns zero when the RAM in bytes is zero. ```rust #[cfg(feature = "report")] #[test] fn ram_mb_zero() { let snap = make_snapshot(0, None, false, 0); assert!(snap.ram_mb().abs() < 0.001); } ``` -------------------------------- ### Converting &Result to Result<&T, &E> Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/error/type.Result.html Illustrates the `as_ref` method, which converts a reference to a `Result` into a `Result<&T, &E>`, allowing access to the contained values without consuming the original Result. ```Rust let x: Result = Ok(2); assert_eq!(x.as_ref(), Ok(&2)); let x: Result = Err("Error"); assert_eq!(x.as_ref(), Err(&"Error")); ``` -------------------------------- ### Format Before and After Without VRAM Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/report.rs.html Formats a report showing before and after RAM states, when no VRAM information is available. ```rust let before = snapshot_no_gpu(100 * 1_048_576); let after = snapshot_no_gpu(150 * 1_048_576); let report = MemoryReport::new(before, after); let s = report.format_before_after("cpu_only"); assert_eq!(s, " cpu_only: RAM 100 MB → 150 MB (+50 MB)\n"); ``` -------------------------------- ### Test: VRAM MB Returns None When No GPU Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/snapshot.rs.html Confirms that `vram_mb()` returns `None` when the `Snapshot` does not contain any GPU information. ```rust #[cfg(feature = "report")] #[test] fn vram_mb_none_when_no_gpu() { let snap = make_snapshot(100, None, false, 0); assert!(snap.vram_mb().is_none()); } ``` -------------------------------- ### NVML Query Function Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/gpu/nvml.rs.html Implements a function to perform a complete NVML query for a given device index. It loads the NVML library, initializes it, queries device details, and shuts down NVML. ```rust /// Run a single `NVML` query session for the given device index. /// /// Loads `NVML`, runs init, queries the device handle, device-wide memory /// info, adapter name, and per-process info, then shuts `NVML` down before /// returning. Per-process query failures are tolerated /// (`process_used_bytes = None`) since the device-wide info is still /// useful. If the library load, init, handle, or device memory query /// fails, the function returns `None`. #[allow(unsafe_code)] pub(super) fn query(idx: u32) -> Option { // SAFETY: libloading::Library::new dynamically loads a shared library. // NVML is a stable NVIDIA driver component with a well-defined C ABI; // the library is reference-counted by the OS and unloaded when `lib` // is dropped at scope exit. let lib = unsafe { libloading::Library::new(NVML_LIB_PATH) }.ok()?; // SAFETY: Loading function symbols from the NVML library. Each name // matches the documented NVML C API exactly. The function signatures // (type aliases above) match the NVML header definitions. let init: libloading::Symbol<'_, NvmlInitFn> = unsafe { lib.get(b"nvmlInit_v2\0") }.ok()?; let shutdown: libloading::Symbol<'_, NvmlShutdownFn> = unsafe { lib.get(b"nvmlShutdown\0") }.ok()?; let get_handle: libloading::Symbol<'_, NvmlDeviceGetHandleByIndexFn> = unsafe { lib.get(b"nvmlDeviceGetHandleByIndex_v2\0") }.ok()?; let get_memory: libloading::Symbol<'_, NvmlDeviceGetMemoryInfoFn> = unsafe { lib.get(b"nvmlDeviceGetMemoryInfo\0") }.ok()?; let get_processes: libloading::Symbol<'_, NvmlDeviceGetComputeRunningProcessesFn> = unsafe { lib.get(b"nvmlDeviceGetComputeRunningProcesses_v3\0") }.ok()?; let get_name: libloading::Symbol<'_, NvmlDeviceGetNameFn> = unsafe { lib.get(b"nvmlDeviceGetName\0") }.ok()?; // SAFETY: nvmlInit_v2 is reentrant + thread-safe; it initializes // internal NVML state. NVML_SUCCESS (0) is the success return code. let ret = unsafe { init() }; if ret != NVML_SUCCESS { #[cfg(feature = "debug-output")] eprintln!("[NVML debug] nvmlInit_v2 returned {ret}"); return None; } // From here, every return path MUST call shutdown to balance the init. // SAFETY: nvmlDeviceGetHandleByIndex_v2 writes a valid opaque handle // into `device` when it returns NVML_SUCCESS. The pointer is owned // by NVML (we treat it as opaque). let mut device: NvmlDevice = std::ptr::null_mut(); let ret = unsafe { get_handle(idx, &raw mut device) }; if ret != NVML_SUCCESS { #[cfg(feature = "debug-output")] eprintln!("[NVML debug] nvmlDeviceGetHandleByIndex_v2(idx={idx}) returned {ret}"); // SAFETY: nvmlShutdown is always safe to call after a successful nvmlInit. unsafe { shutdown() }; return None; } // SAFETY: nvmlDeviceGetMemoryInfo writes into the caller-provided // NvmlMemoryInfo struct. The device handle is valid (acquired above // with NVML_SUCCESS). let mut mem_info = NvmlMemoryInfo { total: 0, free: 0, used: 0, }; ``` -------------------------------- ### Using or to provide a default Result Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/error/type.Result.html Illustrates the `or` method, which returns the `Ok` value of `self` if it's `Ok`, otherwise returns the provided `Result`. Arguments are eagerly evaluated. ```rust let x: Result = Ok(2); let y: Result = Err("late error"); assert_eq!(x.or(y), Ok(2)); let x: Result = Err("early error"); let y: Result = Ok(2); assert_eq!(x.or(y), Ok(2)); let x: Result = Err("not a 2"); let y: Result = Err("late error"); assert_eq!(x.or(y), Err("late error")); let x: Result = Ok(2); let y: Result = Ok(100); assert_eq!(x.or(y), Ok(2)); ``` -------------------------------- ### device_count Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/gpu/mod.rs.html Retrieves the total number of GPUs detected by the system. It prioritizes NVML, then falls back to DXGI on Windows if NVML is unavailable. Returns an error if no GPU source is enabled or successful. ```APIDOC ## device_count ### Description Returns the number of GPUs available on the system. The function attempts to use NVML first, and on Windows, it falls back to DXGI if NVML is not available. If no enabled backend can successfully report a count, it returns an error. ### Method ``` fn device_count() -> Result ``` ### Errors - `HypomnesisError::NoGpuSource`: If no GPU enumeration backend is enabled or if all enabled backends fail to report a count. ``` -------------------------------- ### impl Result, E> Source: https://docs.rs/hypomnesis/0.1.0/hypomnesis/error/type.Result.html Implementation for `Result, E>` providing the `transpose` method. ```APIDOC ## Implementations for Result, E> ### `pub const fn transpose(self) -> Option>` Transposes a `Result` of an `Option` into an `Option` of a `Result`. `Ok(None)` will be mapped to `None`. `Ok(Some(_))` and `Err(_)` will be mapped to `Some(Ok(_))` and `Some(Err(_))`. #### Parameters * `self`: The `Result, E>` to transpose. #### Returns An `Option>`. #### Examples ```rust #[derive(Debug, Eq, PartialEq)] struct SomeErr; let x: Result, SomeErr> = Ok(Some(5)); let y: Option> = Some(Ok(5)); assert_eq!(x.transpose(), y); ``` ``` -------------------------------- ### Test: VRAM MB Returns Some When GPU Present Source: https://docs.rs/hypomnesis/0.1.0/src/hypomnesis/snapshot.rs.html Checks that `vram_mb()` correctly returns the VRAM usage in megabytes when GPU information is available. ```rust #[cfg(feature = "report")] #[test] fn vram_mb_some_when_gpu_present() { let snap = make_snapshot(100, Some(2 * 1_048_576), true, 16 * 1_048_576); assert!((snap.vram_mb().unwrap() - 2.0).abs() < 0.001); } ```