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