/src/llama.cpp/ggml/src/ggml-backend-reg.cpp
Line | Count | Source |
1 | | #include "ggml-backend-impl.h" |
2 | | #include "ggml-backend.h" |
3 | | #include "ggml-backend-dl.h" |
4 | | #include "ggml-impl.h" |
5 | | #include <algorithm> |
6 | | #include <cstring> |
7 | | #include <filesystem> |
8 | | #include <memory> |
9 | | #include <string> |
10 | | #include <type_traits> |
11 | | #include <vector> |
12 | | #include <cctype> |
13 | | |
14 | | #ifdef _WIN32 |
15 | | # define WIN32_LEAN_AND_MEAN |
16 | | # ifndef NOMINMAX |
17 | | # define NOMINMAX |
18 | | # endif |
19 | | # include <windows.h> |
20 | | #elif defined(__APPLE__) |
21 | | # include <mach-o/dyld.h> |
22 | | # include <dlfcn.h> |
23 | | #else |
24 | | # include <dlfcn.h> |
25 | | # include <unistd.h> |
26 | | #endif |
27 | | |
28 | | // Backend registry |
29 | | #ifdef GGML_USE_CPU |
30 | | #include "ggml-cpu.h" |
31 | | #endif |
32 | | |
33 | | #ifdef GGML_USE_CUDA |
34 | | #include "ggml-cuda.h" |
35 | | #endif |
36 | | |
37 | | #ifdef GGML_USE_METAL |
38 | | #include "ggml-metal.h" |
39 | | #endif |
40 | | |
41 | | #ifdef GGML_USE_SYCL |
42 | | #include "ggml-sycl.h" |
43 | | #endif |
44 | | |
45 | | #ifdef GGML_USE_VULKAN |
46 | | #include "ggml-vulkan.h" |
47 | | #endif |
48 | | |
49 | | #ifdef GGML_USE_WEBGPU |
50 | | #include "ggml-webgpu.h" |
51 | | #endif |
52 | | |
53 | | #ifdef GGML_USE_ZDNN |
54 | | #include "ggml-zdnn.h" |
55 | | #endif |
56 | | |
57 | | #ifdef GGML_USE_OPENCL |
58 | | #include "ggml-opencl.h" |
59 | | #endif |
60 | | |
61 | | #ifdef GGML_USE_HEXAGON |
62 | | #include "ggml-hexagon.h" |
63 | | #endif |
64 | | |
65 | | #ifdef GGML_USE_BLAS |
66 | | #include "ggml-blas.h" |
67 | | #endif |
68 | | |
69 | | #ifdef GGML_USE_RPC |
70 | | #include "ggml-rpc.h" |
71 | | #endif |
72 | | |
73 | | #ifdef GGML_USE_VIRTGPU_FRONTEND |
74 | | #include "ggml-virtgpu.h" |
75 | | #endif |
76 | | |
77 | | #ifdef GGML_USE_CANN |
78 | | #include "ggml-cann.h" |
79 | | #endif |
80 | | |
81 | | #ifdef GGML_USE_ZENDNN |
82 | | #include "ggml-zendnn.h" |
83 | | #endif |
84 | | |
85 | | #ifdef GGML_USE_OPENVINO |
86 | | #include "ggml-openvino.h" |
87 | | #endif |
88 | | |
89 | | namespace fs = std::filesystem; |
90 | | |
91 | 0 | static std::string path_str(const fs::path & path) { |
92 | 0 | try { |
93 | | #if defined(__cpp_lib_char8_t) |
94 | | // C++20 and later: u8string() returns std::u8string |
95 | | const std::u8string u8str = path.u8string(); |
96 | | return std::string(reinterpret_cast<const char *>(u8str.data()), u8str.size()); |
97 | | #else |
98 | | // C++17: u8string() returns std::string |
99 | 0 | return path.u8string(); |
100 | 0 | #endif |
101 | 0 | } catch (...) { |
102 | 0 | return std::string(); |
103 | 0 | } |
104 | 0 | } |
105 | | |
106 | | struct ggml_backend_reg_entry { |
107 | | ggml_backend_reg_t reg; |
108 | | dl_handle_ptr handle; |
109 | | }; |
110 | | |
111 | | struct ggml_backend_registry { |
112 | | std::vector<ggml_backend_reg_entry> backends; |
113 | | std::vector<ggml_backend_dev_t> devices; |
114 | | |
115 | 0 | ggml_backend_registry() { |
116 | | #ifdef GGML_USE_CUDA |
117 | | register_backend(ggml_backend_cuda_reg()); |
118 | | #endif |
119 | | #ifdef GGML_USE_METAL |
120 | | register_backend(ggml_backend_metal_reg()); |
121 | | #endif |
122 | | #ifdef GGML_USE_SYCL |
123 | | register_backend(ggml_backend_sycl_reg()); |
124 | | #endif |
125 | | #ifdef GGML_USE_VULKAN |
126 | | // Add runtime disable check |
127 | | if (getenv("GGML_DISABLE_VULKAN") == nullptr) { |
128 | | register_backend(ggml_backend_vk_reg()); |
129 | | } else { |
130 | | GGML_LOG_DEBUG("Vulkan backend disabled by GGML_DISABLE_VULKAN environment variable\n"); |
131 | | } |
132 | | #endif |
133 | | #ifdef GGML_USE_WEBGPU |
134 | | register_backend(ggml_backend_webgpu_reg()); |
135 | | #endif |
136 | | #ifdef GGML_USE_ZDNN |
137 | | register_backend(ggml_backend_zdnn_reg()); |
138 | | #endif |
139 | | #ifdef GGML_USE_VIRTGPU_FRONTEND |
140 | | register_backend(ggml_backend_virtgpu_reg()); |
141 | | #endif |
142 | |
|
143 | | #ifdef GGML_USE_OPENCL |
144 | | register_backend(ggml_backend_opencl_reg()); |
145 | | #endif |
146 | | #ifdef GGML_USE_ZENDNN |
147 | | register_backend(ggml_backend_zendnn_reg()); |
148 | | #endif |
149 | | #ifdef GGML_USE_HEXAGON |
150 | | register_backend(ggml_backend_hexagon_reg()); |
151 | | #endif |
152 | | #ifdef GGML_USE_CANN |
153 | | register_backend(ggml_backend_cann_reg()); |
154 | | #endif |
155 | | #ifdef GGML_USE_BLAS |
156 | | register_backend(ggml_backend_blas_reg()); |
157 | | #endif |
158 | | #ifdef GGML_USE_RPC |
159 | | register_backend(ggml_backend_rpc_reg()); |
160 | | #endif |
161 | | #ifdef GGML_USE_OPENVINO |
162 | | register_backend(ggml_backend_openvino_reg()); |
163 | | #endif |
164 | 0 | #ifdef GGML_USE_CPU |
165 | 0 | register_backend(ggml_backend_cpu_reg()); |
166 | 0 | #endif |
167 | 0 | } |
168 | | |
169 | 0 | ~ggml_backend_registry() { |
170 | | // FIXME: backends cannot be safely unloaded without a function to destroy all the backend resources, |
171 | | // since backend threads may still be running and accessing resources from the dynamic library |
172 | 0 | for (auto & entry : backends) { |
173 | 0 | if (entry.handle) { |
174 | 0 | entry.handle.release(); // NOLINT |
175 | 0 | } |
176 | 0 | } |
177 | 0 | } |
178 | | |
179 | 0 | void register_backend(ggml_backend_reg_t reg, dl_handle_ptr handle = nullptr) { |
180 | 0 | if (!reg) { |
181 | 0 | return; |
182 | 0 | } |
183 | | |
184 | | #ifndef NDEBUG |
185 | | GGML_LOG_DEBUG("%s: registered backend %s (%zu devices)\n", |
186 | | __func__, ggml_backend_reg_name(reg), ggml_backend_reg_dev_count(reg)); |
187 | | #endif |
188 | 0 | backends.push_back({ reg, std::move(handle) }); |
189 | 0 | for (size_t i = 0; i < ggml_backend_reg_dev_count(reg); i++) { |
190 | 0 | register_device(ggml_backend_reg_dev_get(reg, i)); |
191 | 0 | } |
192 | 0 | } |
193 | | |
194 | 0 | void register_device(ggml_backend_dev_t device) { |
195 | | #ifndef NDEBUG |
196 | | GGML_LOG_DEBUG("%s: registered device %s (%s)\n", __func__, ggml_backend_dev_name(device), ggml_backend_dev_description(device)); |
197 | | #endif |
198 | 0 | devices.push_back(device); |
199 | 0 | } |
200 | | |
201 | 0 | ggml_backend_reg_t load_backend(const fs::path & path, bool silent) { |
202 | 0 | dl_handle_ptr handle { dl_load_library(path) }; |
203 | 0 | if (!handle) { |
204 | 0 | if (!silent) { |
205 | 0 | GGML_LOG_ERROR("%s: failed to load %s: %s\n", __func__, path_str(path).c_str(), dl_error()); |
206 | 0 | } |
207 | 0 | return nullptr; |
208 | 0 | } |
209 | | |
210 | 0 | auto score_fn = (ggml_backend_score_t) dl_get_sym(handle.get(), "ggml_backend_score"); |
211 | 0 | if (score_fn && score_fn() == 0) { |
212 | 0 | if (!silent) { |
213 | 0 | GGML_LOG_INFO("%s: backend %s is not supported on this system\n", __func__, path_str(path).c_str()); |
214 | 0 | } |
215 | 0 | return nullptr; |
216 | 0 | } |
217 | | |
218 | 0 | auto backend_init_fn = (ggml_backend_init_t) dl_get_sym(handle.get(), "ggml_backend_init"); |
219 | 0 | if (!backend_init_fn) { |
220 | 0 | if (!silent) { |
221 | 0 | GGML_LOG_ERROR("%s: failed to find ggml_backend_init in %s\n", __func__, path_str(path).c_str()); |
222 | 0 | } |
223 | 0 | return nullptr; |
224 | 0 | } |
225 | | |
226 | 0 | ggml_backend_reg_t reg = backend_init_fn(); |
227 | 0 | if (!reg || reg->api_version != GGML_BACKEND_API_VERSION) { |
228 | 0 | if (!silent) { |
229 | 0 | if (!reg) { |
230 | 0 | GGML_LOG_ERROR("%s: failed to initialize backend from %s: ggml_backend_init returned NULL\n", |
231 | 0 | __func__, path_str(path).c_str()); |
232 | 0 | } else { |
233 | 0 | GGML_LOG_ERROR("%s: failed to initialize backend from %s: incompatible API version (backend: %d, current: %d)\n", |
234 | 0 | __func__, path_str(path).c_str(), reg->api_version, GGML_BACKEND_API_VERSION); |
235 | 0 | } |
236 | 0 | } |
237 | 0 | return nullptr; |
238 | 0 | } |
239 | | |
240 | 0 | GGML_LOG_INFO("%s: loaded %s backend from %s\n", __func__, ggml_backend_reg_name(reg), path_str(path).c_str()); |
241 | |
|
242 | 0 | register_backend(reg, std::move(handle)); |
243 | |
|
244 | 0 | return reg; |
245 | 0 | } |
246 | | |
247 | 0 | void unload_backend(ggml_backend_reg_t reg, bool silent) { |
248 | 0 | auto it = std::find_if(backends.begin(), backends.end(), |
249 | 0 | [reg](const ggml_backend_reg_entry & entry) { return entry.reg == reg; }); |
250 | |
|
251 | 0 | if (it == backends.end()) { |
252 | 0 | if (!silent) { |
253 | 0 | GGML_LOG_ERROR("%s: backend not found\n", __func__); |
254 | 0 | } |
255 | 0 | return; |
256 | 0 | } |
257 | | |
258 | 0 | if (!silent) { |
259 | 0 | GGML_LOG_DEBUG("%s: unloading %s backend\n", __func__, ggml_backend_reg_name(reg)); |
260 | 0 | } |
261 | | |
262 | | // remove devices |
263 | 0 | devices.erase( |
264 | 0 | std::remove_if(devices.begin(), devices.end(), |
265 | 0 | [reg](ggml_backend_dev_t dev) { return ggml_backend_dev_backend_reg(dev) == reg; }), |
266 | 0 | devices.end()); |
267 | | |
268 | | // remove backend |
269 | 0 | backends.erase(it); |
270 | 0 | } |
271 | | }; |
272 | | |
273 | 0 | static ggml_backend_registry & get_reg() { |
274 | 0 | static ggml_backend_registry reg; |
275 | 0 | return reg; |
276 | 0 | } |
277 | | |
278 | | // Internal API |
279 | 0 | void ggml_backend_register(ggml_backend_reg_t reg) { |
280 | 0 | get_reg().register_backend(reg); |
281 | 0 | } |
282 | | |
283 | 0 | void ggml_backend_device_register(ggml_backend_dev_t device) { |
284 | 0 | get_reg().register_device(device); |
285 | 0 | } |
286 | | |
287 | | // Backend (reg) enumeration |
288 | 0 | static bool striequals(const char * a, const char * b) { |
289 | 0 | for (; *a && *b; a++, b++) { |
290 | 0 | if (std::tolower(*a) != std::tolower(*b)) { |
291 | 0 | return false; |
292 | 0 | } |
293 | 0 | } |
294 | 0 | return *a == *b; |
295 | 0 | } |
296 | | |
297 | 0 | size_t ggml_backend_reg_count() { |
298 | 0 | return get_reg().backends.size(); |
299 | 0 | } |
300 | | |
301 | 0 | ggml_backend_reg_t ggml_backend_reg_get(size_t index) { |
302 | 0 | GGML_ASSERT(index < ggml_backend_reg_count()); |
303 | 0 | return get_reg().backends[index].reg; |
304 | 0 | } |
305 | | |
306 | 0 | ggml_backend_reg_t ggml_backend_reg_by_name(const char * name) { |
307 | 0 | for (size_t i = 0; i < ggml_backend_reg_count(); i++) { |
308 | 0 | ggml_backend_reg_t reg = ggml_backend_reg_get(i); |
309 | 0 | if (striequals(ggml_backend_reg_name(reg), name)) { |
310 | 0 | return reg; |
311 | 0 | } |
312 | 0 | } |
313 | 0 | return nullptr; |
314 | 0 | } |
315 | | |
316 | | // Device enumeration |
317 | 0 | size_t ggml_backend_dev_count() { |
318 | 0 | return get_reg().devices.size(); |
319 | 0 | } |
320 | | |
321 | 0 | ggml_backend_dev_t ggml_backend_dev_get(size_t index) { |
322 | 0 | GGML_ASSERT(index < ggml_backend_dev_count()); |
323 | 0 | return get_reg().devices[index]; |
324 | 0 | } |
325 | | |
326 | 0 | ggml_backend_dev_t ggml_backend_dev_by_name(const char * name) { |
327 | 0 | for (size_t i = 0; i < ggml_backend_dev_count(); i++) { |
328 | 0 | ggml_backend_dev_t dev = ggml_backend_dev_get(i); |
329 | 0 | if (striequals(ggml_backend_dev_name(dev), name)) { |
330 | 0 | return dev; |
331 | 0 | } |
332 | 0 | } |
333 | 0 | return nullptr; |
334 | 0 | } |
335 | | |
336 | 0 | ggml_backend_dev_t ggml_backend_dev_by_type(enum ggml_backend_dev_type type) { |
337 | 0 | for (size_t i = 0; i < ggml_backend_dev_count(); i++) { |
338 | 0 | ggml_backend_dev_t dev = ggml_backend_dev_get(i); |
339 | 0 | if (ggml_backend_dev_type(dev) == type) { |
340 | 0 | return dev; |
341 | 0 | } |
342 | 0 | } |
343 | 0 | return nullptr; |
344 | 0 | } |
345 | | |
346 | | // Convenience functions |
347 | 0 | ggml_backend_t ggml_backend_init_by_name(const char * name, const char * params) { |
348 | 0 | ggml_backend_dev_t dev = ggml_backend_dev_by_name(name); |
349 | 0 | if (!dev) { |
350 | 0 | return nullptr; |
351 | 0 | } |
352 | 0 | return ggml_backend_dev_init(dev, params); |
353 | 0 | } |
354 | | |
355 | 0 | ggml_backend_t ggml_backend_init_by_type(enum ggml_backend_dev_type type, const char * params) { |
356 | 0 | ggml_backend_dev_t dev = ggml_backend_dev_by_type(type); |
357 | 0 | if (!dev) { |
358 | 0 | return nullptr; |
359 | 0 | } |
360 | 0 | return ggml_backend_dev_init(dev, params); |
361 | 0 | } |
362 | | |
363 | 0 | ggml_backend_t ggml_backend_init_best(void) { |
364 | 0 | ggml_backend_dev_t dev = ggml_backend_dev_by_type(GGML_BACKEND_DEVICE_TYPE_GPU); |
365 | 0 | dev = dev ? dev : ggml_backend_dev_by_type(GGML_BACKEND_DEVICE_TYPE_IGPU); |
366 | 0 | dev = dev ? dev : ggml_backend_dev_by_type(GGML_BACKEND_DEVICE_TYPE_CPU); |
367 | 0 | if (!dev) { |
368 | 0 | return nullptr; |
369 | 0 | } |
370 | 0 | return ggml_backend_dev_init(dev, nullptr); |
371 | 0 | } |
372 | | |
373 | | // Dynamic loading |
374 | 0 | ggml_backend_reg_t ggml_backend_load(const char * path) { |
375 | 0 | return get_reg().load_backend(path, false); |
376 | 0 | } |
377 | | |
378 | 0 | void ggml_backend_unload(ggml_backend_reg_t reg) { |
379 | 0 | get_reg().unload_backend(reg, true); |
380 | 0 | } |
381 | | |
382 | 0 | static fs::path get_executable_path() { |
383 | | #if defined(__APPLE__) |
384 | | // get executable path |
385 | | std::vector<char> path; |
386 | | uint32_t size; |
387 | | while (true) { |
388 | | size = path.size(); |
389 | | if (_NSGetExecutablePath(path.data(), &size) == 0) { |
390 | | break; |
391 | | } |
392 | | path.resize(size); |
393 | | } |
394 | | std::string base_path(path.data(), size); |
395 | | // remove executable name |
396 | | auto last_slash = base_path.find_last_of('/'); |
397 | | if (last_slash != std::string::npos) { |
398 | | base_path = base_path.substr(0, last_slash); |
399 | | } |
400 | | return base_path + "/"; |
401 | | #elif defined(__linux__) || defined(__FreeBSD__) |
402 | | std::string base_path = "."; |
403 | 0 | std::vector<char> path(1024); |
404 | 0 | while (true) { |
405 | | // get executable path |
406 | 0 | # if defined(__linux__) |
407 | 0 | ssize_t len = readlink("/proc/self/exe", path.data(), path.size()); |
408 | | # elif defined(__FreeBSD__) |
409 | | ssize_t len = readlink("/proc/curproc/file", path.data(), path.size()); |
410 | | # endif |
411 | 0 | if (len == -1) { |
412 | 0 | break; |
413 | 0 | } |
414 | 0 | if (len < (ssize_t) path.size()) { |
415 | 0 | base_path = std::string(path.data(), len); |
416 | | // remove executable name |
417 | 0 | auto last_slash = base_path.find_last_of('/'); |
418 | 0 | if (last_slash != std::string::npos) { |
419 | 0 | base_path = base_path.substr(0, last_slash); |
420 | 0 | } |
421 | 0 | break; |
422 | 0 | } |
423 | 0 | path.resize(path.size() * 2); |
424 | 0 | } |
425 | |
|
426 | 0 | return base_path + "/"; |
427 | | #elif defined(_WIN32) |
428 | | std::vector<wchar_t> path(MAX_PATH); |
429 | | DWORD len = GetModuleFileNameW(NULL, path.data(), path.size()); |
430 | | if (len == 0) { |
431 | | return {}; |
432 | | } |
433 | | std::wstring base_path(path.data(), len); |
434 | | // remove executable name |
435 | | auto last_slash = base_path.find_last_of('\\'); |
436 | | if (last_slash != std::string::npos) { |
437 | | base_path = base_path.substr(0, last_slash); |
438 | | } |
439 | | return base_path + L"\\"; |
440 | | #else |
441 | | return {}; |
442 | | #endif |
443 | 0 | } |
444 | | |
445 | 0 | static fs::path backend_filename_prefix() { |
446 | | #ifdef _WIN32 |
447 | | return fs::u8path("ggml-"); |
448 | | #else |
449 | 0 | return fs::u8path("libggml-"); |
450 | 0 | #endif |
451 | 0 | } |
452 | | |
453 | 0 | static fs::path backend_filename_extension() { |
454 | | #ifdef _WIN32 |
455 | | return fs::u8path(".dll"); |
456 | | #else |
457 | 0 | return fs::u8path(".so"); |
458 | 0 | #endif |
459 | 0 | } |
460 | | |
461 | 0 | static ggml_backend_reg_t ggml_backend_load_best(const char * name, bool silent, const char * user_search_path) { |
462 | | // enumerate all the files that match [lib]ggml-name-*.[so|dll] in the search paths |
463 | 0 | const fs::path name_path = fs::u8path(name); |
464 | 0 | const fs::path file_prefix = backend_filename_prefix().native() + name_path.native() + fs::u8path("-").native(); |
465 | 0 | const fs::path file_extension = backend_filename_extension(); |
466 | |
|
467 | 0 | std::vector<fs::path> search_paths; |
468 | 0 | if (user_search_path == nullptr) { |
469 | | #ifdef GGML_BACKEND_DIR |
470 | | search_paths.push_back(fs::u8path(GGML_BACKEND_DIR)); |
471 | | #endif |
472 | | // default search paths: executable directory, current directory |
473 | 0 | search_paths.push_back(get_executable_path()); |
474 | 0 | search_paths.push_back(fs::current_path()); |
475 | 0 | } else { |
476 | 0 | search_paths.push_back(fs::u8path(user_search_path)); |
477 | 0 | } |
478 | |
|
479 | 0 | int best_score = 0; |
480 | 0 | fs::path best_path; |
481 | 0 | std::error_code ec; |
482 | |
|
483 | 0 | for (const auto & search_path : search_paths) { |
484 | 0 | if (!fs::exists(search_path, ec)) { |
485 | 0 | if (ec) { |
486 | 0 | GGML_LOG_DEBUG("%s: posix_stat(%s) failure, error-message: %s\n", __func__, path_str(search_path).c_str(), ec.message().c_str()); |
487 | 0 | } else { |
488 | 0 | GGML_LOG_DEBUG("%s: search path %s does not exist\n", __func__, path_str(search_path).c_str()); |
489 | 0 | } |
490 | 0 | continue; |
491 | 0 | } |
492 | 0 | fs::directory_iterator dir_it(search_path, fs::directory_options::skip_permission_denied); |
493 | 0 | for (const auto & entry : dir_it) { |
494 | 0 | if (entry.is_regular_file(ec)) { |
495 | 0 | auto filename = entry.path().filename(); |
496 | 0 | auto ext = entry.path().extension(); |
497 | 0 | if (filename.native().find(file_prefix) == 0 && ext == file_extension) { |
498 | 0 | dl_handle_ptr handle { dl_load_library(entry) }; |
499 | 0 | if (!handle && !silent) { |
500 | 0 | GGML_LOG_ERROR("%s: failed to load %s: %s\n", __func__, path_str(entry.path()).c_str(), dl_error()); |
501 | 0 | } |
502 | 0 | if (handle) { |
503 | 0 | auto score_fn = (ggml_backend_score_t) dl_get_sym(handle.get(), "ggml_backend_score"); |
504 | 0 | if (score_fn) { |
505 | 0 | int s = score_fn(); |
506 | | #ifndef NDEBUG |
507 | | GGML_LOG_DEBUG("%s: %s score: %d\n", __func__, path_str(entry.path()).c_str(), s); |
508 | | #endif |
509 | 0 | if (s > best_score) { |
510 | 0 | best_score = s; |
511 | 0 | best_path = entry.path(); |
512 | 0 | } |
513 | 0 | } else { |
514 | 0 | if (!silent) { |
515 | 0 | GGML_LOG_INFO("%s: failed to find ggml_backend_score in %s\n", __func__, path_str(entry.path()).c_str()); |
516 | 0 | } |
517 | 0 | } |
518 | 0 | } |
519 | 0 | } |
520 | 0 | } |
521 | 0 | } |
522 | 0 | } |
523 | |
|
524 | 0 | if (best_score == 0) { |
525 | | // try to load the base backend |
526 | 0 | for (const auto & search_path : search_paths) { |
527 | 0 | fs::path filename = backend_filename_prefix().native() + name_path.native() + backend_filename_extension().native(); |
528 | 0 | fs::path path = search_path / filename; |
529 | 0 | if (std::error_code ec; fs::exists(path, ec)) { |
530 | 0 | return get_reg().load_backend(path, silent); |
531 | 0 | } else { |
532 | 0 | if (ec) { |
533 | 0 | GGML_LOG_DEBUG("%s: posix_stat(%s) failure, error-message: %s\n", __func__, path_str(path).c_str(), ec.message().c_str()); |
534 | 0 | } |
535 | 0 | } |
536 | 0 | } |
537 | 0 | return nullptr; |
538 | 0 | } |
539 | | |
540 | 0 | return get_reg().load_backend(best_path, silent); |
541 | 0 | } |
542 | | |
543 | 0 | void ggml_backend_load_all() { |
544 | 0 | ggml_backend_load_all_from_path(nullptr); |
545 | 0 | } |
546 | | |
547 | 0 | void ggml_backend_load_all_from_path(const char * dir_path) { |
548 | 0 | #ifdef NDEBUG |
549 | 0 | bool silent = true; |
550 | | #else |
551 | | bool silent = false; |
552 | | #endif |
553 | |
|
554 | 0 | ggml_backend_load_best("blas", silent, dir_path); |
555 | 0 | ggml_backend_load_best("zendnn", silent, dir_path); |
556 | 0 | ggml_backend_load_best("cann", silent, dir_path); |
557 | 0 | ggml_backend_load_best("cuda", silent, dir_path); |
558 | 0 | ggml_backend_load_best("hip", silent, dir_path); |
559 | 0 | ggml_backend_load_best("metal", silent, dir_path); |
560 | 0 | ggml_backend_load_best("rpc", silent, dir_path); |
561 | 0 | ggml_backend_load_best("sycl", silent, dir_path); |
562 | 0 | ggml_backend_load_best("vulkan", silent, dir_path); |
563 | 0 | ggml_backend_load_best("virtgpu", silent, dir_path); |
564 | 0 | ggml_backend_load_best("opencl", silent, dir_path); |
565 | 0 | ggml_backend_load_best("hexagon", silent, dir_path); |
566 | 0 | ggml_backend_load_best("musa", silent, dir_path); |
567 | 0 | ggml_backend_load_best("openvino", silent, dir_path); |
568 | 0 | ggml_backend_load_best("cpu", silent, dir_path); |
569 | | // check the environment variable GGML_BACKEND_PATH to load an out-of-tree backend |
570 | 0 | const char * backend_path = std::getenv("GGML_BACKEND_PATH"); |
571 | 0 | if (backend_path) { |
572 | 0 | ggml_backend_load(backend_path); |
573 | 0 | } |
574 | 0 | } |