Skip to main content

llama_cpp_bindings/
llama_backend_device.rs

1use std::ffi::c_char;
2
3use crate::llama_backend_device_type::device_type_from_raw;
4
5pub use crate::llama_backend_device_type::LlamaBackendDeviceType;
6
7/// A ggml backend device
8///
9/// The index is can be used from `LlamaModelParams::with_devices` to select specific devices.
10#[derive(Debug, Clone)]
11pub struct LlamaBackendDevice {
12    /// The index of the device
13    ///
14    /// The index is can be used from `LlamaModelParams::with_devices` to select specific devices.
15    pub index: usize,
16    /// The name of the device (e.g. "Vulkan0")
17    pub name: String,
18    /// A description of the device (e.g. "NVIDIA `GeForce` RTX 3080")
19    pub description: String,
20    /// The backend of the device (e.g. "Vulkan", "CUDA", "CPU")
21    pub backend: String,
22    /// Total memory of the device in bytes
23    pub memory_total: usize,
24    /// Free memory of the device in bytes
25    pub memory_free: usize,
26    /// Device type
27    pub device_type: LlamaBackendDeviceType,
28}
29
30fn cstr_to_string(ptr: *const c_char) -> String {
31    if ptr.is_null() {
32        String::new()
33    } else {
34        unsafe { std::ffi::CStr::from_ptr(ptr) }
35            .to_string_lossy()
36            .to_string()
37    }
38}
39
40/// List ggml backend devices
41#[must_use]
42pub fn list_llama_ggml_backend_devices() -> Vec<LlamaBackendDevice> {
43    let mut devices = Vec::new();
44    let device_count = unsafe { llama_cpp_bindings_sys::ggml_backend_dev_count() };
45
46    for device_index in 0..device_count {
47        let dev = unsafe { llama_cpp_bindings_sys::ggml_backend_dev_get(device_index) };
48        let props = unsafe {
49            let mut props = std::mem::zeroed();
50            llama_cpp_bindings_sys::ggml_backend_dev_get_props(dev, &raw mut props);
51            props
52        };
53        let name = cstr_to_string(props.name);
54        let description = cstr_to_string(props.description);
55        let backend_reg = unsafe { llama_cpp_bindings_sys::ggml_backend_dev_backend_reg(dev) };
56        let backend_name = unsafe { llama_cpp_bindings_sys::ggml_backend_reg_name(backend_reg) };
57        let backend = cstr_to_string(backend_name);
58        let memory_total = props.memory_total;
59        let memory_free = props.memory_free;
60        let device_type = device_type_from_raw(props.type_);
61        devices.push(LlamaBackendDevice {
62            index: device_index,
63            name,
64            description,
65            backend,
66            memory_total,
67            memory_free,
68            device_type,
69        });
70    }
71
72    devices
73}
74
75#[cfg(test)]
76mod tests {
77    use super::{cstr_to_string, list_llama_ggml_backend_devices};
78
79    #[test]
80    fn cstr_to_string_with_null_returns_empty() {
81        let result = cstr_to_string(std::ptr::null());
82
83        assert_eq!(result, "");
84    }
85
86    #[test]
87    fn cstr_to_string_with_valid_ptr() {
88        let result = cstr_to_string(c"hello".as_ptr());
89
90        assert_eq!(result, "hello");
91    }
92
93    #[test]
94    fn list_devices_returns_at_least_one() {
95        #[cfg(feature = "dynamic-backends")]
96        crate::load_backends::load_backends().unwrap();
97
98        let devices = list_llama_ggml_backend_devices();
99        assert!(!devices.is_empty());
100        assert_eq!(devices[0].index, 0);
101        assert!(!devices[0].name.is_empty());
102    }
103}