Diego Devesa commited on
Commit
656e8b1
·
1 Parent(s): 06cddad

ggml : use wstring for backend search paths (llama/10960)

Browse files
ggml/src/CMakeLists.txt CHANGED
@@ -234,6 +234,7 @@ function(ggml_add_backend_library backend)
234
  # write the shared library to the output directory
235
  set_target_properties(${backend} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
236
  target_compile_definitions(${backend} PRIVATE GGML_BACKEND_DL)
 
237
  else()
238
  add_library(${backend} ${ARGN})
239
  target_link_libraries(ggml PUBLIC ${backend})
 
234
  # write the shared library to the output directory
235
  set_target_properties(${backend} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
236
  target_compile_definitions(${backend} PRIVATE GGML_BACKEND_DL)
237
+ add_dependencies(ggml ${backend})
238
  else()
239
  add_library(${backend} ${ARGN})
240
  target_link_libraries(ggml PUBLIC ${backend})
ggml/src/ggml-backend-reg.cpp CHANGED
@@ -66,6 +66,26 @@
66
  #include "ggml-kompute.h"
67
  #endif
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  #ifdef _WIN32
70
 
71
  using dl_handle = std::remove_pointer_t<HMODULE>;
@@ -88,11 +108,6 @@ static dl_handle * dl_load_library(const std::wstring & path) {
88
  return handle;
89
  }
90
 
91
- static dl_handle * dl_load_library(const std::string & path) {
92
- std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
93
- return dl_load_library(converter.from_bytes(path));
94
- }
95
-
96
  static void * dl_get_sym(dl_handle * handle, const char * name) {
97
  DWORD old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
98
  SetErrorMode(old_mode | SEM_FAILCRITICALERRORS);
@@ -114,8 +129,8 @@ struct dl_handle_deleter {
114
  }
115
  };
116
 
117
- static void * dl_load_library(const std::string & path) {
118
- dl_handle * handle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
119
 
120
  return handle;
121
  }
@@ -202,11 +217,11 @@ struct ggml_backend_registry {
202
  devices.push_back(device);
203
  }
204
 
205
- ggml_backend_reg_t load_backend(const char * path, bool silent) {
206
  dl_handle_ptr handle { dl_load_library(path) };
207
  if (!handle) {
208
  if (!silent) {
209
- GGML_LOG_ERROR("%s: failed to load %s\n", __func__, path);
210
  }
211
  return nullptr;
212
  }
@@ -214,7 +229,7 @@ struct ggml_backend_registry {
214
  auto score_fn = (ggml_backend_score_t) dl_get_sym(handle.get(), "ggml_backend_score");
215
  if (score_fn && score_fn() == 0) {
216
  if (!silent) {
217
- GGML_LOG_INFO("%s: backend %s is not supported on this system\n", __func__, path);
218
  }
219
  return nullptr;
220
  }
@@ -222,7 +237,7 @@ struct ggml_backend_registry {
222
  auto backend_init_fn = (ggml_backend_init_t) dl_get_sym(handle.get(), "ggml_backend_init");
223
  if (!backend_init_fn) {
224
  if (!silent) {
225
- GGML_LOG_ERROR("%s: failed to find ggml_backend_init in %s\n", __func__, path);
226
  }
227
  return nullptr;
228
  }
@@ -231,16 +246,16 @@ struct ggml_backend_registry {
231
  if (!reg || reg->api_version != GGML_BACKEND_API_VERSION) {
232
  if (!silent) {
233
  if (!reg) {
234
- GGML_LOG_ERROR("%s: failed to initialize backend from %s: ggml_backend_init returned NULL\n", __func__, path);
235
  } else {
236
  GGML_LOG_ERROR("%s: failed to initialize backend from %s: incompatible API version (backend: %d, current: %d)\n",
237
- __func__, path, reg->api_version, GGML_BACKEND_API_VERSION);
238
  }
239
  }
240
  return nullptr;
241
  }
242
 
243
- GGML_LOG_INFO("%s: loaded %s backend from %s\n", __func__, ggml_backend_reg_name(reg), path);
244
 
245
  register_backend(reg, std::move(handle));
246
 
@@ -376,14 +391,14 @@ ggml_backend_t ggml_backend_init_best(void) {
376
 
377
  // Dynamic loading
378
  ggml_backend_reg_t ggml_backend_load(const char * path) {
379
- return get_reg().load_backend(path, false);
380
  }
381
 
382
  void ggml_backend_unload(ggml_backend_reg_t reg) {
383
  get_reg().unload_backend(reg, true);
384
  }
385
 
386
- static std::string get_executable_path() {
387
  #if defined(__APPLE__)
388
  // get executable path
389
  std::vector<char> path;
@@ -401,7 +416,7 @@ static std::string get_executable_path() {
401
  if (last_slash != std::string::npos) {
402
  base_path = base_path.substr(0, last_slash);
403
  }
404
- return base_path + "/";
405
  #elif defined(__linux__) || defined(__FreeBSD__)
406
  std::string base_path = ".";
407
  std::vector<char> path(1024);
@@ -427,57 +442,63 @@ static std::string get_executable_path() {
427
  path.resize(path.size() * 2);
428
  }
429
 
430
- return base_path + "/";
431
  #elif defined(_WIN32)
432
- std::vector<char> path(MAX_PATH);
433
- DWORD len = GetModuleFileNameA(NULL, path.data(), path.size());
434
  if (len == 0) {
435
- return "";
436
  }
437
- std::string base_path(path.data(), len);
438
  // remove executable name
439
  auto last_slash = base_path.find_last_of('\\');
440
  if (last_slash != std::string::npos) {
441
  base_path = base_path.substr(0, last_slash);
442
  }
443
- return base_path + "\\";
 
 
 
 
 
 
 
 
 
 
444
  #endif
445
  }
446
 
447
- static std::string backend_filename_prefix() {
448
  #ifdef _WIN32
449
- return "ggml-";
450
  #else
451
- return "libggml-";
452
  #endif
453
  }
454
 
455
- static std::string backend_filename_suffix() {
456
  #ifdef _WIN32
457
- return ".dll";
458
  #else
459
- return ".so";
460
  #endif
461
  }
462
 
463
  static ggml_backend_reg_t ggml_backend_load_best(const char * name, bool silent, const char * user_search_path) {
464
  // enumerate all the files that match [lib]ggml-name-*.[so|dll] in the search paths
465
  // TODO: search system paths
466
- std::string file_prefix = backend_filename_prefix() + name + "-";
467
- std::vector<std::string> search_paths;
468
  if (user_search_path == nullptr) {
469
- search_paths.push_back("./");
470
  search_paths.push_back(get_executable_path());
471
  } else {
472
- #if defined(_WIN32)
473
- search_paths.push_back(std::string(user_search_path) + "\\");
474
- #else
475
- search_paths.push_back(std::string(user_search_path) + "/");
476
- #endif
477
  }
478
 
479
  int best_score = 0;
480
- std::string best_path;
481
 
482
  namespace fs = std::filesystem;
483
  for (const auto & search_path : search_paths) {
@@ -487,27 +508,27 @@ static ggml_backend_reg_t ggml_backend_load_best(const char * name, bool silent,
487
  fs::directory_iterator dir_it(search_path, fs::directory_options::skip_permission_denied);
488
  for (const auto & entry : dir_it) {
489
  if (entry.is_regular_file()) {
490
- std::string filename = entry.path().filename().string();
491
- std::string ext = entry.path().extension().string();
492
  if (filename.find(file_prefix) == 0 && ext == backend_filename_suffix()) {
493
- dl_handle_ptr handle { dl_load_library(entry.path().c_str()) };
494
  if (!handle && !silent) {
495
- GGML_LOG_ERROR("%s: failed to load %s\n", __func__, entry.path().string().c_str());
496
  }
497
  if (handle) {
498
  auto score_fn = (ggml_backend_score_t) dl_get_sym(handle.get(), "ggml_backend_score");
499
  if (score_fn) {
500
  int s = score_fn();
501
  #ifndef NDEBUG
502
- GGML_LOG_DEBUG("%s: %s score: %d\n", __func__, entry.path().string().c_str(), s);
503
  #endif
504
  if (s > best_score) {
505
  best_score = s;
506
- best_path = entry.path().string();
507
  }
508
  } else {
509
  if (!silent) {
510
- GGML_LOG_INFO("%s: failed to find ggml_backend_score in %s\n", __func__, entry.path().string().c_str());
511
  }
512
  }
513
  }
@@ -519,15 +540,15 @@ static ggml_backend_reg_t ggml_backend_load_best(const char * name, bool silent,
519
  if (best_score == 0) {
520
  // try to load the base backend
521
  for (const auto & search_path : search_paths) {
522
- std::string path = search_path + backend_filename_prefix() + name + backend_filename_suffix();
523
  if (fs::exists(path)) {
524
- return get_reg().load_backend(path.c_str(), silent);
525
  }
526
  }
527
  return nullptr;
528
  }
529
 
530
- return get_reg().load_backend(best_path.c_str(), silent);
531
  }
532
 
533
  void ggml_backend_load_all() {
 
66
  #include "ggml-kompute.h"
67
  #endif
68
 
69
+ // disable C++17 deprecation warning for std::codecvt_utf8
70
+ #if defined(__clang__)
71
+ # pragma clang diagnostic push
72
+ # pragma clang diagnostic ignored "-Wdeprecated-declarations"
73
+ #endif
74
+
75
+ static std::wstring utf8_to_utf16(const std::string & str) {
76
+ std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
77
+ return converter.from_bytes(str);
78
+ }
79
+
80
+ static std::string utf16_to_utf8(const std::wstring & str) {
81
+ std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
82
+ return converter.to_bytes(str);
83
+ }
84
+
85
+ #if defined(__clang__)
86
+ # pragma clang diagnostic pop
87
+ #endif
88
+
89
  #ifdef _WIN32
90
 
91
  using dl_handle = std::remove_pointer_t<HMODULE>;
 
108
  return handle;
109
  }
110
 
 
 
 
 
 
111
  static void * dl_get_sym(dl_handle * handle, const char * name) {
112
  DWORD old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
113
  SetErrorMode(old_mode | SEM_FAILCRITICALERRORS);
 
129
  }
130
  };
131
 
132
+ static void * dl_load_library(const std::wstring & path) {
133
+ dl_handle * handle = dlopen(utf16_to_utf8(path).c_str(), RTLD_NOW | RTLD_LOCAL);
134
 
135
  return handle;
136
  }
 
217
  devices.push_back(device);
218
  }
219
 
220
+ ggml_backend_reg_t load_backend(const std::wstring & path, bool silent) {
221
  dl_handle_ptr handle { dl_load_library(path) };
222
  if (!handle) {
223
  if (!silent) {
224
+ GGML_LOG_ERROR("%s: failed to load %s\n", __func__, utf16_to_utf8(path).c_str());
225
  }
226
  return nullptr;
227
  }
 
229
  auto score_fn = (ggml_backend_score_t) dl_get_sym(handle.get(), "ggml_backend_score");
230
  if (score_fn && score_fn() == 0) {
231
  if (!silent) {
232
+ GGML_LOG_INFO("%s: backend %s is not supported on this system\n", __func__, utf16_to_utf8(path).c_str());
233
  }
234
  return nullptr;
235
  }
 
237
  auto backend_init_fn = (ggml_backend_init_t) dl_get_sym(handle.get(), "ggml_backend_init");
238
  if (!backend_init_fn) {
239
  if (!silent) {
240
+ GGML_LOG_ERROR("%s: failed to find ggml_backend_init in %s\n", __func__, utf16_to_utf8(path).c_str());
241
  }
242
  return nullptr;
243
  }
 
246
  if (!reg || reg->api_version != GGML_BACKEND_API_VERSION) {
247
  if (!silent) {
248
  if (!reg) {
249
+ GGML_LOG_ERROR("%s: failed to initialize backend from %s: ggml_backend_init returned NULL\n", __func__, utf16_to_utf8(path).c_str());
250
  } else {
251
  GGML_LOG_ERROR("%s: failed to initialize backend from %s: incompatible API version (backend: %d, current: %d)\n",
252
+ __func__, utf16_to_utf8(path).c_str(), reg->api_version, GGML_BACKEND_API_VERSION);
253
  }
254
  }
255
  return nullptr;
256
  }
257
 
258
+ GGML_LOG_INFO("%s: loaded %s backend from %s\n", __func__, ggml_backend_reg_name(reg), utf16_to_utf8(path).c_str());
259
 
260
  register_backend(reg, std::move(handle));
261
 
 
391
 
392
  // Dynamic loading
393
  ggml_backend_reg_t ggml_backend_load(const char * path) {
394
+ return get_reg().load_backend(utf8_to_utf16(path), false);
395
  }
396
 
397
  void ggml_backend_unload(ggml_backend_reg_t reg) {
398
  get_reg().unload_backend(reg, true);
399
  }
400
 
401
+ static std::wstring get_executable_path() {
402
  #if defined(__APPLE__)
403
  // get executable path
404
  std::vector<char> path;
 
416
  if (last_slash != std::string::npos) {
417
  base_path = base_path.substr(0, last_slash);
418
  }
419
+ return utf8_to_utf16(base_path + "/");
420
  #elif defined(__linux__) || defined(__FreeBSD__)
421
  std::string base_path = ".";
422
  std::vector<char> path(1024);
 
442
  path.resize(path.size() * 2);
443
  }
444
 
445
+ return utf8_to_utf16(base_path + "/");
446
  #elif defined(_WIN32)
447
+ std::vector<wchar_t> path(MAX_PATH);
448
+ DWORD len = GetModuleFileNameW(NULL, path.data(), path.size());
449
  if (len == 0) {
450
+ return {};
451
  }
452
+ std::wstring base_path(path.data(), len);
453
  // remove executable name
454
  auto last_slash = base_path.find_last_of('\\');
455
  if (last_slash != std::string::npos) {
456
  base_path = base_path.substr(0, last_slash);
457
  }
458
+ return base_path + L"\\";
459
+ #else
460
+ return {};
461
+ #endif
462
+ }
463
+
464
+ static std::wstring backend_filename_prefix() {
465
+ #ifdef _WIN32
466
+ return L"ggml-";
467
+ #else
468
+ return L"libggml-";
469
  #endif
470
  }
471
 
472
+ static std::wstring backend_filename_suffix() {
473
  #ifdef _WIN32
474
+ return L".dll";
475
  #else
476
+ return L".so";
477
  #endif
478
  }
479
 
480
+ static std::wstring path_separator() {
481
  #ifdef _WIN32
482
+ return L"\\";
483
  #else
484
+ return L"/";
485
  #endif
486
  }
487
 
488
  static ggml_backend_reg_t ggml_backend_load_best(const char * name, bool silent, const char * user_search_path) {
489
  // enumerate all the files that match [lib]ggml-name-*.[so|dll] in the search paths
490
  // TODO: search system paths
491
+ std::wstring file_prefix = backend_filename_prefix() + utf8_to_utf16(name) + L"-";
492
+ std::vector<std::wstring> search_paths;
493
  if (user_search_path == nullptr) {
494
+ search_paths.push_back(L"." + path_separator());
495
  search_paths.push_back(get_executable_path());
496
  } else {
497
+ search_paths.push_back(utf8_to_utf16(user_search_path) + path_separator());
 
 
 
 
498
  }
499
 
500
  int best_score = 0;
501
+ std::wstring best_path;
502
 
503
  namespace fs = std::filesystem;
504
  for (const auto & search_path : search_paths) {
 
508
  fs::directory_iterator dir_it(search_path, fs::directory_options::skip_permission_denied);
509
  for (const auto & entry : dir_it) {
510
  if (entry.is_regular_file()) {
511
+ std::wstring filename = entry.path().filename().wstring();
512
+ std::wstring ext = entry.path().extension().wstring();
513
  if (filename.find(file_prefix) == 0 && ext == backend_filename_suffix()) {
514
+ dl_handle_ptr handle { dl_load_library(entry.path().wstring()) };
515
  if (!handle && !silent) {
516
+ GGML_LOG_ERROR("%s: failed to load %s\n", __func__, utf16_to_utf8(entry.path().wstring()).c_str());
517
  }
518
  if (handle) {
519
  auto score_fn = (ggml_backend_score_t) dl_get_sym(handle.get(), "ggml_backend_score");
520
  if (score_fn) {
521
  int s = score_fn();
522
  #ifndef NDEBUG
523
+ GGML_LOG_DEBUG("%s: %s score: %d\n", __func__, utf16_to_utf8(entry.path().wstring()).c_str(), s);
524
  #endif
525
  if (s > best_score) {
526
  best_score = s;
527
+ best_path = entry.path().wstring();
528
  }
529
  } else {
530
  if (!silent) {
531
+ GGML_LOG_INFO("%s: failed to find ggml_backend_score in %s\n", __func__, utf16_to_utf8(entry.path().wstring()).c_str());
532
  }
533
  }
534
  }
 
540
  if (best_score == 0) {
541
  // try to load the base backend
542
  for (const auto & search_path : search_paths) {
543
+ std::wstring path = search_path + backend_filename_prefix() + utf8_to_utf16(name) + backend_filename_suffix();
544
  if (fs::exists(path)) {
545
+ return get_reg().load_backend(path, silent);
546
  }
547
  }
548
  return nullptr;
549
  }
550
 
551
+ return get_reg().load_backend(best_path, silent);
552
  }
553
 
554
  void ggml_backend_load_all() {
ggml/src/ggml-cpu/CMakeLists.txt CHANGED
@@ -323,6 +323,11 @@ function(ggml_add_cpu_backend_variant_impl tag_name)
323
  target_compile_definitions(${GGML_CPU_NAME} PRIVATE ${ARCH_DEFINITIONS})
324
 
325
  if (GGML_BACKEND_DL)
 
 
 
 
 
326
  # The feature detection code is compiled as a separate target so that
327
  # it can be built without the architecture flags
328
  # Since multiple variants of the CPU backend may be included in the same
 
323
  target_compile_definitions(${GGML_CPU_NAME} PRIVATE ${ARCH_DEFINITIONS})
324
 
325
  if (GGML_BACKEND_DL)
326
+ if (GGML_NATIVE)
327
+ # the feature check relies on ARCH_DEFINITIONS, but it is not set with GGML_NATIVE
328
+ message(FATAL_ERROR "GGML_NATIVE is not compatible with GGML_BACKEND_DL, consider using GGML_CPU_ALL_VARIANTS")
329
+ endif()
330
+
331
  # The feature detection code is compiled as a separate target so that
332
  # it can be built without the architecture flags
333
  # Since multiple variants of the CPU backend may be included in the same