char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
0190529ec
char/aliceai-t5-moe
1#include "ggml-et.h" 2 3#include "ggml-backend-impl.h" 4#include "ggml-backend.h" 5#include "ggml-et-common.h" 6#include "ggml-et-kernels.h" 7#include "ggml-et-memops.h" 8#include "ggml-et-ops.h" 9#include "ggml-impl.h" 10#include "ggml.h" 11 12#include <stdarg.h> 13 14#include <cstdarg> 15#include <cstdio> 16#include <cstdlib> 17#include <cstring> 18#include <vector> 19 20#if __has_include (< filesystem > ) 21# include <filesystem> 22namespace fs= std::filesystem; 23#elif __has_include(<experimental/filesystem>) 24# include <experimental/filesystem> 25namespace fs= std::experimental::filesystem; 26#else 27# error "cannot include the filesystem library" 28#endif 29 30/* 31* ggml_et_dump_tensor_metadata 32* @brief prints the metadata of a single tensorf 33*/ 34static void ggml_et_dump_tensor_metadata (const ggml_tensor * ggtensor ,size_t indent_level ,const char * title ) { 35char * spaces = (char * )alloca (indent_level + 1 ); 36memset (spaces ,' ' ,indent_level ); 37spaces [indent_level ]= '\0' ; 38fprintf (stderr , 39"%s%s: %s\n" 40"%s type: %s\n" 41"%s ne: %lld %lld %lld %lld\n" 42"%s nb: %zu %zu %zu %zu\n" 43"%s op: %s\n" 44"%s data: %p\n" 45"%s src0: %p\n" , 46spaces ,title ,ggtensor -> name ,spaces ,ggml_type_name (ggtensor -> type ),spaces , (long long )ggtensor -> ne [0 ], 47 (long long )ggtensor -> ne [1 ], (long long )ggtensor -> ne [2 ], (long long )ggtensor -> ne [3 ],spaces , 48ggtensor -> nb [0 ],ggtensor -> nb [1 ],ggtensor -> nb [2 ],ggtensor -> nb [3 ],spaces ,ggml_op_name (ggtensor -> op ), 49spaces ,ggtensor -> data ,spaces , (void * )ggtensor -> src [0 ]); 50} 51 52/* 53* ggml_et_dump_operator_metadata 54* @brief prints the metadata of a single tensor (or operator) including it's input and views 55*/ 56static void ggml_et_dump_operator_metadata (const ggml_tensor * ggtensor ) { 57GGML_ASSERT (ggtensor != NULL ); 58ggml_et_dump_tensor_metadata (ggtensor ,0 ,"GGML tensor" ); 59for (int i = 0 ;i < GGML_MAX_SRC && ggtensor -> src [i ];i ++ ) { 60char arr [16 ]; 61int n = snprintf (arr ,sizeof (arr ),"src[%i]->name" ,i ); 62GGML_ASSERT ((unsigned )n < sizeof (arr )&& "printed too much data to stack buffer" ); 63ggml_et_dump_tensor_metadata (ggtensor -> src [i ],2 ,arr ); 64 } 65if (ggtensor -> view_src ) { 66ggml_et_dump_tensor_metadata (ggtensor ,2 ,"view_src" ); 67 } 68} 69 70static struct ggml_et_driver { 71 std::shared_ptr < dev::IDeviceLayer > device_layer ; 72 std::shared_ptr < rt::IRuntime > runtime ; 73 std::unique_ptr < std::ofstream > profile_stream ; 74 std::unique_ptr < std::ofstream > kernel_id_stream ; 75 std::vector < std::pair < std::string , rt::KernelId >> kernel_map ; 76bool profiling_enabled = false; 77}_drv ; 78 79// Check at runtime environment variables for paths likely holding ET toolchain with sysemu elf files 80static std::string ggml_et_get_default_et_path () { 81// List of environment variables to check in order of preference 82const char * const env_vars []= {"ET_TOOLCHAIN" ,"TOOLCHAIN_ROOT" }; 83 84for (const char * var :env_vars ) { 85if (const char * et_path = std::getenv (var )) { 86if (et_path && * et_path != '\0' ) { 87return fs::path (et_path ).string (); 88 } 89 } 90 } 91 92// Otherwise assume default 93return fs::path ("/opt/et" ).string (); 94} 95 96// config when using sysemu instead of PCIe hardware device 97// adapted from `ainekko/et-platform/esperanto-tools-libs/tools/src/bench.cpp` 98static inline auto ggml_et_get_default_sysemu_options () { 99constexpr uint64_t kSysEmuMaxCycles = std::numeric_limits < uint64_t > ::max (); 100constexpr uint64_t kSysEmuMinionShiresMask = 0x1FFFFFFFFu ; 101const std::string et_path = ggml_et_get_default_et_path ()+ "/" ; 102 103 emu::SysEmuOptions sysEmuOptions ; 104 105// Construct all paths 106sysEmuOptions .bootromTrampolineToBL2ElfPath = 107et_path + "lib/esperanto-fw/BootromTrampolineToBL2/BootromTrampolineToBL2.elf" ; 108sysEmuOptions .spBL2ElfPath = 109et_path + "lib/esperanto-fw/ServiceProcessorBL2/fast-boot/ServiceProcessorBL2_fast-boot.elf" ; 110sysEmuOptions .machineMinionElfPath = et_path + "lib/esperanto-fw/MachineMinion/MachineMinion.elf" ; 111sysEmuOptions .masterMinionElfPath = et_path + "lib/esperanto-fw/MasterMinion/MasterMinion.elf" ; 112sysEmuOptions .workerMinionElfPath = et_path + "lib/esperanto-fw/WorkerMinion/WorkerMinion.elf" ; 113sysEmuOptions .executablePath = et_path + "bin/sys_emu" ; 114 115// Check that each path has a valid existing non-zero file otherwise emulator just silently hangs 116const std::vector < std::string > required_files = { 117sysEmuOptions .bootromTrampolineToBL2ElfPath ,sysEmuOptions .spBL2ElfPath , 118sysEmuOptions .machineMinionElfPath ,sysEmuOptions .masterMinionElfPath , 119sysEmuOptions .workerMinionElfPath ,sysEmuOptions .executablePath , 120 }; 121 122for (const auto & file :required_files ) { 123if (!fs::exists (file )|| fs::file_size (file )== 0 ) { 124// Check that each path has a valid existing non-zero file otherwise emulator just silently hangs 125GGML_LOG_ERROR ("ET: Unable to find required sysemu file: %s" ,file .c_str ()); 126GGML_LOG_ERROR ("ET: Confirm et-platform is correctly installed at configured path." ); 127abort (); 128 } 129 } 130 131sysEmuOptions .runDir = (fs::current_path ().string ()+ "/" ); 132sysEmuOptions .maxCycles = kSysEmuMaxCycles ; 133sysEmuOptions .minionShiresMask = kSysEmuMinionShiresMask ; 134sysEmuOptions .puUart0Path = sysEmuOptions .runDir + "pu_uart0_tx.log" ; 135sysEmuOptions .puUart1Path = sysEmuOptions .runDir + "pu_uart1_tx.log" ; 136sysEmuOptions .spUart0Path = sysEmuOptions .runDir + "spio_uart0_tx.log" ; 137sysEmuOptions .spUart1Path = sysEmuOptions .runDir + "spio_uart1_tx.log" ; 138sysEmuOptions .startGdb = false; 139sysEmuOptions .memcheck = false; 140 141return sysEmuOptions ; 142} 143 144// Forward declaration 145static void ggml_et_driver_cleanup (); 146 147static bool ggml_et_driver_init () { 148if (_drv .runtime != nullptr ) { 149assert (_drv .device_layer != nullptr ); 150 }else { 151try { 152#if definedGGML_ET_SYSEMU && GGML_ET_SYSEMU 153// For emulator device using sysEmuOptions provided by function above enabled compiling with `-DGGML_ET_SYSEMU=ON` 154_drv .device_layer = dev::IDeviceLayer ::createSysEmuDeviceLayer (ggml_et_get_default_sysemu_options ()); 155#else 156// For physical PCIe device 157_drv .device_layer = dev::IDeviceLayer ::createPcieDeviceLayer (); 158#endif // GGML_ET_SYSEMU 159 160_drv .runtime = rt::IRuntime ::create (_drv .device_layer ); 161 162// Initialize profiler if requested via environment variable 163const char * profile_path = getenv ("GGML_ET_PROFILE" ); 164if (profile_path ) { 165 std::string output_path = std::string (profile_path )+ "/et_runtime_trace.json" ; 166 std::string kernel_id_path = std::string (profile_path )+ "/kernel_id.json" ; 167 168_drv .profile_stream = std::make_unique < std::ofstream > (output_path ); 169_drv .kernel_id_stream = std::make_unique < std::ofstream > (kernel_id_path ); 170if (!_drv .profile_stream -> is_open ()) { 171GGML_LOG_ERROR ("ET: Failed to open profiling output file: %s" ,output_path .c_str ()); 172abort (); 173 } 174if (!_drv .kernel_id_stream -> is_open ()) { 175GGML_LOG_ERROR ("ET: Failed to open profiling kernel map: %s" ,kernel_id_path .c_str ()); 176abort (); 177 } 178 179auto * profiler = _drv .runtime -> getProfiler (); 180profiler -> start (* _drv .profile_stream , rt::IProfiler ::OutputType ::Json ); 181_drv .profiling_enabled = true; 182GGML_LOG_INFO ("ET: Runtime profiler started (JSON format)" ); 183 184// Register cleanup at program exit 185 std::atexit (ggml_et_driver_cleanup ); 186 } 187 }catch (const std::exception & e ) { 188GGML_LOG_ERROR ("ggml_et: %s" ,e .what ()); 189if (_drv .device_layer != nullptr ) { 190_drv .device_layer .reset (); 191 } 192if (_drv .runtime != nullptr ) { 193_drv .runtime .reset (); 194 } 195return false; 196 } 197 } 198return true; 199} 200 201static std::shared_ptr < dev::IDeviceLayer > ggml_et_devicelayer () { 202return _drv .device_layer ; 203} 204 205std::shared_ptr < rt::IRuntime > ggml_et_runtime () { 206return _drv .runtime ; 207} 208 209static void ggml_et_driver_cleanup () { 210if (_drv .profiling_enabled && _drv .runtime ) { 211GGML_LOG_INFO ("ET: Stopping runtime profiler" ); 212auto * profiler = _drv .runtime -> getProfiler (); 213profiler -> stop (); 214_drv .profiling_enabled = false; 215 216if (_drv .profile_stream ) { 217_drv .profile_stream -> close (); 218_drv .profile_stream .reset (); 219 } 220 221// Save kernel map 222if (_drv .kernel_id_stream && !_drv .kernel_map .empty ()) { 223auto & os = * _drv .kernel_id_stream ; 224// XXX: Manual JSON construction. Not pretty but removes dependency 225os <<"{\n" ; 226for (size_t i = 0 ;i < _drv .kernel_map .size ();i ++ ) { 227os <<" \"" <<_drv .kernel_map [i ].first <<"\": " << (int )_drv .kernel_map [i ].second ; 228if (i + 1 < _drv .kernel_map .size ()) { 229os <<"," ; 230 } 231os <<"\n" ; 232 } 233os <<"}\n" ; 234_drv .kernel_id_stream -> close (); 235_drv .kernel_id_stream .reset (); 236 } 237 } 238} 239 240static ggml_backend_dev_t ggml_backend_et_reg_get_device (ggml_backend_reg_t reg ,size_t devidx ); 241 242static void ggml_backend_et_buffer_free_buffer (ggml_backend_buffer_t buffer ) { 243ggml_backend_et_buffer_context * ctx = (ggml_backend_et_buffer_context * )buffer -> context ; 244if (ctx -> data != nullptr ) { 245 std::shared_ptr < rt::IRuntime > runtime = ggml_et_runtime (); 246if (runtime ) { 247runtime -> freeDevice (ctx -> rtid ,static_cast < std::byte *> (ctx -> data )); 248 } 249 } 250delete ctx ; 251} 252 253static void * ggml_backend_et_buffer_get_base (ggml_backend_buffer_t buffer ) { 254ggml_backend_et_buffer_context * ctx = (ggml_backend_et_buffer_context * )buffer -> context ; 255return ctx -> data ; 256} 257 258static ggml_status ggml_backend_et_buffer_init_tensor (ggml_backend_buffer_t buffer ,ggml_tensor * tensor ) { 259// View tensors share buffer with their view_src, no additional initialization needed 260if (tensor -> view_src != NULL ) { 261return GGML_STATUS_SUCCESS ; 262 } 263 264const size_t original_size = ggml_nbytes (tensor ); 265const size_t padded_size = ggml_backend_buft_get_alloc_size (buffer -> buft ,tensor ); 266 267// Clear padding bytes to avoid NaN values 268// XXX: Martin - do we need this? 269if (padded_size > original_size ) { 270const size_t padding_size = padded_size - original_size ; 271 272// Get device context to access memops kernel 273ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )buffer -> buft -> device -> context ; 274if (!dev_ctx ) { 275GGML_LOG_ERROR ("ET: Failed to get device context for padding clear" ); 276return GGML_STATUS_FAILED ; 277 } 278 279// Use device-side memset kernel for efficient padding clear 280 std::byte * padding_ptr = static_cast < std::byte *> (tensor -> data )+ original_size ; 281if (!ggml_et_memset (dev_ctx ,padding_ptr ,0 ,padding_size )) { 282GGML_LOG_ERROR ("ET: Failed to clear padding using memset kernel for tensor %s" ,tensor -> name ); 283return GGML_STATUS_FAILED ; 284 } 285 } 286 287return GGML_STATUS_SUCCESS ; 288} 289 290static void ggml_backend_et_buffer_set_tensor (ggml_backend_buffer_t buffer , 291ggml_tensor * tensor , 292const void * data , 293size_t offset , 294size_t size ) { 295 std::shared_ptr < rt::IRuntime > runtime = ggml_et_runtime (); 296if (!runtime ) { 297return ; 298 } 299 300// Create short-lived stream for this transfer 301ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )buffer -> buft -> device -> context ; 302 rt::StreamId stream = dev_ctx -> default_stream ; 303 304 std::byte * dst_ptr = static_cast < std::byte *> (tensor -> data )+ offset ; 305const std::byte * src_ptr = static_cast < const std::byte *> (data ); 306 307 rt::EventId event = runtime -> memcpyHostToDevice (stream ,src_ptr ,dst_ptr ,size , true/*barrier*/ ); 308 309runtime -> waitForEvent (event ); 310} 311 312static void ggml_backend_et_buffer_get_tensor (ggml_backend_buffer_t buffer , 313const ggml_tensor * tensor , 314void * data , 315size_t offset , 316size_t size ) { 317 std::shared_ptr < rt::IRuntime > runtime = ggml_et_runtime (); 318if (!runtime ) { 319return ; 320 } 321 322ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )buffer -> buft -> device -> context ; 323 rt::StreamId stream = dev_ctx -> default_stream ; 324 325const std::byte * src_ptr = static_cast < const std::byte *> (tensor -> data )+ offset ; 326 std::byte * dst_ptr = static_cast < std::byte *> (data ); 327 328 rt::EventId event = runtime -> memcpyDeviceToHost (stream ,src_ptr ,dst_ptr ,size , true/*barrier*/ ); 329 330runtime -> waitForEvent (event ); 331} 332 333static bool ggml_backend_et_buffer_cpy_tensor (ggml_backend_buffer_t buffer , 334const ggml_tensor * src , 335ggml_tensor * dst ) { 336GGML_UNUSED (buffer ); 337GGML_UNUSED (src ); 338GGML_UNUSED (dst ); 339return false; 340} 341 342static void ggml_backend_et_buffer_clear (ggml_backend_buffer_t buffer ,uint8_t value ) { 343ggml_backend_et_buffer_context * ctx = (ggml_backend_et_buffer_context * )buffer -> context ; 344 345if (ctx -> size == 0 || ctx -> data == nullptr ) { 346return ; 347 } 348 349// Get device context to access memops kernel 350ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )buffer -> buft -> device -> context ; 351if (!dev_ctx ) { 352GGML_LOG_ERROR ("ET: Failed to get device context for buffer clear" ); 353return ; 354 } 355 356// Use device-side memset kernel for efficient clearing 357if (!ggml_et_memset (dev_ctx ,ctx -> data ,value ,ctx -> size )) { 358GGML_LOG_ERROR ("ET: buffer_clear failed using memset kernel" ); 359return ; 360 } 361 362GGML_LOG_DEBUG ("ET: Buffer cleared successfully using memops kernel" ); 363} 364 365static const struct ggml_backend_buffer_i ggml_backend_et_buffer_i = { 366/* .free_buffer = */ ggml_backend_et_buffer_free_buffer , 367/* .get_base = */ ggml_backend_et_buffer_get_base , 368/* .init_tensor = */ ggml_backend_et_buffer_init_tensor , 369/* .memset_tensor = */ NULL , 370/* .set_tensor = */ ggml_backend_et_buffer_set_tensor , 371/* .get_tensor = */ ggml_backend_et_buffer_get_tensor , 372/* .set_tensor_2d = */ NULL , 373/* .get_tensor_2d = */ NULL , 374/* .cpy_tensor = */ ggml_backend_et_buffer_cpy_tensor , 375/* .clear = */ ggml_backend_et_buffer_clear , 376/* .reset = */ NULL , 377}; 378 379static const char * ggml_backend_et_buffer_type_get_name (ggml_backend_buffer_type_t buft ) { 380GGML_UNUSED (buft ); 381return GGML_ET_NAME ; 382} 383 384static ggml_backend_buffer_t ggml_backend_et_buffer_type_alloc_buffer (ggml_backend_buffer_type_t buft ,size_t size ) { 385ggml_backend_et_buffer_type_context * btctx = (ggml_backend_et_buffer_type_context * )buft -> context ; 386 387ggml_backend_et_buffer_context * ctx = new ggml_backend_et_buffer_context ; 388ctx -> devidx = btctx -> devidx ; 389ctx -> size = size ; 390 391 std::shared_ptr < rt::IRuntime > runtime = ggml_et_runtime (); 392if (!runtime ) { 393delete ctx ; 394return nullptr ; 395 } 396 397 std::vector < rt::DeviceId > rtids = runtime -> getDevices (); 398if (static_cast < size_t > (btctx -> devidx ) >=rtids .size ()) { 399delete ctx ; 400return nullptr ; 401 } 402ctx -> rtid = rtids [btctx -> devidx ]; 403 404ctx -> data = runtime -> mallocDevice (ctx -> rtid ,size ); 405if (ctx -> data == nullptr ) { 406delete ctx ; 407return nullptr ; 408 } 409 410return ggml_backend_buffer_init (buft ,ggml_backend_et_buffer_i ,ctx ,size ); 411} 412 413static size_t ggml_backend_et_buffer_type_get_alignment (ggml_backend_buffer_type_t buft ) { 414 std::shared_ptr < rt::IRuntime > runtime = ggml_et_runtime (); 415if (!runtime || !buft -> device ) { 416return GGML_MEM_ALIGN ; 417 } 418 419ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )buft -> device -> context ; 420 rt::DeviceProperties prop = runtime -> getDeviceProperties (dev_ctx -> rtid ); 421return prop .cacheLineSize_ ; 422} 423 424static size_t ggml_backend_et_buffer_type_get_max_size (ggml_backend_buffer_type_t buft ) { 425if (buft -> device ) { 426ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )buft -> device -> context ; 427return dev_ctx -> total_mem ; 428 } 429return SIZE_MAX ; 430} 431 432static size_t ggml_backend_et_buffer_type_get_alloc_size (ggml_backend_buffer_type_t buft ,const ggml_tensor * tensor ) { 433GGML_UNUSED (buft ); 434return ggml_nbytes_pad (tensor ); 435} 436 437static bool ggml_backend_et_buffer_type_is_host (ggml_backend_buffer_type_t buft ) { 438GGML_UNUSED (buft ); 439return false; 440} 441 442static const struct ggml_backend_buffer_type_i ggml_backend_et_buffer_type_i = { 443/* .get_name = */ ggml_backend_et_buffer_type_get_name , 444/* .alloc_buffer = */ ggml_backend_et_buffer_type_alloc_buffer , 445/* .get_alignment = */ ggml_backend_et_buffer_type_get_alignment , 446/* .get_max_size = */ ggml_backend_et_buffer_type_get_max_size , 447/* .get_alloc_size = */ ggml_backend_et_buffer_type_get_alloc_size , 448/* .is_host = */ ggml_backend_et_buffer_type_is_host , 449}; 450 451static const char * ggml_backend_et_get_name (ggml_backend_t backend ) { 452GGML_UNUSED (backend ); 453return GGML_ET_NAME ; 454} 455 456static void ggml_backend_et_free (ggml_backend_t backend ) { 457ggml_backend_et_context * et_ctx = (ggml_backend_et_context * )backend -> context ; 458 std::shared_ptr < rt::IRuntime > runtime = ggml_et_runtime (); 459 460// Clean up kernels on this device before freeing backend 461ggml_backend_dev_t dev = ggml_backend_et_reg_get_device (ggml_backend_et_reg (),et_ctx -> devidx ); 462if (dev && dev -> context ) { 463ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )dev -> context ; 464 465if (_drv .profiling_enabled ) { 466auto kernels = ggml_et_get_loaded_kernels (dev_ctx ); 467_drv .kernel_map .insert (_drv .kernel_map .end (),kernels .begin (),kernels .end ()); 468 } 469 470ggml_et_unload_all_kernels (dev_ctx ); 471 472if (runtime ) { 473if (dev_ctx -> trace_buffer ) { 474runtime -> freeDevice (dev_ctx -> rtid ,dev_ctx -> trace_buffer ); 475dev_ctx -> trace_buffer = nullptr ; 476 } 477// Drain any in-flight uberkernel launches before freeing the 478// device buffers they read from. 479runtime -> waitForStream (dev_ctx -> default_stream ); 480for (auto & slot :dev_ctx -> uberkernel .slots ) { 481if (slot .device_insts ) { 482runtime -> freeDevice (dev_ctx -> rtid ,slot .device_insts ); 483slot .device_insts = nullptr ; 484 } 485if (slot .device_params ) { 486runtime -> freeDevice (dev_ctx -> rtid ,slot .device_params ); 487slot .device_params = nullptr ; 488 } 489slot .has_pending = false; 490 } 491 } 492 } 493 494delete et_ctx ; 495delete backend ; 496} 497 498static ggml_backend_buffer_type_t ggml_backend_et_get_default_buffer_type (ggml_backend_t backend ) { 499ggml_backend_et_context * et_ctx = (ggml_backend_et_context * )backend -> context ; 500 501return ggml_backend_et_buffer_type (et_ctx -> devidx ); 502} 503 504static void ggml_backend_et_set_tensor_async (ggml_backend_t backend , 505ggml_tensor * tensor , 506const void * data , 507size_t offset , 508size_t size ) { 509 std::shared_ptr < rt::IRuntime > runtime = ggml_et_runtime (); 510if (!runtime ) { 511return ; 512 } 513 514ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )backend -> device -> context ; 515 rt::StreamId stream = dev_ctx -> default_stream ; 516 517 std::byte * dst_ptr = static_cast < std::byte *> (tensor -> data )+ offset ; 518const std::byte * src_ptr = static_cast < const std::byte *> (data ); 519 520runtime -> memcpyHostToDevice (stream ,src_ptr ,dst_ptr ,size , true/*barrier*/ ); 521} 522 523static void ggml_backend_et_get_tensor_async (ggml_backend_t backend , 524const ggml_tensor * tensor , 525void * data , 526size_t offset , 527size_t size ) { 528 std::shared_ptr < rt::IRuntime > runtime = ggml_et_runtime (); 529if (!runtime ) { 530return ; 531 } 532 533ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )backend -> device -> context ; 534 rt::StreamId stream = dev_ctx -> default_stream ; 535 536const std::byte * src_ptr = static_cast < const std::byte *> (tensor -> data )+ offset ; 537 std::byte * dst_ptr = static_cast < std::byte *> (data ); 538 539runtime -> memcpyDeviceToHost (stream ,src_ptr ,dst_ptr ,size , true/*barrier*/ ); 540} 541 542static bool ggml_backend_et_cpy_tensor_async (ggml_backend_t backend_src , 543ggml_backend_t backend_dst , 544const ggml_tensor * src , 545ggml_tensor * dst ) { 546GGML_UNUSED (backend_src ); 547GGML_UNUSED (backend_dst ); 548GGML_UNUSED (src ); 549GGML_UNUSED (dst ); 550return false; 551} 552 553static void ggml_backend_et_synchronize (ggml_backend_t backend ) { 554 std::shared_ptr < rt::IRuntime > runtime = ggml_et_runtime (); 555if (!runtime ) { 556return ; 557 } 558 559ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )backend -> device -> context ; 560runtime -> waitForStream (dev_ctx -> default_stream ); 561 562auto errors = runtime -> retrieveStreamErrors (dev_ctx -> default_stream ); 563if (errors .empty ()) { 564return ; 565 } 566for (const auto & err :errors ) { 567GGML_LOG_ERROR ("ET: stream error detected at synchronization point. Code: %d,Type: %d\n" , (int )err .errorCode_ , 568 (int )err .errorContext_ .value ()[0 ].type_ ); 569 } 570abort (); 571} 572 573static bool ggml_et_can_fuse (const ggml_cgraph * cgraph ,int node_idx , std::initializer_list < ggml_op > ops ) { 574if (!ggml_can_fuse (cgraph ,node_idx ,ops )) { 575return false; 576 } 577 578if (ops .size ()== 2 && ops .begin ()[0 ]== GGML_OP_MUL_MAT && ops .begin ()[1 ]== GGML_OP_ADD ) { 579const ggml_tensor * mm = cgraph -> nodes [node_idx ]; 580const ggml_tensor * add = cgraph -> nodes [node_idx + 1 ]; 581 582// Only Q8_0 weights x F32 activations -> F32 (the kernel that has 583// the bias path). Other MM variants must wait for their own kernel 584// bias support. 585if (mm -> type != GGML_TYPE_F32 || mm -> src [0 ]-> type != GGML_TYPE_Q8_0 || mm -> src [1 ]-> type != GGML_TYPE_F32 ) { 586return false; 587 } 588 589// ADD must be F32 and one of its operands must be the MM output. 590if (add -> type != GGML_TYPE_F32 ) { 591return false; 592 } 593if (add -> src [0 ]!= mm && add -> src [1 ]!= mm ) { 594return false; 595 } 596 597const ggml_tensor * bias = (add -> src [0 ]== mm ) ?add -> src [1 ] :add -> src [0 ]; 598 599if (bias -> type != GGML_TYPE_F32 ) { 600return false; 601 } 602 603// No broadcasting: bias shape must equal MM output shape. 604for (int i = 0 ;i < GGML_MAX_DIMS ;++ i ) { 605if (bias -> ne [i ]!= mm -> ne [i ]) { 606return false; 607 } 608 } 609 610// Bias and dst must be contiguous and have identical strides - the 611// kernel uses dst-style offset arithmetic against bias's nb[]. 612if (!ggml_is_contiguous (bias )|| !ggml_is_contiguous (mm )) { 613return false; 614 } 615for (int i = 0 ;i < GGML_MAX_DIMS ;++ i ) { 616if ((int64_t )bias -> nb [i ]!= (int64_t )add -> nb [i ]) { 617return false; 618 } 619 } 620 } 621 622if (ops .size ()== 2 && ops .begin ()[0 ]== GGML_OP_RMS_NORM && ops .begin ()[1 ]== GGML_OP_MUL ) { 623const ggml_tensor * rms_norm = cgraph -> nodes [node_idx ]; 624const ggml_tensor * mul = cgraph -> nodes [node_idx + 1 ]; 625 626// ET only supports F32 627if (rms_norm -> src [0 ]-> type != GGML_TYPE_F32 || mul -> type != GGML_TYPE_F32 ) { 628return false; 629 } 630 631// Identify the weights tensor (the MUL operand that isn't rms_norm output) 632const ggml_tensor * weights = (mul -> src [0 ]== rms_norm ) ?mul -> src [1 ] :mul -> src [0 ]; 633 634if (weights -> type != GGML_TYPE_F32 ) { 635return false; 636 } 637 638// Both inputs must be contiguous (ET hardware requirement) 639if (!ggml_is_contiguous (rms_norm -> src [0 ])|| !ggml_is_contiguous_rows (weights )) { 640return false; 641 } 642 643// ET requires cache-aligned rows (ne[0] % 16 == 0) 644if (rms_norm -> src [0 ]-> ne [0 ] %16 != 0 || weights -> ne [0 ] %16 != 0 ) { 645return false; 646 } 647 648// Fused kernel doesn't handle dim-0 broadcasting 649if (weights -> ne [0 ]!= rms_norm -> src [0 ]-> ne [0 ]) { 650return false; 651 } 652 } 653 654return true; 655} 656 657static ggml_status ggml_backend_et_graph_compute (ggml_backend_t backend ,ggml_cgraph * cgraph ) { 658ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )backend -> device -> context ; 659ggml_et_uberkernel_begin_graph (& dev_ctx -> uberkernel ); 660 661for (int i = 0 ;i < cgraph -> n_nodes ;i ++ ) { 662ggml_tensor * node = cgraph -> nodes [i ]; 663 664if (node -> op == GGML_OP_NONE || node -> op == GGML_OP_VIEW || node -> op == GGML_OP_RESHAPE || 665node -> op == GGML_OP_PERMUTE || node -> op == GGML_OP_TRANSPOSE ) { 666continue ; 667 } 668 669// --- Fusion checks (before regular dispatch) --- 670if (ggml_et_can_fuse (cgraph ,i , {GGML_OP_RMS_NORM ,GGML_OP_MUL })) { 671ggml_et_op_rms_norm_mul (dev_ctx ,node ,cgraph -> nodes [i + 1 ]); 672i ++ ;// skip the MUL node 673continue ; 674 } 675if (ggml_et_can_fuse (cgraph ,i , {GGML_OP_MUL_MAT ,GGML_OP_ADD })) { 676ggml_et_op_mul_mat (dev_ctx ,node ,cgraph -> nodes [i + 1 ]); 677i ++ ;// skip the ADD node 678continue ; 679 } 680 681switch (node -> op ) { 682case GGML_OP_SQR : 683ggml_et_op_sqr (dev_ctx ,node ); 684break ; 685 686case GGML_OP_UNARY : 687ggml_et_op_unary (dev_ctx ,node ); 688break ; 689 690case GGML_OP_SUM_ROWS : 691ggml_et_op_sum_rows (dev_ctx ,node ); 692break ; 693 694case GGML_OP_MEAN : 695ggml_et_op_mean (dev_ctx ,node ); 696break ; 697 698case GGML_OP_CLAMP : 699ggml_et_op_clamp (dev_ctx ,node ); 700break ; 701 702case GGML_OP_MUL : 703ggml_et_op_mul (dev_ctx ,node ); 704break ; 705 706case GGML_OP_ADD : 707ggml_et_op_add (dev_ctx ,node ); 708break ; 709 710case GGML_OP_SUB : 711ggml_et_op_sub (dev_ctx ,node ); 712break ; 713 714case GGML_OP_CUMSUM : 715ggml_et_op_cumsum (dev_ctx ,node ); 716break ; 717 718case GGML_OP_MUL_MAT : 719ggml_et_op_mul_mat (dev_ctx ,node ); 720break ; 721 722case GGML_OP_MUL_MAT_ID : 723ggml_et_op_mul_mat_id (dev_ctx ,node ); 724break ; 725 726case GGML_OP_ROPE : 727ggml_et_op_rope (dev_ctx ,node ); 728break ; 729 730case GGML_OP_RMS_NORM : 731ggml_et_op_rms_norm (dev_ctx ,node ); 732break ; 733 734case GGML_OP_NORM : 735ggml_et_op_norm (dev_ctx ,node ); 736break ; 737 738case GGML_OP_L2_NORM : 739ggml_et_op_l2_norm (dev_ctx ,node ); 740break ; 741 742case GGML_OP_GROUP_NORM : 743ggml_et_op_group_norm (dev_ctx ,node ); 744break ; 745 746case GGML_OP_SCALE : 747ggml_et_op_scale (dev_ctx ,node ); 748break ; 749 750case GGML_OP_GLU : 751ggml_et_op_glu (dev_ctx ,node ); 752break ; 753 754case GGML_OP_SOFT_MAX : 755ggml_et_op_softmax (dev_ctx ,node ); 756break ; 757 758case GGML_OP_IM2COL : 759ggml_et_op_im2col (dev_ctx ,node ); 760break ; 761 762case GGML_OP_CONV_2D : 763ggml_et_op_conv_2d (dev_ctx ,node ); 764break ; 765 766case GGML_OP_FLASH_ATTN_EXT : 767ggml_et_op_flash_attn_ext (dev_ctx ,node ); 768break ; 769 770case GGML_OP_GET_ROWS : 771ggml_et_op_get_rows (dev_ctx ,node ); 772break ; 773 774case GGML_OP_CONT : 775ggml_et_op_cont (dev_ctx ,node ); 776break ; 777 778case GGML_OP_CPY : 779ggml_et_op_cpy (dev_ctx ,node ); 780break ; 781 782case GGML_OP_CONCAT : 783ggml_et_op_concat (dev_ctx ,node ); 784break ; 785 786case GGML_OP_REPEAT : 787ggml_et_op_repeat (dev_ctx ,node ); 788break ; 789 790case GGML_OP_SSM_CONV : 791ggml_et_op_ssm_conv (dev_ctx ,node ); 792break ; 793 794case GGML_OP_SSM_SCAN : 795ggml_et_op_ssm_scan (dev_ctx ,node ); 796break ; 797 798case GGML_OP_PAD : 799ggml_et_op_pad (dev_ctx ,node ); 800break ; 801 802case GGML_OP_SET_ROWS : 803ggml_et_op_set_rows (dev_ctx ,node ); 804break ; 805 806case GGML_OP_FILL : 807ggml_et_op_fill (dev_ctx ,node ); 808break ; 809 810case GGML_OP_DIAG : 811ggml_et_op_diag (dev_ctx ,node ); 812break ; 813 814case GGML_OP_TRI : 815ggml_et_op_tri (dev_ctx ,node ); 816break ; 817 818case GGML_OP_SOLVE_TRI : 819ggml_et_op_solve_tri (dev_ctx ,node ); 820break ; 821 822case GGML_OP_SET : 823ggml_et_op_set (dev_ctx ,node ); 824break ; 825 826case GGML_OP_RWKV_WKV6 : 827ggml_et_op_rwkv_wkv6 (dev_ctx ,node ); 828break ; 829 830case GGML_OP_RWKV_WKV7 : 831ggml_et_op_rwkv_wkv7 (dev_ctx ,node ); 832break ; 833 834case GGML_OP_GATED_DELTA_NET : 835ggml_et_op_gated_delta_net (dev_ctx ,node ); 836break ; 837 838default : 839ggml_et_uberkernel_abort_graph (& dev_ctx -> uberkernel ); 840GGML_LOG_ERROR ("ET: Unsupported operation in graph: %s" ,ggml_op_name (node -> op )); 841return GGML_STATUS_FAILED ; 842 } 843 844if (ggml_et_uberkernel_failed (& dev_ctx -> uberkernel )) { 845ggml_et_uberkernel_abort_graph (& dev_ctx -> uberkernel ); 846return GGML_STATUS_FAILED ; 847 } 848 } 849 850if (!ggml_et_uberkernel_end_graph (dev_ctx )) { 851ggml_et_uberkernel_abort_graph (& dev_ctx -> uberkernel ); 852return GGML_STATUS_FAILED ; 853 } 854 855return GGML_STATUS_SUCCESS ; 856} 857 858// Check that elements within each row are contiguous (nb[0] == type_size). 859// Higher-dim strides can be arbitrary - kernels navigate them via byte offsets. 860static bool et_ggml_is_row_contiguous (const ggml_tensor * t ) { 861return t -> nb [0 ]== ggml_type_size (t -> type ); 862} 863 864static bool ggml_backend_et_device_supports_op (ggml_backend_dev_t dev ,const ggml_tensor * op ) { 865GGML_UNUSED (dev ); 866 867bool supported = false; 868switch (op -> op ) { 869case GGML_OP_CUMSUM : 870supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 871op -> src [0 ]-> nb [0 ]== sizeof (float )&& ggml_is_contiguous (op ); 872break ; 873case GGML_OP_SQR : 874supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 875op -> ne [0 ] %16 == 0 && ggml_is_contiguous (op )&& ggml_is_contiguous (op -> src [0 ]); 876break ; 877case GGML_OP_SUM_ROWS : 878// dst has ne[0]=1, src0 row length must be cache-aligned 879supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 880op -> src [0 ]-> ne [0 ] %16 == 0 && ggml_is_contiguous (op -> src [0 ]); 881break ; 882case GGML_OP_MEAN : 883// Kernel handles arbitrary ne00 (per-row alignment guard with 884// scalar tail), so no row-length divisibility constraint here. 885supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 886ggml_is_contiguous (op -> src [0 ]); 887break ; 888case GGML_OP_CLAMP : 889// Element-wise; kernel distributes by cache lines and handles a 890// scalar tail, so any contiguous F32 size is fine - including the 891// 1x1x1x1 scalar case. 892supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 893ggml_is_contiguous (op )&& ggml_is_contiguous (op -> src [0 ]); 894break ; 895case GGML_OP_UNARY : 896// Only require dim-0 contiguity (nb[0] == sizeof(float)). Higher 897// dims may be arbitrarily strided views; the kernel walks per-row 898// using all four nb[] values. See unary_f32.c entry_point. 899if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 900ggml_nelements (op ) %16 == 0 && op -> nb [0 ]== sizeof (float )&& op -> src [0 ]-> nb [0 ]== sizeof (float )) { 901switch (ggml_get_unary_op (op )) { 902case GGML_UNARY_OP_ABS : 903case GGML_UNARY_OP_SGN : 904case GGML_UNARY_OP_NEG : 905case GGML_UNARY_OP_STEP : 906case GGML_UNARY_OP_TANH : 907case GGML_UNARY_OP_ELU : 908case GGML_UNARY_OP_RELU : 909case GGML_UNARY_OP_SIGMOID : 910case GGML_UNARY_OP_GELU : 911case GGML_UNARY_OP_GELU_QUICK : 912case GGML_UNARY_OP_SILU : 913case GGML_UNARY_OP_HARDSWISH : 914case GGML_UNARY_OP_HARDSIGMOID : 915case GGML_UNARY_OP_EXP : 916case GGML_UNARY_OP_EXPM1 : 917case GGML_UNARY_OP_SOFTPLUS : 918case GGML_UNARY_OP_GELU_ERF : 919case GGML_UNARY_OP_FLOOR : 920case GGML_UNARY_OP_CEIL : 921case GGML_UNARY_OP_ROUND : 922case GGML_UNARY_OP_TRUNC : 923supported = true; 924break ; 925default : 926break ; 927 } 928 } 929break ; 930case GGML_OP_MUL : 931case GGML_OP_ADD : 932case GGML_OP_SUB : 933supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && op -> src [1 ]&& 934op -> src [1 ]-> type == GGML_TYPE_F32 && op -> nb [0 ]== sizeof (float )&& 935op -> src [0 ]-> nb [0 ]== sizeof (float )&& 936 (op -> src [1 ]-> nb [0 ]== sizeof (float )|| op -> src [1 ]-> ne [0 ]== 1 )&& 937op -> nb [1 ]== op -> ne [0 ]* sizeof (float ); 938break ; 939case GGML_OP_MUL_MAT : 940// Support Q8_0 x F32 -> F32, F16 x F32 -> F32, F16 x F16 -> F32, and F32 x F32 -> F32 matrix multiplication 941// Stride requirements: first dimension must be contiguous for all tensors 942if (op -> type == GGML_TYPE_F32 && 943 ((op -> src [0 ]-> type == GGML_TYPE_F32 && op -> src [1 ]-> type == GGML_TYPE_F32 )|| 944 (op -> src [0 ]-> type == GGML_TYPE_F16 && op -> src [1 ]-> type == GGML_TYPE_F16 ))&& 945op -> ne [0 ] %16 == 0 && // dst row length for tensor-store path 946op -> src [0 ]-> ne [1 ] %16 == 0 && // m 947op -> src [0 ]-> ne [0 ] %16 == 0 && // k 948ggml_is_contiguous (op -> src [0 ])&& ggml_is_contiguous (op -> src [1 ])) { 949// Special path for the FP32 TensorFMA kernel 950// Limitation - generic kernels can tolerate non-cache-aligned dst rows 951// because they publish each output element atomically. The matrix 952// engine path still uses tiled tensor stores, so keep dst rows aligned. 953// The m edge is difficult to do because of the 4 conseqtive load hardware limitation 954// And the k edge is impossible because that is encoded as `stride & 0xFFFFFFFFFFC0ULL` which becomes 0 for stride 16 (4x FP32) :( 955// FIXME: Right now this overwrites the mul_mat_f32 kernel - whatever. Fix later. Demo code 956supported = true; 957 }else if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& 958 (op -> src [0 ]-> type == GGML_TYPE_F16 || op -> src [0 ]-> type == GGML_TYPE_F32 )&& op -> src [1 ]&& 959 (op -> src [1 ]-> type == GGML_TYPE_F16 || op -> src [1 ]-> type == GGML_TYPE_F32 )) { 960// Check first dimension contiguity requirements 961bool src0_first_dim_contiguous = (op -> src [0 ]-> nb [0 ]== ggml_type_size (op -> src [0 ]-> type )); 962bool src1_first_dim_contiguous = (op -> src [1 ]-> nb [0 ]== ggml_type_size (op -> src [1 ]-> type )); 963bool dst_first_dim_contiguous = (op -> nb [0 ]== sizeof (float )); 964 965// Check destination stride ordering (only for dimensions with ne > 1) 966bool dst_properly_ordered = true; 967for (int d = 0 ;d < 3 ;d ++ ) { 968if (op -> ne [d ]> 1 && op -> ne [d + 1 ]> 1 && op -> nb [d ]> op -> nb [d + 1 ]) { 969dst_properly_ordered = false; 970 } 971 } 972 973supported = src0_first_dim_contiguous && src1_first_dim_contiguous && dst_first_dim_contiguous && 974dst_properly_ordered ; 975 }else if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_Q8_0 && op -> src [1 ]&& 976op -> src [1 ]-> type == GGML_TYPE_F32 ) { 977// Keep the existing quantized path constraints separate from the 978// relaxed non-quant generic fallback. 979bool src0_first_dim_contiguous = (op -> src [0 ]-> nb [0 ]== ggml_type_size (op -> src [0 ]-> type )); 980bool src1_first_dim_contiguous = (op -> src [1 ]-> nb [0 ]== ggml_type_size (op -> src [1 ]-> type )); 981bool dst_first_dim_contiguous = (op -> nb [0 ]== sizeof (float )); 982 983bool dst_properly_ordered = true; 984for (int d = 0 ;d < 3 ;d ++ ) { 985if (op -> ne [d ]> 1 && op -> ne [d + 1 ]> 1 && op -> nb [d ]> op -> nb [d + 1 ]) { 986dst_properly_ordered = false; 987 } 988 } 989 990supported = src0_first_dim_contiguous && src1_first_dim_contiguous && dst_first_dim_contiguous && 991dst_properly_ordered ; 992 993 }else if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_Q4_0 && op -> src [1 ]&& 994op -> src [1 ]-> type == GGML_TYPE_F32 ) { 995// Keep the existing quantized path constraints separate from the 996// relaxed non-quant generic fallback. 997bool src0_first_dim_contiguous = (op -> src [0 ]-> nb [0 ]== ggml_type_size (op -> src [0 ]-> type )); 998bool src1_first_dim_contiguous = (op -> src [1 ]-> nb [0 ]== ggml_type_size (op -> src [1 ]-> type )); 999bool dst_first_dim_contiguous = (op -> nb [0 ]== sizeof (float )); 1000 1001bool dst_properly_ordered = true; 1002for (int d = 0 ;d < 3 ;d ++ ) { 1003if (op -> ne [d ]> 1 && op -> ne [d + 1 ]> 1 && op -> nb [d ]> op -> nb [d + 1 ]) { 1004dst_properly_ordered = false; 1005 } 1006 } 1007 1008supported = src0_first_dim_contiguous && src1_first_dim_contiguous && dst_first_dim_contiguous && 1009dst_properly_ordered ; 1010 }else { 1011supported = false; 1012 } 1013break ; 1014case GGML_OP_MUL_MAT_ID : 1015// Support MUL_MAT_ID for Mixture of Experts: (Q8_0/Q4_0/F16/F32) x F32 -> F32 with I32 expert indices 1016// src0 (as): [K, M, n_expert] - expert weight matrices (can be quantized) 1017// src1 (b): [K, n_expert_used, batch] - activations (F32) 1018// src2 (ids): [n_expert_used, batch] - expert selection indices (I32) 1019// dst: [M, n_expert_used, batch, 1] - output (F32) 1020if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& 1021 (op -> src [0 ]-> type == GGML_TYPE_Q8_0 || op -> src [0 ]-> type == GGML_TYPE_Q4_0 || 1022op -> src [0 ]-> type == GGML_TYPE_F16 || op -> src [0 ]-> type == GGML_TYPE_F32 )&& 1023op -> src [1 ]&& op -> src [1 ]-> type == GGML_TYPE_F32 && op -> src [2 ]&& op -> src [2 ]-> type == GGML_TYPE_I32 ) { 1024// Check first dimension contiguity requirements (matching CPU backend) 1025bool src0_first_dim_contiguous = (op -> src [0 ]-> nb [0 ]== ggml_type_size (op -> src [0 ]-> type )); 1026bool src1_first_dim_contiguous = (op -> src [1 ]-> nb [0 ]== ggml_type_size (op -> src [1 ]-> type )); 1027bool src2_first_dim_contiguous = (op -> src [2 ]-> nb [0 ]== ggml_type_size (op -> src [2 ]-> type )); 1028bool dst_first_dim_contiguous = (op -> nb [0 ]== sizeof (float )); 1029 1030// Check destination stride ordering (only for dimensions with ne > 1) 1031bool dst_properly_ordered = true; 1032for (int d = 0 ;d < 3 ;d ++ ) { 1033if (op -> ne [d ]> 1 && op -> ne [d + 1 ]> 1 && op -> nb [d ]> op -> nb [d + 1 ]) { 1034dst_properly_ordered = false; 1035 } 1036 } 1037 1038// Validate tensor dimension constraints from GGML definition 1039bool dims_valid = (op -> src [0 ]-> ne [3 ]== 1 )&& // as is 3d (one matrix per expert) 1040 (op -> src [1 ]-> ne [3 ]== 1 )&& // b is 3d 1041 (op -> src [2 ]-> ne [2 ]== 1 && op -> src [2 ]-> ne [3 ]== 1 )&& // ids is 2d 1042 (op -> src [2 ]-> ne [1 ]== op -> src [1 ]-> ne [2 ])&& // must have expert list per b row 1043 (op -> src [0 ]-> ne [0 ]== op -> src [1 ]-> ne [0 ])&& // K dimension must match 1044 (op -> src [2 ]-> ne [0 ] %op -> src [1 ]-> ne [1 ]== 0 );// can broadcast 1045 1046supported = src0_first_dim_contiguous && src1_first_dim_contiguous && src2_first_dim_contiguous && 1047dst_first_dim_contiguous && dst_properly_ordered && dims_valid ; 1048 }else { 1049supported = false; 1050 } 1051break ; 1052case GGML_OP_ROPE : 1053// Support F32 x I32 -> F32 RoPE for the modes implemented by rope_f32. 1054if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && op -> src [1 ]&& 1055op -> src [1 ]-> type == GGML_TYPE_I32 && ggml_is_contiguous (op )&& et_ggml_is_row_contiguous (op -> src [0 ])) { 1056const int mode = ggml_get_op_params_i32 (op ,2 ); 1057const int ndims = ggml_get_op_params_i32 (op ,1 ); 1058const bool is_normal = mode == GGML_ROPE_TYPE_NORMAL ; 1059const bool is_neox = mode == GGML_ROPE_TYPE_NEOX ; 1060const bool is_imrope = mode == GGML_ROPE_TYPE_IMROPE ; 1061const bool zero_view_offset = op -> src [0 ]-> view_src == nullptr || op -> src [0 ]-> view_offs == 0 ; 1062const bool has_sections = ggml_get_op_params_i32 (op ,11 )> 0 || ggml_get_op_params_i32 (op ,12 )> 0 || 1063ggml_get_op_params_i32 (op ,13 )> 0 ; 1064// FIXME: support ggml_rope_set_offset 1065const bool zero_rot_offset = ggml_get_op_params_i32 (op ,15 )== 0 ; 1066 1067supported = 1068zero_view_offset && zero_rot_offset && ndims <=512 && 1069 (is_normal || (is_neox && ndims %16 == 0 )|| (is_imrope && ndims %16 == 0 && has_sections )); 1070 }else { 1071supported = false; 1072 } 1073break ; 1074case GGML_OP_RMS_NORM : 1075supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 1076op -> ne [0 ] %16 == 0 && ggml_is_contiguous (op )&& et_ggml_is_row_contiguous (op -> src [0 ]); 1077break ; 1078case GGML_OP_NORM : 1079supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 1080op -> ne [0 ] %16 == 0 && ggml_is_contiguous (op )&& et_ggml_is_row_contiguous (op -> src [0 ]); 1081break ; 1082case GGML_OP_L2_NORM : 1083supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 1084op -> ne [0 ] %16 == 0 && ggml_is_contiguous (op )&& et_ggml_is_row_contiguous (op -> src [0 ]); 1085break ; 1086case GGML_OP_GROUP_NORM : 1087supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 1088ggml_is_contiguous (op )&& et_ggml_is_row_contiguous (op -> src [0 ])&& 1089ggml_get_op_params_i32 (op ,0 )> 0 ; 1090break ; 1091case GGML_OP_IM2COL : 1092supported = op -> src [0 ]&& op -> src [1 ]&& 1093 ((op -> type == GGML_TYPE_F32 && op -> src [1 ]-> type == GGML_TYPE_F32 )|| 1094 (op -> type == GGML_TYPE_F16 && 1095 (op -> src [1 ]-> type == GGML_TYPE_F16 || op -> src [1 ]-> type == GGML_TYPE_F32 )))&& 1096ggml_is_contiguous (op )&& ggml_is_contiguous (op -> src [1 ])&& 1097op -> nb [0 ]== ggml_type_size (op -> type )&& op -> src [1 ]-> nb [0 ]== ggml_type_size (op -> src [1 ]-> type ); 1098break ; 1099case GGML_OP_CONV_2D : 1100 { 1101// First-cut conv_2d_f32_me kernel constraints. Anything outside 1102// this falls back to CPU (it's a strict subset on purpose). 1103if (!op -> src [0 ]|| !op -> src [1 ]) { 1104supported = false; 1105break ; 1106 } 1107if (op -> type != GGML_TYPE_F32 || op -> src [0 ]-> type != GGML_TYPE_F32 || 1108op -> src [1 ]-> type != GGML_TYPE_F32 ) { 1109supported = false; 1110break ; 1111 } 1112if (!ggml_is_contiguous (op )|| !ggml_is_contiguous (op -> src [0 ])|| !ggml_is_contiguous (op -> src [1 ])) { 1113supported = false; 1114break ; 1115 } 1116 1117const ggml_tensor * flt = op -> src [0 ];// [Kw, Kh, Cin, Cout] 1118const ggml_tensor * in = op -> src [1 ];// [W, H, Cin, N] 1119const int32_t s0 = ggml_get_op_params_i32 (op ,0 ); 1120const int32_t s1 = ggml_get_op_params_i32 (op ,1 ); 1121const int32_t p0 = ggml_get_op_params_i32 (op ,2 ); 1122const int32_t p1 = ggml_get_op_params_i32 (op ,3 ); 1123const int32_t d0 = ggml_get_op_params_i32 (op ,4 ); 1124const int32_t d1 = ggml_get_op_params_i32 (op ,5 ); 1125 1126const int64_t Kw = flt -> ne [0 ]; 1127const int64_t Kh = flt -> ne [1 ]; 1128const int64_t Cin = flt -> ne [2 ]; 1129const int64_t Cout = flt -> ne [3 ]; 1130const int64_t H = in -> ne [1 ]; 1131 (void )in -> ne [0 ]; 1132 1133if (s0 < 1 || s1 < 1 || !(d0 == 1 && d1 == 1 )|| Cin %16 != 0 || Cout %16 != 0 || in -> ne [3 ]!= 1 ) { 1134supported = false; 1135break ; 1136 } 1137const int64_t OW = op -> ne [0 ]; 1138const int64_t OH = op -> ne [1 ]; 1139if (OW <=0 || OH <=0 ) { 1140supported = false; 1141break ; 1142 } 1143 (void )p0 ; 1144 (void )p1 ; 1145 1146// Mirror the kernel's sizing: 1147// if K_TILES * per_KT_bytes <= budget: 1 buffer, n_chunks=1 1148// else: 2 buffers (double-buffer), shrink chunk_KT until 1149// 2*chunk_KT*per_KT_bytes <= budget. 1150const int64_t Hp = H + 2 * p1 ; 1151const int64_t OW_pad = (OW + 15 )& ~15 ; 1152const int64_t Wp_a = OW_pad ; 1153const bool need_stage = (OW %16 != 0 ); 1154const int64_t stage_bytes = need_stage ? (Cout * OH * OW_pad * 4 ) :0 ; 1155const int64_t L2SCP_BUDGET = 1500 * 1024 ; 1156// Per-hart partial-TenC scratch (mirrors kernel MAX_TILES_PER_HART=2): 1157// 32 minions x 2 tiles x 1024 bytes = 64 KB per shire. 1158const int64_t scratch_bytes = 32 * 2 * 16 * 16 * 4 ; 1159const int64_t budget = L2SCP_BUDGET - stage_bytes - scratch_bytes ; 1160const int64_t per_KT_bytes = Kh * Kw * Cout * 16 * 4 + Kw * 16 * Hp * Wp_a * 4 ; 1161const int64_t K_TILES = Cin /16 ; 1162 1163int64_t chunk_KT_calc ; 1164int64_t n_chunks_calc ; 1165if (K_TILES * per_KT_bytes <=budget ) { 1166chunk_KT_calc = K_TILES ; 1167n_chunks_calc = 1 ; 1168 }else { 1169chunk_KT_calc = K_TILES ; 1170while (chunk_KT_calc > 1 && 2 * chunk_KT_calc * per_KT_bytes > budget ) { 1171chunk_KT_calc -- ; 1172 } 1173while (chunk_KT_calc > 1 && K_TILES %chunk_KT_calc != 0 ) { 1174chunk_KT_calc -- ; 1175 } 1176if (chunk_KT_calc < 1 ) { 1177supported = false; 1178break ; 1179 } 1180n_chunks_calc = K_TILES /chunk_KT_calc ; 1181 } 1182 1183if (n_chunks_calc > 1 ) { 1184const int64_t M_TILES = Cout /16 ; 1185const int64_t w_tiles = (OW + 15 ) /16 ; 1186const int64_t total_tiles = OH * w_tiles * M_TILES ; 1187// MAX_TILES_PER_HART = 2 (mirrors kernel constant). 1188const int64_t max_workers = (need_stage ?32 :1024 )* 2 ; 1189if (total_tiles > max_workers ) { 1190supported = false; 1191break ; 1192 } 1193 } 1194 1195supported = true; 1196break ; 1197 } 1198case GGML_OP_SCALE : 1199// F32 contiguous, total elements must be cache line aligned (16 floats) 1200supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 1201ggml_is_contiguous (op )&& ggml_is_contiguous (op -> src [0 ])&& (ggml_nelements (op ) %16 == 0 ); 1202break ; 1203case GGML_OP_GLU : 1204// Note: we only require row-wise contiguity (ggml_is_contiguous_1) so that 1205// strided views over a packed up_proj tensor (the common split-GLU layout) 1206// are accepted. The kernel walks rows via nb[1] strides, so the inner 1207// dimension just needs to be densely packed. 1208if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 1209ggml_nelements (op ) %16 == 0 && ggml_is_contiguous_1 (op )&& ggml_is_contiguous_1 (op -> src [0 ])) { 1210// Check GLU variant - support SWIGLU, SWIGLU_OAI, GEGLU, GEGLU_ERF, GEGLU_QUICK, REGLU 1211ggml_glu_op glu_type = ggml_get_glu_op (op ); 1212const bool supported_variant = glu_type == GGML_GLU_OP_SWIGLU || glu_type == GGML_GLU_OP_SWIGLU_OAI || 1213glu_type == GGML_GLU_OP_SWIGLU_CLAMP || glu_type == GGML_GLU_OP_GEGLU || 1214glu_type == GGML_GLU_OP_GEGLU_ERF || 1215glu_type == GGML_GLU_OP_GEGLU_QUICK || glu_type == GGML_GLU_OP_REGLU ; 1216 1217if (op -> src [1 ]) { 1218supported = supported_variant && op -> src [1 ]-> type == GGML_TYPE_F32 && 1219ggml_is_contiguous_1 (op -> src [1 ])&& op -> src [0 ]-> ne [0 ]== op -> ne [0 ]&& 1220op -> src [1 ]-> ne [0 ]== op -> ne [0 ]; 1221 }else { 1222supported = supported_variant && op -> src [0 ]-> ne [0 ]== 2 * op -> ne [0 ]; 1223 } 1224 }else { 1225supported = false; 1226 } 1227break ; 1228case GGML_OP_SOFT_MAX : 1229if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 1230ggml_is_contiguous (op )&& ggml_is_contiguous (op -> src [0 ])&& op -> src [0 ]-> ne [0 ]> 1 ) { 1231// Check optional mask tensor (F32 only) 1232if (op -> src [1 ]) { 1233supported = op -> src [1 ]-> type == GGML_TYPE_F32 && ggml_is_contiguous (op -> src [1 ]); 1234if (!supported ) { 1235break ; 1236 } 1237 } 1238// Check optional sinks tensor (F32 only) 1239if (op -> src [2 ]) { 1240supported = op -> src [2 ]-> type == GGML_TYPE_F32 && ggml_is_contiguous (op -> src [2 ]); 1241 }else { 1242supported = true; 1243 } 1244 }else { 1245supported = false; 1246 } 1247break ; 1248case GGML_OP_SSM_SCAN : 1249supported = op -> type == GGML_TYPE_F32 && ggml_is_contiguous (op )&& op -> src [0 ]&& 1250op -> src [0 ]-> type == GGML_TYPE_F32 && ggml_is_contiguous (op -> src [0 ])&& op -> src [1 ]&& 1251op -> src [1 ]-> type == GGML_TYPE_F32 && op -> src [2 ]&& op -> src [2 ]-> type == GGML_TYPE_F32 && 1252ggml_is_contiguous (op -> src [2 ])&& op -> src [3 ]&& op -> src [3 ]-> type == GGML_TYPE_F32 && 1253ggml_is_contiguous (op -> src [3 ])&& op -> src [4 ]&& op -> src [4 ]-> type == GGML_TYPE_F32 && 1254op -> src [5 ]&& op -> src [5 ]-> type == GGML_TYPE_F32 && op -> src [6 ]&& 1255op -> src [6 ]-> type == GGML_TYPE_I32 && ggml_is_contiguous (op -> src [6 ])&& 1256op -> src [1 ]-> nb [0 ]== sizeof (float )&& op -> src [4 ]-> nb [0 ]== sizeof (float )&& 1257op -> src [5 ]-> nb [0 ]== sizeof (float )&& 1258op -> src [1 ]-> nb [1 ]== (size_t )op -> src [1 ]-> ne [0 ]* sizeof (float )&& 1259op -> src [4 ]-> nb [1 ]== (size_t )op -> src [4 ]-> ne [0 ]* sizeof (float )&& 1260op -> src [5 ]-> nb [1 ]== (size_t )op -> src [5 ]-> ne [0 ]* sizeof (float )&& 1261op -> src [0 ]-> ne [0 ]== op -> src [4 ]-> ne [0 ]&& op -> src [0 ]-> ne [1 ]== op -> src [1 ]-> ne [0 ]&& 1262op -> src [0 ]-> ne [2 ]== op -> src [1 ]-> ne [1 ]&& op -> src [1 ]-> ne [2 ]== op -> src [2 ]-> ne [1 ]&& 1263op -> src [1 ]-> ne [3 ]== op -> src [2 ]-> ne [2 ]&& op -> src [4 ]-> ne [2 ]== op -> src [1 ]-> ne [2 ]&& 1264op -> src [4 ]-> ne [3 ]== op -> src [1 ]-> ne [3 ]&& ggml_are_same_shape (op -> src [4 ],op -> src [5 ])&& 1265op -> src [6 ]-> ne [0 ]== op -> src [1 ]-> ne [3 ]&& op -> src [3 ]-> ne [1 ]== op -> src [1 ]-> ne [1 ]&& 1266 (op -> src [3 ]-> ne [0 ]== 1 || op -> src [3 ]-> ne [0 ]== op -> src [0 ]-> ne [0 ])&& 1267 (op -> src [1 ]-> ne [1 ] %op -> src [4 ]-> ne [1 ]== 0 ); 1268break ; 1269case GGML_OP_FLASH_ATTN_EXT : 1270if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && op -> src [1 ]&& 1271 (op -> src [1 ]-> type == GGML_TYPE_F32 || op -> src [1 ]-> type == GGML_TYPE_F16 )&& op -> src [2 ]&& 1272 (op -> src [2 ]-> type == GGML_TYPE_F32 || op -> src [2 ]-> type == GGML_TYPE_F16 )&& op -> src [4 ]== nullptr && 1273ggml_is_contiguous_rows (op )&& ggml_is_contiguous_rows (op -> src [0 ])) { 1274float max_bias = 0.0f ; 1275float logit_softcap = 0.0f ; 1276memcpy (& max_bias , (const float * )op -> op_params + 1 ,sizeof (max_bias )); 1277memcpy (& logit_softcap , (const float * )op -> op_params + 2 ,sizeof (logit_softcap )); 1278 1279const ggml_prec prec = ggml_flash_attn_ext_get_prec (op ); 1280 1281// Mask must be F16 or F32 if present 1282bool mask_ok = (op -> src [3 ]== nullptr )|| (op -> src [3 ]-> type == GGML_TYPE_F32 )|| 1283 (op -> src [3 ]-> type == GGML_TYPE_F16 ); 1284 1285// GQA: n_head_q must be a multiple of n_head_kv 1286const int64_t nhq = op -> src [0 ]-> ne [2 ]; 1287const int64_t nhk = op -> src [1 ]-> ne [2 ]; 1288 1289// K/V row stride must match element size 1290const size_t k_elem = op -> src [1 ]-> type == GGML_TYPE_F16 ?2 :4 ; 1291const size_t v_elem = op -> src [2 ]-> type == GGML_TYPE_F16 ?2 :4 ; 1292 1293// Only support matrix engine path (F16 K/V, dk%32==0); 1294// mask scalar F32 fallback to get baseline perf readings 1295const bool me_eligible = op -> src [1 ]-> type == GGML_TYPE_F16 && op -> src [2 ]-> type == GGML_TYPE_F16 && 1296 (op -> src [0 ]-> ne [0 ] %32 )== 0 ; 1297 1298supported = me_eligible && mask_ok && (prec == GGML_PREC_F32 || prec == GGML_PREC_DEFAULT )&& 1299max_bias == 0.0f && logit_softcap == 0.0f && op -> src [0 ]-> nb [0 ]== sizeof (float )&& 1300op -> src [1 ]-> nb [0 ]== k_elem && op -> src [2 ]-> nb [0 ]== v_elem && op -> nb [0 ]== sizeof (float )&& 1301op -> src [0 ]-> ne [0 ]== op -> src [1 ]-> ne [0 ]&& // dk matches 1302op -> src [2 ]-> ne [0 ]== op -> ne [0 ]&& // dv matches 1303op -> src [2 ]-> ne [0 ] <=512 && // dv limit 1304op -> src [0 ]-> ne [0 ] <=512 && // dk limit 1305nhq %nhk == 0 && // GQA ratio is integer 1306op -> src [0 ]-> ne [1 ]== op -> ne [2 ]&& op -> src [0 ]-> ne [2 ]== op -> ne [1 ]&& 1307op -> src [0 ]-> ne [3 ]== op -> ne [3 ]&& op -> src [1 ]-> ne [1 ]== op -> src [2 ]-> ne [1 ]&& 1308op -> src [1 ]-> ne [2 ]== op -> src [2 ]-> ne [2 ]&& op -> src [1 ]-> ne [3 ]== op -> src [2 ]-> ne [3 ]&& 1309op -> src [0 ]-> ne [3 ]== op -> src [1 ]-> ne [3 ]; 1310 }else { 1311supported = false; 1312 } 1313break ; 1314case GGML_OP_GET_ROWS : 1315// Support F32/F16/Q4_0/Q8_0/Q4_K data with I32 indices -> F32 output 1316if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& 1317 (op -> src [0 ]-> type == GGML_TYPE_F32 || op -> src [0 ]-> type == GGML_TYPE_F16 || 1318op -> src [0 ]-> type == GGML_TYPE_Q4_0 || op -> src [0 ]-> type == GGML_TYPE_Q8_0 || 1319op -> src [0 ]-> type == GGML_TYPE_Q4_K )&& 1320op -> src [1 ]&& op -> src [1 ]-> type == GGML_TYPE_I32 && ggml_is_contiguous (op )&& 1321ggml_is_contiguous (op -> src [0 ])&& ggml_is_contiguous (op -> src [1 ])) { 1322// Validate dimension constraints from ggml implementation 1323supported = (op -> src [0 ]-> ne [2 ]== op -> src [1 ]-> ne [1 ])&& (op -> src [1 ]-> ne [3 ]== 1 ); 1324 }else { 1325supported = false; 1326 } 1327break ; 1328case GGML_OP_CONT : 1329// Support F32->F32 and F16->F16 CONT operations (rearrange non-contiguous to contiguous) 1330if ((op -> type == GGML_TYPE_F32 || op -> type == GGML_TYPE_F16 )&& op -> src [0 ]&& 1331op -> src [0 ]-> type == op -> type && ggml_is_contiguous (op )) { 1332// Defensive check: ensure dst and src0 are not aliased (separate buffers) 1333// While GGML design currently guarantees this, check for future robustness 1334if (op -> data && op -> src [0 ]-> data && op -> data == op -> src [0 ]-> data ) { 1335GGML_LOG_WARN ("ET: CONT operation detected aliased tensors (dst == src0), unsupported" ); 1336supported = false; 1337 }else { 1338supported = true; 1339 } 1340 }else { 1341supported = false; 1342 } 1343break ; 1344case GGML_OP_CPY : 1345// CPY copies src[0] data into dst layout (same as CONT for same-type) 1346// Special path: zero-element tensors (scalars) are accepted as no-ops 1347if (op -> src [0 ]) { 1348const int64_t nelements = op -> ne [0 ]* op -> ne [1 ]* op -> ne [2 ]* op -> ne [3 ]; 1349if (nelements == 0 ) { 1350// Zero-element / scalar no-op case - always supported 1351supported = true; 1352 }else if ((op -> type == GGML_TYPE_F32 || op -> type == GGML_TYPE_F16 )&& op -> src [0 ]-> type == op -> type && 1353ggml_is_contiguous (op )) { 1354// Same-type with contiguous dst - reuse CONT kernel 1355if (op -> data && op -> src [0 ]-> data && op -> data == op -> src [0 ]-> data ) { 1356GGML_LOG_WARN ("ET: CPY operation detected aliased tensors, unsupported" ); 1357supported = false; 1358 }else { 1359supported = true; 1360 } 1361 }else if (op -> type == GGML_TYPE_F16 && op -> src [0 ]-> type == GGML_TYPE_F32 && ggml_is_contiguous (op )) { 1362// F32 -> F16 conversion copy 1363supported = true; 1364 }else { 1365supported = false; 1366 } 1367 }else { 1368supported = false; 1369 } 1370break ; 1371case GGML_OP_CONCAT : 1372if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && op -> src [1 ]&& 1373op -> src [1 ]-> type == GGML_TYPE_F32 && ggml_is_contiguous (op )) { 1374const int32_t dim = ((const int32_t * )op -> op_params )[0 ]; 1375if (dim == 0 && op -> src [0 ]-> ne [0 ] %16 == 0 && op -> src [1 ]-> ne [0 ] %16 == 0 && 1376ggml_is_contiguous (op -> src [0 ])&& ggml_is_contiguous (op -> src [1 ])) { 1377// Fast dim==0 path: both source row segments are cacheline-aligned 1378// and contiguous, so the kernel can use vector row copies. 1379supported = true; 1380 }else if (dim == 0 && ((op -> src [0 ]-> nb [0 ] %sizeof (float )== 0 )|| op -> src [0 ]-> ne [0 ]== 1 )&& 1381 ((op -> src [1 ]-> nb [0 ] %sizeof (float )== 0 )|| op -> src [1 ]-> ne [0 ]== 1 )) { 1382// Slow dim==0 path: scalar, stride-aware copies for non-contiguous 1383// or non-aligned source row segments. Destination remains contiguous. 1384supported = true; 1385 }else if (op -> ne [0 ] %16 == 0 && op -> src [0 ]-> ne [0 ] %16 == 0 && op -> src [1 ]-> ne [0 ] %16 == 0 && 1386ggml_is_contiguous (op -> src [0 ])&& ggml_is_contiguous (op -> src [1 ])) { 1387// Dim >= 1 path: full aligned row copies from one source or the other. 1388supported = true; 1389 } 1390 } 1391break ; 1392case GGML_OP_SSM_CONV : 1393supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && op -> src [1 ]&& 1394op -> src [1 ]-> type == GGML_TYPE_F32 && op -> src [0 ]-> nb [0 ]== sizeof (float )&& 1395op -> src [1 ]-> nb [0 ]== sizeof (float )&& op -> src [0 ]-> nb [1 ]== op -> src [0 ]-> ne [0 ]* sizeof (float )&& 1396op -> src [1 ]-> nb [1 ]== op -> src [1 ]-> ne [0 ]* sizeof (float )&& ggml_is_contiguous (op )&& 1397op -> src [1 ]-> ne [1 ]== op -> src [0 ]-> ne [1 ]&& op -> ne [0 ]== op -> src [0 ]-> ne [1 ]&& 1398op -> ne [1 ]== op -> src [0 ]-> ne [0 ]- op -> src [1 ]-> ne [0 ]+ 1 && op -> ne [2 ]== op -> src [0 ]-> ne [2 ]; 1399break ; 1400case GGML_OP_PAD : 1401// F32 zero-pad only, no dim0 padding, dst contiguous 1402// ne[0] must be CL-aligned (% 16 == 0) or evenly divide a CL (16 % ne[0] == 0) 1403if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 1404ggml_is_contiguous (op )&& (op -> ne [0 ] %16 == 0 || 16 %op -> ne [0 ]== 0 )&& 1405op -> src [0 ]-> nb [0 ]== sizeof (float )) { 1406const int32_t lp0 = ((const int32_t * )op -> op_params )[0 ]; 1407const int32_t rp0 = ((const int32_t * )op -> op_params )[1 ]; 1408const bool circular = (bool ) ((const int32_t * )op -> op_params )[8 ]; 1409if (lp0 == 0 && rp0 == 0 && !circular ) { 1410supported = true; 1411 }else { 1412supported = false; 1413 } 1414 }else { 1415supported = false; 1416 } 1417break ; 1418case GGML_OP_REPEAT : 1419// Two acceptable shapes: 1420// 1. No-op REPEAT (src and dst have identical shape): dispatched 1421// to cont_f32, which handles arbitrary contiguous sizes. 1422// 2. Real REPEAT via repeat_f32 kernel: dst ne[0] cacheline-aligned, 1423// src0 ne[0] cacheline-aligned or 1, dst.ne[i] % src0.ne[i] == 0. 1424if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 1425ggml_is_contiguous (op )&& ggml_is_contiguous (op -> src [0 ])&& ggml_are_same_shape (op -> src [0 ],op )) { 1426supported = true; 1427 }else if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 1428 (op -> src [0 ]-> ne [0 ]== 1 || op -> src [0 ]-> ne [0 ] %16 == 0 )&& op -> ne [0 ] %16 == 0 && 1429ggml_is_contiguous (op )&& ggml_is_contiguous (op -> src [0 ])&& op -> ne [0 ] %op -> src [0 ]-> ne [0 ]== 0 && 1430op -> ne [1 ] %op -> src [0 ]-> ne [1 ]== 0 && op -> ne [2 ] %op -> src [0 ]-> ne [2 ]== 0 && 1431op -> ne [3 ] %op -> src [0 ]-> ne [3 ]== 0 ) { 1432supported = true; 1433 }else { 1434supported = false; 1435 } 1436break ; 1437case GGML_OP_FILL : 1438// F32 contiguous, ne[0] cacheline-aligned for SIMD fill 1439supported = op -> type == GGML_TYPE_F32 && ggml_is_contiguous (op )&& op -> ne [0 ] %16 == 0 ; 1440break ; 1441case GGML_OP_DIAG : 1442// F32 contiguous dst, src0 is 1D vector [N,1,...], dst is [N,N,...] 1443// ne[0] must be cacheline-aligned for SIMD zeroing 1444supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 1445op -> ne [0 ] %16 == 0 && op -> ne [0 ]== op -> ne [1 ]&& op -> src [0 ]-> ne [0 ]== op -> ne [0 ]&& 1446op -> src [0 ]-> ne [1 ]== 1 && ggml_is_contiguous (op )&& ggml_is_contiguous (op -> src [0 ]); 1447break ; 1448case GGML_OP_TRI : 1449// F32 contiguous, same shape in/out 1450// Kernel handles arbitrary ne[0] with aligned fast path + scalar fallback 1451supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && 1452ggml_is_contiguous (op )&& ggml_is_contiguous (op -> src [0 ]); 1453break ; 1454case GGML_OP_SOLVE_TRI : 1455// F32 contiguous, A square, shapes compatible 1456// Only lower-triangular left-side non-unit variant 1457// Require k % 16 == 0 for cache-line-safe column parallelism 1458supported = op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && op -> src [1 ]&& 1459op -> src [1 ]-> type == GGML_TYPE_F32 && op -> src [0 ]-> ne [0 ]== op -> src [0 ]-> ne [1 ]&& 1460op -> src [0 ]-> ne [1 ]== op -> src [1 ]-> ne [1 ]&& op -> src [1 ]-> ne [0 ] %16 == 0 && 1461ggml_is_contiguous (op )&& ggml_is_contiguous (op -> src [0 ])&& ggml_is_contiguous (op -> src [1 ]); 1462break ; 1463case GGML_OP_SET : 1464// Minimal useful support: inplace F32 SET of a contiguous src1 view into 1465// a contiguous dst/base tensor using explicit destination view strides. 1466if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && op -> src [1 ]&& 1467op -> src [1 ]-> type == GGML_TYPE_F32 && ggml_is_contiguous (op )&& ggml_is_contiguous (op -> src [0 ])&& 1468ggml_is_contiguous (op -> src [1 ])&& ggml_are_same_shape (op ,op -> src [0 ])&& op -> src [1 ]-> ne [0 ] %16 == 0 ) { 1469const bool inplace = (bool ) ((const int32_t * )op -> op_params )[4 ]; 1470const size_t nb1 = ((const int32_t * )op -> op_params )[0 ]; 1471const size_t nb2 = ((const int32_t * )op -> op_params )[1 ]; 1472const size_t nb3 = ((const int32_t * )op -> op_params )[2 ]; 1473const size_t offset = ((const int32_t * )op -> op_params )[3 ]; 1474const size_t nb0 = ggml_element_size (op ); 1475const size_t im0 = op -> src [1 ]-> ne [0 ]== 0 ?0 :op -> src [1 ]-> ne [0 ]- 1 ; 1476const size_t im1 = op -> src [1 ]-> ne [1 ]== 0 ?0 :op -> src [1 ]-> ne [1 ]- 1 ; 1477const size_t im2 = op -> src [1 ]-> ne [2 ]== 0 ?0 :op -> src [1 ]-> ne [2 ]- 1 ; 1478const size_t im3 = op -> src [1 ]-> ne [3 ]== 0 ?0 :op -> src [1 ]-> ne [3 ]- 1 ; 1479 1480const bool view_bounds_ok = offset + im0 * nb0 + im1 * nb1 + im2 * nb2 + im3 * nb3 <=ggml_nbytes (op ); 1481 1482const bool cacheline_aligned = 1483 (nb1 %64 == 0 )&& (nb2 %64 == 0 )&& (nb3 %64 == 0 )&& (offset %64 == 0 ); 1484 1485supported = inplace && view_bounds_ok && cacheline_aligned ; 1486 } 1487break ; 1488case GGML_OP_RWKV_WKV6 : 1489// F32 contiguous, head_size must be multiple of 8 for vectorization 1490// 6 sources: k, v, r, tf, td, state 1491if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && op -> src [1 ]&& 1492op -> src [1 ]-> type == GGML_TYPE_F32 && op -> src [2 ]&& op -> src [2 ]-> type == GGML_TYPE_F32 && op -> src [3 ]&& 1493op -> src [3 ]-> type == GGML_TYPE_F32 && op -> src [4 ]&& op -> src [4 ]-> type == GGML_TYPE_F32 && op -> src [5 ]&& 1494op -> src [5 ]-> type == GGML_TYPE_F32 && op -> src [0 ]-> ne [0 ] %8 == 0 && // head_size multiple of 8 1495ggml_is_contiguous (op -> src [0 ])&& ggml_is_contiguous (op -> src [1 ])&& ggml_is_contiguous (op -> src [2 ])&& 1496ggml_is_contiguous (op -> src [3 ])&& ggml_is_contiguous (op -> src [4 ])&& ggml_is_contiguous (op -> src [5 ])) { 1497supported = true; 1498 }else { 1499supported = false; 1500 } 1501break ; 1502case GGML_OP_RWKV_WKV7 : 1503// F32 contiguous, head_size must be multiple of 8 for vectorization 1504if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && op -> src [1 ]&& 1505op -> src [1 ]-> type == GGML_TYPE_F32 && op -> src [2 ]&& op -> src [2 ]-> type == GGML_TYPE_F32 && op -> src [3 ]&& 1506op -> src [3 ]-> type == GGML_TYPE_F32 && op -> src [4 ]&& op -> src [4 ]-> type == GGML_TYPE_F32 && op -> src [5 ]&& 1507op -> src [5 ]-> type == GGML_TYPE_F32 && op -> src [6 ]&& op -> src [6 ]-> type == GGML_TYPE_F32 && 1508op -> src [2 ]-> ne [0 ] %8 == 0 && // head_size multiple of 8 1509ggml_is_contiguous (op -> src [0 ])&& ggml_is_contiguous (op -> src [1 ])&& ggml_is_contiguous (op -> src [2 ])&& 1510ggml_is_contiguous (op -> src [3 ])&& ggml_is_contiguous (op -> src [4 ])&& ggml_is_contiguous (op -> src [5 ])&& 1511ggml_is_contiguous (op -> src [6 ])) { 1512supported = true; 1513 }else { 1514supported = false; 1515 } 1516break ; 1517case GGML_OP_GATED_DELTA_NET : 1518// F32, S_v must be multiple of 8 for vectorization 1519// q, k, v may be row-contiguous with strided higher dimensions. 1520// g, beta, state stay contiguous. 1521if (op -> type == GGML_TYPE_F32 && op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && // q 1522op -> src [1 ]&& op -> src [1 ]-> type == GGML_TYPE_F32 && // k 1523op -> src [2 ]&& op -> src [2 ]-> type == GGML_TYPE_F32 && // v 1524op -> src [3 ]&& op -> src [3 ]-> type == GGML_TYPE_F32 && // g 1525op -> src [4 ]&& op -> src [4 ]-> type == GGML_TYPE_F32 && // beta 1526op -> src [5 ]&& op -> src [5 ]-> type == GGML_TYPE_F32 && // state 1527op -> src [2 ]-> ne [0 ] %8 == 0 && // S_v multiple of 8 1528 (op -> src [3 ]-> ne [0 ]== 1 || op -> src [3 ]-> ne [0 ]== op -> src [2 ]-> ne [0 ])&& // g is scalar or per-element 1529op -> src [4 ]-> ne [0 ]== 1 && // beta is scalar per position 1530et_ggml_is_row_contiguous (op -> src [0 ])&& et_ggml_is_row_contiguous (op -> src [1 ])&& 1531et_ggml_is_row_contiguous (op -> src [2 ])&& ggml_is_contiguous (op -> src [3 ])&& 1532ggml_is_contiguous (op -> src [4 ])&& ggml_is_contiguous (op -> src [5 ])) { 1533supported = true; 1534 }else { 1535supported = false; 1536 } 1537break ; 1538case GGML_OP_VIEW : 1539case GGML_OP_PERMUTE : 1540case GGML_OP_TRANSPOSE : 1541case GGML_OP_RESHAPE : 1542// Metadata-only no-ops, accept any type 1543supported = true; 1544break ; 1545case GGML_OP_SET_ROWS : 1546// Support F32 data with I64 indices -> F16/F32 output (scatter operation) 1547if (op -> src [0 ]&& op -> src [0 ]-> type == GGML_TYPE_F32 && op -> src [1 ]&& op -> src [1 ]-> type == GGML_TYPE_I64 && 1548 (op -> type == GGML_TYPE_F32 || op -> type == GGML_TYPE_F16 )&& ggml_is_contiguous_rows (op )&& 1549ggml_is_contiguous_rows (op -> src [0 ])&& ggml_is_contiguous (op -> src [1 ])) { 1550// Validate dimension constraints from ggml implementation 1551supported = (op -> ne [0 ]== op -> src [0 ]-> ne [0 ])&& // same number of columns 1552 (op -> ne [2 ]== op -> src [0 ]-> ne [2 ])&& // same batch size 1553 (op -> ne [3 ]== op -> src [0 ]-> ne [3 ])&& // same outer dimension 1554 (op -> src [0 ]-> ne [1 ]== op -> src [1 ]-> ne [0 ])&& // src rows = index count 1555 (op -> src [0 ]-> ne [2 ] %op -> src [1 ]-> ne [1 ]== 0 )&& // batch constraint 1556 (op -> src [0 ]-> ne [3 ] %op -> src [1 ]-> ne [2 ]== 0 )&& // outer constraint 1557 (op -> src [1 ]-> ne [3 ]== 1 );// indices tensor constraint 1558 }else { 1559supported = false; 1560 } 1561break ; 1562case GGML_OP_NONE : 1563// Always support NONE operations - they represent leaf nodes (parameters, inputs, constants) 1564// No computation needed, just memory management 1565supported = true; 1566break ; 1567default : 1568supported = false; 1569break ; 1570 } 1571// if(!supported) { 1572// ggml_et_dump_operator_metadata(op); 1573// } 1574return supported ; 1575} 1576 1577static bool ggml_backend_et_device_supports_buft (ggml_backend_dev_t dev ,ggml_backend_buffer_type_t buft ) { 1578GGML_UNUSED (dev ); 1579return buft -> iface .get_name == ggml_backend_et_buffer_type_get_name ; 1580} 1581 1582static bool ggml_backend_et_device_offload_op (ggml_backend_dev_t dev ,const ggml_tensor * op ) { 1583// GET_ROWS (embedding lookup) uses a large weight (tok_embd) that lives on CPU (dev_input). 1584// The scheduler has no mechanism to cache cross-backend weight copies - it re-copies split 1585// inputs every graph_compute call. For GET_ROWS this means copying the entire embedding table 1586// (e.g. 266MB for Llama 3.1 1B) from host to device on every token, just to look up a few rows. 1587// Keep GET_ROWS on CPU and let the scheduler copy only the small result to the device. 1588// The other backends either only offload if the tensor lives on device or is large enough to 1589// justify the copy cost. 1590if (op -> op == GGML_OP_GET_ROWS ) { 1591return false; 1592 } 1593return true; 1594 1595GGML_UNUSED (dev ); 1596} 1597 1598static const struct ggml_backend_i ggml_backend_et_i = { 1599/* .get_name = */ ggml_backend_et_get_name , 1600/* .free = */ ggml_backend_et_free , 1601/* .set_tensor_async = */ ggml_backend_et_set_tensor_async , 1602/* .get_tensor_async = */ ggml_backend_et_get_tensor_async , 1603/* .set_tensor_2d_async = */ NULL , 1604/* .get_tensor_2d_async = */ NULL , 1605/* .cpy_tensor_async = */ NULL , 1606/* .synchronize = */ ggml_backend_et_synchronize , 1607/* .graph_plan_create = */ NULL , 1608/* .graph_plan_free = */ NULL , 1609/* .graph_plan_update = */ NULL , 1610/* .graph_plan_compute = */ NULL , 1611/* .graph_compute = */ ggml_backend_et_graph_compute , 1612/* .event_record = */ NULL , 1613/* .event_wait = */ NULL , 1614/* .graph_optimize = */ NULL , 1615}; 1616 1617static const char * ggml_backend_et_device_get_name (ggml_backend_dev_t dev ) { 1618ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )dev -> context ; 1619return dev_ctx -> name .c_str (); 1620} 1621 1622static const char * ggml_backend_et_device_get_description (ggml_backend_dev_t dev ) { 1623ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )dev -> context ; 1624return dev_ctx -> desc .c_str (); 1625} 1626 1627static void ggml_backend_et_device_get_memory (ggml_backend_dev_t dev ,size_t * free ,size_t * total ) { 1628ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )dev -> context ; 1629// Currently getFreeMemory is not available on a runtime without server. 1630// For now, report total memory as free. 1631* free = dev_ctx -> total_mem ; 1632* total = dev_ctx -> total_mem ; 1633} 1634 1635static enum ggml_backend_dev_type ggml_backend_et_device_get_type (ggml_backend_dev_t dev ) { 1636GGML_UNUSED (dev ); 1637return GGML_BACKEND_DEVICE_TYPE_GPU ; 1638} 1639 1640static void ggml_backend_et_device_get_props (ggml_backend_dev_t dev ,struct ggml_backend_dev_props * props ) { 1641GGML_UNUSED (dev ); 1642props -> name = ggml_backend_et_device_get_name (dev ); 1643props -> description = ggml_backend_et_device_get_description (dev ); 1644props -> type = ggml_backend_et_device_get_type (dev ); 1645ggml_backend_et_device_get_memory (dev ,& props -> memory_free ,& props -> memory_total ); 1646props -> device_id = NULL ;// No PCI device ID available 1647props -> caps = { 1648/* .async = */ true, 1649/* .host_buffer = */ false, 1650/* .buffer_from_host_ptr = */ false, 1651/* .events = */ false, 1652/* .mmap_support = */ true, 1653 }; 1654} 1655 1656static ggml_backend_t ggml_backend_et_device_init_backend (ggml_backend_dev_t dev ,const char * params ) { 1657GGML_UNUSED (params ); 1658ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )dev -> context ; 1659return ggml_backend_et_init (dev_ctx -> devidx ); 1660} 1661 1662static ggml_backend_buffer_type_t ggml_backend_et_device_get_buffer_type (ggml_backend_dev_t dev ) { 1663ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )dev -> context ; 1664return dev_ctx -> buftype ; 1665} 1666 1667static ggml_backend_buffer_type_t ggml_backend_et_device_get_host_buffer_type (ggml_backend_dev_t dev ) { 1668GGML_UNUSED (dev ); 1669return ggml_backend_cpu_buffer_type (); 1670} 1671 1672static const struct ggml_backend_device_i ggml_backend_et_device_i = { 1673/* .get_name = */ ggml_backend_et_device_get_name , 1674/* .get_description = */ ggml_backend_et_device_get_description , 1675/* .get_memory = */ ggml_backend_et_device_get_memory , 1676/* .get_type = */ ggml_backend_et_device_get_type , 1677/* .get_props = */ ggml_backend_et_device_get_props , 1678/* .init_backend = */ ggml_backend_et_device_init_backend , 1679/* .get_buffer_type = */ ggml_backend_et_device_get_buffer_type , 1680/* .get_host_buffer_type = */ ggml_backend_et_device_get_host_buffer_type , 1681/* .buffer_from_host_ptr = */ NULL , 1682/* .supports_op = */ ggml_backend_et_device_supports_op , 1683/* .supports_buft = */ ggml_backend_et_device_supports_buft , 1684/* .offload_op = */ ggml_backend_et_device_offload_op , 1685/* .event_new = */ NULL , 1686/* .event_free = */ NULL , 1687/* .event_synchronize = */ NULL , 1688}; 1689 1690/* 1691Backend Registry. 1692*/ 1693 1694static const char * ggml_backend_et_reg_get_name (ggml_backend_reg_t reg ) { 1695GGML_UNUSED (reg ); 1696return GGML_ET_NAME ; 1697} 1698 1699static size_t ggml_backend_et_reg_get_device_count (ggml_backend_reg_t reg ) { 1700ggml_backend_et_reg_ctx * ctx = (ggml_backend_et_reg_ctx * )reg -> context ; 1701return ctx -> devices .size (); 1702} 1703 1704static ggml_backend_dev_t ggml_backend_et_reg_get_device (ggml_backend_reg_t reg ,size_t devidx ) { 1705ggml_backend_et_reg_ctx * ctx = (ggml_backend_et_reg_ctx * )reg -> context ; 1706if (devidx >=ctx -> devices .size ()) { 1707return nullptr ; 1708 } 1709return ctx -> devices [devidx ]; 1710} 1711 1712static void * ggml_backend_et_get_proc_address (ggml_backend_reg_t reg ,const char * name ) { 1713GGML_UNUSED (reg ); 1714GGML_UNUSED (name ); 1715return nullptr ; 1716} 1717 1718static const struct ggml_backend_reg_i ggml_backend_et_reg_i = { 1719/* .get_name = */ ggml_backend_et_reg_get_name , 1720/* .get_device_count = */ ggml_backend_et_reg_get_device_count , 1721/* .get_device = */ ggml_backend_et_reg_get_device , 1722/* .get_proc_address = */ ggml_backend_et_get_proc_address , 1723}; 1724 1725ggml_backend_reg_t ggml_backend_et_reg (void ) { 1726static ggml_backend_reg_t _reg = []()-> ggml_backend_reg_t { 1727ggml_backend_et_reg_ctx * ctx = new ggml_backend_et_reg_ctx ; 1728 1729if (!ggml_et_driver_init ()) { 1730return nullptr ; 1731 } 1732 1733ggml_backend_reg_t r = new ggml_backend_reg { 1734/* .api_version = */ GGML_BACKEND_API_VERSION , 1735/* .iface = */ ggml_backend_et_reg_i , 1736/* .context = */ nullptr ,// Set later 1737 }; 1738 1739 std::vector < rt::DeviceId > rtids = ggml_et_runtime ()-> getDevices (); 1740 1741for (int i = 0 ;i < ggml_et_devicelayer ()-> getDevicesCount ();i ++ ) { 1742ggml_backend_dev_t dev = new ggml_backend_device { 1743/* .iface = */ ggml_backend_et_device_i , 1744/* .reg = */ r , 1745/* .context = */ nullptr // Set later 1746 }; 1747 1748 rt::DeviceId rtid = rtids [i ]; 1749 rt::DeviceProperties prop = ggml_et_runtime ()-> getDeviceProperties (rtid ); 1750 1751// Create device context. 1752ggml_backend_et_device_context * dev_ctx = new ggml_backend_et_device_context ; 1753dev_ctx -> devidx = i ; 1754dev_ctx -> rtid = rtid ; 1755dev_ctx -> name = GGML_ET_NAME + std::to_string (i ); 1756dev_ctx -> desc = "ET device " + std::to_string (i ); 1757dev_ctx -> total_mem = static_cast < size_t > (prop .memorySize_ ); 1758 { 1759const char * env = getenv ("GGML_ET_UBERKERNEL" ); 1760dev_ctx -> uberkernel_enabled = env && env [0 ]!= '\0' && strcmp (env ,"0" )!= 0 ; 1761 } 1762// Add buffer type for device to device context. 1763ggml_backend_et_buffer_type_context * bufty_ctx = new ggml_backend_et_buffer_type_context ; 1764bufty_ctx -> devidx = i ; 1765bufty_ctx -> name = GGML_ET_NAME + std::to_string (i ); 1766dev_ctx -> buftype = new ggml_backend_buffer_type {/* .iface = */ ggml_backend_et_buffer_type_i , 1767/* .device = */ dev , 1768/* .context = */ bufty_ctx }; 1769 1770// Create default stream for ordered execution on this device 1771dev_ctx -> default_stream = ggml_et_runtime ()-> createStream (rtid ); 1772 1773dev_ctx -> trace_buffer = ggml_et_runtime ()-> mallocDevice (rtid ,ET_TRACE_BUFFER_SIZE ); 1774// Pre-size each slot's host buffers and device-side scratch so the 1775// first few graph_compute calls don't pay a malloc/grow penalty. 1776for (auto & slot :dev_ctx -> uberkernel .slots ) { 1777slot .insts .reserve (256 ); 1778slot .params_blob .reserve (1 <<20 ); 1779slot .device_insts_capacity = 256 * sizeof (ggml_et_uberkernel_inst ); 1780slot .device_params_capacity = 1 <<20 ; 1781slot .device_insts = ggml_et_runtime ()-> mallocDevice (rtid ,slot .device_insts_capacity ); 1782slot .device_params = ggml_et_runtime ()-> mallocDevice (rtid ,slot .device_params_capacity ); 1783if (slot .device_insts == nullptr ) { 1784slot .device_insts_capacity = 0 ; 1785 } 1786if (slot .device_params == nullptr ) { 1787slot .device_params_capacity = 0 ; 1788 } 1789 } 1790 1791dev -> context = dev_ctx ; 1792 1793ctx -> devices .push_back (dev ); 1794 } 1795 1796r -> context = ctx ; 1797return r ; 1798 }(); 1799 1800return _reg ; 1801} 1802 1803ggml_guid_t ggml_backend_et_guid (void ) { 1804static ggml_guid guid = {0x4b ,0xe0 ,0x72 ,0x88 ,0xc0 ,0xf6 ,0x29 ,0xb4 , 18050x79 ,0x9f ,0x70 ,0x68 ,0x71 ,0x0f ,0x6d ,0xc8 }; 1806return & guid ; 1807} 1808 1809ggml_backend_t ggml_backend_et_init (size_t devidx ) { 1810if (!ggml_et_driver_init ()) { 1811return nullptr ; 1812 } 1813 1814if (devidx >= (size_t )ggml_backend_et_get_device_count ()) { 1815return nullptr ; 1816 } 1817 1818ggml_backend_et_context * ctx = new ggml_backend_et_context ; 1819ctx -> devidx = (int )devidx ; 1820 1821ggml_backend_t backend = new ggml_backend { 1822/* .guid = */ ggml_backend_et_guid (), 1823/* .iface = */ ggml_backend_et_i , 1824/* .device = */ ggml_backend_et_reg_get_device (ggml_backend_et_reg (),devidx ), 1825/* .context = */ ctx , 1826 }; 1827 1828return backend ; 1829} 1830 1831bool ggml_backend_is_et (ggml_backend_t backend ) { 1832return backend != NULL && ggml_guid_matches (backend -> guid ,ggml_backend_et_guid ()); 1833} 1834 1835int ggml_backend_et_get_device_count (void ) { 1836return ggml_backend_et_reg_get_device_count (ggml_backend_et_reg ()); 1837} 1838 1839void ggml_backend_et_get_device_description (int devidx ,char * description ,size_t description_size ) { 1840if (devidx < 0 || devidx >=ggml_backend_et_get_device_count ()) { 1841snprintf (description ,description_size ,"ET Device %d (invalid)" ,devidx ); 1842return ; 1843 } 1844 1845ggml_backend_dev_t dev = ggml_backend_et_reg_get_device (ggml_backend_et_reg (),devidx ); 1846ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )dev -> context ; 1847snprintf (description ,description_size ,"%s" ,dev_ctx -> desc .c_str ()); 1848} 1849 1850void ggml_backend_et_get_device_memory (int devidx ,size_t * free ,size_t * total ) { 1851if (devidx < 0 || devidx >=ggml_backend_et_get_device_count ()) { 1852* free = 0 ; 1853* total = 0 ; 1854return ; 1855 } 1856 1857ggml_backend_dev_t dev = ggml_backend_et_reg_get_device (ggml_backend_et_reg (),devidx ); 1858ggml_backend_et_device_get_memory (dev ,free ,total ); 1859} 1860 1861ggml_backend_buffer_type_t ggml_backend_et_buffer_type (size_t dev_num ) { 1862if (dev_num >= (size_t )ggml_backend_et_get_device_count ()) { 1863return nullptr ; 1864 } 1865 1866ggml_backend_dev_t dev = ggml_backend_et_reg_get_device (ggml_backend_et_reg (),dev_num ); 1867ggml_backend_et_device_context * dev_ctx = (ggml_backend_et_device_context * )dev -> context ; 1868return dev_ctx -> buftype ; 1869} 1870 1871ggml_backend_buffer_type_t ggml_backend_et_host_buffer_type (void ) { 1872static ggml_backend_buffer_type host_buffer_type = { 1873/* .iface = */ ggml_backend_et_buffer_type_i , 1874/* .device = */ nullptr , 1875/* .context = */ nullptr , 1876 }; 1877return & host_buffer_type ; 1878} 1879 1880GGML_BACKEND_DL_IMPL (ggml_backend_et_reg )