char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
ca86fb222
char/aliceai-t5-moe
1#include "llama-mmap.h" 2 3#include "llama-impl.h" 4 5#include "ggml.h" 6 7#include <cstring> 8#include <climits> 9#include <cstdlib> 10#include <stdexcept> 11#include <cerrno> 12#include <algorithm> 13 14#ifdef __has_include 15#if __has_include (< unistd .h > ) 16#include <unistd.h> 17#include <fcntl.h> 18#include <sys/stat.h> 19#if defined(_POSIX_MAPPED_FILES ) 20#include <sys/mman.h> 21#endif 22#if defined(_POSIX_MEMLOCK_RANGE ) 23#include <sys/resource.h> 24#endif 25#endif 26#endif 27 28#if defined(_WIN32 ) 29#define WIN32_LEAN_AND_MEAN 30#ifndef NOMINMAX 31#define NOMINMAX 32#endif 33#include <windows.h> 34#ifndef PATH_MAX 35#define PATH_MAX MAX_PATH 36#endif 37#include <io.h> 38#endif 39 40#if defined(__APPLE__ ) 41#include <TargetConditionals.h> 42#endif 43 44#ifdef _WIN32 45# define llama_mmap_ftell _ftelli64 46# define llama_mmap_fseek _fseeki64 47#else 48# define llama_mmap_ftell ftello 49# define llama_mmap_fseek fseeko 50#endif 51 52// TODO: consider moving to llama-impl.h if needed in more places 53#if defined(_WIN32 ) 54static std::string llama_format_win_err (DWORD err ) { 55LPSTR buf ; 56size_t size = FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS , 57NULL ,err ,MAKELANGID (LANG_NEUTRAL ,SUBLANG_DEFAULT ), (LPSTR )& buf ,0 ,NULL ); 58if (!size ) { 59return "FormatMessageA failed" ; 60 } 61 std::string ret (buf ,size ); 62LocalFree (buf ); 63return ret ; 64} 65#endif 66 67// llama_file 68 69struct llama_file::impl { 70#if defined(_WIN32 ) 71HANDLE fp_win32 ; 72 std::string GetErrorMessageWin32 (DWORD error_code )const { 73 std::string ret ; 74LPSTR lpMsgBuf = NULL ; 75DWORD bufLen = FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS , 76NULL ,error_code ,MAKELANGID (LANG_NEUTRAL ,SUBLANG_DEFAULT ), (LPSTR )& lpMsgBuf ,0 ,NULL ); 77if (!bufLen ) { 78ret = format ("Win32 error code: %lx" ,error_code ); 79 }else { 80ret = lpMsgBuf ; 81LocalFree (lpMsgBuf ); 82 } 83 84return ret ; 85 } 86 87impl (const char * fname ,const char * mode , [[maybe_unused ]]const bool use_direct_io = false) { 88fp = ggml_fopen (fname ,mode ); 89if (fp == NULL ) { 90throw std::runtime_error (format ("failed to open %s: %s" ,fname ,strerror (errno ))); 91 } 92fp_win32 = (HANDLE )_get_osfhandle (_fileno (fp )); 93seek (0 ,SEEK_END ); 94size = tell (); 95seek (0 ,SEEK_SET ); 96 } 97 98impl (FILE * file ) :owns_fp (false) { 99fp = file ; 100fp_win32 = (HANDLE )_get_osfhandle (_fileno (fp )); 101seek (0 ,SEEK_END ); 102size = tell (); 103seek (0 ,SEEK_SET ); 104 } 105 106size_t tell ()const { 107LARGE_INTEGER li ; 108li .QuadPart = 0 ; 109BOOL ret = SetFilePointerEx (fp_win32 ,li ,& li ,FILE_CURRENT ); 110if (!ret ) { 111throw std::runtime_error (format ("read error: %s" ,GetErrorMessageWin32 (GetLastError ()).c_str ())); 112 } 113 114return li .QuadPart ; 115 } 116 117void seek (size_t offset ,int whence )const { 118 static_assert(SEEK_SET == FILE_BEGIN ,"SEEK_SET != FILE_BEGIN" ); 119 static_assert(SEEK_CUR == FILE_CURRENT ,"SEEK_CUR != FILE_CURRENT" ); 120 static_assert(SEEK_END == FILE_END ,"SEEK_END != FILE_END" ); 121 122LARGE_INTEGER li ; 123li .QuadPart = offset ; 124BOOL ret = SetFilePointerEx (fp_win32 ,li ,NULL ,whence ); 125if (!ret ) { 126throw std::runtime_error (format ("read error: %s" ,GetErrorMessageWin32 (GetLastError ()).c_str ())); 127 } 128 } 129 130void read_raw (void * ptr ,size_t len ) { 131size_t bytes_read = 0 ; 132while (bytes_read < len ) { 133size_t chunk_size = std::min < size_t > (len - bytes_read ,64 * 1024 * 1024 ); 134DWORD chunk_read = 0 ; 135BOOL result = ReadFile (fp_win32 ,reinterpret_cast < char *> (ptr )+ bytes_read ,chunk_size ,& chunk_read ,NULL ); 136if (!result ) { 137throw std::runtime_error (format ("read error: %s" ,GetErrorMessageWin32 (GetLastError ()).c_str ())); 138 } 139if (chunk_read < chunk_size || chunk_read == 0 ) { 140throw std::runtime_error ("unexpectedly reached end of file" ); 141 } 142 143bytes_read += chunk_read ; 144 } 145 } 146 147uint32_t read_u32 () { 148uint32_t val ; 149read_raw (& val ,sizeof (val )); 150return val ; 151 } 152 153void write_raw (const void * ptr ,size_t len )const { 154size_t bytes_written = 0 ; 155while (bytes_written < len ) { 156size_t chunk_size = std::min < size_t > (len - bytes_written ,64 * 1024 * 1024 ); 157DWORD chunk_written = 0 ; 158BOOL result = WriteFile (fp_win32 ,reinterpret_cast < char const *> (ptr )+ bytes_written ,chunk_size ,& chunk_written ,NULL ); 159if (!result ) { 160throw std::runtime_error (format ("write error: %s" ,GetErrorMessageWin32 (GetLastError ()).c_str ())); 161 } 162if (chunk_written < chunk_size || chunk_written == 0 ) { 163throw std::runtime_error ("unexpectedly failed to write bytes" ); 164 } 165 166bytes_written += chunk_written ; 167 } 168 } 169 170void write_u32 (uint32_t val )const { 171write_raw (& val ,sizeof (val )); 172 } 173 174bool has_direct_io ()const { 175return true; 176 } 177 178 ~impl () { 179if (fp && owns_fp ) { 180 std::fclose (fp ); 181 } 182 } 183#else 184impl (const char * fname ,const char * mode , [[maybe_unused ]]const bool use_direct_io = false) :fname (fname ) { 185#ifdef __linux__ 186// Try unbuffered I/O for read only 187if (use_direct_io && std::strcmp (mode ,"rb" )== 0 ) { 188if (init_fd ()) { 189return ; 190 } 191LLAMA_LOG_WARN ("Failed to open file '%s' with error: %s. Falling back to buffered I/O" , 192fname ,strerror (errno )); 193 } 194#endif 195init_fp (mode ); 196 } 197 198#ifdef __linux__ 199bool init_fd () { 200fd = open (fname .c_str (),O_RDONLY |O_DIRECT ); 201 202if (fd != -1 ) { 203struct stat file_stats {}; 204fstat (fd ,& file_stats ); 205 206size = file_stats .st_size ; 207alignment = file_stats .st_blksize ; 208 209off_t ret = lseek (fd ,0 ,SEEK_SET ); 210if (ret == -1 ) { 211throw std::runtime_error (format ("seek error: %s" ,strerror (errno ))); 212 } 213return true; 214 } 215return false; 216 } 217#endif 218 219void init_fp (const char * mode ) { 220fp = ggml_fopen (fname .c_str (),mode ); 221if (fp == NULL ) { 222throw std::runtime_error (format ("failed to open %s: %s" ,fname .c_str (),strerror (errno ))); 223 } 224seek (0 ,SEEK_END ); 225size = tell (); 226seek (0 ,SEEK_SET ); 227 } 228 229impl (FILE * file ) :fname ("(file*)" ),owns_fp (false) { 230fp = file ; 231seek (0 ,SEEK_END ); 232size = tell (); 233seek (0 ,SEEK_SET ); 234 } 235 236size_t tell ()const { 237if (fd == -1 ) { 238off_t ret = llama_mmap_ftell (fp ); 239if (ret == -1 ) { 240throw std::runtime_error (format ("ftell error: %s" ,strerror (errno ))); 241 } 242 243return (size_t )ret ; 244 } 245 246off_t pos = lseek (fd ,0 ,SEEK_CUR ); 247if (pos == -1 ) { 248throw std::runtime_error (format ("lseek error: %s" ,strerror (errno ))); 249 } 250return (size_t )pos ; 251 } 252 253void seek (size_t offset ,int whence )const { 254off_t ret = 0 ; 255if (fd == -1 ) { 256ret = llama_mmap_fseek (fp ,offset ,whence ); 257 }else { 258ret = lseek (fd ,offset ,whence ); 259 } 260if (ret == -1 ) { 261throw std::runtime_error (format ("seek error: %s" ,strerror (errno ))); 262 } 263 } 264 265void read_raw_unsafe (void * ptr ,size_t len ) { 266if (len == 0 ) { 267return ; 268 } 269errno = 0 ; 270if (fd == -1 ) { 271const size_t curr_off = tell (); 272const size_t to_read = std::min (len ,size - curr_off ); 273 274 std::size_t ret = std::fread (ptr ,to_read ,1 ,fp ); 275if (ferror (fp )) { 276throw std::runtime_error (format ("read error: %s" ,strerror (errno ))); 277 } 278if (to_read > 0 && ret != 1 ) { 279throw std::runtime_error ("unexpectedly reached end of file" ); 280 } 281 }else { 282size_t bytes_read = 0 ; 283while (bytes_read < len ) { 284const size_t to_read = len - bytes_read ; 285ssize_t ret = ::read (fd ,reinterpret_cast < char *> (ptr )+ bytes_read ,to_read ); 286 287if (ret == -1 ) { 288if (errno == EINTR ) { 289continue ;// Interrupted by signal, retry 290 } 291// Fallback to std::fread in case the DMA controller cannot access the buffer 292if (errno == EFAULT || errno == EINVAL ) { 293LLAMA_LOG_WARN ("%s: Falling back to buffered IO due to %s\n" ,__func__ ,strerror (errno )); 294auto curr_off = tell (); 295close (fd ); 296fd = -1 ; 297alignment = 1 ; 298init_fp ("rb" ); 299seek (curr_off ,SEEK_SET ); 300read_raw_unsafe (ptr ,len ); 301return ; 302 } 303throw std::runtime_error (format ("read error: %s" ,strerror (errno ))); 304 } 305if (ret == 0 ) { 306// EOF: allow if this read was only pulling alignment padding past file end 307off_t pos = lseek (fd ,0 ,SEEK_CUR ); 308if (pos != -1 && (size_t )pos == size ) { 309 std::memset (reinterpret_cast < char *> (ptr )+ bytes_read ,0 ,len - bytes_read ); 310return ; 311 } 312throw std::runtime_error ("unexpectedly reached end of file" ); 313 } 314 315bytes_read += (size_t )ret ; 316 } 317 } 318 } 319 320void read_aligned_chunk (void * dest ,size_t size ) { 321size_t offset = tell (); 322off_t aligned_offset = offset & ~(alignment - 1 ); 323off_t offset_from_alignment = offset - aligned_offset ; 324size_t bytes_to_read = (offset_from_alignment + size + alignment - 1 )& ~(alignment - 1 ); 325 326void * raw_buffer = nullptr ; 327int ret = posix_memalign (& raw_buffer ,alignment ,bytes_to_read ); 328if (ret != 0 ) { 329throw std::runtime_error (format ("posix_memalign failed with error %d" ,ret )); 330 } 331 332struct aligned_buffer_deleter { 333void operator()(void * p )const {free (p ); } 334 }; 335 std::unique_ptr < void ,aligned_buffer_deleter > buffer (raw_buffer ); 336 337seek (aligned_offset ,SEEK_SET ); 338read_raw_unsafe (buffer .get (),bytes_to_read ); 339 340uintptr_t actual_data = reinterpret_cast < uintptr_t > (buffer .get ())+ offset_from_alignment ; 341memcpy (dest ,reinterpret_cast < void *> (actual_data ),size ); 342 } 343 344void read_raw (void * ptr ,size_t len ) { 345if (has_direct_io ()) { 346read_aligned_chunk (ptr ,len ); 347 }else { 348read_raw_unsafe (ptr ,len ); 349 } 350 } 351 352uint32_t read_u32 () { 353uint32_t ret ; 354read_raw (& ret ,sizeof (ret )); 355return ret ; 356 } 357 358void write_raw (const void * ptr ,size_t len )const { 359if (len == 0 ) { 360return ; 361 } 362errno = 0 ; 363size_t ret = std::fwrite (ptr ,len ,1 ,fp ); 364if (ret != 1 ) { 365throw std::runtime_error (format ("write error: %s" ,strerror (errno ))); 366 } 367 } 368 369void write_u32 (uint32_t val )const { 370write_raw (& val ,sizeof (val )); 371 } 372 373bool has_direct_io ()const { 374return fd != -1 && alignment > 1 ; 375 } 376 377 ~impl () { 378if (fd != -1 ) { 379close (fd ); 380 }else if (owns_fp ) { 381 std::fclose (fp ); 382 } 383 } 384int fd = -1 ; 385 std::string fname ; 386#endif 387 388size_t read_alignment ()const { 389return alignment ; 390 } 391 392size_t alignment = 1 ; 393 394FILE * fp {}; 395size_t size {}; 396bool owns_fp = true; 397}; 398 399llama_file::llama_file (const char * fname ,const char * mode ,const bool use_direct_io ) : 400pimpl (std::make_unique < impl > (fname ,mode ,use_direct_io )) {} 401 402llama_file::llama_file (FILE * file ) :pimpl (std::make_unique < impl > (file )) {} 403 404llama_file::~llama_file ()= default ; 405 406size_t llama_file::tell ()const {return pimpl -> tell (); } 407size_t llama_file::size ()const {return pimpl -> size ; } 408 409size_t llama_file::read_alignment ()const {return pimpl -> read_alignment (); } 410bool llama_file::has_direct_io ()const {return pimpl -> has_direct_io (); } 411 412int llama_file::file_id ()const { 413#ifdef _WIN32 414return _fileno (pimpl -> fp ); 415#else 416if (pimpl -> fd != -1 ) { 417return pimpl -> fd ; 418 } 419#if defined(fileno ) 420return fileno (pimpl -> fp ); 421#else 422return ::fileno (pimpl -> fp ); 423#endif 424#endif 425} 426 427void llama_file::seek (size_t offset ,int whence )const {pimpl -> seek (offset ,whence ); } 428void llama_file::read_raw (void * ptr ,size_t len ) {pimpl -> read_raw (ptr ,len ); } 429#ifdef _WIN32 430void llama_file::read_raw_unsafe (void * ptr ,size_t len ) {pimpl -> read_raw (ptr ,len ); } 431#else 432void llama_file::read_raw_unsafe (void * ptr ,size_t len ) {pimpl -> read_raw_unsafe (ptr ,len ); } 433#endif 434 435uint32_t llama_file::read_u32 () {return pimpl -> read_u32 (); } 436 437void llama_file::write_raw (const void * ptr ,size_t len )const {pimpl -> write_raw (ptr ,len ); } 438void llama_file::write_u32 (uint32_t val )const {pimpl -> write_u32 (val ); } 439 440// llama_mmap 441 442#if defined(_POSIX_MAPPED_FILES )|| defined(_WIN32 ) 443// merge `ranges` and return their complement within [0, limit) 444static llama_mmap::ranges ranges_complement (llama_mmap::ranges ranges ,size_t limit ) { 445 llama_mmap::ranges res ; 446 std::sort (ranges .begin (),ranges .end ()); 447 448size_t pos = 0 ; 449for (const auto & range :ranges ) { 450const size_t beg = std::min (range .first ,limit ); 451const size_t end = std::min (range .second ,limit ); 452if (beg > pos ) { 453res .emplace_back (pos ,beg ); 454 } 455pos = std::max (pos ,end ); 456 } 457if (pos < limit ) { 458res .emplace_back (pos ,limit ); 459 } 460 461return res ; 462} 463#endif 464 465struct llama_mmap::impl { 466#ifdef _POSIX_MAPPED_FILES 467 std::vector < std::pair < size_t ,size_t >> mapped_fragments ; 468 469impl (struct llama_file * file ,size_t prefetch ,bool numa ,const llama_mmap::ranges & lazy_ranges ) { 470size = file -> size (); 471int fd = file -> file_id (); 472int flags = MAP_SHARED ; 473if (numa ) {prefetch = 0 ; } 474#ifdef __linux__ 475if (posix_fadvise (fd ,0 ,0 ,POSIX_FADV_SEQUENTIAL )) { 476LLAMA_LOG_WARN ("warning: posix_fadvise(.., POSIX_FADV_SEQUENTIAL) failed: %s\n" , 477strerror (errno )); 478 } 479// MAP_POPULATE would fault in the lazy ranges too 480if (prefetch && lazy_ranges .empty ()) {flags |=MAP_POPULATE ; } 481#endif 482addr = mmap (NULL ,file -> size (),PROT_READ ,flags ,fd ,0 ); 483if (addr == MAP_FAILED ) { 484throw std::runtime_error (format ("mmap failed: %s" ,strerror (errno ))); 485 } 486 487// page-aligned madvise over [beg, end), clamped to the file 488auto advise = [& ](size_t beg ,size_t end ,int advice ,const char * name ) { 489const size_t page_size = sysconf (_SC_PAGESIZE ); 490beg = beg & ~(page_size - 1 ); 491end = std::min ((end + page_size - 1 )& ~(page_size - 1 ),file -> size ()); 492if (beg >=end ) { 493return ; 494 } 495if (posix_madvise ((char * )addr + beg ,end - beg ,advice )) { 496LLAMA_LOG_WARN ("warning: posix_madvise(.., %s) failed: %s\n" ,name ,strerror (errno )); 497 } 498 }; 499 500if (prefetch > 0 ) { 501for (const auto & range :ranges_complement (lazy_ranges , std::min (file -> size (),prefetch ))) { 502advise (range .first ,range .second ,POSIX_MADV_WILLNEED ,"POSIX_MADV_WILLNEED" ); 503 } 504 } 505for (const auto & range :lazy_ranges ) { 506advise (range .first ,range .second ,POSIX_MADV_RANDOM ,"POSIX_MADV_RANDOM" ); 507 } 508if (numa ) { 509if (posix_madvise (addr ,file -> size (),POSIX_MADV_RANDOM )) { 510LLAMA_LOG_WARN ("warning: posix_madvise(.., POSIX_MADV_RANDOM) failed: %s\n" , 511strerror (errno )); 512 } 513 } 514 515mapped_fragments .emplace_back (0 ,file -> size ()); 516 } 517 518static void align_range (size_t * first ,size_t * last ,size_t page_size ) { 519size_t offset_in_page = * first & (page_size - 1 ); 520size_t offset_to_page = offset_in_page == 0 ?0 :page_size - offset_in_page ; 521* first += offset_to_page ; 522 523* last = * last & ~(page_size - 1 ); 524 525if (* last <=* first ) { 526* last = * first ; 527 } 528 } 529 530void unmap_fragment (size_t first ,size_t last ) { 531int page_size = sysconf (_SC_PAGESIZE ); 532align_range (& first ,& last ,page_size ); 533size_t len = last - first ; 534 535if (len == 0 ) { 536return ; 537 } 538 539GGML_ASSERT (first %page_size == 0 ); 540GGML_ASSERT (last %page_size == 0 ); 541GGML_ASSERT (last > first ); 542 543void * next_page_start = (uint8_t * )addr + first ; 544 545if (munmap (next_page_start ,len )) { 546LLAMA_LOG_WARN ("warning: munmap failed: %s\n" ,strerror (errno )); 547 } 548 549 std::vector < std::pair < size_t ,size_t >> new_mapped_fragments ; 550for (const auto & frag :mapped_fragments ) { 551if (frag .first < first && frag .second > last ) { 552new_mapped_fragments .emplace_back (frag .first ,first ); 553new_mapped_fragments .emplace_back (last ,frag .second ); 554 }else if (frag .first < first && frag .second > first ) { 555new_mapped_fragments .emplace_back (frag .first ,first ); 556 }else if (frag .first < last && frag .second > last ) { 557new_mapped_fragments .emplace_back (last ,frag .second ); 558 }else if (frag .first >=first && frag .second <=last ) { 559 }else { 560new_mapped_fragments .push_back (frag ); 561 } 562 } 563mapped_fragments = std::move (new_mapped_fragments ); 564 } 565 566 ~impl () { 567for (const auto & frag :mapped_fragments ) { 568if (munmap ((char * )addr + frag .first ,frag .second - frag .first )) { 569LLAMA_LOG_WARN ("warning: munmap failed: %s\n" ,strerror (errno )); 570 } 571 } 572 } 573#elif defined(_WIN32 ) 574HANDLE hMapping = nullptr ; 575 576impl (struct llama_file * file ,size_t prefetch ,bool numa ,const llama_mmap::ranges & lazy_ranges ) { 577GGML_UNUSED (numa ); 578 579size = file -> size (); 580 581HANDLE hFile = (HANDLE )_get_osfhandle (file -> file_id ()); 582 583hMapping = CreateFileMappingA (hFile ,NULL ,PAGE_READONLY ,0 ,0 ,NULL ); 584 585if (hMapping == NULL ) { 586DWORD error = GetLastError (); 587throw std::runtime_error (format ("CreateFileMappingA failed: %s" ,llama_format_win_err (error ).c_str ())); 588 } 589 590addr = MapViewOfFile (hMapping ,FILE_MAP_READ ,0 ,0 ,0 ); 591DWORD error = GetLastError (); 592 593if (addr == NULL ) { 594CloseHandle (hMapping ); 595throw std::runtime_error (format ("MapViewOfFile failed: %s" ,llama_format_win_err (error ).c_str ())); 596 } 597 598if (prefetch > 0 ) { 599#if _WIN32_WINNT >=0x602 600BOOL (WINAPI * pPrefetchVirtualMemory ) (HANDLE ,ULONG_PTR ,PWIN32_MEMORY_RANGE_ENTRY ,ULONG ); 601HMODULE hKernel32 = GetModuleHandleW (L"kernel32.dll" ); 602 603pPrefetchVirtualMemory = (decltype(pPrefetchVirtualMemory ))(void * )GetProcAddress (hKernel32 ,"PrefetchVirtualMemory" ); 604 605if (pPrefetchVirtualMemory ) { 606 std::vector < WIN32_MEMORY_RANGE_ENTRY > entries ; 607for (const auto & range :ranges_complement (lazy_ranges , std::min (size ,prefetch ))) { 608WIN32_MEMORY_RANGE_ENTRY entry ; 609entry .VirtualAddress = (char * )addr + range .first ; 610entry .NumberOfBytes = (SIZE_T ) (range .second - range .first ); 611entries .push_back (entry ); 612 } 613if (!entries .empty ()&& 614 !pPrefetchVirtualMemory (GetCurrentProcess (), (ULONG_PTR )entries .size (),entries .data (),0 )) { 615LLAMA_LOG_WARN ("warning: PrefetchVirtualMemory failed: %s\n" , 616llama_format_win_err (GetLastError ()).c_str ()); 617 } 618 } 619#else 620LLAMA_LOG_DEBUG ("skipping PrefetchVirtualMemory because _WIN32_WINNT < 0x602\n" ); 621#endif 622 } 623 } 624 625void unmap_fragment (size_t first ,size_t last ) { 626GGML_UNUSED (first ); 627GGML_UNUSED (last ); 628 } 629 630 ~impl () { 631if (hMapping ) { 632if (addr ) { 633if (!UnmapViewOfFile (addr )) { 634LLAMA_LOG_WARN ("warning: UnmapViewOfFile failed: %s\n" , 635llama_format_win_err (GetLastError ()).c_str ()); 636 } 637 } 638if (!CloseHandle (hMapping )) { 639LLAMA_LOG_WARN ("warning: CloseHandle failed: %s\n" , 640llama_format_win_err (GetLastError ()).c_str ()); 641 } 642 } 643 } 644#else 645impl (struct llama_file * file ,size_t prefetch ,bool numa ,const llama_mmap::ranges & lazy_ranges ) { 646GGML_UNUSED (file ); 647GGML_UNUSED (prefetch ); 648GGML_UNUSED (numa ); 649GGML_UNUSED (lazy_ranges ); 650 651throw std::runtime_error ("mmap not supported" ); 652 } 653 654void unmap_fragment (size_t first ,size_t last ) { 655GGML_UNUSED (first ); 656GGML_UNUSED (last ); 657 658throw std::runtime_error ("mmap not supported" ); 659 } 660#endif 661 662void * addr ; 663size_t size ; 664}; 665 666llama_mmap::llama_mmap (struct llama_file * file ,size_t prefetch ,bool numa , 667const ranges & lazy_ranges ) :pimpl (std::make_unique < impl > (file ,prefetch ,numa ,lazy_ranges )) {} 668llama_mmap::~llama_mmap ()= default ; 669 670size_t llama_mmap::size ()const {return pimpl -> size ; } 671void * llama_mmap::addr ()const {return pimpl -> addr ; } 672 673void llama_mmap::unmap_fragment (size_t first ,size_t last ) {pimpl -> unmap_fragment (first ,last ); } 674 675#if defined(_POSIX_MEMLOCK_RANGE )|| defined(_WIN32 ) 676const bool llama_mmap::SUPPORTED = true; 677#else 678const bool llama_mmap::SUPPORTED = false; 679#endif 680 681// llama_mlock 682 683struct llama_mlock::impl { 684#ifdef _POSIX_MEMLOCK_RANGE 685static size_t lock_granularity () { 686return (size_t )sysconf (_SC_PAGESIZE ); 687 } 688 689bool raw_lock (const void * addr ,size_t size )const { 690if (!mlock (addr ,size )) { 691return true; 692 } 693 694#ifdef __APPLE__ 695#define MLOCK_SUGGESTION \ 696 "Try increasing the sysctl values 'vm.user_wire_limit' and 'vm.global_user_wire_limit' and/or " \ 697 "decreasing 'vm.global_no_user_wire_amount'. Also try increasing RLIMIT_MEMLOCK (ulimit -l).\n" 698#else 699#define MLOCK_SUGGESTION \ 700 "Try increasing RLIMIT_MEMLOCK ('ulimit -l' as root).\n" 701#endif 702 703char * errmsg = std::strerror (errno ); 704bool suggest = (errno == ENOMEM ); 705#if defined(TARGET_OS_VISION )|| defined(TARGET_OS_TV )|| defined(_AIX )|| defined(__HAIKU__ ) 706// visionOS/tvOS/Haiku don't support RLIMIT_MEMLOCK 707// Skip resource limit checks on these platforms 708suggest = false; 709#else 710struct rlimit lock_limit ; 711if (suggest && getrlimit (RLIMIT_MEMLOCK ,& lock_limit )) { 712suggest = false; 713 } 714if (suggest && ((uint64_t )lock_limit .rlim_max > (uint64_t )lock_limit .rlim_cur + size )) { 715suggest = false; 716 } 717#endif 718 719LLAMA_LOG_WARN ("warning: failed to mlock %zu-byte buffer (after previously locking %zu bytes): %s\n%s" , 720size ,this -> size ,errmsg ,suggest ?MLOCK_SUGGESTION :"" ); 721return false; 722 } 723 724static void raw_unlock (void * addr ,size_t size ) { 725if (munlock (addr ,size )) { 726LLAMA_LOG_WARN ("warning: failed to munlock buffer: %s\n" , std::strerror (errno )); 727 } 728 } 729#elif defined(_WIN32 ) 730static size_t lock_granularity () { 731SYSTEM_INFO si ; 732GetSystemInfo (& si ); 733return (size_t )si .dwPageSize ; 734 } 735 736bool raw_lock (void * ptr ,size_t len )const { 737for (int tries = 1 ; ;tries ++ ) { 738if (VirtualLock (ptr ,len )) { 739return true; 740 } 741if (tries == 2 ) { 742LLAMA_LOG_WARN ("warning: failed to VirtualLock %zu-byte buffer (after previously locking %zu bytes): %s\n" , 743len ,size ,llama_format_win_err (GetLastError ()).c_str ()); 744return false; 745 } 746 747SIZE_T min_ws_size ,max_ws_size ; 748if (!GetProcessWorkingSetSize (GetCurrentProcess (),& min_ws_size ,& max_ws_size )) { 749LLAMA_LOG_WARN ("warning: GetProcessWorkingSetSize failed: %s\n" , 750llama_format_win_err (GetLastError ()).c_str ()); 751return false; 752 } 753size_t increment = len + 1048576 ; 754min_ws_size += increment ; 755max_ws_size += increment ; 756if (!SetProcessWorkingSetSize (GetCurrentProcess (),min_ws_size ,max_ws_size )) { 757LLAMA_LOG_WARN ("warning: SetProcessWorkingSetSize failed: %s\n" , 758llama_format_win_err (GetLastError ()).c_str ()); 759return false; 760 } 761 } 762 } 763 764static void raw_unlock (void * ptr ,size_t len ) { 765if (!VirtualUnlock (ptr ,len )) { 766LLAMA_LOG_WARN ("warning: failed to VirtualUnlock buffer: %s\n" , 767llama_format_win_err (GetLastError ()).c_str ()); 768 } 769 } 770#else 771static size_t lock_granularity () { 772return (size_t )65536 ; 773 } 774 775bool raw_lock (const void * addr ,size_t len )const { 776LLAMA_LOG_WARN ("warning: mlock not supported on this system\n" ); 777return false; 778 } 779 780static void raw_unlock (const void * addr ,size_t len ) {} 781#endif 782 783impl () :addr (NULL ),size (0 ),failed_already (false) {} 784 785void init (void * ptr ) { 786GGML_ASSERT (addr == NULL && size == 0 ); 787addr = ptr ; 788 } 789 790void grow_to (size_t target_size ) { 791GGML_ASSERT (addr ); 792if (failed_already ) { 793return ; 794 } 795size_t granularity = lock_granularity (); 796target_size = (target_size + granularity - 1 )& ~(granularity - 1 ); 797if (target_size > size ) { 798if (raw_lock ((uint8_t * )addr + size ,target_size - size )) { 799size = target_size ; 800 }else { 801failed_already = true; 802 } 803 } 804 } 805 806void * addr ; 807size_t size ; 808 809bool failed_already ; 810}; 811 812llama_mlock::llama_mlock () :pimpl (std::make_unique < impl > ()) {} 813llama_mlock::~llama_mlock ()= default ; 814 815void llama_mlock::init (void * ptr ) {pimpl -> init (ptr ); } 816void llama_mlock::grow_to (size_t target_size ) {pimpl -> grow_to (target_size ); } 817 818#if defined(_POSIX_MEMLOCK_RANGE )|| defined(_WIN32 ) 819const bool llama_mlock::SUPPORTED = true; 820#else 821const bool llama_mlock::SUPPORTED = false; 822#endif 823 824size_t llama_path_max () { 825return PATH_MAX ; 826}