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#[derive(Debug, Clone)]
8pub struct LlamaBackendDevice {
9    pub index: usize,
10    pub name: String,
11    pub description: String,
12    pub backend: String,
13    pub memory_total: usize,
14    pub memory_free: usize,
15    pub device_type: LlamaBackendDeviceType,
16}
17
18fn cstr_to_string(ptr: *const c_char) -> String {
19    if ptr.is_null() {
20        String::new()
21    } else {
22        unsafe { std::ffi::CStr::from_ptr(ptr) }
23            .to_string_lossy()
24            .to_string()
25    }
26}
27
28#[must_use]
29pub fn list_llama_ggml_backend_devices() -> Vec<LlamaBackendDevice> {
30    let mut devices = Vec::new();
31    let device_count = unsafe { llama_cpp_bindings_sys::ggml_backend_dev_count() };
32
33    for device_index in 0..device_count {
34        let dev = unsafe { llama_cpp_bindings_sys::ggml_backend_dev_get(device_index) };
35        let props = unsafe {
36            let mut props = std::mem::zeroed();
37            llama_cpp_bindings_sys::ggml_backend_dev_get_props(dev, &raw mut props);
38            props
39        };
40        let name = cstr_to_string(props.name);
41        let description = cstr_to_string(props.description);
42        let backend_reg = unsafe { llama_cpp_bindings_sys::ggml_backend_dev_backend_reg(dev) };
43        let backend_name = unsafe { llama_cpp_bindings_sys::ggml_backend_reg_name(backend_reg) };
44        let backend = cstr_to_string(backend_name);
45        let memory_total = props.memory_total;
46        let memory_free = props.memory_free;
47        let device_type = device_type_from_raw(props.type_);
48        devices.push(LlamaBackendDevice {
49            index: device_index,
50            name,
51            description,
52            backend,
53            memory_total,
54            memory_free,
55            device_type,
56        });
57    }
58
59    devices
60}
61
62#[cfg(test)]
63mod tests {
64    use super::{cstr_to_string, list_llama_ggml_backend_devices};
65
66    #[test]
67    fn cstr_to_string_with_null_returns_empty() {
68        let result = cstr_to_string(std::ptr::null());
69
70        assert_eq!(result, "");
71    }
72
73    #[test]
74    fn cstr_to_string_with_valid_ptr() {
75        let result = cstr_to_string(c"hello".as_ptr());
76
77        assert_eq!(result, "hello");
78    }
79
80    #[test]
81    fn list_devices_returns_at_least_one() {
82        #[cfg(feature = "dynamic-backends")]
83        crate::load_backends::load_backends().unwrap();
84
85        let devices = list_llama_ggml_backend_devices();
86        assert!(!devices.is_empty());
87        assert_eq!(devices[0].index, 0);
88        assert!(!devices[0].name.is_empty());
89    }
90}