char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
81b0d882a
char/aliceai-t5-moe
1#include "spine_mem_pool.h" 2 3#include "common.h" 4#include "ime_env.h" 5#include "spine_tcm.h" 6 7#include <fcntl.h> 8#include <sys/ioctl.h> 9#include <sys/mman.h> 10#include <unistd.h> 11 12#include <algorithm> 13#include <cerrno> 14#include <cstdint> 15#include <cstdlib> 16#include <limits> 17#include <memory> 18#include <mutex> 19#include <unordered_map> 20#include <vector> 21 22namespace ggml::cpu::riscv64_spacemit { 23namespace { 24 25constexpr size_t SPINE_MEM_POOL_CHUNK_SIZE = 512ull * 1024ull * 1024ull ; 26constexpr size_t SPINE_SHARE_MEM_POOL_CHUNK_SIZE = 512ull * 1024ull ; 27constexpr size_t SPINE_MEM_POOL_1G_REGION_SIZE = 1ull <<30 ; 28constexpr uint64_t HUGETLB_1G_FLAG_REQUIRE_PUD = 1ull <<0 ; 29constexpr char SPINE_MEM_POOL_HUGETLB_1G_DEV []= "/dev/hugetlb_1g" ; 30constexpr char SPINE_MEM_POOL_TCM_SYNC_MEM_DEV []= "/dev/tcm_sync_mem" ; 31 32struct hugetlb_1g_region { 33uint64_t size {0 }; 34uint64_t dma_addr {0 }; 35uint64_t flags {0 }; 36uint64_t reserved {0 }; 37}; 38 39#define HUGETLB_1G_IOC_MAGIC 'M' 40#define HUGETLB_1G_IOC_ALLOC _IOWR(HUGETLB_1G_IOC_MAGIC, 0x00, struct hugetlb_1g_region) 41#define HUGETLB_1G_IOC_FREE _IO(HUGETLB_1G_IOC_MAGIC, 0x01) 42 43struct free_block { 44size_t offset {0 }; 45size_t size {0 }; 46}; 47 48struct pool_chunk { 49uint8_t * base {nullptr }; 50size_t size {0 }; 51int fd {-1 }; 52 std::vector < free_block > free_blocks ; 53}; 54 55struct pool_allocation { 56void * chunk_base {nullptr }; 57size_t chunk_size {0 }; 58void * base {nullptr }; 59size_t size {0 }; 60}; 61 62bool is_power_of_two (size_t value ) { 63return value != 0 && (value & (value - 1 ))== 0 ; 64} 65 66bool align_up (size_t value ,size_t alignment ,size_t * aligned_value ) { 67if (aligned_value == nullptr || alignment == 0 ) { 68return false; 69 } 70 71const size_t remainder = value %alignment ; 72if (remainder == 0 ) { 73* aligned_value = value ; 74return true; 75 } 76 77const size_t padding = alignment - remainder ; 78if (value > std::numeric_limits < size_t > ::max ()- padding ) { 79return false; 80 } 81 82* aligned_value = value + padding ; 83return true; 84} 85 86bool align_up_uintptr (uintptr_t value ,size_t alignment ,uintptr_t * aligned_value ) { 87if (aligned_value == nullptr || alignment == 0 ) { 88return false; 89 } 90 91const uintptr_t remainder = value %alignment ; 92if (remainder == 0 ) { 93* aligned_value = value ; 94return true; 95 } 96 97const uintptr_t padding = alignment - remainder ; 98if (value > std::numeric_limits < uintptr_t > ::max ()- padding ) { 99return false; 100 } 101 102* aligned_value = value + padding ; 103return true; 104} 105 106class spine_mem_pool_manager { 107public : 108explicit spine_mem_pool_manager (size_t default_chunk_size ) :default_chunk_size_ (default_chunk_size ) {} 109 110virtual ~spine_mem_pool_manager ()= default ; 111 112void * alloc (size_t size ,size_t alignment ) { 113if (size == 0 || !is_power_of_two (alignment )) { 114return nullptr ; 115 } 116 117size_t aligned_size = 0 ; 118if (!align_up (size ,alignment ,& aligned_size )) { 119GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: align_up failed for size %zu alignment %zu\n" ,__func__ ,size , 120alignment ); 121return nullptr ; 122 } 123 124pool_allocation allocation ; 125 126 std::lock_guard < std::mutex > lock (mutex_ ); 127 128if (!try_alloc_locked (aligned_size ,alignment ,& allocation )) { 129if (!add_chunk_locked (aligned_size ,alignment )) { 130return nullptr ; 131 } 132 133if (!try_alloc_locked (aligned_size ,alignment ,& allocation )) { 134GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: allocation retry failed for size %zu alignment %zu\n" , 135__func__ ,aligned_size ,alignment ); 136return nullptr ; 137 } 138 } 139 140try { 141const auto [allocation_it ,inserted ]= allocations_ .emplace (allocation .base ,allocation ); 142if (!inserted ) { 143GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: duplicate allocation key %p\n" ,__func__ ,allocation .base ); 144rollback_allocation_locked (allocation ); 145return nullptr ; 146 } 147 }catch (const std::bad_alloc & ) { 148rollback_allocation_locked (allocation ); 149throw ; 150 } 151 152return allocation .base ; 153 } 154 155void free (void * base ) { 156if (base == nullptr ) { 157return ; 158 } 159 160 std::lock_guard < std::mutex > lock (mutex_ ); 161 162auto allocation_it = allocations_ .find (base ); 163if (allocation_it == allocations_ .end ()) { 164GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: unknown allocation %p\n" ,__func__ ,base ); 165return ; 166 } 167 168pool_allocation allocation = allocation_it -> second ; 169allocations_ .erase (allocation_it ); 170 171auto chunk_it = find_chunk_locked (allocation ); 172if (chunk_it == chunks_ .end ()) { 173GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: unknown chunk for allocation %p size %zu\n" ,__func__ , 174allocation .base ,allocation .size ); 175return ; 176 } 177 178auto * chunk_base = chunk_it -> base ; 179auto * alloc_base = static_cast < uint8_t *> (allocation .base ); 180if (alloc_base < chunk_base || alloc_base >=chunk_base + chunk_it -> size ) { 181GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: allocation %p out of chunk range %p..%p\n" ,__func__ , 182allocation .base ,chunk_base ,chunk_base + chunk_it -> size ); 183return ; 184 } 185 186const size_t offset = static_cast < size_t > (alloc_base - chunk_base ); 187if (offset > chunk_it -> size || allocation .size > chunk_it -> size - offset ) { 188GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: allocation %p size %zu exceeds chunk size %zu\n" ,__func__ , 189allocation .base ,allocation .size ,chunk_it -> size ); 190return ; 191 } 192 193insert_free_block_locked (* chunk_it , {offset ,allocation .size }); 194maybe_release_empty_chunk_locked (chunk_it ); 195 } 196 197protected : 198void release_chunks () { 199 std::lock_guard < std::mutex > lock (mutex_ ); 200 201allocations_ .clear (); 202for (auto & chunk :chunks_ ) { 203dealloc_chunk (& chunk ); 204 } 205chunks_ .clear (); 206 } 207 208size_t default_chunk_size ()const {return default_chunk_size_ ; } 209 210static void clear_chunk (pool_chunk * chunk ) { 211chunk -> base = nullptr ; 212chunk -> size = 0 ; 213chunk -> fd = -1 ; 214chunk -> free_blocks .clear (); 215 } 216 217virtual bool alloc_chunk (size_t min_size ,size_t alignment ,void * hint_addr ,pool_chunk * chunk )= 0 ; 218virtual void dealloc_chunk (pool_chunk * chunk )= 0 ; 219 220private : 221struct alloc_candidate { 222size_t chunk_index {0 }; 223size_t block_index {0 }; 224size_t aligned_offset {0 }; 225uintptr_t address { std::numeric_limits < uintptr_t > ::max () }; 226bool valid { false }; 227 }; 228 229 std::vector < pool_chunk > ::iterator find_chunk_locked (const pool_allocation & allocation ) { 230return std::find_if (chunks_ .begin (),chunks_ .end (), [& ](const pool_chunk & chunk ) { 231return chunk .base == allocation .chunk_base && chunk .size == allocation .chunk_size ; 232 }); 233 } 234 235bool add_chunk_locked (size_t min_size ,size_t alignment ) { 236pool_chunk chunk ; 237const size_t chunk_request = default_chunk_size_ == 0 ?min_size : std::max (min_size ,default_chunk_size_ ); 238void * hint_addr = nullptr ; 239 240for (const auto & existing_chunk :chunks_ ) { 241auto * chunk_end = existing_chunk .base + existing_chunk .size ; 242if (hint_addr == nullptr || chunk_end > hint_addr ) { 243hint_addr = chunk_end ; 244 } 245 } 246 247if (!alloc_chunk (chunk_request ,alignment ,hint_addr ,& chunk )) { 248return false; 249 } 250 251if (chunk .base == nullptr || chunk .size < min_size ) { 252GGML_LOG_ERROR ( 253"CPU_RISCV64_SPACEMIT: %s: invalid chunk returned for request size %zu, chunk_base=%p chunk_size=%zu\n" , 254__func__ ,min_size ,chunk .base ,chunk .size ); 255dealloc_chunk (& chunk ); 256return false; 257 } 258 259try { 260chunk .free_blocks .push_back ({0 ,chunk .size }); 261chunks_ .push_back (std::move (chunk )); 262 }catch (const std::bad_alloc & ) { 263dealloc_chunk (& chunk ); 264throw ; 265 } 266 267return true; 268 } 269 270void rollback_allocation_locked (const pool_allocation & allocation ) { 271auto chunk_it = find_chunk_locked (allocation ); 272if (chunk_it == chunks_ .end ()) { 273GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: failed to rollback allocation %p, owning chunk not found\n" , 274__func__ ,allocation .base ); 275return ; 276 } 277 278auto * chunk_base = chunk_it -> base ; 279auto * alloc_base = static_cast < uint8_t *> (allocation .base ); 280if (alloc_base < chunk_base || alloc_base >=chunk_base + chunk_it -> size ) { 281GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: failed to rollback allocation %p, chunk range is invalid\n" , 282__func__ ,allocation .base ); 283return ; 284 } 285 286const size_t offset = static_cast < size_t > (alloc_base - chunk_base ); 287if (offset > chunk_it -> size || allocation .size > chunk_it -> size - offset ) { 288GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: failed to rollback allocation %p size %zu\n" ,__func__ , 289allocation .base ,allocation .size ); 290return ; 291 } 292 293insert_free_block_locked (* chunk_it , {offset ,allocation .size }); 294maybe_release_empty_chunk_locked (chunk_it ); 295 } 296 297bool try_alloc_locked (size_t size ,size_t alignment ,pool_allocation * allocation ) { 298alloc_candidate best ; 299 300for (size_t chunk_index = 0 ;chunk_index < chunks_ .size ();++ chunk_index ) { 301const auto & chunk = chunks_ [chunk_index ]; 302for (size_t block_index = 0 ;block_index < chunk .free_blocks .size ();++ block_index ) { 303const auto & block = chunk .free_blocks [block_index ]; 304 305uintptr_t aligned_addr = 0 ; 306const auto block_addr = reinterpret_cast < uintptr_t > (chunk .base + block .offset ); 307if (!align_up_uintptr (block_addr ,alignment ,& aligned_addr )) { 308continue ; 309 } 310 311if (aligned_addr < block_addr ) { 312continue ; 313 } 314 315const size_t aligned_offset = block .offset + static_cast < size_t > (aligned_addr - block_addr ); 316const size_t padding = aligned_offset - block .offset ; 317if (padding > block .size || size > block .size - padding ) { 318continue ; 319 } 320 321if (!best .valid || aligned_addr < best .address ) { 322best .chunk_index = chunk_index ; 323best .block_index = block_index ; 324best .aligned_offset = aligned_offset ; 325best .address = aligned_addr ; 326best .valid = true; 327 } 328 } 329 } 330 331if (!best .valid ) { 332return false; 333 } 334 335auto & chunk = chunks_ [best .chunk_index ]; 336const free_block block = chunk .free_blocks [best .block_index ]; 337const size_t padding = best .aligned_offset - block .offset ; 338const size_t alloc_end = best .aligned_offset + size ; 339const size_t block_end = block .offset + block .size ; 340 341chunk .free_blocks .erase (chunk .free_blocks .begin ()+ best .block_index ); 342auto insert_it = chunk .free_blocks .begin ()+ best .block_index ; 343if (padding != 0 ) { 344insert_it = chunk .free_blocks .insert (insert_it , {block .offset ,padding }); 345++ insert_it ; 346 } 347if (alloc_end < block_end ) { 348chunk .free_blocks .insert (insert_it , {alloc_end ,block_end - alloc_end }); 349 } 350 351allocation -> chunk_base = chunk .base ; 352allocation -> chunk_size = chunk .size ; 353allocation -> base = chunk .base + best .aligned_offset ; 354allocation -> size = size ; 355return true; 356 } 357 358void maybe_release_empty_chunk_locked (std::vector < pool_chunk > ::iterator chunk_it ) { 359if (chunk_it -> free_blocks .size ()!= 1 ) { 360return ; 361 } 362 363const auto & block = chunk_it -> free_blocks .front (); 364if (block .offset != 0 || block .size != chunk_it -> size ) { 365return ; 366 } 367 368dealloc_chunk (&* chunk_it ); 369chunks_ .erase (chunk_it ); 370 } 371 372void insert_free_block_locked (pool_chunk & chunk ,free_block block ) { 373auto it = chunk .free_blocks .begin (); 374while (it != chunk .free_blocks .end ()&& it -> offset < block .offset ) { 375++ it ; 376 } 377 378if (it != chunk .free_blocks .begin ()) { 379const auto & prev = * (it - 1 ); 380if (prev .offset + prev .size > block .offset ) { 381GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: overlapping free block at offset %zu size %zu\n" ,__func__ , 382block .offset ,block .size ); 383return ; 384 } 385 } 386 387if (it != chunk .free_blocks .end ()&& block .offset + block .size > it -> offset ) { 388GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: overlapping next free block at offset %zu size %zu\n" ,__func__ , 389block .offset ,block .size ); 390return ; 391 } 392 393it = chunk .free_blocks .insert (it ,block ); 394 395if (it != chunk .free_blocks .begin ()) { 396auto prev = it - 1 ; 397if (prev -> offset + prev -> size == it -> offset ) { 398it -> offset = prev -> offset ; 399it -> size += prev -> size ; 400it = chunk .free_blocks .erase (prev ); 401 } 402 } 403 404if (it + 1 != chunk .free_blocks .end ()&& it -> offset + it -> size == (it + 1 )-> offset ) { 405it -> size += (it + 1 )-> size ; 406chunk .free_blocks .erase (it + 1 ); 407 } 408 } 409 410 std::mutex mutex_ ; 411 std::vector < pool_chunk > chunks_ ; 412 std::unordered_map < void * ,pool_allocation > allocations_ ; 413size_t default_chunk_size_ {0 }; 414}; 415 416class spine_mem_pool_posix final :public spine_mem_pool_manager { 417public : 418spine_mem_pool_posix () :spine_mem_pool_manager (0 ) {} 419 420 ~spine_mem_pool_posix ()override {release_chunks (); } 421 422private : 423bool alloc_chunk (size_t min_size ,size_t alignment ,void * hint_addr ,pool_chunk * chunk )override { 424 (void )hint_addr ; 425 426const size_t alloc_alignment = std::max (alignment ,sizeof (void * )); 427void * base = nullptr ; 428const int rc = posix_memalign (& base ,alloc_alignment ,min_size ); 429if (rc != 0 ) { 430GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: posix_memalign failed for size %zu alignment %zu, rc=%d\n" , 431__func__ ,min_size ,alloc_alignment ,rc ); 432return false; 433 } 434 435chunk -> base = static_cast < uint8_t *> (base ); 436chunk -> size = min_size ; 437chunk -> fd = -1 ; 438return true; 439 } 440 441void dealloc_chunk (pool_chunk * chunk )override { 442 std::free (chunk -> base ); 443clear_chunk (chunk ); 444 } 445}; 446 447class spine_mem_pool_transparent_hugepage final :public spine_mem_pool_manager { 448public : 449spine_mem_pool_transparent_hugepage () :spine_mem_pool_manager (SPINE_MEM_POOL_CHUNK_SIZE ) {} 450 451 ~spine_mem_pool_transparent_hugepage ()override {release_chunks (); } 452 453private : 454bool alloc_chunk (size_t min_size ,size_t alignment ,void * hint_addr ,pool_chunk * chunk )override { 455 (void )alignment ; 456 457size_t chunk_size = 0 ; 458if (!align_up (min_size ,default_chunk_size (),& chunk_size )) { 459GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: failed to round chunk size for %zu\n" ,__func__ ,min_size ); 460return false; 461 } 462 463void * map_addr = mmap (hint_addr ,chunk_size ,PROT_READ |PROT_WRITE ,MAP_PRIVATE |MAP_ANONYMOUS ,-1 ,0 ); 464if (map_addr == MAP_FAILED ) { 465GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: mmap failed for chunk size %zu, errno=%d\n" ,__func__ ,chunk_size , 466errno ); 467return false; 468 } 469 470if (madvise (map_addr ,chunk_size ,MADV_HUGEPAGE )!= 0 ) { 471GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: madvise(MADV_HUGEPAGE) failed for chunk size %zu, errno=%d\n" , 472__func__ ,chunk_size ,errno ); 473munmap (map_addr ,chunk_size ); 474return false; 475 } 476 477chunk -> base = static_cast < uint8_t *> (map_addr ); 478chunk -> size = chunk_size ; 479chunk -> fd = -1 ; 480return true; 481 } 482 483void dealloc_chunk (pool_chunk * chunk )override { 484if (chunk -> base != nullptr && chunk -> size != 0 && munmap (chunk -> base ,chunk -> size )!= 0 ) { 485GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: munmap failed for chunk %p size %zu, errno=%d\n" ,__func__ , 486chunk -> base ,chunk -> size ,errno ); 487 } 488 489clear_chunk (chunk ); 490 } 491}; 492 493class spine_mem_pool_hugetlb_1g final :public spine_mem_pool_manager { 494public : 495spine_mem_pool_hugetlb_1g () :spine_mem_pool_manager (SPINE_MEM_POOL_1G_REGION_SIZE ) {} 496 497 ~spine_mem_pool_hugetlb_1g ()override {release_chunks (); } 498 499private : 500bool alloc_chunk (size_t min_size ,size_t alignment ,void * hint_addr ,pool_chunk * chunk )override { 501 (void )alignment ; 502 (void )hint_addr ; 503 504size_t region_size = 0 ; 505if (!align_up (min_size ,SPINE_MEM_POOL_1G_REGION_SIZE ,& region_size )) { 506GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: failed to round hugetlb_1g size for %zu\n" ,__func__ ,min_size ); 507return false; 508 } 509 510const int fd = open (SPINE_MEM_POOL_HUGETLB_1G_DEV ,O_RDWR ); 511if (fd < 0 ) { 512GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: open(%s) failed, errno=%d\n" ,__func__ , 513SPINE_MEM_POOL_HUGETLB_1G_DEV ,errno ); 514return false; 515 } 516 517hugetlb_1g_region region ; 518region .size = region_size ; 519region .flags = HUGETLB_1G_FLAG_REQUIRE_PUD ; 520if (ioctl (fd ,HUGETLB_1G_IOC_ALLOC ,& region )< 0 ) { 521GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: HUGETLB_1G_IOC_ALLOC failed for size %zu, errno=%d\n" ,__func__ , 522region_size ,errno ); 523close (fd ); 524return false; 525 } 526 527void * map_addr = mmap (nullptr ,region .size ,PROT_READ |PROT_WRITE ,MAP_SHARED ,fd ,0 ); 528if (map_addr == MAP_FAILED ) { 529GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: mmap failed for hugetlb_1g size %llu, errno=%d\n" ,__func__ , 530static_cast < unsigned long long > (region .size ),errno ); 531ioctl (fd ,HUGETLB_1G_IOC_FREE ); 532close (fd ); 533return false; 534 } 535 536chunk -> base = static_cast < uint8_t *> (map_addr ); 537chunk -> size = region .size ; 538chunk -> fd = fd ; 539return true; 540 } 541 542void dealloc_chunk (pool_chunk * chunk )override { 543if (chunk -> base != nullptr && chunk -> size != 0 && munmap (chunk -> base ,chunk -> size )!= 0 ) { 544GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: munmap failed for hugetlb_1g chunk %p size %zu, errno=%d\n" , 545__func__ ,chunk -> base ,chunk -> size ,errno ); 546 } 547 548if (chunk -> fd >=0 ) { 549if (ioctl (chunk -> fd ,HUGETLB_1G_IOC_FREE )< 0 ) { 550GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: HUGETLB_1G_IOC_FREE failed for chunk %p, errno=%d\n" , 551__func__ ,chunk -> base ,errno ); 552 } 553 554close (chunk -> fd ); 555 } 556 557clear_chunk (chunk ); 558 } 559}; 560 561class spine_mem_pool_shared_mem final :public spine_mem_pool_manager { 562public : 563spine_mem_pool_shared_mem () :spine_mem_pool_manager (SPINE_SHARE_MEM_POOL_CHUNK_SIZE ) {} 564 565 ~spine_mem_pool_shared_mem ()override {release_chunks (); } 566 567private : 568bool alloc_chunk (size_t min_size ,size_t alignment ,void * hint_addr ,pool_chunk * chunk )override { 569 (void )alignment ; 570 571if (hint_addr != nullptr ) { 572GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: shared_mem does not support multiple active chunks\n" ,__func__ ); 573return false; 574 } 575 576if (min_size > default_chunk_size ()) { 577GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: shared_mem request %zu exceeds chunk size %zu\n" ,__func__ , 578min_size ,default_chunk_size ()); 579return false; 580 } 581 582const int fd = open (SPINE_MEM_POOL_TCM_SYNC_MEM_DEV ,O_RDWR |O_SYNC ); 583if (fd < 0 ) { 584GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: open(%s) failed, errno=%d\n" ,__func__ , 585SPINE_MEM_POOL_TCM_SYNC_MEM_DEV ,errno ); 586return false; 587 } 588 589void * map_addr = mmap (nullptr ,default_chunk_size (),PROT_READ |PROT_WRITE ,MAP_SHARED ,fd ,0 ); 590if (map_addr == MAP_FAILED ) { 591GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: mmap failed for %s size %zu, errno=%d\n" ,__func__ , 592SPINE_MEM_POOL_TCM_SYNC_MEM_DEV ,default_chunk_size (),errno ); 593close (fd ); 594return false; 595 } 596 597chunk -> base = static_cast < uint8_t *> (map_addr ); 598chunk -> size = default_chunk_size (); 599chunk -> fd = fd ; 600return true; 601 } 602 603void dealloc_chunk (pool_chunk * chunk )override { 604if (chunk -> base != nullptr && chunk -> size != 0 && munmap (chunk -> base ,chunk -> size )!= 0 ) { 605GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: munmap failed for shared_mem chunk %p size %zu, errno=%d\n" , 606__func__ ,chunk -> base ,chunk -> size ,errno ); 607 } 608 609if (chunk -> fd >=0 ) { 610close (chunk -> fd ); 611 } 612 613clear_chunk (chunk ); 614 } 615}; 616 617spine_mem_pool_manager & get_spine_mem_pool_manager () { 618static std::once_flag pool_once ; 619static std::unique_ptr < spine_mem_pool_manager > selected_pool ; 620static spine_mem_pool_backend selected_backend = spine_mem_pool_backend::none ; 621 622spine_mem_pool_backend backend = global_spine_env_info .mem_backend ; 623if (backend == spine_mem_pool_backend::none ) { 624backend = spine_mem_pool_backend::transparent_hugepage ; 625 } 626 627 std::call_once (pool_once , [& ]() { 628selected_backend = backend ; 629 630switch (selected_backend ) { 631case spine_mem_pool_backend::posix_memalign : 632selected_pool = std::make_unique < spine_mem_pool_posix > (); 633break ; 634case spine_mem_pool_backend::transparent_hugepage : 635selected_pool = std::make_unique < spine_mem_pool_transparent_hugepage > (); 636break ; 637case spine_mem_pool_backend::hugetlb_1g : 638selected_pool = std::make_unique < spine_mem_pool_hugetlb_1g > (); 639break ; 640case spine_mem_pool_backend::none : 641selected_backend = spine_mem_pool_backend::transparent_hugepage ; 642selected_pool = std::make_unique < spine_mem_pool_transparent_hugepage > (); 643break ; 644 } 645 }); 646 647if (backend != selected_backend ) { 648GGML_LOG_ERROR ( 649"CPU_RISCV64_SPACEMIT: %s: mem pool backend is process-global and mutually exclusive, requested=%d but " 650"selected=%d\n" , 651__func__ ,static_cast < int > (backend ),static_cast < int > (selected_backend )); 652 } 653 654if (selected_pool ) { 655return * selected_pool ; 656 } 657 658throw std::bad_alloc (); 659} 660 661spine_mem_pool_manager & get_spine_mem_pool_shared_mem_manager () { 662static std::once_flag shared_mem_pool_once ; 663static std::unique_ptr < spine_mem_pool_shared_mem > shared_mem_pool ; 664 665 std::call_once (shared_mem_pool_once , [& ]() {shared_mem_pool = std::make_unique < spine_mem_pool_shared_mem > (); }); 666 667if (shared_mem_pool ) { 668return * shared_mem_pool ; 669 } 670 671throw std::bad_alloc (); 672} 673 674}// namespace 675 676bool spine_mem_pool_tcm_init (spine_mem_pool_tcm_info * info )noexcept { 677if (info == nullptr ) { 678return false; 679 } 680 681* info = {}; 682 683if (spine_tcm_open_handle (NULL )!= 0 || !spine_tcm_is_available ()) { 684return false; 685 } 686 687spine_tcm_mem_info_t mem_info ; 688if (spine_tcm_mem_info (& mem_info )!= 0 ) { 689return false; 690 } 691 692info -> available = true; 693info -> blk_size = mem_info .blk_size ; 694info -> blk_num = mem_info .blk_num ; 695info -> is_fake_tcm = mem_info .is_fake_tcm != 0 ; 696return true; 697} 698 699void * spine_mem_pool_tcm_mem_get (int cpu_id )noexcept { 700return spine_tcm_mem_get (cpu_id ); 701} 702 703void * spine_mem_pool_tcm_mem_wait (int cpu_id )noexcept { 704return spine_tcm_mem_try_wait (cpu_id ,1000 * 1000 ); 705} 706 707int spine_mem_pool_tcm_mem_release (int cpu_id )noexcept { 708return spine_tcm_mem_release (cpu_id ); 709} 710 711void * spine_mem_pool_alloc (size_t size ,size_t alignment )noexcept { 712try { 713return get_spine_mem_pool_manager ().alloc (size ,alignment ); 714 }catch (const std::bad_alloc & ) { 715GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: bad_alloc while allocating size %zu\n" ,__func__ ,size ); 716return nullptr ; 717 } 718} 719 720void * spine_mem_pool_shared_mem_alloc (size_t size ,size_t alignment )noexcept { 721try { 722return get_spine_mem_pool_shared_mem_manager ().alloc (size ,alignment ); 723 }catch (const std::bad_alloc & ) { 724GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: bad_alloc while allocating shared memory size %zu\n" ,__func__ ,size ); 725return nullptr ; 726 } 727} 728 729void spine_mem_pool_free (void * base )noexcept { 730try { 731get_spine_mem_pool_manager ().free (base ); 732 }catch (const std::bad_alloc & ) { 733GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: bad_alloc while freeing allocation %p\n" ,__func__ ,base ); 734 } 735} 736 737void spine_mem_pool_shared_mem_free (void * base )noexcept { 738try { 739get_spine_mem_pool_shared_mem_manager ().free (base ); 740 }catch (const std::bad_alloc & ) { 741GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: bad_alloc while freeing shared allocation %p\n" ,__func__ ,base ); 742 } 743} 744 745}// namespace ggml::cpu::riscv64_spacemit 746 747extern "C" { 748void * ggml_backend_cpu_riscv64_spacemit_alloc_shared (size_t size ,size_t alignment ) { 749void * result = ggml::cpu::riscv64_spacemit::spine_mem_pool_shared_mem_alloc (size ,alignment ); 750if (result == nullptr ) { 751GGML_LOG_ERROR ("CPU_RISCV64_SPACEMIT: %s: failed to allocate shared memory size %zu alignment %zu\n" ,__func__ , 752size ,alignment ); 753 } 754return result ; 755} 756 757void ggml_backend_cpu_riscv64_spacemit_free_shared (void * ptr ) { 758 ggml::cpu::riscv64_spacemit::spine_mem_pool_shared_mem_free (ptr ); 759} 760}