furiosa_device/lib.rs
1//! A set of APIs to list and retrieve information of FuriosaAI's NPU devices.
2//! To learn more about FuriosaAI's NPU, please visit <https://furiosa.ai>.
3//!
4//! # Before you start
5//!
6//! This crate requires FuriosaAI's NPU device and its kernel driver. Currently, FuriosaAI offers
7//! NPU devices for only users who register Early Access Program (EAP). Please contact
8//! <contact@furiosa.ai> to learn how to start the EAP. You can also refer to
9//! [Driver, Firmware, and Runtime Installation](https://furiosa-ai.github.io/docs/latest/en/software/installation.html)
10//! to learn the kernel driver installation.
11//!
12//! # Usage
13//!
14//! Add this to your 'Cargo.toml':
15//! ```toml
16//! [dependencies]
17//! furiosa-device = "0.1"
18//! ```
19//!
20//! ## Listing devices from the system
21//!
22//! The current implementation mainly offers two APIs, namely
23//! [`list_devices`] and [`find_device_files`].
24//!
25//! 1. [`list_devices`] enumerates all Furiosa NPU devices in the system.
26//! One can simply call as below:
27//! ```rust,no_run
28//! # #[tokio::main]
29//! # async fn main() -> eyre::Result<()> {
30//! let devices = furiosa_device::list_devices().await?;
31//! # Ok(())
32//! # }
33//! ```
34//!
35//! [Struct `Device`][`Device`] offers methods for further information of each
36//! device.
37//!
38//! 2. If you have a desired configuration, call [`find_device_files`] with your device configuration
39//! described by a [`DeviceConfig`]. [`find_device_files`] will return a list of
40//! [`DeviceFile`]s if there are matched devices.
41//! ```rust,no_run
42//! use furiosa_device::{find_device_files, DeviceConfig};
43//!
44//! // Find two Warboy devices, fused.
45//! # #[tokio::main]
46//! # async fn main() -> eyre::Result<()> {
47//! let config = DeviceConfig::warboy().fused().count(2);
48//! let dev_files = find_device_files(&config).await?;
49//! # Ok(())
50//! # }
51//! ```
52//!
53//! 3. In case you have prior knowledge on the system and want to pick out a
54//! device with specific name, use [`get_device_file`].
55//! ```rust,no_run
56//! # #[tokio::main]
57//! # async fn main() -> eyre::Result<()> {
58//! let device_file = furiosa_device::get_device_file("npu0pe0").await?;
59//! # Ok(())
60//! # }
61//! ```
62
63// Allows displaying feature flags in the documentation.
64#![cfg_attr(docsrs, feature(doc_cfg))]
65#![feature(associated_type_bounds)]
66
67pub use crate::arch::Arch;
68use crate::config::{expand_status, find_device_files_in};
69pub use crate::config::{DeviceConfig, DeviceConfigBuilder, EnvBuilder, NotDetermined};
70pub use crate::device::{
71 ClockFrequency, CoreRange, CoreStatus, Device, DeviceFile, DeviceMode, NumaNode,
72};
73pub use crate::error::{DeviceError, DeviceResult};
74use crate::list::{get_device_with, list_devices_with};
75
76mod arch;
77#[cfg(feature = "blocking")]
78#[cfg_attr(docsrs, doc(cfg(feature = "blocking")))]
79pub mod blocking;
80mod config;
81mod devfs;
82mod device;
83mod error;
84pub mod hwmon;
85mod list;
86pub mod perf_regs;
87pub mod proc;
88mod status;
89mod sysfs;
90
91/// List all Furiosa NPU devices in the system.
92///
93/// See the [crate-level documentation](crate).
94pub async fn list_devices() -> DeviceResult<Vec<Device>> {
95 list_devices_with("/dev", "/sys").await
96}
97
98/// Return a specific Furiosa NPU device in the system.
99///
100/// # Arguments
101///
102/// * `idx` - An index number of the device (e.g., 0, 1)
103///
104/// See the [crate-level documentation](crate).
105pub async fn get_device(idx: u8) -> DeviceResult<Device> {
106 get_device_with(idx, "/dev", "/sys").await
107}
108
109/// Find a set of devices with specific configuration.
110///
111/// # Arguments
112///
113/// * `config` - DeviceConfig
114///
115/// See the [crate-level documentation](crate).
116pub async fn find_device_files(config: &DeviceConfig) -> DeviceResult<Vec<DeviceFile>> {
117 let devices = expand_status(list_devices().await?).await?;
118 find_device_files_in(config, &devices)
119}
120
121/// Return a specific device if it exists.
122///
123/// # Arguments
124///
125/// * `device_name` - A device name (e.g., npu0, npu0pe0, npu0pe0-1)
126///
127/// See the [crate-level documentation](crate).
128pub async fn get_device_file<S: AsRef<str>>(device_name: S) -> DeviceResult<DeviceFile> {
129 get_device_file_with("/dev", device_name.as_ref()).await
130}
131
132pub(crate) async fn get_device_file_with(
133 devfs: &str,
134 device_name: &str,
135) -> DeviceResult<DeviceFile> {
136 let path = devfs::path(devfs, device_name);
137 if !path.exists() {
138 return Err(DeviceError::DeviceNotFound {
139 name: device_name.to_string(),
140 });
141 }
142
143 let file = tokio::fs::File::open(&path).await?;
144 if !devfs::is_character_device(file.metadata().await?.file_type()) {
145 return Err(DeviceError::invalid_device_file(path.display()));
146 }
147
148 devfs::parse_indices(path.file_name().expect("not a file").to_string_lossy())?;
149
150 DeviceFile::try_from(&path)
151}