llama_cpp_2/
llama_backend.rs1use crate::LlamaCppError;
4use llama_cpp_sys_2::ggml_log_level;
5use std::sync::atomic::AtomicBool;
6use std::sync::atomic::Ordering::SeqCst;
7
8#[derive(Eq, PartialEq, Debug)]
12pub struct LlamaBackend {}
13
14static LLAMA_BACKEND_INITIALIZED: AtomicBool = AtomicBool::new(false);
15
16impl LlamaBackend {
17 fn mark_init() -> crate::Result<()> {
19 match LLAMA_BACKEND_INITIALIZED.compare_exchange(false, true, SeqCst, SeqCst) {
20 Ok(_) => Ok(()),
21 Err(_) => Err(LlamaCppError::BackendAlreadyInitialized),
22 }
23 }
24
25 #[tracing::instrument(skip_all)]
45 pub fn init() -> crate::Result<LlamaBackend> {
46 Self::mark_init()?;
47 unsafe { llama_cpp_sys_2::llama_backend_init() }
48 Ok(LlamaBackend {})
49 }
50
51 #[tracing::instrument(skip_all)]
65 pub fn init_numa(strategy: NumaStrategy) -> crate::Result<LlamaBackend> {
66 let this = Self::init()?;
68 unsafe {
69 llama_cpp_sys_2::llama_numa_init(llama_cpp_sys_2::ggml_numa_strategy::from(strategy));
70 }
71 Ok(this)
72 }
73
74 pub fn supports_gpu_offload(&self) -> bool {
76 unsafe { llama_cpp_sys_2::llama_supports_gpu_offload() }
77 }
78
79 pub fn supports_mmap(&self) -> bool {
81 unsafe { llama_cpp_sys_2::llama_supports_mmap() }
82 }
83
84 pub fn supports_mlock(&self) -> bool {
86 unsafe { llama_cpp_sys_2::llama_supports_mlock() }
87 }
88
89 pub fn void_logs(&mut self) {
91 unsafe extern "C" fn void_log(
92 _level: ggml_log_level,
93 _text: *const ::std::os::raw::c_char,
94 _user_data: *mut ::std::os::raw::c_void,
95 ) {
96 }
97
98 unsafe {
99 llama_cpp_sys_2::llama_log_set(Some(void_log), std::ptr::null_mut());
100 }
101 }
102}
103
104#[derive(Debug, Eq, PartialEq, Copy, Clone)]
106pub enum NumaStrategy {
107 DISABLED,
109 DISTRIBUTE,
111 ISOLATE,
113 NUMACTL,
115 MIRROR,
117 COUNT,
119}
120
121#[derive(Debug, Eq, PartialEq, Copy, Clone)]
123pub struct InvalidNumaStrategy(
124 pub llama_cpp_sys_2::ggml_numa_strategy,
126);
127
128impl TryFrom<llama_cpp_sys_2::ggml_numa_strategy> for NumaStrategy {
129 type Error = InvalidNumaStrategy;
130
131 fn try_from(value: llama_cpp_sys_2::ggml_numa_strategy) -> Result<Self, Self::Error> {
132 match value {
133 llama_cpp_sys_2::GGML_NUMA_STRATEGY_DISABLED => Ok(Self::DISABLED),
134 llama_cpp_sys_2::GGML_NUMA_STRATEGY_DISTRIBUTE => Ok(Self::DISTRIBUTE),
135 llama_cpp_sys_2::GGML_NUMA_STRATEGY_ISOLATE => Ok(Self::ISOLATE),
136 llama_cpp_sys_2::GGML_NUMA_STRATEGY_NUMACTL => Ok(Self::NUMACTL),
137 llama_cpp_sys_2::GGML_NUMA_STRATEGY_MIRROR => Ok(Self::MIRROR),
138 llama_cpp_sys_2::GGML_NUMA_STRATEGY_COUNT => Ok(Self::COUNT),
139 value => Err(InvalidNumaStrategy(value)),
140 }
141 }
142}
143
144impl From<NumaStrategy> for llama_cpp_sys_2::ggml_numa_strategy {
145 fn from(value: NumaStrategy) -> Self {
146 match value {
147 NumaStrategy::DISABLED => llama_cpp_sys_2::GGML_NUMA_STRATEGY_DISABLED,
148 NumaStrategy::DISTRIBUTE => llama_cpp_sys_2::GGML_NUMA_STRATEGY_DISTRIBUTE,
149 NumaStrategy::ISOLATE => llama_cpp_sys_2::GGML_NUMA_STRATEGY_ISOLATE,
150 NumaStrategy::NUMACTL => llama_cpp_sys_2::GGML_NUMA_STRATEGY_NUMACTL,
151 NumaStrategy::MIRROR => llama_cpp_sys_2::GGML_NUMA_STRATEGY_MIRROR,
152 NumaStrategy::COUNT => llama_cpp_sys_2::GGML_NUMA_STRATEGY_COUNT,
153 }
154 }
155}
156
157impl Drop for LlamaBackend {
173 fn drop(&mut self) {
174 match LLAMA_BACKEND_INITIALIZED.compare_exchange(true, false, SeqCst, SeqCst) {
175 Ok(_) => {}
176 Err(_) => {
177 unreachable!("This should not be reachable as the only ways to obtain a llama backend involve marking the backend as initialized.")
178 }
179 }
180 unsafe { llama_cpp_sys_2::llama_backend_free() }
181 }
182}
183
184#[cfg(feature = "dynamic-backends")]
189pub fn load_backends_from_path(path: &std::path::Path) {
190 let s = std::ffi::CString::new(path.to_str().expect("path must be valid UTF-8"))
191 .expect("path must not contain null bytes");
192 unsafe { llama_cpp_sys_2::ggml_backend_load_all_from_path(s.as_ptr()) }
193}
194
195#[cfg(feature = "dynamic-backends")]
200pub fn load_backends() {
201 if let Some(dir) = llama_cpp_sys_2::BACKENDS_DIR {
202 load_backends_from_path(std::path::Path::new(dir));
203 }
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209
210 #[test]
211 fn numa_from_and_to() {
212 let numas = [
213 NumaStrategy::DISABLED,
214 NumaStrategy::DISTRIBUTE,
215 NumaStrategy::ISOLATE,
216 NumaStrategy::NUMACTL,
217 NumaStrategy::MIRROR,
218 NumaStrategy::COUNT,
219 ];
220
221 for numa in &numas {
222 let from = llama_cpp_sys_2::ggml_numa_strategy::from(*numa);
223 let to = NumaStrategy::try_from(from).expect("Failed to convert from and to");
224 assert_eq!(*numa, to);
225 }
226 }
227
228 #[test]
229 fn check_invalid_numa() {
230 let invalid = 800;
231 let invalid = NumaStrategy::try_from(invalid);
232 assert_eq!(invalid, Err(InvalidNumaStrategy(invalid.unwrap_err().0)));
233 }
234}