char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
0190529ec
char/aliceai-t5-moe
1/* 2* Copyright (c) 2023-2026 The ggml authors 3* 4* Permission is hereby granted, free of charge, to any person obtaining a copy 5* of this software and associated documentation files (the "Software"), to 6* deal in the Software without restriction, including without limitation the 7* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8* sell copies of the Software, and to permit persons to whom the Software is 9* furnished to do so, subject to the following conditions: 10* 11* The above copyright notice and this permission notice shall be included in 12* all copies or substantial portions of the Software. 13* 14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20* IN THE SOFTWARE. 21*/ 22 23#include "ggml-cann.h" 24 25#include "ggml-backend-impl.h" 26#include "ggml-cann/aclnn_ops.h" 27#include "ggml-cann/common.h" 28#include "ggml-impl.h" 29#include "ggml.h" 30 31#include <acl/acl.h> 32#include <aclnnop/aclnn_trans_matmul_weight.h> 33#include <stdarg.h> 34 35#include <chrono> 36#include <cmath> 37#include <cstdio> 38#include <cstring> 39#include <memory> 40#include <mutex> 41#include <optional> 42#include <queue> 43#include <unordered_map> 44#include <unordered_set> 45#include <vector> 46 47#define GGML_COMMON_DECL_C 48 49#include "ggml-common.h" 50 51#define GGML_CANN_NAME "CANN" 52 53/** 54* @brief Handles CANN errors by printing an error message and aborting. 55* 56* @param stmt The statement that caused the error. 57* @param func The function in which the error occurred. 58* @param file The file in which the error occurred. 59* @param line The line number where the error occurred. 60* @param msg The error message. 61*/ 62[[noreturn ]]void ggml_cann_error (const char * stmt ,const char * func ,const char * file ,int line ,const char * msg ) { 63int32_t id = -1 ; 64aclrtGetDevice (& id ); 65 66GGML_LOG_ERROR ("CANN error: %s\n" ,msg ); 67GGML_LOG_ERROR (" current device: %d, in function %s at %s:%d\n" ,id ,func ,file ,line ); 68GGML_LOG_ERROR (" %s\n" ,stmt ); 69// abort with GGML_ASSERT to get a stack trace 70GGML_ABORT ("CANN error" ); 71} 72 73// Thread-local variable to record the current device of this thread. 74thread_localint g_current_cann_device = -1 ; 75 76/** 77* @brief Set the CANN device to be used. 78* 79* @param device The target device ID to set. 80*/ 81void ggml_cann_set_device (const int32_t device ) { 82// int current_device = -1; 83// Note: In some CANN versions, if no device has been set yet, 84// aclrtGetDevice(¤t_device) may return 0 by default. 85// aclrtGetDevice(¤t_device); 86 87// If the current device is already the target one, no need to switch. 88if (device == g_current_cann_device ) { 89return ; 90 } 91 92// Switch to the new device. 93ACL_CHECK (aclrtSetDevice (device )); 94 95// Update the global device record. 96g_current_cann_device = device ; 97} 98 99/** 100* @brief Get the value of the specified environment variable (name) as lowercase. 101* if not empty, return a std::string object 102*/ 103std::optional < std::string > get_env_as_lowercase (const std::string & name ) { 104const char * val = std::getenv (name .c_str ()); 105if (!val ) { 106return std::nullopt ; 107 } 108 std::string res = std::string (val ); 109 std::transform (res .begin (),res .end (),res .begin (), ::tolower ); 110return res ; 111} 112 113/** 114* @brief Verify whether the environment variable is a valid value. 115*/ 116bool parse_bool (const std::string & value ) { 117static const std::unordered_set < std::string > valid_values = {"on" ,"1" ,"yes" ,"y" ,"enable" ,"true" }; 118return valid_values .find (value )!= valid_values .end (); 119} 120 121/** 122* @brief Parse a string as an integer, returning 0 if invalid. 123* 124* This function attempts to convert the input string `value` to an `int`. 125* If the string is not a valid integer or is out of the `int` range, 126* it returns 0. 127* 128* @param value The string to parse. 129* @return The parsed integer, or 0 if conversion fails. 130*/ 131int parse_integer (const std::string & value ) { 132try { 133return std::stoi (value ); 134 }catch (...) { 135return 0 ; 136 } 137} 138 139/** 140* @brief Initialize the CANN device information. 141* 142* This function initializes the CANN device information by obtaining the 143* device count and setting the memory allocation granularity for each device. 144* 145* @return A structure containing the device information. 146*/ 147static ggml_cann_device_info ggml_cann_init () { 148ggml_cann_device_info info = {}; 149 150aclError err = aclrtGetDeviceCount ((uint32_t * )& info .device_count ); 151 152if (err != ACL_SUCCESS ) { 153GGML_LOG_ERROR ("%s: failed to initialize CANN: %s\n" ,__func__ ,aclGetRecentErrMsg ()); 154return info ; 155 } 156 157GGML_ASSERT (info .device_count <=GGML_CANN_MAX_DEVICES ); 158 159for (int id = 0 ;id < info .device_count ;++ id ) { 160aclrtPhysicalMemProp prop = {}; 161prop .handleType = ACL_MEM_HANDLE_TYPE_NONE ; 162prop .allocationType = ACL_MEM_ALLOCATION_TYPE_PINNED ; 163prop .memAttr = ACL_HBM_MEM_HUGE ; 164prop .location .type = ACL_MEM_LOCATION_TYPE_DEVICE ; 165prop .location .id = id ; 166prop .reserve = 0 ; 167err = aclrtMemGetAllocationGranularity (& prop ,ACL_RT_MEM_ALLOC_GRANULARITY_RECOMMENDED , 168& info .devices [id ].vmm_granularity ); 169info .devices [id ].vmm = err == ACL_SUCCESS ; 170 171size_t free ,total ; 172ggml_backend_cann_get_device_memory (id ,& free ,& total ); 173info .devices [id ].total_vram = free ; 174 } 175 176// TODO: add more device info later. 177return info ; 178} 179 180/** 181* @brief Retrieve the CANN device information. 182* 183* This function returns a reference to a structure containing the CANN device 184* information. The device information is initialized once and reused on 185* subsequent calls. 186* 187* @return A reference to the structure containing the device information. 188*/ 189const ggml_cann_device_info & ggml_cann_info () { 190static ggml_cann_device_info info = ggml_cann_init (); 191return info ; 192} 193 194//#define DEBUG_CANN_MALLOC 195/** 196* @brief A pool of CANN buffers(priority segment buffer). 197* 198* This class manages a pool of CANN buffers for a specific device. 199*/ 200struct ggml_cann_pool_buf_prio :public ggml_cann_pool { 201/** 202* @brief The maximum reuse margin for a buffer. 203*/ 204static const size_t max_reuse_margin = 1ull <<22 ;// 4MB 205 206/** 207* @brief The minimum free margin for a buffer. 208*/ 209static const size_t min_free_margin = 1ull <<20 ;// 1MB 210 211/** 212* @brief The alignment for buffer allocation. 213*/ 214static const size_t alignment = 128 ; 215 216/** 217* @brief The device ID associated with this buffer pool. 218*/ 219int device ; 220 221/** 222* @brief Whether to disable clean during buffer allocation. 223*/ 224bool disable_clean = false; 225 226/** 227* @brief Structure representing a CANN buffer. 228*/ 229struct ggml_cann_buffer { 230void * ptr = nullptr ;///< Pointer to the buffer. 231size_t size = 0 ;///< Size of the buffer. 232 std::chrono::steady_clock::time_point last_used ;///< Last used time. 233 234bool operator> (const ggml_cann_buffer & other )const {return size > other .size ; } 235 }; 236 237/** 238* @brief Array of CANN buffers in the pool. 239*/ 240 std::unordered_map < void * ,size_t > buffer_pool ; 241 std::priority_queue < ggml_cann_buffer , std::vector < ggml_cann_buffer > , std::greater <>> free_buffers ; 242 243/** 244* @brief Total size of all buffers in the pool. 245*/ 246size_t pool_size = 0 ; 247 248/** 249* @brief Constructor to initialize the buffer pool for a specific device. 250* 251* @param device The device ID to associate with this buffer pool. 252*/ 253explicit ggml_cann_pool_buf_prio (int device ) :device (device ) { 254disable_clean = parse_bool (get_env_as_lowercase ("GGML_CANN_DISABLE_BUF_POOL_CLEAN" ).value_or ("" )); 255 } 256 257/** 258* @brief Destructor to free all buffers in the pool. 259*/ 260 ~ggml_cann_pool_buf_prio () { 261ggml_cann_set_device (device ); 262for (auto & [b_ptr ,b_size ] :buffer_pool ) { 263aclrtFree (b_ptr ); 264pool_size -= b_size ; 265 } 266buffer_pool .clear (); 267GGML_ASSERT (pool_size == 0 ); 268 } 269 270/** 271* @brief Allocate a buffer of the given size. 272* 273* @param size The size of the buffer to allocate. 274* @param actual_size A pointer to a variable to receive the actual size of 275* the allocated buffer. 276* @return A pointer to the allocated buffer. 277*/ 278void * alloc (size_t size ,size_t * actual_size )override { 279size = GGML_PAD (size ,alignment ); 280if (size == 0 ) { 281size = alignment ; 282 } 283 284void * ptr = nullptr ; 285auto now = std::chrono::steady_clock::now (); 286 287 std::vector < ggml_cann_buffer > free_buffers_rest ; 288free_buffers_rest .reserve (free_buffers .size ()); 289while (!free_buffers .empty ()) { 290auto b = free_buffers .top (); 291free_buffers .pop (); 292 293if (b .size >=size ) { 294// reuse the buffer if the size is enough 295const size_t margin = b .size - size ; 296if (margin <=max_reuse_margin ) { 297* actual_size = b .size ; 298ptr = b .ptr ; 299#ifdef DEBUG_CANN_MALLOC 300GGML_LOG_INFO ( 301"cann pool[%d]: reused %p, " 302"pool_size = %5u MB, " 303"size = %5u MB, " 304"margin = %5u MB\n" , 305device ,b .ptr , (uint32_t ) (GGML_PAD (pool_size ,1048576 ) /1048576 ), 306 (uint32_t ) (GGML_PAD (size ,1048576 ) /1048576 ), 307 (uint32_t ) (GGML_PAD (margin ,1048576 ) /1048576 )); 308#endif 309break ; 310 } 311 } 312 313bool should_clean = !disable_clean && b .size > min_free_margin && 314 std::chrono::duration_cast < std::chrono::milliseconds > (now - b .last_used ).count ()> 100 ; 315if (should_clean ) { 316// free the buffer if the size is needed to be freed 317ACL_CHECK (aclrtFree (b .ptr )); 318pool_size -= b .size ; 319buffer_pool .erase (b .ptr ); 320#ifdef DEBUG_CANN_MALLOC 321GGML_LOG_INFO ( 322"cann pool[%d]: clean %p, " 323"pool_size = %5u MB, " 324"size = %5u MB\n" , 325device ,b .ptr , (uint32_t ) (GGML_PAD (pool_size ,1048576 ) /1048576 ), 326 (uint32_t ) (GGML_PAD (b .size ,1048576 ) /1048576 )); 327#endif 328continue ; 329 } 330free_buffers_rest .push_back (b ); 331 } 332for (ggml_cann_buffer & b :free_buffers_rest ) { 333free_buffers .push (std::move (b )); 334 } 335 336#ifdef DEBUG_CANN_MALLOC 337GGML_LOG_INFO ("cann pool[%d] free pool_size = %5u MB\n\n" ,device , 338 (uint32_t ) (GGML_PAD (pool_size ,1048576 ) /1048576 )); 339#endif 340if (ptr != nullptr ) { 341return ptr ; 342 } 343 344// allocate a new buffer if no buffer can be reused 345ggml_cann_set_device (device ); 346ACL_CHECK (aclrtMalloc (& ptr ,size ,ACL_MEM_MALLOC_HUGE_FIRST )); 347* actual_size = size ; 348pool_size += size ; 349#ifdef DEBUG_CANN_MALLOC 350GGML_LOG_INFO ( 351"cann pool[%d]: allocate %p, " 352"pool_size = %5u MB, " 353"size = %5u MB\n" , 354device ,ptr , (uint32_t ) (GGML_PAD (pool_size ,1048576 ) /1048576 ), 355 (uint32_t ) (GGML_PAD (size ,1048576 ) /1048576 )); 356#endif 357buffer_pool .emplace (ptr ,size ); 358return ptr ; 359 } 360 361/** 362* @brief Free a buffer and return it to the pool. 363* 364* @param ptr Pointer to the buffer to free. 365* @param size Size of the buffer to free. 366*/ 367void free (void * ptr ,size_t size )override { 368GGML_UNUSED (size ); 369auto it = buffer_pool .find (ptr ); 370if (it == buffer_pool .end ()) { 371GGML_ABORT ("cann pool[%d]: buffer %p not found in pool\n" ,device ,ptr ); 372 } 373 374auto now = std::chrono::steady_clock::now (); 375free_buffers .emplace (ggml_cann_buffer {ptr ,it -> second ,now }); 376#ifdef DEBUG_CANN_MALLOC 377GGML_LOG_INFO ( 378"cann pool[%d]: return %p, " 379"pool_size = %5u MB\n" , 380device ,ptr , (uint32_t ) (GGML_PAD (pool_size ,1048576 ) /1048576 )); 381#endif 382 } 383}; 384 385/** 386* @brief A pool of CANN buffers(segment buffer). 387* 388* This class manages a pool of CANN buffers for a specific device. 389*/ 390struct ggml_cann_pool_buf :public ggml_cann_pool { 391/** 392* @brief The maximum reuse margin for a buffer. 393*/ 394static const size_t max_reuse_margin = 1ull <<22 ;// 4MB 395 396/** 397* @brief The minimum free margin for a buffer. 398*/ 399static const size_t min_free_margin = 1ull <<20 ;// 1MB 400 401/** 402* @brief The alignment for buffer allocation. 403*/ 404static const size_t alignment = 128 ; 405 406/** 407* @brief The maximum number of buffers in the pool. 408*/ 409static const int MAX_BUFFERS = 256 ; 410 411/** 412* @brief The device ID associated with this buffer pool. 413*/ 414int device ; 415 416/** 417* @brief Whether to disable clean during buffer allocation. 418*/ 419bool disable_clean = false; 420 421/** 422* @brief Structure representing a CANN buffer. 423*/ 424struct ggml_cann_buffer { 425void * ptr = nullptr ;///< Pointer to the buffer memory. 426size_t size = 0 ;///< Size of the buffer. 427bool used = false;///< Whether the buffer is currently in use. 428 std::chrono::steady_clock::time_point last_used ;///< Last used time. 429 }; 430 431/** 432* @brief Array of CANN buffers in the pool. 433*/ 434ggml_cann_buffer buffer_pool [MAX_BUFFERS ]= {}; 435 436/** 437* @brief Total size of all buffers in the pool. 438*/ 439size_t pool_size = 0 ; 440 441/** 442* @brief Constructor to initialize the buffer pool for a specific device. 443* 444* @param device The device ID to associate with this buffer pool. 445*/ 446explicit ggml_cann_pool_buf (int device ) :device (device ) { 447disable_clean = parse_bool (get_env_as_lowercase ("GGML_CANN_DISABLE_BUF_POOL_CLEAN" ).value_or ("" )); 448 } 449 450/** 451* @brief Destructor to free all buffers in the pool. 452*/ 453 ~ggml_cann_pool_buf () { 454ggml_cann_set_device (device ); 455for (int i = 0 ;i < MAX_BUFFERS ;++ i ) { 456ggml_cann_buffer & b = buffer_pool [i ]; 457if (b .ptr != nullptr ) { 458aclrtFree (b .ptr ); 459pool_size -= b .size ; 460 } 461 } 462GGML_ASSERT (pool_size == 0 ); 463 } 464 465/** 466* @brief Allocate a buffer of the given size. 467* 468* @param size The size of the buffer to allocate. 469* @param actual_size A pointer to a variable to receive the actual size of 470* the allocated buffer. 471* @return A pointer to the allocated buffer. 472*/ 473void * alloc (size_t size ,size_t * actual_size )override { 474size = GGML_PAD (size ,alignment ); 475if (size == 0 ) { 476size = alignment ; 477 } 478 479void * ptr = nullptr ; 480auto now = std::chrono::steady_clock::now (); 481 482int i = 0 ; 483for (;i < MAX_BUFFERS ;++ i ) { 484ggml_cann_buffer & b = buffer_pool [i ]; 485if (b .ptr == nullptr ) { 486break ; 487 } 488if (b .used ) { 489continue ; 490 } 491if (b .size >=size ) { 492// reuse the buffer if the size is enough 493const size_t margin = b .size - size ; 494if (margin <=max_reuse_margin ) { 495* actual_size = b .size ; 496b .used = true; 497ptr = b .ptr ; 498#ifdef DEBUG_CANN_MALLOC 499GGML_LOG_INFO ( 500"cann pool[%d]: reused %p, " 501"pool_size = %5u MB, " 502"size = %5u MB, " 503"margin = %5u MB\n" , 504device ,b .ptr , (uint32_t ) (GGML_PAD (pool_size ,1048576 ) /1048576 ), 505 (uint32_t ) (GGML_PAD (size ,1048576 ) /1048576 ), 506 (uint32_t ) (GGML_PAD (margin ,1048576 ) /1048576 )); 507#endif 508break ; 509 } 510 } 511 512bool should_clean = !disable_clean && b .size > min_free_margin && 513 std::chrono::duration_cast < std::chrono::milliseconds > (now - b .last_used ).count ()> 100 ; 514if (should_clean ) { 515// free the buffer if the size is needed to be freed 516ACL_CHECK (aclrtFree (b .ptr )); 517pool_size -= b .size ; 518#ifdef DEBUG_CANN_MALLOC 519GGML_LOG_INFO ( 520"cann pool[%d]: clean %p, " 521"pool_size = %5u MB, " 522"size = %5u MB\n" , 523device ,b .ptr , (uint32_t ) (GGML_PAD (pool_size ,1048576 ) /1048576 ), 524 (uint32_t ) (GGML_PAD (b .size ,1048576 ) /1048576 )); 525#endif 526b .ptr = nullptr ; 527 } 528 } 529if (ptr != nullptr ) { 530return ptr ; 531 } 532 533if (i < MAX_BUFFERS ) { 534// allocate a new buffer if no buffer can be reused 535ggml_cann_buffer & b = buffer_pool [i ]; 536ggml_cann_set_device (device ); 537ACL_CHECK (aclrtMalloc (& b .ptr ,size ,ACL_MEM_MALLOC_HUGE_FIRST )); 538pool_size += size ; 539* actual_size = size ; 540b .size = size ; 541b .used = true; 542if (i >=MAX_BUFFERS - 8 ) { 543GGML_LOG_WARN ("cann pool[%d]: slots almost full\n" ,device ); 544 } 545#ifdef DEBUG_CANN_MALLOC 546GGML_LOG_INFO ( 547"cann pool[%d]: allocate %p, " 548"pool_size = %5u MB, " 549"size = %5u MB\n" , 550device ,b .ptr , (uint32_t ) (GGML_PAD (pool_size ,1048576 ) /1048576 ), 551 (uint32_t ) (GGML_PAD (b .size ,1048576 ) /1048576 )); 552#endif 553return b .ptr ; 554 } 555 556GGML_ABORT ("cann pool[%d]: slots full\n" ,device ); 557 } 558 559/** 560* @brief Free a buffer and return it to the pool. 561* 562* @param ptr Pointer to the buffer to free. 563* @param size Size of the buffer to free. 564*/ 565void free (void * ptr ,size_t size )override { 566GGML_UNUSED (size ); 567for (int i = 0 ;i < MAX_BUFFERS ;++ i ) { 568ggml_cann_buffer & b = buffer_pool [i ]; 569if (b .ptr != ptr ) { 570continue ; 571 } 572b .used = false; 573b .last_used = std::chrono::steady_clock::now (); 574#ifdef DEBUG_CANN_MALLOC 575GGML_LOG_INFO ( 576"cann pool[%d]: return %p, " 577"pool_size = %5u MB\n" , 578device ,b .ptr , (uint32_t ) (GGML_PAD (pool_size ,1048576 ) /1048576 )); 579#endif 580return ; 581 } 582GGML_ABORT ("cann pool[%d]: slots full\n" ,device ); 583 } 584}; 585 586/** 587* @brief A pool of CANN buffers with virtual memory. 588* 589* This class manages a pool of CANN buffers with virtual memory for a specific 590* device. 591*/ 592struct ggml_cann_pool_vmm :public ggml_cann_pool { 593/** 594* @brief The maximum size of the virtual memory pool (32 GB). 595*/ 596size_t max_size ; 597 598/** 599* @brief The device ID associated with this buffer pool. 600*/ 601int device ; 602 603/** 604* @brief Pointer to the start of the virtual memory pool. 605*/ 606void * pool_addr = 0 ; 607 608/** 609* @brief Amount of virtual memory used in the pool. 610*/ 611size_t pool_used = 0 ; 612 613/** 614* @brief Total size of the virtual memory pool. 615*/ 616size_t pool_size = 0 ; 617 618/** 619* @brief Allocation granularity for the virtual memory pool. 620*/ 621size_t granularity ; 622 623/** 624* @brief Handles for the physical memory allocated. 625*/ 626 std::vector < aclrtDrvMemHandle > handles ; 627 628/** 629* @brief Offsets for the mapped memory regions. 630*/ 631 std::vector < void *> map_offsets ; 632 633/** 634* @brief Constructor to initialize the buffer pool with virtual memory for 635* a specific device. 636* 637* @param device The device ID to associate with this buffer pool. 638*/ 639explicit ggml_cann_pool_vmm (int device ) :device (device ) { 640auto dev = ggml_cann_info ().devices [device ]; 641granularity = dev .vmm_granularity ; 642max_size = dev .total_vram ; 643 } 644 645/** 646* @brief Destructor to free all buffers in the virtual memory pool. 647*/ 648 ~ggml_cann_pool_vmm () { 649if (pool_addr != 0 ) { 650for (auto & offset :map_offsets ) { 651ACL_CHECK (aclrtUnmapMem (offset )); 652 } 653for (auto & handle :handles ) { 654ACL_CHECK (aclrtFreePhysical (handle )); 655 } 656ACL_CHECK (aclrtReleaseMemAddress (pool_addr )); 657 } 658 } 659 660/** 661* @brief Allocate a buffer of the given size in the virtual memory pool. 662* 663* @param size The size of the buffer to allocate. 664* @param actual_size A pointer to a variable to receive the actual size of 665* the allocated buffer. 666* @return A pointer to the allocated buffer. 667*/ 668void * alloc (size_t size ,size_t * actual_size )override { 669// round up the allocation size to the alignment to ensure that all 670// allocations are aligned for all data types 671const size_t alignment = 128 ; 672size = GGML_PAD (size ,alignment ); 673if (size == 0 ) { 674size = alignment ; 675 } 676 677size_t avail = pool_size - pool_used ; 678 679if (size > avail ) { 680// round up to the next multiple of the granularity 681size_t reserve_size = size - avail ; 682reserve_size = GGML_PAD (reserve_size ,granularity ); 683 684GGML_ASSERT (pool_size + reserve_size <=max_size ); 685 686// allocate more physical memory 687aclrtPhysicalMemProp prop = {}; 688prop .handleType = ACL_MEM_HANDLE_TYPE_NONE ; 689prop .allocationType = ACL_MEM_ALLOCATION_TYPE_PINNED ; 690prop .memAttr = ACL_HBM_MEM_HUGE ; 691prop .location .type = ACL_MEM_LOCATION_TYPE_DEVICE ; 692prop .location .id = device ; 693prop .reserve = 0 ; 694aclrtDrvMemHandle handle ; 695ACL_CHECK (aclrtMallocPhysical (& handle ,reserve_size ,& prop ,0 )); 696 697// reserve virtual address space (if not already reserved) 698if (pool_addr == 0 ) { 699ACL_CHECK (aclrtReserveMemAddress (& pool_addr ,max_size ,0 ,NULL ,1 )); 700 } 701 702// map at the end of the pool 703ACL_CHECK (aclrtMapMem ((char * )pool_addr + pool_size ,reserve_size ,0 ,handle ,0 )); 704 705handles .push_back (handle ); 706map_offsets .push_back ((char * )pool_addr + pool_size ); 707 708// add to the pool 709pool_size += reserve_size ; 710 711#ifdef DEBUG_CANN_MALLOC 712GGML_LOG_INFO ("cann pool[%d]: size increased to %llu MB (reserved %llu MB)\n" ,device , 713 (unsigned long long ) (pool_size /1024 /1024 ), 714 (unsigned long long ) (reserve_size /1024 /1024 )); 715#endif 716 } 717 718GGML_ASSERT (pool_addr != 0 ); 719 720void * ptr = (void * ) ((char * )pool_addr + pool_used ); 721* actual_size = size ; 722pool_used += size ; 723 724#ifdef DEBUG_CANN_MALLOC 725GGML_LOG_INFO ("cann pool[%d]: allocated %llu bytes at %llx\n" ,device , (unsigned long long )size , 726 (unsigned long long )ptr ); 727#endif 728return ptr ; 729 } 730 731/** 732* @brief Free a buffer and return it to the virtual memory pool. 733* 734* @param ptr Pointer to the buffer to free. 735* @param size Size of the buffer to free. 736*/ 737void free (void * ptr ,size_t size )override { 738#ifdef DEBUG_CANN_MALLOC 739GGML_LOG_INFO ("cann pool[%d]: freed %llu bytes at %llx\n" ,device , (unsigned long long )size , 740 (unsigned long long )ptr ); 741#endif 742 743pool_used -= size ; 744 745// all deallocations must be in reverse order of the allocations 746GGML_ASSERT (ptr == (void * ) ((char * )pool_addr + pool_used )); 747 } 748}; 749 750/** 751* @brief Create a new CANN pool for a specific device. 752* 753* Factory method to create a new CANN pool object based on the device type. 754* 755* @param device The device ID for which to create the pool. 756* @return A unique pointer to the created CANN pool. 757*/ 758std::unique_ptr < ggml_cann_pool > ggml_backend_cann_context::new_pool_for_device (int device ) { 759 std::string mem_pool_type = get_env_as_lowercase ("GGML_CANN_MEM_POOL" ).value_or ("" ); 760 761if (mem_pool_type == "prio" ) { 762GGML_LOG_INFO ("%s: device %d use buffer pool with priority queue\n" ,__func__ ,device ); 763return std::unique_ptr < ggml_cann_pool > (new ggml_cann_pool_buf_prio (device )); 764 } 765 766if (ggml_cann_info ().devices [device ].vmm && mem_pool_type != "leg" ) { 767GGML_LOG_INFO ("%s: device %d use vmm pool\n" ,__func__ ,device ); 768return std::unique_ptr < ggml_cann_pool > (new ggml_cann_pool_vmm (device )); 769 } 770 771GGML_LOG_INFO ("%s: device %d use buffer pool\n" ,__func__ ,device ); 772return std::unique_ptr < ggml_cann_pool > (new ggml_cann_pool_buf (device )); 773} 774 775// cann buffer 776 777/** 778* @brief Tracks multi-threaded write progress for a single tensor. 779* 780* When multiple threads call set_tensor on different chunks of the same tensor, 781* this tracker accumulates progress and defers post-processing (quantized format 782* transform or ND-to-NZ conversion) until all data has been written. 783*/ 784struct TensorSetTracker { 785 std::mutex mtx ;///< Protects concurrent access to this tracker 786size_t bytes_written = 0 ;///< Accumulated bytes written so far 787size_t total_bytes = 0 ;///< Target size (full tensor) 788 std::vector < uint8_t > host_buffer ;///< Host staging buffer for quantized tensors 789}; 790 791/** 792* @brief Context for managing a CANN buffer associated with a specific device. 793* 794* This structure holds information about a CANN buffer, including the device 795* ID, device pointer, and a name derived from GGML_CANN_NAME and the device ID. 796*/ 797struct ggml_backend_cann_buffer_context { 798int32_t device ;///< The device ID associated with this buffer context. 799void * dev_ptr = nullptr ;///< Pointer to the device memory allocated for the buffer. 800 801 std::mutex tracker_mutex ;///< Protects the trackers map 802 std::unordered_map < void * , std::unique_ptr < TensorSetTracker >> trackers ; 803 804/** 805* @brief Constructor to initialize the CANN buffer context. 806* 807* @param device The device ID associated with this buffer context. 808* @param dev_ptr Pointer to the device memory allocated for the buffer. 809*/ 810ggml_backend_cann_buffer_context (int32_t device ,void * dev_ptr ) :device (device ),dev_ptr (dev_ptr ) {} 811 812/** 813* @brief Destructor to free the device memory allocated for the buffer. 814*/ 815 ~ggml_backend_cann_buffer_context () {ACL_CHECK (aclrtFree (dev_ptr )); } 816 817/** 818* @brief Get or create a tracker for the given tensor. 819*/ 820TensorSetTracker * get_or_create_tracker (ggml_tensor * tensor ) { 821 std::lock_guard < std::mutex > lock (tracker_mutex ); 822auto key = tensor -> data ; 823auto it = trackers .find (key ); 824if (it == trackers .end ()) { 825auto tracker = std::make_unique < TensorSetTracker > (); 826tracker -> total_bytes = ggml_nbytes (tensor ); 827auto * ptr = tracker .get (); 828trackers [key ]= std::move (tracker ); 829return ptr ; 830 } 831return it -> second .get (); 832 } 833 834/** 835* @brief Remove the tracker for the given tensor. 836*/ 837void remove_tracker (ggml_tensor * tensor ) { 838 std::lock_guard < std::mutex > lock (tracker_mutex ); 839trackers .erase (tensor -> data ); 840 } 841}; 842 843// cann buffer type 844/** 845* @brief Structure representing context information for a specific backend 846* buffer type. 847*/ 848struct ggml_backend_cann_buffer_type_context { 849int32_t device ;/**< Device identifier associated with the buffer context. */ 850 std::string name ;/**< Name associated with the buffer context. */ 851}; 852 853/** 854* @brief Retrieves the name associated with a CANN buffer type. 855* 856* This function returns the descriptive name associated with the specified 857* CANN buffer type context. 858* 859* @param buft Pointer to the buffer type context. 860* @return Const pointer to the C-style string containing the name. 861*/ 862static const char * ggml_backend_cann_buffer_type_name (ggml_backend_buffer_type_t buft ) { 863ggml_backend_cann_buffer_type_context * buft_ctx = (ggml_backend_cann_buffer_type_context * )buft -> context ; 864 865return buft_ctx -> name .c_str (); 866} 867 868/** 869* @brief Checks if the backend buffer type is associated with the CANN backend. 870* 871* This function checks whether the provided backend buffer type is associated 872* with the CANN backend based on the comparison of its name retrieval function 873* pointer. 874* 875* @param buft Pointer to the backend buffer type to check. 876* @return bool Returns true if the buffer type is associated with the CANN 877* backend, otherwise false. 878*/ 879static bool ggml_backend_buft_is_cann (ggml_backend_buffer_type_t buft ) { 880return buft -> iface .get_name == ggml_backend_cann_buffer_type_name ; 881} 882 883/** 884* @brief Free resources associated with a CANN buffer. 885* 886* This function frees the resources associated with a CANN buffer, including 887* its context. 888* 889* @param buffer The CANN buffer to free. 890*/ 891static void ggml_backend_cann_buffer_free_buffer (ggml_backend_buffer_t buffer ) { 892ggml_backend_cann_buffer_context * ctx = (ggml_backend_cann_buffer_context * )buffer -> context ; 893delete ctx ; 894} 895 896/** 897* @brief Retrieve the base pointer of a CANN buffer. 898* 899* This function returns the base pointer of a CANN buffer, which points to the 900* device memory allocated for the buffer. 901* 902* @param buffer The CANN buffer whose base pointer is to be retrieved. 903* @return A pointer to the base of the device memory allocated for the buffer. 904*/ 905static void * ggml_backend_cann_buffer_get_base (ggml_backend_buffer_t buffer ) { 906ggml_backend_cann_buffer_context * ctx = (ggml_backend_cann_buffer_context * )buffer -> context ; 907return ctx -> dev_ptr ; 908} 909 910/** 911* @brief Transform quantized Q4.0 tensor data into a format suitable for CANN 912* processing. 913* 914* This function transforms quantized Q4.0 tensor data into a format suitable 915* for CANN processing. It extracts quantization values and scales from the 916* source data and prepares them in a format expected by CANN operations. 917* 918* @param tensor Pointer to the tensor information. 919* @param src Pointer to the source data in Q4.0 format. 920* @param dst Pointer to the destination buffer where transformed data will be 921* stored. 922*/ 923static void ggml_backend_cann_transform_q4_0 (ggml_tensor * tensor ,const void * src ,void * dst ) { 924int64_t n_elems = ggml_nelements (tensor ); 925int64_t groups = n_elems /QK4_0 ; 926size_t quant_bytes = n_elems * sizeof (uint8_t ) /2 ; 927 928uint8_t * quant_offset = (uint8_t * )dst ; 929uint16_t * scale_offset = (uint16_t * ) ((char * )dst + quant_bytes ); 930 931for (int i = 0 ;i < groups ;i ++ ) { 932const block_q4_0 * group = (const block_q4_0 * ) ((const char * )src + i * sizeof (block_q4_0 )); 933* scale_offset = group -> d ; 934scale_offset ++ ; 935 936// 0-15 937for (int j = 0 ;j < QK4_0 /2 ;j += 2 ) { 938 (* quant_offset )= (group -> qs [j ]& 0x0F ); 939 (* quant_offset ) |= ((group -> qs [j + 1 ] <<4 )); 940quant_offset ++ ; 941 } 942 943// 16-31 944for (int j = 0 ;j < QK4_0 /2 ;j += 2 ) { 945 (* quant_offset )= (group -> qs [j ] >>4 ); 946 (* quant_offset ) |= (group -> qs [j + 1 ]& 0xF0 ); 947quant_offset ++ ; 948 } 949 } 950 951// put (uint4b_t -8) into int4b_t 952for (quant_offset = (uint8_t * )dst ;quant_offset < (uint8_t * )dst + quant_bytes ;quant_offset ++ ) { 953 (* quant_offset ) ^=0x88 ; 954 } 955} 956 957/** 958* @brief Transform CANN processed data back into quantized Q4.0 format. 959* 960* This function transforms CANN processed data back into quantized Q4.0 format. 961* It reverses the transformation performed by 962* ggml_backend_cann_transform_q4_0(), converting the data back into its 963* original quantized form. 964* 965* @param tensor Pointer to the tensor information. 966* @param src Pointer to the source buffer containing transformed data. 967* @param dst Pointer to the destination buffer where the Q4.0 formatted data 968* will be stored. 969*/ 970static void ggml_backend_cann_transform_back_q4_0 (const ggml_tensor * tensor ,void * src ,void * dst ) { 971int64_t n_elems = ggml_nelements (tensor ); 972int64_t groups = n_elems /QK4_0 ; 973size_t quant_bytes = n_elems * sizeof (uint8_t ) /2 ; 974 975uint8_t * quant_offset = (uint8_t * )src ; 976uint16_t * scale_offset = (uint16_t * ) ((char * )src + quant_bytes ); 977 978for (;quant_offset < (uint8_t * )src + quant_bytes ;quant_offset ++ ) { 979 (* quant_offset ) ^=0x88 ; 980 } 981quant_offset = (uint8_t * )src ; 982 983for (int i = 0 ;i < groups ;i ++ ) { 984block_q4_0 * group = (block_q4_0 * ) ((char * )dst + i * sizeof (block_q4_0 )); 985group -> d = * scale_offset ; 986scale_offset ++ ; 987 988// 0-15 989for (int j = 0 ;j < QK4_0 /2 ;j += 2 ) { 990group -> qs [j ]= ((* quant_offset )& 0x0F ); 991group -> qs [j + 1 ]= ((* quant_offset ) >>4 ); 992quant_offset ++ ; 993 } 994 995// 16-31 996for (int j = 0 ;j < QK4_0 /2 ;j += 2 ) { 997group -> qs [j ] |= ((* quant_offset ) <<4 ); 998group -> qs [j + 1 ] |= ((* quant_offset )& 0xF0 ); 999quant_offset ++ ; 1000 } 1001 } 1002} 1003 1004/** 1005* @brief Transform quantized Q8.0 tensor data into a format suitable for CANN 1006* processing. 1007* 1008* This function transforms quantized Q8.0 tensor data into a format suitable 1009* for CANN processing. It extracts quantization values and scales from the 1010* source data and prepares them in a format expected by CANN operations. 1011* 1012* @param tensor Pointer to the tensor information. 1013* @param src Pointer to the source data in Q8.0 format. 1014* @param dst Pointer to the destination buffer where transformed data will be 1015* stored. 1016*/ 1017static void ggml_backend_cann_transform_q8_0 (ggml_tensor * tensor ,const void * src ,void * dst ) { 1018int64_t n_elems = ggml_nelements (tensor ); 1019int64_t groups = n_elems /QK8_0 ; 1020size_t quant_bytes = n_elems * sizeof (uint8_t ); 1021 1022uint8_t * quant_offset = (uint8_t * )dst ; 1023uint16_t * scale_offset = (uint16_t * ) ((char * )dst + quant_bytes ); 1024 1025for (int i = 0 ;i < groups ;i ++ ) { 1026const block_q8_0 * group = (const block_q8_0 * ) ((const char * )src + i * sizeof (block_q8_0 )); 1027* scale_offset = group -> d ; 1028scale_offset ++ ; 1029size_t group_quant_size = QK8_0 * sizeof (uint8_t ); 1030memcpy (quant_offset ,group -> qs ,group_quant_size ); 1031quant_offset += group_quant_size ; 1032 } 1033} 1034 1035/** 1036* @brief Transform CANN processed data back into quantized Q8.0 format. 1037* 1038* This function transforms CANN processed data back into quantized Q8.0 format. 1039* It reverses the transformation performed by 1040* ggml_backend_cann_transform_q8_0(), converting the data back into its 1041* original quantized form. 1042* 1043* @param tensor Pointer to the tensor information. 1044* @param src Pointer to the source buffer containing transformed data. 1045* @param dst Pointer to the destination buffer where the Q8.0 formatted data 1046* will be stored. 1047*/ 1048static void ggml_backend_cann_transform_back_q8_0 (const ggml_tensor * tensor ,const void * src ,void * dst ) { 1049int64_t n_elems = ggml_nelements (tensor ); 1050int64_t groups = n_elems /QK8_0 ; 1051size_t quant_bytes = n_elems * sizeof (uint8_t ); 1052 1053const uint8_t * quant_offset = (const uint8_t * )src ; 1054const uint16_t * scale_offset = (const uint16_t * ) ((const char * )src + quant_bytes ); 1055 1056for (int i = 0 ;i < groups ;i ++ ) { 1057block_q8_0 * group = (block_q8_0 * ) ((char * )dst + i * sizeof (block_q8_0 )); 1058group -> d = * scale_offset ; 1059scale_offset ++ ; 1060size_t group_quant_size = QK8_0 * sizeof (uint8_t ); 1061memcpy (group -> qs ,quant_offset ,group_quant_size ); 1062quant_offset += group_quant_size ; 1063 } 1064} 1065 1066/** 1067* @brief Transform tensor data based on its type for CANN processing. 1068* 1069* This function transforms tensor data based on its quantization type for CANN 1070* processing. It dispatches the transformation based on the tensor's type to 1071* specialized functions handling Q4.0 and Q8.0 formats. 1072* 1073* @param tensor Pointer to the tensor information. 1074* @param src Pointer to the source data to be transformed. 1075* @param dst Pointer to the destination buffer where transformed data will be 1076* stored. 1077*/ 1078static void ggml_backend_cann_transform (ggml_tensor * tensor ,const void * src ,void * dst ) { 1079switch (tensor -> type ) { 1080case GGML_TYPE_Q4_0 : 1081ggml_backend_cann_transform_q4_0 (tensor ,src ,dst ); 1082break ; 1083case GGML_TYPE_Q8_0 : 1084ggml_backend_cann_transform_q8_0 (tensor ,src ,dst ); 1085break ; 1086default : 1087break ; 1088 } 1089} 1090 1091/** 1092* @brief Transform CANN processed data back into tensor data based on its type. 1093* 1094* This function transforms CANN processed data back into tensor data based on 1095* its quantization type for Q4.0 and Q8.0 formats. It dispatches the 1096* transformation based on the tensor's type to specialized functions. 1097* 1098* @param tensor Pointer to the tensor information. 1099* @param src Pointer to the source data containing CANN processed data. 1100* @param dst Pointer to the destination buffer where transformed tensor data 1101* will be stored. 1102*/ 1103static void ggml_backend_cann_transform_back (const ggml_tensor * tensor ,void * src ,void * dst ) { 1104switch (tensor -> type ) { 1105case GGML_TYPE_Q4_0 : 1106ggml_backend_cann_transform_back_q4_0 (tensor ,src ,dst ); 1107break ; 1108case GGML_TYPE_Q8_0 : 1109ggml_backend_cann_transform_back_q8_0 (tensor ,src ,dst ); 1110break ; 1111default : 1112break ; 1113 } 1114} 1115 1116/** 1117* @brief Check if transformation is needed for a given tensor type. 1118* 1119* This function checks if transformation is needed for a given tensor type 1120* to prepare data for CANN processing. 1121* 1122* @param type The tensor type to check. 1123* @return true if transformation is needed, false otherwise. 1124*/ 1125static bool need_transform (ggml_type type ) { 1126switch (type ) { 1127case GGML_TYPE_Q4_0 : 1128case GGML_TYPE_Q8_0 : 1129return true; 1130default : 1131return false; 1132 } 1133} 1134 1135/** 1136* @brief Initialize a tensor using data from a CANN buffer. 1137* 1138* This function initializes a tensor using data from a CANN buffer. 1139* It handles special cases such as views and quantization. 1140* 1141* @param buffer The CANN buffer from which to initialize the tensor. 1142* @param tensor Pointer to the tensor to be initialized. 1143*/ 1144static enum ggml_status ggml_backend_cann_buffer_init_tensor (ggml_backend_buffer_t buffer ,ggml_tensor * tensor ) { 1145if (tensor -> view_src != NULL && tensor -> view_offs == 0 ) { 1146GGML_ASSERT (tensor -> view_src -> buffer -> buft == buffer -> buft ); 1147return GGML_STATUS_SUCCESS ; 1148 } 1149 1150// TODO: cann backend doesn't support quantized yet. Just leave the code 1151// here. 1152if (ggml_is_quantized (tensor -> type )) { 1153// Initialize padding to 0 to avoid possible NaN values 1154size_t original_size = ggml_nbytes (tensor ); 1155size_t padded_size = ggml_backend_buft_get_alloc_size (buffer -> buft ,tensor ); 1156 1157if (padded_size > original_size && tensor -> view_src == nullptr ) { 1158size_t memset_size = padded_size - original_size ; 1159ACL_CHECK (aclrtMemset ((char * )tensor -> data + original_size ,memset_size ,0 ,memset_size )); 1160 } 1161 } 1162return GGML_STATUS_SUCCESS ; 1163} 1164 1165/** 1166* @brief Workspace for caching NZ buffers per device. 1167* 1168* This struct manages a device buffer used in NZ computations. It supports 1169* allocation, reallocation, and clearing of cached memory. The struct is 1170* designed to be used with a global array, one per device. 1171*/ 1172struct ggml_cann_nz_workspace { 1173 std::mutex mtx ;// Protects ptr/allocated from concurrent access 1174void * ptr ;// Pointer to allocated device buffer 1175size_t allocated ;// Size of currently allocated buffer in bytes 1176 1177/** 1178* @brief Constructor. Initializes the workspace with no allocated memory. 1179*/ 1180ggml_cann_nz_workspace () :ptr (nullptr ),allocated (0 ) {} 1181 1182/** 1183* @brief Free cached memory and reset the workspace. 1184* 1185* If a buffer has been allocated, this function releases it using 1186* aclrtFree and resets internal state. 1187*/ 1188void clear () { 1189if (ptr ) { 1190ACL_CHECK (aclrtFree (ptr )); 1191ptr = nullptr ; 1192allocated = 0 ; 1193 } 1194 } 1195 1196/** 1197* @brief Allocate or reallocate the workspace buffer. 1198* 1199* If the requested size is larger than the currently allocated size, 1200* the old buffer will be freed and a new buffer of the requested size 1201* will be allocated on the device. 1202* 1203* @param new_size Size in bytes to allocate for the workspace. 1204*/ 1205void realloc (size_t new_size ) { 1206if (new_size > allocated ) { 1207clear (); 1208ACL_CHECK (aclrtMalloc (& ptr ,new_size ,ACL_MEM_MALLOC_HUGE_FIRST )); 1209allocated = new_size ; 1210 } 1211 } 1212 1213/** 1214* @brief Get the device buffer pointer. 1215* 1216* @return Pointer to the allocated buffer, or nullptr if not allocated. 1217*/ 1218void * get ()const {return ptr ; } 1219}; 1220 1221/** 1222* @brief Global array of NZ workspaces, one per device. 1223*/ 1224static ggml_cann_nz_workspace g_nz_workspaces [GGML_CANN_MAX_DEVICES ]; 1225 1226/** 1227* @brief Convert tensor weights to NZ format using Ascend CANN API. 1228* 1229* This function creates a transposed tensor descriptor and performs the 1230* TransMatmulWeight operation. Converting tensor formats can significantly 1231* improve performance on certain hardware. 1232* 1233* @param tensor Pointer to the input ggml_tensor containing the weights. 1234* @param offset Byte offset within the tensor data buffer where weights start. 1235* @param device device id. 1236* 1237* @note The workspace buffer used in this function is managed globally and reused 1238* across calls. This reduces overhead from repeated memory allocation and deallocation. 1239*/ 1240static void weight_format_to_nz (ggml_tensor * tensor ,int device ) { 1241acl_tensor_ptr weightTransposed = ggml_cann_create_tensor (tensor ,tensor -> ne ,tensor -> nb ,2 ,ACL_FORMAT_ND ,0 ); 1242uint64_t workspaceSize = 0 ; 1243aclOpExecutor * executor ; 1244 1245// TransMatmulWeight 1246ACL_CHECK (aclnnTransMatmulWeightGetWorkspaceSize (weightTransposed .get (),& workspaceSize ,& executor )); 1247 1248 std::lock_guard < std::mutex > lock (g_nz_workspaces [device ].mtx ); 1249// Avoid frequent malloc/free of the workspace. 1250g_nz_workspaces [device ].realloc (workspaceSize ); 1251 1252void * g_nz_workspace = g_nz_workspaces [device ].get (); 1253 1254ACL_CHECK (aclnnTransMatmulWeight (g_nz_workspace ,workspaceSize ,executor ,nullptr )); 1255} 1256 1257// TODO: need handle tensor which has paddings. 1258/** 1259* @brief Set tensor data in a CANN buffer. 1260* 1261* This function sets tensor data in a CANN buffer, handling transformations 1262* if needed based on the tensor's type. It supports multi-threaded calls 1263* where different threads write different chunks of the same tensor. 1264* 1265* For quantized tensors (Q4_0/Q8_0), data is staged in a host buffer and 1266* the format transform is deferred until all chunks are written. 1267* For NZ weight tensors, chunks are uploaded directly but the ND-to-NZ 1268* conversion is deferred until all chunks are written. 1269* 1270* @param buffer The CANN buffer where the tensor data will be set. 1271* @param tensor Pointer to the tensor whose data will be set. 1272* @param data Pointer to the source data to be copied into the tensor. 1273* @param offset Offset in the source data from where to start copying. 1274* @param size Size of the data to be copied, in bytes. 1275*/ 1276static void ggml_backend_cann_buffer_set_tensor (ggml_backend_buffer_t buffer , 1277ggml_tensor * tensor , 1278const void * data , 1279size_t offset , 1280size_t size ) { 1281ggml_backend_cann_buffer_context * ctx = (ggml_backend_cann_buffer_context * )buffer -> context ; 1282 1283ggml_cann_set_device (ctx -> device ); 1284 1285// Only check env once. 1286static bool weight_to_nz = parse_bool (get_env_as_lowercase ("GGML_CANN_WEIGHT_NZ" ).value_or ("on" )); 1287 1288bool is_quantized = need_transform (tensor -> type ); 1289bool is_nz = !is_quantized && tensor -> type != GGML_TYPE_BF16 && weight_to_nz && 1290is_matmul_weight ((const ggml_tensor * )tensor ); 1291 1292// Plain tensor (not quantized, not NZ): direct copy, no tracking needed 1293if (!is_quantized && !is_nz ) { 1294ACL_CHECK (aclrtMemcpy ((char * )tensor -> data + offset ,size ,data ,size ,ACL_MEMCPY_HOST_TO_DEVICE )); 1295return ; 1296 } 1297 1298// Single-shot write (full tensor at once): handle directly without tracking overhead 1299if (offset == 0 && size == ggml_nbytes (tensor )) { 1300if (is_quantized ) { 1301void * transform_buffer = malloc (size ); 1302ggml_backend_cann_transform (tensor ,data ,transform_buffer ); 1303ACL_CHECK (aclrtMemcpy (tensor -> data ,size ,transform_buffer ,size ,ACL_MEMCPY_HOST_TO_DEVICE )); 1304free (transform_buffer ); 1305 }else { 1306// NZ weight 1307GGML_ASSERT (tensor -> ne [2 ]== 1 ); 1308GGML_ASSERT (tensor -> ne [3 ]== 1 ); 1309ACL_CHECK (aclrtMemcpy (tensor -> data ,size ,data ,size ,ACL_MEMCPY_HOST_TO_DEVICE )); 1310weight_format_to_nz (tensor ,ctx -> device ); 1311 } 1312return ; 1313 } 1314 1315// Chunked write: use tracker to accumulate progress and defer transform/conversion 1316TensorSetTracker * tracker = ctx -> get_or_create_tracker (tensor ); 1317 std::unique_lock < std::mutex > lock (tracker -> mtx ); 1318 1319if (is_quantized ) { 1320// Stage data in host buffer; transform requires full tensor data 1321if (tracker -> host_buffer .empty ()) { 1322tracker -> host_buffer .resize (tracker -> total_bytes ); 1323 } 1324memcpy (tracker -> host_buffer .data ()+ offset ,data ,size ); 1325 }else { 1326// NZ weight: upload chunk to device immediately, defer conversion 1327ACL_CHECK (aclrtMemcpy ((char * )tensor -> data + offset ,size ,data ,size ,ACL_MEMCPY_HOST_TO_DEVICE )); 1328 } 1329 1330tracker -> bytes_written += size ; 1331 1332// All chunks received: perform deferred transform/conversion 1333if (tracker -> bytes_written >=tracker -> total_bytes ) { 1334if (is_quantized ) { 1335void * transform_buffer = malloc (tracker -> total_bytes ); 1336ggml_backend_cann_transform (tensor ,tracker -> host_buffer .data (),transform_buffer ); 1337ACL_CHECK (aclrtMemcpy (tensor -> data ,tracker -> total_bytes ,transform_buffer ,tracker -> total_bytes ,ACL_MEMCPY_HOST_TO_DEVICE )); 1338free (transform_buffer ); 1339 } 1340 1341if (is_nz ) { 1342GGML_ASSERT (tensor -> ne [2 ]== 1 ); 1343GGML_ASSERT (tensor -> ne [3 ]== 1 ); 1344weight_format_to_nz (tensor ,ctx -> device ); 1345 } 1346 1347// Unlock before removing tracker, as remove_tracker destroys the mutex 1348lock .unlock (); 1349ctx -> remove_tracker (tensor ); 1350 } 1351} 1352 1353/** 1354* @brief Get tensor data from a CANN buffer. 1355* 1356* This function retrieves tensor data from a CANN buffer, handling 1357* transformations if needed based on the tensor's type. 1358* 1359* @param buffer The CANN buffer from which to retrieve tensor data. 1360* @param tensor Pointer to the tensor whose data will be retrieved. 1361* @param data Pointer to the destination buffer where the tensor data will be 1362* copied. 1363* @param offset Offset in the destination buffer where to start copying. 1364* @param size Size of the data to be copied, in bytes. 1365*/ 1366static void ggml_backend_cann_buffer_get_tensor (ggml_backend_buffer_t buffer , 1367const ggml_tensor * tensor , 1368void * data , 1369size_t offset , 1370size_t size ) { 1371ggml_backend_cann_buffer_context * ctx = (ggml_backend_cann_buffer_context * )buffer -> context ; 1372 1373ggml_cann_set_device (ctx -> device ); 1374 1375if (!need_transform (tensor -> type )) { 1376ACL_CHECK (aclrtMemcpy (data ,size , (char * )tensor -> data + offset ,size ,ACL_MEMCPY_DEVICE_TO_HOST )); 1377 }else { 1378void * transform_buffer = malloc (size ); 1379ACL_CHECK (aclrtMemcpy (transform_buffer ,size , (char * )tensor -> data + offset ,size ,ACL_MEMCPY_DEVICE_TO_HOST )); 1380ggml_backend_cann_transform_back (tensor ,transform_buffer ,data ); 1381free (transform_buffer ); 1382 } 1383} 1384 1385/** 1386* @brief Copy tensor data between CANN buffers if possible. 1387* 1388* This function copies tensor data between CANN buffers if the source and 1389* destination buffers are CANN buffers and they meet the necessary conditions 1390* (same device or devices can access each other). 1391* 1392* @param buffer The destination CANN buffer where the tensor data will be 1393* copied. 1394* @param src Pointer to the source tensor whose data will be copied. 1395* @param dst Pointer to the destination tensor where the data will be copied. 1396* @return true if the copy operation succeeded, false otherwise. 1397*/ 1398static bool ggml_backend_cann_buffer_cpy_tensor (ggml_backend_buffer_t buffer , 1399const ggml_tensor * src , 1400ggml_tensor * dst ) { 1401if (ggml_backend_buft_is_cann (src -> buffer -> buft )) { 1402ggml_backend_cann_buffer_context * src_ctx = (ggml_backend_cann_buffer_context * )src -> buffer -> context ; 1403ggml_backend_cann_buffer_context * dst_ctx = (ggml_backend_cann_buffer_context * )buffer -> context ; 1404 1405size_t memcpy_size = ggml_nbytes (src ); 1406// Same device. 1407if (src_ctx -> device == dst_ctx -> device ) { 1408ACL_CHECK (aclrtMemcpy ((char * )dst -> data ,memcpy_size , (const char * )src -> data ,memcpy_size , 1409ACL_MEMCPY_DEVICE_TO_DEVICE )); 1410return true; 1411 }else { 1412#ifdef ASCEND_310P 1413// TODO: Support 310p P2P copy 1414return false; 1415#endif 1416// Different device but can access by peer. 1417int32_t canAccessPeer = 0 ; 1418ACL_CHECK (aclrtDeviceCanAccessPeer (& canAccessPeer ,src_ctx -> device ,dst_ctx -> device )); 1419if (canAccessPeer ) { 1420ggml_cann_set_device (src_ctx -> device ); 1421ACL_CHECK (aclrtDeviceEnablePeerAccess (dst_ctx -> device ,0 )); 1422ACL_CHECK (aclrtMemcpy ((char * )dst -> data ,memcpy_size , (const char * )src -> data ,memcpy_size , 1423ACL_MEMCPY_DEVICE_TO_DEVICE )); 1424return true; 1425 } 1426 } 1427 } 1428return false; 1429} 1430 1431/** 1432* @brief Set a region of a tensor's device memory to a specified value. 1433* 1434* @param buffer The CANN buffer containing the tensor. 1435* @param tensor Pointer to the tensor whose memory will be set. 1436* @param value The value to which each byte in the region will be set. 1437* @param offset Byte offset within the tensor's data to start setting. 1438* @param size Number of bytes to set. 1439*/ 1440static void ggml_backend_cann_buffer_memset_tensor (ggml_backend_buffer_t buffer ,ggml_tensor * tensor ,uint8_t value ,size_t offset ,size_t size ) { 1441ggml_backend_cann_buffer_context * ctx = (ggml_backend_cann_buffer_context * )buffer -> context ; 1442 1443ggml_cann_set_device (ctx -> device ); 1444ACL_CHECK (aclrtMemset ((char * )tensor -> data + offset ,size ,value ,size )); 1445} 1446 1447/** 1448* @brief Clear a CANN buffer by setting all its memory to a specified value. 1449* 1450* This function clears a CANN buffer by setting all its memory to a specified 1451* value. 1452* 1453* @param buffer The CANN buffer to be cleared. 1454* @param value The value to which each byte in the buffer will be set. 1455*/ 1456static void ggml_backend_cann_buffer_clear (ggml_backend_buffer_t buffer ,uint8_t value ) { 1457ggml_backend_cann_buffer_context * ctx = (ggml_backend_cann_buffer_context * )buffer -> context ; 1458 1459ggml_cann_set_device (ctx -> device ); 1460ACL_CHECK (aclrtMemset (ctx -> dev_ptr ,buffer -> size ,value ,buffer -> size )); 1461} 1462 1463/** 1464* @brief Interface for a CANN buffer in the backend. 1465* 1466* This structure defines function pointers to operations that can be performed 1467* on a CANN buffer within the backend. 1468*/ 1469static const ggml_backend_buffer_i ggml_backend_cann_buffer_interface = { 1470/* .free_buffer = */ ggml_backend_cann_buffer_free_buffer , 1471/* .get_base = */ ggml_backend_cann_buffer_get_base , 1472/* .init_tensor = */ ggml_backend_cann_buffer_init_tensor , 1473/* .memset_tensor = */ ggml_backend_cann_buffer_memset_tensor , 1474/* .set_tensor = */ ggml_backend_cann_buffer_set_tensor , 1475/* .get_tensor = */ ggml_backend_cann_buffer_get_tensor , 1476/* .set_tensor_2d = */ NULL , 1477/* .get_tensor_2d = */ NULL , 1478/* .cpy_tensor = */ ggml_backend_cann_buffer_cpy_tensor , 1479/* .clear = */ ggml_backend_cann_buffer_clear , 1480/* .reset = */ NULL , 1481}; 1482 1483/** 1484* @brief Allocates a new CANN buffer of the specified type and size. 1485* 1486* This function allocates a new CANN buffer on the specified device with the 1487* given size. 1488* 1489* @param buft Pointer to the buffer type context. 1490* @param size Size in bytes of the buffer to allocate. 1491* @return Pointer to the allocated buffer, or nullptr if allocation fails. 1492*/ 1493static ggml_backend_buffer_t ggml_backend_cann_buffer_type_alloc_buffer (ggml_backend_buffer_type_t buft ,size_t size ) { 1494ggml_backend_cann_buffer_type_context * buft_ctx = (ggml_backend_cann_buffer_type_context * )buft -> context ; 1495 1496ggml_cann_set_device (buft_ctx -> device ); 1497 1498const size_t alignment = 128 ; 1499size = GGML_PAD (size ,alignment ); 1500if (size == 0 ) { 1501size = alignment ; 1502 } 1503void * dev_ptr ; 1504aclError err = aclrtMalloc (& dev_ptr ,size ,ACL_MEM_MALLOC_HUGE_FIRST ); 1505if (err != ACL_SUCCESS ) { 1506GGML_LOG_ERROR ("%s: allocating %.2f MiB on device %d: aclrtMalloc failed: %s\n" ,__func__ , 1507size /1024.0 /1024.0 ,buft_ctx -> device ,aclGetRecentErrMsg ()); 1508return nullptr ; 1509 } 1510 1511ggml_backend_cann_buffer_context * ctx = new ggml_backend_cann_buffer_context (buft_ctx -> device ,dev_ptr ); 1512 1513return ggml_backend_buffer_init (buft ,ggml_backend_cann_buffer_interface ,ctx ,size ); 1514} 1515 1516/** 1517* @brief Retrieves the memory alignment requirement for CANN buffers of this 1518* type. 1519* 1520* This function returns the alignment requirement in bytes for memory allocated 1521* by the CANN buffer type. 1522* 1523* @param buft Pointer to the buffer type context (unused in this 1524* implementation). 1525* @return The alignment requirement in bytes (fixed at 128 bytes for CANN 1526* buffers). 1527*/ 1528static size_t ggml_backend_cann_buffer_type_get_alignment (ggml_backend_buffer_type_t buft ) { 1529return 128 ; 1530 1531GGML_UNUSED (buft ); 1532} 1533 1534/** 1535* @brief Calculates the allocation size required for a tensor in a CANN buffer. 1536* 1537* Computes the total allocation size needed for storing the tensor's data in a 1538* CANN buffer, considering any necessary padding or adjustments for quantized 1539* types. 1540* 1541* @param buft Pointer to the buffer type context (unused in this 1542* implementation). 1543* @param tensor Pointer to the tensor for which the allocation size is 1544* calculated. 1545* @return The total allocation size in bytes required for the tensor in the 1546* CANN buffer. 1547*/ 1548static size_t ggml_backend_cann_buffer_type_get_alloc_size (ggml_backend_buffer_type_t buft , 1549const ggml_tensor * tensor ) { 1550size_t size = ggml_nbytes (tensor ); 1551int64_t ne0 = tensor -> ne [0 ]; 1552 1553// Only check env once. 1554static bool weight_to_nz = parse_bool (get_env_as_lowercase ("GGML_CANN_WEIGHT_NZ" ).value_or ("on" )); 1555 1556// last line must bigger than 32, because every single op deal at 1557// least 32 bytes. 1558// TODO: quantized type? 1559// int64_t line_size = ne0 * ggml_element_size(tensor); 1560// int64_t line_size_align_32 = (line_size + 31) & ~31; 1561// size += (line_size_align_32 - line_size); 1562if (ggml_is_quantized (tensor -> type )) { 1563if (ne0 %MATRIX_ROW_PADDING != 0 ) { 1564size += ggml_row_size (tensor -> type ,MATRIX_ROW_PADDING - ne0 %MATRIX_ROW_PADDING ); 1565 } 1566 }else if (weight_to_nz && tensor -> type != GGML_TYPE_BF16 1567&& is_matmul_weight ((const ggml_tensor * )tensor )) { 1568// NZ format weight are not support quantized yet. 1569// If ND tensor transform to NZ, size may changed. 1570int64_t shape []= {tensor -> ne [1 ],tensor -> ne [0 ] }; 1571GGML_ASSERT (tensor -> ne [2 ]== 1 ); 1572GGML_ASSERT (tensor -> ne [3 ]== 1 ); 1573const aclIntArray * acl_shape = aclCreateIntArray (shape ,2 ); 1574size_t new_size ; 1575ACL_CHECK (aclnnCalculateMatmulWeightSizeV2 (acl_shape ,ggml_cann_type_mapping (tensor -> type ),& new_size )); 1576ACL_CHECK (aclDestroyIntArray (acl_shape )); 1577size = std::max (size ,new_size ); 1578 } 1579 1580return size ; 1581 1582GGML_UNUSED (buft ); 1583} 1584 1585static bool ggml_backend_cann_buffer_type_is_host (ggml_backend_buffer_type_t buft ) { 1586return false; 1587 1588GGML_UNUSED (buft ); 1589} 1590 1591/** 1592* @brief Interface for managing CANN buffer types in the GGML backend. 1593* 1594* Provides function pointers for allocating, querying properties, and managing 1595* memory for CANN buffer types in the GGML backend. 1596*/ 1597static const ggml_backend_buffer_type_i ggml_backend_cann_buffer_type_interface = { 1598/* .get_name = */ ggml_backend_cann_buffer_type_name , 1599/* .alloc_buffer = */ ggml_backend_cann_buffer_type_alloc_buffer , 1600/* .get_alignment = */ ggml_backend_cann_buffer_type_get_alignment , 1601/* .get_max_size = */ NULL ,// defaults to SIZE_MAX 1602/* .get_alloc_size = */ ggml_backend_cann_buffer_type_get_alloc_size , 1603/* .is_host = */ ggml_backend_cann_buffer_type_is_host , 1604}; 1605 1606/** 1607* @brief Retrieves the CANN buffer type for a specified device. 1608* 1609* This function initializes and returns the buffer type interface associated 1610* with the given device. It ensures thread-safe access using a mutex. 1611* 1612* @param device The device index for which to retrieve the buffer type. 1613* @return A pointer to the buffer type interface for the specified device, or 1614* nullptr if the device index is out of range. 1615*/ 1616ggml_backend_buffer_type_t ggml_backend_cann_buffer_type (int32_t device ) { 1617static std::mutex mutex ; 1618 std::lock_guard < std::mutex > lock (mutex ); 1619 1620if (device >=ggml_backend_cann_get_device_count ()) { 1621return nullptr ; 1622 } 1623 1624static ggml_backend_buffer_type ggml_backend_cann_buffer_types [GGML_CANN_MAX_DEVICES ]; 1625 1626static bool ggml_backend_cann_buffer_type_initialized = false; 1627 1628if (!ggml_backend_cann_buffer_type_initialized ) { 1629for (int32_t i = 0 ;i < ggml_cann_info ().device_count ;i ++ ) { 1630ggml_backend_cann_buffer_types [i ]= { 1631/* .iface = */ ggml_backend_cann_buffer_type_interface , 1632/* .device = */ ggml_backend_reg_dev_get (ggml_backend_cann_reg (),i ), 1633/* .context = */ 1634new ggml_backend_cann_buffer_type_context {i ,"CANN" + std::to_string (i ) }, 1635 }; 1636 } 1637ggml_backend_cann_buffer_type_initialized = true; 1638 } 1639 1640return & ggml_backend_cann_buffer_types [device ]; 1641} 1642 1643/** 1644* @brief Retrieves the name associated with a CANN host buffer type. 1645* 1646* This function returns the descriptive name associated with the specified 1647* CANN host buffer type context. 1648* 1649* @param buft Pointer to the host buffer type context. 1650* @return Const pointer to the C-style string containing the name. 1651*/ 1652static const char * ggml_backend_cann_host_buffer_type_name (ggml_backend_buffer_type_t buft ) { 1653return "CANN_Host" ; 1654 1655GGML_UNUSED (buft ); 1656} 1657 1658/** 1659* @brief Retrieves the name associated with a CANN host buffer. 1660* 1661* This function returns the descriptive name associated with the specified 1662* CANN host buffer context. 1663* 1664* @param buft Pointer to the host buffer context. 1665* @return Const pointer to the C-style string containing the name. 1666*/ 1667static const char * ggml_backend_cann_host_buffer_name (ggml_backend_buffer_t buffer ) { 1668return "CANN_Host" ; 1669 1670GGML_UNUSED (buffer ); 1671} 1672 1673/** 1674* @brief Free resources associated with a CANN host buffer. 1675* 1676* This function frees the resources associated with a CANN host buffer, including 1677* its context. 1678* 1679* @param buffer The CANN host buffer to free. 1680*/ 1681static void ggml_backend_cann_host_buffer_free (ggml_backend_buffer_t buffer ) { 1682ACL_CHECK (aclrtFreeHost (buffer -> context )); 1683} 1684 1685/** 1686* @brief Allocates a new CANN host buffer of the specified size. 1687* 1688* This function allocates a new CANN host buffer with the given size. 1689* @param size Size in bytes of the host buffer to allocate. 1690* @return Pointer to the allocated host buffer, or nullptr if allocation fails. 1691*/ 1692static void * ggml_cann_host_malloc (size_t size ) { 1693if (getenv ("GGML_CANN_NO_PINNED" )!= nullptr ) { 1694return nullptr ; 1695 } 1696 1697const size_t alignment = 128 ; 1698size = GGML_PAD (size ,alignment ); 1699if (size == 0 ) { 1700size = alignment ; 1701 } 1702 1703void * hostPtr = nullptr ; 1704aclError err = aclrtMallocHost ((void ** )& hostPtr ,size ); 1705if (err != ACL_SUCCESS ) { 1706GGML_LOG_WARN ("%s: failed to allocate %.2f MiB of pinned memory: %s\n" ,__func__ ,size /1024.0 /1024.0 , 1707aclGetRecentErrMsg ()); 1708return nullptr ; 1709 } 1710return hostPtr ; 1711} 1712 1713/** 1714* @brief Allocates a new CANN host buffer of the specified type and size. 1715* 1716* @param buft Pointer to the host buffer type context. 1717* @param size Size in bytes of the host buffer to allocate. 1718* @return Pointer to the allocated host buffer, or CPU buffer pointer if allocation fails. 1719*/ 1720static ggml_backend_buffer_t ggml_backend_cann_host_buffer_type_alloc_buffer (ggml_backend_buffer_type_t buft , 1721size_t size ) { 1722void * hostPtr = ggml_cann_host_malloc (size ); 1723 1724if (hostPtr == nullptr ) { 1725// fallback to cpu buffer 1726return ggml_backend_buft_alloc_buffer (ggml_backend_cpu_buffer_type (),size ); 1727 } 1728 1729ggml_backend_buffer_t buffer = ggml_backend_cpu_buffer_from_ptr (hostPtr ,size ); 1730buffer -> buft = buft ; 1731buffer -> iface .free_buffer = ggml_backend_cann_host_buffer_free ; 1732 1733return buffer ; 1734} 1735 1736/** 1737* @brief Interface for managing CANN host buffer types in the GGML backend. 1738* 1739* Provides function pointers for allocating, querying properties, and managing 1740* memory for CANN buffer types in the GGML backend. 1741*/ 1742ggml_backend_buffer_type_t ggml_backend_cann_host_buffer_type () { 1743static struct ggml_backend_buffer_type ggml_backend_cann_buffer_type_host = { 1744/* .iface = */ { 1745/* .get_name = */ ggml_backend_cann_host_buffer_type_name , 1746/* .alloc_buffer = */ ggml_backend_cann_host_buffer_type_alloc_buffer , 1747/* .get_alignment = */ ggml_backend_cpu_buffer_type ()-> iface .get_alignment , 1748/* .get_max_size = */ NULL ,// defaults to SIZE_MAX 1749/* .get_alloc_size = */ ggml_backend_cpu_buffer_type ()-> iface .get_alloc_size , 1750/* .is_host = */ ggml_backend_cpu_buffer_type ()-> iface .is_host , 1751 }, 1752/* .device = */ 1753ggml_backend_reg_dev_get (ggml_backend_cann_reg (),0 ), 1754/* .context = */ nullptr , 1755 }; 1756 1757return & ggml_backend_cann_buffer_type_host ; 1758} 1759 1760/** 1761* @brief Computes the forward operation for a given tensor using CANN 1762* operations. 1763* 1764* This function selects the appropriate CANN operation based on the type of 1765* operation specified in the tensor and performs the computation. 1766* 1767* @param ctx The CANN context containing necessary resources and 1768* configurations. 1769* @param dst The destination tensor where the result of the computation will be 1770* stored. 1771* @return true if the computation was successful; false otherwise. 1772*/ 1773static bool ggml_cann_compute_forward (ggml_backend_cann_context & ctx ,struct ggml_tensor * dst ) { 1774switch (dst -> op ) { 1775case GGML_OP_REPEAT : 1776ggml_cann_repeat (ctx ,dst ); 1777break ; 1778case GGML_OP_GET_ROWS : 1779ggml_cann_get_rows (ctx ,dst ); 1780break ; 1781case GGML_OP_SET_ROWS : 1782ggml_cann_set_rows (ctx ,dst ); 1783break ; 1784case GGML_OP_DUP : 1785ggml_cann_dup (ctx ,dst ); 1786break ; 1787case GGML_OP_ADD : 1788case GGML_OP_ADD1 : 1789ggml_cann_binary_op < aclnn_add > (ctx ,dst ); 1790break ; 1791case GGML_OP_SUB : 1792ggml_cann_binary_op < aclnn_sub > (ctx ,dst ); 1793break ; 1794case GGML_OP_ACC : 1795ggml_cann_acc (ctx ,dst ); 1796break ; 1797case GGML_OP_MUL : 1798ggml_cann_binary_op < aclnn_mul > (ctx ,dst ); 1799break ; 1800case GGML_OP_DIV : 1801ggml_cann_binary_op < aclnn_div > (ctx ,dst ); 1802break ; 1803case GGML_OP_UNARY : 1804switch (ggml_get_unary_op (dst )) { 1805case GGML_UNARY_OP_ABS : 1806GGML_CANN_CALL_OP_UNARY (Abs ); 1807break ; 1808case GGML_UNARY_OP_NEG : 1809GGML_CANN_CALL_OP_UNARY (Neg ); 1810break ; 1811case GGML_UNARY_OP_GELU : 1812case GGML_UNARY_OP_GELU_ERF : 1813// aclnnGelu internally uses the erf-based approximation. 1814GGML_CANN_CALL_OP_UNARY (Gelu ); 1815break ; 1816case GGML_UNARY_OP_SILU : 1817GGML_CANN_CALL_OP_UNARY (Silu ); 1818break ; 1819case GGML_UNARY_OP_GELU_QUICK : 1820 { 1821auto lambda = [](ggml_backend_cann_context & ctx ,aclTensor * acl_src ,aclTensor * acl_dst ) { 1822GGML_CANN_CALL_ACLNN_OP (ctx ,GeluV2 ,acl_src ,0 ,acl_dst ); 1823 }; 1824ggml_cann_op_unary (lambda ,ctx ,dst ); 1825 } 1826break ; 1827case GGML_UNARY_OP_TANH : 1828GGML_CANN_CALL_OP_UNARY (Tanh ); 1829break ; 1830case GGML_UNARY_OP_RELU : 1831GGML_CANN_CALL_OP_UNARY (Relu ); 1832break ; 1833case GGML_UNARY_OP_SIGMOID : 1834GGML_CANN_CALL_OP_UNARY (Sigmoid ); 1835break ; 1836case GGML_UNARY_OP_HARDSIGMOID : 1837GGML_CANN_CALL_OP_UNARY (Hardsigmoid ); 1838break ; 1839case GGML_UNARY_OP_HARDSWISH : 1840GGML_CANN_CALL_OP_UNARY (Hardswish ); 1841break ; 1842case GGML_UNARY_OP_EXP : 1843GGML_CANN_CALL_OP_UNARY (Exp ); 1844break ; 1845case GGML_UNARY_OP_ELU : 1846ggml_cann_elu (ctx ,dst ); 1847break ; 1848case GGML_UNARY_OP_SGN : 1849GGML_CANN_CALL_OP_UNARY (Sign ); 1850break ; 1851case GGML_UNARY_OP_STEP : 1852ggml_cann_step (ctx ,dst ); 1853break ; 1854case GGML_UNARY_OP_SOFTPLUS : 1855ggml_cann_softplus (ctx ,dst ); 1856break ; 1857default : 1858return false; 1859 } 1860break ; 1861case GGML_OP_GLU : 1862switch (ggml_get_glu_op (dst )) { 1863case GGML_GLU_OP_REGLU : 1864GGML_CANN_CALL_OP_UNARY_GATED (Relu ); 1865break ; 1866case GGML_GLU_OP_GEGLU : 1867ggml_cann_geglu (ctx ,dst ,0 );// approximate=0 → tanh 1868break ; 1869case GGML_GLU_OP_GEGLU_ERF : 1870ggml_cann_geglu (ctx ,dst ,1 );// approximate=1 → erf 1871break ; 1872case GGML_GLU_OP_SWIGLU : 1873ggml_cann_swiglu (ctx ,dst ); 1874break ; 1875case GGML_GLU_OP_SWIGLU_CLAMP : 1876ggml_cann_swiglu_clamp (ctx ,dst ); 1877break ; 1878case GGML_GLU_OP_GEGLU_QUICK : 1879ggml_cann_geglu_quick (ctx ,dst ); 1880break ; 1881default : 1882return false; 1883 } 1884break ; 1885case GGML_OP_NORM : 1886ggml_cann_norm (ctx ,dst ); 1887break ; 1888case GGML_OP_GROUP_NORM : 1889ggml_cann_group_norm (ctx ,dst ); 1890break ; 1891case GGML_OP_L2_NORM : 1892ggml_cann_l2_norm (ctx ,dst ); 1893break ; 1894case GGML_OP_CROSS_ENTROPY_LOSS : 1895ggml_cann_cross_entropy_loss (ctx ,dst ); 1896break ; 1897case GGML_OP_CONCAT : 1898ggml_cann_concat (ctx ,dst ); 1899break ; 1900case GGML_OP_UPSCALE : 1901ggml_cann_upsample_nearest2d (ctx ,dst ); 1902break ; 1903case GGML_OP_PAD : 1904ggml_cann_pad (ctx ,dst ); 1905break ; 1906case GGML_OP_ARANGE : 1907ggml_cann_arange (ctx ,dst ); 1908break ; 1909case GGML_OP_TIMESTEP_EMBEDDING : 1910ggml_cann_timestep_embedding (ctx ,dst ); 1911break ; 1912case GGML_OP_LEAKY_RELU : 1913ggml_cann_leaky_relu (ctx ,dst ); 1914break ; 1915case GGML_OP_RMS_NORM : 1916ggml_cann_rms_norm (ctx ,dst ); 1917break ; 1918case GGML_OP_MUL_MAT : 1919ggml_cann_mul_mat (ctx ,dst ); 1920break ; 1921case GGML_OP_MUL_MAT_ID : 1922ggml_cann_mul_mat_id (ctx ,dst ); 1923break ; 1924case GGML_OP_SCALE : 1925ggml_cann_scale (ctx ,dst ); 1926break ; 1927case GGML_OP_SQR : 1928GGML_ASSERT (dst -> src [1 ]== nullptr ); 1929dst -> src [1 ]= dst -> src [0 ]; 1930ggml_cann_binary_op < aclnn_mul > (ctx ,dst ); 1931break ; 1932case GGML_OP_SQRT : 1933GGML_CANN_CALL_OP_UNARY (Sqrt ); 1934break ; 1935case GGML_OP_CLAMP : 1936ggml_cann_clamp (ctx ,dst ); 1937break ; 1938case GGML_OP_CPY : 1939ggml_cann_cpy (ctx ,dst ); 1940break ; 1941case GGML_OP_SET : 1942ggml_cann_set (ctx ,dst ); 1943break ; 1944case GGML_OP_CONT : 1945ggml_cann_dup (ctx ,dst ); 1946break ; 1947case GGML_OP_NONE : 1948case GGML_OP_RESHAPE : 1949case GGML_OP_VIEW : 1950case GGML_OP_PERMUTE : 1951case GGML_OP_TRANSPOSE : 1952break ; 1953case GGML_OP_DIAG_MASK_INF : 1954ggml_cann_diag_mask (ctx ,dst ,- INFINITY ); 1955break ; 1956case GGML_OP_SOFT_MAX : 1957ggml_cann_softmax (ctx ,dst ); 1958break ; 1959case GGML_OP_ROPE : 1960ggml_cann_rope (ctx ,dst ); 1961break ; 1962case GGML_OP_IM2COL : 1963ggml_cann_im2col (ctx ,dst ); 1964break ; 1965case GGML_OP_POOL_2D : 1966ggml_cann_pool2d (ctx ,dst ); 1967break ; 1968case GGML_OP_SUM : 1969ggml_cann_sum (ctx ,dst ); 1970break ; 1971case GGML_OP_SUM_ROWS : 1972ggml_cann_sum_rows (ctx ,dst ); 1973break ; 1974case GGML_OP_ARGSORT : 1975ggml_cann_argsort (ctx ,dst ); 1976break ; 1977case GGML_OP_ARGMAX : 1978ggml_cann_argmax (ctx ,dst ); 1979break ; 1980case GGML_OP_COS : 1981ggml_cann_op_unary < aclnn_cos > (ctx ,dst ); 1982break ; 1983case GGML_OP_SIN : 1984ggml_cann_op_unary < aclnn_sin > (ctx ,dst ); 1985break ; 1986case GGML_OP_CONV_TRANSPOSE_1D : 1987ggml_cann_conv_transpose_1d (ctx ,dst ); 1988break ; 1989case GGML_OP_LOG : 1990GGML_CANN_CALL_OP_UNARY (Log ); 1991break ; 1992case GGML_OP_MEAN : 1993ggml_cann_mean (ctx ,dst ); 1994break ; 1995case GGML_OP_PAD_REFLECT_1D : 1996ggml_cann_pad_reflect_1d (ctx ,dst ); 1997break ; 1998case GGML_OP_COUNT_EQUAL : 1999ggml_cann_count_equal (ctx ,dst ); 2000break ; 2001case GGML_OP_FLASH_ATTN_EXT : 2002ggml_cann_flash_attn_ext (ctx ,dst ); 2003break ; 2004case GGML_OP_OUT_PROD : 2005ggml_cann_out_prod (ctx ,dst ); 2006break ; 2007case GGML_OP_GATED_LINEAR_ATTN : 2008ggml_cann_gated_linear_attn (ctx ,dst ); 2009break ; 2010case GGML_OP_SSM_CONV : 2011ggml_cann_ssm_conv (ctx ,dst ); 2012break ; 2013case GGML_OP_CUMSUM : 2014ggml_cann_cumsum (ctx ,dst ); 2015break ; 2016case GGML_OP_TRI : 2017ggml_cann_tri (ctx ,dst ); 2018break ; 2019case GGML_OP_FILL : 2020ggml_cann_fill (ctx ,dst ); 2021break ; 2022case GGML_OP_DIAG : 2023ggml_cann_diag (ctx ,dst ); 2024break ; 2025case GGML_OP_SOLVE_TRI : 2026ggml_cann_solve_tri (ctx ,dst ); 2027break ; 2028default : 2029return false; 2030 } 2031 2032return true; 2033} 2034 2035// backend 2036/** 2037* @brief Retrieves the name associated with the CANN backend. 2038* 2039* This function returns the name assigned to the CANN backend, which is stored 2040* in the context of the provided backend structure. 2041* 2042* @param backend Pointer to the CANN backend structure. 2043* @return A pointer to a constant string representing the backend name. 2044*/ 2045static const char * ggml_backend_cann_name (ggml_backend_t backend ) { 2046ggml_backend_cann_context * cann_ctx = (ggml_backend_cann_context * )backend -> context ; 2047 2048return cann_ctx -> name .c_str (); 2049} 2050 2051/** 2052* @brief Frees resources associated with the CANN backend. 2053* 2054* This function releases resources associated with the CANN backend context 2055* and resets the device associated with the backend to its initial state. 2056* 2057* @param backend Pointer to the CANN backend structure to be freed. 2058*/ 2059static void ggml_backend_cann_free (ggml_backend_t backend ) { 2060ggml_backend_cann_context * cann_ctx = (ggml_backend_cann_context * )backend -> context ; 2061ACL_CHECK (aclrtSynchronizeDevice ()); 2062ACL_CHECK (aclrtResetDevice (cann_ctx -> device )); 2063 2064delete cann_ctx ; 2065delete backend ; 2066} 2067 2068/** 2069* @brief Sets tensor data asynchronously in the CANN backend. 2070* 2071* This function asynchronously sets tensor data in the CANN backend. 2072* 2073* @param backend Pointer to the CANN backend structure. 2074* @param tensor Pointer to the tensor structure to set data for. 2075* @param data Pointer to the host data to copy to the tensor. 2076* @param offset Offset in bytes within the host data. 2077* @param size Size of the data to copy in bytes. 2078*/ 2079static void ggml_backend_cann_set_tensor_async (ggml_backend_t backend , 2080ggml_tensor * tensor , 2081const void * data , 2082size_t offset , 2083size_t size ) { 2084ggml_backend_cann_context * cann_ctx = (ggml_backend_cann_context * )backend -> context ; 2085ggml_backend_buffer_t buf = tensor -> view_src ?tensor -> view_src -> buffer :tensor -> buffer ; 2086 2087GGML_ASSERT (buf -> buft == ggml_backend_cann_buffer_type (cann_ctx -> device )&& "unsupported buffer type" ); 2088GGML_ASSERT (!ggml_is_quantized (tensor -> type )); 2089 2090ACL_CHECK (aclrtMemcpyAsync ((char * )tensor -> data + offset ,size ,data ,size ,ACL_MEMCPY_HOST_TO_DEVICE , 2091cann_ctx -> stream ())); 2092} 2093 2094/** 2095* @brief Gets tensor data asynchronously in the CANN backend. 2096* 2097* This function asynchronously gets tensor data in the CANN backend. 2098* 2099* @param backend Pointer to the CANN backend structure. 2100* @param tensor Pointer to the tensor structure to get data from. 2101* @param data Pointer to the host data to copy from the tensor. 2102* @param offset Offset in bytes within the host data. 2103* @param size Size of the data to copy in bytes. 2104*/ 2105static void ggml_backend_cann_get_tensor_async (ggml_backend_t backend , 2106const ggml_tensor * tensor , 2107void * data , 2108size_t offset , 2109size_t size ) { 2110ggml_backend_cann_context * cann_ctx = (ggml_backend_cann_context * )backend -> context ; 2111ggml_backend_buffer_t buf = tensor -> view_src ?tensor -> view_src -> buffer :tensor -> buffer ; 2112 2113GGML_ASSERT (buf -> buft == ggml_backend_cann_buffer_type (cann_ctx -> device )&& "unsupported buffer type" ); 2114GGML_ASSERT (!ggml_is_quantized (tensor -> type )); 2115 2116ACL_CHECK (aclrtMemcpyAsync (data ,size , (char * )tensor -> data + offset ,size ,ACL_MEMCPY_DEVICE_TO_HOST , 2117cann_ctx -> stream ())); 2118} 2119 2120/** 2121* @brief Asynchronously copies tensor data between CANN backends. 2122* 2123* This function copies tensor data asynchronously between two CANN backends. It 2124* checks if both tensors reside in CANN buffers and whether the devices support 2125* peer-to-peer access for direct copying. If not, it returns false. 2126* 2127* @param backend_src Pointer to the source CANN backend structure. 2128* @param backend_dst Pointer to the destination CANN backend structure. 2129* @param src Pointer to the source tensor to copy data from. 2130* @param dst Pointer to the destination tensor to copy data to. 2131* @return true if the copy operation succeeds, false otherwise. 2132*/ 2133static bool ggml_backend_cann_cpy_tensor_async (ggml_backend_t backend_src , 2134ggml_backend_t backend_dst , 2135const ggml_tensor * src , 2136ggml_tensor * dst ) { 2137GGML_ASSERT (ggml_backend_is_cann (backend_src )|| ggml_backend_is_cann (backend_dst )); 2138 2139GGML_ASSERT (!is_matmul_weight ((const ggml_tensor * )src )); 2140 2141if (!ggml_backend_buft_is_cann (src -> buffer -> buft )|| !ggml_backend_buft_is_cann (dst -> buffer -> buft )) { 2142return false; 2143 } 2144 2145ggml_backend_buffer_t buf_src = src -> view_src ?src -> view_src -> buffer :src -> buffer ; 2146ggml_backend_buffer_t buf_dst = dst -> view_src ?dst -> view_src -> buffer :dst -> buffer ; 2147 2148ggml_backend_cann_context * cann_ctx_src = (ggml_backend_cann_context * )backend_src -> context ; 2149ggml_backend_cann_context * cann_ctx_dst = (ggml_backend_cann_context * )backend_dst -> context ; 2150 2151size_t copy_size = ggml_nbytes (dst ); 2152if (copy_size == 0 ) { 2153return true; 2154 } 2155if (backend_src != backend_dst ) { 2156#ifdef ASCEND_310P 2157// TODO: Support 310p P2P copy 2158return false; 2159#endif 2160ggml_backend_cann_buffer_context * buf_ctx_src = (ggml_backend_cann_buffer_context * )buf_src -> context ; 2161ggml_backend_cann_buffer_context * buf_ctx_dst = (ggml_backend_cann_buffer_context * )buf_dst -> context ; 2162 2163GGML_ASSERT (cann_ctx_src -> device == buf_ctx_src -> device ); 2164GGML_ASSERT (cann_ctx_dst -> device == buf_ctx_dst -> device ); 2165 2166int32_t canAccessPeer = 0 ; 2167ACL_CHECK (aclrtDeviceCanAccessPeer (& canAccessPeer ,cann_ctx_src -> device ,cann_ctx_dst -> device )); 2168if (!canAccessPeer ) { 2169return false; 2170 } 2171 2172// need open both directions for memcpyasync between devices. 2173ACL_CHECK (aclrtDeviceEnablePeerAccess (cann_ctx_src -> device ,0 )); 2174ggml_cann_set_device (cann_ctx_src -> device ); 2175ACL_CHECK (aclrtDeviceEnablePeerAccess (cann_ctx_dst -> device ,0 )); 2176 2177// wait for task_queue empty to keep task order. 2178ACL_CHECK (aclrtMemcpyAsync (dst -> data ,copy_size ,src -> data ,copy_size ,ACL_MEMCPY_DEVICE_TO_DEVICE , 2179cann_ctx_src -> stream ())); 2180// record event on src stream after the copy 2181// TODO: this event is not effective with acl graph mode, change to use aclrtSynchronizeStream 2182// if (!cann_ctx_src->copy_event) { 2183// ACL_CHECK(aclrtCreateEventWithFlag(&cann_ctx_src->copy_event, ACL_EVENT_SYNC)); 2184// } 2185// ACL_CHECK(aclrtRecordEvent(cann_ctx_src->copy_event, cann_ctx_src->stream())); 2186 2187// // wait on dst stream for the copy to complete 2188// ggml_cann_set_device(cann_ctx_dst->device); 2189// ACL_CHECK(aclrtStreamWaitEvent(cann_ctx_dst->stream(), cann_ctx_src->copy_event)); 2190ACL_CHECK (aclrtSynchronizeStream (cann_ctx_src -> stream ())); 2191 }else { 2192// src and dst are on the same backend 2193ACL_CHECK (aclrtMemcpyAsync (dst -> data ,copy_size ,src -> data ,copy_size ,ACL_MEMCPY_DEVICE_TO_DEVICE , 2194cann_ctx_dst -> stream ())); 2195 } 2196 2197return true; 2198} 2199 2200/** 2201* @brief Synchronizes a CANN backend. 2202* 2203* This function synchronizes the specified CANN backend by waiting for all 2204* operations in its associated stream to complete. 2205* 2206* @param backend Pointer to the CANN backend structure to synchronize. 2207*/ 2208static void ggml_backend_cann_synchronize (ggml_backend_t backend ) { 2209ggml_backend_cann_context * cann_ctx = (ggml_backend_cann_context * )backend -> context ; 2210ggml_cann_set_device (cann_ctx -> device ); 2211ACL_CHECK (aclrtSynchronizeStream (cann_ctx -> stream ())); 2212} 2213 2214/** 2215* @brief Check if CANN backend can fuse the specified operation sequence 2216* 2217* This function determines whether an operation sequence starting from the specified node 2218* can be fused into an optimized operation in the CANN backend. Operation fusion can reduce 2219* memory access overhead and improve computational efficiency. 2220* 2221* @param cgraph Pointer to the computation graph 2222* @param node_idx Index of the starting node in the computation graph 2223* @param ops Sequence of operation types to check for fusion 2224* @return true if the operations can be fused 2225* @return false if the operations cannot be fused 2226*/ 2227static bool ggml_cann_can_fuse (const struct ggml_cgraph * cgraph , 2228int node_idx , 2229 std::initializer_list < enum ggml_op > ops ) { 2230if (!ggml_can_fuse (cgraph ,node_idx ,ops )) { 2231return false; 2232 } 2233 2234// CANN backend supports fusing ADD + RMS_NORM operations 2235if ((ops .size ()== 2 )&& ops .begin ()[0 ]== GGML_OP_ADD && ops .begin ()[1 ]== GGML_OP_RMS_NORM ) { 2236ggml_tensor * add_node = cgraph -> nodes [node_idx ]; 2237// TODO: support broadcast for ADD + RMS_NORM 2238if (add_node -> src [0 ]-> ne [0 ]!= add_node -> src [1 ]-> ne [0 ]|| add_node -> src [0 ]-> ne [1 ]!= add_node -> src [1 ]-> ne [1 ]|| 2239add_node -> src [0 ]-> ne [2 ]!= add_node -> src [1 ]-> ne [2 ]|| add_node -> src [0 ]-> ne [3 ]!= add_node -> src [1 ]-> ne [3 ]) { 2240return false; 2241 } 2242return true; 2243 } 2244 2245return false; 2246} 2247 2248/** 2249* @brief Evaluate the computation graph and optionally capture or execute it using CANN graph API. 2250* 2251* If CANN graph execution is enabled and graph capture is required, this function begins 2252* graph capture, runs the graph, ends capture, and stores the captured graph. 2253* 2254* Otherwise, it falls back to op-by-op execution using the CANN compute kernel dispatcher. 2255* 2256* @param cann_ctx The CANN backend context. 2257* @param cgraph The ggml computation graph. 2258* @param use_cann_graph Whether to use CANN graph execution. 2259* @param cann_graph_capture_required Whether graph capture is needed due to graph changes. 2260*/ 2261static void evaluate_and_capture_cann_graph (ggml_backend_cann_context * cann_ctx , 2262ggml_cgraph * cgraph , 2263bool use_cann_graph , 2264bool cann_graph_capture_required ) { 2265#ifdef USE_ACL_GRAPH 2266if (use_cann_graph && cann_graph_capture_required ) {// Begin CANN graph capture 2267ACL_CHECK (aclmdlRICaptureBegin (cann_ctx -> stream (),ACL_MODEL_RI_CAPTURE_MODE_GLOBAL )); 2268 } 2269#endif // USE_ACL_GRAPH 2270// Only perform the graph execution if CANN graphs are not enabled, or we are capturing the graph. 2271// With the use of CANN graphs, the execution will be performed by the graph launch. 2272static bool opt_fusion = parse_bool (get_env_as_lowercase ("GGML_CANN_OPERATOR_FUSION" ).value_or ("" )); 2273 2274if (!use_cann_graph || cann_graph_capture_required ) { 2275for (int i = 0 ;i < cgraph -> n_nodes ;i ++ ) { 2276ggml_tensor * node = cgraph -> nodes [i ]; 2277if (opt_fusion ) { 2278if (ggml_cann_can_fuse (cgraph ,i , {GGML_OP_ADD ,GGML_OP_RMS_NORM })) { 2279ggml_cann_op_add_rms_norm_fused (* cann_ctx ,node ,cgraph -> nodes [i + 1 ]); 2280i ++ ; 2281continue ; 2282 } 2283 } 2284 2285if (ggml_is_empty (node )|| node -> op == GGML_OP_RESHAPE || node -> op == GGML_OP_TRANSPOSE || 2286node -> op == GGML_OP_VIEW || node -> op == GGML_OP_PERMUTE || node -> op == GGML_OP_NONE ) { 2287continue ; 2288 } 2289 2290if ((node -> flags & GGML_TENSOR_FLAG_COMPUTE )== 0 ) { 2291continue ; 2292 } 2293 2294bool ok = ggml_cann_compute_forward (* cann_ctx ,node ); 2295if (!ok ) { 2296GGML_LOG_ERROR ("%s: op not supported %s (%s)\n" ,__func__ ,node -> name ,ggml_op_name (node -> op )); 2297 } 2298GGML_ASSERT (ok ); 2299 } 2300 } 2301 2302#ifdef USE_ACL_GRAPH 2303if (use_cann_graph ) { 2304GGML_ASSERT (!cann_ctx -> graph_lru_cache .cache_list .empty ()); 2305ggml_cann_graph * matched_graph = cann_ctx -> graph_lru_cache .cache_list .front (); 2306 2307if (cann_graph_capture_required ) {// End CANN graph capture 2308ACL_CHECK (aclmdlRICaptureEnd (cann_ctx -> stream (),& matched_graph -> graph )); 2309 } 2310 2311// Execute CANN graph 2312ACL_CHECK (aclmdlRIExecuteAsync (matched_graph -> graph ,cann_ctx -> stream ())); 2313 } 2314#endif // USE_ACL_GRAPH 2315} 2316 2317/** 2318* @brief Computes a computational graph using a CANN backend. 2319* 2320* This function computes the operations defined in the computational graph 2321* using the specified CANN backend. 2322* 2323* @param backend Pointer to the CANN backend structure to use for computation. 2324* @param cgraph Pointer to the computational graph structure containing nodes 2325* representing operations to be computed. 2326* @return enum ggml_status Returns GGML_STATUS_SUCCESS if computation 2327* completes successfully, otherwise an appropriate error status. 2328*/ 2329static enum ggml_status ggml_backend_cann_graph_compute (ggml_backend_t backend ,ggml_cgraph * cgraph ) { 2330ggml_backend_cann_context * cann_ctx = (ggml_backend_cann_context * )backend -> context ; 2331ggml_cann_set_device (cann_ctx -> device ); 2332g_nz_workspaces [cann_ctx -> device ].clear (); 2333 2334// calculate rope cache for fist layer in current device. 2335cann_ctx -> rope_cache .cached = false; 2336 2337bool graph_capture_required = false; 2338#ifdef USE_ACL_GRAPH 2339bool use_cann_graph = true; 2340 2341static bool prefill_use_graph = parse_bool (get_env_as_lowercase ("GGML_CANN_PREFILL_USE_GRAPH" ).value_or ("" )); 2342if (!prefill_use_graph ) { 2343// Do not use acl_graph for prefill. 2344for (int i = 0 ;i < cgraph -> n_nodes ;i ++ ) { 2345ggml_tensor * node = cgraph -> nodes [i ]; 2346// TODO: Optimize here. Currently, we can only 2347// get seq_len by FA's input. 2348if (node -> op == GGML_OP_FLASH_ATTN_EXT ) { 2349// Q -> src[0], shape: [B, S, N, D] 2350use_cann_graph = (node -> src [0 ]-> ne [1 ]== 1 ); 2351break ; 2352 } 2353 } 2354 } 2355 2356if (!cann_ctx -> acl_graph_mode ) { 2357use_cann_graph = false; 2358 } 2359 2360if (use_cann_graph ) { 2361// If no matching graph is found, the graph needs to be recaptured. 2362graph_capture_required = !cann_ctx -> graph_lru_cache .find_and_move_to_front (cgraph ); 2363 2364if (graph_capture_required ) { 2365// If no matching graph is found, add a new ACL graph. 2366ggml_cann_graph * new_graph = ggml_cann_graph::create_from_cgraph (cgraph ); 2367cann_ctx -> graph_lru_cache .push (new_graph ); 2368 2369// Pre-load rope cache before graph capture. During capture the 2370// stream cannot perform host-to-device memcpy or device memory 2371// malloc/free. Running the full cache init now populates the 2372// cache metadata so these branches are skipped during capture, 2373// while also warming up the memory pool. 2374for (int i = 0 ;i < cgraph -> n_nodes ;i ++ ) { 2375ggml_tensor * node = cgraph -> nodes [i ]; 2376if (node -> op == GGML_OP_ROPE ) { 2377ggml_cann_rope_cache_preload (* cann_ctx ,node ); 2378break ; 2379 } 2380 } 2381 } 2382 } 2383#else 2384bool use_cann_graph = false; 2385#endif // USE_ACL_GRAPH 2386evaluate_and_capture_cann_graph (cann_ctx ,cgraph ,use_cann_graph ,graph_capture_required ); 2387 2388return GGML_STATUS_SUCCESS ; 2389} 2390 2391/** 2392* @brief Checks if the CANN backend supports a specific operation. 2393* 2394* This function checks whether the specified operation is supported by the 2395* CANN backend. 2396* 2397* @param backend Pointer to the CANN backend structure to check support for 2398* the operation. 2399* @param op Pointer to the tensor representing the operation to check. 2400* @return bool Returns true if the operation is supported by the backend, 2401* otherwise false. 2402*/ 2403static bool ggml_backend_cann_supports_op (ggml_backend_dev_t dev ,const ggml_tensor * op ) { 2404switch (op -> op ) { 2405case GGML_OP_UNARY : 2406switch (ggml_get_unary_op (op )) { 2407case GGML_UNARY_OP_ABS : 2408case GGML_UNARY_OP_NEG : 2409case GGML_UNARY_OP_GELU : 2410case GGML_UNARY_OP_SILU : 2411case GGML_UNARY_OP_RELU : 2412case GGML_UNARY_OP_SIGMOID : 2413case GGML_UNARY_OP_HARDSIGMOID : 2414case GGML_UNARY_OP_HARDSWISH : 2415case GGML_UNARY_OP_GELU_QUICK : 2416case GGML_UNARY_OP_TANH : 2417case GGML_UNARY_OP_EXP : 2418case GGML_UNARY_OP_ELU : 2419case GGML_UNARY_OP_SGN : 2420case GGML_UNARY_OP_STEP : 2421case GGML_UNARY_OP_GELU_ERF : 2422case GGML_UNARY_OP_SOFTPLUS : 2423return true; 2424default : 2425return false; 2426 } 2427case GGML_OP_GLU : 2428switch (ggml_get_glu_op (op )) { 2429case GGML_GLU_OP_REGLU : 2430case GGML_GLU_OP_GEGLU : 2431case GGML_GLU_OP_SWIGLU : 2432case GGML_GLU_OP_GEGLU_ERF : 2433case GGML_GLU_OP_GEGLU_QUICK : 2434case GGML_GLU_OP_SWIGLU_CLAMP : 2435return true; 2436default : 2437return false; 2438 } 2439break ; 2440case GGML_OP_MUL_MAT : 2441 { 2442switch (op -> src [0 ]-> type ) { 2443#ifndef ASCEND_310P 2444case GGML_TYPE_BF16 : 2445#endif 2446case GGML_TYPE_F16 : 2447case GGML_TYPE_F32 : 2448return true; 2449case GGML_TYPE_Q8_0 : 2450case GGML_TYPE_Q4_0 : 2451#ifdef ASCEND_310P 2452// Q4 && Q8 per group is not support on 310p device 2453return false; 2454#endif 2455// only support contiguous for quantized types. 2456return ggml_is_contiguous (op -> src [0 ])&& ggml_is_contiguous (op -> src [1 ]); 2457default : 2458return false; 2459 } 2460 } 2461case GGML_OP_MUL_MAT_ID : 2462switch (op -> src [0 ]-> type ) { 2463case GGML_TYPE_F16 : 2464case GGML_TYPE_F32 : 2465return true; 2466case GGML_TYPE_Q8_0 : 2467case GGML_TYPE_Q4_0 : 2468#ifdef ASCEND_310P 2469// Q4 && Q8 per group is not support on 310p device 2470return false; 2471#endif 2472// only support contiguous for quantized types. 2473return ggml_is_contiguous (op -> src [0 ])&& ggml_is_contiguous (op -> src [1 ]); 2474default : 2475return false; 2476 } 2477// embedding 2478case GGML_OP_GET_ROWS : 2479 { 2480switch (op -> src [0 ]-> type ) { 2481case GGML_TYPE_F32 : 2482case GGML_TYPE_F16 : 2483#ifndef ASCEND_310P 2484case GGML_TYPE_BF16 : 2485#endif 2486case GGML_TYPE_Q8_0 : 2487return true; 2488default : 2489return false; 2490 } 2491 } 2492break ; 2493case GGML_OP_SET_ROWS : 2494 { 2495switch (op -> type ) { 2496case GGML_TYPE_F32 : 2497case GGML_TYPE_F16 : 2498#ifndef ASCEND_310P 2499case GGML_TYPE_BF16 : 2500#endif 2501return true; 2502default : 2503return false; 2504 } 2505 } 2506break ; 2507case GGML_OP_CPY : 2508 { 2509ggml_tensor * src = op -> src [0 ]; 2510#ifdef ASCEND_310P 2511if ((op -> type != GGML_TYPE_F32 && op -> type != GGML_TYPE_F16 )|| 2512 (src -> type != GGML_TYPE_F32 && src -> type != GGML_TYPE_F16 )) { 2513// only support F32 and F16 on 310P. 2514return false; 2515 } 2516#else 2517if ((op -> type != GGML_TYPE_F32 && op -> type != GGML_TYPE_F16 && op -> type != GGML_TYPE_BF16 )|| 2518 (src -> type != GGML_TYPE_F32 && src -> type != GGML_TYPE_F16 && src -> type != GGML_TYPE_BF16 )) { 2519// only support F32, F16 and BF16. 2520return false; 2521 } 2522#endif 2523return true; 2524 } 2525break ; 2526case GGML_OP_CONT : 2527 { 2528switch (op -> src [0 ]-> type ) { 2529case GGML_TYPE_F32 : 2530case GGML_TYPE_F16 : 2531#ifndef ASCEND_310P 2532case GGML_TYPE_BF16 : 2533#endif 2534return true; 2535default : 2536return false; 2537 } 2538 } 2539case GGML_OP_ROPE : 2540 { 2541if (((const int32_t * )op -> op_params )[15 ]!= 0 ) { 2542return false;// FIXME: support ggml_rope_set_offset 2543 } 2544if (op -> src [0 ]-> ne [0 ]> 896 ) { 2545return false; 2546 } 2547#ifdef ASCEND_310P 2548// TODO: Support rope_dim < ne00(dim) 2549if (op -> src [0 ]-> ne [0 ]!= op -> op_params [1 ]) { 2550return false; 2551 } 2552if (!ggml_is_contiguous (op -> src [0 ])) { 2553return false; 2554 } 2555#endif 2556return true; 2557 } 2558case GGML_OP_UPSCALE : 2559 { 2560// aclnnUpsampleNearest2dGetWorkspaceSize not support 2561// selfDimN[2]/outDimN[2] or selfDimC[3]/outDimC[3] not equal 2562if (op -> src [0 ]-> ne [2 ]* op -> ne [3 ]!= op -> src [0 ]-> ne [3 ]* op -> ne [2 ]) { 2563return false; 2564 } 2565if (op -> op_params [0 ]!= GGML_SCALE_MODE_NEAREST ) { 2566return false; 2567 } 2568if (op -> op_params [0 ]& GGML_SCALE_FLAG_ANTIALIAS ) { 2569return false; 2570 } 2571return true; 2572 } 2573case GGML_OP_POOL_2D : 2574 { 2575const int32_t * opts = (const int32_t * )op -> op_params ; 2576#ifdef ASCEND_310P 2577enum ggml_op_pool opt = static_cast < ggml_op_pool > (opts [0 ]); 2578if (opt == GGML_OP_POOL_MAX ) { 2579return false; 2580 } 2581#endif 2582const int k0 = opts [1 ]; 2583const int k1 = opts [2 ]; 2584const int p0 = opts [5 ]; 2585const int p1 = opts [6 ]; 2586// value of paddingH should be at most half of kernelH 2587// value of paddingW should be at most half of kernelW 2588return (p0 <= (k0 /2 ))&& (p1 <= (k1 /2 )); 2589 } 2590case GGML_OP_SUM : 2591return ggml_is_contiguous_rows (op -> src [0 ]); 2592case GGML_OP_L2_NORM : 2593case GGML_OP_CROSS_ENTROPY_LOSS : 2594case GGML_OP_DUP : 2595case GGML_OP_IM2COL : 2596case GGML_OP_CONCAT : 2597case GGML_OP_REPEAT : 2598case GGML_OP_NONE : 2599case GGML_OP_RESHAPE : 2600case GGML_OP_VIEW : 2601case GGML_OP_PERMUTE : 2602case GGML_OP_TRANSPOSE : 2603case GGML_OP_NORM : 2604case GGML_OP_ADD : 2605case GGML_OP_ADD1 : 2606case GGML_OP_SUB : 2607case GGML_OP_MUL : 2608case GGML_OP_DIV : 2609case GGML_OP_RMS_NORM : 2610case GGML_OP_SQR : 2611case GGML_OP_SQRT : 2612case GGML_OP_CLAMP : 2613case GGML_OP_DIAG_MASK_INF : 2614case GGML_OP_SUM_ROWS : 2615case GGML_OP_ARGSORT : 2616case GGML_OP_ACC : 2617case GGML_OP_SET : 2618case GGML_OP_GROUP_NORM : 2619return true; 2620case GGML_OP_PAD : 2621// TODO: add circular padding support for cann, see https://github.com/ggml-org/llama.cpp/pull/16985 2622return ggml_get_op_params_i32 (op ,8 )== 0 ; 2623case GGML_OP_ARANGE : 2624case GGML_OP_TIMESTEP_EMBEDDING : 2625case GGML_OP_LEAKY_RELU : 2626case GGML_OP_ARGMAX : 2627case GGML_OP_COS : 2628case GGML_OP_SIN : 2629case GGML_OP_LOG : 2630case GGML_OP_MEAN : 2631case GGML_OP_PAD_REFLECT_1D : 2632case GGML_OP_COUNT_EQUAL : 2633case GGML_OP_GATED_LINEAR_ATTN : 2634return true; 2635case GGML_OP_OUT_PROD : 2636 { 2637#ifdef ASCEND_310P 2638// Ger is not supported on 310p device 2639return false; 2640#endif 2641switch (op -> src [0 ]-> type ) { 2642case GGML_TYPE_F16 : 2643case GGML_TYPE_F32 : 2644return true; 2645default : 2646return false; 2647 } 2648 } 2649case GGML_OP_CONV_TRANSPOSE_1D : 2650return true; 2651case GGML_OP_SCALE : 2652float bias ; 2653memcpy (& bias , (const float * ) (op -> op_params )+ 1 ,sizeof (float )); 2654return bias == 0.0f ;// TODO: support bias != 0.0f 2655case GGML_OP_SOFT_MAX : 2656// TODO: support attention sinks [TAG_ATTN_SINKS] 2657if (op -> src [2 ]) { 2658return false; 2659 } 2660return true; 2661case GGML_OP_FLASH_ATTN_EXT : 2662 { 2663#ifdef ASCEND_310P 2664// FA not support on 310p device 2665return false; 2666#endif 2667// derived from [ggml-cuda.cu] 2668if (op -> src [1 ]-> type != GGML_TYPE_F16 || op -> src [2 ]-> type != GGML_TYPE_F16 ) { 2669return false; 2670 } 2671if (op -> src [1 ]-> type != GGML_TYPE_F16 && op -> src [1 ]-> type != GGML_TYPE_F32 && 2672op -> src [1 ]-> type != GGML_TYPE_BF16 ) { 2673return false; 2674 } 2675if (op -> type != GGML_TYPE_F16 && op -> type != GGML_TYPE_F32 && op -> type != GGML_TYPE_BF16 ) { 2676return false; 2677 } 2678// TODO: support attention sinks [TAG_ATTN_SINKS] 2679if (op -> src [4 ]) { 2680return false; 2681 } 2682if (op -> src [1 ]-> ne [0 ]!= op -> src [2 ]-> ne [0 ]) { 2683// different head sizes of K and V are not supported yet 2684return false; 2685 } 2686float logitSoftcap = 0.0f ; 2687memcpy (& logitSoftcap , (const float * ) (op -> op_params )+ 2 ,sizeof (float )); 2688if (logitSoftcap != 0.0f ) { 2689return false; 2690 } 2691return true; 2692 } 2693case GGML_OP_SSM_CONV : 2694return true; 2695case GGML_OP_CUMSUM : 2696return op -> src [0 ]-> type == GGML_TYPE_F32 ; 2697case GGML_OP_TRI : 2698return op -> src [0 ]-> type == GGML_TYPE_F32 ; 2699case GGML_OP_FILL : 2700return op -> src [0 ]-> type == GGML_TYPE_F32 ; 2701case GGML_OP_DIAG : 2702return op -> src [0 ]-> type == GGML_TYPE_F32 ; 2703case GGML_OP_SOLVE_TRI : 2704return op -> src [0 ]-> type == GGML_TYPE_F32 ; 2705default : 2706return false; 2707 } 2708 2709GGML_UNUSED (dev ); 2710} 2711 2712/** 2713* @brief Records an event on the CANN backend stream. 2714* 2715* This function records the given event on the ACL runtime stream associated 2716* with the backend context. 2717* 2718* @param event Pointer to the event structure to be recorded. 2719*/ 2720static void ggml_backend_cann_event_record (ggml_backend_t backend ,ggml_backend_event_t event ) { 2721ggml_backend_cann_context * cann_ctx = (ggml_backend_cann_context * )backend -> context ; 2722ACL_CHECK (aclrtRecordEvent ((aclrtEvent )event -> context ,cann_ctx -> stream ())); 2723} 2724 2725/** 2726* @brief Waits for a recorded event to complete on the CANN backend stream. 2727* 2728* This function makes the given backend wait for the event to complete on its 2729* ACL runtime stream. 2730* 2731* @param backend Pointer to the backend structure. 2732* @param event Pointer to the event structure that the backend needs to wait 2733* for. 2734*/ 2735static void ggml_backend_cann_event_wait (ggml_backend_t backend ,ggml_backend_event_t event ) { 2736ggml_backend_cann_context * cann_ctx = (ggml_backend_cann_context * )backend -> context ; 2737if (ggml_backend_is_cann (backend )) { 2738ACL_CHECK (aclrtStreamWaitEvent (cann_ctx -> stream (), (aclrtEvent )event -> context )); 2739 }else { 2740GGML_ABORT ("fatal error" ); 2741 } 2742} 2743 2744/** 2745* @brief Structure defining the interface for the CANN backend. 2746* 2747* This structure contains function pointers for various operations 2748* supported by the CANN backend, including name retrieval, memory 2749* management, tensor operations, synchronization, and event handling. 2750*/ 2751static const ggml_backend_i ggml_backend_cann_interface = { 2752/* .get_name = */ ggml_backend_cann_name , 2753/* .free = */ ggml_backend_cann_free , 2754/* .set_tensor_async = */ ggml_backend_cann_set_tensor_async , 2755/* .get_tensor_async = */ ggml_backend_cann_get_tensor_async , 2756/* .set_tensor_2d_async = */ NULL , 2757/* .get_tensor_2d_async = */ NULL , 2758/* .cpy_tensor_async = */ ggml_backend_cann_cpy_tensor_async , 2759/* .synchronize = */ ggml_backend_cann_synchronize , 2760/* .graph_plan_create = */ NULL , 2761/* .graph_plan_free = */ NULL , 2762/* .graph_plan_update = */ NULL , 2763/* .graph_plan_compute = */ NULL , 2764/* .graph_compute = */ ggml_backend_cann_graph_compute , 2765/* .event_record = */ ggml_backend_cann_event_record , 2766/* .event_wait = */ ggml_backend_cann_event_wait , 2767/* .graph_optimize = */ NULL , 2768}; 2769 2770/** 2771* @brief Return the hardcoded GUID for the CANN backend. 2772* 2773* This function returns a static GUID which uniquely identifies the CANN 2774* backend. 2775* 2776* @return A pointer to the static GUID. 2777*/ 2778static ggml_guid_t ggml_backend_cann_guid () { 2779static ggml_guid guid = {0xa1 ,0x94 ,0xaf ,0xac ,0xbd ,0x4f ,0x47 ,0x34 , 27800xbe ,0x1a ,0x9e ,0x71 ,0x1f ,0x9e ,0xed ,0x64 }; 2781return & guid ; 2782} 2783 2784// backend device 2785struct ggml_backend_cann_device_context { 2786int device ; 2787 std::string name ; 2788 std::string description ; 2789int op_offload_min_batch_size ; 2790}; 2791 2792static const char * ggml_backend_cann_device_get_name (ggml_backend_dev_t dev ) { 2793ggml_backend_cann_device_context * ctx = (ggml_backend_cann_device_context * )dev -> context ; 2794return ctx -> name .c_str (); 2795} 2796 2797static const char * ggml_backend_cann_device_get_description (ggml_backend_dev_t dev ) { 2798ggml_backend_cann_device_context * ctx = (ggml_backend_cann_device_context * )dev -> context ; 2799return ctx -> description .c_str (); 2800} 2801 2802static void ggml_backend_cann_device_get_memory (ggml_backend_dev_t dev ,size_t * free ,size_t * total ) { 2803ggml_backend_cann_device_context * ctx = (ggml_backend_cann_device_context * )dev -> context ; 2804ggml_backend_cann_get_device_memory (ctx -> device ,free ,total ); 2805} 2806 2807static enum ggml_backend_dev_type ggml_backend_cann_device_get_type (ggml_backend_dev_t dev ) { 2808GGML_UNUSED (dev ); 2809return GGML_BACKEND_DEVICE_TYPE_GPU ; 2810} 2811 2812static void ggml_backend_cann_device_get_props (ggml_backend_dev_t dev ,ggml_backend_dev_props * props ) { 2813props -> name = ggml_backend_cann_device_get_name (dev ); 2814props -> description = ggml_backend_cann_device_get_description (dev ); 2815props -> type = ggml_backend_cann_device_get_type (dev ); 2816ggml_backend_cann_device_get_memory (dev ,& props -> memory_free ,& props -> memory_total ); 2817 2818bool host_buffer = getenv ("GGML_CANN_NO_PINNED" )== nullptr ; 2819 2820props -> caps = { 2821/* .async = */ false, 2822/* .host_buffer = */ host_buffer , 2823/* .buffer_from_host_ptr = */ false, 2824/* .events = */ true, 2825/* .mmap_support = */ true, 2826 }; 2827} 2828 2829static ggml_backend_t ggml_backend_cann_device_init (ggml_backend_dev_t dev ,const char * params ) { 2830GGML_UNUSED (params ); 2831ggml_backend_cann_device_context * ctx = (ggml_backend_cann_device_context * )dev -> context ; 2832return ggml_backend_cann_init (ctx -> device ); 2833} 2834 2835/** 2836* @brief Checks if the CANN backend supports a specific backend buffer type. 2837* 2838* This function determines whether the CANN backend supports the given backend 2839* buffer type by comparing the device context of the backend and buffer type. 2840* It returns true if the devices are same between the backend context and 2841* buffer type context. 2842* 2843* @param backend Pointer to the CANN backend. 2844* @param buft Pointer to the backend buffer type to check. 2845* @return bool Returns true if the CANN backend supports the buffer type, 2846* otherwise false. 2847*/ 2848static bool ggml_backend_cann_supports_buft (ggml_backend_dev_t dev ,ggml_backend_buffer_type_t buft ) { 2849if (ggml_backend_buft_is_cann (buft )) { 2850ggml_backend_cann_device_context * dev_ctx = (ggml_backend_cann_device_context * )dev -> context ; 2851ggml_backend_cann_buffer_type_context * buft_ctx = (ggml_backend_cann_buffer_type_context * )buft -> context ; 2852return buft_ctx -> device == dev_ctx -> device ; 2853 } 2854return false; 2855} 2856 2857static ggml_backend_buffer_type_t ggml_backend_cann_device_get_buffer_type (ggml_backend_dev_t dev ) { 2858ggml_backend_cann_device_context * ctx = (ggml_backend_cann_device_context * )dev -> context ; 2859return ggml_backend_cann_buffer_type (ctx -> device ); 2860} 2861 2862static ggml_backend_buffer_type_t ggml_backend_cann_device_get_host_buffer_type (ggml_backend_dev_t dev ) { 2863GGML_UNUSED (dev ); 2864return ggml_backend_cann_host_buffer_type (); 2865} 2866 2867/** 2868* @brief Determines if a tensor operation should be offloaded to the CANN 2869* backend. 2870* 2871* This function checks if a given tensor operation should be offloaded to the 2872* CANN backend based on the operation type and the size of the tensor. It 2873* returns true if the second dimension (ne[1]) of the tensor is greater than or 2874* equal to the minimum batch size and the operation is not GGML_OP_GET_ROWS. 2875* 2876* @param backend Pointer to the CANN backend. 2877* @param op Pointer to the tensor operation to check. 2878* @return bool Returns true if the operation should be offloaded, otherwise 2879* false. 2880*/ 2881static bool ggml_backend_cann_offload_op (ggml_backend_dev_t dev ,const ggml_tensor * op ) { 2882ggml_backend_cann_device_context * dev_ctx = (ggml_backend_cann_device_context * )dev -> context ; 2883 2884return op -> ne [1 ] >=dev_ctx -> op_offload_min_batch_size && op -> op != GGML_OP_GET_ROWS ; 2885} 2886 2887/** 2888* @brief Creates a new event for the CANN backend device. 2889* 2890* This function initializes a new event for the CANN backend by setting the 2891* device and creating an ACL runtime event. The created event is then wrapped 2892* in a ggml_backend_event structure and returned. 2893* 2894* @param backend Pointer to the CANN backend. 2895* @return ggml_backend_event_t Returns a pointer to the new event structure. 2896*/ 2897static ggml_backend_event_t ggml_backend_cann_device_event_new (ggml_backend_dev_t dev ) { 2898ggml_backend_cann_device_context * dev_ctx = (ggml_backend_cann_device_context * )dev -> context ; 2899 2900ggml_cann_set_device (dev_ctx -> device ); 2901 2902aclrtEvent event ; 2903ACL_CHECK (aclrtCreateEvent (& event )); 2904 2905return new ggml_backend_event { 2906/* .device = */ ggml_backend_reg_dev_get (ggml_backend_cann_reg (),dev_ctx -> device ), 2907/* .context = */ event , 2908 }; 2909} 2910 2911/** 2912* @brief Frees a CANN backend event. 2913* 2914* This function destroys the ACL runtime event associated with the given CANN 2915* backend event and then deletes the event structure itself. 2916* 2917* @param event Pointer to the event structure to be freed. 2918*/ 2919static void ggml_backend_cann_device_event_free (ggml_backend_dev_t dev ,ggml_backend_event_t event ) { 2920ACL_CHECK (aclrtDestroyEvent ((aclrtEvent )event -> context )); 2921 2922delete event ; 2923GGML_UNUSED (dev ); 2924} 2925 2926/** 2927* @brief Synchronizes the given event on the CANN backend. 2928* 2929* This function waits for the specified event to complete on the ACL runtime. 2930* 2931* @param event Pointer to the event structure to be synchronized. 2932*/ 2933static void ggml_backend_cann_device_event_synchronize (ggml_backend_dev_t dev ,ggml_backend_event_t event ) { 2934ACL_CHECK (aclrtSynchronizeEvent ((aclrtEvent )event -> context )); 2935 2936GGML_UNUSED (dev ); 2937} 2938 2939static const ggml_backend_device_i ggml_backend_cann_device_interface = { 2940/* .get_name = */ ggml_backend_cann_device_get_name , 2941/* .get_description = */ ggml_backend_cann_device_get_description , 2942/* .get_memory = */ ggml_backend_cann_device_get_memory , 2943/* .get_type = */ ggml_backend_cann_device_get_type , 2944/* .get_props = */ ggml_backend_cann_device_get_props , 2945/* .init_backend = */ ggml_backend_cann_device_init ,// called for every card 2946/* .get_buffer_type = */ ggml_backend_cann_device_get_buffer_type , 2947/* .get_host_buffer_type = */ ggml_backend_cann_device_get_host_buffer_type , 2948/* .buffer_from_host_ptr = */ NULL ,// not supported for CANN 2949/* .supports_op = */ ggml_backend_cann_supports_op , 2950/* .supports_buft = */ ggml_backend_cann_supports_buft , 2951/* .offload_op = */ ggml_backend_cann_offload_op , 2952/* .event_new = */ ggml_backend_cann_device_event_new , 2953/* .event_free = */ ggml_backend_cann_device_event_free , 2954/* .event_synchronize = */ ggml_backend_cann_device_event_synchronize , 2955}; 2956 2957// backend reg 2958struct ggml_backend_cann_reg_context { 2959 std::vector < ggml_backend_dev_t > devices ; 2960}; 2961 2962static const char * ggml_backend_cann_reg_get_name (ggml_backend_reg_t reg ) { 2963GGML_UNUSED (reg ); 2964return GGML_CANN_NAME ; 2965} 2966 2967static size_t ggml_backend_cann_reg_get_device_count (ggml_backend_reg_t reg ) { 2968ggml_backend_cann_reg_context * ctx = (ggml_backend_cann_reg_context * )reg -> context ; 2969return ctx -> devices .size (); 2970} 2971 2972static ggml_backend_dev_t ggml_backend_cann_reg_get_device (ggml_backend_reg_t reg ,size_t index ) { 2973ggml_backend_cann_reg_context * ctx = (ggml_backend_cann_reg_context * )reg -> context ; 2974GGML_ASSERT (index < ctx -> devices .size ()); 2975return ctx -> devices [index ]; 2976} 2977 2978static void * ggml_backend_cann_reg_get_proc_address (ggml_backend_reg_t reg ,const char * name ) { 2979GGML_UNUSED (reg ); 2980GGML_UNUSED (name ); 2981// reserved for future use 2982return nullptr ; 2983} 2984 2985static const ggml_backend_reg_i ggml_backend_cann_reg_interface = { 2986/* .get_name = */ ggml_backend_cann_reg_get_name , 2987/* .get_device_count = */ ggml_backend_cann_reg_get_device_count , 2988/* .get_device = */ ggml_backend_cann_reg_get_device , 2989/* .get_proc_address = */ ggml_backend_cann_reg_get_proc_address , 2990}; 2991 2992// backend registry, called only once for cann backend 2993ggml_backend_reg_t ggml_backend_cann_reg () { 2994static ggml_backend_reg reg ; 2995static bool initialized = false; 2996 2997 { 2998static std::mutex mutex ; 2999 std::lock_guard < std::mutex > lock (mutex ); 3000if (!initialized ) { 3001aclInit (nullptr ); 3002ggml_backend_cann_reg_context * ctx = new ggml_backend_cann_reg_context ; 3003const int min_batch_size = getenv ("GGML_OP_OFFLOAD_MIN_BATCH" ) ?atoi (getenv ("GGML_OP_OFFLOAD_MIN_BATCH" )) :32 ; 3004 3005for (int i = 0 ;i < ggml_cann_info ().device_count ;i ++ ) { 3006ggml_backend_cann_device_context * dev_ctx = new ggml_backend_cann_device_context (); 3007dev_ctx -> description = aclrtGetSocName (); 3008dev_ctx -> device = i ; 3009dev_ctx -> name = GGML_CANN_NAME + std::to_string (i ); 3010dev_ctx -> op_offload_min_batch_size = min_batch_size ; 3011ggml_cann_set_device (i ); 3012ggml_backend_dev_t dev = new ggml_backend_device {/* .iface = */ ggml_backend_cann_device_interface , 3013/* .reg = */ & reg , 3014/* .context = */ dev_ctx }; 3015ctx -> devices .push_back (dev ); 3016 } 3017 3018reg = ggml_backend_reg {/* .api_version = */ GGML_BACKEND_API_VERSION , 3019/* .iface = */ ggml_backend_cann_reg_interface , 3020/* .context = */ ctx }; 3021 } 3022 3023initialized = true; 3024 } 3025 3026return & reg ; 3027} 3028 3029ggml_backend_t ggml_backend_cann_init (int32_t device ) { 3030aclInit (nullptr ); 3031if (device < 0 || device >=ggml_backend_cann_get_device_count ()) { 3032GGML_LOG_ERROR ("%s: error: invalid device %d\n" ,__func__ ,device ); 3033return nullptr ; 3034 } 3035 3036ggml_backend_cann_context * ctx = new ggml_backend_cann_context (device ); 3037if (ctx == nullptr ) { 3038GGML_LOG_ERROR ("%s: error: failed to allocate context\n" ,__func__ ); 3039return nullptr ; 3040 } 3041ggml_cann_set_device (ctx -> device ); 3042ggml_backend_t cann_backend = 3043new ggml_backend {/* .guid = */ ggml_backend_cann_guid (), 3044/* .interface = */ ggml_backend_cann_interface , 3045/* .device = */ ggml_backend_reg_dev_get (ggml_backend_cann_reg (),device ), 3046/* .context = */ ctx }; 3047 3048return cann_backend ; 3049} 3050 3051bool ggml_backend_is_cann (ggml_backend_t backend ) { 3052return backend != NULL && ggml_guid_matches (backend -> guid ,ggml_backend_cann_guid ()); 3053} 3054 3055int32_t ggml_backend_cann_get_device_count () { 3056return ggml_cann_info ().device_count ; 3057} 3058 3059void ggml_backend_cann_get_device_description (int32_t device ,char * description ,size_t description_size ) { 3060ggml_cann_set_device (device ); 3061const char * soc_name = aclrtGetSocName (); 3062snprintf (description ,description_size ,"%s" ,soc_name ); 3063} 3064 3065void ggml_backend_cann_get_device_memory (int32_t device ,size_t * free ,size_t * total ) { 3066ggml_cann_set_device (device ); 3067ACL_CHECK (aclrtGetMemInfo (ACL_HBM_MEM ,free ,total )); 3068} 3069 3070GGML_BACKEND_DL_IMPL (ggml_backend_cann_reg )