char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
ad6c66839
char/aliceai-t5-moe
1#include "ggml-cuda.h" 2#include "ggml-impl.h" 3#include "ggml-backend-impl.h" 4 5#include "ggml-cuda/allreduce.cuh" 6#include "ggml-cuda/common.cuh" 7#include "ggml-cuda/acc.cuh" 8#include "ggml-cuda/add-id.cuh" 9#include "ggml-cuda/arange.cuh" 10#include "ggml-cuda/argmax.cuh" 11#include "ggml-cuda/argsort.cuh" 12#include "ggml-cuda/binbcast.cuh" 13#include "ggml-cuda/clamp.cuh" 14#include "ggml-cuda/col2im-1d.cuh" 15#include "ggml-cuda/concat.cuh" 16#include "ggml-cuda/conv-transpose-1d.cuh" 17#include "ggml-cuda/conv2d.cuh" 18#include "ggml-cuda/conv2d-dw.cuh" 19#include "ggml-cuda/conv2d-transpose.cuh" 20#include "ggml-cuda/convert.cuh" 21#include "ggml-cuda/count-equal.cuh" 22#include "ggml-cuda/cpy.cuh" 23#include "ggml-cuda/cross-entropy-loss.cuh" 24#include "ggml-cuda/cumsum.cuh" 25#include "ggml-cuda/diagmask.cuh" 26#include "ggml-cuda/diag.cuh" 27#include "ggml-cuda/fattn.cuh" 28#include "ggml-cuda/fwht.cuh" 29#include "ggml-cuda/getrows.cuh" 30#include "ggml-cuda/im2col.cuh" 31#include "ggml-cuda/mmf.cuh" 32#include "ggml-cuda/mmq.cuh" 33#include "ggml-cuda/mmvf.cuh" 34#include "ggml-cuda/mmvq.cuh" 35#include "ggml-cuda/moe-weighted-reduction.cuh" 36#include "ggml-cuda/norm.cuh" 37#include "ggml-cuda/opt-step-adamw.cuh" 38#include "ggml-cuda/opt-step-sgd.cuh" 39#include "ggml-cuda/out-prod.cuh" 40#include "ggml-cuda/pad.cuh" 41#include "ggml-cuda/pool2d.cuh" 42#include "ggml-cuda/pool1d.cuh" 43#include "ggml-cuda/quantize.cuh" 44#include "ggml-cuda/rope.cuh" 45#include "ggml-cuda/roll.cuh" 46#include "ggml-cuda/scale.cuh" 47#include "ggml-cuda/snake.cuh" 48#include "ggml-cuda/softcap.cuh" 49#include "ggml-cuda/softmax.cuh" 50#include "ggml-cuda/ssm-conv.cuh" 51#include "ggml-cuda/ssm-scan.cuh" 52#include "ggml-cuda/sum.cuh" 53#include "ggml-cuda/sumrows.cuh" 54#include "ggml-cuda/top-k.cuh" 55#include "ggml-cuda/mean.cuh" 56#include "ggml-cuda/tsembd.cuh" 57#include "ggml-cuda/topk-moe.cuh" 58#include "ggml-cuda/unary.cuh" 59#include "ggml-cuda/upscale.cuh" 60#include "ggml-cuda/wkv.cuh" 61#include "ggml-cuda/gla.cuh" 62#include "ggml-cuda/gated_delta_net.cuh" 63#include "ggml-cuda/dsv4-hc.cuh" 64#include "ggml-cuda/set.cuh" 65#include "ggml-cuda/set-rows.cuh" 66#include "ggml-cuda/pad_reflect_1d.cuh" 67#include "ggml-cuda/solve_tri.cuh" 68#include "ggml-cuda/tri.cuh" 69#include "ggml-cuda/cumsum.cuh" 70#include "ggml-cuda/fill.cuh" 71#include "ggml-cuda/lightning-indexer.cuh" 72#include "ggml.h" 73 74#include <algorithm> 75#include <array> 76#include <atomic> 77#include <charconv> 78#include <cinttypes> 79#include <condition_variable> 80#include <cstddef> 81#include <cstdint> 82#include <cfloat> 83#include <initializer_list> 84#include <limits> 85#include <map> 86#include <memory> 87#include <mutex> 88#include <cstdarg> 89#include <cstdio> 90#include <cstdlib> 91#include <string> 92#include <vector> 93 94static_assert(sizeof(half) == sizeof(ggml_fp16_t), "wrong fp16 size"); 95 96#define GGML_LOG_WARN_ONCE(str) \ 97 { static std::once_flag warn_flag; std::call_once(warn_flag, []() { GGML_LOG_WARN(str); }); } 98 99[[noreturn]] 100void ggml_cuda_error(const char * stmt, const char * func, const char * file, int line, const char * msg) { 101 int id = -1; // in case cudaGetDevice fails 102 (void)cudaGetDevice(&id); 103 104 GGML_LOG_ERROR(GGML_CUDA_NAME " error: %s\n", msg); 105 GGML_LOG_ERROR(" current device: %d, in function %s at %s:%d\n", id, func, file, line); 106 GGML_LOG_ERROR(" %s\n", stmt); 107 // abort with GGML_ABORT to get a stack trace 108 GGML_ABORT(GGML_CUDA_NAME " error"); 109} 110 111// map a (possibly virtual) device id to the physical CUDA device that backs it 112static int ggml_cuda_get_physical_device(int device) { 113 const ggml_cuda_device_info & info = ggml_cuda_info(); 114 GGML_ASSERT(device >= 0 && device < info.device_count); 115 return info.devices[device].physical_device; 116} 117 118// this is faster on Windows 119// probably because the Windows CUDA libraries forget to make this check before invoking the drivers 120void ggml_cuda_set_device(int device) { 121 // translate the (possibly virtual) device id to the physical CUDA device that backs it 122 const int physical_device = ggml_cuda_get_physical_device(device); 123 124 int current_device; 125 CUDA_CHECK(cudaGetDevice(¤t_device)); 126 127 if (physical_device == current_device) { 128 return; 129 } 130 131 CUDA_CHECK(cudaSetDevice(physical_device)); 132} 133 134int ggml_cuda_get_device() { 135 int id; 136 CUDA_CHECK(cudaGetDevice(&id)); 137 return id; 138} 139 140static cudaError_t ggml_cuda_device_malloc(void ** ptr, size_t size, int device) { 141 ggml_cuda_set_device(device); 142 cudaError_t err; 143 if (getenv("GGML_CUDA_ENABLE_UNIFIED_MEMORY") != nullptr) { 144 err = cudaMallocManaged(ptr, size); 145#if defined(GGML_USE_HIP) 146 if (err == hipSuccess) { 147 // hipMemAdviseSetCoarseGrain is an optional performance hint; 148 // ignore errors (e.g. hipErrorInvalidValue on some APU/iGPU configs). 149 (void)cudaMemAdvise(*ptr, size, hipMemAdviseSetCoarseGrain, device); 150 (void)hipGetLastError(); // clear any error 151 } 152 153 // fall back to cudaMalloc if not supported (e.g. on Windows) 154 if (err == hipErrorNotSupported) { 155 static bool warned_unsupported = false; 156 if (!warned_unsupported) { 157 GGML_LOG_WARN("hipMallocManaged unsupported, falling back to hipMalloc.\n"); 158 warned_unsupported = true; 159 } 160 161 err = cudaMalloc(ptr, size); 162 } 163#endif // defined(GGML_USE_HIP) 164 } else { 165 err = cudaMalloc(ptr, size); 166 } 167 return err; 168} 169 170#if defined(GGML_USE_HIP) 171static int ggml_cuda_parse_id(char devName[]) { 172 // A list of possible Target IDs can be found under the rocclr/clr repo in device.cpp 173 // these values are not stable so this is susceptible to breakage 174 // https://github.com/ROCm/clr/blob/amd-staging/rocclr/device/device.cpp 175 int archMajor = 0x0; 176 int archMinor = 0x0; 177 int archNum = GGML_CUDA_CC_OFFSET_AMD; 178 int archLen = strlen(devName); 179 char archName[archLen + 1]; 180 181 // strip leading 'gfx' while copying into our buffer 182 if (archLen > 3) { 183 strcpy(archName, &devName[3]); 184 archLen -= 3; 185 } 186 187 // trim trailing :xnack- or :sramecc- statuses 188 archLen = strcspn(archName, ":"); 189 archName[archLen] = '\0'; 190 191 // tease out the version information 192 if (archLen > 8) { 193 // versions labeled generic use '-' as delimiter 194 // strip the trailing "-generic" then iterate through what remains 195 if ((strstr(archName, "-generic"))) { 196 archName[archLen - 8] = '\0'; 197 char * pch; 198 if ((pch = strtok(archName, "-"))) { 199 archMajor = (int)strtoul(pch, 0, 16); 200 if ((pch = strtok(NULL, "-"))) { 201 archMinor = 0x10 * (int)strtoul(pch, 0, 16); 202 } 203 } 204 } 205 } else if (archLen >= 3) { 206 // last two digits should be the minor * 0x10 + stepping 207 archMinor = (int)strtoul(&archName[archLen - 2], 0, 16); 208 archName[archLen - 2] = '\0'; 209 210 // only the major version remains 211 archMajor = (int)strtoul(archName, 0, 16); 212 } 213 archNum += archMajor * 0x100; 214 archNum += archMinor; 215 216 return archNum; 217} 218#endif // defined(GGML_USE_HIP) 219 220static ggml_cuda_device_info ggml_cuda_init() { 221 ggml_cuda_device_info info = {}; 222 223 cudaError_t err = cudaGetDeviceCount(&info.physical_device_count); 224 if (err != cudaSuccess) { 225 GGML_LOG_ERROR("%s: failed to initialize " GGML_CUDA_NAME ": %s\n", __func__, cudaGetErrorString(err)); 226 return info; 227 } 228 229 GGML_ASSERT(info.physical_device_count <= GGML_CUDA_MAX_DEVICES); 230 231 // by default expose exactly the physical devices; GGML_CUDA_DEVICES can request a different 232 // number of (virtual) devices to emulate multi-GPU systems on a machine with fewer GPUs 233 info.device_count = info.physical_device_count; 234 235 const char * devices_env = getenv("GGML_CUDA_DEVICES"); 236 if (devices_env != nullptr && info.physical_device_count > 0) { 237 const int requested = atoi(devices_env); 238 if (requested > 0) { 239 info.device_count = requested; 240 } else { 241 GGML_LOG_WARN("%s: ignoring invalid GGML_CUDA_DEVICES=\"%s\"\n", __func__, devices_env); 242 } 243 } 244 245 if (info.device_count > GGML_CUDA_MAX_DEVICES) { 246 GGML_LOG_WARN("%s: requested %d devices, clamping to GGML_CUDA_MAX_DEVICES=%d\n", 247 __func__, info.device_count, GGML_CUDA_MAX_DEVICES); 248 info.device_count = GGML_CUDA_MAX_DEVICES; 249 } 250 251 // map each (virtual) device to a backing physical device (round-robin), assign each its index 252 // among the (virtual) devices sharing that physical GPU, and store the per-physical share count 253 int physical_share_count[GGML_CUDA_MAX_DEVICES] = {}; 254 GGML_ASSERT(info.device_count == 0 || info.physical_device_count > 0); 255 for (int id = 0; id < info.device_count; ++id) { 256 info.devices[id].physical_device = id % info.physical_device_count; 257 info.devices[id].virtual_index = physical_share_count[info.devices[id].physical_device]++; 258 } 259 260 int64_t total_vram = 0; 261 for (int id = 0; id < info.physical_device_count; ++id) { 262 cudaDeviceProp prop; 263 CUDA_CHECK(cudaGetDeviceProperties(&prop, id)); 264 total_vram += prop.totalGlobalMem; 265 } 266 GGML_LOG_INFO("%s: found %d " GGML_CUDA_NAME " devices (Total VRAM: %zu MiB):\n", 267 __func__, info.physical_device_count, (size_t)(total_vram / (1024 * 1024))); 268 if (info.device_count != info.physical_device_count) { 269 GGML_LOG_INFO("%s: emulating %d virtual device(s) on %d physical device(s) (GGML_CUDA_DEVICES)\n", 270 __func__, info.device_count, info.physical_device_count); 271 } 272 total_vram = 0; 273 274 std::vector<std::pair<int, std::string>> turing_devices_without_mma; 275 for (int id = 0; id < info.device_count; ++id) { 276 const int physical_id = info.devices[id].physical_device; 277 278 int device_vmm = 0; 279 280#if defined(GGML_USE_VMM) 281 CUdevice device; 282 CU_CHECK(cuDeviceGet(&device, physical_id)); 283 CU_CHECK(cuDeviceGetAttribute(&device_vmm, CU_DEVICE_ATTRIBUTE_VIRTUAL_MEMORY_MANAGEMENT_SUPPORTED, device)); 284 285 if (device_vmm) { 286 CUmemAllocationProp alloc_prop = {}; 287 alloc_prop.type = CU_MEM_ALLOCATION_TYPE_PINNED; 288 alloc_prop.location.type = CU_MEM_LOCATION_TYPE_DEVICE; 289 alloc_prop.location.id = physical_id; 290 CU_CHECK(cuMemGetAllocationGranularity(&info.devices[id].vmm_granularity, &alloc_prop, CU_MEM_ALLOC_GRANULARITY_RECOMMENDED)); 291 } 292#endif // defined(GGML_USE_VMM) 293 info.devices[id].vmm = !!device_vmm; 294 295 cudaDeviceProp prop; 296 CUDA_CHECK(cudaGetDeviceProperties(&prop, physical_id)); 297 298 // a virtual device owns only a share of its physical GPU's memory; report that share so the 299 // logged per-device VRAM sums to the physical total above. 300 GGML_ASSERT(physical_share_count[physical_id] > 0); 301 info.devices[id].physical_share_count = physical_share_count[physical_id]; 302 const size_t device_vram = prop.totalGlobalMem / info.devices[id].physical_share_count; 303 const size_t device_vram_mib = device_vram / (1024 * 1024); 304 305 info.default_tensor_split[id] = total_vram; 306 total_vram += device_vram; 307 info.devices[id].integrated = false; // Temporarily disabled due to issues with corrupted output (e.g. #15034) 308 info.devices[id].nsm = prop.multiProcessorCount; 309 info.devices[id].smpb = prop.sharedMemPerBlock; 310 info.devices[id].warp_size = prop.warpSize; 311 312#ifndef GGML_USE_MUSA 313 int supports_coop_launch = 0; 314 CUDA_CHECK(cudaDeviceGetAttribute(&supports_coop_launch, cudaDevAttrCooperativeLaunch, physical_id)); 315 info.devices[id].supports_cooperative_launch = !!supports_coop_launch; 316#else 317 info.devices[id].supports_cooperative_launch = false; 318#endif // !(GGML_USE_MUSA) 319 320#if defined(GGML_USE_HIP) 321 info.devices[id].smpbo = prop.sharedMemPerBlock; 322 323 info.devices[id].cc = ggml_cuda_parse_id(prop.gcnArchName); 324 if ((info.devices[id].cc & 0xff00) == 0x0) { 325 GGML_LOG_WARN("invalid architecture ID received for device %d %s: %s cc %d.%d\n", 326 id, prop.name, prop.gcnArchName, prop.major, prop.minor); 327 328 // Fallback to prop.major and prop.minor 329 if (prop.major > 0) { 330 info.devices[id].cc = GGML_CUDA_CC_OFFSET_AMD + prop.major * 0x100; 331 info.devices[id].cc += prop.minor * 0x10; 332 } 333 } 334 GGML_LOG_INFO(" Device %d: %s, %s (0x%x), VMM: %s, Wave Size: %d, VRAM: %zu MiB\n", 335 id, prop.name, prop.gcnArchName, info.devices[id].cc & 0xffff, 336 device_vmm ? "yes" : "no", prop.warpSize, 337 device_vram_mib); 338#elif defined(GGML_USE_MUSA) 339 // FIXME: Ensure compatibility with varying warp sizes across different MUSA archs. 340 info.devices[id].warp_size = 32; 341 info.devices[id].smpbo = prop.sharedMemPerBlockOptin; 342 info.devices[id].cc = GGML_CUDA_CC_OFFSET_MTHREADS + prop.major * 0x100; 343 info.devices[id].cc += prop.minor * 0x10; 344 GGML_LOG_INFO(" Device %d: %s, compute capability %d.%d, VMM: %s, VRAM: %zu MiB\n", 345 id, prop.name, prop.major, prop.minor, device_vmm ? "yes" : "no", 346 device_vram_mib); 347#else 348 info.devices[id].smpbo = prop.sharedMemPerBlockOptin; 349 info.devices[id].cc = 100*prop.major + 10*prop.minor; 350 GGML_LOG_INFO(" Device %d: %s, compute capability %d.%d, VMM: %s, VRAM: %zu MiB\n", 351 id, prop.name, prop.major, prop.minor, device_vmm ? "yes" : "no", 352 device_vram_mib); 353 std::string device_name(prop.name); 354 if (device_name == "NVIDIA GeForce MX450") { 355 turing_devices_without_mma.push_back({ id, device_name }); 356 } else if (device_name == "NVIDIA GeForce MX550") { 357 turing_devices_without_mma.push_back({ id, device_name }); 358 } else if (device_name.substr(0, 21) == "NVIDIA GeForce GTX 16") { 359 turing_devices_without_mma.push_back({ id, device_name }); 360 } 361 362 // Temporary performance fix: 363 // Setting device scheduling strategy for iGPUs with cc121 to "spinning" to avoid delays in cuda synchronize calls. 364 // TODO: Check for future drivers the default scheduling strategy and 365 // remove this call again when cudaDeviceScheduleSpin is default. 366 if (prop.major == 12 && prop.minor == 1) { 367 CUDA_CHECK(cudaSetDevice(physical_id)); 368 CUDA_CHECK(cudaSetDeviceFlags(cudaDeviceScheduleSpin)); 369 } 370 371#endif // defined(GGML_USE_HIP) 372 } 373 374 if (ggml_cuda_highest_compiled_arch(GGML_CUDA_CC_TURING) >= GGML_CUDA_CC_TURING && !turing_devices_without_mma.empty()) { 375 GGML_LOG_INFO("The following devices will have suboptimal performance due to a lack of tensor cores:\n"); 376 for (size_t device_pos = 0; device_pos < turing_devices_without_mma.size(); device_pos++) { 377 GGML_LOG_INFO( 378 " Device %d: %s\n", turing_devices_without_mma[device_pos].first, turing_devices_without_mma[device_pos].second.c_str()); 379 } 380 GGML_LOG_INFO( 381 "Consider compiling with CMAKE_CUDA_ARCHITECTURES=61-virtual;80-virtual and DGGML_CUDA_FORCE_MMQ to force the use of the Pascal code for Turing.\n"); 382 } 383 384 for (int id = 0; id < info.device_count; ++id) { 385 info.default_tensor_split[id] /= total_vram; 386 } 387 388 // configure logging to stdout 389 // CUBLAS_CHECK(cublasLoggerConfigure(1, 1, 0, nullptr)); 390 391 if (getenv("GGML_CUDA_P2P") != nullptr) { 392 for (int id = 0; id < info.physical_device_count; ++id) { 393 CUDA_CHECK(cudaSetDevice(id)); 394 for (int id_other = 0; id_other < info.physical_device_count; ++id_other) { 395 if (id == id_other) { 396 continue; 397 } 398 int can_access_peer; 399 CUDA_CHECK(cudaDeviceCanAccessPeer(&can_access_peer, id, id_other)); 400 if (can_access_peer) { 401 CUDA_CHECK(cudaDeviceEnablePeerAccess(id_other, 0)); 402 } 403 } 404 } 405 } 406 407 return info; 408} 409 410const ggml_cuda_device_info & ggml_cuda_info() { 411 static ggml_cuda_device_info info = ggml_cuda_init(); 412 return info; 413} 414 415// #define DEBUG_CUDA_MALLOC 416 417// buffer pool for cuda (legacy) 418struct ggml_cuda_pool_leg : public ggml_cuda_pool { 419 static const int MAX_BUFFERS = 256; 420 421 int device; 422 struct ggml_cuda_buffer { 423 void * ptr = nullptr; 424 size_t size = 0; 425 }; 426 427 ggml_cuda_buffer buffer_pool[MAX_BUFFERS] = {}; 428 size_t pool_size = 0; 429 430 explicit ggml_cuda_pool_leg(int device) : 431 device(device) { 432 } 433 434 ~ggml_cuda_pool_leg() { 435 clear_pool(); 436 GGML_ASSERT(pool_size == 0); 437 } 438 439 void clear_pool() { 440 ggml_cuda_set_device(device); 441 for (int i = 0; i < MAX_BUFFERS; ++i) { 442 ggml_cuda_buffer & b = buffer_pool[i]; 443 if (b.ptr != nullptr) { 444 CUDA_CHECK(cudaFree(b.ptr)); 445 pool_size -= b.size; 446 b.ptr = nullptr; 447 b.size = 0; 448 } 449 } 450 } 451 452 void * alloc(size_t size, size_t * actual_size) override { 453#ifdef DEBUG_CUDA_MALLOC 454 int nnz = 0; 455 size_t max_size = 0; 456#endif 457 size_t best_diff = 1ull << 36; 458 int ibest = -1; 459 for (int i = 0; i < MAX_BUFFERS; ++i) { 460 ggml_cuda_buffer& b = buffer_pool[i]; 461 if (b.ptr != nullptr) { 462#ifdef DEBUG_CUDA_MALLOC 463 ++nnz; 464 if (b.size > max_size) max_size = b.size; 465#endif 466 if (b.size >= size) { 467 size_t diff = b.size - size; 468 if (diff < best_diff) { 469 best_diff = diff; 470 ibest = i; 471 if (!best_diff) { 472 void * ptr = b.ptr; 473 *actual_size = b.size; 474 b.ptr = nullptr; 475 b.size = 0; 476 return ptr; 477 } 478 } 479 } 480 } 481 } 482 if (ibest >= 0) { 483 ggml_cuda_buffer& b = buffer_pool[ibest]; 484 void * ptr = b.ptr; 485 *actual_size = b.size; 486 b.ptr = nullptr; 487 b.size = 0; 488 return ptr; 489 } 490 void * ptr; 491 size_t look_ahead_size = (size_t) (1.05 * size); 492 look_ahead_size = 256 * ((look_ahead_size + 255)/256); 493 ggml_cuda_set_device(device); 494 cudaError_t err = ggml_cuda_device_malloc(&ptr, look_ahead_size, device); 495 if (err == cudaErrorMemoryAllocation) { 496 (void)cudaGetLastError(); 497 const size_t cached_bytes = pool_size; 498 GGML_LOG_DEBUG(GGML_CUDA_NAME " pool[%d]: alloc of %.2f MiB failed, flushing %.2f MiB of cached buffers and retrying\n", 499 device, look_ahead_size/1024.0/1024.0, cached_bytes/1024.0/1024.0); 500 CUDA_CHECK(cudaDeviceSynchronize()); 501 clear_pool(); 502 err = ggml_cuda_device_malloc(&ptr, look_ahead_size, device); 503 if (err == cudaSuccess) { 504 GGML_LOG_DEBUG(GGML_CUDA_NAME " pool[%d]: retry succeeded\n", device); 505 } 506 } 507 CUDA_CHECK(err); 508 *actual_size = look_ahead_size; 509 pool_size += look_ahead_size; 510#ifdef DEBUG_CUDA_MALLOC 511 GGML_LOG_INFO("%s[%d]: %d buffers, max_size = %u MB, pool_size = %u MB, requested %u MB\n", __func__, device, nnz, 512 (uint32_t)(max_size / 1024 / 1024), (uint32_t)(pool_size / 1024 / 1024), (uint32_t)(size / 1024 / 1024)); 513#endif 514 return ptr; 515 } 516 517 void free(void * ptr, size_t size) override { 518 for (int i = 0; i < MAX_BUFFERS; ++i) { 519 ggml_cuda_buffer& b = buffer_pool[i]; 520 if (b.ptr == nullptr) { 521 b.ptr = ptr; 522 b.size = size; 523 return; 524 } 525 } 526 GGML_LOG_DEBUG(GGML_CUDA_NAME " buffer pool full, increase MAX_CUDA_BUFFERS\n"); 527 ggml_cuda_set_device(device); 528 CUDA_CHECK(cudaFree(ptr)); 529 pool_size -= size; 530 } 531}; 532 533// pool with virtual memory 534#if defined(GGML_USE_VMM) 535struct ggml_cuda_pool_vmm : public ggml_cuda_pool { 536 static const size_t CUDA_POOL_VMM_MAX_SIZE = 1ull << 35; // 32 GB 537 538 int device; 539 int physical_device; 540 CUdeviceptr pool_addr = 0; 541 size_t pool_used = 0; 542 size_t pool_size = 0; 543 size_t granularity; 544#if defined(GGML_USE_HIP) 545 std::vector<std::pair<CUdeviceptr, size_t>> mappings; 546#endif 547 548 explicit ggml_cuda_pool_vmm(int device) : 549 device(device), 550 physical_device(ggml_cuda_get_physical_device(device)), 551 granularity(ggml_cuda_info().devices[device].vmm_granularity) { 552 } 553 554 ~ggml_cuda_pool_vmm() { 555 if (pool_addr != 0) { 556#if defined(GGML_USE_HIP) 557 // Workaround for https://github.com/ROCm/ROCR-Runtime/issues/285 558 for (std::pair<CUdeviceptr, size_t> & mapping : mappings) { 559 CU_CHECK(cuMemUnmap(mapping.first, mapping.second)); 560 } 561#else 562 CU_CHECK(cuMemUnmap(pool_addr, pool_size)); 563#endif 564 CU_CHECK(cuMemAddressFree(pool_addr, CUDA_POOL_VMM_MAX_SIZE)); 565 } 566 } 567 568 void * alloc(size_t size, size_t * actual_size) override { 569 // round up the allocation size to the alignment to ensure that all allocations are aligned for all data types 570 const size_t alignment = 128; 571 size = alignment * ((size + alignment - 1) / alignment); 572 573 size_t avail = pool_size - pool_used; 574 575 if (size > avail) { 576 // round up to the next multiple of the granularity 577 size_t reserve_size = size - avail; 578 reserve_size = granularity * ((reserve_size + granularity - 1) / granularity); 579 580 GGML_ASSERT(pool_size + reserve_size <= CUDA_POOL_VMM_MAX_SIZE); 581 582 // allocate more physical memory 583 CUmemAllocationProp prop = {}; 584 prop.type = CU_MEM_ALLOCATION_TYPE_PINNED; 585 prop.location.type = CU_MEM_LOCATION_TYPE_DEVICE; 586 prop.location.id = physical_device; 587 CUmemGenericAllocationHandle handle; 588 CU_CHECK(cuMemCreate(&handle, reserve_size, &prop, 0)); 589 590 // reserve virtual address space (if not already reserved) 591 if (pool_addr == 0) { 592 CU_CHECK(cuMemAddressReserve(&pool_addr, CUDA_POOL_VMM_MAX_SIZE, 0, 0, 0)); 593 } 594 595 // map at the end of the pool 596 CUdeviceptr start_ptr = (CUdeviceptr)((char *)(pool_addr) + pool_size); 597 CU_CHECK(cuMemMap(start_ptr, reserve_size, 0, handle, 0)); 598#if defined(GGML_USE_HIP) 599 mappings.push_back({start_ptr, reserve_size}); 600#endif 601 602 // the memory allocation handle is no longer needed after mapping 603 CU_CHECK(cuMemRelease(handle)); 604 605 // VMM Bug fix for P2P access if GGML_CUDA_P2P is set, or if NCCL build 606 bool use_peer_access = getenv("GGML_CUDA_P2P") != nullptr; 607#if defined(GGML_USE_NCCL) 608 use_peer_access = true; 609#endif // defined(GGML_USE_NCCL) 610 611 if (use_peer_access) { 612 // NCCL implicitly enables peer access (cudaDeviceEnablePeerAccess), and 613 // GGML_CUDA_P2P enables it explicitly. Unlike cudaMalloc buffers, VMM 614 // allocations do not become peer-accessible from that alone, so access 615 // must be granted explicitly here. With virtual devices, grant access 616 // on the backing *physical* devices (deduplicated, since several 617 // virtual devices can map to the same physical GPU). 618 std::vector<CUmemAccessDesc> access_descs; 619 bool physical_seen[GGML_CUDA_MAX_DEVICES] = {}; 620 const int device_count = ggml_cuda_info().device_count; 621 for (int id = 0; id < device_count; ++id) { 622 const int id_physical = ggml_cuda_get_physical_device(id); 623 if (id_physical != physical_device) { 624 int can_access_peer = 0; 625 CUDA_CHECK(cudaDeviceCanAccessPeer(&can_access_peer, id_physical, physical_device)); 626 if (!can_access_peer) { 627 continue; 628 } 629 } 630 if (physical_seen[id_physical]) { 631 continue; 632 } 633 physical_seen[id_physical] = true; 634 CUmemAccessDesc access = {}; 635 access.location.type = CU_MEM_LOCATION_TYPE_DEVICE; 636 access.location.id = id_physical; 637 access.flags = CU_MEM_ACCESS_FLAGS_PROT_READWRITE; 638 access_descs.push_back(access); 639 } 640 CU_CHECK(cuMemSetAccess(start_ptr, reserve_size, access_descs.data(), access_descs.size())); 641 } else { 642 // set access for non P2P 643 CUmemAccessDesc access = {}; 644 access.location.type = CU_MEM_LOCATION_TYPE_DEVICE; 645 access.location.id = physical_device; 646 access.flags = CU_MEM_ACCESS_FLAGS_PROT_READWRITE; 647 CU_CHECK(cuMemSetAccess(start_ptr, reserve_size, &access, 1)); 648 } 649 650 // add to the pool 651 pool_size += reserve_size; 652 653 //printf("cuda pool[%d]: size increased to %llu MB (reserved %llu MB)\n", 654 // device, (unsigned long long) (pool_size/1024/1024), 655 // (unsigned long long) (reserve_size/1024/1024)); 656 } 657 658 GGML_ASSERT(pool_addr != 0); 659 660 void * ptr = (void *) ((CUdeviceptr)((char *)(pool_addr) + pool_used)); 661 *actual_size = size; 662 pool_used += size; 663 664#ifdef DEBUG_CUDA_MALLOC 665 printf("cuda pool[%d]: allocated %llu bytes at %llx\n", device, (unsigned long long) size, ptr); 666#endif 667 668 return ptr; 669 } 670 671 void free(void * ptr, size_t size) override { 672#ifdef DEBUG_CUDA_MALLOC 673 printf("cuda pool[%d]: freed %llu bytes at %llx\n", device, (unsigned long long) size, ptr); 674#endif 675 676 pool_used -= size; 677 678 // all deallocations must be in reverse order of the allocations 679 GGML_ASSERT(ptr == (void *) ((char *)(pool_addr) + pool_used)); 680 } 681}; 682#endif // defined(GGML_USE_VMM) 683 684std::unique_ptr<ggml_cuda_pool> ggml_backend_cuda_context::new_pool_for_device(int device, 685 [[maybe_unused]] int stream_no) { 686#if defined(GGML_USE_VMM) 687 if (ggml_cuda_info().devices[device].vmm) { 688 return std::unique_ptr<ggml_cuda_pool>(new ggml_cuda_pool_vmm(device)); 689 } 690#endif // defined(GGML_USE_VMM) 691 return std::unique_ptr<ggml_cuda_pool>(new ggml_cuda_pool_leg(device)); 692} 693 694// destroying a cuBLAS handle while a graph is being captured in a different thread can result in a CUDA error 695// this lock is used to ensure that no cuBLAS handle is destroyed while a graph is being captured 696 697static std::mutex ggml_cuda_lock; 698static std::condition_variable ggml_cuda_lock_cv; 699static std::atomic<int> ggml_cuda_lock_counter; 700 701ggml_backend_cuda_context::~ggml_backend_cuda_context() { 702 std::unique_lock<std::mutex> lock(ggml_cuda_lock); 703 ggml_cuda_lock_cv.wait(lock, []{ return ggml_cuda_lock_counter.load(std::memory_order_relaxed) == 0; }); 704 705 if (copy_event != nullptr) { 706 CUDA_CHECK(cudaEventDestroy(copy_event)); 707 } 708 for (int i = 0; i < GGML_CUDA_MAX_DEVICES; ++i) { 709 for (int j = 0; j < GGML_CUDA_MAX_STREAMS; ++j) { 710 if (streams[i][j] != nullptr) { 711 CUDA_CHECK(cudaStreamDestroy(streams[i][j])); 712 } 713 if (cublas_handles[i][j] != nullptr) { 714 CUBLAS_CHECK(cublasDestroy(cublas_handles[i][j])); 715 } 716 if (cublas_workspaces[i][j] != nullptr) { 717 CUDA_CHECK(cudaFree(cublas_workspaces[i][j])); 718 } 719 } 720 } 721} 722 723 724// cuda buffer 725 726struct ggml_backend_cuda_buffer_context { 727 int device; 728 void * dev_ptr = nullptr; 729 std::string name; 730 731 ggml_backend_cuda_buffer_context(int device, void * dev_ptr) : 732 device(device), dev_ptr(dev_ptr), 733 name(GGML_CUDA_NAME + std::to_string(device)) { 734 } 735 736 ~ggml_backend_cuda_buffer_context() { 737 CUDA_CHECK(cudaFree(dev_ptr)); 738 } 739}; 740 741static void ggml_backend_cuda_buffer_free_buffer(ggml_backend_buffer_t buffer) { 742 ggml_backend_cuda_buffer_context * ctx = (ggml_backend_cuda_buffer_context *)buffer->context; 743 delete ctx; 744} 745 746static bool ggml_backend_buffer_is_cuda(ggml_backend_buffer_t buffer) { 747 return buffer->iface.free_buffer == ggml_backend_cuda_buffer_free_buffer; 748} 749 750static void * ggml_backend_cuda_buffer_get_base(ggml_backend_buffer_t buffer) { 751 ggml_backend_cuda_buffer_context * ctx = (ggml_backend_cuda_buffer_context *)buffer->context; 752 return ctx->dev_ptr; 753} 754 755static enum ggml_status ggml_backend_cuda_buffer_init_tensor(ggml_backend_buffer_t buffer, ggml_tensor * tensor) { 756 ggml_backend_cuda_buffer_context * ctx = (ggml_backend_cuda_buffer_context *)buffer->context; 757 758 if (tensor->view_src != NULL) { 759 assert(tensor->view_src->buffer->buft == buffer->buft); 760 return GGML_STATUS_SUCCESS; 761 } 762 763 if (ggml_is_quantized(tensor->type) && tensor->view_src == nullptr && ggml_backend_buffer_get_usage(buffer) != GGML_BACKEND_BUFFER_USAGE_COMPUTE) { 764 // initialize padding to 0 to avoid possible NaN values 765 const size_t original_size = ggml_nbytes(tensor); 766 const size_t padded_size = ggml_backend_buft_get_alloc_size(buffer->buft, tensor); 767 768 if (padded_size > original_size) { 769 ggml_cuda_set_device(ctx->device); 770 CUDA_CHECK(cudaMemset((char *)tensor->data + original_size, 0, padded_size - original_size)); 771 } 772 } 773 return GGML_STATUS_SUCCESS; 774} 775 776static void ggml_backend_cuda_buffer_memset_tensor(ggml_backend_buffer_t buffer, ggml_tensor * tensor, uint8_t value, size_t offset, size_t size) { 777 ggml_backend_cuda_buffer_context * ctx = (ggml_backend_cuda_buffer_context *) buffer->context; 778 779 ggml_cuda_set_device(ctx->device); 780 CUDA_CHECK(cudaMemsetAsync((char *) tensor->data + offset, value, size, cudaStreamPerThread)); 781 CUDA_CHECK(cudaStreamSynchronize(cudaStreamPerThread)); 782} 783 784static void ggml_backend_cuda_buffer_set_tensor(ggml_backend_buffer_t buffer, ggml_tensor * tensor, const void * data, size_t offset, size_t size) { 785 ggml_backend_cuda_buffer_context * ctx = (ggml_backend_cuda_buffer_context *) buffer->context; 786 787 ggml_cuda_set_device(ctx->device); 788 CUDA_CHECK(cudaMemcpyAsync((char *) tensor->data + offset, data, size, cudaMemcpyHostToDevice, cudaStreamPerThread)); 789 CUDA_CHECK(cudaStreamSynchronize(cudaStreamPerThread)); 790} 791 792static void ggml_backend_cuda_buffer_get_tensor(ggml_backend_buffer_t buffer, const ggml_tensor * tensor, void * data, size_t offset, size_t size) { 793 ggml_backend_cuda_buffer_context * ctx = (ggml_backend_cuda_buffer_context *) buffer->context; 794 795 ggml_cuda_set_device(ctx->device); 796 CUDA_CHECK(cudaMemcpyAsync(data, (const char *) tensor->data + offset, size, cudaMemcpyDeviceToHost, cudaStreamPerThread)); 797 CUDA_CHECK(cudaStreamSynchronize(cudaStreamPerThread)); 798} 799 800static void ggml_backend_cuda_buffer_set_tensor_2d(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor, const void * data, 801 size_t offset, size_t size, size_t n_copies, size_t stride_tensor, size_t stride_data) { 802 ggml_backend_cuda_buffer_context * ctx = (ggml_backend_cuda_buffer_context *) buffer->context; 803 804 ggml_cuda_set_device(ctx->device); 805 CUDA_CHECK(cudaMemcpy2DAsync( 806 (char *) tensor->data + offset, stride_tensor, data, stride_data, size, n_copies, cudaMemcpyHostToDevice, cudaStreamPerThread)); 807 CUDA_CHECK(cudaStreamSynchronize(cudaStreamPerThread)); 808} 809 810static void ggml_backend_cuda_buffer_get_tensor_2d(ggml_backend_buffer_t buffer, const struct ggml_tensor * tensor, void * data, 811 size_t offset, size_t size, size_t n_copies, size_t stride_tensor, size_t stride_data) { 812 ggml_backend_cuda_buffer_context * ctx = (ggml_backend_cuda_buffer_context *)buffer->context; 813 814 ggml_cuda_set_device(ctx->device); 815 CUDA_CHECK(cudaMemcpy2DAsync( 816 data, stride_data, (const char *) tensor->data + offset, stride_tensor, size, n_copies, cudaMemcpyDeviceToHost, cudaStreamPerThread)); 817 CUDA_CHECK(cudaStreamSynchronize(cudaStreamPerThread)); 818} 819 820static bool ggml_backend_cuda_buffer_cpy_tensor(ggml_backend_buffer_t buffer, const ggml_tensor * src, ggml_tensor * dst) { 821 if (ggml_backend_buffer_is_cuda(src->buffer)) { 822 ggml_backend_cuda_buffer_context * src_ctx = (ggml_backend_cuda_buffer_context *)src->buffer->context; 823 ggml_backend_cuda_buffer_context * dst_ctx = (ggml_backend_cuda_buffer_context *)dst->buffer->context; 824 // compare the backing physical devices: distinct virtual devices may share one physical GPU, 825 // in which case a same-device copy (not a peer copy) is required 826 const int src_physical = ggml_cuda_get_physical_device(src_ctx->device); 827 const int dst_physical = ggml_cuda_get_physical_device(dst_ctx->device); 828 if (src_physical == dst_physical) { 829 CUDA_CHECK(cudaMemcpyAsync(dst->data, src->data, ggml_nbytes(src), cudaMemcpyDeviceToDevice, cudaStreamPerThread)); 830 } else { 831#ifdef GGML_CUDA_NO_PEER_COPY 832 return false; 833#else 834 CUDA_CHECK(cudaMemcpyPeerAsync(dst->data, dst_physical, src->data, src_physical, ggml_nbytes(src), cudaStreamPerThread)); 835#endif 836 } 837 CUDA_CHECK(cudaStreamSynchronize(cudaStreamPerThread)); 838 return true; 839 } 840 return false; 841 842 GGML_UNUSED(buffer); 843} 844 845static void ggml_backend_cuda_buffer_clear(ggml_backend_buffer_t buffer, uint8_t value) { 846 ggml_backend_cuda_buffer_context * ctx = (ggml_backend_cuda_buffer_context *)buffer->context; 847 848 ggml_cuda_set_device(ctx->device); 849 CUDA_CHECK(cudaMemsetAsync(ctx->dev_ptr, value, buffer->size, cudaStreamPerThread)); 850 CUDA_CHECK(cudaStreamSynchronize(cudaStreamPerThread)); 851} 852 853static const ggml_backend_buffer_i ggml_backend_cuda_buffer_interface = { 854 /* .free_buffer = */ ggml_backend_cuda_buffer_free_buffer, 855 /* .get_base = */ ggml_backend_cuda_buffer_get_base, 856 /* .init_tensor = */ ggml_backend_cuda_buffer_init_tensor, 857 /* .memset_tensor = */ ggml_backend_cuda_buffer_memset_tensor, 858 /* .set_tensor = */ ggml_backend_cuda_buffer_set_tensor, 859 /* .get_tensor = */ ggml_backend_cuda_buffer_get_tensor, 860 /* .set_tensor_2d = */ ggml_backend_cuda_buffer_set_tensor_2d, 861 /* .get_tensor_2d = */ ggml_backend_cuda_buffer_get_tensor_2d, 862 /* .cpy_tensor = */ ggml_backend_cuda_buffer_cpy_tensor, 863 /* .clear = */ ggml_backend_cuda_buffer_clear, 864 /* .reset = */ NULL, 865}; 866 867// cuda buffer type 868struct ggml_backend_cuda_buffer_type_context { 869 int device; 870 std::string name; 871}; 872 873static const char * ggml_backend_cuda_buffer_type_get_name(ggml_backend_buffer_type_t buft) { 874 ggml_backend_cuda_buffer_type_context * ctx = (ggml_backend_cuda_buffer_type_context *)buft->context; 875 876 return ctx->name.c_str(); 877} 878 879static bool ggml_backend_buft_is_cuda(ggml_backend_buffer_type_t buft) { 880 return buft->iface.get_name == ggml_backend_cuda_buffer_type_get_name; 881} 882 883static ggml_backend_buffer_t ggml_backend_cuda_buffer_type_alloc_buffer(ggml_backend_buffer_type_t buft, size_t size) { 884 ggml_backend_cuda_buffer_type_context * buft_ctx = (ggml_backend_cuda_buffer_type_context *)buft->context; 885 886 ggml_cuda_set_device(buft_ctx->device); 887 888 void * dev_ptr; 889 cudaError_t err = ggml_cuda_device_malloc(&dev_ptr, size, buft_ctx->device); 890 if (err != cudaSuccess) { 891 // clear the error 892 (void)cudaGetLastError(); 893 GGML_LOG_ERROR("%s: allocating %.2f MiB on device %d: cudaMalloc failed: %s\n", __func__, size / 1024.0 / 1024.0, buft_ctx->device, cudaGetErrorString(err)); 894 return nullptr; 895 } 896 897 ggml_backend_cuda_buffer_context * ctx = new ggml_backend_cuda_buffer_context(buft_ctx->device, dev_ptr); 898 899 return ggml_backend_buffer_init(buft, ggml_backend_cuda_buffer_interface, ctx, size); 900} 901 902static size_t ggml_backend_cuda_buffer_type_get_alignment(ggml_backend_buffer_type_t buft) { 903 return 128; 904 905 GGML_UNUSED(buft); 906} 907 908static size_t ggml_backend_cuda_buffer_type_get_alloc_size(ggml_backend_buffer_type_t buft, const ggml_tensor * tensor) { 909 ggml_backend_cuda_buffer_type_context * buft_ctx = (ggml_backend_cuda_buffer_type_context *) buft->context; 910 911 size_t size = tensor->op == GGML_OP_FLASH_ATTN_EXT 912 ? ggml_cuda_flash_attn_ext_get_alloc_size(buft_ctx->device, tensor) 913 : ggml_nbytes(tensor); 914 int64_t ne0 = tensor->ne[0]; 915 916 // [TAG_ALLOC_SIZE_EXPAND] 917 if (ggml_is_quantized(tensor->type)) { 918 if (ne0 % MATRIX_ROW_PADDING != 0) { 919 GGML_ASSERT(tensor->nb[0] == ggml_element_size(tensor)); 920 size += ggml_row_size(tensor->type, MATRIX_ROW_PADDING - ne0 % MATRIX_ROW_PADDING); 921 } 922 } 923 924 return size; 925} 926 927static const ggml_backend_buffer_type_i ggml_backend_cuda_buffer_type_interface = { 928 /* .get_name = */ ggml_backend_cuda_buffer_type_get_name, 929 /* .alloc_buffer = */ ggml_backend_cuda_buffer_type_alloc_buffer, 930 /* .get_alignment = */ ggml_backend_cuda_buffer_type_get_alignment, 931 /* .get_max_size = */ NULL, // defaults to SIZE_MAX 932 /* .get_alloc_size = */ ggml_backend_cuda_buffer_type_get_alloc_size, 933 /* .is_host = */ NULL, 934}; 935 936ggml_backend_buffer_type_t ggml_backend_cuda_buffer_type(int device) { 937 static std::mutex mutex; 938 std::lock_guard<std::mutex> lock(mutex); 939 940 if (device >= ggml_backend_cuda_get_device_count()) { 941 return nullptr; 942 } 943 944 static ggml_backend_buffer_type ggml_backend_cuda_buffer_types[GGML_CUDA_MAX_DEVICES]; 945 946 static bool ggml_backend_cuda_buffer_type_initialized = false; 947 948 if (!ggml_backend_cuda_buffer_type_initialized) { 949 for (int i = 0; i < ggml_backend_cuda_get_device_count(); i++) { 950 ggml_backend_cuda_buffer_types[i] = { 951 /* .iface = */ ggml_backend_cuda_buffer_type_interface, 952 /* .device = */ ggml_backend_reg_dev_get(ggml_backend_cuda_reg(), i), 953 /* .context = */ new ggml_backend_cuda_buffer_type_context{i, GGML_CUDA_NAME + std::to_string(i)}, 954 }; 955 } 956 ggml_backend_cuda_buffer_type_initialized = true; 957 } 958 959 return &ggml_backend_cuda_buffer_types[device]; 960} 961 962// Communication context for multi-GPU AllReduce during tensor parallelism. 963// 964// Created once per meta backend instance. Resources for the selected mode 965// (NCCL communicators or the internal AllReduce pipeline) are initialised 966// eagerly during comm_init so any init failure surfaces at startup rather 967// than mid-run. 968struct ggml_backend_cuda_comm_context { 969 using try_allreduce_fn = bool(*)(ggml_backend_cuda_comm_context *, struct ggml_tensor **); 970 971 std::vector<ggml_backend_t> backends; 972 std::vector<int> dev_ids; 973 974 // Set by the init chain (comm_init_{nccl, internal, none}) to one of 975 // try_allreduce_{nccl, internal, butterfly}. nccl needs `comms`, 976 // internal needs `ar_pipeline`, butterfly needs nothing. Per-call 977 // failures return false; the meta backend's generic implementation then 978 // handles that call. 979 try_allreduce_fn try_allreduce = nullptr; 980 981 ggml_cuda_ar_pipeline * ar_pipeline = nullptr; 982 983#ifdef GGML_USE_NCCL 984 std::vector<ncclComm_t> comms; 985#endif // GGML_USE_NCCL 986 987 ~ggml_backend_cuda_comm_context() { 988#ifdef GGML_USE_NCCL 989 for (ncclComm_t comm : comms) { 990 NCCL_CHECK(ncclCommDestroy(comm)); 991 } 992#endif // GGML_USE_NCCL 993 ggml_cuda_ar_pipeline_free(ar_pipeline); 994 } 995}; 996 997#ifdef GGML_USE_NCCL 998// AllReduce via NCCL. Reduces as FP32 for small tensors and BF16 for large 999// tensors (bandwidth-bound), then converts back to FP32. 1000static bool ggml_backend_cuda_comm_allreduce_nccl( 1001 ggml_backend_cuda_comm_context * comm_ctx, struct ggml_tensor ** tensors) { 1002 const int64_t ne = ggml_nelements(tensors[0]); 1003 // FIXME the input of llm_graph_context::build_in_out_ids can produce a tensor with 0 elements if n_outputs == 0 1004 // This then causes a crash in this function 1005 if (ne == 0) { 1006 return true; 1007 } 1008 1009 const size_t n_backends = comm_ctx->backends.size(); 1010 1011 for (size_t i = 0; i < n_backends; ++i) { 1012 GGML_ASSERT(tensors[i] != nullptr); 1013 GGML_ASSERT(ggml_nelements(tensors[i]) == ne); 1014 GGML_ASSERT(ggml_is_contiguously_allocated(tensors[i])); 1015 } 1016 1017 // For small tensors, simply reduce them as FP32. 1018 // The following heuristic for how "small" a tensor should be is based on RTX 4090s connected via 16x PCIe 4.0. 1019 if ((n_backends <= 2 && ne < 32768) || (n_backends == 3 && ne < 131072) || (n_backends >= 4 && ne < 262144)) { 1020 for (size_t i = 0; i < n_backends; ++i) { 1021 if ((tensors[i]->flags & GGML_TENSOR_FLAG_COMPUTE) == 0) { 1022 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *) comm_ctx->backends[i]->context; 1023 ggml_cuda_set_device(cuda_ctx->device); 1024 CUDA_CHECK(cudaMemsetAsync(tensors[i]->data, 0, ggml_nbytes(tensors[i]), cuda_ctx->stream())); 1025 } 1026 } 1027 NCCL_CHECK(ncclGroupStart()); 1028 for (size_t i = 0; i < n_backends; ++i) { 1029 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *) comm_ctx->backends[i]->context; 1030 NCCL_CHECK(ncclAllReduce(tensors[i]->data, tensors[i]->data, ne, ncclFloat, ncclSum, comm_ctx->comms[i], cuda_ctx->stream())); 1031 } 1032 NCCL_CHECK(ncclGroupEnd()); 1033 return true; 1034 } 1035 1036 // For large tensors it's faster to compress them to BF16 for the reduction: 1037 to_bf16_cuda_t to_bf16 = ggml_get_to_bf16_cuda(GGML_TYPE_F32); 1038 to_fp32_cuda_t to_fp32 = ggml_get_to_fp32_cuda(GGML_TYPE_BF16); 1039 1040 ggml_cuda_pool_alloc<nv_bfloat16> tmp[GGML_CUDA_MAX_DEVICES]; 1041 for (size_t i = 0; i < n_backends; ++i) { 1042 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *) comm_ctx->backends[i]->context; 1043 tmp[i].pool = &cuda_ctx->pool(); 1044 tmp[i].alloc(ne); 1045 1046 ggml_cuda_set_device(cuda_ctx->device); 1047 if (tensors[i]->flags & GGML_TENSOR_FLAG_COMPUTE) { 1048 to_bf16(tensors[i]->data, tmp[i].get(), ne, cuda_ctx->stream()); 1049 } else { 1050 CUDA_CHECK(cudaMemsetAsync(tmp[i].get(), 0, ne * sizeof(nv_bfloat16), cuda_ctx->stream())); 1051 } 1052 CUDA_CHECK(cudaGetLastError()); 1053 } 1054 1055 NCCL_CHECK(ncclGroupStart()); 1056 for (size_t i = 0; i < n_backends; ++i) { 1057 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *) comm_ctx->backends[i]->context; 1058 NCCL_CHECK(ncclAllReduce(tmp[i].get(), tmp[i].get(), ne, ncclBfloat16, ncclSum, comm_ctx->comms[i], cuda_ctx->stream())); 1059 } 1060 NCCL_CHECK(ncclGroupEnd()); 1061 1062 for (size_t i = 0; i < n_backends; ++i) { 1063 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *) comm_ctx->backends[i]->context; 1064 1065 ggml_cuda_set_device(cuda_ctx->device); 1066 to_fp32(tmp[i].get(), (float *) tensors[i]->data, ne, cuda_ctx->stream()); 1067 CUDA_CHECK(cudaGetLastError()); 1068 } 1069 1070 return true; 1071} 1072#endif // GGML_USE_NCCL 1073 1074// Run the internal AR pipeline. Returns false on unsupported / failed input 1075// -- the caller decides whether to abort (env-forced) or fall back silently. 1076static bool ggml_backend_cuda_comm_allreduce_internal( 1077 ggml_backend_cuda_comm_context * comm_ctx, struct ggml_tensor ** tensors) { 1078 GGML_ASSERT(comm_ctx->ar_pipeline != nullptr); 1079 1080 const size_t n_backends = comm_ctx->backends.size(); 1081 GGML_ASSERT(n_backends == 2); 1082 GGML_ASSERT(tensors[0] != nullptr); 1083 1084 const int64_t ne = ggml_nelements(tensors[0]); 1085 const ggml_type type = tensors[0]->type; 1086 1087 if (type != GGML_TYPE_F32 && type != GGML_TYPE_F16 && type != GGML_TYPE_BF16) { 1088 GGML_LOG_DEBUG("%s: internal unsupported: type=%d\n", __func__, (int) type); 1089 return false; 1090 } 1091 1092 if (ne == 0) { 1093 return true; 1094 } 1095 1096 for (size_t i = 0; i < n_backends; ++i) { 1097 if (tensors[i] == nullptr) { 1098 GGML_LOG_ERROR("%s: internal failed: tensor[%zu] is null\n", __func__, i); 1099 return false; 1100 } 1101 if (ggml_nelements(tensors[i]) != ne || tensors[i]->type != type) { 1102 GGML_LOG_ERROR("%s: internal failed: tensor[%zu] ne=%" PRId64 " type=%d expected ne=%" PRId64 " type=%d\n", 1103 __func__, i, ggml_nelements(tensors[i]), (int) tensors[i]->type, ne, (int) type); 1104 return false; 1105 } 1106 if (!ggml_is_contiguously_allocated(tensors[i])) { 1107 GGML_LOG_DEBUG("%s: internal unsupported: tensor[%zu] is not contiguously allocated: ne=%" PRId64 " nbytes=%zu packed=%zu type=%d\n", 1108 __func__, i, ne, ggml_nbytes(tensors[i]), 1109 (size_t) ne * ggml_type_size(type) / ggml_blck_size(type), (int) type); 1110 return false; 1111 } 1112 if (((uintptr_t) tensors[i]->data & 0xF) != 0) { 1113 GGML_LOG_DEBUG("%s: internal unsupported: tensor[%zu] data pointer is not 16-byte aligned: %p type=%d ne=%" PRId64 "\n", 1114 __func__, i, tensors[i]->data, (int) type, ne); 1115 return false; 1116 } 1117 GGML_ASSERT((ggml_nbytes(tensors[i]) & 0xF) == 0); 1118 } 1119 1120 return ggml_cuda_ar_allreduce(comm_ctx->ar_pipeline, comm_ctx->backends.data(), tensors); 1121} 1122 1123// --------------------------------------------------------------------------- 1124// Per-call dispatch -- three variants, one per backend. Each is set as 1125// comm_ctx->try_allreduce by the matching init step. Per-call failure 1126// returns false; the meta backend's generic implementation handles that call. 1127// --------------------------------------------------------------------------- 1128 1129#ifdef GGML_USE_NCCL 1130static bool ggml_backend_cuda_comm_try_allreduce_nccl( 1131 ggml_backend_cuda_comm_context * comm_ctx, struct ggml_tensor ** tensors) { 1132 return ggml_backend_cuda_comm_allreduce_nccl(comm_ctx, tensors); 1133} 1134#endif // GGML_USE_NCCL 1135 1136static bool ggml_backend_cuda_comm_try_allreduce_internal( 1137 ggml_backend_cuda_comm_context * comm_ctx, struct ggml_tensor ** tensors) { 1138 return ggml_backend_cuda_comm_allreduce_internal(comm_ctx, tensors); 1139} 1140 1141static bool ggml_backend_cuda_comm_try_allreduce_butterfly( 1142 ggml_backend_cuda_comm_context *, struct ggml_tensor **) { 1143 return false; 1144} 1145 1146static void ggml_backend_cuda_comm_free(void * comm_ctx_v) { 1147 if (comm_ctx_v == nullptr) { 1148 return; 1149 } 1150 delete static_cast<ggml_backend_cuda_comm_context *>(comm_ctx_v); 1151} 1152 1153// --------------------------------------------------------------------------- 1154// Init -- chained nccl -> internal -> none. Each step tries to bring up its 1155// resource; on failure it warns and recurses into the next step. 1156// --------------------------------------------------------------------------- 1157static void ggml_backend_cuda_comm_init_none(ggml_backend_cuda_comm_context * ret) { 1158 ret->try_allreduce = ggml_backend_cuda_comm_try_allreduce_butterfly; 1159} 1160 1161static void ggml_backend_cuda_comm_init_internal(ggml_backend_cuda_comm_context * ret) { 1162 ret->ar_pipeline = ggml_cuda_ar_pipeline_init(ret->dev_ids.data(), ret->dev_ids.size()); 1163 if (ret->ar_pipeline) { 1164 ret->try_allreduce = ggml_backend_cuda_comm_try_allreduce_internal; 1165 return; 1166 } 1167 1168 // Clear sticky CUDA error from the failed init. 1169 (void) cudaGetLastError(); 1170 GGML_LOG_WARN("internal AllReduce init failed (n_devices != 2?); " 1171 "falling back to meta-backend butterfly\n"); 1172 ggml_backend_cuda_comm_init_none(ret); 1173} 1174 1175static void ggml_backend_cuda_comm_init_nccl(ggml_backend_cuda_comm_context * ret) { 1176#ifdef GGML_USE_NCCL 1177 // Disabling NCCL path when CUDA virtual devices are in use since NCCL requires one distinct physical GPU per rank. 1178 const ggml_cuda_device_info & info = ggml_cuda_info(); 1179 if (info.device_count > info.physical_device_count) { 1180 GGML_LOG_WARN("NCCL disabled: virtual devices in use; " 1181 "falling back to internal AllReduce\n"); 1182 ggml_backend_cuda_comm_init_internal(ret); 1183 return; 1184 } 1185 1186 const size_t n = ret->dev_ids.size(); 1187 ret->comms.resize(n); 1188 ncclResult_t rc = ncclCommInitAll(ret->comms.data(), (int) n, ret->dev_ids.data()); 1189 if (rc == ncclSuccess) { 1190 ret->try_allreduce = ggml_backend_cuda_comm_try_allreduce_nccl; 1191 return; 1192 } 1193 1194 ret->comms.clear(); 1195 GGML_LOG_WARN("NCCL init failed (%s); falling back to internal AllReduce\n", 1196 ncclGetErrorString(rc)); 1197#else // GGML_USE_NCCL 1198#ifndef GGML_USE_HIP 1199 GGML_LOG_WARN("NCCL not compiled in; falling back to internal AllReduce. " 1200 "Recompile with -DGGML_CUDA_NCCL=ON for best multi-GPU performance.\n"); 1201#endif // !GGML_USE_HIP 1202#endif // GGML_USE_NCCL 1203 1204 ggml_backend_cuda_comm_init_internal(ret); 1205} 1206 1207// Top-level init. Picks one of the three init paths based on 1208// GGML_CUDA_ALLREDUCE (or the platform default) and lets the chain handle 1209// any fallback. Unrecognised env values warn and fall through to the 1210// platform default. 1211static void * ggml_backend_cuda_comm_init(ggml_backend_t * backends, size_t n_backends) { 1212 for (size_t i = 0; i < n_backends; i++) { 1213 if (!ggml_backend_is_cuda(backends[i])) { 1214 return nullptr; 1215 } 1216 } 1217 1218 auto * ret = new ggml_backend_cuda_comm_context; 1219 ret->backends.assign(backends, backends + n_backends); 1220 ret->dev_ids.reserve(n_backends); 1221 for (size_t i = 0; i < n_backends; i++) { 1222 ret->dev_ids.push_back(static_cast<ggml_backend_cuda_context *>(backends[i]->context)->device); 1223 } 1224 1225 const char * env = getenv("GGML_CUDA_ALLREDUCE"); 1226 if (!env) { 1227 // Platform default: Linux uses NCCL, otherwise (generally Windows) internal 1228#if defined(__linux__) 1229 ggml_backend_cuda_comm_init_nccl(ret); 1230#else 1231 ggml_backend_cuda_comm_init_internal(ret); 1232#endif // defined(__linux__) 1233 } else { 1234 std::string env_str(env); 1235 if (env_str == "nccl") { 1236 ggml_backend_cuda_comm_init_nccl(ret); 1237 } else if (env_str == "internal") { 1238 ggml_backend_cuda_comm_init_internal(ret); 1239 } else if (env_str == "none") { 1240 ggml_backend_cuda_comm_init_none(ret); 1241 } else { 1242 GGML_LOG_WARN("unknown GGML_CUDA_ALLREDUCE value: %s\n", env); 1243 ggml_backend_cuda_comm_init_none(ret); 1244 } 1245 } 1246 1247 return ret; 1248} 1249 1250// Top-level dispatch -- calls the function pointer chosen by comm_init. 1251// Returns false to let the meta-backend's butterfly run. 1252static bool ggml_backend_cuda_comm_allreduce_tensor(void * comm_ctx_v, struct ggml_tensor ** tensors) { 1253 if (comm_ctx_v == nullptr) { 1254 return false; 1255 } 1256 auto * comm_ctx = static_cast<ggml_backend_cuda_comm_context *>(comm_ctx_v); 1257 return comm_ctx->try_allreduce(comm_ctx, tensors); 1258} 1259 1260// host buffer type 1261 1262static const char * ggml_backend_cuda_host_buffer_type_name(ggml_backend_buffer_type_t buft) { 1263 return GGML_CUDA_NAME "_Host"; 1264 1265 GGML_UNUSED(buft); 1266} 1267 1268static bool ggml_backend_buft_is_cuda_host(ggml_backend_buffer_type_t buft) { 1269 return buft->iface.get_name == ggml_backend_cuda_host_buffer_type_name; 1270} 1271 1272static void ggml_backend_cuda_host_buffer_free_buffer(ggml_backend_buffer_t buffer) { 1273 CUDA_CHECK(cudaFreeHost(buffer->context)); 1274} 1275 1276static void * ggml_cuda_host_malloc(size_t size) { 1277 if (getenv("GGML_CUDA_NO_PINNED") != nullptr) { 1278 return nullptr; 1279 } 1280 1281 void * ptr = nullptr; 1282 cudaError_t err = cudaMallocHost((void **) &ptr, size); 1283 if (err != cudaSuccess) { 1284 // clear the error 1285 (void)cudaGetLastError(); 1286 GGML_LOG_DEBUG("%s: failed to allocate %.2f MiB of pinned memory: %s\n", __func__, 1287 size / 1024.0 / 1024.0, cudaGetErrorString(err)); 1288 return nullptr; 1289 } 1290 1291 return ptr; 1292} 1293 1294static ggml_backend_buffer_t ggml_backend_cuda_host_buffer_type_alloc_buffer(ggml_backend_buffer_type_t buft, size_t size) { 1295 void * ptr = ggml_cuda_host_malloc(size); 1296 1297 if (ptr == nullptr) { 1298 // fallback to cpu buffer 1299 return ggml_backend_buft_alloc_buffer(ggml_backend_cpu_buffer_type(), size); 1300 } 1301 1302 ggml_backend_buffer_t buffer = ggml_backend_cpu_buffer_from_ptr(ptr, size); 1303 buffer->buft = buft; 1304 buffer->iface.free_buffer = ggml_backend_cuda_host_buffer_free_buffer; 1305 1306 return buffer; 1307} 1308 1309ggml_backend_buffer_type_t ggml_backend_cuda_host_buffer_type() { 1310 static struct ggml_backend_buffer_type ggml_backend_cuda_buffer_type_host = { 1311 /* .iface = */ { 1312 /* .get_name = */ ggml_backend_cuda_host_buffer_type_name, 1313 /* .alloc_buffer = */ ggml_backend_cuda_host_buffer_type_alloc_buffer, 1314 /* .get_alignment = */ ggml_backend_cpu_buffer_type()->iface.get_alignment, 1315 /* .get_max_size = */ NULL, // defaults to SIZE_MAX 1316 /* .get_alloc_size = */ ggml_backend_cpu_buffer_type()->iface.get_alloc_size, 1317 /* .is_host = */ ggml_backend_cpu_buffer_type()->iface.is_host, 1318 }, 1319 /* .device = */ ggml_backend_reg_dev_get(ggml_backend_cuda_reg(), 0), 1320 /* .context = */ nullptr, 1321 }; 1322 1323 return &ggml_backend_cuda_buffer_type_host; 1324} 1325 1326//static bool ggml_backend_buffer_is_cuda_host(ggml_backend_buffer_t buffer) { 1327// return buffer->buft->iface.get_name == ggml_backend_cuda_host_buffer_type_name; 1328//} 1329 1330/// kernels 1331 1332typedef void (*ggml_cuda_op_mul_mat_t)( 1333 ggml_backend_cuda_context & ctx, 1334 const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst, const char * src0_dd_i, const float * src1_ddf_i, 1335 const char * src1_ddq_i, float * dst_dd_i, const int64_t row_low, const int64_t row_high, const int64_t src1_ncols, 1336 const int64_t src1_padded_row_size, cudaStream_t stream); 1337 1338static __global__ void k_compute_batched_ptrs( 1339 const void * src0_as_f16, const void * src1_as_f16, char * dst, 1340 const void ** ptrs_src, void ** ptrs_dst, 1341 int64_t ne12, int64_t ne13, 1342 int64_t ne23, 1343 size_t nb02, size_t nb03, 1344 size_t nb12, size_t nb13, 1345 size_t nbd2, size_t nbd3, 1346 int64_t r2, int64_t r3) { 1347 const int64_t i13 = blockIdx.x * blockDim.x + threadIdx.x; 1348 const int64_t i12 = blockIdx.y * blockDim.y + threadIdx.y; 1349 1350 if (i13 >= ne13 || i12 >= ne12) { 1351 return; 1352 } 1353 1354 const int64_t i03 = i13 / r3; 1355 const int64_t i02 = i12 / r2; 1356 1357 ptrs_src[0*ne23 + i12 + i13*ne12] = (const char *) src0_as_f16 + i02*nb02 + i03*nb03; 1358 ptrs_src[1*ne23 + i12 + i13*ne12] = (const char *) src1_as_f16 + i12*nb12 + i13*nb13; 1359 ptrs_dst[0*ne23 + i12 + i13*ne12] = ( char *) dst + i12*nbd2 + i13*nbd3; 1360} 1361 1362// Type traits for mapping ggml types to CUDA/cuBLAS types 1363template<ggml_type T> 1364struct batched_mul_mat_traits; 1365 1366template<> 1367struct batched_mul_mat_traits<GGML_TYPE_F32> { 1368 using cuda_type = float; 1369 static inline const cublasComputeType_t compute_type = CUBLAS_COMPUTE_32F; 1370 static inline const cudaDataType_t data_type = CUDA_R_32F; 1371 static inline const ggml_type ggml_type_val = GGML_TYPE_F32; 1372 static inline const float alpha = 1.0f; 1373 static inline const float beta = 0.0f; 1374 static inline const void* get_alpha() { static const float val = alpha; return &val; } 1375 static inline const void* get_beta() { static const float val = beta; return &val; } 1376 static inline auto convert(ggml_type src_type) { return ggml_get_to_fp32_cuda(src_type); } 1377 static inline auto convert_nc(ggml_type src_type) { return ggml_get_to_fp32_nc_cuda(src_type); } 1378}; 1379 1380template<> 1381struct batched_mul_mat_traits<GGML_TYPE_BF16> { 1382 using cuda_type = nv_bfloat16; 1383 static inline const cublasComputeType_t compute_type = CUBLAS_COMPUTE_32F; 1384 static inline const cudaDataType_t data_type = CUDA_R_16BF; 1385 static inline const ggml_type ggml_type_val = GGML_TYPE_BF16; 1386 static inline const float alpha = 1.0f; 1387 static inline const float beta = 0.0f; 1388 static inline const void* get_alpha() { static const float val = alpha; return &val; } 1389 static inline const void* get_beta() { static const float val = beta; return &val; } 1390 static inline auto convert(ggml_type src_type) { return ggml_get_to_bf16_cuda(src_type); } 1391 static inline auto convert_nc(ggml_type src_type) { return ggml_get_to_bf16_nc_cuda(src_type); } 1392}; 1393 1394template<> 1395struct batched_mul_mat_traits<GGML_TYPE_F16> { 1396 using cuda_type = half; 1397 static inline const cublasComputeType_t compute_type = CUBLAS_COMPUTE_16F; 1398 static inline const cudaDataType_t data_type = CUDA_R_16F; 1399 static inline const ggml_type ggml_type_val = GGML_TYPE_F16; 1400 static inline const half alpha = 1.0; 1401 static inline const half beta = 0.0; 1402 static inline const void* get_alpha() { static const half val = alpha; return &val; } 1403 static inline const void* get_beta() { static const half val = beta; return &val; } 1404 static inline auto convert(ggml_type src_type) { return ggml_get_to_fp16_cuda(src_type); } 1405 static inline auto convert_nc(ggml_type src_type) { return ggml_get_to_fp16_nc_cuda(src_type); } 1406}; 1407 1408template<ggml_type compute_type> 1409static void ggml_cuda_mul_mat_cublas_impl(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) { 1410 using traits = batched_mul_mat_traits<compute_type>; 1411 using cuda_t = typename traits::cuda_type; 1412 1413 GGML_ASSERT(ggml_is_contiguous(dst)); 1414 1415 // Byte offsets and tensor dimensions are currently used in an inconsistent way for dst. 1416 // As long as dst is contiguous this does not matter though. 1417 1418 GGML_TENSOR_BINARY_OP_LOCALS 1419 1420 const int64_t ne_dst = ggml_nelements(dst); 1421 cudaStream_t main_stream = ctx.stream(); 1422 cublasHandle_t cublas_h = ctx.cublas_handle(); 1423 1424 const size_t src0_ts = ggml_type_size(src0->type); 1425 GGML_ASSERT(nb00 == src0_ts); 1426 int64_t s01 = nb01 / src0_ts; 1427 int64_t s02 = nb02 / src0_ts; 1428 int64_t s03 = nb03 / src0_ts; 1429 1430 const size_t src1_ts = ggml_type_size(src1->type); 1431 GGML_ASSERT(nb10 == src1_ts); 1432 int64_t s11 = nb11 / src1_ts; 1433 int64_t s12 = nb12 / src1_ts; 1434 int64_t s13 = nb13 / src1_ts; 1435 1436 float * dst_ddf = (float *) dst->data; 1437 1438 const cuda_t * src0_ptr = nullptr; 1439 const cuda_t * src1_ptr = nullptr; 1440 1441 ggml_cuda_pool_alloc<cuda_t> src0_alloc(ctx.pool()); 1442 ggml_cuda_pool_alloc<cuda_t> src1_alloc(ctx.pool()); 1443 1444 bool is_src0_cont_2 = ggml_is_contiguous_2(src0); 1445 bool is_src1_cont_2 = ggml_is_contiguous_2(src1); 1446 1447 if (src0->type == compute_type) { 1448 src0_ptr = (const cuda_t *) src0->data; 1449 } else { 1450 src0_alloc.alloc(ggml_nelements(src0)); 1451 1452 if (ggml_is_contiguously_allocated(src0)) { 1453 const auto convert_func = traits::convert(src0->type); 1454 GGML_ASSERT(convert_func != nullptr); 1455 convert_func(src0->data, src0_alloc.get(), ggml_nelements(src0), main_stream); 1456 const size_t src0_bs = ggml_blck_size(src0->type); 1457 s01 *= src0_bs; 1458 s02 *= src0_bs; 1459 s03 *= src0_bs; 1460 } else { 1461 const auto convert_func = traits::convert_nc(src0->type); 1462 GGML_ASSERT(convert_func != nullptr); 1463 convert_func(src0->data, src0_alloc.get(), ne00, ne01, ne02, ne03, s01, s02, s03, main_stream); 1464 s01 = ne00; 1465 s02 = ne01*s01; 1466 s03 = ne02*s02; 1467 is_src0_cont_2 = true; 1468 } 1469 src0_ptr = src0_alloc.get(); 1470 } 1471 1472 if (src1->type == compute_type) { 1473 src1_ptr = (const cuda_t *) src1->data; 1474 } else { 1475 src1_alloc.alloc(ggml_nelements(src1)); 1476 1477 if (ggml_is_contiguously_allocated(src1)) { 1478 const auto convert_func = traits::convert(src1->type); 1479 GGML_ASSERT(convert_func != nullptr); 1480 convert_func(src1->data, src1_alloc.get(), ggml_nelements(src1), main_stream); 1481 const size_t src1_bs = ggml_blck_size(src1->type); 1482 s11 *= src1_bs; 1483 s12 *= src1_bs; 1484 s13 *= src1_bs; 1485 } else { 1486 const auto convert_func = traits::convert_nc(src1->type); 1487 GGML_ASSERT(convert_func != nullptr); 1488 convert_func(src1->data, src1_alloc.get(), ne10, ne11, ne12, ne13, s11, s12, s13, main_stream); 1489 s11 = ne10; 1490 s12 = ne11*s11; 1491 s13 = ne12*s12; 1492 is_src1_cont_2 = true; 1493 } 1494 src1_ptr = src1_alloc.get(); 1495 } 1496 1497 ggml_cuda_pool_alloc<cuda_t> dst_temp(ctx.pool()); 1498 char * dst_ptr; 1499 size_t nbd2 = dst->nb[2]; 1500 size_t nbd3 = dst->nb[3]; 1501 1502 cublasComputeType_t cu_compute_type = traits::compute_type; 1503 cudaDataType_t cu_data_type = traits::data_type; 1504 cudaDataType_t cu_data_type_a = traits::data_type; 1505 cudaDataType_t cu_data_type_b = traits::data_type; 1506 const void * alpha = traits::get_alpha(); 1507 const void * beta = traits::get_beta(); 1508 1509 const int cc = ggml_cuda_info().devices[ctx.device].cc; 1510 bool prefer_f32_output = false; 1511 if (compute_type == GGML_TYPE_F16) { 1512 prefer_f32_output = cc == GGML_CUDA_CC_VOLTA || GGML_CUDA_CC_IS_RDNA4(cc) || GGML_CUDA_CC_IS_CDNA(cc); 1513 } else if (compute_type == GGML_TYPE_BF16) { 1514 prefer_f32_output = !GGML_CUDA_CC_IS_RDNA3(cc) && !GGML_CUDA_CC_IS_CDNA(cc); 1515 } 1516 1517 if (prefer_f32_output) { 1518 dst_ptr = (char *) dst_ddf; 1519 cu_compute_type = batched_mul_mat_traits<GGML_TYPE_F32>::compute_type; 1520 cu_data_type = batched_mul_mat_traits<GGML_TYPE_F32>::data_type; 1521 alpha = batched_mul_mat_traits<GGML_TYPE_F32>::get_alpha(); 1522 beta = batched_mul_mat_traits<GGML_TYPE_F32>::get_beta(); 1523 } else { 1524 if constexpr (compute_type == GGML_TYPE_F32) { 1525 dst_ptr = (char *) dst_ddf; // Direct F32 output 1526 } else { 1527 dst_ptr = (char *) dst_temp.alloc(ne_dst); 1528 nbd2 /= sizeof(float) / sizeof(cuda_t); 1529 nbd3 /= sizeof(float) / sizeof(cuda_t); 1530 } 1531 } 1532 1533 GGML_ASSERT(ne12 % ne02 == 0); 1534 GGML_ASSERT(ne13 % ne03 == 0); 1535 1536 // broadcast factors 1537 const int64_t r2 = ne12/ne02; 1538 const int64_t r3 = ne13/ne03; 1539 1540 // Theoretically cublasGemmStridedBatchedEx would always work, even for a single matrix. 1541 // However, for some old NVIDIA and AMD GPUs the strided/Ex GEMM is much slower, 1542 // probably because the internal kernel selection logic is suboptimal. 1543 if (compute_type == GGML_TYPE_F32 && ne12 == 1 && ne13 == 1) { 1544 CUBLAS_CHECK( 1545 cublasSgemm(cublas_h, CUBLAS_OP_T, CUBLAS_OP_N, 1546 ne01, ne11, ne10, 1547 (const float *) alpha, (const float *) src0_ptr, s01, 1548 (const float *) src1_ptr, s11, 1549 (const float *) beta, (float *) dst_ptr, ne0)); 1550 } else if (ne12 == 1 && ne13 == 1) { 1551 CUBLAS_CHECK( 1552 cublasGemmEx(cublas_h, CUBLAS_OP_T, CUBLAS_OP_N, 1553 ne01, ne11, ne10, 1554 alpha, src0_ptr, cu_data_type_a, s01, 1555 src1_ptr, cu_data_type_b, s11, 1556 beta, dst_ptr, cu_data_type, ne0, 1557 cu_compute_type, 1558 CUBLAS_GEMM_DEFAULT_TENSOR_OP)); 1559 } else if (r2 == 1 && r3 == 1 && is_src0_cont_2 && is_src1_cont_2) { 1560 // with a [0, 2, 1, 3] perm. and ne02==1 the matrix strides need to be determined from dim 3: 1561 const int64_t sma = ne02 == 1 ? s03 : s02; 1562 const int64_t smb = ne12 == 1 ? s13 : s12; 1563 1564 // there is no broadcast and src0, src1 are contiguous across dims 2, 3 1565 // use cublasGemmStridedBatchedEx 1566 CUBLAS_CHECK( 1567 cublasGemmStridedBatchedEx(cublas_h, CUBLAS_OP_T, CUBLAS_OP_N, 1568 ne01, ne11, ne10, 1569 alpha, src0_ptr, cu_data_type_a, s01, sma, // strideA 1570 src1_ptr, cu_data_type_b, s11, smb, // strideB 1571 beta, dst_ptr, cu_data_type, ne0, ne1*ne0, // strideC 1572 ne12*ne13, 1573 cu_compute_type, 1574 CUBLAS_GEMM_DEFAULT_TENSOR_OP)); 1575 } else { 1576 // use cublasGemmBatchedEx 1577 const int64_t ne23 = ne12*ne13; 1578 1579 ggml_cuda_pool_alloc<const void *> ptrs_src(ctx.pool(), 2*ne23); 1580 ggml_cuda_pool_alloc< void *> ptrs_dst(ctx.pool(), 1*ne23); 1581 1582 const size_t src_type_size = sizeof(cuda_t); 1583 1584 const int threads_x = 16; 1585 const int threads_y = 16; 1586 const dim3 block_dims(threads_x, threads_y); 1587 1588 const dim3 grid_dims( 1589 (ne13 + threads_x - 1) / threads_x, 1590 (ne12 + threads_y - 1) / threads_y 1591 ); 1592 k_compute_batched_ptrs<<<grid_dims, block_dims, 0, main_stream>>>( 1593 src0_ptr, src1_ptr, dst_ptr, 1594 ptrs_src.get(), ptrs_dst.get(), 1595 ne12, ne13, 1596 ne23, 1597 s02*src_type_size, s03*src_type_size, 1598 s12*src_type_size, s13*src_type_size, 1599 nbd2, nbd3, 1600 r2, r3); 1601 1602 CUDA_CHECK(cudaGetLastError()); 1603 1604 CUBLAS_CHECK( 1605 cublasGemmBatchedEx(cublas_h, CUBLAS_OP_T, CUBLAS_OP_N, 1606 ne01, ne11, ne10, 1607 alpha, (const void **) (ptrs_src.get() + 0*ne23), cu_data_type_a, s01, 1608 (const void **) (ptrs_src.get() + 1*ne23), cu_data_type_b, s11, 1609 beta, ( void **) (ptrs_dst.get() + 0*ne23), cu_data_type, ne0, 1610 ne23, 1611 cu_compute_type, 1612 CUBLAS_GEMM_DEFAULT_TENSOR_OP)); 1613 } 1614 1615 // Convert output back to F32 if needed 1616 if (cu_data_type != CUDA_R_32F) { 1617 const to_fp32_cuda_t to_fp32_cuda = ggml_get_to_fp32_cuda(traits::ggml_type_val); 1618 to_fp32_cuda(dst_temp.get(), dst_ddf, ne_dst, main_stream); 1619 } 1620} 1621 1622static void ggml_cuda_mul_mat_cublas(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) { 1623 const int cc = ggml_cuda_info().devices[ctx.device].cc; 1624 ggml_type compute_type = src0->type; 1625 if (ggml_is_quantized(compute_type)) { 1626 compute_type = fast_fp16_hardware_available(cc) ? GGML_TYPE_F16 : GGML_TYPE_F32; 1627 } else if (compute_type == GGML_TYPE_F16 && !fast_fp16_hardware_available(cc)) { 1628 compute_type = GGML_TYPE_F32; 1629 } else if (compute_type == GGML_TYPE_BF16 && !fast_bf16_hardware_available(cc)) { 1630 if (GGML_CUDA_CC_IS_AMD(cc) && src1->ne[1] > 32) { 1631 compute_type = GGML_TYPE_F32; 1632 } 1633 if (GGML_CUDA_CC_IS_NVIDIA(cc) && src1->ne[1] > (cc >= GGML_CUDA_CC_VOLTA ? 8 : 128)) { 1634 compute_type = GGML_TYPE_F32; 1635 } 1636 } 1637 if (dst->op_params[0] == GGML_PREC_F32) { 1638 compute_type = GGML_TYPE_F32; 1639 } 1640 1641 const char * env_c = getenv("GGML_CUDA_CUBLAS_COMPUTE_TYPE"); 1642 if (env_c != nullptr) { 1643 std::string env_cpp = env_c; 1644 for (char & c : env_cpp) { 1645 c = std::tolower(c); 1646 } 1647 if (env_cpp == "f32" || env_cpp == "fp32") { 1648 compute_type = GGML_TYPE_F32; 1649 } else if (env_cpp == "f16" || env_cpp == "fp16") { 1650 compute_type = GGML_TYPE_F16; 1651 } else if (env_cpp == "bf16") { 1652 compute_type = GGML_TYPE_BF16; 1653 } else if (env_cpp != "auto") { 1654 GGML_LOG_WARN("%s: unknown value for GGML_CUDA_CUBLAS_COMPUTE_TYPE: %s", __func__, env_cpp.c_str()); 1655 } 1656 } 1657 1658 switch (compute_type) { 1659 case GGML_TYPE_F32: 1660 ggml_cuda_mul_mat_cublas_impl<GGML_TYPE_F32>(ctx, src0, src1, dst); 1661 break; 1662 case GGML_TYPE_BF16: 1663 ggml_cuda_mul_mat_cublas_impl<GGML_TYPE_BF16>(ctx, src0, src1, dst); 1664 break; 1665 case GGML_TYPE_F16: 1666 ggml_cuda_mul_mat_cublas_impl<GGML_TYPE_F16>(ctx, src0, src1, dst); 1667 break; 1668 default: 1669 GGML_ABORT("fatal error"); 1670 } 1671} 1672 1673static bool ggml_cuda_should_fuse_mul_mat(const ggml_tensor * ffn_up, 1674 const ggml_tensor * ffn_gate, 1675 const ggml_tensor * glu, 1676 const ggml_tensor * ffn_up_bias = nullptr, 1677 const ggml_tensor * ffn_gate_bias = nullptr, 1678 const ggml_tensor * ffn_up_scale = nullptr, 1679 const ggml_tensor * ffn_gate_scale = nullptr) { 1680 const bool has_bias = ffn_up_bias != nullptr || ffn_gate_bias != nullptr; 1681 const bool has_scale = ffn_up_scale != nullptr || ffn_gate_scale != nullptr; 1682 1683 if (has_bias && (!ffn_up_bias || !ffn_gate_bias)) { 1684 return false; 1685 } 1686 if (has_scale && (!ffn_up_scale || !ffn_gate_scale)) { 1687 return false; 1688 } 1689 1690 const bool is_mul_mat = ffn_up->op == GGML_OP_MUL_MAT && ffn_gate->op == GGML_OP_MUL_MAT && glu->op == GGML_OP_GLU; 1691 const bool is_mul_mat_id = ffn_up->op == GGML_OP_MUL_MAT_ID && ffn_gate->op == GGML_OP_MUL_MAT_ID && glu->op == GGML_OP_GLU; 1692 1693 GGML_ASSERT(ffn_up && ffn_gate && glu); 1694 1695 if (!is_mul_mat && !is_mul_mat_id) { 1696 return false; 1697 } 1698 1699 const ggml_op expected_bias_op = is_mul_mat ? GGML_OP_ADD : GGML_OP_ADD_ID; 1700 const ggml_tensor * ffn_up_bias_src = has_scale ? ffn_up_scale : ffn_up; 1701 const ggml_tensor * ffn_gate_bias_src = has_scale ? ffn_gate_scale : ffn_gate; 1702 const ggml_tensor * ffn_up_out = has_bias ? ffn_up_bias : ffn_up_bias_src; 1703 const ggml_tensor * ffn_gate_out = has_bias ? ffn_gate_bias : ffn_gate_bias_src; 1704 1705 if (glu->src[0] != ffn_gate_out || glu->src[1] != ffn_up_out) { 1706 return false; 1707 } 1708 1709 if (has_scale) { 1710 if (ffn_up_scale->op != GGML_OP_MUL || ffn_gate_scale->op != GGML_OP_MUL) { 1711 return false; 1712 } 1713 const bool up_has_mm = ffn_up_scale->src[0] == ffn_up || ffn_up_scale->src[1] == ffn_up; 1714 const bool gate_has_mm = ffn_gate_scale->src[0] == ffn_gate || ffn_gate_scale->src[1] == ffn_gate; 1715 if (!up_has_mm || !gate_has_mm) { 1716 return false; 1717 } 1718 } 1719 1720 if (has_bias) { 1721 if (ffn_up_bias->op != expected_bias_op || ffn_gate_bias->op != expected_bias_op) { 1722 return false; 1723 } 1724 1725 if (expected_bias_op == GGML_OP_ADD) { 1726 const bool up_has_mul = ffn_up_bias->src[0] == ffn_up_bias_src || ffn_up_bias->src[1] == ffn_up_bias_src; 1727 const bool gate_has_mul = ffn_gate_bias->src[0] == ffn_gate_bias_src || ffn_gate_bias->src[1] == ffn_gate_bias_src; 1728 if (!up_has_mul || !gate_has_mul) { 1729 return false; 1730 } 1731 } else { // GGML_OP_ADD_ID 1732 if (ffn_up_bias->src[0] != ffn_up_bias_src || ffn_gate_bias->src[0] != ffn_gate_bias_src) { 1733 return false; 1734 } 1735 if (ffn_up_bias->src[2] != ffn_up->src[2] || ffn_gate_bias->src[2] != ffn_gate->src[2]) { 1736 return false; 1737 } 1738 } 1739 } 1740 1741 if (ffn_up->src[0]->type != ffn_gate->src[0]->type || !ggml_are_same_shape(ffn_up->src[0], ffn_gate->src[0]) || 1742 !ggml_are_same_stride(ffn_up->src[0], ffn_gate->src[0])) { 1743 return false; 1744 } 1745 1746 if (ffn_up->src[1] != ffn_gate->src[1]) { 1747 return false; 1748 } 1749 1750 if (is_mul_mat_id && ffn_up->src[2] != ffn_gate->src[2]) { 1751 return false; 1752 } 1753 1754 static constexpr std::array<ggml_glu_op, 4> valid_glu_ops = { GGML_GLU_OP_SWIGLU, GGML_GLU_OP_GEGLU, GGML_GLU_OP_SWIGLU_OAI, GGML_GLU_OP_SWIGLU_CLAMP }; 1755 1756 if (std::find(valid_glu_ops.begin(), valid_glu_ops.end(), ggml_get_glu_op(glu)) == valid_glu_ops.end()) { 1757 return false; 1758 } 1759 1760 if (const bool swapped = ggml_get_op_params_i32(glu, 1); swapped) { 1761 return false; 1762 } 1763 1764 return true; 1765} 1766 1767static bool ggml_cuda_should_fuse_mul_mat_vec_f(const ggml_tensor * tensor) { 1768 ggml_tensor * src0 = tensor->src[0]; 1769 ggml_tensor * src1 = tensor->src[1]; 1770 const ggml_tensor * dst = tensor; 1771 1772 const bool is_mul_mat_id = tensor->op == GGML_OP_MUL_MAT_ID; 1773 1774 bool use_mul_mat_vec_f = 1775 (src0->type == GGML_TYPE_F32 || src0->type == GGML_TYPE_F16 || src0->type == GGML_TYPE_BF16) && 1776 src1->type == GGML_TYPE_F32 && dst->type == GGML_TYPE_F32; 1777 1778 const int cc = ggml_cuda_info().devices[ggml_cuda_get_device()].cc; 1779 use_mul_mat_vec_f = use_mul_mat_vec_f && ggml_cuda_should_use_mmvf(src0->type, cc, src0->ne, src0->nb, is_mul_mat_id ? src1->ne[2] : src1->ne[1]); 1780 1781 //we only support fusion for ncols_dst = 1 1782 if (tensor->op == GGML_OP_MUL_MAT && dst->ne[1] != 1) { 1783 return false; 1784 } 1785 1786 if (tensor->op == GGML_OP_MUL_MAT_ID && dst->ne[2] != 1) { 1787 return false; 1788 } 1789 1790 1791 return use_mul_mat_vec_f; 1792} 1793 1794static bool ggml_cuda_should_fuse_mul_mat_vec_q(const ggml_tensor * tensor) { 1795 ggml_tensor * src0 = tensor->src[0]; 1796 ggml_tensor * src1 = tensor->src[1]; 1797 const ggml_tensor * dst = tensor; 1798 1799 const bool bad_padding_clear = ggml_backend_buffer_get_usage(src0->buffer) == GGML_BACKEND_BUFFER_USAGE_COMPUTE && 1800 ggml_nbytes(src0) != ggml_backend_buffer_get_alloc_size(src0->buffer, src0) && 1801 src0->view_src; 1802 1803 bool use_mul_mat_vec_q = ggml_is_quantized(src0->type) && !bad_padding_clear && src1->type == GGML_TYPE_F32 && 1804 dst->type == GGML_TYPE_F32 && src1->ne[1] <= MMVQ_MAX_BATCH_SIZE; 1805 1806 // fusion is not universally faster on Pascal 1807 const int cc = ggml_cuda_info().devices[ggml_cuda_get_device()].cc; 1808 if (cc <= GGML_CUDA_CC_PASCAL) { 1809 return false; 1810 } 1811 //we only support fusion for ncols_dst = 1 1812 if (tensor->op == GGML_OP_MUL_MAT && dst->ne[1] != 1) { 1813 return false; 1814 } 1815 1816 if (tensor->op == GGML_OP_MUL_MAT_ID && dst->ne[2] > get_mmvq_mmid_max_batch(src0->type, cc)) { 1817 return false; 1818 } 1819 1820 return use_mul_mat_vec_q; 1821} 1822 1823static void ggml_cuda_mul_mat(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) { 1824 GGML_TENSOR_BINARY_OP_LOCALS 1825 1826 const int32_t hint = ggml_get_op_params_i32(dst, 1); 1827 if (hint == GGML_HINT_SRC0_IS_HADAMARD && ggml_cuda_op_fwht(ctx, src1, dst)) { 1828 return; 1829 } 1830 1831 // If src0 is a temporary compute buffer it may have some padding that needs to be cleared for mul_mat_vec_q or mul_mat_q. 1832 // But if src0 is also a view of another tensor then this cannot be done safely because it may overwrite valid tensor data. 1833 // Therefore, in such cases use cuBLAS. 1834 const bool bad_padding_clear = ggml_backend_buffer_get_usage(src0->buffer) == GGML_BACKEND_BUFFER_USAGE_COMPUTE 1835 && ggml_nbytes(src0) != ggml_backend_buffer_get_alloc_size(src0->buffer, src0) && src0->view_src; 1836 if (bad_padding_clear || src1->type != GGML_TYPE_F32 || dst->type != GGML_TYPE_F32) { 1837 ggml_cuda_mul_mat_cublas(ctx, src0, src1, dst); 1838 return; 1839 } 1840 1841 const int cc = ggml_cuda_info().devices[ctx.device].cc; 1842 const int warp_size = ggml_cuda_info().devices[ctx.device].warp_size; 1843 1844 if (ggml_cuda_should_use_mmvf(src0->type, cc, src0->ne, src0->nb, ne11)) { 1845 // The custom F16 vector kernel can be used over batched cuBLAS GEMM. 1846 // But this is only faster for GPUs without tensor cores or with a thin src0 matrix (particularly KQV in attention) 1847 ggml_cuda_mul_mat_vec_f(ctx, src0, src1, nullptr, dst); 1848 return; 1849 } 1850 // A transposed vector can still use MMVQ (i.e. ne01 == 1) 1851 if (ne01 == 1 && ne11 > MMVF_MAX_BATCH_SIZE && ne2 == 1 && ne3 == 1 1852 && src0->type == GGML_TYPE_F32 1853 && ggml_is_contiguous(src0) && ggml_is_contiguous(src1) && ggml_is_contiguous(dst) 1854 && ggml_cuda_should_use_mmvf(src1->type, cc, src1->ne, src1->nb, /*ne11 =*/ 1)) { 1855 ggml_tensor dst_vec = *dst; 1856 dst_vec.ne[0] = ne11; 1857 dst_vec.ne[1] = 1; 1858 dst_vec.nb[1] = dst_vec.nb[0]*ne11; 1859 dst_vec.nb[2] = dst_vec.nb[1]; 1860 dst_vec.nb[3] = dst_vec.nb[1]; 1861 ggml_cuda_mul_mat_vec_f(ctx, src1, src0, nullptr, &dst_vec); 1862 return; 1863 } 1864 if (ggml_cuda_should_use_mmf(src0->type, cc, warp_size, src0->ne, src0->nb, ne11, /*mul_mat_id =*/ false)) { 1865 ggml_cuda_mul_mat_f(ctx, src0, src1, nullptr, dst); 1866 return; 1867 } 1868 if (ggml_cuda_should_use_mmvq(src0->type, cc, ne11)) { 1869 ggml_cuda_mul_mat_vec_q(ctx, src0, src1, nullptr, dst); 1870 return; 1871 } 1872 if (ggml_cuda_should_use_mmq(src0->type, cc, ne11, /*n_experts =*/ 0)) { 1873 ggml_cuda_mul_mat_q(ctx, src0, src1, nullptr, dst); 1874 return; 1875 } 1876 ggml_cuda_mul_mat_cublas(ctx, src0, src1, dst); 1877} 1878 1879// returns true when ggml_cuda_mul_mat_id takes the fallback path that requires stream synchronization 1880// [TAG_MUL_MAT_ID_CUDA_GRAPHS] 1881static bool ggml_cuda_mul_mat_id_needs_sync(const ggml_tensor * dst, const int cc) { 1882 const ggml_tensor * src0 = dst->src[0]; 1883 const ggml_tensor * src1 = dst->src[1]; 1884 1885 if (src1->type != GGML_TYPE_F32 || dst->type != GGML_TYPE_F32) { 1886 return true; 1887 } 1888 1889 if (dst->ne[2] <= MMVQ_MAX_BATCH_SIZE) { 1890 if (ggml_is_quantized(src0->type)) { 1891 if (dst->ne[2] <= get_mmvq_mmid_max_batch(src0->type, cc)) { 1892 return false; 1893 } 1894 } else if (GGML_CUDA_CC_IS_AMD(cc)) { 1895 return false; 1896 } 1897 } 1898 1899 if (ggml_cuda_should_use_mmq(src0->type, cc, src1->ne[2], /*n_experts=*/src0->ne[2])) { 1900 return false; 1901 } 1902 1903 if (ggml_cuda_should_use_mmf(src0->type, cc, WARP_SIZE, src0->ne, src0->nb, src1->ne[2], /*mul_mat_id=*/true)) { 1904 return false; 1905 } 1906 1907 return true; 1908} 1909 1910static void ggml_cuda_mul_mat_id(ggml_backend_cuda_context & ctx, ggml_tensor * dst) { 1911 const ggml_tensor * src0 = dst->src[0]; 1912 const ggml_tensor * src1 = dst->src[1]; 1913 const ggml_tensor * ids = dst->src[2]; 1914 1915 GGML_ASSERT(src1->type == GGML_TYPE_F32); 1916 GGML_ASSERT(dst->type == GGML_TYPE_F32); 1917 1918 GGML_TENSOR_BINARY_OP_LOCALS 1919 1920 const int cc = ggml_cuda_info().devices[ggml_cuda_get_device()].cc; 1921 1922 // [TAG_MUL_MAT_ID_CUDA_GRAPHS] 1923 if (src1->type == GGML_TYPE_F32 && dst->type == GGML_TYPE_F32) { 1924 static_assert(MMVQ_MAX_BATCH_SIZE == MMVF_MAX_BATCH_SIZE); 1925 if (ne2 <= MMVQ_MAX_BATCH_SIZE) { 1926 if (ggml_is_quantized(src0->type)) { 1927 const int mmvq_mmid_max = get_mmvq_mmid_max_batch(src0->type, cc); 1928 if (ne2 <= mmvq_mmid_max) { 1929 ggml_cuda_mul_mat_vec_q(ctx, src0, src1, ids, dst); 1930 return; 1931 } 1932 } else { 1933 if (GGML_CUDA_CC_IS_AMD(cc)) { 1934 ggml_cuda_mul_mat_vec_f(ctx, src0, src1, ids, dst); 1935 return; 1936 } 1937 } 1938 } 1939 1940 if (ggml_cuda_should_use_mmq(src0->type, cc, ne12, /*n_experts=*/ne02)) { 1941 ggml_cuda_mul_mat_q(ctx, src0, src1, ids, dst); 1942 return; 1943 } 1944 1945 if (ggml_cuda_should_use_mmf(src0->type, cc, WARP_SIZE, src0->ne, src0->nb, src1->ne[2], /*mul_mat_id=*/true)) { 1946 ggml_cuda_mul_mat_f(ctx, src0, src1, ids, dst); 1947 return; 1948 } 1949 } 1950 1951 // note: this path should not be reached when recording CUDA graphs, because it requires stream synchronization 1952 GGML_ASSERT(ggml_cuda_mul_mat_id_needs_sync(dst, cc)); 1953 cudaStream_t stream = ctx.stream(); 1954 1955 GGML_ASSERT(nb12 % nb11 == 0); 1956 GGML_ASSERT(nb2 % nb1 == 0); 1957 1958 const ggml_type type_src1_sorted = (src0->type == GGML_TYPE_F16 && !fast_fp16_hardware_available(cc)) 1959 || ggml_is_quantized(src0->type) ? GGML_TYPE_F32 : src0->type; 1960 const ggml_type type_dst_sorted = GGML_TYPE_F32; 1961 const size_t ts_src1_sorted = ggml_type_size(type_src1_sorted); 1962 const size_t ts_dst_sorted = ggml_type_size(type_dst_sorted); 1963 1964 const int64_t n_expert_used = ids->ne[0]; 1965 const int64_t ne_get_rows = ne12 * n_expert_used; 1966 1967 std::vector<int32_t> ids_to_sorted_host; 1968 ids_to_sorted_host.reserve(2*ne_get_rows); 1969 std::vector<int32_t> ids_from_sorted_host(ne_get_rows); 1970 1971 ggml_cuda_pool_alloc<int32_t> ids_buf_dev(ctx.pool(), 2*ne_get_rows); 1972 1973 std::vector<int32_t> tokens_per_expert(ne02); 1974 1975 ggml_cuda_pool_alloc<char> src1_sorted(ctx.pool(), ne12*n_expert_used*ne10*ts_src1_sorted); 1976 ggml_cuda_pool_alloc<char> dst_sorted(ctx.pool(), ne2 *n_expert_used* ne0*ts_dst_sorted); 1977 1978 std::vector<char> ids_host(ggml_nbytes(ids)); 1979 CUDA_CHECK(cudaMemcpyAsync(ids_host.data(), ids->data, ggml_nbytes(ids), cudaMemcpyDeviceToHost, stream)); 1980 CUDA_CHECK(cudaStreamSynchronize(stream)); 1981 1982 for (int64_t i02 = 0; i02 < ne02; ++i02) { // expert matrices 1983 for (int64_t i12 = 0; i12 < ne12; ++i12) { // tokens 1984 for (int64_t iex = 0; iex < n_expert_used; ++iex) { 1985 const int32_t expert_to_use = *(const int32_t *)(ids_host.data() + i12*ids->nb[1] + iex*ids->nb[0]); 1986 assert(expert_to_use >= 0 && expert_to_use < ne02); 1987 if (expert_to_use == i02) { 1988 ids_from_sorted_host[i12*n_expert_used + iex] = ids_to_sorted_host.size(); 1989 ids_to_sorted_host.push_back(i12*ne11 + iex % ne11); 1990 tokens_per_expert[i02]++; 1991 break; 1992 } 1993 } 1994 } 1995 } 1996 GGML_ASSERT(ids_to_sorted_host.size() == size_t(ne_get_rows)); 1997 1998 ids_to_sorted_host.insert(ids_to_sorted_host.end(), ids_from_sorted_host.begin(), ids_from_sorted_host.end()); 1999 2000 CUDA_CHECK(cudaMemcpyAsync(ids_buf_dev.ptr, ids_to_sorted_host.data(), 2*ne_get_rows*sizeof(int32_t), cudaMemcpyHostToDevice, stream)); 2001 CUDA_CHECK(cudaStreamSynchronize(stream)); 2002 2003 const int32_t * ids_to_sorted = ids_buf_dev.ptr + 0*ne_get_rows; 2004 const int32_t * ids_from_sorted = ids_buf_dev.ptr + 1*ne_get_rows; 2005 2006 get_rows_cuda(src1->data, src1->type, ids_to_sorted, src1_sorted.ptr, type_src1_sorted, 2007 ne10, nb11, nb12, nb13, 2008 ne_get_rows, 1, 1, sizeof(int32_t), ne_get_rows*sizeof(int32_t), ne_get_rows*sizeof(int32_t), 2009 ne10*ts_src1_sorted, ne_get_rows*ne10*ts_src1_sorted, ne_get_rows*ne10*ts_src1_sorted, stream); 2010 CUDA_CHECK(cudaGetLastError()); 2011 2012 char * src1_data_cur = (char *) src1_sorted.ptr; 2013 char * dst_data_cur = (char *) dst_sorted.ptr; 2014 for (int64_t i02 = 0; i02 < ne02; ++i02) { 2015 if (tokens_per_expert[i02] == 0) { 2016 continue; 2017 } 2018 2019 ggml_tensor src0_slice = *src0; 2020 src0_slice.ne[2] = 1; 2021 src0_slice.nb[3] = src0_slice.nb[2]; 2022 src0_slice.op = GGML_OP_VIEW; 2023 src0_slice.view_src = dst->src[0]; // non-const pointer to src0 2024 src0_slice.data = (char *) src0->data + i02*nb02; 2025 2026 ggml_tensor src1_slice; 2027 memset(&src1_slice, 0, sizeof(src1_slice)); 2028 src1_slice.buffer = src1->buffer; 2029 src1_slice.type = type_src1_sorted; 2030 src1_slice.ne[0] = ne10; 2031 src1_slice.ne[1] = tokens_per_expert[i02]; 2032 src1_slice.ne[2] = 1; 2033 src1_slice.ne[3] = 1; 2034 src1_slice.nb[0] = ts_src1_sorted; 2035 src1_slice.nb[1] = src1_slice.ne[0] * src1_slice.nb[0]; 2036 src1_slice.nb[2] = src1_slice.ne[1] * src1_slice.nb[1]; 2037 src1_slice.nb[3] = src1_slice.ne[2] * src1_slice.nb[2]; 2038 src1_slice.data = src1_data_cur; 2039 2040 ggml_tensor dst_slice; 2041 memset(&dst_slice, 0, sizeof(dst_slice)); 2042 dst_slice.buffer = dst->buffer; 2043 dst_slice.type = type_dst_sorted; 2044 dst_slice.ne[0] = ne0; 2045 dst_slice.ne[1] = tokens_per_expert[i02]; 2046 dst_slice.ne[2] = 1; 2047 dst_slice.ne[3] = 1; 2048 dst_slice.nb[0] = ts_dst_sorted; 2049 dst_slice.nb[1] = dst_slice.ne[0] * dst_slice.nb[0]; 2050 dst_slice.nb[2] = dst_slice.ne[1] * dst_slice.nb[1]; 2051 dst_slice.nb[3] = dst_slice.ne[2] * dst_slice.nb[2]; 2052 dst_slice.data = dst_data_cur; 2053 2054 ggml_cuda_mul_mat(ctx, &src0_slice, &src1_slice, &dst_slice); 2055 CUDA_CHECK(cudaGetLastError()); 2056 2057 src1_data_cur += src1_slice.nb[2]; 2058 dst_data_cur += dst_slice.nb[2]; 2059 } 2060 2061 get_rows_cuda(dst_sorted.ptr, type_dst_sorted, ids_from_sorted, dst->data, dst->type, 2062 ne0, ne0*ts_dst_sorted, ne_get_rows*ne0*ts_dst_sorted, ne_get_rows*ne0*ts_dst_sorted, 2063 ne_get_rows, 1, 1, sizeof(int32_t), ne_get_rows*sizeof(int32_t), ne_get_rows*sizeof(int32_t), 2064 nb1, nb2, nb3, stream); 2065} 2066 2067static bool ggml_cuda_compute_forward(ggml_backend_cuda_context & ctx, struct ggml_tensor * dst) { 2068 switch (dst->op) { 2069 case GGML_OP_ARGMAX: 2070 ggml_cuda_argmax(ctx, dst); 2071 break; 2072 case GGML_OP_COUNT_EQUAL: 2073 ggml_cuda_count_equal(ctx, dst); 2074 break; 2075 case GGML_OP_REPEAT: 2076 ggml_cuda_op_repeat(ctx, dst); 2077 break; 2078 case GGML_OP_REPEAT_BACK: 2079 ggml_cuda_op_repeat_back(ctx, dst); 2080 break; 2081 case GGML_OP_GET_ROWS: 2082 ggml_cuda_op_get_rows(ctx, dst); 2083 break; 2084 case GGML_OP_GET_ROWS_BACK: 2085 ggml_cuda_op_get_rows_back(ctx, dst); 2086 break; 2087 case GGML_OP_SET_ROWS: 2088 ggml_cuda_op_set_rows(ctx, dst); 2089 break; 2090 case GGML_OP_SET: 2091 ggml_cuda_op_set(ctx, dst); 2092 break; 2093 case GGML_OP_DUP: 2094 ggml_cuda_dup(ctx, dst); 2095 break; 2096 case GGML_OP_CPY: 2097 ggml_cuda_cpy(ctx, dst->src[0], dst->src[1]); 2098 break; 2099 case GGML_OP_CONT: 2100 ggml_cuda_dup(ctx, dst); 2101 break; 2102 case GGML_OP_ADD: 2103 case GGML_OP_ADD1: // TODO: more efficient implementation 2104 ggml_cuda_op_add(ctx, dst); 2105 break; 2106 case GGML_OP_ADD_ID: 2107 ggml_cuda_op_add_id(ctx, dst); 2108 break; 2109 case GGML_OP_SUB: 2110 ggml_cuda_op_sub(ctx, dst); 2111 break; 2112 case GGML_OP_ACC: 2113 ggml_cuda_op_acc(ctx, dst); 2114 break; 2115 case GGML_OP_MUL: 2116 ggml_cuda_op_mul(ctx, dst); 2117 break; 2118 case GGML_OP_DIV: 2119 ggml_cuda_op_div(ctx, dst); 2120 break; 2121 case GGML_OP_UNARY: 2122 switch (ggml_get_unary_op(dst)) { 2123 case GGML_UNARY_OP_ABS: 2124 ggml_cuda_op_abs(ctx, dst); 2125 break; 2126 case GGML_UNARY_OP_SGN: 2127 ggml_cuda_op_sgn(ctx, dst); 2128 break; 2129 case GGML_UNARY_OP_NEG: 2130 ggml_cuda_op_neg(ctx, dst); 2131 break; 2132 case GGML_UNARY_OP_STEP: 2133 ggml_cuda_op_step(ctx, dst); 2134 break; 2135 case GGML_UNARY_OP_GELU: 2136 ggml_cuda_op_gelu(ctx, dst); 2137 break; 2138 case GGML_UNARY_OP_SILU: 2139 ggml_cuda_op_silu(ctx, dst); 2140 break; 2141 case GGML_UNARY_OP_GELU_ERF: 2142 ggml_cuda_op_gelu_erf(ctx, dst); 2143 break; 2144 case GGML_UNARY_OP_GELU_QUICK: 2145 ggml_cuda_op_gelu_quick(ctx, dst); 2146 break; 2147 case GGML_UNARY_OP_TANH: 2148 ggml_cuda_op_tanh(ctx, dst); 2149 break; 2150 case GGML_UNARY_OP_RELU: 2151 ggml_cuda_op_relu(ctx, dst); 2152 break; 2153 case GGML_UNARY_OP_SIGMOID: 2154 ggml_cuda_op_sigmoid(ctx, dst); 2155 break; 2156 case GGML_UNARY_OP_HARDSIGMOID: 2157 ggml_cuda_op_hardsigmoid(ctx, dst); 2158 break; 2159 case GGML_UNARY_OP_HARDSWISH: 2160 ggml_cuda_op_hardswish(ctx, dst); 2161 break; 2162 case GGML_UNARY_OP_EXP: 2163 ggml_cuda_op_exp(ctx, dst); 2164 break; 2165 case GGML_UNARY_OP_ELU: 2166 ggml_cuda_op_elu(ctx, dst); 2167 break; 2168 case GGML_UNARY_OP_XIELU: 2169 ggml_cuda_op_xielu(ctx, dst); 2170 break; 2171 case GGML_UNARY_OP_FLOOR: 2172 ggml_cuda_op_floor(ctx, dst); 2173 break; 2174 case GGML_UNARY_OP_CEIL: 2175 ggml_cuda_op_ceil(ctx, dst); 2176 break; 2177 case GGML_UNARY_OP_ROUND: 2178 ggml_cuda_op_round(ctx, dst); 2179 break; 2180 case GGML_UNARY_OP_TRUNC: 2181 ggml_cuda_op_trunc(ctx, dst); 2182 break; 2183 case GGML_UNARY_OP_EXPM1: 2184 ggml_cuda_op_expm1(ctx, dst); 2185 break; 2186 case GGML_UNARY_OP_SOFTPLUS: 2187 ggml_cuda_op_softplus(ctx, dst); 2188 break; 2189 default: 2190 return false; 2191 } 2192 break; 2193 case GGML_OP_GLU: 2194 switch (ggml_get_glu_op(dst)) { 2195 case GGML_GLU_OP_REGLU: 2196 ggml_cuda_op_reglu(ctx, dst); 2197 break; 2198 case GGML_GLU_OP_GEGLU: 2199 ggml_cuda_op_geglu(ctx, dst); 2200 break; 2201 case GGML_GLU_OP_SWIGLU: 2202 ggml_cuda_op_swiglu(ctx, dst); 2203 break; 2204 case GGML_GLU_OP_SWIGLU_OAI: 2205 ggml_cuda_op_swiglu_oai(ctx, dst); 2206 break; 2207 case GGML_GLU_OP_GEGLU_ERF: 2208 ggml_cuda_op_geglu_erf(ctx, dst); 2209 break; 2210 case GGML_GLU_OP_GEGLU_QUICK: 2211 ggml_cuda_op_geglu_quick(ctx, dst); 2212 break; 2213 case GGML_GLU_OP_SWIGLU_CLAMP: 2214 ggml_cuda_op_swiglu_clamp(ctx, dst); 2215 break; 2216 default: 2217 return false; 2218 } 2219 break; 2220 case GGML_OP_NORM: 2221 ggml_cuda_op_norm(ctx, dst); 2222 break; 2223 case GGML_OP_GROUP_NORM: 2224 ggml_cuda_op_group_norm(ctx, dst); 2225 break; 2226 case GGML_OP_L2_NORM: 2227 ggml_cuda_op_l2_norm(ctx, dst); 2228 break; 2229 case GGML_OP_CONCAT: 2230 ggml_cuda_op_concat(ctx, dst); 2231 break; 2232 case GGML_OP_UPSCALE: 2233 ggml_cuda_op_upscale(ctx, dst); 2234 break; 2235 case GGML_OP_PAD: 2236 ggml_cuda_op_pad(ctx, dst); 2237 break; 2238 case GGML_OP_PAD_REFLECT_1D: 2239 ggml_cuda_op_pad_reflect_1d(ctx, dst); 2240 break; 2241 case GGML_OP_ARANGE: 2242 ggml_cuda_op_arange(ctx, dst); 2243 break; 2244 case GGML_OP_TIMESTEP_EMBEDDING: 2245 ggml_cuda_op_timestep_embedding(ctx, dst); 2246 break; 2247 case GGML_OP_LEAKY_RELU: 2248 ggml_cuda_op_leaky_relu(ctx, dst); 2249 break; 2250 case GGML_OP_SILU_BACK: 2251 ggml_cuda_op_silu_back(ctx, dst); 2252 break; 2253 case GGML_OP_RMS_NORM: 2254 ggml_cuda_op_rms_norm(ctx, dst); 2255 break; 2256 case GGML_OP_RMS_NORM_BACK: 2257 ggml_cuda_op_rms_norm_back(ctx, dst); 2258 break; 2259 case GGML_OP_MUL_MAT: 2260 ggml_cuda_mul_mat(ctx, dst->src[0], dst->src[1], dst); 2261 break; 2262 case GGML_OP_MUL_MAT_ID: 2263 ggml_cuda_mul_mat_id(ctx, dst); 2264 break; 2265 case GGML_OP_OUT_PROD: 2266 ggml_cuda_out_prod(ctx, dst); 2267 break; 2268 case GGML_OP_SCALE: 2269 ggml_cuda_op_scale(ctx, dst); 2270 break; 2271 case GGML_OP_SQR: 2272 ggml_cuda_op_sqr(ctx, dst); 2273 break; 2274 case GGML_OP_SQRT: 2275 ggml_cuda_op_sqrt(ctx, dst); 2276 break; 2277 case GGML_OP_SIN: 2278 ggml_cuda_op_sin(ctx, dst); 2279 break; 2280 case GGML_OP_COS: 2281 ggml_cuda_op_cos(ctx, dst); 2282 break; 2283 case GGML_OP_CLAMP: 2284 ggml_cuda_op_clamp(ctx, dst); 2285 break; 2286 case GGML_OP_LOG: 2287 ggml_cuda_op_log(ctx, dst); 2288 break; 2289 case GGML_OP_NONE: 2290 case GGML_OP_RESHAPE: 2291 case GGML_OP_VIEW: 2292 case GGML_OP_PERMUTE: 2293 case GGML_OP_TRANSPOSE: 2294 break; 2295 case GGML_OP_DIAG: 2296 ggml_cuda_op_diag(ctx, dst); 2297 break; 2298 case GGML_OP_DIAG_MASK_INF: 2299 ggml_cuda_op_diag_mask_inf(ctx, dst); 2300 break; 2301 case GGML_OP_SOFT_MAX: 2302 ggml_cuda_op_soft_max(ctx, dst); 2303 break; 2304 case GGML_OP_SOFT_MAX_BACK: 2305 ggml_cuda_op_soft_max_back(ctx, dst); 2306 break; 2307 case GGML_OP_ROPE: 2308 ggml_cuda_op_rope(ctx, dst); 2309 break; 2310 case GGML_OP_ROPE_BACK: 2311 ggml_cuda_op_rope_back(ctx, dst); 2312 break; 2313 case GGML_OP_ROLL: 2314 ggml_cuda_op_roll(ctx, dst); 2315 break; 2316 case GGML_OP_IM2COL: 2317 ggml_cuda_op_im2col(ctx, dst); 2318 break; 2319 case GGML_OP_IM2COL_3D: 2320 ggml_cuda_op_im2col_3d(ctx, dst); 2321 break; 2322 case GGML_OP_CONV_2D: 2323 ggml_cuda_op_conv2d(ctx, dst); 2324 break; 2325 case GGML_OP_CONV_2D_DW: 2326 ggml_cuda_op_conv2d_dw(ctx, dst); 2327 break; 2328 case GGML_OP_CONV_TRANSPOSE_2D: 2329 ggml_cuda_conv_2d_transpose_p0(ctx, dst); 2330 break; 2331 case GGML_OP_CONV_TRANSPOSE_1D: 2332 ggml_cuda_op_conv_transpose_1d(ctx,dst); 2333 break; 2334 case GGML_OP_COL2IM_1D: 2335 ggml_cuda_op_col2im_1d(ctx, dst); 2336 break; 2337 case GGML_OP_POOL_2D: 2338 ggml_cuda_op_pool2d(ctx, dst); 2339 break; 2340 case GGML_OP_POOL_1D: 2341 ggml_cuda_op_pool1d(ctx, dst); 2342 break; 2343 case GGML_OP_SUM: 2344 ggml_cuda_op_sum(ctx, dst); 2345 break; 2346 case GGML_OP_CUMSUM: 2347 ggml_cuda_op_cumsum(ctx, dst); 2348 break; 2349 case GGML_OP_SUM_ROWS: 2350 ggml_cuda_op_sum_rows(ctx, dst); 2351 break; 2352 case GGML_OP_MEAN: 2353 ggml_cuda_op_mean(ctx, dst); 2354 break; 2355 case GGML_OP_SSM_CONV: 2356 ggml_cuda_op_ssm_conv(ctx, dst); 2357 break; 2358 case GGML_OP_SSM_SCAN: 2359 ggml_cuda_op_ssm_scan(ctx, dst); 2360 break; 2361 case GGML_OP_TOP_K: 2362 ggml_cuda_op_top_k(ctx, dst); 2363 break; 2364 case GGML_OP_ARGSORT: 2365 ggml_cuda_op_argsort(ctx, dst); 2366 break; 2367 case GGML_OP_FLASH_ATTN_EXT: 2368 ggml_cuda_flash_attn_ext(ctx, dst); 2369 break; 2370 case GGML_OP_CROSS_ENTROPY_LOSS: 2371 ggml_cuda_cross_entropy_loss(ctx, dst); 2372 break; 2373 case GGML_OP_TRI: 2374 ggml_cuda_op_tri(ctx, dst); 2375 break; 2376 case GGML_OP_RWKV_WKV6: 2377 ggml_cuda_op_rwkv_wkv6(ctx, dst); 2378 break; 2379 case GGML_OP_GATED_LINEAR_ATTN: 2380 ggml_cuda_op_gated_linear_attn(ctx, dst); 2381 break; 2382 case GGML_OP_GATED_DELTA_NET: 2383 ggml_cuda_op_gated_delta_net(ctx, dst); 2384 break; 2385 case GGML_OP_DSV4_HC_COMB: 2386 ggml_cuda_op_dsv4_hc_comb(ctx, dst); 2387 break; 2388 case GGML_OP_DSV4_HC_PRE: 2389 ggml_cuda_op_dsv4_hc_pre(ctx, dst); 2390 break; 2391 case GGML_OP_DSV4_HC_POST: 2392 ggml_cuda_op_dsv4_hc_post(ctx, dst); 2393 break; 2394 case GGML_OP_RWKV_WKV7: 2395 ggml_cuda_op_rwkv_wkv7(ctx, dst); 2396 break; 2397 case GGML_OP_CROSS_ENTROPY_LOSS_BACK: 2398 ggml_cuda_cross_entropy_loss_back(ctx, dst); 2399 break; 2400 case GGML_OP_OPT_STEP_ADAMW: 2401 ggml_cuda_opt_step_adamw(ctx, dst); 2402 break; 2403 case GGML_OP_OPT_STEP_SGD: 2404 ggml_cuda_opt_step_sgd(ctx, dst); 2405 break; 2406 case GGML_OP_SOLVE_TRI: 2407 ggml_cuda_op_solve_tri(ctx, dst); 2408 break; 2409 case GGML_OP_FILL: 2410 ggml_cuda_op_fill(ctx, dst); 2411 break; 2412 case GGML_OP_LIGHTNING_INDEXER: 2413 ggml_cuda_lightning_indexer(ctx, dst); 2414 break; 2415 default: 2416 return false; 2417 } 2418 2419 cudaError_t err = cudaGetLastError(); 2420 if (err != cudaSuccess) { 2421 GGML_LOG_ERROR("%s: %s failed\n", __func__, ggml_op_desc(dst)); 2422 CUDA_CHECK(err); 2423 } 2424 2425 return true; 2426} 2427 2428//////////////////////////////////////////////////////////////////////////////// 2429 2430// backend 2431 2432static const char * ggml_backend_cuda_get_name(ggml_backend_t backend) { 2433 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *)backend->context; 2434 2435 return cuda_ctx->name.c_str(); 2436} 2437 2438static void ggml_backend_cuda_free(ggml_backend_t backend) { 2439 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *)backend->context; 2440 2441 delete cuda_ctx; 2442 delete backend; 2443} 2444 2445static void ggml_backend_cuda_set_tensor_async(ggml_backend_t backend, ggml_tensor * tensor, const void * data, size_t offset, size_t size) { 2446 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *) backend->context; 2447 ggml_backend_buffer_t buf = tensor->view_src ? tensor->view_src->buffer : tensor->buffer; 2448 2449 GGML_ASSERT(buf->buft == ggml_backend_cuda_buffer_type(cuda_ctx->device) && "unsupported buffer type"); 2450 2451 CUDA_CHECK(cudaMemcpyAsync((char *) tensor->data + offset, data, size, cudaMemcpyHostToDevice, cuda_ctx->stream())); 2452} 2453 2454static void ggml_backend_cuda_get_tensor_async(ggml_backend_t backend, const ggml_tensor * tensor, void * data, size_t offset, size_t size) { 2455 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *) backend->context; 2456 ggml_backend_buffer_t buf = tensor->view_src ? tensor->view_src->buffer : tensor->buffer; 2457 2458 GGML_ASSERT(buf->buft == ggml_backend_cuda_buffer_type(cuda_ctx->device) && "unsupported buffer type"); 2459 2460 CUDA_CHECK(cudaMemcpyAsync(data, (const char *) tensor->data + offset, size, cudaMemcpyDeviceToHost, cuda_ctx->stream())); 2461} 2462 2463static void ggml_backend_cuda_set_tensor_2d_async(ggml_backend_t backend, struct ggml_tensor * tensor, const void * data, 2464 size_t offset, size_t size, size_t n_copies, size_t stride_tensor, size_t stride_data) { 2465 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *) backend->context; 2466 ggml_backend_buffer_t buf = tensor->view_src ? tensor->view_src->buffer : tensor->buffer; 2467 2468 GGML_ASSERT(buf->buft == ggml_backend_cuda_buffer_type(cuda_ctx->device) && "unsupported buffer type"); 2469 2470 CUDA_CHECK(cudaMemcpy2DAsync( 2471 (char *) tensor->data + offset, stride_tensor, data, stride_data, size, n_copies, cudaMemcpyHostToDevice, cuda_ctx->stream())); 2472} 2473 2474static void ggml_backend_cuda_get_tensor_2d_async(ggml_backend_t backend, const struct ggml_tensor * tensor, void * data, 2475 size_t offset, size_t size, size_t n_copies, size_t stride_tensor, size_t stride_data) { 2476 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *) backend->context; 2477 ggml_backend_buffer_t buf = tensor->view_src ? tensor->view_src->buffer : tensor->buffer; 2478 2479 GGML_ASSERT(buf->buft == ggml_backend_cuda_buffer_type(cuda_ctx->device) && "unsupported buffer type"); 2480 2481 CUDA_CHECK(cudaMemcpy2DAsync( 2482 data, stride_data, (const char *) tensor->data + offset, stride_tensor, size, n_copies, cudaMemcpyDeviceToHost, cuda_ctx->stream())); 2483} 2484 2485static bool ggml_backend_cuda_cpy_tensor_async(ggml_backend_t backend_src, ggml_backend_t backend_dst, const ggml_tensor * src, ggml_tensor * dst) { 2486 ggml_backend_buffer_t buf_src = src->view_src ? src->view_src->buffer : src->buffer; 2487 ggml_backend_buffer_t buf_dst = dst->view_src ? dst->view_src->buffer : dst->buffer; 2488 2489 if (!ggml_backend_is_cuda(backend_src) || !ggml_backend_is_cuda(backend_dst)) { 2490 return false; 2491 } 2492 2493 if (!ggml_backend_buffer_is_cuda(buf_src) || !ggml_backend_buffer_is_cuda(buf_dst)) { 2494 return false; 2495 } 2496 2497 // device -> device copy 2498 ggml_backend_cuda_context * cuda_ctx_src = (ggml_backend_cuda_context *) backend_src->context; 2499 ggml_backend_cuda_context * cuda_ctx_dst = (ggml_backend_cuda_context *) backend_dst->context; 2500 2501 ggml_backend_cuda_buffer_context * buf_ctx_src = (ggml_backend_cuda_buffer_context *) buf_src->context; 2502 ggml_backend_cuda_buffer_context * buf_ctx_dst = (ggml_backend_cuda_buffer_context *) buf_dst->context; 2503 2504 if (cuda_ctx_src->device != buf_ctx_src->device || cuda_ctx_dst->device != buf_ctx_dst->device) { 2505#ifndef NDEBUG 2506 GGML_LOG_DEBUG("%s: backend and buffer devices do not match\n", __func__); 2507#endif // NDEBUG 2508 return false; 2509 } 2510 2511 if (backend_src != backend_dst) { 2512 // copy on src stream 2513 // compare the backing physical devices: distinct virtual devices may share one physical GPU, 2514 // in which case a same-device copy (not a peer copy) is required 2515 const int src_physical = ggml_cuda_get_physical_device(cuda_ctx_src->device); 2516 const int dst_physical = ggml_cuda_get_physical_device(cuda_ctx_dst->device); 2517 if (src_physical == dst_physical) { 2518 CUDA_CHECK(cudaMemcpyAsync(dst->data, src->data, ggml_nbytes(dst), cudaMemcpyDeviceToDevice, cuda_ctx_src->stream())); 2519 } else { 2520#ifdef GGML_CUDA_NO_PEER_COPY 2521 return false; 2522#else 2523 CUDA_CHECK(cudaMemcpyPeerAsync(dst->data, dst_physical, src->data, src_physical, ggml_nbytes(dst), cuda_ctx_src->stream())); 2524#endif // GGML_CUDA_NO_PEER_COPY 2525 } 2526 2527 // record event on src stream after the copy 2528 if (!cuda_ctx_src->copy_event) { 2529 ggml_cuda_set_device(cuda_ctx_src->device); 2530 CUDA_CHECK(cudaEventCreateWithFlags(&cuda_ctx_src->copy_event, cudaEventDisableTiming)); 2531 } 2532 2533 CUDA_CHECK(cudaEventRecord(cuda_ctx_src->copy_event, cuda_ctx_src->stream())); 2534 2535 // wait on dst stream for the copy to complete 2536 CUDA_CHECK(cudaStreamWaitEvent(cuda_ctx_dst->stream(), cuda_ctx_src->copy_event, 0)); 2537 } else { 2538 // src and dst are on the same backend 2539 CUDA_CHECK(cudaMemcpyAsync(dst->data, src->data, ggml_nbytes(dst), cudaMemcpyDeviceToDevice, cuda_ctx_src->stream())); 2540 } 2541 return true; 2542} 2543 2544static void ggml_backend_cuda_synchronize(ggml_backend_t backend) { 2545 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *)backend->context; 2546 2547 CUDA_CHECK(cudaStreamSynchronize(cuda_ctx->stream())); 2548 2549 GGML_UNUSED(backend); 2550} 2551 2552static bool ggml_cuda_is_view_or_noop(const ggml_tensor * t) { 2553 return ggml_is_empty(t) || t->op == GGML_OP_RESHAPE || t->op == GGML_OP_TRANSPOSE || 2554 t->op == GGML_OP_VIEW || t->op == GGML_OP_PERMUTE || t->op == GGML_OP_NONE; 2555} 2556 2557#ifdef USE_CUDA_GRAPH 2558static bool ggml_cuda_graph_check_compability(ggml_cgraph * cgraph) { 2559 2560 bool use_cuda_graph = true; 2561 // Loop over nodes in GGML graph to obtain info needed for CUDA graph 2562 2563 for (int i = 0; i < cgraph->n_nodes; i++) { 2564 ggml_tensor * node = cgraph->nodes[i]; 2565 2566 if (ggml_cuda_is_view_or_noop(node)) { 2567 continue; 2568 } 2569 2570 // [TAG_MUL_MAT_ID_CUDA_GRAPHS] 2571 if (node->op == GGML_OP_MUL_MAT_ID) { 2572 const int cc = ggml_cuda_info().devices[ggml_cuda_get_device()].cc; 2573 if (ggml_cuda_mul_mat_id_needs_sync(node, cc)) { 2574 // the mul_mat_id fallback path synchronizes the stream, so we cannot use CUDA graphs 2575 // ref: https://github.com/ggml-org/llama.cpp/pull/18958 2576 use_cuda_graph = false; 2577#ifndef NDEBUG 2578 GGML_LOG_DEBUG("%s: disabling CUDA graphs due to unsupported node type\n", __func__); 2579#endif 2580 } 2581 } 2582 2583 if (!use_cuda_graph) { 2584 break; 2585 } 2586 } 2587 2588 return use_cuda_graph; 2589} 2590 2591static const void * ggml_cuda_graph_get_key(ggml_cgraph * cgraph) { 2592 return cgraph->nodes[0]; 2593} 2594 2595static bool ggml_cuda_graph_update_required(ggml_backend_cuda_context * cuda_ctx, ggml_cgraph * cgraph) { 2596 bool res = false; 2597 2598 const void * graph_key = ggml_cuda_graph_get_key(cgraph); 2599 ggml_cuda_graph * graph = cuda_ctx->cuda_graph(graph_key); 2600 2601 if (cgraph->uid != 0 && 2602 cgraph->uid == graph->uid) { 2603 GGML_LOG_DEBUG("CUDA Graph id %zu reused\n", cgraph->uid); 2604 GGML_ASSERT((int)graph->node_props.size() == cgraph->n_nodes); 2605 return false; 2606 } 2607 2608 graph->uid = cgraph->uid; 2609 2610 // Check if the graph size has changed 2611 if ((int)graph->node_props.size() != cgraph->n_nodes) { 2612 res = true; 2613 graph->node_props.resize(cgraph->n_nodes); 2614 } 2615 2616 for (int i = 0; i < cgraph->n_nodes; i++) { 2617 ggml_cuda_graph::node_properties prop = {}; 2618 memcpy(&prop.node, cgraph->nodes[i], sizeof(ggml_tensor)); 2619 2620 for (int j = 0; j < GGML_MAX_SRC; ++j) { 2621 if (cgraph->nodes[i]->src[j]) { 2622 prop.node_src_data_ptrs[j] = cgraph->nodes[i]->src[j]->data; 2623 memcpy(prop.node_src_ne[j], cgraph->nodes[i]->src[j]->ne, sizeof(prop.node_src_ne[j])); 2624 memcpy(prop.node_src_nb[j], cgraph->nodes[i]->src[j]->nb, sizeof(prop.node_src_nb[j])); 2625 } 2626 } 2627 2628 if (res || memcmp(&graph->node_props[i], &prop, sizeof(prop)) != 0) { 2629 graph->node_props[i] = prop; 2630 res = true; 2631 } 2632 } 2633 2634 return res; 2635} 2636 2637static void ggml_cuda_graph_update_executable(ggml_backend_cuda_context * cuda_ctx, const void * graph_key) { 2638 ggml_cuda_graph * graph = cuda_ctx->cuda_graph(graph_key); 2639 2640#if CUDART_VERSION >= 12000 2641 cudaGraphExecUpdateResultInfo result_info; 2642 cudaError_t stat = cudaGraphExecUpdate(graph->instance, graph->graph, &result_info); 2643#else 2644 cudaGraphNode_t errorNode; 2645 cudaGraphExecUpdateResult result_info; 2646 cudaError_t stat = cudaGraphExecUpdate(graph->instance, graph->graph, &errorNode, &result_info); 2647#endif // CUDART_VERSION >= 12000 2648 2649 if (stat == cudaErrorGraphExecUpdateFailure) { 2650#ifndef NDEBUG 2651 GGML_LOG_DEBUG("%s: CUDA graph update failed\n", __func__); 2652#endif 2653 2654 // The pre-existing graph exec cannot be updated due to violated constraints 2655 // so instead clear error and re-instantiate 2656 (void)cudaGetLastError(); 2657 CUDA_CHECK(cudaGraphExecDestroy(graph->instance)); 2658 graph->instance = nullptr; 2659 CUDA_CHECK(cudaGraphInstantiate(&graph->instance, graph->graph, NULL, NULL, 0)); 2660 } else { 2661 GGML_ASSERT(stat == cudaSuccess); 2662 } 2663} 2664#endif // USE_CUDA_GRAPH 2665 2666static bool ggml_cuda_should_fuse_rope_set_rows(const ggml_tensor * rope, 2667 const ggml_tensor * view, 2668 const ggml_tensor * set_rows) { 2669 2670 if (rope->op != GGML_OP_ROPE || view->op != GGML_OP_VIEW || set_rows->op != GGML_OP_SET_ROWS) { 2671 return false; 2672 } 2673 // ne3 not tested 2674 if (rope->src[0]->ne[3] != 1) { 2675 return false; 2676 } 2677 2678 if (set_rows->type != GGML_TYPE_F32 && set_rows->type != GGML_TYPE_F16) { 2679 return false; 2680 } 2681 2682 if (set_rows->src[1]->type != GGML_TYPE_I64) { 2683 return false; 2684 } 2685 2686 // The view should flatten two dims of rope into one dim 2687 if (!ggml_is_contiguous(view) || view->ne[0] != rope->ne[0] * rope->ne[1]) { 2688 return false; 2689 } 2690 2691 // Only norm/neox shaders have the fusion code 2692 const int mode = ((const int32_t *) rope->op_params)[2]; 2693 if (mode != GGML_ROPE_TYPE_NORMAL && mode != GGML_ROPE_TYPE_NEOX) { 2694 return false; 2695 } 2696 2697 return true; 2698} 2699 2700static bool ggml_cuda_should_fuse_rms_norm_mul_rope(const ggml_tensor * rms_norm, 2701 const ggml_tensor * mul, 2702 const ggml_tensor * rope) { 2703 if (rms_norm->op != GGML_OP_RMS_NORM || mul->op != GGML_OP_MUL || rope->op != GGML_OP_ROPE) { 2704 return false; 2705 } 2706 2707 if (rms_norm->src[0]->type != GGML_TYPE_F32 || rms_norm->type != GGML_TYPE_F32 || 2708 mul->src[0]->type != GGML_TYPE_F32 || mul->src[1]->type != GGML_TYPE_F32 || 2709 mul->type != GGML_TYPE_F32 || rope->type != GGML_TYPE_F32) { 2710 return false; 2711 } 2712 2713 if (rope->src[0] != mul) { 2714 return false; 2715 } 2716 2717 //if rms norm is the B operand, then we don't handle broadcast 2718 if (rms_norm == mul->src[1] && !ggml_are_same_shape(mul->src[0], rms_norm)) { 2719 return false; 2720 } 2721 2722 if (!ggml_are_same_shape(rms_norm, mul)) { 2723 return false; 2724 } 2725 2726 //rms_norm kernel assumes contiguous rows 2727 if (!ggml_is_contiguous_rows(rms_norm->src[0]) || 2728 !ggml_is_contiguous_rows(mul->src[0]) || !ggml_is_contiguous_rows(mul->src[1])) { 2729 return false; 2730 } 2731 2732 // the fused kernel handles the norm/neox rope modes only 2733 const int mode = ((const int32_t *) rope->op_params)[2]; 2734 if (mode != GGML_ROPE_TYPE_NORMAL && mode != GGML_ROPE_TYPE_NEOX) { 2735 return false; 2736 } 2737 2738 const int n_dims = ((const int32_t *) rope->op_params)[1]; 2739 if (n_dims % 2 != 0 || rope->src[0]->ne[0] % 2 != 0) { 2740 return false; 2741 } 2742 2743 // ggml_rope_set_offset is not yet supported in the fused kernel 2744 const int n_offs = ((const int32_t *) rope->op_params)[15]; 2745 if (n_offs != 0) { 2746 return false; 2747 } 2748 2749 return true; 2750} 2751 2752// match gated_delta_net + the strided cpy that scatters its state snapshots into the cache 2753// (slot i -> rollback group i, slot 0 newest), so the kernel can write them and skip the cpy. 2754static int ggml_cuda_try_gdn_cache_fusion( 2755 const ggml_cgraph * cgraph, int node_idx, ggml_cuda_gated_delta_net_fused_cache & fused_state_cpy) { 2756 const ggml_tensor * gdn = cgraph->nodes[node_idx]; 2757 // the kernel skips the snapshot tail, so the gdn output must not be a graph output 2758 if (gdn->op != GGML_OP_GATED_DELTA_NET || gdn->type != GGML_TYPE_F32 || 2759 (gdn->flags & GGML_TENSOR_FLAG_OUTPUT)) { 2760 return 0; 2761 } 2762 2763 const ggml_tensor * src_v = gdn->src[2]; 2764 const int64_t S_v = src_v->ne[0]; 2765 const int64_t H = src_v->ne[1]; 2766 const int64_t n_tokens = src_v->ne[2]; 2767 const int64_t n_seqs = src_v->ne[3]; 2768 const int64_t D = S_v * S_v * H; 2769 const int64_t K = ggml_get_op_params_i32(gdn, 0); // snapshot slot count 2770 const int64_t n_written = std::min<int64_t>(n_tokens, K); // newest n_written slots are written 2771 2772 // snapshot tail starts right after the attention scores 2773 const size_t tail_off = ggml_row_size(GGML_TYPE_F32, S_v * H * n_tokens * n_seqs); 2774 2775 // snapshot cpy is the first real node after the gdn (skip views/no-ops) 2776 const ggml_tensor * cpy = nullptr; 2777 int skip = 0; 2778 for (int j = node_idx + 1; j < cgraph->n_nodes && cpy == nullptr; ++j) { 2779 const ggml_tensor * n = cgraph->nodes[j]; 2780 if (ggml_cuda_is_view_or_noop(n)) { 2781 continue; 2782 } 2783 if (n->op != GGML_OP_CPY || (n->flags & GGML_TENSOR_FLAG_OUTPUT)) { 2784 return 0; 2785 } 2786 cpy = n; 2787 skip = j - node_idx; 2788 } 2789 if (cpy == nullptr) { 2790 return 0; 2791 } 2792 2793 const ggml_tensor * src = cpy->src[0]; // view of the gdn snapshot tail 2794 const ggml_tensor * dst = cpy->src[1]; // cache view the kernel writes to 2795 2796 // src must be this gdn's snapshot tail (contiguous, at the tail offset) 2797 if (src->op != GGML_OP_VIEW || src->view_src != gdn || src->view_offs != tail_off || 2798 !ggml_is_contiguous(src)) { 2799 return 0; 2800 } 2801 2802 // dst is the [D, n_seqs, n_written] cache view; require nb[1] == D (the per-seq stride the kernel 2803 // assumes). ggml_cpy pins src to the same element count. 2804 const std::array<int64_t, GGML_MAX_DIMS> expected_ne = { D, n_seqs, n_written, 1 }; 2805 if (dst->op != GGML_OP_VIEW || dst->type != GGML_TYPE_F32 || dst->data == nullptr || 2806 !std::equal(expected_ne.begin(), expected_ne.end(), dst->ne) || 2807 dst->nb[0] != ggml_type_size(GGML_TYPE_F32) || dst->nb[1] != (size_t) ggml_row_size(GGML_TYPE_F32, D)) { 2808 return 0; 2809 } 2810 2811 fused_state_cpy.data = (float *) dst->data; // rollback group 0 (newest) 2812 fused_state_cpy.slot_stride = K > 1 ? (int64_t) (dst->nb[2] / sizeof(float)) : 0; 2813 return skip; 2814} 2815 2816static bool ggml_cuda_topk_moe_fusion(const struct ggml_cgraph * cgraph, int node_idx, ggml_cuda_topk_moe_args & args) { 2817 args.sigmoid = false; 2818 args.sqrt_softplus = false; 2819 args.softmax = false; 2820 args.delayed_softmax = false; 2821 args.prob_bias = false; 2822 args.norm = false; 2823 2824 const int n_nodes = cgraph->n_nodes; 2825 ggml_tensor ** nodes = cgraph->nodes; 2826 2827 if (nodes[node_idx]->op == GGML_OP_SOFT_MAX) { 2828 args.softmax = true; 2829 } 2830 2831 if (nodes[node_idx]->op == GGML_OP_UNARY) { 2832 const ggml_unary_op unary_op = ggml_get_unary_op(nodes[node_idx]); 2833 if (unary_op == GGML_UNARY_OP_SIGMOID) { 2834 args.sigmoid = true; 2835 } else if (unary_op == GGML_UNARY_OP_SOFTPLUS && node_idx + 1 < n_nodes && 2836 nodes[node_idx + 1]->op == GGML_OP_SQRT && nodes[node_idx + 1]->src[0] == nodes[node_idx]) { 2837 // sqrt(softplus(x)) scoring (DeepSeek-V4) 2838 args.sqrt_softplus = true; 2839 node_idx++; 2840 } else { 2841 return false; 2842 } 2843 } 2844 2845 if (nodes[node_idx]->op == GGML_OP_ARGSORT) { 2846 args.delayed_softmax = true; 2847 } 2848 2849 node_idx++; 2850 2851 if (args.sigmoid || args.sqrt_softplus || args.softmax) { 2852 // SOFTMAX -> RESHAPE 2853 if (node_idx >= n_nodes || nodes[node_idx]->op != GGML_OP_RESHAPE || 2854 nodes[node_idx]->src[0] != nodes[node_idx - 1]) { 2855 return false; 2856 } 2857 ggml_tensor * probs_reshaped = nodes[node_idx]; 2858 node_idx++; 2859 2860 if (node_idx >= n_nodes) { 2861 return false; 2862 } 2863 2864 // src of bias add is the unreshaped probs (-2 instead of -1) 2865 if (nodes[node_idx]->op == GGML_OP_ADD && nodes[node_idx]->src[0] == nodes[node_idx - 2]) { 2866 args.prob_bias = true; 2867 node_idx++; 2868 } 2869 // RESHAPE/ADD -> ARGSORT 2870 if (node_idx >= n_nodes || nodes[node_idx]->op != GGML_OP_ARGSORT) { 2871 return false; 2872 } 2873 2874 if (args.prob_bias && nodes[node_idx]->src[0] != nodes[node_idx - 1]) { 2875 return false; 2876 } else if (!args.prob_bias && nodes[node_idx]->src[0] != nodes[node_idx - 2]) { 2877 return false; 2878 } 2879 2880 node_idx++; 2881 2882 // ARGSORT-> VIEW 2883 if (node_idx >= n_nodes || nodes[node_idx]->op != GGML_OP_VIEW || 2884 nodes[node_idx]->src[0] != nodes[node_idx - 1]) { 2885 return false; 2886 } 2887 node_idx++; 2888 2889 if (node_idx >= n_nodes || nodes[node_idx]->op != GGML_OP_GET_ROWS) { 2890 return false; 2891 } 2892 2893 // GET_ROWS 2894 if (nodes[node_idx]->src[0] != probs_reshaped || nodes[node_idx]->src[1] != nodes[node_idx - 1]) { 2895 return false; 2896 } 2897 node_idx++; 2898 } else if (args.delayed_softmax) { 2899 if (node_idx - 2 < 0) { 2900 return false; 2901 } 2902 ggml_tensor * probs_reshaped = nodes[node_idx - 2]; 2903 2904 // VIEW->ARGSORT 2905 if (node_idx >= n_nodes || nodes[node_idx]->op != GGML_OP_VIEW || 2906 nodes[node_idx]->src[0] != nodes[node_idx - 1]) { 2907 return false; 2908 } 2909 node_idx++; 2910 2911 // GET_ROWS 2912 if (node_idx >= n_nodes || nodes[node_idx]->src[1] != nodes[node_idx - 1] || 2913 nodes[node_idx]->src[0] != probs_reshaped) { 2914 return false; 2915 } 2916 node_idx++; 2917 2918 static const std::vector<ggml_op> remaining_ops = { GGML_OP_RESHAPE, GGML_OP_SOFT_MAX, GGML_OP_RESHAPE }; 2919 2920 for (const ggml_op op : remaining_ops) { 2921 if (node_idx >= n_nodes || nodes[node_idx]->op != op || nodes[node_idx]->src[0] != nodes[node_idx - 1]) { 2922 return false; 2923 } 2924 node_idx++; 2925 } 2926 } 2927 2928 // At this point we can check for norm + scale. Everything is now at least valid till the norm 2929 if (node_idx >= n_nodes) { 2930 return true; 2931 } 2932 2933 if (nodes[node_idx]->op == GGML_OP_RESHAPE) { 2934 //check RESHAPE->SUM_ROWS->CLAMP->DIV->RESHAPE 2935 static const std::vector<ggml_op> norm_ops = { GGML_OP_RESHAPE, GGML_OP_SUM_ROWS, GGML_OP_CLAMP }; 2936 2937 args.norm = true; 2938 for (const ggml_op op : norm_ops) { 2939 if (nodes[node_idx]->op == op && nodes[node_idx]->src[0] == nodes[node_idx - 1]) { 2940 node_idx++; 2941 } else { 2942 args.norm = false; 2943 return true; 2944 } 2945 } 2946 2947 // DIV <- CLAMP, RESHAPE 2948 if (nodes[node_idx]->op != GGML_OP_DIV || nodes[node_idx]->src[1] != nodes[node_idx - 1] || 2949 nodes[node_idx]->src[0] != nodes[node_idx - 3]) { 2950 args.norm = false; 2951 return true; 2952 } 2953 node_idx++; 2954 2955 if (nodes[node_idx]->op != GGML_OP_RESHAPE || nodes[node_idx]->src[0] != nodes[node_idx - 1]) { 2956 args.norm = false; 2957 return true; 2958 } 2959 2960 node_idx++; 2961 } 2962 2963 if (nodes[node_idx]->op == GGML_OP_SCALE && nodes[node_idx]->src[0] == nodes[node_idx - 1]) { 2964 args.scale = true; 2965 } 2966 2967 return true; 2968} 2969 2970// returns whether the write (out) nodes overwrite the read nodes in operation 2971static bool ggml_cuda_check_fusion_memory_ranges(const ggml_cgraph * cgraph, 2972 const int node_idx, 2973 const int node_count, 2974 const int * out_nodes, 2975 const int out_count, 2976 const bool is_topk_moe = false) { 2977 auto nodes_overlap = [&](const ggml_tensor * a, const ggml_tensor * b) { 2978 const int64_t a_start = (int64_t) a->data; 2979 const int64_t a_end = a_start + ggml_backend_buft_get_alloc_size(a->buffer->buft, a); 2980 2981 const int64_t b_start = (int64_t) b->data; 2982 const int64_t b_end = b_start + ggml_backend_buft_get_alloc_size(b->buffer->buft, b); 2983 2984 if ((b_start <= a_start && a_start < b_end) || (a_start <= b_start && b_start < a_end)) { 2985 return true; 2986 } 2987 2988 return false; 2989 }; 2990 2991 bool is_ok = true; 2992 // one block reads all logits before it writes, so logits may alias the out nodes 2993 const ggml_tensor * logits_may_alias = nullptr; 2994 if (is_topk_moe && ggml_nrows(cgraph->nodes[node_idx]) <= TOPK_MOE_ROWS_PER_BLOCK) { 2995 logits_may_alias = cgraph->nodes[node_idx]->src[0]; 2996 } 2997 2998 for (int i = 0; i < out_count; ++i) { 2999 const ggml_tensor * dst = cgraph->nodes[out_nodes[i]]; 3000 3001 for (int j = node_idx; j < node_idx + node_count; ++j) { 3002 // Loop over all srcs of all nodes in the fusion. If the src overlaps 3003 // the destination and the src is not an intermediate node that's being 3004 // elided, then disable fusion. 3005 3006 for (int src_idx = 0; src_idx < GGML_MAX_SRC; ++src_idx) { 3007 const ggml_tensor * src = cgraph->nodes[j]->src[src_idx]; 3008 3009 if (!src || src->op == GGML_OP_NONE || src == logits_may_alias) { 3010 continue; 3011 } 3012 3013 if (nodes_overlap(dst, src)) { 3014 bool found = false; 3015 3016 for (int k = node_idx; k < j; ++k) { 3017 if (cgraph->nodes[k] == src) { 3018 found = true; 3019 break; 3020 } 3021 } 3022 3023 if (!found) { 3024 is_ok = false; 3025 break; 3026 } 3027 } 3028 } 3029 } 3030 } 3031 3032 return is_ok; 3033} 3034 3035// The long form spans 2*k + 1 nodes. ggml_can_fuse_subgraph() accepts at most 3036// 31 nodes, so k <= 15; larger values use the per-operation path. 3037static constexpr int MOE_WEIGHTED_REDUCTION_MAX_EXPERTS = 15; 3038 3039struct ggml_cuda_moe_weighted_reduction_match { 3040 const ggml_tensor * experts = nullptr; 3041 const ggml_tensor * expert_scale = nullptr; 3042 const ggml_tensor * weights = nullptr; 3043 ggml_tensor * dst = nullptr; 3044 int node_count = 0; 3045}; 3046 3047static bool ggml_cuda_match_moe_weighted_reduction( 3048 const ggml_cgraph * cgraph, 3049 int node_idx, 3050 ggml_cuda_moe_weighted_reduction_match & match) { 3051 const ggml_tensor * first = cgraph->nodes[node_idx]; 3052 if (first->op != GGML_OP_MUL || first->type != GGML_TYPE_F32 || !ggml_is_contiguous(first)) { 3053 return false; 3054 } 3055 3056 auto split_mul = [](const ggml_tensor * mul, const ggml_tensor *& full, const ggml_tensor *& broadcast) { 3057 auto is_weights = [mul](const ggml_tensor * tensor) { 3058 return tensor && tensor->type == GGML_TYPE_F32 && ggml_is_contiguous(tensor) && tensor->ne[0] == 1 && 3059 tensor->ne[1] == mul->ne[1] && tensor->ne[2] == mul->ne[2] && tensor->ne[3] == mul->ne[3]; 3060 }; 3061 auto is_experts = [mul](const ggml_tensor * tensor) { 3062 return tensor && tensor->type == GGML_TYPE_F32 && ggml_is_contiguous(tensor) && 3063 ggml_are_same_shape(tensor, mul); 3064 }; 3065 3066 if (is_experts(mul->src[0]) && is_weights(mul->src[1])) { 3067 full = mul->src[0]; 3068 broadcast = mul->src[1]; 3069 return true; 3070 } 3071 if (is_experts(mul->src[1]) && is_weights(mul->src[0])) { 3072 full = mul->src[1]; 3073 broadcast = mul->src[0]; 3074 return true; 3075 } 3076 return false; 3077 }; 3078 3079 const ggml_tensor * weighted = first; 3080 const ggml_tensor * experts = nullptr; 3081 const ggml_tensor * expert_scale = nullptr; 3082 const ggml_tensor * weights = nullptr; 3083 int mul_count = 1; 3084 3085 // Match both structural forms: 3086 // (experts * expert_scale) * router_weight 3087 // experts * router_weight 3088 // The matcher does not depend on the model or quantization type. 3089 if (node_idx + 1 < cgraph->n_nodes) { 3090 const ggml_tensor * second = cgraph->nodes[node_idx + 1]; 3091 const ggml_tensor * scaled = nullptr; 3092 const ggml_tensor * route = nullptr; 3093 const ggml_tensor * raw = nullptr; 3094 const ggml_tensor * scale = nullptr; 3095 if (second->op == GGML_OP_MUL && second->type == GGML_TYPE_F32 && ggml_is_contiguous(second) && 3096 split_mul(second, scaled, route) && scaled == first && split_mul(first, raw, scale)) { 3097 weighted = second; 3098 experts = raw; 3099 expert_scale = scale; 3100 weights = route; 3101 mul_count = 2; 3102 } 3103 } 3104 3105 if (experts == nullptr && !split_mul(first, experts, weights)) { 3106 return false; 3107 } 3108 3109 const int n_expert_used = (int) weighted->ne[1]; 3110 const int64_t n_tokens = weighted->ne[2] * weighted->ne[3]; 3111 if (n_expert_used < 2 || n_expert_used > MOE_WEIGHTED_REDUCTION_MAX_EXPERTS || n_tokens <= 0) { 3112 return false; 3113 } 3114 3115 const int node_count = 2 * n_expert_used + mul_count - 1; 3116 if (node_idx + node_count > cgraph->n_nodes) { 3117 return false; 3118 } 3119 3120 std::vector<ggml_op> ops(node_count, GGML_OP_VIEW); 3121 ops[0] = GGML_OP_MUL; 3122 if (mul_count == 2) { 3123 ops[1] = GGML_OP_MUL; 3124 } 3125 std::vector<const ggml_tensor *> views; 3126 views.reserve(n_expert_used); 3127 const ggml_tensor * previous = nullptr; 3128 int n_adds = 0; 3129 for (int offset = mul_count; offset < node_count; ++offset) { 3130 const ggml_tensor * candidate = cgraph->nodes[node_idx + offset]; 3131 ops[offset] = candidate->op; 3132 3133 if (candidate->op == GGML_OP_VIEW) { 3134 const int expert = (int) views.size(); 3135 if (expert >= n_expert_used || candidate->src[0] != weighted || candidate->view_src != weighted || 3136 candidate->type != GGML_TYPE_F32 || candidate->ne[0] != weighted->ne[0] || 3137 candidate->ne[1] != n_tokens || candidate->ne[2] != 1 || candidate->ne[3] != 1 || 3138 candidate->nb[0] != weighted->nb[0] || candidate->nb[1] != weighted->nb[2] || 3139 candidate->view_offs != (size_t) expert * weighted->nb[1]) { 3140 return false; 3141 } 3142 views.push_back(candidate); 3143 continue; 3144 } 3145 3146 if (candidate->op != GGML_OP_ADD || views.size() < 2 || n_adds + 1 >= (int) views.size()) { 3147 return false; 3148 } 3149 const ggml_tensor * lhs = n_adds == 0 ? views[0] : previous; 3150 const ggml_tensor * rhs = views[n_adds + 1]; 3151 if (candidate->src[0] != lhs || candidate->src[1] != rhs || candidate->type != GGML_TYPE_F32) { 3152 return false; 3153 } 3154 previous = candidate; 3155 ++n_adds; 3156 } 3157 3158 if ((int) views.size() != n_expert_used || n_adds != n_expert_used - 1 || previous == nullptr) { 3159 return false; 3160 } 3161 if (!ggml_is_contiguous(previous) || previous->ne[0] != weighted->ne[0] || 3162 previous->ne[1] != n_tokens || previous->ne[2] != 1 || previous->ne[3] != 1) { 3163 return false; 3164 } 3165 3166 const int output_idx = node_idx + node_count - 1; 3167 if (!ggml_can_fuse_subgraph(cgraph, node_idx, node_count, ops.data(), &output_idx, 1)) { 3168 return false; 3169 } 3170 3171 match.experts = experts; 3172 match.expert_scale = expert_scale; 3173 match.weights = weights; 3174 match.dst = cgraph->nodes[output_idx]; 3175 match.node_count = node_count; 3176 return true; 3177} 3178 3179 3180static bool ggml_cuda_can_fuse(const struct ggml_cgraph * cgraph, 3181 int node_idx, 3182 std::initializer_list<enum ggml_op> ops, 3183 std::initializer_list<enum ggml_unary_op> unary_ops) { 3184#ifndef NDEBUG 3185 const size_t num_unary = std::count(ops.begin(), ops.end(), GGML_OP_UNARY); 3186 GGML_ASSERT(unary_ops.size() == num_unary); 3187#endif 3188 3189 const auto is_equal = [](const std::initializer_list<enum ggml_op> & list1, 3190 const std::initializer_list<enum ggml_op> & list2) { 3191 return std::equal(list1.begin(), list1.end(), list2.begin(), list2.end()); 3192 }; 3193 3194 std::initializer_list<enum ggml_op> mul_mat_bias_glu_ops = { GGML_OP_MUL_MAT, GGML_OP_ADD, GGML_OP_MUL_MAT, GGML_OP_ADD, GGML_OP_GLU }; 3195 std::initializer_list<enum ggml_op> mul_mat_id_bias_glu_ops = { GGML_OP_MUL_MAT_ID, GGML_OP_ADD_ID, GGML_OP_MUL_MAT_ID, GGML_OP_ADD_ID, GGML_OP_GLU }; 3196 3197 std::initializer_list<enum ggml_op> mul_mat_id_glu_ops = { GGML_OP_MUL_MAT_ID, GGML_OP_MUL_MAT_ID, GGML_OP_GLU }; 3198 std::initializer_list<enum ggml_op> mul_mat_glu_ops = { GGML_OP_MUL_MAT, GGML_OP_MUL_MAT, GGML_OP_GLU }; 3199 3200 if ((is_equal(mul_mat_bias_glu_ops, ops) || is_equal(mul_mat_id_bias_glu_ops, ops)) && 3201 ggml_can_fuse_subgraph(cgraph, node_idx, ops, { node_idx + 4 })) { 3202 const ggml_tensor * ffn_gate = cgraph->nodes[node_idx]; 3203 const ggml_tensor * ffn_gate_bias = cgraph->nodes[node_idx + 1]; 3204 const ggml_tensor * ffn_up = cgraph->nodes[node_idx + 2]; 3205 const ggml_tensor * ffn_up_bias = cgraph->nodes[node_idx + 3]; 3206 const ggml_tensor * glu = cgraph->nodes[node_idx + 4]; 3207 3208 if (ggml_cuda_should_fuse_mul_mat(ffn_up, ffn_gate, glu, ffn_up_bias, ffn_gate_bias)) { 3209 int out_nodes[] = { node_idx + 4 }; 3210 return ggml_cuda_check_fusion_memory_ranges(cgraph, node_idx, (int)ops.size(), out_nodes, 1); 3211 } 3212 } 3213 3214 if ((is_equal(mul_mat_id_glu_ops, ops) || is_equal(mul_mat_glu_ops, ops)) && 3215 ggml_can_fuse_subgraph(cgraph, node_idx, ops, { node_idx + 2 })) { 3216 const ggml_tensor * ffn_gate = cgraph->nodes[node_idx]; 3217 const ggml_tensor * ffn_up = cgraph->nodes[node_idx + 1]; 3218 const ggml_tensor * glu = cgraph->nodes[node_idx + 2]; 3219 3220 if (ggml_cuda_should_fuse_mul_mat(ffn_up, ffn_gate, glu)) { 3221 int out_nodes[] = { node_idx + 2 }; 3222 return ggml_cuda_check_fusion_memory_ranges(cgraph, node_idx, (int)ops.size(), out_nodes, 1); 3223 } 3224 } 3225 3226 std::initializer_list<enum ggml_op> rms_norm_mul_rope_ops = { GGML_OP_RMS_NORM, GGML_OP_MUL, GGML_OP_ROPE }; 3227 std::initializer_list<enum ggml_op> rms_norm_mul_rope_set_rows_ops = { GGML_OP_RMS_NORM, GGML_OP_MUL, GGML_OP_ROPE, GGML_OP_VIEW, GGML_OP_SET_ROWS }; 3228 3229 if (is_equal(rms_norm_mul_rope_set_rows_ops, ops) && ggml_can_fuse_subgraph(cgraph, node_idx, ops, { node_idx + 4 })) { 3230 const ggml_tensor * rms_norm = cgraph->nodes[node_idx]; 3231 const ggml_tensor * mul = cgraph->nodes[node_idx + 1]; 3232 const ggml_tensor * rope = cgraph->nodes[node_idx + 2]; 3233 const ggml_tensor * view = cgraph->nodes[node_idx + 3]; 3234 const ggml_tensor * set_rows = cgraph->nodes[node_idx + 4]; 3235 3236 if (ggml_check_edges(cgraph, node_idx, {{1, 0, 0}, {2, 0, 1}, {3, 0, 2}, {4, 0, 3}}) && 3237 ggml_cuda_should_fuse_rms_norm_mul_rope(rms_norm, mul, rope) && 3238 ggml_cuda_should_fuse_rope_set_rows(rope, view, set_rows)) { 3239 int out_nodes[] = { node_idx + 4 }; 3240 return ggml_cuda_check_fusion_memory_ranges(cgraph, node_idx, (int)ops.size(), out_nodes, 1); 3241 } 3242 } 3243 3244 if (is_equal(rms_norm_mul_rope_ops, ops) && ggml_can_fuse(cgraph, node_idx, ops)) { 3245 const ggml_tensor * rms_norm = cgraph->nodes[node_idx]; 3246 const ggml_tensor * mul = cgraph->nodes[node_idx + 1]; 3247 const ggml_tensor * rope = cgraph->nodes[node_idx + 2]; 3248 3249 if (ggml_cuda_should_fuse_rms_norm_mul_rope(rms_norm, mul, rope)) { 3250 int out_nodes[] = { node_idx + 2 }; 3251 return ggml_cuda_check_fusion_memory_ranges(cgraph, node_idx, (int)ops.size(), out_nodes, 1); 3252 } 3253 return false; 3254 } 3255 3256 std::initializer_list<enum ggml_op> rope_set_rows_ops = { GGML_OP_ROPE, GGML_OP_VIEW, GGML_OP_SET_ROWS }; 3257 3258 if (is_equal(rope_set_rows_ops, ops) && ggml_can_fuse_subgraph(cgraph, node_idx, ops, { node_idx + 2 })) { 3259 const ggml_tensor * rope = cgraph->nodes[node_idx]; 3260 const ggml_tensor * view = cgraph->nodes[node_idx + 1]; 3261 const ggml_tensor * set_rows = cgraph->nodes[node_idx + 2]; 3262 3263 if (ggml_cuda_should_fuse_rope_set_rows(rope, view, set_rows)) { 3264 int out_nodes[] = { node_idx + 2 }; 3265 return ggml_cuda_check_fusion_memory_ranges(cgraph, node_idx, (int)ops.size(), out_nodes, 1); 3266 } 3267 } 3268 3269 if (!ggml_can_fuse(cgraph, node_idx, ops)) { 3270 return false; 3271 } 3272 3273 if ((ops.size() == 2 || ops.size() == 3) && ops.begin()[0] == GGML_OP_RMS_NORM && ops.begin()[1] == GGML_OP_MUL) { 3274 const ggml_tensor *rms_norm = cgraph->nodes[node_idx]; 3275 const ggml_tensor *mul = cgraph->nodes[node_idx+1]; 3276 const ggml_tensor *add = nullptr; 3277 3278 if (ops.size() == 3 && ops.begin()[2] == GGML_OP_ADD) { 3279 add = cgraph->nodes[node_idx+2]; 3280 } 3281 3282 GGML_ASSERT(rms_norm->src[0]->type == GGML_TYPE_F32); 3283 GGML_ASSERT(rms_norm->type == GGML_TYPE_F32); 3284 3285 //rms norm only supports F32 3286 if (mul->src[0]->type != GGML_TYPE_F32 || 3287 mul->src[1]->type != GGML_TYPE_F32 || 3288 mul->type != GGML_TYPE_F32) { 3289 return false; 3290 } 3291 3292 if (add && (add->src[0]->type != GGML_TYPE_F32 || 3293 add->src[1]->type != GGML_TYPE_F32 || 3294 add->type != GGML_TYPE_F32) ) { 3295 return false; 3296 } 3297 3298 //if rms norm is the B operand, then we don't handle broadcast 3299 if (rms_norm == mul->src[1] && !ggml_are_same_shape(mul->src[0], rms_norm)) { 3300 return false; 3301 } 3302 3303 //rms_norm kernel assumes contiguous rows 3304 if (!ggml_is_contiguous_rows(mul->src[0]) || !ggml_is_contiguous_rows(mul->src[1])) { 3305 return false; 3306 } 3307 3308 if (add && (!ggml_is_contiguous(add->src[0]) || !ggml_is_contiguous_rows(add->src[1]))) { 3309 return false; 3310 } 3311 3312 return true; 3313 } 3314 3315 if (ops.size() == 2 && ops.begin()[0] == GGML_OP_SSM_CONV && ops.begin()[1] == GGML_OP_UNARY 3316 && unary_ops.size() == 1 && unary_ops.begin()[0] == GGML_UNARY_OP_SILU) { 3317 const ggml_tensor * ssm_conv = cgraph->nodes[node_idx]; 3318 const ggml_tensor * silu = cgraph->nodes[node_idx+1]; 3319 if (ggml_get_unary_op(silu) != unary_ops.begin()[0]) { 3320 return false; 3321 } 3322 3323 if (ssm_conv->type != GGML_TYPE_F32 || silu->type != GGML_TYPE_F32) { 3324 return false; 3325 } 3326 3327 return true; 3328 } 3329 3330 if (ops.size() == 3 && ops.begin()[0] == GGML_OP_SSM_CONV && ops.begin()[1] == GGML_OP_ADD 3331 && ops.begin()[2] == GGML_OP_UNARY && unary_ops.size() == 1 && unary_ops.begin()[0] == GGML_UNARY_OP_SILU) { 3332 const ggml_tensor * ssm_conv = cgraph->nodes[node_idx]; 3333 const ggml_tensor * add = cgraph->nodes[node_idx+1]; 3334 const ggml_tensor * silu = cgraph->nodes[node_idx+2]; 3335 if (ggml_get_unary_op(silu) != unary_ops.begin()[0]) { 3336 return false; 3337 } 3338 3339 if (ssm_conv->type != GGML_TYPE_F32 || add->type != GGML_TYPE_F32 || silu->type != GGML_TYPE_F32) { 3340 return false; 3341 } 3342 3343 // ADD must consume ssm_conv's output and broadcast a 1-D channel-wise bias. 3344 const ggml_tensor * bias = (add->src[0] == ssm_conv) ? add->src[1] : add->src[0]; 3345 if (bias->type != GGML_TYPE_F32 || !ggml_is_contiguous(bias)) { 3346 return false; 3347 } 3348 if (ggml_nelements(bias) != ssm_conv->ne[0] || bias->ne[0] != ssm_conv->ne[0]) { 3349 return false; 3350 } 3351 3352 return true; 3353 } 3354 3355 if (ops.size() == 2 && ops.begin()[0] == GGML_OP_UNARY && ops.begin()[1] == GGML_OP_MUL 3356 && unary_ops.size() == 1 && (unary_ops.begin()[0] == GGML_UNARY_OP_SILU || unary_ops.begin()[0] == GGML_UNARY_OP_SIGMOID || unary_ops.begin()[0] == GGML_UNARY_OP_SOFTPLUS)) { 3357 const ggml_tensor * unary = cgraph->nodes[node_idx]; 3358 const ggml_tensor * mul = cgraph->nodes[node_idx+1]; 3359 3360 if (ggml_get_unary_op(unary) != unary_ops.begin()[0]) { 3361 return false; 3362 } 3363 3364 if (unary->type != GGML_TYPE_F32 && unary->type != GGML_TYPE_F16) { 3365 return false; 3366 } 3367 3368 if (unary->type != mul->type) { 3369 return false; 3370 } 3371 3372 const ggml_tensor * other = (mul->src[0] == unary) ? mul->src[1] : mul->src[0]; 3373 if (other->type != unary->type) { 3374 return false; 3375 } 3376 if (!ggml_is_contiguous_1(other) || !ggml_is_contiguous_1(unary->src[0]) || !ggml_are_same_shape(other, unary)) { 3377 return false; 3378 } 3379 3380 return true; 3381 } 3382 3383 if (ops.size() == 2 && ops.begin()[0] == GGML_OP_UNARY && ops.begin()[1] == GGML_OP_SQR 3384 && unary_ops.size() == 1 && unary_ops.begin()[0] == GGML_UNARY_OP_RELU) { 3385 const ggml_tensor * unary = cgraph->nodes[node_idx]; 3386 const ggml_tensor * sqr = cgraph->nodes[node_idx+1]; 3387 3388 if (ggml_get_unary_op(unary) != GGML_UNARY_OP_RELU) { 3389 return false; 3390 } 3391 3392 if (unary->type != GGML_TYPE_F32 && unary->type != GGML_TYPE_F16) { 3393 return false; 3394 } 3395 3396 if (unary->type != sqr->type) { 3397 return false; 3398 } 3399 3400 if (!ggml_is_contiguous(unary->src[0])) { 3401 return false; 3402 } 3403 3404 return true; 3405 } 3406 3407 if (ops.size() == 3 && ops.begin()[0] == GGML_OP_SCALE && ops.begin()[1] == GGML_OP_UNARY && ops.begin()[2] == GGML_OP_SCALE 3408 && unary_ops.size() == 1 && unary_ops.begin()[0] == GGML_UNARY_OP_TANH) { 3409 const ggml_tensor *scale = cgraph->nodes[node_idx]; 3410 const ggml_tensor *tanh = cgraph->nodes[node_idx+1]; 3411 const ggml_tensor *scale2 = cgraph->nodes[node_idx+2]; 3412 3413 GGML_ASSERT(scale->src[0]->type == GGML_TYPE_F32); 3414 GGML_ASSERT(scale->type == GGML_TYPE_F32); 3415 3416 if (ggml_get_unary_op(tanh) != GGML_UNARY_OP_TANH) { 3417 return false; 3418 } 3419 3420 // Check for bias 3421 if (ggml_get_op_params_f32(scale, 1) != 0.0f || ggml_get_op_params_f32(scale2, 1) != 0.0f) { 3422 return false; 3423 } 3424 3425 return true; 3426 } 3427 3428 return false; 3429} 3430 3431// try and fuse nodes and return the number of nodes to skip 3432static int ggml_cuda_try_fuse(ggml_backend_cuda_context * cuda_ctx, ggml_cgraph * cgraph, int i) { 3433 3434 static bool disable_fusion = getenv("GGML_CUDA_DISABLE_FUSION") != nullptr && std::atoi(getenv("GGML_CUDA_DISABLE_FUSION")); 3435 if (disable_fusion) { 3436 return 0; 3437 } 3438 3439 ggml_tensor * node = cgraph->nodes[i]; 3440 3441 if (node->op == GGML_OP_MUL) { 3442 ggml_cuda_moe_weighted_reduction_match match; 3443 if (ggml_cuda_match_moe_weighted_reduction(cgraph, i, match)) { 3444 const int output_idx = i + match.node_count - 1; 3445 if (ggml_cuda_check_fusion_memory_ranges(cgraph, i, match.node_count, &output_idx, 1)) { 3446 ggml_cuda_op_moe_weighted_reduction( 3447 *cuda_ctx, match.experts, match.expert_scale, match.weights, match.dst); 3448 return match.node_count - 1; 3449 } 3450 } 3451 } 3452 3453 // gated_delta_net -> cpy: scatter recurrent-state snapshots into the cache 3454 if (node->op == GGML_OP_GATED_DELTA_NET) { 3455 ggml_cuda_gated_delta_net_fused_cache fused_state_cpy; 3456 const int nodes_to_skip = ggml_cuda_try_gdn_cache_fusion(cgraph, i, fused_state_cpy); 3457 if (nodes_to_skip > 0) { 3458#ifdef GGML_CUDA_DEBUG 3459 GGML_LOG_INFO("%s: fused gated_delta_net snapshot copies for %s (skipped %d nodes)\n", 3460 __func__, node->name, nodes_to_skip); 3461#endif 3462 ggml_cuda_op_gated_delta_net_fused_cache(*cuda_ctx, node, fused_state_cpy); 3463 return nodes_to_skip; 3464 } 3465 } 3466 3467 //topk-moe 3468 if (cgraph->nodes[i]->op == GGML_OP_UNARY || cgraph->nodes[i]->op == GGML_OP_SOFT_MAX || 3469 cgraph->nodes[i]->op == GGML_OP_ARGSORT) { 3470 ggml_cuda_topk_moe_args args; 3471 const bool can_fuse = ggml_cuda_topk_moe_fusion(cgraph, i, args); 3472 std::vector<ggml_op> ops; 3473 3474 if (can_fuse) { 3475 const ggml_tensor * logits = node->src[0]; 3476 ggml_tensor * weights = nullptr; 3477 ggml_tensor * ids = nullptr; 3478 const ggml_tensor * bias = nullptr; 3479 const ggml_tensor * clamp = nullptr; 3480 const ggml_tensor * scale = nullptr; 3481 3482 if (!args.delayed_softmax) { 3483 int out_nodes[2]; // nodes which can't be elided 3484 3485 if (args.sigmoid) { 3486 ops.insert(ops.end(), { GGML_OP_UNARY }); 3487 } else if (args.sqrt_softplus) { 3488 ops.insert(ops.end(), { GGML_OP_UNARY, GGML_OP_SQRT }); 3489 } else { 3490 ops.insert(ops.end(), { GGML_OP_SOFT_MAX }); 3491 } 3492 const int i_probs = i + (int) ops.size() - 1; // last node of the gating activation 3493 3494 if (args.prob_bias) { 3495 bias = cgraph->nodes[i_probs + 2]->src[1]; 3496 ops.insert(ops.end(), { GGML_OP_RESHAPE, GGML_OP_ADD, GGML_OP_ARGSORT, GGML_OP_VIEW, 3497 GGML_OP_GET_ROWS }); 3498 out_nodes[0] = i_probs + 4; 3499 } else { 3500 ops.insert(ops.end(), { GGML_OP_RESHAPE, GGML_OP_ARGSORT, GGML_OP_VIEW, GGML_OP_GET_ROWS }); 3501 out_nodes[0] = i_probs + 3; 3502 } 3503 ids = cgraph->nodes[out_nodes[0]]; 3504 3505 if (args.norm) { 3506 ops.insert(ops.end(), 3507 { GGML_OP_RESHAPE, GGML_OP_SUM_ROWS, GGML_OP_CLAMP, GGML_OP_DIV, GGML_OP_RESHAPE }); 3508 clamp = cgraph->nodes[i + ops.size() - 3]; 3509 } 3510 if (args.scale) { 3511 ops.insert(ops.end(), { GGML_OP_SCALE }); 3512 scale = cgraph->nodes[i + ops.size() - 1]; 3513 } 3514 3515 weights = cgraph->nodes[i + ops.size() - 1]; 3516 out_nodes[1] = i + ops.size() - 1; 3517 3518 if (ggml_can_fuse_subgraph(cgraph, i, ops.size(), ops.data(), out_nodes, 2) && 3519 ggml_cuda_should_use_topk_moe(node, logits, weights, ids) && 3520 ggml_cuda_check_fusion_memory_ranges(cgraph, i, ops.size(), out_nodes, 2, /*is_topk_moe=*/true)) { 3521 ggml_cuda_op_topk_moe(*cuda_ctx, logits, weights, ids, clamp, scale, bias, args); 3522 return ops.size() - 1; 3523 } 3524 } else if (!args.norm && !args.prob_bias) { 3525 //special case gpt-oss, no norm, no bias. 3526 ops.insert(ops.end(), { GGML_OP_ARGSORT, GGML_OP_VIEW, GGML_OP_GET_ROWS, GGML_OP_RESHAPE, 3527 GGML_OP_SOFT_MAX, GGML_OP_RESHAPE }); 3528 weights = cgraph->nodes[i + 5]; 3529 ids = cgraph->nodes[i + 1]; 3530 const ggml_tensor * softmax = cgraph->nodes[i + 4]; 3531 3532 int out_nodes[2] = { i + 1, i + 5 }; 3533 if (ggml_can_fuse_subgraph(cgraph, i, ops.size(), ops.data(), out_nodes, 2) && 3534 ggml_cuda_should_use_topk_moe(softmax, logits, weights, ids) && 3535 ggml_cuda_check_fusion_memory_ranges(cgraph, i, ops.size(), out_nodes, 2, /*is_topk_moe=*/true)) { 3536 ggml_cuda_op_topk_moe(*cuda_ctx, logits, weights, ids, clamp, scale, bias, args); 3537 return ops.size() - 1; 3538 } 3539 } 3540 } 3541 } 3542 3543 //RoPE + view + set-rows 3544 if (ggml_cuda_can_fuse(cgraph, i, { GGML_OP_ROPE, GGML_OP_VIEW, GGML_OP_SET_ROWS }, {})) { 3545 ggml_tensor * rope = cgraph->nodes[i]; 3546 ggml_tensor * set_rows = cgraph->nodes[i + 2]; 3547 3548 ggml_cuda_op_rope_fused(*cuda_ctx, rope, set_rows); 3549 return 2; 3550 } 3551 3552 // Snake activation: y = x + sin(a*x)^2 * inv_b 3553 // Naive 5-op decomposition emitted by frontends: mul -> sin -> sqr -> mul -> add 3554 if (ggml_can_fuse_subgraph(cgraph, i, 3555 { GGML_OP_MUL, GGML_OP_SIN, GGML_OP_SQR, GGML_OP_MUL, GGML_OP_ADD }, 3556 { i + 4 })) { 3557 const ggml_tensor * mul0 = cgraph->nodes[i]; 3558 const ggml_tensor * sqr = cgraph->nodes[i + 2]; 3559 const ggml_tensor * mul1 = cgraph->nodes[i + 3]; 3560 ggml_tensor * add = cgraph->nodes[i + 4]; 3561 3562 // x carries the full activation shape, a is the broadcast operand 3563 const ggml_tensor * x = ggml_are_same_shape(mul0, mul0->src[0]) ? mul0->src[0] : mul0->src[1]; 3564 const ggml_tensor * a = (x == mul0->src[0]) ? mul0->src[1] : mul0->src[0]; 3565 3566 // mul1 reads sqr and inv_b in either operand order 3567 const ggml_tensor * inv_b = (mul1->src[0] == sqr) ? mul1->src[1] : mul1->src[0]; 3568 3569 // closure check: the trailing add must read the same x as the leading mul 3570 const ggml_tensor * x_in_add = (add->src[0] == mul1) ? add->src[1] : add->src[0]; 3571 3572 // Kernel iterates over total = T * C, so x and add must be 2D and 3573 // a / inv_b must collapse to [1, C, 1, 1]. Higher dims are not handled. 3574 const bool dim_ok = (x->ne[2] == 1 && x->ne[3] == 1) && 3575 (add->ne[2] == 1 && add->ne[3] == 1) && 3576 (a->ne[2] == 1 && a->ne[3] == 1); 3577 const bool shape_ok = ggml_are_same_shape(a, inv_b) && a->ne[0] == 1 && a->ne[1] == x->ne[1]; 3578 3579 // x is in the supported whitelist and every chain intermediate shares 3580 // x's type. launch_snake reads a and inv_b as const float *, so they 3581 // stay F32. 3582 const ggml_tensor * sin1 = cgraph->nodes[i + 1]; 3583 const bool types_ok = (x->type == GGML_TYPE_F32 || x->type == GGML_TYPE_F16 || x->type == GGML_TYPE_BF16) && 3584 (a->type == GGML_TYPE_F32) && (inv_b->type == GGML_TYPE_F32) && 3585 (mul0->type == x->type) && (sin1->type == x->type) && 3586 (sqr->type == x->type) && (mul1->type == x->type) && 3587 (add->type == x->type); 3588 3589 // kernel reads x[idx] and a[c] / inv_b[c] linearly, so every operand is contiguous 3590 const bool contig_ok = ggml_is_contiguous(x) && ggml_is_contiguous(add) && 3591 ggml_is_contiguous(a) && ggml_is_contiguous(inv_b); 3592 3593 if (types_ok && shape_ok && dim_ok && contig_ok && x_in_add == x) { 3594 ggml_cuda_op_snake_fused(*cuda_ctx, x, a, inv_b, add); 3595 return 4; 3596 } 3597 } 3598 3599 // multi-(add or mul) 3600 if (node->op == GGML_OP_ADD || node->op == GGML_OP_MUL) { 3601 int n_fuse = 0; 3602 ggml_op ops[8]; 3603 std::fill(ops, ops + 8, node->op); 3604 3605 for (; n_fuse <= 6; ++n_fuse) { 3606 if (!ggml_can_fuse(cgraph, i + n_fuse, ops + n_fuse, 2)) { 3607 break; 3608 } 3609 if (cgraph->nodes[i + n_fuse] != cgraph->nodes[i + n_fuse + 1]->src[0]) { 3610 break; 3611 } 3612 if (!ggml_are_same_layout(cgraph->nodes[i + n_fuse]->src[1], cgraph->nodes[i + n_fuse + 1]->src[1])) { 3613 break; 3614 } 3615 } 3616 3617 n_fuse++; 3618 3619 if (n_fuse > 1) { 3620 ggml_tensor fused_node; 3621 memcpy(&fused_node, node, sizeof(ggml_tensor)); 3622 for (int j = 0; j < n_fuse - 1; ++j) { 3623 fused_node.src[j + 2] = cgraph->nodes[i + j + 1]->src[1]; 3624 } 3625 fused_node.data = cgraph->nodes[i + n_fuse - 1]->data; 3626 if (node->op == GGML_OP_ADD) { 3627 ggml_cuda_op_fused_add(*cuda_ctx, &fused_node, n_fuse); 3628 } else { 3629 ggml_cuda_op_fused_mul(*cuda_ctx, &fused_node, n_fuse); 3630 } 3631 return n_fuse - 1; 3632 } 3633 } 3634 3635 bool fused_mul_mat_vec = false; 3636 int fused_node_count = 0; 3637 3638 auto get_mul_mat_scale = [](const ggml_tensor * scale_node, const ggml_tensor * mm_node) -> const ggml_tensor * { 3639 const bool scale_lhs_mm = scale_node->src[0] == mm_node; 3640 const bool scale_rhs_mm = scale_node->src[1] == mm_node; 3641 if (!scale_lhs_mm && !scale_rhs_mm) { 3642 return nullptr; 3643 } 3644 3645 const ggml_tensor * scale = scale_lhs_mm ? scale_node->src[1] : scale_node->src[0]; 3646 if (mm_node->src[0]->type != GGML_TYPE_NVFP4 || scale_node->type != GGML_TYPE_F32 || 3647 scale->type != GGML_TYPE_F32 || !ggml_is_contiguous(scale) || ggml_nelements(scale) != 1 || 3648 !ggml_are_same_shape(scale_node, mm_node)) { 3649 return nullptr; 3650 } 3651 3652 return scale; 3653 }; 3654 3655 auto get_mul_mat_id_scale = [](const ggml_tensor * reshape, const ggml_tensor * repeat, const ggml_tensor * getrows, 3656 const ggml_tensor * scale_node, const ggml_tensor * mm_node) -> const ggml_tensor * { 3657 if (repeat->src[0] != reshape || getrows->src[0] != repeat || getrows->src[1] != mm_node->src[2]) { 3658 return nullptr; 3659 } 3660 if (!((scale_node->src[0] == mm_node && scale_node->src[1] == getrows) || 3661 (scale_node->src[0] == getrows && scale_node->src[1] == mm_node))) { 3662 return nullptr; 3663 } 3664 3665 const ggml_tensor * scale = reshape->src[0]; 3666 if (mm_node->src[0]->type != GGML_TYPE_NVFP4 || scale_node->type != GGML_TYPE_F32 || 3667 scale->type != GGML_TYPE_F32 || !ggml_is_contiguous(scale) || ggml_nelements(scale) != mm_node->src[0]->ne[2] || 3668 !ggml_are_same_shape(scale_node, mm_node)) { 3669 return nullptr; 3670 } 3671 3672 return scale; 3673 }; 3674 3675 auto get_bias_tensor = [](const ggml_tensor * bias_node, const ggml_tensor * mul_node, ggml_op op_bias) -> const ggml_tensor * { 3676 if (op_bias == GGML_OP_ADD) { 3677 if (bias_node->src[0] == mul_node) { 3678 return bias_node->src[1]; 3679 } 3680 if (bias_node->src[1] == mul_node) { 3681 return bias_node->src[0]; 3682 } 3683 return nullptr; 3684 } 3685 GGML_ASSERT(op_bias == GGML_OP_ADD_ID); 3686 GGML_ASSERT(bias_node->src[0] == mul_node); 3687 return bias_node->src[1]; 3688 }; 3689 3690 // gate + glu + up, with optional scale/bias on both lanes. 3691 for (ggml_op op : { GGML_OP_MUL_MAT, GGML_OP_MUL_MAT_ID }) { 3692 const ggml_op bias_op = op == GGML_OP_MUL_MAT ? GGML_OP_ADD : GGML_OP_ADD_ID; 3693 3694 if (op == GGML_OP_MUL_MAT) { 3695 for (const bool with_bias : { false, true }) { 3696 const int gate_idx = i; 3697 const int gate_scale_idx = i + 1; 3698 const int gate_bias_idx = with_bias ? i + 2 : -1; 3699 const int up_idx = with_bias ? i + 3 : i + 2; 3700 const int up_scale_idx = up_idx + 1; 3701 const int up_bias_idx = with_bias ? up_idx + 2 : -1; 3702 const int glu_idx = with_bias ? up_idx + 3 : up_idx + 2; 3703 3704 const int out_nodes[] = { glu_idx }; 3705 ggml_op ops[7]; 3706 if (with_bias) { 3707 ops[0] = op; 3708 ops[1] = GGML_OP_MUL; 3709 ops[2] = bias_op; 3710 ops[3] = op; 3711 ops[4] = GGML_OP_MUL; 3712 ops[5] = bias_op; 3713 ops[6] = GGML_OP_GLU; 3714 } else { 3715 ops[0] = op; 3716 ops[1] = GGML_OP_MUL; 3717 ops[2] = op; 3718 ops[3] = GGML_OP_MUL; 3719 ops[4] = GGML_OP_GLU; 3720 } 3721 const int n_ops = with_bias ? 7 : 5; 3722 3723 if (!ggml_can_fuse_subgraph(cgraph, i, n_ops, ops, out_nodes, 1) || 3724 !ggml_cuda_check_fusion_memory_ranges(cgraph, i, n_ops, out_nodes, 1)) { 3725 continue; 3726 } 3727 3728 ggml_tensor * gate_n = cgraph->nodes[gate_idx]; 3729 ggml_tensor * gate_scale_n = cgraph->nodes[gate_scale_idx]; 3730 ggml_tensor * gate_out_n = with_bias ? cgraph->nodes[gate_bias_idx] : gate_scale_n; 3731 ggml_tensor * up_n = cgraph->nodes[up_idx]; 3732 ggml_tensor * up_scale_n = cgraph->nodes[up_scale_idx]; 3733 ggml_tensor * up_out_n = with_bias ? cgraph->nodes[up_bias_idx] : up_scale_n; 3734 const ggml_tensor * glu = cgraph->nodes[glu_idx]; 3735 3736 if (!ggml_cuda_should_fuse_mul_mat(up_n, gate_n, glu, 3737 with_bias ? up_out_n : nullptr, with_bias ? gate_out_n : nullptr, up_scale_n, gate_scale_n)) { 3738 continue; 3739 } 3740 3741 const ggml_tensor * gate_scale = get_mul_mat_scale(gate_scale_n, gate_n); 3742 const ggml_tensor * up_scale = get_mul_mat_scale(up_scale_n, up_n); 3743 if (!gate_scale || !up_scale) { 3744 continue; 3745 } 3746 3747 const ggml_tensor * up_bias = with_bias ? get_bias_tensor(up_out_n, up_scale_n, bias_op) : nullptr; 3748 const ggml_tensor * gate_bias = with_bias ? get_bias_tensor(gate_out_n, gate_scale_n, bias_op) : nullptr; 3749 if (with_bias && (!ggml_are_same_shape(gate_out_n->src[0], gate_out_n->src[1]) || 3750 !ggml_are_same_shape(up_out_n->src[0], up_out_n->src[1]))) { 3751 continue; 3752 } 3753 3754 const ggml_tensor * src0 = up_n->src[0]; 3755 const ggml_tensor * src1 = up_n->src[1]; 3756 const ggml_tensor * ids = up_n->src[2]; 3757 3758 ggml_cuda_mm_fusion_args_host fusion_data{}; 3759 fusion_data.gate = gate_n->src[0]; 3760 fusion_data.x_bias = up_bias; 3761 fusion_data.gate_bias = gate_bias; 3762 fusion_data.x_scale = up_scale; 3763 fusion_data.gate_scale = gate_scale; 3764 fusion_data.glu_op = ggml_get_glu_op(glu); 3765 fusion_data.glu_limit = ggml_get_op_params_f32(glu, 3); 3766 3767 if (ggml_cuda_should_fuse_mul_mat_vec_q(up_n)) { 3768 ggml_cuda_mul_mat_vec_q(*cuda_ctx, src0, src1, ids, cgraph->nodes[glu_idx], &fusion_data); 3769 fused_mul_mat_vec = true; 3770 fused_node_count = n_ops; 3771 break; 3772 } 3773 } 3774 3775 if (fused_mul_mat_vec) { 3776 break; 3777 } 3778 } else { 3779 for (const bool with_bias : { false, true }) { 3780 const int gate_idx = i; 3781 const int gate_scale_idx = i + 4; 3782 const int gate_bias_idx = with_bias ? i + 5 : -1; 3783 const int up_idx = with_bias ? i + 6 : i + 5; 3784 const int up_scale_idx = up_idx + 4; 3785 const int up_bias_idx = with_bias ? up_idx + 5 : -1; 3786 const int glu_idx = with_bias ? up_idx + 6 : up_idx + 5; 3787 3788 const int out_nodes[] = { glu_idx }; 3789 ggml_op ops[13]; 3790 if (with_bias) { 3791 ops[0] = op; 3792 ops[1] = GGML_OP_RESHAPE; 3793 ops[2] = GGML_OP_REPEAT; 3794 ops[3] = GGML_OP_GET_ROWS; 3795 ops[4] = GGML_OP_MUL; 3796 ops[5] = bias_op; 3797 ops[6] = op; 3798 ops[7] = GGML_OP_RESHAPE; 3799 ops[8] = GGML_OP_REPEAT; 3800 ops[9] = GGML_OP_GET_ROWS; 3801 ops[10] = GGML_OP_MUL; 3802 ops[11] = bias_op; 3803 ops[12] = GGML_OP_GLU; 3804 } else { 3805 ops[0] = op; 3806 ops[1] = GGML_OP_RESHAPE; 3807 ops[2] = GGML_OP_REPEAT; 3808 ops[3] = GGML_OP_GET_ROWS; 3809 ops[4] = GGML_OP_MUL; 3810 ops[5] = op; 3811 ops[6] = GGML_OP_RESHAPE; 3812 ops[7] = GGML_OP_REPEAT; 3813 ops[8] = GGML_OP_GET_ROWS; 3814 ops[9] = GGML_OP_MUL; 3815 ops[10] = GGML_OP_GLU; 3816 } 3817 const int n_ops = with_bias ? 13 : 11; 3818 3819 if (!ggml_can_fuse_subgraph(cgraph, i, n_ops, ops, out_nodes, 1) || 3820 !ggml_cuda_check_fusion_memory_ranges(cgraph, i, n_ops, out_nodes, 1)) { 3821 continue; 3822 } 3823 3824 ggml_tensor * gate_n = cgraph->nodes[gate_idx]; 3825 ggml_tensor * gate_scale_n = cgraph->nodes[gate_scale_idx]; 3826 ggml_tensor * gate_out_n = with_bias ? cgraph->nodes[gate_bias_idx] : gate_scale_n; 3827 ggml_tensor * up_n = cgraph->nodes[up_idx]; 3828 ggml_tensor * up_scale_n = cgraph->nodes[up_scale_idx]; 3829 ggml_tensor * up_out_n = with_bias ? cgraph->nodes[up_bias_idx] : up_scale_n; 3830 const ggml_tensor * glu = cgraph->nodes[glu_idx]; 3831 3832 if (!ggml_cuda_should_fuse_mul_mat(up_n, gate_n, glu, 3833 with_bias ? up_out_n : nullptr, with_bias ? gate_out_n : nullptr, up_scale_n, gate_scale_n)) { 3834 continue; 3835 } 3836 3837 const ggml_tensor * gate_scale = get_mul_mat_id_scale(cgraph->nodes[gate_idx + 1], cgraph->nodes[gate_idx + 2], 3838 cgraph->nodes[gate_idx + 3], gate_scale_n, gate_n); 3839 const ggml_tensor * up_scale = get_mul_mat_id_scale(cgraph->nodes[up_idx + 1], cgraph->nodes[up_idx + 2], 3840 cgraph->nodes[up_idx + 3], up_scale_n, up_n); 3841 if (!gate_scale || !up_scale) { 3842 continue; 3843 } 3844 3845 const ggml_tensor * up_bias = with_bias ? get_bias_tensor(up_out_n, up_scale_n, bias_op) : nullptr; 3846 const ggml_tensor * gate_bias = with_bias ? get_bias_tensor(gate_out_n, gate_scale_n, bias_op) : nullptr; 3847 3848 const ggml_tensor * src0 = up_n->src[0]; 3849 const ggml_tensor * src1 = up_n->src[1]; 3850 const ggml_tensor * ids = up_n->src[2]; 3851 3852 ggml_cuda_mm_fusion_args_host fusion_data{}; 3853 fusion_data.gate = gate_n->src[0]; 3854 fusion_data.x_bias = up_bias; 3855 fusion_data.gate_bias = gate_bias; 3856 fusion_data.x_scale = up_scale; 3857 fusion_data.gate_scale = gate_scale; 3858 fusion_data.glu_op = ggml_get_glu_op(glu); 3859 fusion_data.glu_limit = ggml_get_op_params_f32(glu, 3); 3860 3861 if (ggml_cuda_should_fuse_mul_mat_vec_q(up_n)) { 3862 ggml_cuda_mul_mat_vec_q(*cuda_ctx, src0, src1, ids, cgraph->nodes[glu_idx], &fusion_data); 3863 fused_mul_mat_vec = true; 3864 fused_node_count = n_ops; 3865 break; 3866 } 3867 } 3868 3869 if (fused_mul_mat_vec) { 3870 break; 3871 } 3872 } 3873 3874 if (ggml_cuda_can_fuse(cgraph, i, { op, bias_op, op, bias_op, GGML_OP_GLU }, {})) { 3875 ggml_tensor * glu = cgraph->nodes[i + 4]; 3876 ggml_tensor * gate_bias_n = glu->src[0]; 3877 ggml_tensor * up_bias_n = glu->src[1]; 3878 3879 //we don't assume the order for {gate, up}. Instead infer it from the bias tensor 3880 ggml_tensor * gate_n = nullptr; 3881 ggml_tensor * up_n = nullptr; 3882 3883 if (gate_bias_n->src[0] == cgraph->nodes[i] || gate_bias_n->src[1] == cgraph->nodes[i]) { 3884 gate_n = cgraph->nodes[i]; 3885 up_n = cgraph->nodes[i + 2]; 3886 } else if (gate_bias_n->src[0] == cgraph->nodes[i + 2] || gate_bias_n->src[1] == cgraph->nodes[i + 2]) { 3887 gate_n = cgraph->nodes[i + 2]; 3888 up_n = cgraph->nodes[i]; 3889 } else { 3890 continue; 3891 } 3892 3893 const ggml_tensor * up_bias_tensor = get_bias_tensor(up_bias_n, up_n, bias_op); 3894 const ggml_tensor * gate_bias_tensor = get_bias_tensor(gate_bias_n, gate_n, bias_op); 3895 3896 if (!up_bias_tensor || !gate_bias_tensor) { 3897 continue; 3898 } 3899 3900 // we don't support repeating adds 3901 if (bias_op == GGML_OP_ADD && (!ggml_are_same_shape(gate_bias_n->src[0], gate_bias_n->src[1]) || 3902 !ggml_are_same_shape(up_bias_n->src[0], up_bias_n->src[1]))) { 3903 continue; 3904 } 3905 3906 const ggml_tensor * src0 = up_n->src[0]; 3907 const ggml_tensor * src1 = up_n->src[1]; 3908 const ggml_tensor * ids = up_n->src[2]; 3909 3910 if (ggml_cuda_should_fuse_mul_mat_vec_f(up_n)) { 3911 ggml_cuda_mm_fusion_args_host fusion_data{}; 3912 fusion_data.gate = gate_n->src[0]; 3913 fusion_data.x_bias = up_bias_tensor; 3914 fusion_data.gate_bias = gate_bias_tensor; 3915 fusion_data.glu_op = ggml_get_glu_op(glu); 3916 fusion_data.glu_limit = ggml_get_op_params_f32(glu, 3); 3917 3918 ggml_cuda_mul_mat_vec_f(*cuda_ctx, src0, src1, ids, glu, &fusion_data); 3919 fused_mul_mat_vec = true; 3920 fused_node_count = 5; 3921 break; 3922 } 3923 3924 if (ggml_cuda_should_fuse_mul_mat_vec_q(up_n)) { 3925 ggml_cuda_mm_fusion_args_host fusion_data{}; 3926 fusion_data.gate = gate_n->src[0]; 3927 fusion_data.x_bias = up_bias_tensor; 3928 fusion_data.gate_bias = gate_bias_tensor; 3929 fusion_data.glu_op = ggml_get_glu_op(glu); 3930 fusion_data.glu_limit = ggml_get_op_params_f32(glu, 3); 3931 3932 ggml_cuda_mul_mat_vec_q(*cuda_ctx, src0, src1, ids, glu, &fusion_data); 3933 fused_mul_mat_vec = true; 3934 fused_node_count = 5; 3935 break; 3936 } 3937 } else if (ggml_cuda_can_fuse(cgraph, i, { op, op, GGML_OP_GLU }, {})) { 3938 ggml_tensor * glu = cgraph->nodes[i + 2]; 3939 ggml_tensor * gate = glu->src[0]; 3940 ggml_tensor * up = glu->src[1]; 3941 3942 bool ok = (gate == cgraph->nodes[i] && up == cgraph->nodes[i + 1]) || 3943 (gate == cgraph->nodes[i + 1] && up == cgraph->nodes[i]); 3944 3945 if (!ok) { 3946 continue; 3947 } 3948 3949 const ggml_tensor * src0 = up->src[0]; 3950 const ggml_tensor * src1 = up->src[1]; 3951 const ggml_tensor * ids = up->src[2]; 3952 3953 if (ggml_cuda_should_fuse_mul_mat_vec_f(up)) { 3954 ggml_cuda_mm_fusion_args_host fusion_data{}; 3955 fusion_data.gate = gate->src[0]; 3956 fusion_data.glu_op = ggml_get_glu_op(glu); 3957 fusion_data.glu_limit = ggml_get_op_params_f32(glu, 3); 3958 3959 ggml_cuda_mul_mat_vec_f(*cuda_ctx, src0, src1, ids, glu, &fusion_data); 3960 fused_mul_mat_vec = true; 3961 fused_node_count = 3; 3962 break; 3963 } 3964 3965 if (ggml_cuda_should_fuse_mul_mat_vec_q(up)) { 3966 ggml_cuda_mm_fusion_args_host fusion_data{}; 3967 fusion_data.gate = gate->src[0]; 3968 fusion_data.glu_op = ggml_get_glu_op(glu); 3969 fusion_data.glu_limit = ggml_get_op_params_f32(glu, 3); 3970 3971 ggml_cuda_mul_mat_vec_q(*cuda_ctx, src0, src1, ids, glu, &fusion_data); 3972 fused_mul_mat_vec = true; 3973 fused_node_count = 3; 3974 break; 3975 } 3976 } 3977 } 3978 3979 if (fused_mul_mat_vec) { 3980 return fused_node_count - 1; 3981 } 3982 3983 fused_mul_mat_vec = false; 3984 fused_node_count = 0; 3985 3986 // mul_mat + scale + optional bias 3987 for (ggml_op op : { GGML_OP_MUL_MAT, GGML_OP_MUL_MAT_ID }) { 3988 const ggml_op bias_op = op == GGML_OP_MUL_MAT ? GGML_OP_ADD : GGML_OP_ADD_ID; 3989 3990 for (const bool with_bias : { false, true }) { 3991 const int n_ops = op == GGML_OP_MUL_MAT ? (with_bias ? 3 : 2) : (with_bias ? 6 : 5); 3992 const int out_nodes[] = { i + n_ops - 1 }; 3993 ggml_op ops[6]; 3994 if (op == GGML_OP_MUL_MAT) { 3995 if (with_bias) { 3996 ops[0] = op; 3997 ops[1] = GGML_OP_MUL; 3998 ops[2] = bias_op; 3999 } else { 4000 ops[0] = op; 4001 ops[1] = GGML_OP_MUL; 4002 } 4003 } else { 4004 if (with_bias) { 4005 ops[0] = op; 4006 ops[1] = GGML_OP_RESHAPE; 4007 ops[2] = GGML_OP_REPEAT; 4008 ops[3] = GGML_OP_GET_ROWS; 4009 ops[4] = GGML_OP_MUL; 4010 ops[5] = bias_op; 4011 } else { 4012 ops[0] = op; 4013 ops[1] = GGML_OP_RESHAPE; 4014 ops[2] = GGML_OP_REPEAT; 4015 ops[3] = GGML_OP_GET_ROWS; 4016 ops[4] = GGML_OP_MUL; 4017 } 4018 } 4019 4020 if (!ggml_can_fuse_subgraph(cgraph, i, n_ops, ops, out_nodes, 1) || 4021 !ggml_cuda_check_fusion_memory_ranges(cgraph, i, n_ops, out_nodes, 1)) { 4022 continue; 4023 } 4024 4025 ggml_tensor * mm_node = cgraph->nodes[i]; 4026 ggml_tensor * scale_node = op == GGML_OP_MUL_MAT ? cgraph->nodes[i + 1] : cgraph->nodes[i + 4]; 4027 ggml_tensor * out_node = with_bias ? cgraph->nodes[i + n_ops - 1] : scale_node; 4028 4029 const ggml_tensor * scale = nullptr; 4030 if (op == GGML_OP_MUL_MAT) { 4031 scale = get_mul_mat_scale(scale_node, mm_node); 4032 } else { 4033 scale = get_mul_mat_id_scale(cgraph->nodes[i + 1], cgraph->nodes[i + 2], cgraph->nodes[i + 3], scale_node, mm_node); 4034 } 4035 if (!scale) { 4036 continue; 4037 } 4038 4039 const ggml_tensor * bias = with_bias ? get_bias_tensor(out_node, scale_node, bias_op) : nullptr; 4040 if (with_bias && !bias) { 4041 continue; 4042 } 4043 if (with_bias && bias_op == GGML_OP_ADD && !ggml_are_same_shape(out_node->src[0], out_node->src[1])) { 4044 continue; 4045 } 4046 if (with_bias && bias_op == GGML_OP_ADD_ID && out_node->src[2] != mm_node->src[2]) { 4047 continue; 4048 } 4049 4050 const ggml_tensor * src0 = mm_node->src[0]; 4051 const ggml_tensor * src1 = mm_node->src[1]; 4052 const ggml_tensor * ids = mm_node->src[2]; 4053 4054 ggml_cuda_mm_fusion_args_host fusion_data{}; 4055 fusion_data.x_bias = bias; 4056 fusion_data.x_scale = scale; 4057 4058 if (ggml_cuda_should_fuse_mul_mat_vec_q(mm_node)) { 4059 ggml_cuda_mul_mat_vec_q(*cuda_ctx, src0, src1, ids, out_node, &fusion_data); 4060 fused_mul_mat_vec = true; 4061 fused_node_count = n_ops; 4062 break; 4063 } 4064 } 4065 if (fused_mul_mat_vec) { 4066 break; 4067 } 4068 } 4069 4070 if (fused_mul_mat_vec) { 4071 return fused_node_count - 1; 4072 } 4073 4074 // mul_mat + add 4075 for (ggml_op op : { GGML_OP_MUL_MAT, GGML_OP_MUL_MAT_ID }) { 4076 const ggml_op bias_op = op == GGML_OP_MUL_MAT ? GGML_OP_ADD : GGML_OP_ADD_ID; 4077 4078 if (!ggml_can_fuse(cgraph, i, { op, bias_op })) { 4079 continue; 4080 } 4081 4082 ggml_tensor * mm_node = cgraph->nodes[i]; 4083 ggml_tensor * bias_node = cgraph->nodes[i + 1]; 4084 4085 ggml_tensor * bias_tensor = nullptr; 4086 if (bias_op == GGML_OP_ADD) { 4087 if (bias_node->src[0] == mm_node) { 4088 bias_tensor = bias_node->src[1]; 4089 } else if (bias_node->src[1] == mm_node) { 4090 bias_tensor = bias_node->src[0]; 4091 } else { 4092 continue; 4093 } 4094 } else { 4095 if (bias_node->src[0] != mm_node) { 4096 continue; 4097 } 4098 bias_tensor = bias_node->src[1]; 4099 } 4100 4101 const ggml_tensor * src0 = mm_node->src[0]; 4102 const ggml_tensor * src1 = mm_node->src[1]; 4103 const ggml_tensor * ids = mm_node->src[2]; 4104 4105 if (bias_op == GGML_OP_ADD_ID && bias_node->src[2] != ids) { 4106 continue; 4107 } 4108 4109 if (bias_op == GGML_OP_ADD && !ggml_are_same_shape(bias_node->src[0], bias_node->src[1])) { 4110 continue; 4111 } 4112 4113 ggml_cuda_mm_fusion_args_host fusion_data{}; 4114 fusion_data.x_bias = bias_tensor; 4115 4116 if (ggml_cuda_should_fuse_mul_mat_vec_f(mm_node)) { 4117 ggml_cuda_mul_mat_vec_f(*cuda_ctx, src0, src1, ids, bias_node, &fusion_data); 4118 fused_mul_mat_vec = true; 4119 fused_node_count = 2; 4120 break; 4121 } 4122 4123 if (ggml_cuda_should_fuse_mul_mat_vec_q(mm_node)) { 4124 ggml_cuda_mul_mat_vec_q(*cuda_ctx, src0, src1, ids, bias_node, &fusion_data); 4125 fused_mul_mat_vec = true; 4126 fused_node_count = 2; 4127 break; 4128 } 4129 } 4130 4131 if (fused_mul_mat_vec) { 4132 return fused_node_count - 1; 4133 } 4134 4135 if (ggml_cuda_can_fuse(cgraph, i, { GGML_OP_RMS_NORM, GGML_OP_MUL, GGML_OP_ROPE, GGML_OP_VIEW, GGML_OP_SET_ROWS }, {})) { 4136 ggml_cuda_op_rms_norm_mul_rope_fused(*cuda_ctx, node, cgraph->nodes[i + 1], cgraph->nodes[i + 2], cgraph->nodes[i + 4]); 4137 return 4; 4138 } 4139 4140 if (ggml_cuda_can_fuse(cgraph, i, { GGML_OP_RMS_NORM, GGML_OP_MUL, GGML_OP_ROPE }, {})) { 4141 ggml_cuda_op_rms_norm_mul_rope_fused(*cuda_ctx, node, cgraph->nodes[i + 1], cgraph->nodes[i + 2], nullptr); 4142 return 2; 4143 } 4144 4145 if (ggml_cuda_can_fuse(cgraph, i, { GGML_OP_RMS_NORM, GGML_OP_MUL, GGML_OP_ADD }, {})) { 4146 ggml_cuda_op_rms_norm_fused_add(*cuda_ctx, node, cgraph->nodes[i + 1], cgraph->nodes[i + 2]); 4147 return 2; 4148 } 4149 4150 if (ggml_cuda_can_fuse(cgraph, i, { GGML_OP_RMS_NORM, GGML_OP_MUL }, {})) { 4151 ggml_cuda_op_rms_norm_fused(*cuda_ctx, node, cgraph->nodes[i + 1]); 4152 return 1; 4153 } 4154 4155 if (ggml_cuda_can_fuse(cgraph, i, { GGML_OP_SSM_CONV, GGML_OP_ADD, GGML_OP_UNARY }, { GGML_UNARY_OP_SILU })) { 4156 ggml_cuda_op_ssm_conv(*cuda_ctx, node, cgraph->nodes[i + 1], cgraph->nodes[i + 2]); 4157 return 2; 4158 } 4159 4160 if (ggml_cuda_can_fuse(cgraph, i, { GGML_OP_SSM_CONV, GGML_OP_UNARY }, { GGML_UNARY_OP_SILU })) { 4161 ggml_cuda_op_ssm_conv(*cuda_ctx, node, /*bias_add_node=*/ nullptr, cgraph->nodes[i + 1]); 4162 return 1; 4163 } 4164 4165 if (ggml_cuda_can_fuse(cgraph, i, { GGML_OP_UNARY, GGML_OP_MUL }, { GGML_UNARY_OP_SILU }) || 4166 ggml_cuda_can_fuse(cgraph, i, { GGML_OP_UNARY, GGML_OP_MUL }, { GGML_UNARY_OP_SIGMOID }) || 4167 ggml_cuda_can_fuse(cgraph, i, { GGML_OP_UNARY, GGML_OP_MUL }, { GGML_UNARY_OP_SOFTPLUS })) { 4168 ggml_cuda_op_unary_mul(*cuda_ctx, node, cgraph->nodes[i + 1]); 4169 return 1; 4170 } 4171 4172 if (ggml_cuda_can_fuse(cgraph, i, { GGML_OP_UNARY, GGML_OP_SQR }, { GGML_UNARY_OP_RELU })) { 4173 ggml_cuda_op_relu_sqr(*cuda_ctx, node, cgraph->nodes[i + 1]); 4174 return 1; 4175 } 4176 4177 if (ggml_cuda_can_fuse(cgraph, i, { GGML_OP_SCALE, GGML_OP_UNARY, GGML_OP_SCALE }, { GGML_UNARY_OP_TANH })) { 4178 ggml_cuda_op_softcap(*cuda_ctx, cgraph->nodes[i + 2], node); 4179 return 2; 4180 } 4181 4182 return 0; 4183} 4184 4185static void ggml_cuda_graph_evaluate_and_capture(ggml_backend_cuda_context * cuda_ctx, ggml_cgraph * cgraph, const bool use_cuda_graph, const bool cuda_graph_update_required, const void * graph_key) { 4186 bool graph_evaluated_or_captured = false; 4187 4188 // flag used to determine whether it is an integrated_gpu 4189 const bool integrated = ggml_cuda_info().devices[cuda_ctx->device].integrated; 4190 4191 ggml_cuda_stream_context & stream_ctx = cuda_ctx->stream_context(); 4192 bool is_concurrent_event_active = false; 4193 ggml_cuda_concurrent_event * concurrent_event = nullptr; 4194 bool should_launch_concurrent_events = false; 4195 4196 const auto try_launch_concurrent_event = [&](const ggml_tensor * node) { 4197 if (stream_ctx.concurrent_events.find(node) != stream_ctx.concurrent_events.end()) { 4198 concurrent_event = &stream_ctx.concurrent_events[node]; 4199 4200 is_concurrent_event_active = true; 4201 4202 GGML_LOG_DEBUG("Launching %d streams at %s\n", concurrent_event->n_streams, node->name); 4203 4204 cudaStream_t main_stream = cuda_ctx->stream(); // this should be stream 0 4205 GGML_ASSERT(cuda_ctx->curr_stream_no == 0); 4206 CUDA_CHECK(cudaEventRecord(concurrent_event->fork_event, main_stream)); 4207 4208 for (int i = 1; i <= concurrent_event->n_streams; ++i) { 4209 cudaStream_t stream = cuda_ctx->stream(cuda_ctx->device, i); 4210 CUDA_CHECK(cudaStreamWaitEvent(stream, concurrent_event->fork_event)); 4211 } 4212 } 4213 }; 4214 4215 while (!graph_evaluated_or_captured) { 4216 // Only perform the graph execution if CUDA graphs are not enabled, or we are capturing the graph. 4217 // With the use of CUDA graphs, the execution will be performed by the graph launch. 4218 if (!use_cuda_graph || cuda_graph_update_required) { 4219 [[maybe_unused]] int prev_i = 0; 4220 4221 if (stream_ctx.concurrent_events.size() > 0) { 4222 should_launch_concurrent_events = true; 4223 for (const auto & [tensor, event] : stream_ctx.concurrent_events) { 4224 should_launch_concurrent_events = should_launch_concurrent_events && event.is_valid(); 4225 } 4226 } 4227 4228 if (should_launch_concurrent_events) { 4229 // Restore original node order within each concurrent region to enable fusion within streams 4230 4231 std::unordered_map<const ggml_tensor *, int> node_to_idx; 4232 node_to_idx.reserve(cgraph->n_nodes); 4233 for (int i = 0; i < cgraph->n_nodes; ++i) { 4234 node_to_idx[cgraph->nodes[i]] = i; 4235 } 4236 4237 for (auto & [fork_node, event] : stream_ctx.concurrent_events) { 4238 // Find positions of all nodes from this event in the current graph 4239 std::vector<int> positions; 4240 positions.reserve(event.original_order.size()); 4241 4242 bool all_found = true; 4243 for (const ggml_tensor * orig_node : event.original_order) { 4244 auto it = node_to_idx.find(orig_node); 4245 if (it != node_to_idx.end()) { 4246 positions.push_back(it->second); 4247 } else { 4248 all_found = false; 4249 break; 4250 } 4251 } 4252 4253 if (!all_found || positions.size() != event.original_order.size()) { 4254 continue; 4255 } 4256 4257 // Sort positions to get contiguous range 4258 std::vector<int> sorted_positions = positions; 4259 std::sort(sorted_positions.begin(), sorted_positions.end()); 4260 4261 bool is_contiguous = true; 4262 for (size_t i = 1; i < sorted_positions.size(); ++i) { 4263 if (sorted_positions[i] != sorted_positions[i-1] + 1) { 4264 is_contiguous = false; 4265 break; 4266 } 4267 } 4268 4269 if (!is_contiguous) { 4270 continue; 4271 } 4272 4273 // Restore original order at the sorted positions 4274 int start_pos = sorted_positions[0]; 4275 for (size_t i = 0; i < event.original_order.size(); ++i) { 4276 cgraph->nodes[start_pos + i] = const_cast<ggml_tensor *>(event.original_order[i]); 4277 } 4278 } 4279 } else { 4280 stream_ctx.concurrent_events.clear(); 4281 } 4282 4283 for (int i = 0; i < cgraph->n_nodes; i++) { 4284 ggml_tensor * node = cgraph->nodes[i]; 4285 if (is_concurrent_event_active) { 4286 GGML_ASSERT(concurrent_event); 4287 4288 if (node == concurrent_event->join_node) { 4289 cuda_ctx->curr_stream_no = 0; 4290 for (int i = 1; i <= concurrent_event->n_streams; ++i) { 4291 // Wait on join events of forked streams in the main stream 4292 CUDA_CHECK(cudaEventRecord(concurrent_event->join_events[i - 1], 4293 cuda_ctx->stream(cuda_ctx->device, i))); 4294 CUDA_CHECK(cudaStreamWaitEvent(cuda_ctx->stream(), concurrent_event->join_events[i - 1])); 4295 } 4296 4297 is_concurrent_event_active = false; 4298 concurrent_event = nullptr; 4299 } else { 4300 GGML_ASSERT (concurrent_event->stream_mapping.find(node) != concurrent_event->stream_mapping.end()); 4301 cuda_ctx->curr_stream_no = concurrent_event->stream_mapping[node]; 4302 GGML_LOG_DEBUG("Setting stream no to %d for node %s\n", cuda_ctx->curr_stream_no, node->name); 4303 } 4304 } else if (i - prev_i > 1) { 4305 //the previous node was fused 4306 const ggml_tensor * prev_node = cgraph->nodes[i - 1]; 4307 try_launch_concurrent_event(prev_node); 4308 4309 if (is_concurrent_event_active) { 4310 cuda_ctx->curr_stream_no = concurrent_event->stream_mapping[node]; 4311 GGML_LOG_DEBUG("Setting stream no to %d for node %s\n", cuda_ctx->curr_stream_no, node->name); 4312 } 4313 } 4314 4315 prev_i = i; 4316 4317 if (ggml_cuda_is_view_or_noop(node)) { 4318 continue; 4319 } 4320 4321 if ((node->flags & GGML_TENSOR_FLAG_COMPUTE) == 0) { 4322 continue; 4323 } 4324 4325 int nodes_to_skip = ggml_cuda_try_fuse(cuda_ctx, cgraph, i); 4326 4327 if (nodes_to_skip != 0) { 4328#ifdef GGML_CUDA_DEBUG 4329 const int last_fused = i + nodes_to_skip; 4330 GGML_LOG_INFO("nodes_fused: %d, first: %s (%s), last: %s (%s)\n", 4331 nodes_to_skip + 1, ggml_op_name(node->op), node->name, 4332 ggml_op_name(cgraph->nodes[last_fused]->op), cgraph->nodes[last_fused]->name); 4333#endif 4334 i += nodes_to_skip; 4335 continue; 4336 } 4337#ifndef NDEBUG 4338 // On integrated GPUs (APUs, e.g. RDNA3.5) the scheduler may place a 4339 // node's output on the host-visible buffer, which the compute path 4340 // handles. Allow that here, mirroring the src-tensor check below. 4341 assert(node->buffer->buft == ggml_backend_cuda_buffer_type(cuda_ctx->device) || 4342 (integrated && ggml_backend_buft_is_cuda_host(node->buffer->buft))); 4343 for (int j = 0; j < GGML_MAX_SRC; j++) { 4344 if (node->src[j] != nullptr) { 4345 assert(node->src[j]->buffer); 4346 assert(node->src[j]->buffer->buft == ggml_backend_cuda_buffer_type(cuda_ctx->device) || 4347 (integrated && ggml_backend_buft_is_cuda_host(node->src[j]->buffer->buft))); 4348 } 4349 } 4350#else 4351 GGML_UNUSED(integrated); 4352#endif // NDEBUG 4353 4354 bool ok = ggml_cuda_compute_forward(*cuda_ctx, node); 4355 if (!ok) { 4356 GGML_LOG_ERROR("%s: op not supported %s (%s)\n", __func__, node->name, ggml_op_name(node->op)); 4357 } 4358 GGML_ASSERT(ok); 4359 4360 if (!is_concurrent_event_active) { 4361 try_launch_concurrent_event(node); 4362 } 4363 } 4364 } 4365 4366#ifdef USE_CUDA_GRAPH 4367 ggml_cuda_graph * graph = cuda_ctx->cuda_graph(graph_key); 4368 if (use_cuda_graph && cuda_graph_update_required) { // End CUDA graph capture 4369 if (graph->graph != nullptr) { 4370 CUDA_CHECK(cudaGraphDestroy(graph->graph)); 4371 graph->graph = nullptr; 4372 } 4373 4374 CUDA_CHECK(cudaStreamEndCapture(cuda_ctx->stream(), &graph->graph)); 4375 graph_evaluated_or_captured = true; // CUDA graph has been captured 4376 4377 std::lock_guard<std::mutex> lock(ggml_cuda_lock); 4378 if (ggml_cuda_lock_counter.fetch_sub(1, std::memory_order_relaxed) == 1) { 4379 ggml_cuda_lock_cv.notify_all(); 4380 } 4381 } else { 4382 graph_evaluated_or_captured = true; // ggml graph has been directly evaluated 4383 } 4384 } 4385 4386 if (use_cuda_graph) { 4387 ggml_cuda_graph * graph = cuda_ctx->cuda_graph(graph_key); 4388 if (graph->instance == nullptr) { // Create executable graph from captured graph. 4389 CUDA_CHECK(cudaGraphInstantiate(&graph->instance, graph->graph, NULL, NULL, 0)); 4390 } 4391 if (cuda_graph_update_required) { // Update graph executable 4392 ggml_cuda_graph_update_executable(cuda_ctx, graph_key); 4393 } 4394 // Launch graph 4395 CUDA_CHECK(cudaGraphLaunch(graph->instance, cuda_ctx->stream())); 4396#else 4397 GGML_UNUSED(graph_key); 4398 graph_evaluated_or_captured = true; 4399#endif // USE_CUDA_GRAPH 4400 } 4401} 4402 4403#ifdef USE_CUDA_GRAPH 4404static bool ggml_cuda_graph_set_enabled(ggml_backend_cuda_context * cuda_ctx, const void * graph_key) { 4405 ggml_cuda_graph * graph = cuda_ctx->cuda_graph(graph_key); 4406 4407 if (graph->graph == nullptr) { 4408 if (ggml_cuda_info().devices[cuda_ctx->device].cc < GGML_CUDA_CC_VOLTA) { 4409 if (!graph->disable_due_to_gpu_arch) { 4410 GGML_LOG_DEBUG("%s: disabling CUDA graphs due to GPU architecture\n", __func__); 4411 } 4412 graph->disable_due_to_gpu_arch = true; 4413 } 4414 } 4415 4416 return graph->is_enabled(); 4417} 4418#endif // USE_CUDA_GRAPH 4419 4420static enum ggml_status ggml_backend_cuda_graph_compute(ggml_backend_t backend, ggml_cgraph * cgraph) { 4421 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *) backend->context; 4422 4423 ggml_cuda_set_device(cuda_ctx->device); 4424 4425 bool use_cuda_graph = false; 4426 bool cuda_graph_update_required = false; 4427 const void * graph_key = nullptr; 4428 4429#ifdef USE_CUDA_GRAPH 4430 graph_key = ggml_cuda_graph_get_key(cgraph); 4431 4432 ggml_cuda_graph_set_enabled(cuda_ctx, graph_key); 4433 4434 ggml_cuda_graph * graph = cuda_ctx->cuda_graph(graph_key); 4435 if (graph->is_enabled()) { 4436 const bool graph_compatible = ggml_cuda_graph_check_compability(cgraph); 4437 if (graph_compatible) { 4438 const bool properties_changed = ggml_cuda_graph_update_required(cuda_ctx, cgraph); 4439 4440 if (!graph->warmup_complete) { 4441 // Warmup: need at least 2 calls with no property change on the 2nd call 4442 if (!properties_changed) { 4443 graph->warmup_complete = true; 4444 GGML_LOG_DEBUG("%s: CUDA graph warmup complete\n", __func__); 4445 use_cuda_graph = true; 4446 cuda_graph_update_required = true; 4447 } 4448 // else: properties changed or first call - execute directly (use_cuda_graph stays false) 4449 } else { 4450 // Post-warmup: normal CUDA graph operation 4451 if (properties_changed) { 4452 // Properties changed - reset warmup, execute directly until stable again 4453 graph->warmup_complete = false; 4454 GGML_LOG_DEBUG("%s: CUDA graph warmup reset\n", __func__); 4455 } else { 4456 use_cuda_graph = true; 4457 cuda_graph_update_required = graph->instance == nullptr; 4458 } 4459 } 4460 } 4461 } 4462#endif // USE_CUDA_GRAPH 4463 4464 if (use_cuda_graph && cuda_graph_update_required) { 4465 // Start CUDA graph capture 4466 { 4467 std::lock_guard<std::mutex> lock(ggml_cuda_lock); 4468 ggml_cuda_lock_counter.fetch_add(1, std::memory_order_relaxed); 4469 } 4470 4471 CUDA_CHECK(cudaStreamBeginCapture(cuda_ctx->stream(), cudaStreamCaptureModeRelaxed)); 4472 } 4473 4474 ggml_cuda_graph_evaluate_and_capture(cuda_ctx, cgraph, use_cuda_graph, cuda_graph_update_required, graph_key); 4475 4476 return GGML_STATUS_SUCCESS; 4477} 4478 4479static void ggml_backend_cuda_event_record(ggml_backend_t backend, ggml_backend_event_t event) { 4480 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *)backend->context; 4481 4482 CUDA_CHECK(cudaEventRecord((cudaEvent_t)event->context, cuda_ctx->stream())); 4483} 4484 4485static void ggml_backend_cuda_event_wait(ggml_backend_t backend, ggml_backend_event_t event) { 4486 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *)backend->context; 4487 4488 if (ggml_backend_is_cuda(backend)) { 4489 CUDA_CHECK(cudaStreamWaitEvent(cuda_ctx->stream(), (cudaEvent_t)event->context, 0)); 4490 } else { 4491#if 0 4492 // untested 4493 auto wait_fn = [](void * user_data) { 4494 ggml_backend_event_t event = (ggml_backend_event_t)user_data; 4495 ggml_backend_event_synchronize(event); 4496 }; 4497 4498 CUDA_CHECK(cudaLaunchHostFunc(cuda_ctx->stream(), wait_fn, event)); 4499#endif 4500 GGML_ABORT("fatal error"); 4501 } 4502} 4503 4504static void ggml_backend_cuda_graph_optimize(ggml_backend_t backend, ggml_cgraph * cgraph, ggml_backend_graph_optimize_params * params) { 4505 ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *) backend->context; 4506 4507 static const bool disable_fusion = getenv("GGML_CUDA_DISABLE_FUSION") != nullptr && std::atoi(getenv("GGML_CUDA_DISABLE_FUSION")); 4508 if (!disable_fusion) { 4509 for (int i = 0; i < cgraph->n_nodes; ++i) { 4510 if (cgraph->nodes[i]->op != GGML_OP_MUL) { 4511 continue; 4512 } 4513 4514 ggml_cuda_moe_weighted_reduction_match match; 4515 if (!ggml_cuda_match_moe_weighted_reduction(cgraph, i, match)) { 4516 continue; 4517 } 4518 4519 params->add_alloc_dep(params->user_data, const_cast<ggml_tensor *>(match.experts), match.dst); 4520 params->add_alloc_dep(params->user_data, const_cast<ggml_tensor *>(match.weights), match.dst); 4521 if (match.expert_scale != nullptr) { 4522 params->add_alloc_dep( 4523 params->user_data, const_cast<ggml_tensor *>(match.expert_scale), match.dst); 4524 } 4525 i += match.node_count - 1; 4526 } 4527 } 4528 4529#ifdef USE_CUDA_GRAPH 4530 const void * graph_key = ggml_cuda_graph_get_key(cgraph); 4531 const bool use_cuda_graph = ggml_cuda_graph_set_enabled(cuda_ctx, graph_key); 4532#else 4533 const bool use_cuda_graph = false; 4534 GGML_UNUSED(cuda_ctx); 4535 GGML_UNUSED(cgraph); 4536#endif 4537 4538 static bool enable_graph_optimization = [] { 4539 const char * env = getenv("GGML_CUDA_GRAPH_OPT"); 4540 return env != nullptr && atoi(env) == 1; 4541 }(); 4542 4543 if (!enable_graph_optimization) { 4544 return; 4545 } 4546 4547 ggml_cuda_stream_context & stream_context = cuda_ctx->stream_context(); 4548 stream_context.reset(); 4549 4550 if (!use_cuda_graph) { 4551 return; 4552 } 4553 4554 ggml_cuda_set_device(cuda_ctx->device); 4555 4556 // number of out-degrees for a particular node 4557 std::unordered_map<const ggml_tensor *, int> fan_out; 4558 // reverse mapping of node to index in the cgraph 4559 std::unordered_map<const ggml_tensor *, int> node_indices; 4560 4561 const auto & is_noop = [](const ggml_tensor * node) -> bool { 4562 return ggml_is_empty(node) || node->op == GGML_OP_NONE || node->op == GGML_OP_RESHAPE || 4563 node->op == GGML_OP_TRANSPOSE || node->op == GGML_OP_VIEW || node->op == GGML_OP_PERMUTE; 4564 }; 4565 4566 const auto & depends_on = [](const ggml_tensor * dst, const ggml_tensor * src) -> bool { 4567 for (uint32_t s = 0; s < GGML_MAX_SRC; ++s) { 4568 if (dst->src[s] == src) { 4569 return true; 4570 } 4571 } 4572 // implicit dependency if they view the same tensor 4573 const ggml_tensor * dst2 = dst->view_src ? dst->view_src : dst; 4574 const ggml_tensor * src2 = src->view_src ? src->view_src : src; 4575 if (dst2 == src2) { 4576 return true; 4577 } 4578 return false; 4579 }; 4580 4581 for (int node_idx = 0; node_idx < cgraph->n_nodes; node_idx++) { 4582 const ggml_tensor * node = cgraph->nodes[node_idx]; 4583 node_indices[node] = node_idx; 4584 4585 if (is_noop(node)) { 4586 continue; 4587 } 4588 for (int src_idx = 0; src_idx < GGML_MAX_SRC; ++src_idx) { 4589 const ggml_tensor * src = cgraph->nodes[node_idx]->src[src_idx]; 4590 //TODO: check why nrows > 1 fails 4591 if (node && !is_noop(node) && ggml_nrows(node) <= 1) { 4592 fan_out[src] += 1; 4593 } 4594 } 4595 } 4596 4597 // Target Q, K, V for concurrency 4598 // this is a more general way to find nodes which can be candidates for concurrency (although it has not been tested for anything else): 4599 // 1. find fan-out (fork) nodes where the same input is used at least N times (in QKV, it would be "attn-norm") 4600 // 2. find the join node, where 2 or more of the outputs are required (in QKV, this would "KQ" or "flash-attn") 4601 // 3. account for all branches from the fork to the join 4602 // 4. To extend lifetimes of the tensors, we interleave the branches (see below for more details) 4603 // 5. save the original cgraph and restore it in graph_compute, to enable fusion within streams 4604 // See discussion: https://github.com/ggml-org/llama.cpp/pull/16991#issuecomment-3522620030 4605 4606 const int min_fan_out = 3; 4607 const int max_fan_out = 3; 4608 4609 // store {fork_idx, join_idx} 4610 std::vector<std::pair<int, int>> concurrent_node_ranges; 4611 4612 for (const auto & [root_node, count] : fan_out) { 4613 if (count >= min_fan_out && count <= max_fan_out) { 4614 const int root_node_idx = node_indices[root_node]; 4615 4616 // only optimize for attn_norm 4617 // TODO: make this more generic 4618 if (!strstr(root_node->name, "attn_norm")) { 4619 continue; 4620 } 4621 4622 bool is_part_of_event = false; 4623 for (const auto & [start, end] : concurrent_node_ranges) { 4624 if (root_node_idx >= start && root_node_idx <= end) { 4625 is_part_of_event = true; 4626 } 4627 } 4628 4629 if (is_part_of_event) { 4630 continue; 4631 } 4632 4633 std::vector<std::vector<const ggml_tensor *>> nodes_per_branch; 4634 for (int i = root_node_idx + 1; i < cgraph->n_nodes; ++i) { 4635 const ggml_tensor * node = cgraph->nodes[i]; 4636 if (!is_noop(node) && depends_on(node, root_node)) { 4637 nodes_per_branch.push_back({ node }); 4638 } 4639 } 4640 4641 GGML_ASSERT(nodes_per_branch.size() == (size_t) count); 4642 4643 //find the join point 4644 const ggml_tensor * join_node = nullptr; 4645 4646 const auto & belongs_to_branch = [&](const ggml_tensor * node, 4647 const std::vector<const ggml_tensor *> & branch) -> bool { 4648 for (const ggml_tensor * n : branch) { 4649 if (depends_on(node, n)) { 4650 return true; 4651 } 4652 } 4653 return false; 4654 }; 4655 4656 for (int i = root_node_idx + 1; i < cgraph->n_nodes; ++i) { 4657 const ggml_tensor * curr_node = cgraph->nodes[i]; 4658 4659 int num_joins = 0; 4660 for (size_t branch_idx = 0; branch_idx < nodes_per_branch.size(); branch_idx++) { 4661 if (belongs_to_branch(curr_node, nodes_per_branch[branch_idx])) { 4662 num_joins++; 4663 } 4664 } 4665 4666 if (num_joins >= 2) { 4667 join_node = curr_node; 4668 break; 4669 } 4670 4671 bool found_branch = false; 4672 for (size_t branch_idx = 0; branch_idx < nodes_per_branch.size(); branch_idx++) { 4673 std::vector<const ggml_tensor *> & branch_vec = nodes_per_branch[branch_idx]; 4674 if (belongs_to_branch(curr_node, branch_vec)) { 4675 //continue accumulating 4676 if (std::find(branch_vec.begin(), branch_vec.end(), curr_node) == branch_vec.end()) { 4677 branch_vec.push_back(curr_node); 4678 } 4679 found_branch = true; 4680 } 4681 } 4682 4683 if (!found_branch && is_noop(curr_node)) { 4684 // we can put it in any branch because it will be ignored 4685 nodes_per_branch[0].push_back({ curr_node }); 4686 } 4687 } 4688 4689 if (join_node) { 4690 //Create ggml_cuda_concurrent_event 4691 ggml_cuda_concurrent_event concurrent_event(nodes_per_branch.size()); 4692 concurrent_event.join_node = join_node; 4693 4694 for (size_t branch_idx = 0; branch_idx < nodes_per_branch.size(); branch_idx++) { 4695 for (const ggml_tensor * n : nodes_per_branch[branch_idx]) { 4696 concurrent_event.stream_mapping[n] = branch_idx + 1; 4697 } 4698 } 4699 4700 int fork_node_idx = node_indices[root_node]; 4701 int join_node_idx = node_indices[join_node]; 4702 4703 int current_branch_idx = 0; 4704 int current_node_idx = fork_node_idx + 1; 4705 const int n_branches = nodes_per_branch.size(); 4706 4707 int total_branch_nodes = 0; 4708 for (std::vector<const ggml_tensor *> branch_nodes : nodes_per_branch) { 4709 total_branch_nodes += branch_nodes.size(); 4710 } 4711 4712 // there are other nodes in the middle which are unaccounted for 4713 // usually (cpy) nodes, then ignore this fork 4714 if (join_node_idx - fork_node_idx - 1 != total_branch_nodes) { 4715 GGML_LOG_DEBUG( 4716 "Skipping %s because the number of nodes in the middle is not equal to the total number of " 4717 "branch nodes %d != %d\n", 4718 root_node->name, join_node_idx - fork_node_idx - 1, total_branch_nodes); 4719 continue; 4720 } 4721 4722 // Save the original order of nodes in this region before interleaving 4723 // This is used later to restore grouping for fusion within streams 4724 concurrent_event.original_order.reserve(total_branch_nodes); 4725 for (int i = fork_node_idx + 1; i < join_node_idx; ++i) { 4726 concurrent_event.original_order.push_back(cgraph->nodes[i]); 4727 } 4728 4729 std::unordered_map<const ggml_tensor *, ggml_cuda_concurrent_event> & concurrent_events = cuda_ctx->stream_context().concurrent_events; 4730 GGML_ASSERT(concurrent_events.find(root_node) == concurrent_events.end()); 4731 concurrent_events.emplace(root_node, std::move(concurrent_event)); 4732 GGML_LOG_DEBUG("Adding stream at node %s %p\n", root_node->name, root_node); 4733 concurrent_node_ranges.emplace_back(fork_node_idx, join_node_idx); 4734 4735 // interleave tensors to extend lifetimes so that ggml graph doesn't recycle them 4736 // example transformation: 4737 // [attn-norm, QMul, QNorm, QRope, KMul, KNorm, KRope, VMul, attn] -> 4738 // [attn-norm, QMul, KMul, VMul, QNorm, VNorm, QRope, KRope, attn] 4739 while (current_node_idx < join_node_idx) { 4740 std::vector<const ggml_tensor *> & branch_nodes = nodes_per_branch[current_branch_idx]; 4741 4742 bool has_node = false; 4743 for (std::vector<const ggml_tensor *> branch_node : nodes_per_branch) { 4744 has_node |= branch_node.size() > 0; 4745 } 4746 4747 GGML_ASSERT(has_node); 4748 4749 if (branch_nodes.empty()) { 4750 current_branch_idx = (current_branch_idx + 1) % n_branches; 4751 continue; 4752 } 4753 4754 cgraph->nodes[current_node_idx] = const_cast<ggml_tensor *>(branch_nodes.front()); 4755 current_node_idx++; 4756 branch_nodes.erase(branch_nodes.begin()); 4757 4758 // append all empty nodes 4759 while (!branch_nodes.empty() && is_noop(branch_nodes.front())) { 4760 cgraph->nodes[current_node_idx] = const_cast<ggml_tensor *>(branch_nodes.front()); 4761 current_node_idx++; 4762 branch_nodes.erase(branch_nodes.begin()); 4763 } 4764 4765 current_branch_idx = (current_branch_idx + 1) % n_branches; 4766 } 4767 } 4768 } 4769 } 4770} 4771 4772static const ggml_backend_i ggml_backend_cuda_interface = { 4773 /* .get_name = */ ggml_backend_cuda_get_name, 4774 /* .free = */ ggml_backend_cuda_free, 4775 /* .set_tensor_async = */ ggml_backend_cuda_set_tensor_async, 4776 /* .get_tensor_async = */ ggml_backend_cuda_get_tensor_async, 4777 /* .set_tensor_2d_async = */ ggml_backend_cuda_set_tensor_2d_async, 4778 /* .get_tensor_2d_async = */ ggml_backend_cuda_get_tensor_2d_async, 4779 /* .cpy_tensor_async = */ ggml_backend_cuda_cpy_tensor_async, 4780 /* .synchronize = */ ggml_backend_cuda_synchronize, 4781 /* .graph_plan_create = */ NULL, 4782 /* .graph_plan_free = */ NULL, 4783 /* .graph_plan_update = */ NULL, 4784 /* .graph_plan_compute = */ NULL, 4785 /* .graph_compute = */ ggml_backend_cuda_graph_compute, 4786 /* .event_record = */ ggml_backend_cuda_event_record, 4787 /* .event_wait = */ ggml_backend_cuda_event_wait, 4788 /* .graph_optimize = */ ggml_backend_cuda_graph_optimize, 4789}; 4790 4791static ggml_guid_t ggml_backend_cuda_guid() { 4792 static ggml_guid guid = { 0x2c, 0xdd, 0xe8, 0x1c, 0x65, 0xb3, 0x65, 0x73, 0x6a, 0x12, 0x88, 0x61, 0x1c, 0xc9, 0xdc, 0x25 }; 4793 return &guid; 4794} 4795 4796bool ggml_backend_is_cuda(ggml_backend_t backend) { 4797 return backend != NULL && ggml_guid_matches(backend->guid, ggml_backend_cuda_guid()); 4798} 4799 4800int ggml_backend_cuda_get_device_count() { 4801 return ggml_cuda_info().device_count; 4802} 4803 4804static std::string ggml_cuda_device_description(int device) { 4805 cudaDeviceProp prop; 4806 CUDA_CHECK(cudaGetDeviceProperties(&prop, ggml_cuda_get_physical_device(device))); 4807 4808 const ggml_cuda_device_info & info = ggml_cuda_info(); 4809 std::string description = prop.name; 4810 if (info.device_count > info.physical_device_count) { 4811 description += " (dev p" + std::to_string(info.devices[device].physical_device) + 4812 "/v" + std::to_string(info.devices[device].virtual_index) + ")"; 4813 } 4814 return description; 4815} 4816 4817void ggml_backend_cuda_get_device_description(int device, char * description, size_t description_size) { 4818 snprintf(description, description_size, "%s", ggml_cuda_device_description(device).c_str()); 4819} 4820 4821static int ggml_cuda_physical_device_share_count(int device) { 4822 const ggml_cuda_device_info & info = ggml_cuda_info(); 4823 GGML_ASSERT(device >= 0 && device < info.device_count); 4824 return info.devices[device].physical_share_count; 4825} 4826 4827void ggml_backend_cuda_get_device_memory(int device, size_t * free, size_t * total) { 4828 ggml_cuda_set_device(device); 4829 4830 CUDA_CHECK(cudaMemGetInfo(free, total)); 4831 4832 // virtual devices sharing one physical GPU share its memory pool; split it between them 4833 const int share_count = ggml_cuda_physical_device_share_count(device); 4834 *free /= share_count; 4835 *total /= share_count; 4836} 4837 4838bool ggml_backend_cuda_register_host_buffer(void * buffer, size_t size) { 4839 if (getenv("GGML_CUDA_REGISTER_HOST") == nullptr) { 4840 return false; 4841 } 4842 4843#if CUDART_VERSION >= 11010 || defined(GGML_USE_MUSA) || defined(GGML_USE_HIP) 4844 cudaError_t err = cudaHostRegister(buffer, size, cudaHostRegisterPortable | cudaHostRegisterReadOnly); 4845 if (err != cudaSuccess) { 4846 // clear the error 4847 (void)cudaGetLastError(); 4848 4849 GGML_LOG_DEBUG("%s: failed to register %.2f MiB of pinned memory: %s\n", __func__, 4850 size / 1024.0 / 1024.0, cudaGetErrorString(err)); 4851 return false; 4852 } 4853 return true; 4854#else 4855 GGML_UNUSED(buffer); 4856 GGML_UNUSED(size); 4857 return false; 4858#endif // CUDART_VERSION >= 11010 || defined(GGML_USE_MUSA) 4859} 4860 4861void ggml_backend_cuda_unregister_host_buffer(void * buffer) { 4862 if (getenv("GGML_CUDA_REGISTER_HOST") == nullptr) { 4863 return; 4864 } 4865 4866 cudaError_t err = cudaHostUnregister(buffer); 4867 if (err != cudaSuccess) { 4868 // clear the error 4869 (void)cudaGetLastError(); 4870 } 4871} 4872 4873 4874// backend device 4875 4876struct ggml_backend_cuda_device_context { 4877 int device; 4878 std::string name; 4879 std::string description; 4880 std::string pci_bus_id; 4881 int op_offload_min_batch_size; 4882}; 4883 4884static const char * ggml_backend_cuda_device_get_name(ggml_backend_dev_t dev) { 4885 ggml_backend_cuda_device_context * ctx = (ggml_backend_cuda_device_context *)dev->context; 4886 return ctx->name.c_str(); 4887} 4888 4889static const char * ggml_backend_cuda_device_get_description(ggml_backend_dev_t dev) { 4890 ggml_backend_cuda_device_context * ctx = (ggml_backend_cuda_device_context *)dev->context; 4891 return ctx->description.c_str(); 4892} 4893 4894#if defined(__linux__) 4895// Helper function to get available memory from /proc/meminfo for UMA systems 4896static bool ggml_backend_cuda_get_available_uma_memory(long * available_memory_kb, long * free_swap_kb) { 4897 FILE * meminfo_file = nullptr; 4898 // 2KB buffer for reading /proc/meminfo since it does not report size info, should be enough 4899 const size_t BUFFER_SIZE = 2048; 4900 auto file_buffer = std::make_unique<char[]>(BUFFER_SIZE); 4901 size_t bytes_read = 0; 4902 long huge_tlb_total_pages = -1; 4903 long huge_tlb_free_pages = -1; 4904 long huge_tlb_page_size = -1; 4905 4906 if (available_memory_kb == nullptr || free_swap_kb == nullptr) { 4907 return false; 4908 } 4909 4910 meminfo_file = fopen("/proc/meminfo", "r"); 4911 if (meminfo_file == nullptr) { 4912 GGML_LOG_ERROR("%s: failed to open /proc/meminfo\n", __func__); 4913 return false; 4914 } 4915 4916 // Read file into buffer 4917 bytes_read = fread(file_buffer.get(), 1, BUFFER_SIZE - 1, meminfo_file); 4918 fclose(meminfo_file); 4919 4920 if (bytes_read == 0) { 4921 GGML_LOG_ERROR("%s: failed to read from /proc/meminfo\n", __func__); 4922 return false; 4923 } 4924 file_buffer[bytes_read] = '\0'; 4925 4926 *available_memory_kb = -1; 4927 *free_swap_kb = -1; 4928 4929 // Parse the file buffer line by line 4930 char * line = file_buffer.get(); 4931 char * line_next; 4932 while (line < file_buffer.get() + bytes_read) { 4933 // Find the end of the current line 4934 line_next = strchr(line, '\n'); 4935 if (line_next != nullptr) { 4936 *line_next = '\0'; 4937 line_next++; 4938 } else { 4939 line_next = file_buffer.get() + bytes_read; 4940 } 4941 4942 long value; 4943 if (sscanf(line, "MemAvailable: %ld kB", &value) == 1) { 4944 *available_memory_kb = value; 4945 } else if (sscanf(line, "SwapFree: %ld kB", &value) == 1) { 4946 *free_swap_kb = value; 4947 } else if (sscanf(line, "HugePages_Total: %ld", &value) == 1) { 4948 huge_tlb_total_pages = value; 4949 } else if (sscanf(line, "HugePages_Free: %ld", &value) == 1) { 4950 huge_tlb_free_pages = value; 4951 } else if (sscanf(line, "Hugepagesize: %ld kB", &value) == 1) { 4952 huge_tlb_page_size = value; 4953 } 4954 4955 line = line_next; 4956 } 4957 4958 if (huge_tlb_total_pages != 0 && huge_tlb_total_pages != -1) { 4959 *available_memory_kb = huge_tlb_free_pages * huge_tlb_page_size; 4960 4961 // Hugetlbfs pages are not swappable. 4962 *free_swap_kb = 0; 4963 } 4964 4965 GGML_LOG_DEBUG("%s: final available_memory_kb: %ld\n", __func__, *available_memory_kb); 4966 return true; 4967} 4968#endif // defined(__linux__) 4969 4970static void ggml_backend_cuda_device_get_memory(ggml_backend_dev_t dev, size_t * free, size_t * total) { 4971 ggml_backend_cuda_device_context * ctx = (ggml_backend_cuda_device_context *)dev->context; 4972 ggml_cuda_set_device(ctx->device); 4973 cudaError_t err = cudaMemGetInfo(free, total); 4974 if (err != cudaSuccess) { 4975 (void)cudaGetLastError(); 4976 GGML_LOG_WARN("%s: cudaMemGetInfo failed (%s), returning 0/0\n", __func__, cudaGetErrorString(err)); 4977 *free = 0; 4978 *total = 0; 4979 return; 4980 } 4981 4982// ref: https://github.com/ggml-org/llama.cpp/pull/17368 4983#if defined(__linux__) && !defined(GGML_USE_HIP) 4984 // Check if this is a UMA (Unified Memory Architecture) system 4985 cudaDeviceProp prop; 4986 CUDA_CHECK(cudaGetDeviceProperties(&prop, ggml_cuda_get_physical_device(ctx->device))); 4987 4988 // Check if UMA is explicitly enabled via environment variable 4989 bool uma_env = getenv("GGML_CUDA_ENABLE_UNIFIED_MEMORY") != nullptr; 4990 bool is_uma = prop.integrated > 0 || uma_env; 4991 4992 if (is_uma) { 4993 // For UMA systems (like DGX Spark), use system memory info 4994 long available_memory_kb = 0; 4995 long free_swap_kb = 0; 4996 4997 if (ggml_backend_cuda_get_available_uma_memory(&available_memory_kb, &free_swap_kb) && available_memory_kb > 0) { 4998 *free = (size_t)available_memory_kb * 1024; 4999 } else { 5000 GGML_LOG_ERROR("%s: /proc/meminfo reading failed, using cudaMemGetInfo\n", __func__); 5001 } 5002 } 5003#endif // defined(__linux__) && !defined(GGML_USE_HIP) 5004 5005 // virtual devices sharing one physical GPU share its memory pool; split it between them 5006 const int share_count = ggml_cuda_physical_device_share_count(ctx->device); 5007 *free /= share_count; 5008 *total /= share_count; 5009} 5010 5011static enum ggml_backend_dev_type ggml_backend_cuda_device_get_type(ggml_backend_dev_t dev) { 5012 ggml_backend_cuda_device_context * ctx = (ggml_backend_cuda_device_context *) dev->context; 5013 5014 cudaDeviceProp prop; 5015 CUDA_CHECK(cudaGetDeviceProperties(&prop, ggml_cuda_get_physical_device(ctx->device))); 5016 5017 return prop.integrated 5018 ? GGML_BACKEND_DEVICE_TYPE_IGPU 5019 : GGML_BACKEND_DEVICE_TYPE_GPU; 5020} 5021 5022static void ggml_backend_cuda_device_get_props(ggml_backend_dev_t dev, ggml_backend_dev_props * props) { 5023 ggml_backend_cuda_device_context * ctx = (ggml_backend_cuda_device_context *)dev->context; 5024 5025 props->name = ggml_backend_cuda_device_get_name(dev); 5026 props->description = ggml_backend_cuda_device_get_description(dev); 5027 props->type = ggml_backend_cuda_device_get_type(dev); 5028 props->device_id = ctx->pci_bus_id.empty() ? nullptr : ctx->pci_bus_id.c_str(); 5029 ggml_backend_cuda_device_get_memory(dev, &props->memory_free, &props->memory_total); 5030 5031 bool host_buffer = getenv("GGML_CUDA_NO_PINNED") == nullptr; 5032#ifdef GGML_CUDA_NO_PEER_COPY 5033 bool events = false; 5034#else 5035 bool events = true; 5036#endif 5037 5038 props->caps = { 5039 /* .async = */ true, 5040 /* .host_buffer = */ host_buffer, 5041 /* .buffer_from_host_ptr = */ false, 5042 /* .events = */ events, 5043 /* .mmap_support = */ props->type != GGML_BACKEND_DEVICE_TYPE_IGPU, 5044 }; 5045} 5046 5047static ggml_backend_t ggml_backend_cuda_device_init_backend(ggml_backend_dev_t dev, const char * params) { 5048 GGML_UNUSED(params); 5049 ggml_backend_cuda_device_context * ctx = (ggml_backend_cuda_device_context *)dev->context; 5050 return ggml_backend_cuda_init(ctx->device); 5051} 5052 5053static ggml_backend_buffer_type_t ggml_backend_cuda_device_get_buffer_type(ggml_backend_dev_t dev) { 5054 ggml_backend_cuda_device_context * ctx = (ggml_backend_cuda_device_context *)dev->context; 5055 return ggml_backend_cuda_buffer_type(ctx->device); 5056} 5057 5058static ggml_backend_buffer_type_t ggml_backend_cuda_device_get_host_buffer_type(ggml_backend_dev_t dev) { 5059 GGML_UNUSED(dev); 5060 return ggml_backend_cuda_host_buffer_type(); 5061} 5062 5063// TODO: move these functions here 5064static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const ggml_tensor * op) { 5065 ggml_backend_cuda_device_context * dev_ctx = (ggml_backend_cuda_device_context *) dev->context; 5066 5067 // check if all the sources are allocated on this device 5068 for (int i = 0; i < GGML_MAX_SRC; i++) { 5069 if (op->src[i] && op->src[i]->buffer && ggml_backend_buft_is_cuda(op->src[i]->buffer->buft)) { 5070 ggml_backend_cuda_buffer_type_context * buft_ctx = (ggml_backend_cuda_buffer_type_context *)op->src[i]->buffer->buft->context; 5071 if (buft_ctx->device != dev_ctx->device) { 5072 return false; 5073 } 5074 } 5075 } 5076 5077 switch (op->op) { 5078 case GGML_OP_UNARY: 5079 switch (ggml_get_unary_op(op)) { 5080 case GGML_UNARY_OP_ABS: 5081 case GGML_UNARY_OP_SGN: 5082 case GGML_UNARY_OP_NEG: 5083 case GGML_UNARY_OP_STEP: 5084 case GGML_UNARY_OP_GELU: 5085 case GGML_UNARY_OP_SILU: 5086 case GGML_UNARY_OP_RELU: 5087 case GGML_UNARY_OP_SIGMOID: 5088 case GGML_UNARY_OP_HARDSIGMOID: 5089 case GGML_UNARY_OP_HARDSWISH: 5090 case GGML_UNARY_OP_GELU_ERF: 5091 case GGML_UNARY_OP_GELU_QUICK: 5092 case GGML_UNARY_OP_TANH: 5093 case GGML_UNARY_OP_EXP: 5094 case GGML_UNARY_OP_EXPM1: 5095 case GGML_UNARY_OP_SOFTPLUS: 5096 case GGML_UNARY_OP_ELU: 5097 case GGML_UNARY_OP_XIELU: 5098 case GGML_UNARY_OP_FLOOR: 5099 case GGML_UNARY_OP_CEIL: 5100 case GGML_UNARY_OP_ROUND: 5101 case GGML_UNARY_OP_TRUNC: 5102 // TODO: should become: 5103 //return ggml_is_contiguous_rows(op->src[0]); 5104 return ggml_is_contiguous(op->src[0]); 5105 default: 5106 return false; 5107 } 5108 break; 5109 case GGML_OP_GLU: 5110 switch (ggml_get_glu_op(op)) { 5111 case GGML_GLU_OP_REGLU: 5112 case GGML_GLU_OP_GEGLU: 5113 case GGML_GLU_OP_SWIGLU: 5114 case GGML_GLU_OP_SWIGLU_OAI: 5115 case GGML_GLU_OP_GEGLU_ERF: 5116 case GGML_GLU_OP_GEGLU_QUICK: 5117 case GGML_GLU_OP_SWIGLU_CLAMP: 5118 return ggml_is_contiguous_1(op->src[0]); 5119 default: 5120 return false; 5121 } 5122 break; 5123 case GGML_OP_MUL_MAT: 5124 case GGML_OP_MUL_MAT_ID: 5125 { 5126 struct ggml_tensor * a = op->src[0]; 5127 struct ggml_tensor * b = op->src[1]; 5128 if (a->nb[0] != ggml_element_size(a) || b->nb[0] != ggml_element_size(b)) { 5129 return false; // TODO this could in principle be implemented though currently there is no use case. 5130 } 5131 if (b->type == GGML_TYPE_F16 && a->type != GGML_TYPE_F16) { 5132 return false; 5133 } 5134#ifdef GGML_USE_MUSA 5135 const int cc = ggml_cuda_info().devices[dev_ctx->device].cc; 5136 if (b->ne[2]*b->ne[3] > 1 && !ggml_is_transposed(a) && !ggml_is_transposed(b)) { 5137 if (GGML_CUDA_CC_IS_QY1(cc) && op->op == GGML_OP_MUL_MAT && 5138 a->type == GGML_TYPE_F16 && b->type == GGML_TYPE_F16) { 5139 return false; 5140 } 5141 if (GGML_CUDA_CC_IS_QY2(cc) && op->op == GGML_OP_MUL_MAT_ID && 5142 a->type == GGML_TYPE_Q2_K && b->type == GGML_TYPE_F32) { 5143 return false; 5144 } 5145 } 5146#endif // GGML_USE_MUSA 5147 switch (a->type) { 5148 case GGML_TYPE_F32: 5149 case GGML_TYPE_F16: 5150 case GGML_TYPE_Q1_0: 5151 case GGML_TYPE_Q2_0: 5152 case GGML_TYPE_Q4_0: 5153 case GGML_TYPE_Q4_1: 5154 case GGML_TYPE_Q5_0: 5155 case GGML_TYPE_Q5_1: 5156 case GGML_TYPE_Q8_0: 5157 case GGML_TYPE_MXFP4: 5158 case GGML_TYPE_NVFP4: 5159 case GGML_TYPE_Q2_K: 5160 case GGML_TYPE_Q3_K: 5161 case GGML_TYPE_Q4_K: 5162 case GGML_TYPE_Q5_K: 5163 case GGML_TYPE_Q6_K: 5164 case GGML_TYPE_Q8_K: 5165 case GGML_TYPE_IQ1_M: 5166 case GGML_TYPE_IQ1_S: 5167 case GGML_TYPE_IQ2_S: 5168 case GGML_TYPE_IQ2_XS: 5169 case GGML_TYPE_IQ2_XXS: 5170 case GGML_TYPE_IQ3_S: 5171 case GGML_TYPE_IQ3_XXS: 5172 case GGML_TYPE_IQ4_NL: 5173 case GGML_TYPE_IQ4_XS: 5174 case GGML_TYPE_BF16: 5175 return true; 5176 default: 5177 return false; 5178 } 5179 } break; 5180 case GGML_OP_OUT_PROD: 5181 return op->type == GGML_TYPE_F32 && op->src[0]->type == GGML_TYPE_F32 && op->src[1]->type == GGML_TYPE_F32; 5182 case GGML_OP_GET_ROWS: 5183 { 5184 switch (op->src[0]->type) { 5185 case GGML_TYPE_F16: 5186 case GGML_TYPE_F32: 5187 case GGML_TYPE_BF16: 5188 case GGML_TYPE_I32: 5189 case GGML_TYPE_Q1_0: 5190 case GGML_TYPE_Q2_0: 5191 case GGML_TYPE_Q4_0: 5192 case GGML_TYPE_Q4_1: 5193 case GGML_TYPE_Q5_0: 5194 case GGML_TYPE_Q5_1: 5195 case GGML_TYPE_Q8_0: 5196 case GGML_TYPE_Q2_K: 5197 case GGML_TYPE_Q3_K: 5198 case GGML_TYPE_Q4_K: 5199 case GGML_TYPE_Q5_K: 5200 case GGML_TYPE_Q6_K: 5201 case GGML_TYPE_IQ2_XXS: 5202 case GGML_TYPE_IQ2_XS: 5203 case GGML_TYPE_IQ2_S: 5204 case GGML_TYPE_IQ3_XXS: 5205 case GGML_TYPE_IQ3_S: 5206 case GGML_TYPE_IQ1_S: 5207 case GGML_TYPE_IQ1_M: 5208 case GGML_TYPE_IQ4_XS: 5209 return true; 5210 case GGML_TYPE_IQ4_NL: 5211 case GGML_TYPE_MXFP4: 5212 // 32-value sub-blocks, the row size does not guarantee 5213 // the QK_K super-blocks the get_rows kernel iterates on 5214 return op->src[0]->ne[0] % QK_K == 0; 5215 default: 5216 return false; 5217 } 5218 } break; 5219 case GGML_OP_GET_ROWS_BACK: 5220 { 5221 return op->type == GGML_TYPE_F32 && op->src[0]->type == GGML_TYPE_F32 && op->ne[2] == 1 && op->ne[3] == 1; 5222 } break; 5223 case GGML_OP_SET_ROWS: 5224 { 5225 return ( 5226 ( 5227 (op->type == GGML_TYPE_F32 || op->type == GGML_TYPE_F16 || op->type == GGML_TYPE_BF16 || 5228 op->type == GGML_TYPE_Q4_0 || op->type == GGML_TYPE_Q4_1 || op->type == GGML_TYPE_Q5_0 || 5229 op->type == GGML_TYPE_Q5_1 || op->type == GGML_TYPE_Q8_0 || op->type == GGML_TYPE_IQ4_NL) && 5230 op->src[0]->type == GGML_TYPE_F32 5231 ) || ( 5232 op->type == GGML_TYPE_F16 && op->src[0]->type == GGML_TYPE_F16 5233 ) 5234 ) && 5235 (op->src[1]->type == GGML_TYPE_I64 || op->src[1]->type == GGML_TYPE_I32); 5236 } break; 5237 case GGML_OP_SET: 5238 { 5239 const ggml_type t = op->type; 5240 return (t == GGML_TYPE_F32 || t == GGML_TYPE_I32) && 5241 t == op->src[0]->type && 5242 t == op->src[1]->type; 5243 } break; 5244 case GGML_OP_CPY: 5245 { 5246 ggml_type src0_type = op->src[0]->type; 5247 ggml_type src1_type = op->src[1]->type; 5248 if ((src0_type == GGML_TYPE_F32 || src0_type == GGML_TYPE_BF16 || src0_type == GGML_TYPE_F16) && 5249 (src1_type == GGML_TYPE_F32 || src1_type == GGML_TYPE_BF16 || src1_type == GGML_TYPE_F16) 5250 ) { 5251 return true; 5252 } 5253 if (src0_type == GGML_TYPE_F32 && src1_type == GGML_TYPE_Q8_0) { 5254 return true; 5255 } 5256 if (src0_type == GGML_TYPE_Q8_0 && src1_type == GGML_TYPE_F32) { 5257 return true; 5258 } 5259 if (src0_type == GGML_TYPE_F32 && src1_type == GGML_TYPE_Q4_0) { 5260 return true; 5261 } 5262 if (src0_type == GGML_TYPE_Q4_0 && src1_type == GGML_TYPE_F32) { 5263 return true; 5264 } 5265 if (src0_type == GGML_TYPE_F32 && src1_type == GGML_TYPE_Q4_1) { 5266 return true; 5267 } 5268 if (src0_type == GGML_TYPE_Q4_1 && src1_type == GGML_TYPE_F32) { 5269 return true; 5270 } 5271 if (src0_type == GGML_TYPE_F32 && src1_type == GGML_TYPE_Q5_0) { 5272 return true; 5273 } 5274 if (src0_type == GGML_TYPE_Q5_0 && src1_type == GGML_TYPE_F32) { 5275 return true; 5276 } 5277 if (src0_type == GGML_TYPE_F32 && src1_type == GGML_TYPE_Q5_1) { 5278 return true; 5279 } 5280 if (src0_type == GGML_TYPE_Q5_1 && src1_type == GGML_TYPE_F32) { 5281 return true; 5282 } 5283 if (src0_type == GGML_TYPE_F32 && src1_type == GGML_TYPE_IQ4_NL) { 5284 return true; 5285 } 5286 if (src0_type == GGML_TYPE_F32 && src1_type == GGML_TYPE_I32) { 5287 return true; 5288 } 5289 if (src0_type == GGML_TYPE_I32 && src1_type == GGML_TYPE_F32) { 5290 return true; 5291 } 5292 if (src0_type == GGML_TYPE_I32 && src1_type == GGML_TYPE_I32) { 5293 return true; 5294 } 5295 if (src0_type == src1_type && ggml_is_contiguous(op->src[0]) && ggml_is_contiguous(op->src[1])) { 5296 return true; 5297 } 5298 return false; 5299 } break; 5300 case GGML_OP_DUP: 5301 { 5302 ggml_type src0_type = op->src[0]->type; 5303 return src0_type != GGML_TYPE_I32 && src0_type != GGML_TYPE_I16; 5304 } break; 5305 case GGML_OP_ARGMAX: 5306 case GGML_OP_COUNT_EQUAL: 5307 { 5308 return true; 5309 } break; 5310 case GGML_OP_REPEAT: 5311 { 5312 // the CUDA REPEAT path only implements F32/F16; other types assert at runtime 5313 ggml_type src0_type = op->src[0]->type; 5314 return src0_type == GGML_TYPE_F32 || src0_type == GGML_TYPE_F16; 5315 } break; 5316 case GGML_OP_REPEAT_BACK: 5317 return op->type == GGML_TYPE_F32 && (op->src[0]->ne[2]*op->src[0]->ne[3]) <= (1 << 15); 5318 case GGML_OP_CONCAT: 5319 { 5320 ggml_type src0_type = op->src[0]->type; 5321 ggml_type src1_type = op->src[1]->type; 5322 const int32_t dim = op->op_params[0]; 5323 return src0_type == src1_type && 5324 src0_type == op->type && 5325 ( 5326 ( 5327 ggml_is_quantized(src0_type) && 5328 ( 5329 ( 5330 dim == 3 && 5331 ggml_is_contiguous(op->src[0]) && 5332 ggml_is_contiguous(op->src[1]) 5333 ) || ( 5334 dim != 3 && 5335 ggml_is_contiguous_to_3(op->src[0]) && 5336 ggml_is_contiguous_to_3(op->src[1]) 5337 ) 5338 ) && 5339 op->src[0]->ne[0] % ggml_blck_size(src0_type) == 0 && 5340 op->src[1]->ne[0] % ggml_blck_size(src0_type) == 0 5341 ) || ( 5342 !ggml_is_quantized(src0_type) && 5343 ggml_blck_size(src0_type) == 1 && 5344 ( 5345 ggml_type_size(src0_type) == 1 || 5346 ggml_type_size(src0_type) == 2 || 5347 ggml_type_size(src0_type) == 4 || 5348 ggml_type_size(src0_type) == 8 5349 ) 5350 ) 5351 ); 5352 } break; 5353 case GGML_OP_CONV_TRANSPOSE_1D: 5354 { 5355 ggml_type src0_type = op->src[0]->type; 5356 ggml_type src1_type = op->src[1]->type; 5357 if (src0_type == GGML_TYPE_F32 && src1_type == GGML_TYPE_F32) { 5358 return true; 5359 } 5360 return false; 5361 } break; 5362 case GGML_OP_COL2IM_1D: 5363 { 5364 ggml_type src0_type = op->src[0]->type; 5365 return (src0_type == GGML_TYPE_F32 || src0_type == GGML_TYPE_F16 || src0_type == GGML_TYPE_BF16) && 5366 op->type == src0_type && 5367 ggml_is_contiguous(op->src[0]) && 5368 ggml_is_contiguous(op); 5369 } break; 5370 case GGML_OP_SILU_BACK: 5371 return ggml_is_contiguous(op->src[0]) && op->src[0]->type == GGML_TYPE_F32; 5372 break; 5373 case GGML_OP_NORM: 5374 case GGML_OP_RMS_NORM: 5375 case GGML_OP_L2_NORM: 5376 return ggml_is_contiguous_rows(op->src[0]); 5377 case GGML_OP_RMS_NORM_BACK: 5378 return ggml_is_contiguous(op->src[0]); 5379 break; 5380 case GGML_OP_NONE: 5381 case GGML_OP_RESHAPE: 5382 case GGML_OP_VIEW: 5383 case GGML_OP_PERMUTE: 5384 case GGML_OP_TRANSPOSE: 5385 case GGML_OP_ADD_ID: 5386 case GGML_OP_ADD1: 5387 case GGML_OP_SCALE: 5388 case GGML_OP_SQR: 5389 case GGML_OP_SQRT: 5390 case GGML_OP_SIN: 5391 case GGML_OP_COS: 5392 case GGML_OP_CLAMP: 5393 case GGML_OP_LOG: 5394 return true; 5395 case GGML_OP_ADD: 5396 case GGML_OP_SUB: 5397 case GGML_OP_MUL: 5398 case GGML_OP_DIV: 5399 return (op->src[0]->type == GGML_TYPE_F32 || op->src[0]->type == GGML_TYPE_F16) && 5400 (op->src[1]->type == GGML_TYPE_F32 || op->src[1]->type == GGML_TYPE_F16) && 5401 (op->type == GGML_TYPE_F32 || op->type == GGML_TYPE_F16); 5402 case GGML_OP_SSM_SCAN: { 5403 const int32_t K = ggml_get_op_params_i32(op, 0); 5404 5405 if (op->src[3]->ne[0] == 1) { 5406 // Mamba2 5407 // (kernel only supports (d_state == 128 || d_state == 256) && d_head % 16 == 0) 5408 return (op->src[0]->ne[0] == 128 || op->src[0]->ne[0] == 256) && op->src[0]->ne[1] % 16 == 0; 5409 } else { 5410 if (K > 1) { 5411 return false; 5412 } 5413 5414 // Mamba 5415 // (kernel only supports d_state == 16, d_head == 1, n_head % 128 == 0, n_group == 1) 5416 return op->src[0]->ne[0] == 16 && op->src[0]->ne[1] == 1 && op->src[0]->ne[2] % 128 == 0 && op->src[4]->ne[1] == 1; 5417 } 5418 } 5419 case GGML_OP_SSM_CONV: { 5420 // assumes d_inner % threads == 0 5421 return op->src[0]->ne[1] % 128 == 0; 5422 } 5423 case GGML_OP_CONT: 5424 return true; 5425 case GGML_OP_DIAG_MASK_INF: 5426 return true; 5427 case GGML_OP_SOFT_MAX: 5428 return true; 5429 case GGML_OP_SOFT_MAX_BACK: { 5430 float max_bias = 0.0f; 5431 memcpy(&max_bias, (const float *) op->op_params + 1, sizeof(float)); 5432 return max_bias == 0.0f; 5433 } 5434 case GGML_OP_ROLL: 5435 if(op->src[0]->type == GGML_TYPE_F32 && ggml_is_contiguous(op->src[0])) { 5436 return true; 5437 } 5438 return false; 5439 case GGML_OP_ROPE: 5440 case GGML_OP_ROPE_BACK: { 5441 return op->src[0]->nb[0] == ggml_type_size(op->src[0]->type) && ggml_is_contiguous_2(op->src[0]); 5442 } 5443 case GGML_OP_IM2COL: 5444 case GGML_OP_IM2COL_3D: 5445 case GGML_OP_CONV_2D: 5446 return (ggml_is_contiguous(op->src[0]) && ggml_is_contiguous(op->src[1])); 5447 case GGML_OP_CONV_2D_DW: 5448 return op->src[0]->type == GGML_TYPE_F32; 5449 case GGML_OP_CONV_TRANSPOSE_2D: 5450 case GGML_OP_POOL_1D: 5451 case GGML_OP_POOL_2D: 5452 return true; 5453 case GGML_OP_ACC: 5454 // TODO: extend support like so: 5455 //return ggml_is_contiguous_rows(op->src[0]) && ggml_is_contiguous_rows(op->src[1]); 5456 return ggml_is_contiguous(op->src[0]) && ggml_is_contiguous(op->src[1]); 5457 case GGML_OP_SUM: 5458 return ggml_is_contiguous_rows(op->src[0]); 5459 case GGML_OP_TOP_K: 5460#if defined(GGML_USE_HIP) || defined(GGML_CUDA_USE_CUB) 5461 return true; 5462#else 5463 return op->src[0]->ne[0] <= 1024; 5464#endif // defined(GGML_USE_HIP) || defined(GGML_CUDA_USE_CUB) 5465 case GGML_OP_ARGSORT: 5466#ifndef GGML_CUDA_USE_CUB 5467 return op->src[0]->ne[0] <= 1024; 5468#else 5469 return true; 5470#endif 5471 case GGML_OP_SUM_ROWS: 5472 case GGML_OP_MEAN: 5473 case GGML_OP_GROUP_NORM: 5474 return ggml_is_contiguous(op->src[0]); 5475 case GGML_OP_PAD: 5476 return true; 5477 case GGML_OP_UPSCALE: 5478 case GGML_OP_PAD_REFLECT_1D: 5479 case GGML_OP_ARANGE: 5480 case GGML_OP_TIMESTEP_EMBEDDING: 5481 case GGML_OP_LEAKY_RELU: 5482 case GGML_OP_RWKV_WKV6: 5483 case GGML_OP_GATED_LINEAR_ATTN: 5484 case GGML_OP_RWKV_WKV7: 5485 return true; 5486 case GGML_OP_GATED_DELTA_NET: 5487 //TODO: enable once MUSA compiler is solved https://github.com/ggml-org/llama.cpp/pull/19504#issuecomment-4018634327 5488#ifdef GGML_USE_MUSA 5489 return false; 5490#else 5491 return true; 5492#endif // GGML_USE_MUSA 5493 case GGML_OP_DSV4_HC_COMB: 5494 return op->src[0]->type == GGML_TYPE_F32 && op->src[1]->type == GGML_TYPE_F32 && 5495 op->src[2]->type == GGML_TYPE_F32 && op->type == GGML_TYPE_F32; 5496 case GGML_OP_DSV4_HC_PRE: 5497 return op->src[0]->type == GGML_TYPE_F32 && op->src[1]->type == GGML_TYPE_F32 && 5498 op->type == GGML_TYPE_F32; 5499 case GGML_OP_DSV4_HC_POST: 5500 return op->src[0]->type == GGML_TYPE_F32 && op->src[1]->type == GGML_TYPE_F32 && 5501 op->src[2]->type == GGML_TYPE_F32 && op->src[3]->type == GGML_TYPE_F32 && 5502 op->type == GGML_TYPE_F32; 5503 case GGML_OP_FLASH_ATTN_EXT: 5504 return ggml_cuda_flash_attn_ext_supported(dev_ctx->device, op); 5505 case GGML_OP_CROSS_ENTROPY_LOSS: 5506 case GGML_OP_CROSS_ENTROPY_LOSS_BACK: 5507 case GGML_OP_OPT_STEP_ADAMW: 5508 case GGML_OP_OPT_STEP_SGD: 5509 case GGML_OP_FILL: 5510 case GGML_OP_CUMSUM: 5511 case GGML_OP_TRI: 5512 case GGML_OP_DIAG: 5513 case GGML_OP_SOLVE_TRI: 5514 return true; 5515 case GGML_OP_LIGHTNING_INDEXER: 5516 return ggml_cuda_lightning_indexer_supported(dev_ctx->device, op); 5517 5518 default: 5519 return false; 5520 } 5521} 5522 5523static bool ggml_backend_cuda_device_supports_buft(ggml_backend_dev_t dev, ggml_backend_buffer_type_t buft) { 5524 ggml_backend_cuda_device_context * dev_ctx = (ggml_backend_cuda_device_context *) dev->context; 5525 const bool integrated = ggml_cuda_info().devices[dev_ctx->device].integrated; 5526 return (ggml_backend_buft_is_cuda(buft) && buft->device == dev) || (integrated && ggml_backend_buft_is_cuda_host(buft)); 5527} 5528 5529static int64_t get_op_batch_size(const ggml_tensor * op) { 5530 switch (op->op) { 5531 case GGML_OP_GET_ROWS: 5532 return 0; 5533 case GGML_OP_MUL_MAT: 5534 return op->ne[1]; 5535 case GGML_OP_MUL_MAT_ID: 5536 case GGML_OP_ROPE: 5537 case GGML_OP_ROPE_BACK: 5538 return op->ne[2]; 5539 default: 5540 return ggml_nrows(op); 5541 } 5542} 5543 5544static bool ggml_backend_cuda_device_offload_op(ggml_backend_dev_t dev, const ggml_tensor * op) { 5545 ggml_backend_cuda_device_context * dev_ctx = (ggml_backend_cuda_device_context *) dev->context; 5546 5547 return get_op_batch_size(op) >= dev_ctx->op_offload_min_batch_size; 5548} 5549 5550static ggml_backend_event_t ggml_backend_cuda_device_event_new(ggml_backend_dev_t dev) { 5551#ifdef GGML_CUDA_NO_PEER_COPY 5552 GGML_UNUSED(dev); 5553 return nullptr; 5554#else 5555 ggml_backend_cuda_device_context * dev_ctx = (ggml_backend_cuda_device_context *)dev->context; 5556 5557 ggml_cuda_set_device(dev_ctx->device); 5558 5559 cudaEvent_t event; 5560 CUDA_CHECK(cudaEventCreateWithFlags(&event, cudaEventDisableTiming)); 5561 5562 return new ggml_backend_event { 5563 /* .device = */ dev, 5564 /* .context = */ event, 5565 }; 5566#endif 5567} 5568 5569static void ggml_backend_cuda_device_event_free(ggml_backend_dev_t dev, ggml_backend_event_t event) { 5570 GGML_UNUSED(dev); 5571 5572 CUDA_CHECK(cudaEventDestroy((cudaEvent_t)event->context)); 5573 delete event; 5574} 5575 5576static void ggml_backend_cuda_device_event_synchronize(ggml_backend_dev_t dev, ggml_backend_event_t event) { 5577 GGML_UNUSED(dev); 5578 CUDA_CHECK(cudaEventSynchronize((cudaEvent_t)event->context)); 5579} 5580 5581static const ggml_backend_device_i ggml_backend_cuda_device_interface = { 5582 /* .get_name = */ ggml_backend_cuda_device_get_name, 5583 /* .get_description = */ ggml_backend_cuda_device_get_description, 5584 /* .get_memory = */ ggml_backend_cuda_device_get_memory, 5585 /* .get_type = */ ggml_backend_cuda_device_get_type, 5586 /* .get_props = */ ggml_backend_cuda_device_get_props, 5587 /* .init_backend = */ ggml_backend_cuda_device_init_backend, 5588 /* .get_buffer_type = */ ggml_backend_cuda_device_get_buffer_type, 5589 /* .get_host_buffer_type = */ ggml_backend_cuda_device_get_host_buffer_type, 5590 /* .buffer_from_host_ptr = */ NULL, 5591 /* .supports_op = */ ggml_backend_cuda_device_supports_op, 5592 /* .supports_buft = */ ggml_backend_cuda_device_supports_buft, 5593 /* .offload_op = */ ggml_backend_cuda_device_offload_op, 5594 /* .event_new = */ ggml_backend_cuda_device_event_new, 5595 /* .event_free = */ ggml_backend_cuda_device_event_free, 5596 /* .event_synchronize = */ ggml_backend_cuda_device_event_synchronize, 5597}; 5598 5599// backend reg 5600 5601struct ggml_backend_cuda_reg_context { 5602 std::vector<ggml_backend_dev_t> devices; 5603}; 5604 5605static const char * ggml_backend_cuda_reg_get_name(ggml_backend_reg_t reg) { 5606 GGML_UNUSED(reg); 5607 return GGML_CUDA_NAME; 5608} 5609 5610static size_t ggml_backend_cuda_reg_get_device_count(ggml_backend_reg_t reg) { 5611 ggml_backend_cuda_reg_context * ctx = (ggml_backend_cuda_reg_context *)reg->context; 5612 return ctx->devices.size(); 5613} 5614 5615static ggml_backend_dev_t ggml_backend_cuda_reg_get_device(ggml_backend_reg_t reg, size_t index) { 5616 ggml_backend_cuda_reg_context * ctx = (ggml_backend_cuda_reg_context *)reg->context; 5617 GGML_ASSERT(index < ctx->devices.size()); 5618 return ctx->devices[index]; 5619} 5620 5621static ggml_backend_feature * ggml_backend_cuda_get_features(ggml_backend_reg_t reg) { 5622 static std::vector<ggml_backend_feature> features = []() { 5623 std::vector<ggml_backend_feature> features; 5624 #define _STRINGIFY(...) #__VA_ARGS__ 5625 #define STRINGIFY(...) _STRINGIFY(__VA_ARGS__) 5626 5627 #ifdef __CUDA_ARCH_LIST__ 5628 features.push_back({ "ARCHS", STRINGIFY(__CUDA_ARCH_LIST__) }); 5629 #endif 5630 5631 #ifdef GGML_CUDA_FORCE_MMQ 5632 features.push_back({ "FORCE_MMQ", "1" }); 5633 #endif 5634 5635 #ifdef GGML_CUDA_FORCE_CUBLAS 5636 features.push_back({ "FORCE_CUBLAS", "1" }); 5637 #endif 5638 5639 #ifndef GGML_USE_VMM 5640 features.push_back({ "NO_VMM", "1" }); 5641 #endif 5642 5643 #ifdef GGML_CUDA_NO_PEER_COPY 5644 features.push_back({ "NO_PEER_COPY", "1" }); 5645 #endif 5646 5647 #ifdef GGML_CUDA_USE_GRAPHS 5648 features.push_back({ "USE_GRAPHS", "1" }); 5649 #endif 5650 5651 #ifdef GGML_CUDA_FA_QUANTS 5652 features.push_back({ "FA_QUANTS", GGML_CUDA_FA_QUANTS }); 5653 #endif 5654 5655 { 5656 const auto & info = ggml_cuda_info(); 5657 for (int id = 0; id < info.device_count; ++id) { 5658 if (blackwell_mma_available(info.devices[id].cc)) { 5659 features.push_back({ "BLACKWELL_NATIVE_FP4", "1"}); 5660 break; 5661 } 5662 } 5663 } 5664 5665 #undef _STRINGIFY 5666 #undef STRINGIFY 5667 5668 features.push_back({ nullptr, nullptr }); 5669 5670 return features; 5671 }(); 5672 5673 return features.data(); 5674 5675 GGML_UNUSED(reg); 5676} 5677 5678static void * ggml_backend_cuda_reg_get_proc_address(ggml_backend_reg_t reg, const char * name) { 5679 GGML_UNUSED(reg); 5680 if (strcmp(name, "ggml_backend_comm_init") == 0) { 5681 return (void *)ggml_backend_cuda_comm_init; 5682 } 5683 if (strcmp(name, "ggml_backend_comm_free") == 0) { 5684 return (void *)ggml_backend_cuda_comm_free; 5685 } 5686 if (strcmp(name, "ggml_backend_comm_allreduce_tensor") == 0) { 5687 return (void *)ggml_backend_cuda_comm_allreduce_tensor; 5688 } 5689 if (strcmp(name, "ggml_backend_register_host_buffer") == 0) { 5690 return (void *)ggml_backend_cuda_register_host_buffer; 5691 } 5692 if (strcmp(name, "ggml_backend_unregister_host_buffer") == 0) { 5693 return (void *)ggml_backend_cuda_unregister_host_buffer; 5694 } 5695 if (strcmp(name, "ggml_backend_get_features") == 0) { 5696 return (void *)ggml_backend_cuda_get_features; 5697 } 5698 return nullptr; 5699} 5700 5701static const ggml_backend_reg_i ggml_backend_cuda_reg_interface = { 5702 /* .get_name = */ ggml_backend_cuda_reg_get_name, 5703 /* .get_device_count = */ ggml_backend_cuda_reg_get_device_count, 5704 /* .get_device = */ ggml_backend_cuda_reg_get_device, 5705 /* .get_proc_address = */ ggml_backend_cuda_reg_get_proc_address, 5706}; 5707 5708// backend registry 5709ggml_backend_reg_t ggml_backend_cuda_reg() { 5710 static ggml_backend_reg reg; 5711 static bool initialized = false; 5712 5713 { 5714 static std::mutex mutex; 5715 std::lock_guard<std::mutex> lock(mutex); 5716 if (!initialized) { 5717 ggml_backend_cuda_reg_context * ctx = new ggml_backend_cuda_reg_context; 5718 const int min_batch_size = getenv("GGML_OP_OFFLOAD_MIN_BATCH") ? atoi(getenv("GGML_OP_OFFLOAD_MIN_BATCH")) : 32; 5719 5720 const ggml_cuda_device_info & info = ggml_cuda_info(); 5721 const bool virtual_devices = info.device_count > info.physical_device_count; 5722 5723 for (int i = 0; i < info.device_count; i++) { 5724 const int physical_id = info.devices[i].physical_device; 5725 5726 ggml_backend_cuda_device_context * dev_ctx = new ggml_backend_cuda_device_context; 5727 dev_ctx->device = i; 5728 dev_ctx->name = GGML_CUDA_NAME + std::to_string(i); 5729 dev_ctx->description = ggml_cuda_device_description(i); 5730 5731 char pci_bus_id[32] = {}; 5732 CUDA_CHECK(cudaDeviceGetPCIBusId(pci_bus_id, sizeof(pci_bus_id), physical_id)); 5733 dev_ctx->pci_bus_id = pci_bus_id; 5734 if (virtual_devices) { 5735 // make the pci bus id unique for virtual devices 5736 dev_ctx->pci_bus_id += "-v" + std::to_string(i); 5737 } 5738 for (char & c : dev_ctx->pci_bus_id) { 5739 c = std::tolower(c); 5740 } 5741 dev_ctx->op_offload_min_batch_size = min_batch_size; 5742 5743 ggml_backend_dev_t dev = new ggml_backend_device { 5744 /* .iface = */ ggml_backend_cuda_device_interface, 5745 /* .reg = */ ®, 5746 /* .context = */ dev_ctx 5747 }; 5748 ctx->devices.push_back(dev); 5749 } 5750 5751 reg = ggml_backend_reg { 5752 /* .api_version = */ GGML_BACKEND_API_VERSION, 5753 /* .iface = */ ggml_backend_cuda_reg_interface, 5754 /* .context = */ ctx 5755 }; 5756 } 5757 5758 initialized = true; 5759 } 5760 5761 return ® 5762} 5763 5764ggml_backend_t ggml_backend_cuda_init(int device) { 5765 if (device < 0 || device >= ggml_backend_cuda_get_device_count()) { 5766 GGML_LOG_ERROR("%s: invalid device %d\n", __func__, device); 5767 return nullptr; 5768 } 5769 5770 ggml_backend_cuda_context * ctx = new ggml_backend_cuda_context(device); 5771 if (ctx == nullptr) { 5772 GGML_LOG_ERROR("%s: failed to allocate context\n", __func__); 5773 return nullptr; 5774 } 5775 5776 ggml_backend_t cuda_backend = new ggml_backend { 5777 /* .guid = */ ggml_backend_cuda_guid(), 5778 /* .iface = */ ggml_backend_cuda_interface, 5779 /* .device = */ ggml_backend_reg_dev_get(ggml_backend_cuda_reg(), device), 5780 /* .context = */ ctx, 5781 }; 5782 5783 return cuda_backend; 5784} 5785 5786GGML_BACKEND_DL_IMPL(ggml_backend_cuda_reg)