test-smi-rs 0.1.2

APIs for managing and monitoring FuriosaAI NPUs
Documentation
//! # Furiosa System Management Interface Python Binding
//!
//! ## Overview
//! Furiosa System Management Interface, is a programmatic interface for managing and monitoring FuriosaAI NPUs.
//!
//! The interface provides the following API modules, each designed to offer distinct functionalities for managing and monitoring NPU devices.
//! These modules enable developers to access essential hardware information, topology details, system-wide information, and performance metrics.
//!
//! The goal of the `furiosa-smi-rs` crate is to provide wrappers around the C furiosa-smi API.
//!
//! ### Device Module
//! Provides NPU device discovery and information.
//!
//! - **Features:**
//!     - Device Specifications
//!     - Liveness
//!     - Error Status
//!
//! ### Topology Module
//! Provides the device topology status within the system.
//!
//! - **Features:**
//!     - Device-to-Device Link Type
//!
//! ### System Module
//! Provides system-wide information about NPU devices.
//!
//! - **Features:**
//!     - Driver Information
//!
//! ### Performance Module
//! Provides NPU device performance status and metrics.
//!
//! - **Features:**
//!     - Power Consumption
//!     - Temperature
//!     - Core Utilization
//!     - Memory Utilization
//!     - Performance Counter
//!
//! ## Installation
//!
//! Run the following Cargo command in your project directory:
//!
//! ```bash
//! cargo add furiosa-smi-rs
//! ```
//!
//! Or add the following line to your Cargo.toml:
//! ```toml
//! furiosa-smi-rs = "0.1.0"
//! ```
//!
//! ## Usage example
//!
//! To get started with Furiosa-smi-rs, simply import the `test_smi_rs` crate and utilize its functions to interact with NPU devices. The package provides various methods to access the NPU device information and status.
//!
//! ```rust,no_run
//! use test_smi_rs::{Device, SmiResult};
//!
//! fn main() -> SmiResult<()> {
//!     // Retrieve a list of NPU devices in the system.
//!     let devices: Vec<Device> = test_smi_rs::list_devices()?;
//!
//!     for device in devices.iter() {
//!         // Acquire information about the NPU device.
//!         let device_info = device.device_info()?;
//!         println!("Device Info");
//!         println!("\t\tDevice Arch: {:?}", device_info.arch());
//!         println!("\t\tDevice Cores: {:?}", device_info.core_num());
//!     }
//!
//!     // You can use other APIs. Please refer to the documentation.
//!     Ok(())
//! }
//! ```
//!
//! The expected output is as below.
//!
//! ```bash
//! Device Info
//!         Device Arch: Rngd
//!         Device Cores: 8
//!
//!         ...
//! ```

#![allow(non_upper_case_globals)]

pub use crate::core_status::*;
pub use crate::device::*;
pub use crate::device_error_info::*;
pub use crate::device_file::*;
pub use crate::device_info::*;
pub use crate::error::*;
use crate::generated::binding::*;
pub use crate::performance::*;
pub use crate::types::*;
pub use crate::version::*;
use std::sync::{Arc, RwLock};

mod core_status;
mod device;
mod device_error_info;
mod device_file;
mod device_info;
mod error;
mod generated;
mod performance;
mod types;
mod util;
mod version;

#[allow(clippy::arc_with_non_send_sync)]
/// List all Furiosa NPU devices in the system.
pub fn list_devices() -> SmiResult<Vec<Device>> {
    let mut output = FuriosaSmiDeviceHandles {
        count: 0,
        device_handles: [0; FURIOSA_SMI_MAX_DEVICE_HANDLE_SIZE as usize],
    };

    let observer_instance = Arc::new(RwLock::new(create_observer()?));

    match unsafe { furiosa_smi_get_device_handles(&mut output as *mut FuriosaSmiDeviceHandles) } {
        FuriosaSmiReturnCode_FURIOSA_SMI_RETURN_CODE_OK => {
            let mut devices = Vec::with_capacity(output.count as usize);
            for i in 0..output.count as usize {
                devices.push(new_device(
                    output.device_handles[i],
                    observer_instance.clone(),
                ));
            }
            Ok(devices)
        }
        err => Err(SmiError::from(err)),
    }
}

/// Print a driver information of the device.
pub fn driver_info() -> SmiResult<VersionInfo> {
    let mut output = default_version_info();

    match unsafe { furiosa_smi_get_driver_info(&mut output as *mut FuriosaSmiVersion) } {
        FuriosaSmiReturnCode_FURIOSA_SMI_RETURN_CODE_OK => Ok(new_version_info(output)),
        err => Err(SmiError::from(err)),
    }
}

fn create_observer() -> SmiResult<DeviceObserverInstance> {
    let mut observer_instance: FuriosaSmiObserverInstance = default_observer_instance();

    match unsafe {
        furiosa_smi_create_observer(&mut observer_instance as *mut FuriosaSmiObserverInstance)
    } {
        FuriosaSmiReturnCode_FURIOSA_SMI_RETURN_CODE_OK => {
            Ok(new_observer_instance(observer_instance))
        }
        err => Err(SmiError::from(err)),
    }
}