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