whispercpp 1.3.7 → 1.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -4
  3. data/ext/options.rb +1 -1
  4. data/ext/ruby_whisper.c +0 -1
  5. data/ext/ruby_whisper.h +7 -1
  6. data/ext/ruby_whisper_context.c +50 -1
  7. data/ext/ruby_whisper_log_settable.h +1 -2
  8. data/ext/ruby_whisper_params.c +9 -8
  9. data/ext/ruby_whisper_transcribe.cpp +0 -19
  10. data/ext/ruby_whisper_vad_context.c +30 -10
  11. data/ext/ruby_whisper_vad_context_detect.cpp +8 -9
  12. data/ext/ruby_whisper_vad_params.c +4 -4
  13. data/ext/ruby_whisper_vad_segment.c +2 -2
  14. data/ext/sources/CMakeLists.txt +2 -1
  15. data/ext/sources/cmake/parakeet.pc.in +2 -2
  16. data/ext/sources/cmake/whisper.pc.in +2 -2
  17. data/ext/sources/examples/cli/cli.cpp +9 -1
  18. data/ext/sources/examples/common-ggml.cpp +2 -0
  19. data/ext/sources/examples/vad-speech-segments/speech.cpp +3 -2
  20. data/ext/sources/ggml/CMakeLists.txt +3 -4
  21. data/ext/sources/ggml/include/ggml-cuda.h +0 -3
  22. data/ext/sources/ggml/include/ggml-sycl.h +8 -0
  23. data/ext/sources/ggml/include/ggml.h +3 -1
  24. data/ext/sources/ggml/src/CMakeLists.txt +8 -1
  25. data/ext/sources/ggml/src/ggml-backend-meta.cpp +7 -4
  26. data/ext/sources/ggml/src/ggml-common.h +13 -2
  27. data/ext/sources/ggml/src/ggml-cpu/CMakeLists.txt +1 -1
  28. data/ext/sources/ggml/src/ggml-cpu/amx/mmq.cpp +5 -6
  29. data/ext/sources/ggml/src/ggml-cpu/arch/arm/quants.c +78 -4
  30. data/ext/sources/ggml/src/ggml-cpu/arch/x86/quants.c +142 -4
  31. data/ext/sources/ggml/src/ggml-cpu/arch-fallback.h +7 -2
  32. data/ext/sources/ggml/src/ggml-cpu/ggml-cpu.c +14 -0
  33. data/ext/sources/ggml/src/ggml-cpu/llamafile/sgemm.cpp +26 -19
  34. data/ext/sources/ggml/src/ggml-cpu/ops.cpp +129 -46
  35. data/ext/sources/ggml/src/ggml-cpu/quants.c +51 -0
  36. data/ext/sources/ggml/src/ggml-cpu/quants.h +3 -0
  37. data/ext/sources/ggml/src/ggml-cpu/simd-gemm.h +1 -1
  38. data/ext/sources/ggml/src/ggml-cpu/simd-mappings.h +11 -0
  39. data/ext/sources/ggml/src/ggml-cpu/vec.cpp +2 -2
  40. data/ext/sources/ggml/src/ggml-cuda/binbcast.cu +90 -46
  41. data/ext/sources/ggml/src/ggml-cuda/col2im-1d.cu +81 -0
  42. data/ext/sources/ggml/src/ggml-cuda/col2im-1d.cuh +3 -0
  43. data/ext/sources/ggml/src/ggml-cuda/common.cuh +4 -0
  44. data/ext/sources/ggml/src/ggml-cuda/concat.cu +33 -21
  45. data/ext/sources/ggml/src/ggml-cuda/conv-transpose-1d.cu +14 -12
  46. data/ext/sources/ggml/src/ggml-cuda/convert.cu +86 -34
  47. data/ext/sources/ggml/src/ggml-cuda/cpy.cu +80 -29
  48. data/ext/sources/ggml/src/ggml-cuda/fattn-common.cuh +9 -5
  49. data/ext/sources/ggml/src/ggml-cuda/fattn-mma-f16.cuh +4 -0
  50. data/ext/sources/ggml/src/ggml-cuda/fattn-tile.cuh +9 -5
  51. data/ext/sources/ggml/src/ggml-cuda/fattn.cu +27 -21
  52. data/ext/sources/ggml/src/ggml-cuda/gated_delta_net.cu +40 -25
  53. data/ext/sources/ggml/src/ggml-cuda/gated_delta_net.cuh +10 -0
  54. data/ext/sources/ggml/src/ggml-cuda/getrows.cu +15 -12
  55. data/ext/sources/ggml/src/ggml-cuda/ggml-cuda.cu +718 -1248
  56. data/ext/sources/ggml/src/ggml-cuda/mmq.cu +7 -0
  57. data/ext/sources/ggml/src/ggml-cuda/mmvq.cu +77 -40
  58. data/ext/sources/ggml/src/ggml-cuda/out-prod.cu +55 -12
  59. data/ext/sources/ggml/src/ggml-cuda/set-rows.cu +64 -4
  60. data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_16-ncols2_2.cu +1 -0
  61. data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_32-ncols2_2.cu +1 -0
  62. data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_4-ncols2_2.cu +1 -0
  63. data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_8-ncols2_2.cu +1 -0
  64. data/ext/sources/ggml/src/ggml-cuda/topk-moe.cu +7 -1
  65. data/ext/sources/ggml/src/ggml-cuda/vendors/hip.h +1 -0
  66. data/ext/sources/ggml/src/ggml-cuda/vendors/musa.h +1 -0
  67. data/ext/sources/ggml/src/ggml-hexagon/CMakeLists.txt +0 -5
  68. data/ext/sources/ggml/src/ggml-hexagon/ggml-hexagon.cpp +1634 -1293
  69. data/ext/sources/ggml/src/ggml-hexagon/htp/CMakeLists.txt +11 -40
  70. data/ext/sources/ggml/src/ggml-hexagon/htp/cmake-toolchain.cmake +13 -15
  71. data/ext/sources/ggml/src/ggml-hexagon/htp/concat-ops.c +1 -1
  72. data/ext/sources/ggml/src/ggml-hexagon/htp/flash-attn-ops.c +1749 -399
  73. data/ext/sources/ggml/src/ggml-hexagon/htp/flash-attn-ops.h +303 -0
  74. data/ext/sources/ggml/src/ggml-hexagon/htp/hex-common.h +80 -0
  75. data/ext/sources/ggml/src/ggml-hexagon/htp/hex-dma.h +26 -23
  76. data/ext/sources/ggml/src/ggml-hexagon/htp/hex-profile.h +64 -0
  77. data/ext/sources/ggml/src/ggml-hexagon/htp/hex-utils.h +1 -83
  78. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-fa-kernels.h +555 -0
  79. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-mm-kernels-tiled.h +1303 -0
  80. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-queue.c +9 -0
  81. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-queue.h +27 -4
  82. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-utils.h +59 -37
  83. data/ext/sources/ggml/src/ggml-hexagon/htp/htp-ctx.h +11 -3
  84. data/ext/sources/ggml/src/ggml-hexagon/htp/htp-ops.h +52 -12
  85. data/ext/sources/ggml/src/ggml-hexagon/htp/htp-vtcm.h +19 -0
  86. data/ext/sources/ggml/src/ggml-hexagon/htp/htp_iface.idl +2 -1
  87. data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-base.h +14 -30
  88. data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-exp.h +39 -0
  89. data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-fa-kernels.h +232 -0
  90. data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-mm-kernels-flat.h +1511 -0
  91. data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-mm-kernels-tiled.h +1200 -0
  92. data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-sigmoid.h +39 -0
  93. data/ext/sources/ggml/src/ggml-hexagon/htp/main.c +127 -32
  94. data/ext/sources/ggml/src/ggml-hexagon/htp/matmul-ops.c +3023 -4425
  95. data/ext/sources/ggml/src/ggml-hexagon/htp/matmul-ops.h +650 -0
  96. data/ext/sources/ggml/src/ggml-hexagon/htp/rope-ops.c +48 -13
  97. data/ext/sources/ggml/src/ggml-hexagon/htp/ssm-conv.c +10 -9
  98. data/ext/sources/ggml/src/ggml-hexagon/htp/worker-pool.c +15 -3
  99. data/ext/sources/ggml/src/ggml-hexagon/htp/worker-pool.h +8 -0
  100. data/ext/sources/ggml/src/ggml-hexagon/htp-opnode.h +168 -50
  101. data/ext/sources/ggml/src/ggml-hexagon/libggml-htp.inf +0 -4
  102. data/ext/sources/ggml/src/ggml-hip/CMakeLists.txt +5 -0
  103. data/ext/sources/ggml/src/ggml-metal/ggml-metal-device.cpp +69 -5
  104. data/ext/sources/ggml/src/ggml-metal/ggml-metal-device.h +4 -1
  105. data/ext/sources/ggml/src/ggml-metal/ggml-metal-device.m +27 -6
  106. data/ext/sources/ggml/src/ggml-metal/ggml-metal-impl.h +38 -0
  107. data/ext/sources/ggml/src/ggml-metal/ggml-metal-ops.cpp +132 -2
  108. data/ext/sources/ggml/src/ggml-metal/ggml-metal-ops.h +2 -0
  109. data/ext/sources/ggml/src/ggml-metal/ggml-metal.metal +345 -87
  110. data/ext/sources/ggml/src/ggml-opencl/CMakeLists.txt +13 -0
  111. data/ext/sources/ggml/src/ggml-opencl/fa_tune.h +92 -0
  112. data/ext/sources/ggml/src/ggml-opencl/ggml-opencl.cpp +4060 -357
  113. data/ext/sources/ggml/src/ggml-opencl/kernels/cvt.cl +198 -0
  114. data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f16.cl +81 -41
  115. data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32.cl +88 -39
  116. data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32_f16.cl +1995 -96
  117. data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32_q4_0.cl +1615 -0
  118. data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32_q8_0.cl +1486 -0
  119. data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_pre_f16.cl +156 -0
  120. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_f32_ns.cl +74 -6
  121. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q4_0_f32_ns.cl +74 -6
  122. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q4_1_f32_ns.cl +74 -6
  123. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q4_k_f32_ns.cl +71 -6
  124. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q5_0_f32_ns.cl +74 -6
  125. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q5_1_f32_ns.cl +74 -6
  126. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q5_k_f32_ns.cl +74 -6
  127. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q6_k_f32_ns.cl +74 -6
  128. data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q1_0_f32.cl +94 -0
  129. data/ext/sources/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q1_0_f32.cl +121 -0
  130. data/ext/sources/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q8_0_f32.cl +1 -1
  131. data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mm_q1_0_f32_l4_lm.cl +156 -0
  132. data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mv_f16_f32_l4.cl +1149 -0
  133. data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mv_q1_0_f32.cl +141 -0
  134. data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mv_q1_0_f32_flat.cl +190 -0
  135. data/ext/sources/ggml/src/ggml-opencl/kernels/norm.cl +5 -2
  136. data/ext/sources/ggml/src/ggml-opencl/kernels/set_rows.cl +500 -0
  137. data/ext/sources/ggml/src/ggml-opencl/libdl.h +79 -0
  138. data/ext/sources/ggml/src/ggml-openvino/.clang-format +0 -5
  139. data/ext/sources/ggml/src/ggml-openvino/CMakeLists.txt +2 -4
  140. data/ext/sources/ggml/src/ggml-openvino/ggml-decoder.cpp +733 -130
  141. data/ext/sources/ggml/src/ggml-openvino/ggml-decoder.h +76 -23
  142. data/ext/sources/ggml/src/ggml-openvino/ggml-openvino-extra.cpp +57 -3
  143. data/ext/sources/ggml/src/ggml-openvino/ggml-openvino-extra.h +29 -8
  144. data/ext/sources/ggml/src/ggml-openvino/ggml-openvino.cpp +307 -59
  145. data/ext/sources/ggml/src/ggml-openvino/ggml-quants.cpp +66 -0
  146. data/ext/sources/ggml/src/ggml-openvino/ggml-quants.h +10 -4
  147. data/ext/sources/ggml/src/ggml-openvino/openvino/decoder.h +56 -16
  148. data/ext/sources/ggml/src/ggml-openvino/openvino/frontend.h +1 -1
  149. data/ext/sources/ggml/src/ggml-openvino/openvino/input_model.h +4 -4
  150. data/ext/sources/ggml/src/ggml-openvino/openvino/node_context.h +94 -37
  151. data/ext/sources/ggml/src/ggml-openvino/openvino/op/add_id.cpp +76 -0
  152. data/ext/sources/ggml/src/ggml-openvino/openvino/op/argsort.cpp +47 -0
  153. data/ext/sources/ggml/src/ggml-openvino/openvino/op/clamp.cpp +33 -0
  154. data/ext/sources/ggml/src/ggml-openvino/openvino/op/concat.cpp +48 -0
  155. data/ext/sources/ggml/src/ggml-openvino/openvino/op/cont.cpp +8 -16
  156. data/ext/sources/ggml/src/ggml-openvino/openvino/op/cpy.cpp +14 -1
  157. data/ext/sources/ggml/src/ggml-openvino/openvino/op/div.cpp +146 -0
  158. data/ext/sources/ggml/src/ggml-openvino/openvino/op/flash_attn_ext.cpp +108 -21
  159. data/ext/sources/ggml/src/ggml-openvino/openvino/op/gated_delta_net.cpp +282 -0
  160. data/ext/sources/ggml/src/ggml-openvino/openvino/op/gated_delta_net.hpp +65 -0
  161. data/ext/sources/ggml/src/ggml-openvino/openvino/op/get_rows.cpp +2 -9
  162. data/ext/sources/ggml/src/ggml-openvino/openvino/op/glu_geglu.cpp +21 -7
  163. data/ext/sources/ggml/src/ggml-openvino/openvino/op/glu_swiglu.cpp +41 -8
  164. data/ext/sources/ggml/src/ggml-openvino/openvino/op/im2col.cpp +120 -0
  165. data/ext/sources/ggml/src/ggml-openvino/openvino/op/l2_norm.cpp +44 -0
  166. data/ext/sources/ggml/src/ggml-openvino/openvino/op/mul_mat_id.cpp +226 -0
  167. data/ext/sources/ggml/src/ggml-openvino/openvino/op/mulmat.cpp +19 -9
  168. data/ext/sources/ggml/src/ggml-openvino/openvino/op/norm.cpp +58 -0
  169. data/ext/sources/ggml/src/ggml-openvino/openvino/op/pad.cpp +95 -0
  170. data/ext/sources/ggml/src/ggml-openvino/openvino/op/permute.cpp +58 -13
  171. data/ext/sources/ggml/src/ggml-openvino/openvino/op/repeat.cpp +74 -0
  172. data/ext/sources/ggml/src/ggml-openvino/openvino/op/reshape.cpp +13 -6
  173. data/ext/sources/ggml/src/ggml-openvino/openvino/op/rms_norm.cpp +1 -1
  174. data/ext/sources/ggml/src/ggml-openvino/openvino/op/rope.cpp +134 -38
  175. data/ext/sources/ggml/src/ggml-openvino/openvino/op/set_rows.cpp +3 -3
  176. data/ext/sources/ggml/src/ggml-openvino/openvino/op/softmax.cpp +126 -49
  177. data/ext/sources/ggml/src/ggml-openvino/openvino/op/ssm_conv.cpp +59 -0
  178. data/ext/sources/ggml/src/ggml-openvino/openvino/op/sum_rows.cpp +27 -0
  179. data/ext/sources/ggml/src/ggml-openvino/openvino/op/transpose.cpp +32 -1
  180. data/ext/sources/ggml/src/ggml-openvino/openvino/op/unary_silu.cpp +1 -1
  181. data/ext/sources/ggml/src/ggml-openvino/openvino/op/unary_softplus.cpp +38 -0
  182. data/ext/sources/ggml/src/ggml-openvino/openvino/op/view.cpp +90 -25
  183. data/ext/sources/ggml/src/ggml-openvino/openvino/op_table.cpp +41 -23
  184. data/ext/sources/ggml/src/ggml-openvino/openvino/op_table.h +18 -5
  185. data/ext/sources/ggml/src/ggml-openvino/openvino/pass/mark_decompression_convert_constant_folding.h +1 -1
  186. data/ext/sources/ggml/src/ggml-openvino/openvino/translate_session.cpp +43 -40
  187. data/ext/sources/ggml/src/ggml-openvino/openvino/translate_session.h +5 -4
  188. data/ext/sources/ggml/src/ggml-openvino/openvino/utils.cpp +548 -3
  189. data/ext/sources/ggml/src/ggml-openvino/openvino/utils.h +28 -26
  190. data/ext/sources/ggml/src/ggml-openvino/utils.cpp +383 -94
  191. data/ext/sources/ggml/src/ggml-openvino/utils.h +11 -8
  192. data/ext/sources/ggml/src/ggml-quants.c +76 -0
  193. data/ext/sources/ggml/src/ggml-quants.h +3 -0
  194. data/ext/sources/ggml/src/ggml-sycl/CMakeLists.txt +5 -5
  195. data/ext/sources/ggml/src/ggml-sycl/backend.hpp +2 -0
  196. data/ext/sources/ggml/src/ggml-sycl/binbcast.cpp +12 -0
  197. data/ext/sources/ggml/src/ggml-sycl/col2im-1d.cpp +102 -0
  198. data/ext/sources/ggml/src/ggml-sycl/col2im-1d.hpp +8 -0
  199. data/ext/sources/ggml/src/ggml-sycl/common.cpp +6 -8
  200. data/ext/sources/ggml/src/ggml-sycl/common.hpp +19 -2
  201. data/ext/sources/ggml/src/ggml-sycl/concat.cpp +21 -1
  202. data/ext/sources/ggml/src/ggml-sycl/conv2d-dw.cpp +158 -0
  203. data/ext/sources/ggml/src/ggml-sycl/conv2d-dw.hpp +10 -0
  204. data/ext/sources/ggml/src/ggml-sycl/conv2d-transpose.cpp +125 -0
  205. data/ext/sources/ggml/src/ggml-sycl/conv2d-transpose.hpp +10 -0
  206. data/ext/sources/ggml/src/ggml-sycl/conv2d.cpp +150 -0
  207. data/ext/sources/ggml/src/ggml-sycl/conv2d.hpp +10 -0
  208. data/ext/sources/ggml/src/ggml-sycl/conv3d.cpp +224 -0
  209. data/ext/sources/ggml/src/ggml-sycl/conv3d.hpp +8 -0
  210. data/ext/sources/ggml/src/ggml-sycl/convert.cpp +6 -0
  211. data/ext/sources/ggml/src/ggml-sycl/cpy.cpp +706 -0
  212. data/ext/sources/ggml/src/ggml-sycl/cpy.hpp +281 -0
  213. data/ext/sources/ggml/src/ggml-sycl/cross_entropy_loss.cpp +255 -0
  214. data/ext/sources/ggml/src/ggml-sycl/cross_entropy_loss.hpp +7 -0
  215. data/ext/sources/ggml/src/ggml-sycl/dequantize.hpp +15 -0
  216. data/ext/sources/ggml/src/ggml-sycl/dmmv.cpp +492 -319
  217. data/ext/sources/ggml/src/ggml-sycl/dpct/helper.hpp +15 -7
  218. data/ext/sources/ggml/src/ggml-sycl/element_wise.cpp +215 -115
  219. data/ext/sources/ggml/src/ggml-sycl/element_wise.hpp +2 -0
  220. data/ext/sources/ggml/src/ggml-sycl/ggml-sycl.cpp +1006 -336
  221. data/ext/sources/ggml/src/ggml-sycl/mmvq.cpp +252 -67
  222. data/ext/sources/ggml/src/ggml-sycl/mmvq.hpp +17 -0
  223. data/ext/sources/ggml/src/ggml-sycl/norm.cpp +103 -49
  224. data/ext/sources/ggml/src/ggml-sycl/outprod.cpp +45 -9
  225. data/ext/sources/ggml/src/ggml-sycl/pool.cpp +185 -0
  226. data/ext/sources/ggml/src/ggml-sycl/pool.hpp +22 -0
  227. data/ext/sources/ggml/src/ggml-sycl/presets.hpp +3 -1
  228. data/ext/sources/ggml/src/ggml-sycl/set_rows.cpp +10 -2
  229. data/ext/sources/ggml/src/ggml-sycl/softmax.cpp +9 -10
  230. data/ext/sources/ggml/src/ggml-sycl/vecdotq.hpp +35 -0
  231. data/ext/sources/ggml/src/ggml-vulkan/CMakeLists.txt +5 -0
  232. data/ext/sources/ggml/src/ggml-vulkan/ggml-vulkan.cpp +833 -215
  233. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/col2im_1d.comp +61 -0
  234. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/conv2d_mm.comp +1 -1
  235. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/conv3d_mm.comp +431 -0
  236. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/diag.comp +3 -3
  237. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/flash_attn.comp +1 -0
  238. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/flash_attn_cm1.comp +1 -0
  239. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/generic_unary_head.glsl +21 -19
  240. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/get_rows_back.comp +25 -0
  241. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/glu_head.glsl +23 -4
  242. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/glu_main.glsl +14 -18
  243. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/l2_norm.comp +4 -7
  244. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mat_vecq.comp +21 -24
  245. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mm.comp +31 -23
  246. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mm_cm2.comp +6 -5
  247. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mm_funcs.glsl +84 -67
  248. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/norm.comp +10 -10
  249. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/repeat_back.comp +3 -3
  250. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/roll.comp +3 -3
  251. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/tri.comp +3 -3
  252. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/unary.comp +168 -0
  253. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/vulkan-shaders-gen.cpp +121 -74
  254. data/ext/sources/ggml/src/ggml-webgpu/ggml-webgpu-shader-lib.hpp +26 -19
  255. data/ext/sources/ggml/src/ggml-webgpu/ggml-webgpu.cpp +31 -36
  256. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/common_decls.tmpl +16 -2
  257. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/flash_attn_vec_split.wgsl +7 -7
  258. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/get_rows.wgsl +21 -0
  259. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_decls.tmpl +439 -320
  260. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_id_vec.wgsl +2 -2
  261. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_vec.wgsl +45 -39
  262. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_vec_acc.tmpl +586 -465
  263. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_vec_q_acc.tmpl +63 -69
  264. data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/quantize_q8.wgsl +14 -9
  265. data/ext/sources/ggml/src/ggml.c +36 -14
  266. data/ext/sources/include/whisper.h +21 -0
  267. data/ext/sources/src/whisper.cpp +164 -14
  268. data/lib/whisper/log_settable.rb +5 -8
  269. data/lib/whisper/model/uri.rb +0 -7
  270. data/sig/whisper.rbs +6 -0
  271. data/test/test_vad.rb +9 -0
  272. data/test/test_vad_context.rb +2 -2
  273. data/whispercpp.gemspec +1 -1
  274. metadata +62 -37
  275. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-flash-attn-ops.c +0 -1878
  276. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-matmul-ops.c +0 -2066
  277. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-ops.c +0 -6
  278. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-ops.h +0 -88
  279. data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-profile.h +0 -34
  280. data/ext/sources/ggml/src/ggml-hexagon/htp/vtcm-utils.h +0 -16
  281. data/ext/sources/ggml/src/ggml-openvino/openvino/op/unary_gelu.cpp +0 -25
  282. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/abs.comp +0 -21
  283. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/ceil.comp +0 -22
  284. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/clamp.comp +0 -17
  285. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/cos.comp +0 -17
  286. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/elu.comp +0 -27
  287. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/exp.comp +0 -20
  288. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/floor.comp +0 -22
  289. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/gelu.comp +0 -25
  290. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/gelu_erf.comp +0 -39
  291. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/gelu_quick.comp +0 -23
  292. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/hardsigmoid.comp +0 -22
  293. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/hardswish.comp +0 -22
  294. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/leaky_relu.comp +0 -22
  295. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/neg.comp +0 -20
  296. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/relu.comp +0 -21
  297. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/round.comp +0 -29
  298. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sgn.comp +0 -21
  299. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sigmoid.comp +0 -20
  300. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/silu.comp +0 -22
  301. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sin.comp +0 -17
  302. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/softplus.comp +0 -23
  303. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sqrt.comp +0 -17
  304. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/square.comp +0 -17
  305. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/step.comp +0 -22
  306. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/tanh.comp +0 -20
  307. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/trunc.comp +0 -22
  308. data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/xielu.comp +0 -35
@@ -11,6 +11,7 @@
11
11
  #include "ggml-cuda/argsort.cuh"
12
12
  #include "ggml-cuda/binbcast.cuh"
13
13
  #include "ggml-cuda/clamp.cuh"
14
+ #include "ggml-cuda/col2im-1d.cuh"
14
15
  #include "ggml-cuda/concat.cuh"
15
16
  #include "ggml-cuda/conv-transpose-1d.cuh"
16
17
  #include "ggml-cuda/conv2d.cuh"
@@ -542,12 +543,42 @@ struct ggml_cuda_pool_vmm : public ggml_cuda_pool {
542
543
  // the memory allocation handle is no longer needed after mapping
543
544
  CU_CHECK(cuMemRelease(handle));
544
545
 
545
- // set access
546
- CUmemAccessDesc access = {};
547
- access.location.type = CU_MEM_LOCATION_TYPE_DEVICE;
548
- access.location.id = device;
549
- access.flags = CU_MEM_ACCESS_FLAGS_PROT_READWRITE;
550
- CU_CHECK(cuMemSetAccess((CUdeviceptr)((char *)(pool_addr) + pool_size), reserve_size, &access, 1));
546
+ // VMM Bug fix for P2P access if GGML_CUDA_P2P is set, or if NCCL build
547
+ bool use_peer_access = getenv("GGML_CUDA_P2P") != nullptr;
548
+ #if defined(GGML_USE_NCCL)
549
+ use_peer_access = true;
550
+ #endif // defined(GGML_USE_NCCL)
551
+
552
+ if (use_peer_access) {
553
+ // NCCL implicitly enables peer access (cudaDeviceEnablePeerAccess), and
554
+ // GGML_CUDA_P2P enables it explicitly. Unlike cudaMalloc buffers, VMM
555
+ // allocations do not become peer-accessible from that alone, so access
556
+ // must be granted explicitly here.
557
+ std::vector<CUmemAccessDesc> access_descs;
558
+ const int device_count = ggml_cuda_info().device_count;
559
+ for (int id = 0; id < device_count; ++id) {
560
+ if (id != device) {
561
+ int can_access_peer = 0;
562
+ CUDA_CHECK(cudaDeviceCanAccessPeer(&can_access_peer, id, device));
563
+ if (!can_access_peer) {
564
+ continue;
565
+ }
566
+ }
567
+ CUmemAccessDesc access = {};
568
+ access.location.type = CU_MEM_LOCATION_TYPE_DEVICE;
569
+ access.location.id = id;
570
+ access.flags = CU_MEM_ACCESS_FLAGS_PROT_READWRITE;
571
+ access_descs.push_back(access);
572
+ }
573
+ CU_CHECK(cuMemSetAccess(start_ptr, reserve_size, access_descs.data(), access_descs.size()));
574
+ } else {
575
+ // set access for non P2P
576
+ CUmemAccessDesc access = {};
577
+ access.location.type = CU_MEM_LOCATION_TYPE_DEVICE;
578
+ access.location.id = device;
579
+ access.flags = CU_MEM_ACCESS_FLAGS_PROT_READWRITE;
580
+ CU_CHECK(cuMemSetAccess(start_ptr, reserve_size, &access, 1));
581
+ }
551
582
 
552
583
  // add to the pool
553
584
  pool_size += reserve_size;
@@ -622,18 +653,6 @@ ggml_backend_cuda_context::~ggml_backend_cuda_context() {
622
653
 
623
654
  // cuda buffer
624
655
 
625
- struct ggml_backend_cuda_device_context {
626
- int device;
627
- std::string name;
628
- std::string description;
629
- std::string pci_bus_id;
630
- int op_offload_min_batch_size;
631
- #if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
632
- std::mutex device_mutex;
633
- int active_count = 0;
634
- #endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
635
- };
636
-
637
656
  struct ggml_backend_cuda_buffer_context {
638
657
  int device;
639
658
  void * dev_ptr = nullptr;
@@ -651,13 +670,6 @@ struct ggml_backend_cuda_buffer_context {
651
670
 
652
671
  static void ggml_backend_cuda_buffer_free_buffer(ggml_backend_buffer_t buffer) {
653
672
  ggml_backend_cuda_buffer_context * ctx = (ggml_backend_cuda_buffer_context *)buffer->context;
654
-
655
- #if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
656
- ggml_backend_cuda_device_context * dev_ctx = (ggml_backend_cuda_device_context *) buffer->buft->device->context;
657
- std::lock_guard<std::mutex> lock(dev_ctx->device_mutex);
658
- dev_ctx->active_count--;
659
- #endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
660
-
661
673
  delete ctx;
662
674
  }
663
675
 
@@ -810,12 +822,6 @@ static ggml_backend_buffer_t ggml_backend_cuda_buffer_type_alloc_buffer(ggml_bac
810
822
 
811
823
  ggml_backend_cuda_buffer_context * ctx = new ggml_backend_cuda_buffer_context(buft_ctx->device, dev_ptr);
812
824
 
813
- #if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
814
- ggml_backend_cuda_device_context * dev_ctx = (ggml_backend_cuda_device_context *) buft->device->context;
815
- std::lock_guard<std::mutex> lock(dev_ctx->device_mutex);
816
- dev_ctx->active_count++;
817
- #endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
818
-
819
825
  return ggml_backend_buffer_init(buft, ggml_backend_cuda_buffer_interface, ctx, size);
820
826
  }
821
827
 
@@ -878,299 +884,6 @@ ggml_backend_buffer_type_t ggml_backend_cuda_buffer_type(int device) {
878
884
  return &ggml_backend_cuda_buffer_types[device];
879
885
  }
880
886
 
881
- // cuda split buffer
882
-
883
- static int64_t get_row_rounding(const std::array<float, GGML_CUDA_MAX_DEVICES> & tensor_split) {
884
- int64_t row_rounding = 0;
885
- for (int id = 0; id < ggml_backend_cuda_get_device_count(); ++id) {
886
- if (tensor_split[id] >= (id + 1 < ggml_backend_cuda_get_device_count() ? tensor_split[id + 1] : 1.0f)) {
887
- continue;
888
- }
889
-
890
- const int cc = ggml_cuda_info().devices[id].cc;
891
- row_rounding = std::max(row_rounding, (int64_t)get_mmq_y_host(cc));
892
- }
893
- return row_rounding;
894
- }
895
-
896
- static void get_row_split(int64_t * row_low, int64_t * row_high, const ggml_tensor * tensor, const std::array<float, GGML_CUDA_MAX_DEVICES> & tensor_split, int id) {
897
- const int64_t nrows = ggml_nrows(tensor);
898
- const int64_t rounding = get_row_rounding(tensor_split);
899
-
900
- *row_low = id == 0 ? 0 : nrows*tensor_split[id];
901
- *row_low -= *row_low % rounding;
902
-
903
- if (id == ggml_backend_cuda_get_device_count() - 1) {
904
- *row_high = nrows;
905
- } else {
906
- *row_high = nrows*tensor_split[id + 1];
907
- *row_high -= *row_high % rounding;
908
- }
909
- }
910
-
911
- static size_t ggml_nbytes_split(const struct ggml_tensor * tensor, int nrows_split) {
912
- static_assert(GGML_MAX_DIMS == 4, "GGML_MAX_DIMS is not 4 - update this function");
913
-
914
- return nrows_split*ggml_row_size(tensor->type, tensor->ne[0]);
915
- }
916
-
917
- struct ggml_backend_cuda_split_buffer_type_context {
918
- int main_device;
919
- std::array<float, GGML_CUDA_MAX_DEVICES> tensor_split;
920
- std::string name;
921
- };
922
-
923
- struct ggml_backend_cuda_split_buffer_context {
924
- ~ggml_backend_cuda_split_buffer_context() {
925
- for (ggml_tensor_extra_gpu * extra : tensor_extras) {
926
- for (int id = 0; id < GGML_CUDA_MAX_DEVICES; ++id) {
927
- for (int64_t is = 0; is < GGML_CUDA_MAX_STREAMS; ++is) {
928
- if (extra->events[id][is] != nullptr) {
929
- CUDA_CHECK(cudaEventDestroy(extra->events[id][is]));
930
- }
931
- }
932
- if (extra->data_device[id] != nullptr) {
933
- CUDA_CHECK(cudaFree(extra->data_device[id]));
934
- }
935
- }
936
- delete extra;
937
- }
938
- }
939
-
940
- std::vector<ggml_tensor_extra_gpu *> tensor_extras;
941
- };
942
-
943
-
944
- static void ggml_backend_cuda_split_buffer_free_buffer(ggml_backend_buffer_t buffer) {
945
- ggml_backend_cuda_split_buffer_context * ctx = (ggml_backend_cuda_split_buffer_context *)buffer->context;
946
- delete ctx;
947
- }
948
-
949
- static void * ggml_backend_cuda_split_buffer_get_base(ggml_backend_buffer_t buffer) {
950
- // the pointers are stored in the tensor extras, this is just a dummy address and never dereferenced
951
- return (void *)0x1000;
952
-
953
- GGML_UNUSED(buffer);
954
- }
955
-
956
- static enum ggml_status ggml_backend_cuda_split_buffer_init_tensor(ggml_backend_buffer_t buffer, ggml_tensor * tensor) {
957
- GGML_ASSERT(tensor->view_src == nullptr); // views of split tensors are not supported
958
- GGML_ASSERT(ggml_is_contiguous(tensor) && "split buffers only supported for contiguous tensors");
959
-
960
- ggml_backend_cuda_split_buffer_context * ctx = (ggml_backend_cuda_split_buffer_context *)buffer->context;
961
- ggml_backend_cuda_split_buffer_type_context * buft_ctx = (ggml_backend_cuda_split_buffer_type_context *)buffer->buft->context;
962
-
963
- const int64_t ne0 = tensor->ne[0];
964
-
965
- ggml_tensor_extra_gpu * extra = new ggml_tensor_extra_gpu{};
966
- ctx->tensor_extras.push_back(extra);
967
-
968
- for (int id = 0; id < ggml_backend_cuda_get_device_count(); ++id) {
969
- int64_t row_low, row_high;
970
- get_row_split(&row_low, &row_high, tensor, buft_ctx->tensor_split, id);
971
-
972
- int64_t nrows_split = row_high - row_low;
973
- if (nrows_split == 0) {
974
- continue;
975
- }
976
-
977
- size_t size = ggml_nbytes_split(tensor, nrows_split);
978
- const size_t original_size = size;
979
-
980
- // pad last row to a multiple of 512 elements to avoid out-of-bounds memory accesses
981
- if (ne0 % MATRIX_ROW_PADDING != 0) {
982
- size += ggml_row_size(tensor->type, MATRIX_ROW_PADDING - ne0 % MATRIX_ROW_PADDING);
983
- }
984
-
985
- // FIXME: do not crash if cudaMalloc fails
986
- // currently, init_tensor cannot fail, it needs to be fixed in ggml-backend first
987
- ggml_cuda_set_device(id);
988
- char * buf;
989
- CUDA_CHECK(ggml_cuda_device_malloc((void**)&buf, size, id));
990
-
991
- // set padding to 0 to avoid possible NaN values
992
- if (size > original_size) {
993
- CUDA_CHECK(cudaMemset(buf + original_size, 0, size - original_size));
994
- }
995
-
996
- extra->data_device[id] = buf;
997
-
998
- for (int64_t is = 0; is < GGML_CUDA_MAX_STREAMS; ++is) {
999
- CUDA_CHECK(cudaEventCreateWithFlags(&extra->events[id][is], cudaEventDisableTiming));
1000
- }
1001
- }
1002
- tensor->extra = extra;
1003
- return GGML_STATUS_SUCCESS;
1004
- }
1005
-
1006
- static void ggml_backend_cuda_split_buffer_set_tensor(ggml_backend_buffer_t buffer, ggml_tensor * tensor, const void * data, size_t offset, size_t size) {
1007
- // split tensors must always be set in their entirety at once
1008
- GGML_ASSERT(offset == 0);
1009
- GGML_ASSERT(size == ggml_nbytes(tensor));
1010
- GGML_ASSERT(ggml_is_contiguous(tensor) && "split buffers only supported for contiguous tensors");
1011
-
1012
- ggml_backend_cuda_split_buffer_type_context * buft_ctx = (ggml_backend_cuda_split_buffer_type_context *)buffer->buft->context;
1013
-
1014
- const int64_t ne0 = tensor->ne[0];
1015
- const size_t nb1 = tensor->nb[1];
1016
- ggml_tensor_extra_gpu * extra = (ggml_tensor_extra_gpu *)tensor->extra;
1017
-
1018
- for (int id = 0; id < ggml_backend_cuda_get_device_count(); ++id) {
1019
- int64_t row_low, row_high;
1020
- get_row_split(&row_low, &row_high, tensor, buft_ctx->tensor_split, id);
1021
-
1022
- int64_t nrows_split = row_high - row_low;
1023
- if (nrows_split == 0) {
1024
- continue;
1025
- }
1026
-
1027
- const size_t offset_split = row_low*nb1;
1028
- size_t size = ggml_nbytes_split(tensor, nrows_split);
1029
- const size_t original_size = size;
1030
-
1031
- // pad last row to a multiple of 512 elements to avoid out-of-bounds memory accesses
1032
- if (ne0 % MATRIX_ROW_PADDING != 0) {
1033
- size += ggml_row_size(tensor->type, MATRIX_ROW_PADDING - ne0 % MATRIX_ROW_PADDING);
1034
- }
1035
-
1036
- const char * buf_host = (const char *)data + offset_split;
1037
- CUDA_CHECK(cudaMemcpyAsync(extra->data_device[id], buf_host, original_size, cudaMemcpyHostToDevice, cudaStreamPerThread));
1038
- }
1039
-
1040
- for (int id = 0; id < ggml_backend_cuda_get_device_count(); ++id) {
1041
- CUDA_CHECK(cudaStreamSynchronize(cudaStreamPerThread));
1042
- }
1043
- }
1044
-
1045
- static void ggml_backend_cuda_split_buffer_get_tensor(ggml_backend_buffer_t buffer, const ggml_tensor * tensor, void * data, size_t offset, size_t size) {
1046
- // split tensors must always be set in their entirety at once
1047
- GGML_ASSERT(offset == 0);
1048
- GGML_ASSERT(size == ggml_nbytes(tensor));
1049
- GGML_ASSERT(ggml_is_contiguous(tensor) && "split buffers only supported for contiguous tensors");
1050
-
1051
- ggml_backend_cuda_split_buffer_type_context * buft_ctx = (ggml_backend_cuda_split_buffer_type_context *)buffer->buft->context;
1052
-
1053
- const int64_t ne0 = tensor->ne[0];
1054
- const size_t nb1 = tensor->nb[1];
1055
- ggml_tensor_extra_gpu * extra = (ggml_tensor_extra_gpu *)tensor->extra;
1056
-
1057
- for (int id = 0; id < ggml_backend_cuda_get_device_count(); ++id) {
1058
- int64_t row_low, row_high;
1059
- get_row_split(&row_low, &row_high, tensor, buft_ctx->tensor_split, id);
1060
-
1061
- int64_t nrows_split = row_high - row_low;
1062
- if (nrows_split == 0) {
1063
- continue;
1064
- }
1065
-
1066
- const size_t offset_split = row_low*nb1;
1067
- size_t size = ggml_nbytes_split(tensor, nrows_split);
1068
- const size_t original_size = size;
1069
-
1070
- // pad last row to a multiple of 512 elements to avoid out-of-bounds memory accesses
1071
- if (ne0 % MATRIX_ROW_PADDING != 0) {
1072
- size += ggml_row_size(tensor->type, MATRIX_ROW_PADDING - ne0 % MATRIX_ROW_PADDING);
1073
- }
1074
-
1075
- char * buf_host = (char *)data + offset_split;
1076
- CUDA_CHECK(cudaMemcpyAsync(buf_host, extra->data_device[id], original_size, cudaMemcpyDeviceToHost, cudaStreamPerThread));
1077
- }
1078
-
1079
- for (int id = 0; id < ggml_backend_cuda_get_device_count(); ++id) {
1080
- CUDA_CHECK(cudaStreamSynchronize(cudaStreamPerThread));
1081
- }
1082
- }
1083
-
1084
- static void ggml_backend_cuda_split_buffer_clear(ggml_backend_buffer_t buffer, uint8_t value) {
1085
- GGML_UNUSED(buffer);
1086
- GGML_UNUSED(value);
1087
- }
1088
-
1089
- static const ggml_backend_buffer_i ggml_backend_cuda_split_buffer_interface = {
1090
- /* .free_buffer = */ ggml_backend_cuda_split_buffer_free_buffer,
1091
- /* .get_base = */ ggml_backend_cuda_split_buffer_get_base,
1092
- /* .init_tensor = */ ggml_backend_cuda_split_buffer_init_tensor,
1093
- /* .memset_tensor = */ NULL,
1094
- /* .set_tensor = */ ggml_backend_cuda_split_buffer_set_tensor,
1095
- /* .get_tensor = */ ggml_backend_cuda_split_buffer_get_tensor,
1096
- /* .set_tensor_2d = */ NULL,
1097
- /* .get_tensor_2d = */ NULL,
1098
- /* .cpy_tensor = */ NULL,
1099
- /* .clear = */ ggml_backend_cuda_split_buffer_clear,
1100
- /* .reset = */ NULL,
1101
- };
1102
-
1103
- // cuda split buffer type
1104
-
1105
- static const char * ggml_backend_cuda_split_buffer_type_get_name(ggml_backend_buffer_type_t buft) {
1106
- ggml_backend_cuda_split_buffer_type_context * ctx = (ggml_backend_cuda_split_buffer_type_context *)buft->context;
1107
-
1108
- return ctx->name.c_str();
1109
- }
1110
-
1111
- static bool ggml_backend_buft_is_cuda_split(ggml_backend_buffer_type_t buft) {
1112
- return buft->iface.get_name == ggml_backend_cuda_split_buffer_type_get_name;
1113
- }
1114
-
1115
- static ggml_backend_buffer_t ggml_backend_cuda_split_buffer_type_alloc_buffer(ggml_backend_buffer_type_t buft, size_t size) {
1116
- // since we don't know the exact split after rounding, we cannot allocate the device buffers at this point
1117
- // instead, we allocate them for each tensor separately in init_tensor
1118
- // however, the size still represents the maximum cumulative size of all the device buffers after the tensors are allocated,
1119
- // as returned by get_alloc_size. this limit is enforced during tensor allocation by ggml-alloc, so it must be correct.
1120
- ggml_backend_cuda_split_buffer_context * ctx = new ggml_backend_cuda_split_buffer_context();
1121
-
1122
- return ggml_backend_buffer_init(buft, ggml_backend_cuda_split_buffer_interface, ctx, size);
1123
- }
1124
-
1125
- static size_t ggml_backend_cuda_split_buffer_type_get_alignment(ggml_backend_buffer_type_t buft) {
1126
- return 128;
1127
-
1128
- GGML_UNUSED(buft);
1129
- }
1130
-
1131
- static size_t ggml_backend_cuda_split_buffer_type_get_alloc_size(ggml_backend_buffer_type_t buft, const ggml_tensor * tensor) {
1132
- ggml_backend_cuda_split_buffer_type_context * ctx = (ggml_backend_cuda_split_buffer_type_context *)buft->context;
1133
- GGML_ASSERT(ggml_is_contiguous(tensor) && "split buffers only supported for contiguous tensors");
1134
-
1135
- size_t total_size = 0;
1136
-
1137
- const int64_t ne0 = tensor->ne[0];
1138
-
1139
- for (int id = 0; id < ggml_backend_cuda_get_device_count(); ++id) {
1140
- int64_t row_low, row_high;
1141
- get_row_split(&row_low, &row_high, tensor, ctx->tensor_split, id);
1142
-
1143
- int64_t nrows_split = row_high - row_low;
1144
- if (nrows_split == 0) {
1145
- continue;
1146
- }
1147
-
1148
- total_size += ggml_nbytes_split(tensor, nrows_split);
1149
-
1150
- // pad last row to a multiple of 512 elements to avoid out-of-bounds memory accesses
1151
- if (ne0 % MATRIX_ROW_PADDING != 0) {
1152
- total_size += ggml_row_size(tensor->type, MATRIX_ROW_PADDING - ne0 % MATRIX_ROW_PADDING);
1153
- }
1154
- }
1155
-
1156
- return total_size;
1157
- }
1158
-
1159
- static bool ggml_backend_cuda_split_buffer_type_is_host(ggml_backend_buffer_type_t buft) {
1160
- return false;
1161
-
1162
- GGML_UNUSED(buft);
1163
- }
1164
-
1165
- static const ggml_backend_buffer_type_i ggml_backend_cuda_split_buffer_type_interface = {
1166
- /* .get_name = */ ggml_backend_cuda_split_buffer_type_get_name,
1167
- /* .alloc_buffer = */ ggml_backend_cuda_split_buffer_type_alloc_buffer,
1168
- /* .get_alignment = */ ggml_backend_cuda_split_buffer_type_get_alignment,
1169
- /* .get_max_size = */ NULL, // defaults to SIZE_MAX
1170
- /* .get_alloc_size = */ ggml_backend_cuda_split_buffer_type_get_alloc_size,
1171
- /* .is_host = */ ggml_backend_cuda_split_buffer_type_is_host,
1172
- };
1173
-
1174
887
  // Communication context for multi-GPU AllReduce during tensor parallelism.
1175
888
  //
1176
889
  // Created once per meta backend instance. Resources for the selected mode
@@ -1460,48 +1173,6 @@ static bool ggml_backend_cuda_comm_allreduce_tensor(void * comm_ctx_v, struct gg
1460
1173
  return comm_ctx->try_allreduce(comm_ctx, tensors);
1461
1174
  }
1462
1175
 
1463
- ggml_backend_buffer_type_t ggml_backend_cuda_split_buffer_type(int main_device, const float * tensor_split) {
1464
- static std::mutex mutex;
1465
- std::lock_guard<std::mutex> lock(mutex);
1466
-
1467
- static std::map<std::pair<int, std::array<float, GGML_CUDA_MAX_DEVICES>>, struct ggml_backend_buffer_type> buft_map;
1468
-
1469
- std::array<float, GGML_CUDA_MAX_DEVICES> tensor_split_arr = {};
1470
-
1471
- bool all_zero = tensor_split == nullptr || std::all_of(tensor_split, tensor_split + GGML_CUDA_MAX_DEVICES, [](float x) { return x == 0.0f; });
1472
- if (all_zero) {
1473
- tensor_split_arr = ggml_cuda_info().default_tensor_split;
1474
- } else {
1475
- float split_sum = 0.0f;
1476
- for (int i = 0; i < ggml_backend_cuda_get_device_count(); ++i) {
1477
- tensor_split_arr[i] = split_sum;
1478
- split_sum += tensor_split[i];
1479
- }
1480
- for (int i = 0; i < ggml_backend_cuda_get_device_count(); ++i) {
1481
- tensor_split_arr[i] /= split_sum;
1482
- }
1483
- }
1484
-
1485
- auto it = buft_map.find({main_device, tensor_split_arr});
1486
- if (it != buft_map.end()) {
1487
- return &it->second;
1488
- }
1489
- auto * ctx = new ggml_backend_cuda_split_buffer_type_context{
1490
- main_device,
1491
- tensor_split_arr,
1492
- GGML_CUDA_NAME + std::to_string(main_device) + "_Split",
1493
- };
1494
-
1495
- struct ggml_backend_buffer_type buft {
1496
- /* .iface = */ ggml_backend_cuda_split_buffer_type_interface,
1497
- /* .device = */ ggml_backend_reg_dev_get(ggml_backend_cuda_reg(), main_device),
1498
- /* .context = */ ctx,
1499
- };
1500
-
1501
- auto result = buft_map.emplace(std::make_pair(main_device, tensor_split_arr), buft);
1502
- return &result.first->second;
1503
- }
1504
-
1505
1176
  // host buffer type
1506
1177
 
1507
1178
  static const char * ggml_backend_cuda_host_buffer_type_name(ggml_backend_buffer_type_t buft) {
@@ -1515,12 +1186,6 @@ static bool ggml_backend_buft_is_cuda_host(ggml_backend_buffer_type_t buft) {
1515
1186
  }
1516
1187
 
1517
1188
  static void ggml_backend_cuda_host_buffer_free_buffer(ggml_backend_buffer_t buffer) {
1518
- #if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
1519
- ggml_backend_cuda_device_context * dev_ctx = (ggml_backend_cuda_device_context *) buffer->buft->device->context;
1520
- std::lock_guard<std::mutex> lock(dev_ctx->device_mutex);
1521
- dev_ctx->active_count--;
1522
- #endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
1523
-
1524
1189
  CUDA_CHECK(cudaFreeHost(buffer->context));
1525
1190
  }
1526
1191
 
@@ -1529,8 +1194,6 @@ static void * ggml_cuda_host_malloc(size_t size) {
1529
1194
  return nullptr;
1530
1195
  }
1531
1196
 
1532
- ggml_cuda_set_device(0); // cudaMallocHost can create the implicit CUDA device context, make sure that this is consistently done on device 0.
1533
-
1534
1197
  void * ptr = nullptr;
1535
1198
  cudaError_t err = cudaMallocHost((void **) &ptr, size);
1536
1199
  if (err != cudaSuccess) {
@@ -1556,12 +1219,6 @@ static ggml_backend_buffer_t ggml_backend_cuda_host_buffer_type_alloc_buffer(ggm
1556
1219
  buffer->buft = buft;
1557
1220
  buffer->iface.free_buffer = ggml_backend_cuda_host_buffer_free_buffer;
1558
1221
 
1559
- #if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
1560
- ggml_backend_cuda_device_context * dev_ctx = (ggml_backend_cuda_device_context *) buft->device->context;
1561
- std::lock_guard<std::mutex> lock(dev_ctx->device_mutex);
1562
- dev_ctx->active_count++;
1563
- #endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
1564
-
1565
1222
  return buffer;
1566
1223
  }
1567
1224
 
@@ -1594,572 +1251,6 @@ typedef void (*ggml_cuda_op_mul_mat_t)(
1594
1251
  const char * src1_ddq_i, float * dst_dd_i, const int64_t row_low, const int64_t row_high, const int64_t src1_ncols,
1595
1252
  const int64_t src1_padded_row_size, cudaStream_t stream);
1596
1253
 
1597
- #ifndef GGML_CUDA_PEER_MAX_BATCH_SIZE
1598
- #define GGML_CUDA_PEER_MAX_BATCH_SIZE 128
1599
- #endif // GGML_CUDA_PEER_MAX_BATCH_SIZE
1600
-
1601
- #define MUL_MAT_SRC1_COL_STRIDE 128
1602
-
1603
- static cudaError_t ggml_cuda_cpy_tensor_2d(
1604
- void * dst, const struct ggml_tensor * src, int64_t i3, int64_t i2, int64_t i1_low, int64_t i1_high, cudaStream_t stream) {
1605
-
1606
- const char * src_ptr = (const char *) src->data;
1607
- char * dst_ptr = (char *) dst;
1608
-
1609
- const int64_t ne0 = src->ne[0];
1610
- const int64_t nb0 = src->nb[0];
1611
- const int64_t nb1 = src->nb[1];
1612
- const int64_t nb2 = src->nb[2];
1613
- const int64_t nb3 = src->nb[3];
1614
- const enum ggml_type type = src->type;
1615
- const int64_t ts = ggml_type_size(type);
1616
- const int64_t bs = ggml_blck_size(type);
1617
- const int64_t i1_diff = i1_high - i1_low;
1618
-
1619
- const char * x = src_ptr + i1_low*nb1 + i2*nb2 + i3*nb3;
1620
- if (nb0 == ts && nb1 == ts*ne0/bs) {
1621
- return cudaMemcpyAsync(dst_ptr, x, i1_diff*nb1, cudaMemcpyDeviceToDevice, stream);
1622
- } else if (nb0 == ts) {
1623
- return cudaMemcpy2DAsync(dst_ptr, ts*ne0/bs, x, nb1, ts*ne0/bs, i1_diff, cudaMemcpyDeviceToDevice, stream);
1624
- } else {
1625
- for (int64_t i1 = 0; i1 < i1_diff; i1++) {
1626
- const void * rx = (const void *) ((const char *) x + i1*nb1);
1627
- void * rd = (void *) (dst_ptr + i1*ts*ne0/bs);
1628
- // pretend the row is a matrix with cols=1
1629
- cudaError_t r = cudaMemcpy2DAsync(rd, ts/bs, rx, nb0, ts/bs, ne0, cudaMemcpyDeviceToDevice, stream);
1630
- if (r != cudaSuccess) {
1631
- return r;
1632
- }
1633
- }
1634
- return cudaSuccess;
1635
- }
1636
- }
1637
-
1638
- struct cublas_force_compute_type {
1639
- bool fp32 = false;
1640
- bool fp16 = false;
1641
- };
1642
-
1643
- static const cublas_force_compute_type & ggml_cuda_cublas_get_force_compute_type() {
1644
- static const cublas_force_compute_type compute_type = [] {
1645
- cublas_force_compute_type result;
1646
-
1647
- const bool ggml_cuda_force_cublas_compute_32f_env = getenv("GGML_CUDA_FORCE_CUBLAS_COMPUTE_32F") != nullptr;
1648
- const bool ggml_cuda_force_cublas_compute_16f_env = getenv("GGML_CUDA_FORCE_CUBLAS_COMPUTE_16F") != nullptr;
1649
-
1650
- GGML_ASSERT(ggml_cuda_force_cublas_compute_16f_env == false || ggml_cuda_force_cublas_compute_32f_env == false);
1651
-
1652
- if (ggml_cuda_force_cublas_compute_32f_env) {
1653
- GGML_LOG_INFO("Detected GGML_CUDA_FORCE_CUBLAS_COMPUTE_32F\n");
1654
- result.fp32 = true;
1655
- } else if (ggml_cuda_force_cublas_compute_16f_env) {
1656
- GGML_LOG_INFO("Detected GGML_CUDA_FORCE_CUBLAS_COMPUTE_16F\n");
1657
- result.fp16 = true;
1658
- }
1659
-
1660
- return result;
1661
- }();
1662
-
1663
- return compute_type;
1664
- }
1665
-
1666
- static void ggml_cuda_op_mul_mat_cublas(
1667
- ggml_backend_cuda_context & ctx,
1668
- const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst, const char * src0_dd_i, const float * src1_ddf_i,
1669
- const char * src1_ddq_i, float * dst_dd_i, const int64_t row_low, const int64_t row_high, const int64_t src1_ncols,
1670
- const int64_t src1_padded_row_size, cudaStream_t stream) {
1671
-
1672
- GGML_ASSERT(src0_dd_i != nullptr);
1673
- GGML_ASSERT(src1_ddf_i != nullptr);
1674
- GGML_ASSERT(dst_dd_i != nullptr);
1675
-
1676
- const int64_t ne00 = src0->ne[0];
1677
- const int64_t ne10 = src1->ne[0];
1678
-
1679
- const int64_t ne0 = dst->ne[0];
1680
-
1681
- const int64_t row_diff = row_high - row_low;
1682
-
1683
- int id = ggml_cuda_get_device();
1684
-
1685
- // the main device has a larger memory buffer to hold the results from all GPUs
1686
- // ldc == nrows of the matrix that cuBLAS writes into
1687
- int64_t ldc = id == ctx.device ? ne0 : row_diff;
1688
-
1689
- const int cc = ggml_cuda_info().devices[id].cc;
1690
-
1691
- const bool supports_bf16 = GGML_CUDA_CC_IS_NVIDIA(cc) || GGML_CUDA_CC_IS_AMD(cc) ||
1692
- (GGML_CUDA_CC_IS_MTHREADS(cc) && cc >= GGML_CUDA_CC_QY2);
1693
-
1694
- const bool use_fp16 =
1695
- src0->type != GGML_TYPE_NVFP4 &&
1696
- (src0->type == GGML_TYPE_F16 || ggml_is_quantized(src0->type)) &&
1697
- ggml_is_contiguous(src0) &&
1698
- row_diff == src0->ne[1] &&
1699
- dst->op_params[0] == GGML_PREC_DEFAULT;
1700
-
1701
- if (supports_bf16 && src0->type == GGML_TYPE_BF16 && ggml_is_contiguous(src0) && row_diff == src0->ne[1]) {
1702
- ggml_cuda_pool_alloc<nv_bfloat16> src1_as_bf16(ctx.pool(id));
1703
- if (src1->type != GGML_TYPE_BF16) {
1704
- const to_bf16_cuda_t to_bf16_cuda = ggml_get_to_bf16_cuda(src1->type);
1705
- GGML_ASSERT(to_bf16_cuda != nullptr);
1706
- size_t ne = src1_ncols*ne10;
1707
- src1_as_bf16.alloc(ne);
1708
- to_bf16_cuda(src1_ddf_i, src1_as_bf16.get(), ne, stream);
1709
- }
1710
- const nv_bfloat16 * src1_ptr = src1->type == GGML_TYPE_BF16 ? (const nv_bfloat16 *) src1_ddf_i : src1_as_bf16.get();
1711
- const nv_bfloat16 * src0_ptr = (const nv_bfloat16 *)src0_dd_i;
1712
- ggml_cuda_pool_alloc<nv_bfloat16> dst_bf16(ctx.pool(id), row_diff*src1_ncols);
1713
-
1714
- const float alpha_f32 = 1.0f;
1715
- const float beta_f32 = 0.0f;
1716
-
1717
- CUBLAS_CHECK(cublasSetStream(ctx.cublas_handle(id), stream));
1718
- CUBLAS_CHECK(
1719
- cublasGemmEx(ctx.cublas_handle(id), CUBLAS_OP_T, CUBLAS_OP_N,
1720
- row_diff, src1_ncols, ne10,
1721
- &alpha_f32, src0_ptr, CUDA_R_16BF, ne00,
1722
- src1_ptr, CUDA_R_16BF, ne10,
1723
- &beta_f32, dst_bf16.get(), CUDA_R_16BF, ldc,
1724
- CUBLAS_COMPUTE_32F,
1725
- CUBLAS_GEMM_DEFAULT_TENSOR_OP));
1726
-
1727
- const to_fp32_cuda_t to_fp32_cuda = ggml_get_to_fp32_cuda(GGML_TYPE_BF16);
1728
- to_fp32_cuda(dst_bf16.get(), dst_dd_i, row_diff*src1_ncols, stream);
1729
- } else if (fast_fp16_hardware_available(cc) && use_fp16) {
1730
- // convert src0 and src1 to fp16, multiply as fp16, convert dst to fp32
1731
- ggml_cuda_pool_alloc<half> src0_as_f16(ctx.pool(id));
1732
- if (src0->type != GGML_TYPE_F16) {
1733
- const to_fp16_cuda_t to_fp16_cuda = ggml_get_to_fp16_cuda(src0->type);
1734
- GGML_ASSERT(to_fp16_cuda != nullptr);
1735
- size_t ne = row_diff*ne00;
1736
- src0_as_f16.alloc(ne);
1737
- to_fp16_cuda(src0_dd_i, src0_as_f16.get(), ne, stream);
1738
- }
1739
- const half * src0_ptr = src0->type == GGML_TYPE_F16 ? (const half *) src0_dd_i : src0_as_f16.get();
1740
-
1741
- ggml_cuda_pool_alloc<half> src1_as_f16(ctx.pool(id));
1742
- if (src1->type != GGML_TYPE_F16) {
1743
- const to_fp16_cuda_t to_fp16_cuda = ggml_get_to_fp16_cuda(src1->type);
1744
- GGML_ASSERT(to_fp16_cuda != nullptr);
1745
- size_t ne = src1_ncols*ne10;
1746
- src1_as_f16.alloc(ne);
1747
- to_fp16_cuda(src1_ddf_i, src1_as_f16.get(), ne, stream);
1748
- }
1749
- const half * src1_ptr = src1->type == GGML_TYPE_F16 ? (const half *) src1_ddf_i : src1_as_f16.get();
1750
-
1751
- CUBLAS_CHECK(cublasSetStream(ctx.cublas_handle(id), stream));
1752
-
1753
- const auto & force_compute_type = ggml_cuda_cublas_get_force_compute_type();
1754
-
1755
- if (!force_compute_type.fp16 && (GGML_CUDA_CC_IS_CDNA(cc)
1756
- || GGML_CUDA_CC_IS_RDNA4(cc)
1757
- || cc == GGML_CUDA_CC_VOLTA
1758
- || force_compute_type.fp32))
1759
- {
1760
- const float alpha = 1.0f;
1761
- const float beta = 0.0f;
1762
- CUBLAS_CHECK(
1763
- cublasGemmEx(ctx.cublas_handle(id), CUBLAS_OP_T, CUBLAS_OP_N,
1764
- row_diff, src1_ncols, ne10,
1765
- &alpha, src0_ptr, CUDA_R_16F, ne00,
1766
- src1_ptr, CUDA_R_16F, ne10,
1767
- &beta, dst_dd_i, CUDA_R_32F, ldc,
1768
- CUBLAS_COMPUTE_32F,
1769
- CUBLAS_GEMM_DEFAULT_TENSOR_OP));
1770
- } else {
1771
- ggml_cuda_pool_alloc<half> dst_f16(ctx.pool(id), row_diff*src1_ncols);
1772
-
1773
- const half alpha_f16 = 1.0f;
1774
- const half beta_f16 = 0.0f;
1775
-
1776
- CUBLAS_CHECK(
1777
- cublasGemmEx(ctx.cublas_handle(id), CUBLAS_OP_T, CUBLAS_OP_N,
1778
- row_diff, src1_ncols, ne10,
1779
- &alpha_f16, src0_ptr, CUDA_R_16F, ne00,
1780
- src1_ptr, CUDA_R_16F, ne10,
1781
- &beta_f16, dst_f16.get(), CUDA_R_16F, ldc,
1782
- CUBLAS_COMPUTE_16F,
1783
- CUBLAS_GEMM_DEFAULT_TENSOR_OP));
1784
-
1785
- const to_fp32_cuda_t to_fp32_cuda = ggml_get_to_fp32_cuda(GGML_TYPE_F16);
1786
- to_fp32_cuda(dst_f16.get(), dst_dd_i, row_diff*src1_ncols, stream);
1787
- }
1788
- } else {
1789
- ggml_cuda_pool_alloc<float> src0_ddq_as_f32(ctx.pool(id));
1790
- ggml_cuda_pool_alloc<float> src1_ddq_as_f32(ctx.pool(id));
1791
-
1792
- if (src0->type != GGML_TYPE_F32) {
1793
- const to_fp32_cuda_t to_fp32_cuda = ggml_get_to_fp32_cuda(src0->type);
1794
- GGML_ASSERT(to_fp32_cuda != nullptr);
1795
- src0_ddq_as_f32.alloc(row_diff*ne00);
1796
- to_fp32_cuda(src0_dd_i, src0_ddq_as_f32.get(), row_diff*ne00, stream);
1797
- }
1798
- if (src1->type != GGML_TYPE_F32) {
1799
- const to_fp32_cuda_t to_fp32_cuda = ggml_get_to_fp32_cuda(src1->type);
1800
- GGML_ASSERT(to_fp32_cuda != nullptr);
1801
- src1_ddq_as_f32.alloc(src1_ncols*ne10);
1802
- to_fp32_cuda(src1_ddf_i, src1_ddq_as_f32.get(), src1_ncols*ne10, stream);
1803
- }
1804
-
1805
- const float * src0_ddf_i = src0->type == GGML_TYPE_F32 ? (const float *) src0_dd_i : src0_ddq_as_f32.get();
1806
- const float * src1_ddf1_i = src1->type == GGML_TYPE_F32 ? (const float *) src1_ddf_i : src1_ddq_as_f32.get();
1807
-
1808
- const float alpha = 1.0f;
1809
- const float beta = 0.0f;
1810
-
1811
- CUBLAS_CHECK(cublasSetStream(ctx.cublas_handle(id), stream));
1812
- CUBLAS_CHECK(
1813
- cublasSgemm(ctx.cublas_handle(id), CUBLAS_OP_T, CUBLAS_OP_N,
1814
- row_diff, src1_ncols, ne10,
1815
- &alpha, src0_ddf_i, ne00,
1816
- src1_ddf1_i, ne10,
1817
- &beta, dst_dd_i, ldc));
1818
- }
1819
-
1820
- GGML_UNUSED_VARS(dst, src1_ddq_i, src1_padded_row_size);
1821
- }
1822
-
1823
- static cudaError_t ggml_cuda_Memcpy2DPeerAsync(
1824
- void * dst, int dstDevice, size_t dpitch, void * src, int srcDevice, size_t spitch, size_t width, size_t height, cudaStream_t stream) {
1825
-
1826
- #if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
1827
- // cudaMemcpy2DAsync may fail with copies between vmm pools of different devices
1828
- cudaMemcpy3DPeerParms p = {};
1829
- p.dstDevice = dstDevice;
1830
- p.dstPtr = make_cudaPitchedPtr(dst, dpitch, dpitch, height);
1831
- p.srcDevice = srcDevice;
1832
- p.srcPtr = make_cudaPitchedPtr(src, spitch, spitch, height);
1833
- p.extent = make_cudaExtent(width, height, 1);
1834
- return cudaMemcpy3DPeerAsync(&p, stream);
1835
- #else
1836
- // HIP does not support cudaMemcpy3DPeerAsync or vmm pools
1837
- GGML_UNUSED(dstDevice);
1838
- GGML_UNUSED(srcDevice);
1839
- return cudaMemcpy2DAsync(dst, dpitch, src, spitch, width, height, cudaMemcpyDeviceToDevice, stream);
1840
- #endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
1841
- }
1842
-
1843
- static void ggml_cuda_op_mul_mat(
1844
- ggml_backend_cuda_context & ctx,
1845
- const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst, ggml_cuda_op_mul_mat_t op,
1846
- quantize_cuda_t quantize_src1) {
1847
-
1848
- const int64_t ne00 = src0->ne[0];
1849
- const int64_t ne01 = src0->ne[1];
1850
- const int64_t ne02 = src0->ne[2];
1851
- const int64_t ne03 = src0->ne[3];
1852
-
1853
- const int64_t ne10 = src1->ne[0];
1854
- const int64_t ne11 = src1->ne[1];
1855
- const int64_t ne12 = src1->ne[2];
1856
- const int64_t ne13 = src1->ne[3];
1857
- const int64_t nrows1 = ggml_nrows(src1);
1858
-
1859
- const int64_t ne0 = dst->ne[0];
1860
- const int64_t ne1 = dst->ne[1];
1861
-
1862
- // const int64_t nb10 = src1->nb[0];
1863
- const int64_t nb11 = src1->nb[1];
1864
- const int64_t nb12 = src1->nb[2];
1865
- const int64_t nb13 = src1->nb[3];
1866
-
1867
- const int64_t nb2 = dst->nb[2];
1868
- const int64_t nb3 = dst->nb[3];
1869
-
1870
- ggml_backend_cuda_buffer_context * src1_ctx = (ggml_backend_cuda_buffer_context *) src1->buffer->context;
1871
- ggml_backend_cuda_buffer_context * dst_ctx = (ggml_backend_cuda_buffer_context *) dst->buffer->context;
1872
-
1873
- GGML_ASSERT(src1->type == GGML_TYPE_F32 || (src1->ne[2] == 1 && src1->ne[3] == 1));
1874
-
1875
- GGML_ASSERT(ne12 % ne02 == 0);
1876
- GGML_ASSERT(ne13 % ne03 == 0);
1877
-
1878
- const int64_t i02_divisor = ne12 / ne02;
1879
- const int64_t i03_divisor = ne13 / ne03;
1880
-
1881
- const size_t src0_ts = ggml_type_size(src0->type);
1882
- const size_t src0_bs = ggml_blck_size(src0->type);
1883
- const size_t q8_1_ts = sizeof(block_q8_1);
1884
- const size_t q8_1_bs = QK8_1;
1885
-
1886
- const bool src0_is_contiguous = ggml_is_contiguous(src0);
1887
- const bool src1_is_contiguous = ggml_is_contiguous(src1);
1888
-
1889
- const int64_t src1_padded_col_size = GGML_PAD(ne10, MATRIX_ROW_PADDING);
1890
-
1891
- const bool split = ggml_backend_buft_is_cuda_split(src0->buffer->buft);
1892
- GGML_ASSERT(!(split && ne02 > 1));
1893
- GGML_ASSERT(!(split && ne03 > 1));
1894
- GGML_ASSERT(!(split && ne02 < ne12));
1895
- GGML_ASSERT(!(split && ne03 < ne13));
1896
-
1897
- ggml_tensor_extra_gpu * src0_extra = split ? (ggml_tensor_extra_gpu *) src0->extra : nullptr;
1898
-
1899
-
1900
- std::array<float, GGML_CUDA_MAX_DEVICES> tensor_split;
1901
- if (split) {
1902
- ggml_backend_cuda_split_buffer_type_context * buft_ctx = (ggml_backend_cuda_split_buffer_type_context *) src0->buffer->buft->context;
1903
- tensor_split = buft_ctx->tensor_split;
1904
- }
1905
-
1906
- struct dev_data {
1907
- int cc;
1908
-
1909
- ggml_cuda_pool_alloc<char> src0_dd_alloc;
1910
- ggml_cuda_pool_alloc<float> src1_ddf_alloc;
1911
- ggml_cuda_pool_alloc<char> src1_ddq_alloc;
1912
- ggml_cuda_pool_alloc<float> dst_dd_alloc;
1913
-
1914
- char * src0_dd = nullptr;
1915
- float * src1_ddf = nullptr; // float
1916
- char * src1_ddq = nullptr; // q8_1
1917
- float * dst_dd = nullptr;
1918
-
1919
- int64_t row_low;
1920
- int64_t row_high;
1921
- };
1922
-
1923
- dev_data dev[GGML_CUDA_MAX_DEVICES];
1924
-
1925
- int used_devices = 0;
1926
-
1927
- for (int id = 0; id < ggml_backend_cuda_get_device_count(); ++id) {
1928
- dev[id].cc = ggml_cuda_info().devices[id].cc;
1929
-
1930
- // by default, use all rows
1931
- dev[id].row_low = 0;
1932
- dev[id].row_high = ne01;
1933
-
1934
- // for multi GPU, get the row boundaries from tensor split
1935
- // and round to mul_mat_q tile sizes
1936
- if (split) {
1937
- const int64_t rounding = get_row_rounding(tensor_split);
1938
-
1939
- if (id != 0) {
1940
- dev[id].row_low = ne01*tensor_split[id];
1941
- if (dev[id].row_low < ne01) {
1942
- dev[id].row_low -= dev[id].row_low % rounding;
1943
- }
1944
- }
1945
-
1946
- if (id != ggml_backend_cuda_get_device_count() - 1) {
1947
- dev[id].row_high = ne01*tensor_split[id + 1];
1948
- if (dev[id].row_high < ne01) {
1949
- dev[id].row_high -= dev[id].row_high % rounding;
1950
- }
1951
- }
1952
- }
1953
- }
1954
-
1955
- for (int id = 0; id < ggml_backend_cuda_get_device_count(); ++id) {
1956
- if ((!split && id != ctx.device) || dev[id].row_low == dev[id].row_high) {
1957
- continue;
1958
- }
1959
-
1960
- used_devices++;
1961
-
1962
- const bool src1_on_device = id == src1_ctx->device;
1963
- const bool dst_on_device = id == dst_ctx->device;
1964
-
1965
- ggml_cuda_set_device(id);
1966
- cudaStream_t stream = ctx.stream(id, 0);
1967
-
1968
- if (src0_is_contiguous) {
1969
- dev[id].src0_dd = split ? (char *) src0_extra->data_device[id] : (char *) src0->data;
1970
- } else {
1971
- // If src0 is not contiguous it will be copied to a temporary buffer.
1972
- // This buffer needs to be cleared entirely because multiple regions will function as padding.
1973
- const size_t nbytes_data = ggml_nbytes(src0);
1974
- const size_t nbytes_padding = ggml_row_size(src0->type, MATRIX_ROW_PADDING - ne00 % MATRIX_ROW_PADDING);
1975
- dev[id].src0_dd = dev[id].src0_dd_alloc.alloc(ctx.pool(id), nbytes_data + nbytes_padding);
1976
- CUDA_CHECK(cudaMemsetAsync(dev[id].src0_dd, 0, nbytes_data + nbytes_padding, stream));
1977
- }
1978
-
1979
- // If src0 is on a temporary compute buffer (partial offloading) there may be some padding that needs to be cleared:
1980
- if (ne00 % MATRIX_ROW_PADDING != 0 && ggml_is_quantized(src0->type) && ggml_backend_buffer_get_usage(src0->buffer) == GGML_BACKEND_BUFFER_USAGE_COMPUTE && src0->view_src == nullptr) {
1981
- GGML_ASSERT(ggml_is_contiguously_allocated(src0));
1982
- GGML_ASSERT(!src0->view_src);
1983
- const size_t nbytes_data = ggml_row_size(src0->type, (dev[id].row_high - dev[id].row_low)*ne00);
1984
- const size_t nbytes_padding = ggml_row_size(src0->type, MATRIX_ROW_PADDING - ne00 % MATRIX_ROW_PADDING);
1985
- CUDA_CHECK(cudaMemsetAsync(dev[id].src0_dd + nbytes_data, 0, nbytes_padding, stream));
1986
- }
1987
-
1988
- if (src1_on_device && src1_is_contiguous) {
1989
- dev[id].src1_ddf = (float *) src1->data;
1990
- } else {
1991
- dev[id].src1_ddf = dev[id].src1_ddf_alloc.alloc(ctx.pool(id), ggml_nelements(src1));
1992
- }
1993
-
1994
- if (quantize_src1) {
1995
- size_t src_1_ddq_size = nrows1*src1_padded_col_size*q8_1_ts/q8_1_bs;
1996
- if (quantize_src1 == quantize_mmq_q8_1_cuda) {
1997
- src_1_ddq_size += get_mmq_x_max_host(dev[id].cc)*sizeof(block_q8_1_mmq);
1998
- }
1999
- dev[id].src1_ddq = dev[id].src1_ddq_alloc.alloc(ctx.pool(id), src_1_ddq_size);
2000
-
2001
- if (src1_on_device && src1_is_contiguous) {
2002
- quantize_src1(
2003
- dev[id].src1_ddf, nullptr, dev[id].src1_ddq, src0->type, ne10,
2004
- nb11/sizeof(float), nb12/sizeof(float), nb13/sizeof(float),
2005
- src1_padded_col_size, ne11, ne12, ne13, stream);
2006
- CUDA_CHECK(cudaGetLastError());
2007
- }
2008
- }
2009
-
2010
- if (dst_on_device) {
2011
- dev[id].dst_dd = (float *) dst->data;
2012
- } else {
2013
- const size_t size_dst_ddf = split ? (dev[id].row_high - dev[id].row_low)*ne1 : ggml_nelements(dst);
2014
- dev[id].dst_dd = dev[id].dst_dd_alloc.alloc(ctx.pool(id), size_dst_ddf);
2015
- }
2016
- }
2017
-
2018
- // if multiple devices are used they need to wait for the main device
2019
- // here an event is recorded that signals that the main device has finished calculating the input data
2020
- if (split && used_devices > 1) {
2021
- ggml_cuda_set_device(ctx.device);
2022
- CUDA_CHECK(cudaEventRecord(src0_extra->events[ctx.device][0], ctx.stream()));
2023
- }
2024
-
2025
- const int64_t src1_col_stride = split && used_devices > 1 ? MUL_MAT_SRC1_COL_STRIDE : ne11;
2026
- for (int64_t src1_col_0 = 0; src1_col_0 < ne11; src1_col_0 += src1_col_stride) {
2027
- const int64_t is = split ? (src1_col_0/src1_col_stride) % GGML_CUDA_MAX_STREAMS : 0;
2028
- const int64_t src1_ncols = src1_col_0 + src1_col_stride > ne11 ? ne11 - src1_col_0 : src1_col_stride;
2029
-
2030
- for (int id = 0; id < ggml_backend_cuda_get_device_count(); ++id) {
2031
- if ((!split && id != ctx.device) || dev[id].row_low == dev[id].row_high) {
2032
- continue;
2033
- }
2034
-
2035
- const bool src1_on_device = id == src1_ctx->device;
2036
- const bool dst_on_device = id == dst_ctx->device;
2037
- const int64_t row_diff = dev[id].row_high - dev[id].row_low;
2038
-
2039
- ggml_cuda_set_device(id);
2040
- cudaStream_t stream = ctx.stream(id, is);
2041
-
2042
- // wait for main GPU data if necessary
2043
- if (split && (id != ctx.device || is != 0)) {
2044
- CUDA_CHECK(cudaStreamWaitEvent(stream, src0_extra->events[ctx.device][0], 0));
2045
- }
2046
-
2047
- for (int64_t i0 = 0; i0 < ne13*ne12; ++i0) {
2048
- const int64_t i03 = i0 / ne12;
2049
- const int64_t i02 = i0 % ne12;
2050
-
2051
- size_t src1_ddq_i_offset = i0*ne11 * src1_padded_col_size*q8_1_ts/q8_1_bs;
2052
- if (quantize_src1 == quantize_mmq_q8_1_cuda) {
2053
- src1_ddq_i_offset += src1_col_0 * sizeof(block_q8_1_mmq);
2054
- } else {
2055
- src1_ddq_i_offset += src1_col_0 * src1_padded_col_size*q8_1_ts/q8_1_bs;
2056
- }
2057
-
2058
- // for split tensors the data begins at i0 == i0_offset_low
2059
- const size_t nbytes_src0_matrix = ne01*ne00*src0_ts / src0_bs;
2060
- char * src0_dd_i = dev[id].src0_dd + ((i03/i03_divisor)*ne02 + (i02/i02_divisor)) * nbytes_src0_matrix;
2061
- float * src1_ddf_i = dev[id].src1_ddf + (i0*ne11 + src1_col_0) * ne10;
2062
- char * src1_ddq_i = dev[id].src1_ddq + src1_ddq_i_offset;
2063
- float * dst_dd_i = dev[id].dst_dd + (i0*ne1 + src1_col_0) * (dst_on_device ? ne0 : row_diff);
2064
-
2065
- // the main device memory buffer can be on VRAM scratch, with space for all partial results
2066
- // in that case an offset on dst_ddf_i is needed
2067
- if (id == ctx.device) {
2068
- dst_dd_i += dev[id].row_low; // offset is 0 if no tensor split
2069
- }
2070
-
2071
- // copy src0, src1 to device if necessary
2072
- if (src1_is_contiguous) {
2073
- if (id != ctx.device) {
2074
- if (quantize_src1) {
2075
- char * src1_ddq_i_source = dev[ctx.device].src1_ddq + src1_ddq_i_offset;
2076
- if (quantize_src1 == quantize_mmq_q8_1_cuda) {
2077
- const size_t pitch = ne11*sizeof(block_q8_1_mmq);
2078
- const size_t width = src1_ncols*sizeof(block_q8_1_mmq);
2079
- const size_t height = src1_padded_col_size/(4*QK8_1);
2080
- CUDA_CHECK(ggml_cuda_Memcpy2DPeerAsync(src1_ddq_i, id, pitch, src1_ddq_i_source, ctx.device, pitch, width, height, stream));
2081
- } else {
2082
- CUDA_CHECK(cudaMemcpyPeerAsync(
2083
- src1_ddq_i, id, src1_ddq_i_source, ctx.device, src1_ncols*src1_padded_col_size*q8_1_ts/q8_1_bs, stream));
2084
- }
2085
- } else {
2086
- float * src1_ddf_i_source = (float *) src1->data;
2087
- src1_ddf_i_source += (i0*ne11 + src1_col_0) * ne10;
2088
- CUDA_CHECK(cudaMemcpyPeerAsync(src1_ddf_i, id, src1_ddf_i_source, ctx.device,
2089
- src1_ncols*ne10*sizeof(float), stream));
2090
- }
2091
- }
2092
- } else if (src1_on_device && !src1_is_contiguous) {
2093
- CUDA_CHECK(ggml_cuda_cpy_tensor_2d(
2094
- src1_ddf_i, src1, i03, i02, src1_col_0, src1_col_0+src1_ncols, stream));
2095
- } else {
2096
- GGML_ABORT("fatal error");
2097
- }
2098
-
2099
- if (quantize_src1 && !src1_is_contiguous) {
2100
- quantize_src1(
2101
- src1_ddf_i, nullptr, src1_ddq_i, src0->type, ne10, ne10, ne11*ne10, ne12*ne11*ne10,
2102
- src1_padded_col_size, src1_ncols, 1, 1, stream);
2103
- CUDA_CHECK(cudaGetLastError());
2104
- }
2105
-
2106
- if (src1_col_0 == 0 && !src0_is_contiguous && i03 % i03_divisor == 0 && i02 % i02_divisor == 0) {
2107
- CUDA_CHECK(ggml_cuda_cpy_tensor_2d(
2108
- src0_dd_i, src0, i03/i03_divisor, i02/i02_divisor, dev[id].row_low, dev[id].row_high, stream));
2109
- }
2110
-
2111
- // do the computation
2112
- op(ctx, src0, src1, dst, src0_dd_i, src1_ddf_i, src1_ddq_i, dst_dd_i,
2113
- dev[id].row_low, dev[id].row_high, src1_ncols, src1_padded_col_size, stream);
2114
- CUDA_CHECK(cudaGetLastError());
2115
-
2116
- // copy dst to host or other device if necessary
2117
- if (!dst_on_device) {
2118
- void * dst_off_device = dst->data;
2119
- if (split) {
2120
- // src0 = weight matrix is saved as a transposed matrix for better memory layout.
2121
- // dst is NOT transposed.
2122
- // The outputs of matrix matrix multiplications can therefore NOT simply be concatenated for >1 GPU.
2123
- // Instead they need to be copied to the correct slice in ne0 = dst row index.
2124
- // If dst is a vector with ne0 == 1 then you don't have to do this but it still produces correct results.
2125
- float * dhf_dst_i = (float *) ((char *) dst_off_device + i02*nb2 + i03*nb3);
2126
- GGML_ASSERT(dst->nb[1] == ne0*sizeof(float));
2127
- dhf_dst_i += src1_col_0*ne0 + dev[id].row_low;
2128
- CUDA_CHECK(ggml_cuda_Memcpy2DPeerAsync(
2129
- dhf_dst_i, ctx.device, ne0*sizeof(float), dst_dd_i, id, row_diff*sizeof(float), row_diff*sizeof(float), src1_ncols, stream));
2130
- } else {
2131
- float * dhf_dst_i = (float *) ((char *) dst_off_device + i02*nb2 + i03*nb3);
2132
- GGML_ASSERT(dst->nb[1] == ne0*sizeof(float));
2133
- dhf_dst_i += src1_col_0*ne0;
2134
- CUDA_CHECK(cudaMemcpyAsync(dhf_dst_i, dst_dd_i, src1_ncols*ne0*sizeof(float), cudaMemcpyDeviceToDevice, stream));
2135
- }
2136
- }
2137
-
2138
- // add event for the main device to wait on until other device is done
2139
- if (split && (id != ctx.device || is != 0)) {
2140
- CUDA_CHECK(cudaEventRecord(src0_extra->events[id][is], stream));
2141
- }
2142
- }
2143
- }
2144
- }
2145
-
2146
- // main device waits for all other devices to be finished
2147
- if (split && ggml_backend_cuda_get_device_count() > 1) {
2148
- int64_t is_max = (ne11 + MUL_MAT_SRC1_COL_STRIDE - 1) / MUL_MAT_SRC1_COL_STRIDE;
2149
- is_max = is_max <= GGML_CUDA_MAX_STREAMS ? is_max : GGML_CUDA_MAX_STREAMS;
2150
-
2151
- ggml_cuda_set_device(ctx.device);
2152
- for (int id = 0; id < ggml_backend_cuda_get_device_count(); ++id) {
2153
- if (dev[id].row_low == dev[id].row_high) {
2154
- continue;
2155
- }
2156
- for (int64_t is = 0; is < is_max; ++is) {
2157
- CUDA_CHECK(cudaStreamWaitEvent(ctx.stream(), src0_extra->events[id][is], 0));
2158
- }
2159
- }
2160
- }
2161
- }
2162
-
2163
1254
  static __global__ void k_compute_batched_ptrs(
2164
1255
  const void * src0_as_f16, const void * src1_as_f16, char * dst,
2165
1256
  const void ** ptrs_src, void ** ptrs_dst,
@@ -2198,7 +1289,8 @@ struct batched_mul_mat_traits<GGML_TYPE_F32> {
2198
1289
  static inline const float beta = 0.0f;
2199
1290
  static inline const void* get_alpha() { static const float val = alpha; return &val; }
2200
1291
  static inline const void* get_beta() { static const float val = beta; return &val; }
2201
- static inline auto get_nc_converter(ggml_type src_type) { return ggml_get_to_fp32_nc_cuda(src_type); }
1292
+ static inline auto convert(ggml_type src_type) { return ggml_get_to_fp32_cuda(src_type); }
1293
+ static inline auto convert_nc(ggml_type src_type) { return ggml_get_to_fp32_nc_cuda(src_type); }
2202
1294
  };
2203
1295
 
2204
1296
  template<>
@@ -2211,7 +1303,8 @@ struct batched_mul_mat_traits<GGML_TYPE_BF16> {
2211
1303
  static inline const float beta = 0.0f;
2212
1304
  static inline const void* get_alpha() { static const float val = alpha; return &val; }
2213
1305
  static inline const void* get_beta() { static const float val = beta; return &val; }
2214
- static inline auto get_nc_converter(ggml_type src_type) { return ggml_get_to_bf16_nc_cuda(src_type); }
1306
+ static inline auto convert(ggml_type src_type) { return ggml_get_to_bf16_cuda(src_type); }
1307
+ static inline auto convert_nc(ggml_type src_type) { return ggml_get_to_bf16_nc_cuda(src_type); }
2215
1308
  };
2216
1309
 
2217
1310
  template<>
@@ -2224,18 +1317,15 @@ struct batched_mul_mat_traits<GGML_TYPE_F16> {
2224
1317
  static inline const half beta = 0.0;
2225
1318
  static inline const void* get_alpha() { static const half val = alpha; return &val; }
2226
1319
  static inline const void* get_beta() { static const half val = beta; return &val; }
2227
- static inline auto get_nc_converter(ggml_type src_type) { return ggml_get_to_fp16_nc_cuda(src_type); }
1320
+ static inline auto convert(ggml_type src_type) { return ggml_get_to_fp16_cuda(src_type); }
1321
+ static inline auto convert_nc(ggml_type src_type) { return ggml_get_to_fp16_nc_cuda(src_type); }
2228
1322
  };
2229
1323
 
2230
- template<ggml_type src0_type>
2231
- static void ggml_cuda_mul_mat_batched_cublas_impl(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) {
2232
- using traits = batched_mul_mat_traits<src0_type>;
1324
+ template<ggml_type compute_type>
1325
+ static void ggml_cuda_mul_mat_cublas_impl(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) {
1326
+ using traits = batched_mul_mat_traits<compute_type>;
2233
1327
  using cuda_t = typename traits::cuda_type;
2234
1328
 
2235
- GGML_ASSERT(!ggml_is_transposed(src0));
2236
- GGML_ASSERT(!ggml_is_transposed(src1));
2237
- GGML_ASSERT(!ggml_backend_buft_is_cuda_split(src0->buffer->buft));
2238
- GGML_ASSERT(src0->type == src0_type);
2239
1329
  GGML_ASSERT(ggml_is_contiguous(dst));
2240
1330
 
2241
1331
  // Byte offsets and tensor dimensions are currently used in an inconsistent way for dst.
@@ -2247,12 +1337,19 @@ static void ggml_cuda_mul_mat_batched_cublas_impl(ggml_backend_cuda_context & ct
2247
1337
  cudaStream_t main_stream = ctx.stream();
2248
1338
  CUBLAS_CHECK(cublasSetStream(ctx.cublas_handle(), main_stream));
2249
1339
 
1340
+ const size_t src0_ts = ggml_type_size(src0->type);
1341
+ GGML_ASSERT(nb00 == src0_ts);
1342
+ int64_t s01 = nb01 / src0_ts;
1343
+ int64_t s02 = nb02 / src0_ts;
1344
+ int64_t s03 = nb03 / src0_ts;
1345
+
1346
+ const size_t src1_ts = ggml_type_size(src1->type);
1347
+ GGML_ASSERT(nb10 == src1_ts);
1348
+ int64_t s11 = nb11 / src1_ts;
1349
+ int64_t s12 = nb12 / src1_ts;
1350
+ int64_t s13 = nb13 / src1_ts;
1351
+
2250
1352
  float * dst_ddf = (float *) dst->data;
2251
- const size_t ts_src1 = ggml_type_size(src1->type);
2252
- GGML_ASSERT(nb10 == ts_src1);
2253
- int64_t s11 = nb11 / ts_src1;
2254
- int64_t s12 = nb12 / ts_src1;
2255
- int64_t s13 = nb13 / ts_src1;
2256
1353
 
2257
1354
  const cuda_t * src0_ptr = nullptr;
2258
1355
  const cuda_t * src1_ptr = nullptr;
@@ -2263,31 +1360,58 @@ static void ggml_cuda_mul_mat_batched_cublas_impl(ggml_backend_cuda_context & ct
2263
1360
  bool is_src0_cont_2 = ggml_is_contiguous_2(src0);
2264
1361
  bool is_src1_cont_2 = ggml_is_contiguous_2(src1);
2265
1362
 
2266
- // Handle src0
2267
- src0_ptr = (const cuda_t *) src0->data;
1363
+ if (src0->type == compute_type) {
1364
+ src0_ptr = (const cuda_t *) src0->data;
1365
+ } else {
1366
+ src0_alloc.alloc(ggml_nelements(src0));
1367
+
1368
+ if (ggml_is_contiguously_allocated(src0)) {
1369
+ const auto convert_func = traits::convert(src0->type);
1370
+ GGML_ASSERT(convert_func != nullptr);
1371
+ convert_func(src0->data, src0_alloc.get(), ggml_nelements(src0), main_stream);
1372
+ const size_t src0_bs = ggml_blck_size(src0->type);
1373
+ s01 *= src0_bs;
1374
+ s02 *= src0_bs;
1375
+ s03 *= src0_bs;
1376
+ } else {
1377
+ const auto convert_func = traits::convert_nc(src0->type);
1378
+ GGML_ASSERT(convert_func != nullptr);
1379
+ convert_func(src0->data, src0_alloc.get(), ne00, ne01, ne02, ne03, s01, s02, s03, main_stream);
1380
+ s01 = ne00;
1381
+ s02 = ne01*s01;
1382
+ s03 = ne02*s02;
1383
+ is_src0_cont_2 = true;
1384
+ }
1385
+ src0_ptr = src0_alloc.get();
1386
+ }
2268
1387
 
2269
- // Handle src1 - convert if necessary
2270
- if (src1->type == src0_type) {
1388
+ if (src1->type == compute_type) {
2271
1389
  src1_ptr = (const cuda_t *) src1->data;
2272
1390
  } else {
2273
- // Convert src1 to target type using traits conversion functions
2274
- const int64_t ne_src1 = ggml_nelements(src1);
2275
- src1_alloc.alloc(ne_src1);
2276
-
2277
- const auto convert_func = traits::get_nc_converter(src1->type);
2278
- GGML_ASSERT(convert_func != nullptr);
2279
- convert_func(src1->data, src1_alloc.get(), ne10, ne11, ne12, ne13, s11, s12, s13, main_stream);
1391
+ src1_alloc.alloc(ggml_nelements(src1));
1392
+
1393
+ if (ggml_is_contiguously_allocated(src1)) {
1394
+ const auto convert_func = traits::convert(src1->type);
1395
+ GGML_ASSERT(convert_func != nullptr);
1396
+ convert_func(src1->data, src1_alloc.get(), ggml_nelements(src1), main_stream);
1397
+ const size_t src1_bs = ggml_blck_size(src1->type);
1398
+ s11 *= src1_bs;
1399
+ s12 *= src1_bs;
1400
+ s13 *= src1_bs;
1401
+ } else {
1402
+ const auto convert_func = traits::convert_nc(src1->type);
1403
+ GGML_ASSERT(convert_func != nullptr);
1404
+ convert_func(src1->data, src1_alloc.get(), ne10, ne11, ne12, ne13, s11, s12, s13, main_stream);
1405
+ s11 = ne10;
1406
+ s12 = ne11*s11;
1407
+ s13 = ne12*s12;
1408
+ is_src1_cont_2 = true;
1409
+ }
2280
1410
  src1_ptr = src1_alloc.get();
2281
- s11 = ne10;
2282
- s12 = ne11*s11;
2283
- s13 = ne12*s12;
2284
-
2285
- is_src1_cont_2 = true;
2286
1411
  }
2287
1412
 
2288
- // Setup destination buffer
2289
1413
  ggml_cuda_pool_alloc<cuda_t> dst_temp(ctx.pool());
2290
- char * dst_t;
1414
+ char * dst_ptr;
2291
1415
  size_t nbd2 = dst->nb[2];
2292
1416
  size_t nbd3 = dst->nb[3];
2293
1417
 
@@ -2298,35 +1422,28 @@ static void ggml_cuda_mul_mat_batched_cublas_impl(ggml_backend_cuda_context & ct
2298
1422
  const void * alpha = traits::get_alpha();
2299
1423
  const void * beta = traits::get_beta();
2300
1424
 
2301
- const auto & force_compute_type = ggml_cuda_cublas_get_force_compute_type();
2302
-
2303
- int id = ggml_cuda_get_device();
2304
- const int cc = ggml_cuda_info().devices[id].cc;
2305
- static constexpr bool is_src0_type_f16 = src0_type == GGML_TYPE_F16;
2306
-
2307
- // bf16 and fp32 are already being computed in fp32 (ensure it using static_assert),
2308
- // so checking necessity of forced fp32 only for fp16 src0_type
2309
- static_assert(is_src0_type_f16 || traits::compute_type == CUBLAS_COMPUTE_32F);
2310
-
2311
- const bool need_compute_32f = is_src0_type_f16 && !force_compute_type.fp16 && (GGML_CUDA_CC_IS_CDNA(cc)
2312
- || GGML_CUDA_CC_IS_RDNA4(cc)
2313
- || cc == GGML_CUDA_CC_VOLTA
2314
- || force_compute_type.fp32);
1425
+ const int cc = ggml_cuda_info().devices[ctx.device].cc;
1426
+ bool prefer_f32_output = false;
1427
+ if (compute_type == GGML_TYPE_F16) {
1428
+ prefer_f32_output = cc == GGML_CUDA_CC_VOLTA || GGML_CUDA_CC_IS_RDNA4(cc) || GGML_CUDA_CC_IS_CDNA(cc);
1429
+ } else if (compute_type == GGML_TYPE_BF16) {
1430
+ prefer_f32_output = !GGML_CUDA_CC_IS_RDNA3(cc) && !GGML_CUDA_CC_IS_CDNA(cc);
1431
+ }
2315
1432
 
2316
- if (dst->op_params[0] == GGML_PREC_DEFAULT && !need_compute_32f) {
2317
- if constexpr (src0_type == GGML_TYPE_F32) {
2318
- dst_t = (char *) dst_ddf; // Direct F32 output
2319
- } else {
2320
- dst_t = (char *) dst_temp.alloc(ne_dst);
2321
- nbd2 /= sizeof(float) / sizeof(cuda_t);
2322
- nbd3 /= sizeof(float) / sizeof(cuda_t);
2323
- }
2324
- } else {
2325
- dst_t = (char *) dst_ddf;
1433
+ if (prefer_f32_output) {
1434
+ dst_ptr = (char *) dst_ddf;
2326
1435
  cu_compute_type = batched_mul_mat_traits<GGML_TYPE_F32>::compute_type;
2327
1436
  cu_data_type = batched_mul_mat_traits<GGML_TYPE_F32>::data_type;
2328
1437
  alpha = batched_mul_mat_traits<GGML_TYPE_F32>::get_alpha();
2329
1438
  beta = batched_mul_mat_traits<GGML_TYPE_F32>::get_beta();
1439
+ } else {
1440
+ if constexpr (compute_type == GGML_TYPE_F32) {
1441
+ dst_ptr = (char *) dst_ddf; // Direct F32 output
1442
+ } else {
1443
+ dst_ptr = (char *) dst_temp.alloc(ne_dst);
1444
+ nbd2 /= sizeof(float) / sizeof(cuda_t);
1445
+ nbd3 /= sizeof(float) / sizeof(cuda_t);
1446
+ }
2330
1447
  }
2331
1448
 
2332
1449
  GGML_ASSERT(ne12 % ne02 == 0);
@@ -2336,19 +1453,38 @@ static void ggml_cuda_mul_mat_batched_cublas_impl(ggml_backend_cuda_context & ct
2336
1453
  const int64_t r2 = ne12/ne02;
2337
1454
  const int64_t r3 = ne13/ne03;
2338
1455
 
2339
- if (r2 == 1 && r3 == 1 && is_src0_cont_2 && is_src1_cont_2) {
1456
+ // Theoretically cublasGemmStridedBatchedEx would always work, even for a single matrix.
1457
+ // However, for some old NVIDIA and AMD GPUs the strided/Ex GEMM is much slower,
1458
+ // probably because the internal kernel selection logic is suboptimal.
1459
+ if (compute_type == GGML_TYPE_F32 && ne12 == 1 && ne13 == 1) {
1460
+ CUBLAS_CHECK(
1461
+ cublasSgemm(ctx.cublas_handle(), CUBLAS_OP_T, CUBLAS_OP_N,
1462
+ ne01, ne11, ne10,
1463
+ (const float *) alpha, (const float *) src0_ptr, s01,
1464
+ (const float *) src1_ptr, s11,
1465
+ (const float *) beta, (float *) dst_ptr, ne0));
1466
+ } else if (ne12 == 1 && ne13 == 1) {
1467
+ CUBLAS_CHECK(
1468
+ cublasGemmEx(ctx.cublas_handle(), CUBLAS_OP_T, CUBLAS_OP_N,
1469
+ ne01, ne11, ne10,
1470
+ alpha, src0_ptr, cu_data_type_a, s01,
1471
+ src1_ptr, cu_data_type_b, s11,
1472
+ beta, dst_ptr, cu_data_type, ne0,
1473
+ cu_compute_type,
1474
+ CUBLAS_GEMM_DEFAULT_TENSOR_OP));
1475
+ } else if (r2 == 1 && r3 == 1 && is_src0_cont_2 && is_src1_cont_2) {
2340
1476
  // with a [0, 2, 1, 3] perm. and ne02==1 the matrix strides need to be determined from dim 3:
2341
- const int64_t sma = ne02 == 1 ? nb03/nb00 : nb02/nb00;
2342
- const int64_t smb = ne12 == 1 ? s13 : s12;
1477
+ const int64_t sma = ne02 == 1 ? s03 : s02;
1478
+ const int64_t smb = ne12 == 1 ? s13 : s12;
2343
1479
 
2344
1480
  // there is no broadcast and src0, src1 are contiguous across dims 2, 3
2345
1481
  // use cublasGemmStridedBatchedEx
2346
1482
  CUBLAS_CHECK(
2347
1483
  cublasGemmStridedBatchedEx(ctx.cublas_handle(), CUBLAS_OP_T, CUBLAS_OP_N,
2348
1484
  ne01, ne11, ne10,
2349
- alpha, src0_ptr, cu_data_type_a, nb01/nb00, sma, // strideA
2350
- src1_ptr, cu_data_type_b, s11, smb, // strideB
2351
- beta, dst_t, cu_data_type, ne0, ne1*ne0, // strideC
1485
+ alpha, src0_ptr, cu_data_type_a, s01, sma, // strideA
1486
+ src1_ptr, cu_data_type_b, s11, smb, // strideB
1487
+ beta, dst_ptr, cu_data_type, ne0, ne1*ne0, // strideC
2352
1488
  ne12*ne13,
2353
1489
  cu_compute_type,
2354
1490
  CUBLAS_GEMM_DEFAULT_TENSOR_OP));
@@ -2359,24 +1495,23 @@ static void ggml_cuda_mul_mat_batched_cublas_impl(ggml_backend_cuda_context & ct
2359
1495
  ggml_cuda_pool_alloc<const void *> ptrs_src(ctx.pool(), 2*ne23);
2360
1496
  ggml_cuda_pool_alloc< void *> ptrs_dst(ctx.pool(), 1*ne23);
2361
1497
 
2362
- size_t src1_stride_size = sizeof(cuda_t);
1498
+ const size_t src_type_size = sizeof(cuda_t);
2363
1499
 
2364
1500
  const int threads_x = 16;
2365
1501
  const int threads_y = 16;
2366
- dim3 block_dims(threads_x, threads_y);
1502
+ const dim3 block_dims(threads_x, threads_y);
2367
1503
 
2368
- dim3 grid_dims(
1504
+ const dim3 grid_dims(
2369
1505
  (ne13 + threads_x - 1) / threads_x,
2370
1506
  (ne12 + threads_y - 1) / threads_y
2371
1507
  );
2372
1508
  k_compute_batched_ptrs<<<grid_dims, block_dims, 0, main_stream>>>(
2373
- src0_ptr, src1_ptr, dst_t,
1509
+ src0_ptr, src1_ptr, dst_ptr,
2374
1510
  ptrs_src.get(), ptrs_dst.get(),
2375
1511
  ne12, ne13,
2376
1512
  ne23,
2377
- nb02, nb03,
2378
- (src1->type == src0_type) ? nb12 : s12*src1_stride_size,
2379
- (src1->type == src0_type) ? nb13 : s13*src1_stride_size,
1513
+ s02*src_type_size, s03*src_type_size,
1514
+ s12*src_type_size, s13*src_type_size,
2380
1515
  nbd2, nbd3,
2381
1516
  r2, r3);
2382
1517
 
@@ -2385,7 +1520,7 @@ static void ggml_cuda_mul_mat_batched_cublas_impl(ggml_backend_cuda_context & ct
2385
1520
  CUBLAS_CHECK(
2386
1521
  cublasGemmBatchedEx(ctx.cublas_handle(), CUBLAS_OP_T, CUBLAS_OP_N,
2387
1522
  ne01, ne11, ne10,
2388
- alpha, (const void **) (ptrs_src.get() + 0*ne23), cu_data_type_a, nb01/nb00,
1523
+ alpha, (const void **) (ptrs_src.get() + 0*ne23), cu_data_type_a, s01,
2389
1524
  (const void **) (ptrs_src.get() + 1*ne23), cu_data_type_b, s11,
2390
1525
  beta, ( void **) (ptrs_dst.get() + 0*ne23), cu_data_type, ne0,
2391
1526
  ne23,
@@ -2394,27 +1529,52 @@ static void ggml_cuda_mul_mat_batched_cublas_impl(ggml_backend_cuda_context & ct
2394
1529
  }
2395
1530
 
2396
1531
  // Convert output back to F32 if needed
2397
- if (dst->op_params[0] == GGML_PREC_DEFAULT && cu_data_type != CUDA_R_32F) {
1532
+ if (cu_data_type != CUDA_R_32F) {
2398
1533
  const to_fp32_cuda_t to_fp32_cuda = ggml_get_to_fp32_cuda(traits::ggml_type_val);
2399
1534
  to_fp32_cuda(dst_temp.get(), dst_ddf, ne_dst, main_stream);
2400
1535
  }
2401
1536
  }
2402
1537
 
2403
- static void ggml_cuda_mul_mat_batched_cublas(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) {
2404
- GGML_ASSERT(src0->type == GGML_TYPE_F16 || src0->type == GGML_TYPE_BF16 || src0->type == GGML_TYPE_F32);
1538
+ static void ggml_cuda_mul_mat_cublas(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) {
1539
+ ggml_type compute_type = src0->type;
1540
+ if (ggml_is_quantized(compute_type)) {
1541
+ compute_type = fast_fp16_hardware_available(ggml_cuda_info().devices[ctx.device].cc) ? GGML_TYPE_F16 : GGML_TYPE_F32;
1542
+ } else if (compute_type == GGML_TYPE_F16 && !fast_fp16_hardware_available(ggml_cuda_info().devices[ctx.device].cc)) {
1543
+ compute_type = GGML_TYPE_F32;
1544
+ }
1545
+ if (dst->op_params[0] == GGML_PREC_F32) {
1546
+ compute_type = GGML_TYPE_F32;
1547
+ }
1548
+
1549
+ const char * env_c = getenv("GGML_CUDA_CUBLAS_COMPUTE_TYPE");
1550
+ if (env_c != nullptr) {
1551
+ std::string env_cpp = env_c;
1552
+ for (char & c : env_cpp) {
1553
+ c = std::tolower(c);
1554
+ }
1555
+ if (env_cpp == "f32" || env_cpp == "fp32") {
1556
+ compute_type = GGML_TYPE_F32;
1557
+ } else if (env_cpp == "f16" || env_cpp == "fp16") {
1558
+ compute_type = GGML_TYPE_F16;
1559
+ } else if (env_cpp == "bf16") {
1560
+ compute_type = GGML_TYPE_BF16;
1561
+ } else if (env_cpp != "auto") {
1562
+ GGML_LOG_WARN("%s: unknown value for GGML_CUDA_CUBLAS_COMPUTE_TYPE: %s", __func__, env_cpp.c_str());
1563
+ }
1564
+ }
2405
1565
 
2406
- switch (src0->type) {
1566
+ switch (compute_type) {
2407
1567
  case GGML_TYPE_F32:
2408
- ggml_cuda_mul_mat_batched_cublas_impl<GGML_TYPE_F32>(ctx, src0, src1, dst);
1568
+ ggml_cuda_mul_mat_cublas_impl<GGML_TYPE_F32>(ctx, src0, src1, dst);
2409
1569
  break;
2410
1570
  case GGML_TYPE_BF16:
2411
- ggml_cuda_mul_mat_batched_cublas_impl<GGML_TYPE_BF16>(ctx, src0, src1, dst);
1571
+ ggml_cuda_mul_mat_cublas_impl<GGML_TYPE_BF16>(ctx, src0, src1, dst);
2412
1572
  break;
2413
1573
  case GGML_TYPE_F16:
2414
- ggml_cuda_mul_mat_batched_cublas_impl<GGML_TYPE_F16>(ctx, src0, src1, dst);
1574
+ ggml_cuda_mul_mat_cublas_impl<GGML_TYPE_F16>(ctx, src0, src1, dst);
2415
1575
  break;
2416
1576
  default:
2417
- GGML_ABORT("Unsupported type");
1577
+ GGML_ABORT("fatal error");
2418
1578
  }
2419
1579
  }
2420
1580
 
@@ -2422,12 +1582,18 @@ static bool ggml_cuda_should_fuse_mul_mat(const ggml_tensor * ffn_up,
2422
1582
  const ggml_tensor * ffn_gate,
2423
1583
  const ggml_tensor * glu,
2424
1584
  const ggml_tensor * ffn_up_bias = nullptr,
2425
- const ggml_tensor * ffn_gate_bias = nullptr) {
1585
+ const ggml_tensor * ffn_gate_bias = nullptr,
1586
+ const ggml_tensor * ffn_up_scale = nullptr,
1587
+ const ggml_tensor * ffn_gate_scale = nullptr) {
2426
1588
  const bool has_bias = ffn_up_bias != nullptr || ffn_gate_bias != nullptr;
1589
+ const bool has_scale = ffn_up_scale != nullptr || ffn_gate_scale != nullptr;
2427
1590
 
2428
1591
  if (has_bias && (!ffn_up_bias || !ffn_gate_bias)) {
2429
1592
  return false;
2430
1593
  }
1594
+ if (has_scale && (!ffn_up_scale || !ffn_gate_scale)) {
1595
+ return false;
1596
+ }
2431
1597
 
2432
1598
  const bool is_mul_mat = ffn_up->op == GGML_OP_MUL_MAT && ffn_gate->op == GGML_OP_MUL_MAT && glu->op == GGML_OP_GLU;
2433
1599
  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;
@@ -2439,34 +1605,45 @@ static bool ggml_cuda_should_fuse_mul_mat(const ggml_tensor * ffn_up,
2439
1605
  }
2440
1606
 
2441
1607
  const ggml_op expected_bias_op = is_mul_mat ? GGML_OP_ADD : GGML_OP_ADD_ID;
1608
+ const ggml_tensor * ffn_up_bias_src = has_scale ? ffn_up_scale : ffn_up;
1609
+ const ggml_tensor * ffn_gate_bias_src = has_scale ? ffn_gate_scale : ffn_gate;
1610
+ const ggml_tensor * ffn_up_out = has_bias ? ffn_up_bias : ffn_up_bias_src;
1611
+ const ggml_tensor * ffn_gate_out = has_bias ? ffn_gate_bias : ffn_gate_bias_src;
2442
1612
 
2443
- if (has_bias) {
2444
- if (ffn_up_bias->op != expected_bias_op || ffn_gate_bias->op != expected_bias_op) {
1613
+ if (glu->src[0] != ffn_gate_out || glu->src[1] != ffn_up_out) {
1614
+ return false;
1615
+ }
1616
+
1617
+ if (has_scale) {
1618
+ if (ffn_up_scale->op != GGML_OP_MUL || ffn_gate_scale->op != GGML_OP_MUL) {
2445
1619
  return false;
2446
1620
  }
1621
+ const bool up_has_mm = ffn_up_scale->src[0] == ffn_up || ffn_up_scale->src[1] == ffn_up;
1622
+ const bool gate_has_mm = ffn_gate_scale->src[0] == ffn_gate || ffn_gate_scale->src[1] == ffn_gate;
1623
+ if (!up_has_mm || !gate_has_mm) {
1624
+ return false;
1625
+ }
1626
+ }
2447
1627
 
2448
- if (glu->src[0] != ffn_gate_bias || glu->src[1] != ffn_up_bias) {
1628
+ if (has_bias) {
1629
+ if (ffn_up_bias->op != expected_bias_op || ffn_gate_bias->op != expected_bias_op) {
2449
1630
  return false;
2450
1631
  }
2451
1632
 
2452
1633
  if (expected_bias_op == GGML_OP_ADD) {
2453
- const bool up_has_mul = ffn_up_bias->src[0] == ffn_up || ffn_up_bias->src[1] == ffn_up;
2454
- const bool gate_has_mul = ffn_gate_bias->src[0] == ffn_gate || ffn_gate_bias->src[1] == ffn_gate;
1634
+ const bool up_has_mul = ffn_up_bias->src[0] == ffn_up_bias_src || ffn_up_bias->src[1] == ffn_up_bias_src;
1635
+ const bool gate_has_mul = ffn_gate_bias->src[0] == ffn_gate_bias_src || ffn_gate_bias->src[1] == ffn_gate_bias_src;
2455
1636
  if (!up_has_mul || !gate_has_mul) {
2456
1637
  return false;
2457
1638
  }
2458
1639
  } else { // GGML_OP_ADD_ID
2459
- if (ffn_up_bias->src[0] != ffn_up || ffn_gate_bias->src[0] != ffn_gate) {
1640
+ if (ffn_up_bias->src[0] != ffn_up_bias_src || ffn_gate_bias->src[0] != ffn_gate_bias_src) {
2460
1641
  return false;
2461
1642
  }
2462
1643
  if (ffn_up_bias->src[2] != ffn_up->src[2] || ffn_gate_bias->src[2] != ffn_gate->src[2]) {
2463
1644
  return false;
2464
1645
  }
2465
1646
  }
2466
- } else {
2467
- if (glu->src[0] != ffn_gate && glu->src[1] != ffn_up) {
2468
- return false;
2469
- }
2470
1647
  }
2471
1648
 
2472
1649
  if (ffn_up->src[0]->type != ffn_gate->src[0]->type || !ggml_are_same_shape(ffn_up->src[0], ffn_gate->src[0]) ||
@@ -2478,7 +1655,7 @@ static bool ggml_cuda_should_fuse_mul_mat(const ggml_tensor * ffn_up,
2478
1655
  return false;
2479
1656
  }
2480
1657
 
2481
- if (ffn_up->src[2] && (ffn_up->src[2] != ffn_gate->src[2])) {
1658
+ if (is_mul_mat_id && ffn_up->src[2] != ffn_gate->src[2]) {
2482
1659
  return false;
2483
1660
  }
2484
1661
 
@@ -2492,14 +1669,6 @@ static bool ggml_cuda_should_fuse_mul_mat(const ggml_tensor * ffn_up,
2492
1669
  return false;
2493
1670
  }
2494
1671
 
2495
- const bool split = ggml_backend_buft_is_cuda_split(ffn_up->src[0]->buffer->buft) ||
2496
- ggml_backend_buft_is_cuda_split(ffn_gate->src[0]->buffer->buft);
2497
-
2498
- //TODO: add support for fusion for split buffers
2499
- if (split) {
2500
- return false;
2501
- }
2502
-
2503
1672
  return true;
2504
1673
  }
2505
1674
 
@@ -2517,14 +1686,6 @@ static bool ggml_cuda_should_fuse_mul_mat_vec_f(const ggml_tensor * tensor) {
2517
1686
  const int cc = ggml_cuda_info().devices[ggml_cuda_get_device()].cc;
2518
1687
  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]);
2519
1688
 
2520
- const bool split = ggml_backend_buft_is_cuda_split(src0->buffer->buft) ||
2521
- ggml_backend_buft_is_cuda_split(src1->buffer->buft);
2522
-
2523
- //TODO: add support for fusion for split buffers
2524
- if (split) {
2525
- return false;
2526
- }
2527
-
2528
1689
  //we only support fusion for ncols_dst = 1
2529
1690
  if (tensor->op == GGML_OP_MUL_MAT && dst->ne[1] != 1) {
2530
1691
  return false;
@@ -2564,108 +1725,49 @@ static bool ggml_cuda_should_fuse_mul_mat_vec_q(const ggml_tensor * tensor) {
2564
1725
  return false;
2565
1726
  }
2566
1727
 
2567
-
2568
- const bool split = ggml_backend_buft_is_cuda_split(src0->buffer->buft) ||
2569
- ggml_backend_buft_is_cuda_split(src1->buffer->buft);
2570
-
2571
- //TODO: add support for fusion for split buffers
2572
- if (split) {
2573
- return false;
2574
- }
2575
-
2576
1728
  return use_mul_mat_vec_q;
2577
1729
  }
2578
1730
 
2579
1731
  static void ggml_cuda_mul_mat(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) {
2580
- const bool split = ggml_backend_buft_is_cuda_split(src0->buffer->buft);
1732
+ GGML_TENSOR_BINARY_OP_LOCALS
1733
+
1734
+ const int32_t hint = ggml_get_op_params_i32(dst, 1);
1735
+ if (hint == GGML_HINT_SRC0_IS_HADAMARD && ggml_cuda_op_fwht(ctx, src1, dst)) {
1736
+ return;
1737
+ }
2581
1738
 
2582
1739
  // 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.
2583
1740
  // But if src0 is also a view of another tensor then this cannot be done safely because it may overwrite valid tensor data.
2584
1741
  // Therefore, in such cases use cuBLAS.
2585
1742
  const bool bad_padding_clear = ggml_backend_buffer_get_usage(src0->buffer) == GGML_BACKEND_BUFFER_USAGE_COMPUTE
2586
1743
  && ggml_nbytes(src0) != ggml_backend_buffer_get_alloc_size(src0->buffer, src0) && src0->view_src;
2587
-
2588
- bool use_mul_mat_vec_f = (src0->type == GGML_TYPE_F32 || src0->type == GGML_TYPE_F16 || src0->type == GGML_TYPE_BF16)
2589
- && src1->type == GGML_TYPE_F32 && dst->type == GGML_TYPE_F32;
2590
- bool use_mul_mat_f = !ggml_is_quantized(src0->type)
2591
- && src1->type == GGML_TYPE_F32 && dst->type == GGML_TYPE_F32;
2592
- bool use_mul_mat_vec_q = ggml_is_quantized(src0->type) && !bad_padding_clear
2593
- && src1->type == GGML_TYPE_F32 && dst->type == GGML_TYPE_F32
2594
- && src1->ne[1] <= MMVQ_MAX_BATCH_SIZE;
2595
- bool use_mul_mat_q = ggml_is_quantized(src0->type) && !bad_padding_clear
2596
- && src1->type == GGML_TYPE_F32 && dst->type == GGML_TYPE_F32;
2597
-
2598
- bool any_gpus_with_slow_fp16 = false;
2599
-
2600
- if (split) {
2601
- ggml_backend_cuda_split_buffer_type_context * buft_ctx = (ggml_backend_cuda_split_buffer_type_context *) src0->buffer->buft->context;
2602
- auto & tensor_split = buft_ctx->tensor_split;
2603
- for (int id = 0; id < ggml_backend_cuda_get_device_count(); ++id) {
2604
- // skip devices that are not going to do any work:
2605
- if (tensor_split[id] >= (id + 1 < ggml_backend_cuda_get_device_count() ? tensor_split[id + 1] : 1.0f)) {
2606
- continue;
2607
- }
2608
-
2609
- const int cc = ggml_cuda_info().devices[id].cc;
2610
- const int warp_size = ggml_cuda_info().devices[id].warp_size;
2611
- use_mul_mat_q = use_mul_mat_q && ggml_cuda_should_use_mmq(src0->type, cc, src1->ne[1], /*n_experts=*/0);
2612
- use_mul_mat_f = use_mul_mat_f && ggml_cuda_should_use_mmf(src0->type, cc, warp_size, src0->ne, src0->nb, src1->ne[1], /*mul_mat_id=*/false);
2613
- use_mul_mat_vec_f = use_mul_mat_vec_f && ggml_cuda_should_use_mmvf(src0->type, cc, src0->ne, src0->nb, src1->ne[1]);
2614
- use_mul_mat_vec_q = use_mul_mat_vec_q && ggml_cuda_should_use_mmvq(src0->type, cc, src1->ne[1]);
2615
- any_gpus_with_slow_fp16 = any_gpus_with_slow_fp16 || !fast_fp16_hardware_available(cc);
2616
- }
2617
- } else {
2618
- const int cc = ggml_cuda_info().devices[ctx.device].cc;
2619
- const int warp_size = ggml_cuda_info().devices[ctx.device].warp_size;
2620
- use_mul_mat_q = use_mul_mat_q && ggml_cuda_should_use_mmq(src0->type, cc, src1->ne[1], /*n_experts=*/0);
2621
- use_mul_mat_f = use_mul_mat_f && ggml_cuda_should_use_mmf(src0->type, cc, warp_size, src0->ne, src0->nb, src1->ne[1], /*mul_mat_id=*/false);
2622
- use_mul_mat_vec_f = use_mul_mat_vec_f && ggml_cuda_should_use_mmvf(src0->type, cc, src0->ne, src0->nb, src1->ne[1]);
2623
- use_mul_mat_vec_q = use_mul_mat_vec_q && ggml_cuda_should_use_mmvq(src0->type, cc, src1->ne[1]);
2624
- any_gpus_with_slow_fp16 = any_gpus_with_slow_fp16 || !fast_fp16_hardware_available(cc);
2625
- }
2626
-
2627
- // debug helpers
2628
- //printf("src0: %8d %8d %8d %8d\n", src0->ne[0], src0->ne[1], src0->ne[2], src0->ne[3]);
2629
- //printf(" %8d %8d %8d %8d\n", src0->nb[0], src0->nb[1], src0->nb[2], src0->nb[3]);
2630
- //printf("src1: %8d %8d %8d %8d\n", src1->ne[0], src1->ne[1], src1->ne[2], src1->ne[3]);
2631
- //printf(" %8d %8d %8d %8d\n", src1->nb[0], src1->nb[1], src1->nb[2], src1->nb[3]);
2632
- //printf("src0 is contiguous %d, transposed %d, type = %s, name = %s\n", ggml_is_contiguous(src0), ggml_is_transposed(src0), ggml_type_name(src0->type), src0->name);
2633
- //printf("src1 is contiguous %d, transposed %d, type = %s, name = %s\n", ggml_is_contiguous(src1), ggml_is_transposed(src1), ggml_type_name(src1->type), src1->name);
2634
-
2635
- //TODO update for generic tensor parallelism
2636
- const int cc = ggml_cuda_info().devices[ggml_cuda_get_device()].cc;
2637
- bool use_batched_cublas_f16 = src0->type == GGML_TYPE_F16 && (src1->type == GGML_TYPE_F16 || !any_gpus_with_slow_fp16);
2638
- bool use_batched_cublas_bf16 = src0->type == GGML_TYPE_BF16 && bf16_mma_hardware_available(cc);
2639
- bool use_batched_cublas_f32 = src0->type == GGML_TYPE_F32;
2640
-
2641
- const int32_t hint = ggml_get_op_params_i32(dst, 1);
2642
- if (hint == GGML_HINT_SRC0_IS_HADAMARD && !split && ggml_cuda_op_fwht(ctx, src1, dst)) {
1744
+ if (bad_padding_clear || src1->type != GGML_TYPE_F32 || dst->type != GGML_TYPE_F32) {
1745
+ ggml_cuda_mul_mat_cublas(ctx, src0, src1, dst);
2643
1746
  return;
2644
1747
  }
2645
1748
 
2646
- if (!split && use_mul_mat_vec_f) {
2647
- // the custom F16 vector kernel can be used over batched cuBLAS GEMM
2648
- // but this is only faster for GPUs without tensor cores or with a thin src0 matrix (particularly KQV in attention)
1749
+ const int cc = ggml_cuda_info().devices[ctx.device].cc;
1750
+ const int warp_size = ggml_cuda_info().devices[ctx.device].warp_size;
1751
+
1752
+ if (ggml_cuda_should_use_mmvf(src0->type, cc, src0->ne, src0->nb, ne11)) {
1753
+ // The custom F16 vector kernel can be used over batched cuBLAS GEMM.
1754
+ // But this is only faster for GPUs without tensor cores or with a thin src0 matrix (particularly KQV in attention)
2649
1755
  ggml_cuda_mul_mat_vec_f(ctx, src0, src1, nullptr, dst);
2650
- } else if (!split && use_mul_mat_f) {
1756
+ return;
1757
+ }
1758
+ if (ggml_cuda_should_use_mmf(src0->type, cc, warp_size, src0->ne, src0->nb, ne11, /*mul_mat_id =*/ false)) {
2651
1759
  ggml_cuda_mul_mat_f(ctx, src0, src1, nullptr, dst);
2652
- } else if (!split && use_mul_mat_vec_q) {
1760
+ return;
1761
+ }
1762
+ if (ggml_cuda_should_use_mmvq(src0->type, cc, ne11)) {
2653
1763
  ggml_cuda_mul_mat_vec_q(ctx, src0, src1, nullptr, dst);
2654
- } else if (!split && use_mul_mat_q) {
1764
+ return;
1765
+ }
1766
+ if (ggml_cuda_should_use_mmq(src0->type, cc, ne11, /*n_experts =*/ 0)) {
2655
1767
  ggml_cuda_mul_mat_q(ctx, src0, src1, nullptr, dst);
2656
- } else if (!split && (use_batched_cublas_f16 || use_batched_cublas_bf16 || use_batched_cublas_f32)
2657
- && !ggml_is_transposed(src0) && !ggml_is_transposed(src1) && src1->ne[2]*src1->ne[3] > 1) {
2658
- // general KQ + KQV multi-batch without FlashAttention
2659
- ggml_cuda_mul_mat_batched_cublas(ctx, src0, src1, dst);
2660
- } else if (use_mul_mat_vec_f) {
2661
- ggml_cuda_op_mul_mat(ctx, src0, src1, dst, ggml_cuda_op_mul_mat_vec_f, nullptr);
2662
- } else if (use_mul_mat_vec_q) {
2663
- ggml_cuda_op_mul_mat(ctx, src0, src1, dst, ggml_cuda_op_mul_mat_vec_q, quantize_row_q8_1_cuda);
2664
- } else if (use_mul_mat_q) {
2665
- ggml_cuda_op_mul_mat(ctx, src0, src1, dst, ggml_cuda_op_mul_mat_q, quantize_mmq_q8_1_cuda);
2666
- } else {
2667
- ggml_cuda_op_mul_mat(ctx, src0, src1, dst, ggml_cuda_op_mul_mat_cublas, nullptr);
1768
+ return;
2668
1769
  }
1770
+ ggml_cuda_mul_mat_cublas(ctx, src0, src1, dst);
2669
1771
  }
2670
1772
 
2671
1773
  static void ggml_cuda_mul_mat_id(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
@@ -2675,7 +1777,6 @@ static void ggml_cuda_mul_mat_id(ggml_backend_cuda_context & ctx, ggml_tensor *
2675
1777
 
2676
1778
  GGML_ASSERT(src1->type == GGML_TYPE_F32);
2677
1779
  GGML_ASSERT(dst->type == GGML_TYPE_F32);
2678
- GGML_ASSERT(!ggml_backend_buft_is_cuda_split(src0->buffer->buft) && "mul_mat_id does not support split buffers");
2679
1780
 
2680
1781
  GGML_TENSOR_BINARY_OP_LOCALS
2681
1782
 
@@ -3090,6 +2191,9 @@ static bool ggml_cuda_compute_forward(ggml_backend_cuda_context & ctx, struct gg
3090
2191
  case GGML_OP_CONV_TRANSPOSE_1D:
3091
2192
  ggml_cuda_op_conv_transpose_1d(ctx,dst);
3092
2193
  break;
2194
+ case GGML_OP_COL2IM_1D:
2195
+ ggml_cuda_op_col2im_1d(ctx, dst);
2196
+ break;
3093
2197
  case GGML_OP_POOL_2D:
3094
2198
  ggml_cuda_op_pool2d(ctx, dst);
3095
2199
  break;
@@ -3179,12 +2283,6 @@ static const char * ggml_backend_cuda_get_name(ggml_backend_t backend) {
3179
2283
  static void ggml_backend_cuda_free(ggml_backend_t backend) {
3180
2284
  ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *)backend->context;
3181
2285
 
3182
- #if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
3183
- ggml_backend_cuda_device_context * dev_ctx = (ggml_backend_cuda_device_context *) backend->device->context;
3184
- std::lock_guard<std::mutex> lock(dev_ctx->device_mutex);
3185
- dev_ctx->active_count--;
3186
- #endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
3187
-
3188
2286
  delete cuda_ctx;
3189
2287
  delete backend;
3190
2288
  }
@@ -3292,6 +2390,11 @@ static void ggml_backend_cuda_synchronize(ggml_backend_t backend) {
3292
2390
  GGML_UNUSED(backend);
3293
2391
  }
3294
2392
 
2393
+ static bool ggml_cuda_is_view_or_noop(const ggml_tensor * t) {
2394
+ return ggml_is_empty(t) || t->op == GGML_OP_RESHAPE || t->op == GGML_OP_TRANSPOSE ||
2395
+ t->op == GGML_OP_VIEW || t->op == GGML_OP_PERMUTE || t->op == GGML_OP_NONE;
2396
+ }
2397
+
3295
2398
  #ifdef USE_CUDA_GRAPH
3296
2399
  static bool ggml_cuda_graph_check_compability(ggml_cgraph * cgraph) {
3297
2400
 
@@ -3301,17 +2404,10 @@ static bool ggml_cuda_graph_check_compability(ggml_cgraph * cgraph) {
3301
2404
  for (int i = 0; i < cgraph->n_nodes; i++) {
3302
2405
  ggml_tensor * node = cgraph->nodes[i];
3303
2406
 
3304
- if (ggml_is_empty(node) || node->op == GGML_OP_RESHAPE || node->op == GGML_OP_TRANSPOSE || node->op == GGML_OP_VIEW || node->op == GGML_OP_PERMUTE || node->op == GGML_OP_NONE) {
2407
+ if (ggml_cuda_is_view_or_noop(node)) {
3305
2408
  continue;
3306
2409
  }
3307
2410
 
3308
- if (node->src[0] && node->src[0]->buffer && ggml_backend_buft_is_cuda_split(node->src[0]->buffer->buft)) {
3309
- use_cuda_graph = false; // Split buffers are not supported by CUDA graph capture
3310
- #ifndef NDEBUG
3311
- GGML_LOG_DEBUG("%s: disabling CUDA graphs due to split buffer\n", __func__);
3312
- #endif
3313
- }
3314
-
3315
2411
  // [TAG_MUL_MAT_ID_CUDA_GRAPHS]
3316
2412
  if (node->op == GGML_OP_MUL_MAT_ID) {
3317
2413
  const int cc = ggml_cuda_info().devices[ggml_cuda_get_device()].cc;
@@ -3444,6 +2540,70 @@ static bool ggml_cuda_should_fuse_rope_set_rows(const ggml_tensor * rope,
3444
2540
  return true;
3445
2541
  }
3446
2542
 
2543
+ // match gated_delta_net + the strided cpy that scatters its state snapshots into the cache
2544
+ // (slot i -> rollback group i, slot 0 newest), so the kernel can write them and skip the cpy.
2545
+ static int ggml_cuda_try_gdn_cache_fusion(
2546
+ const ggml_cgraph * cgraph, int node_idx, ggml_cuda_gated_delta_net_fused_cache & fused_state_cpy) {
2547
+ const ggml_tensor * gdn = cgraph->nodes[node_idx];
2548
+ // the kernel skips the snapshot tail, so the gdn output must not be a graph output
2549
+ if (gdn->op != GGML_OP_GATED_DELTA_NET || gdn->type != GGML_TYPE_F32 ||
2550
+ (gdn->flags & GGML_TENSOR_FLAG_OUTPUT)) {
2551
+ return 0;
2552
+ }
2553
+
2554
+ const ggml_tensor * src_v = gdn->src[2];
2555
+ const int64_t S_v = src_v->ne[0];
2556
+ const int64_t H = src_v->ne[1];
2557
+ const int64_t n_tokens = src_v->ne[2];
2558
+ const int64_t n_seqs = src_v->ne[3];
2559
+ const int64_t D = S_v * S_v * H;
2560
+ const int64_t K = ggml_get_op_params_i32(gdn, 0); // snapshot slot count
2561
+ const int64_t n_written = std::min<int64_t>(n_tokens, K); // newest n_written slots are written
2562
+
2563
+ // snapshot tail starts right after the attention scores
2564
+ const size_t tail_off = ggml_row_size(GGML_TYPE_F32, S_v * H * n_tokens * n_seqs);
2565
+
2566
+ // snapshot cpy is the first real node after the gdn (skip views/no-ops)
2567
+ const ggml_tensor * cpy = nullptr;
2568
+ int skip = 0;
2569
+ for (int j = node_idx + 1; j < cgraph->n_nodes && cpy == nullptr; ++j) {
2570
+ const ggml_tensor * n = cgraph->nodes[j];
2571
+ if (ggml_cuda_is_view_or_noop(n)) {
2572
+ continue;
2573
+ }
2574
+ if (n->op != GGML_OP_CPY || (n->flags & GGML_TENSOR_FLAG_OUTPUT)) {
2575
+ return 0;
2576
+ }
2577
+ cpy = n;
2578
+ skip = j - node_idx;
2579
+ }
2580
+ if (cpy == nullptr) {
2581
+ return 0;
2582
+ }
2583
+
2584
+ const ggml_tensor * src = cpy->src[0]; // view of the gdn snapshot tail
2585
+ const ggml_tensor * dst = cpy->src[1]; // cache view the kernel writes to
2586
+
2587
+ // src must be this gdn's snapshot tail (contiguous, at the tail offset)
2588
+ if (src->op != GGML_OP_VIEW || src->view_src != gdn || src->view_offs != tail_off ||
2589
+ !ggml_is_contiguous(src)) {
2590
+ return 0;
2591
+ }
2592
+
2593
+ // dst is the [D, n_seqs, n_written] cache view; require nb[1] == D (the per-seq stride the kernel
2594
+ // assumes). ggml_cpy pins src to the same element count.
2595
+ const std::array<int64_t, GGML_MAX_DIMS> expected_ne = { D, n_seqs, n_written, 1 };
2596
+ if (dst->op != GGML_OP_VIEW || dst->type != GGML_TYPE_F32 || dst->data == nullptr ||
2597
+ !std::equal(expected_ne.begin(), expected_ne.end(), dst->ne) ||
2598
+ dst->nb[0] != ggml_type_size(GGML_TYPE_F32) || dst->nb[1] != (size_t) ggml_row_size(GGML_TYPE_F32, D)) {
2599
+ return 0;
2600
+ }
2601
+
2602
+ fused_state_cpy.data = (float *) dst->data; // rollback group 0 (newest)
2603
+ fused_state_cpy.slot_stride = K > 1 ? (int64_t) (dst->nb[2] / sizeof(float)) : 0;
2604
+ return skip;
2605
+ }
2606
+
3447
2607
  static bool ggml_cuda_topk_moe_fusion(const struct ggml_cgraph * cgraph, int node_idx, ggml_cuda_topk_moe_args & args) {
3448
2608
  args.sigmoid = false;
3449
2609
  args.softmax = false;
@@ -3885,6 +3045,20 @@ static int ggml_cuda_try_fuse(ggml_backend_cuda_context * cuda_ctx, ggml_cgraph
3885
3045
 
3886
3046
  ggml_tensor * node = cgraph->nodes[i];
3887
3047
 
3048
+ // gated_delta_net -> cpy: scatter recurrent-state snapshots into the cache
3049
+ if (node->op == GGML_OP_GATED_DELTA_NET) {
3050
+ ggml_cuda_gated_delta_net_fused_cache fused_state_cpy;
3051
+ const int nodes_to_skip = ggml_cuda_try_gdn_cache_fusion(cgraph, i, fused_state_cpy);
3052
+ if (nodes_to_skip > 0) {
3053
+ #ifdef GGML_CUDA_DEBUG
3054
+ GGML_LOG_INFO("%s: fused gated_delta_net snapshot copies for %s (skipped %d nodes)\n",
3055
+ __func__, node->name, nodes_to_skip);
3056
+ #endif
3057
+ ggml_cuda_op_gated_delta_net_fused_cache(*cuda_ctx, node, fused_state_cpy);
3058
+ return nodes_to_skip;
3059
+ }
3060
+ }
3061
+
3888
3062
  //topk-moe
3889
3063
  if (cgraph->nodes[i]->op == GGML_OP_UNARY || cgraph->nodes[i]->op == GGML_OP_SOFT_MAX ||
3890
3064
  cgraph->nodes[i]->op == GGML_OP_ARGSORT) {
@@ -3991,18 +3165,21 @@ static int ggml_cuda_try_fuse(ggml_backend_cuda_context * cuda_ctx, ggml_cgraph
3991
3165
  (a->ne[2] == 1 && a->ne[3] == 1);
3992
3166
  const bool shape_ok = ggml_are_same_shape(a, inv_b) && a->ne[0] == 1 && a->ne[1] == x->ne[1];
3993
3167
 
3994
- // x must be in the supported whitelist and every operand / intermediate
3995
- // result must share x's type, since launch_snake casts a / inv_b as
3996
- // float and templates the kernel on a single T. Mixed precision chains
3997
- // fall back to the naive path.
3168
+ // x is in the supported whitelist and every chain intermediate shares
3169
+ // x's type. launch_snake reads a and inv_b as const float *, so they
3170
+ // stay F32.
3998
3171
  const ggml_tensor * sin1 = cgraph->nodes[i + 1];
3999
3172
  const bool types_ok = (x->type == GGML_TYPE_F32 || x->type == GGML_TYPE_F16 || x->type == GGML_TYPE_BF16) &&
4000
- (a->type == x->type) && (inv_b->type == x->type) &&
3173
+ (a->type == GGML_TYPE_F32) && (inv_b->type == GGML_TYPE_F32) &&
4001
3174
  (mul0->type == x->type) && (sin1->type == x->type) &&
4002
3175
  (sqr->type == x->type) && (mul1->type == x->type) &&
4003
3176
  (add->type == x->type);
4004
3177
 
4005
- if (types_ok && shape_ok && dim_ok && x_in_add == x) {
3178
+ // kernel reads x[idx] and a[c] / inv_b[c] linearly, so every operand is contiguous
3179
+ const bool contig_ok = ggml_is_contiguous(x) && ggml_is_contiguous(add) &&
3180
+ ggml_is_contiguous(a) && ggml_is_contiguous(inv_b);
3181
+
3182
+ if (types_ok && shape_ok && dim_ok && contig_ok && x_in_add == x) {
4006
3183
  ggml_cuda_op_snake_fused(*cuda_ctx, x, a, inv_b, add);
4007
3184
  return 4;
4008
3185
  }
@@ -4047,10 +3224,240 @@ static int ggml_cuda_try_fuse(ggml_backend_cuda_context * cuda_ctx, ggml_cgraph
4047
3224
  bool fused_mul_mat_vec = false;
4048
3225
  int fused_node_count = 0;
4049
3226
 
4050
- // gate + glu + up
3227
+ auto get_mul_mat_scale = [](const ggml_tensor * scale_node, const ggml_tensor * mm_node) -> const ggml_tensor * {
3228
+ const bool scale_lhs_mm = scale_node->src[0] == mm_node;
3229
+ const bool scale_rhs_mm = scale_node->src[1] == mm_node;
3230
+ if (!scale_lhs_mm && !scale_rhs_mm) {
3231
+ return nullptr;
3232
+ }
3233
+
3234
+ const ggml_tensor * scale = scale_lhs_mm ? scale_node->src[1] : scale_node->src[0];
3235
+ if (mm_node->src[0]->type != GGML_TYPE_NVFP4 || scale_node->type != GGML_TYPE_F32 ||
3236
+ scale->type != GGML_TYPE_F32 || !ggml_is_contiguous(scale) || ggml_nelements(scale) != 1 ||
3237
+ !ggml_are_same_shape(scale_node, mm_node)) {
3238
+ return nullptr;
3239
+ }
3240
+
3241
+ return scale;
3242
+ };
3243
+
3244
+ auto get_mul_mat_id_scale = [](const ggml_tensor * reshape, const ggml_tensor * repeat, const ggml_tensor * getrows,
3245
+ const ggml_tensor * scale_node, const ggml_tensor * mm_node) -> const ggml_tensor * {
3246
+ if (repeat->src[0] != reshape || getrows->src[0] != repeat || getrows->src[1] != mm_node->src[2]) {
3247
+ return nullptr;
3248
+ }
3249
+ if (!((scale_node->src[0] == mm_node && scale_node->src[1] == getrows) ||
3250
+ (scale_node->src[0] == getrows && scale_node->src[1] == mm_node))) {
3251
+ return nullptr;
3252
+ }
3253
+
3254
+ const ggml_tensor * scale = reshape->src[0];
3255
+ if (mm_node->src[0]->type != GGML_TYPE_NVFP4 || scale_node->type != GGML_TYPE_F32 ||
3256
+ scale->type != GGML_TYPE_F32 || !ggml_is_contiguous(scale) || ggml_nelements(scale) != mm_node->src[0]->ne[2] ||
3257
+ !ggml_are_same_shape(scale_node, mm_node)) {
3258
+ return nullptr;
3259
+ }
3260
+
3261
+ return scale;
3262
+ };
3263
+
3264
+ auto get_bias_tensor = [](const ggml_tensor * bias_node, const ggml_tensor * mul_node, ggml_op op_bias) -> const ggml_tensor * {
3265
+ if (op_bias == GGML_OP_ADD) {
3266
+ if (bias_node->src[0] == mul_node) {
3267
+ return bias_node->src[1];
3268
+ }
3269
+ if (bias_node->src[1] == mul_node) {
3270
+ return bias_node->src[0];
3271
+ }
3272
+ return nullptr;
3273
+ }
3274
+ GGML_ASSERT(op_bias == GGML_OP_ADD_ID);
3275
+ GGML_ASSERT(bias_node->src[0] == mul_node);
3276
+ return bias_node->src[1];
3277
+ };
3278
+
3279
+ // gate + glu + up, with optional scale/bias on both lanes.
4051
3280
  for (ggml_op op : { GGML_OP_MUL_MAT, GGML_OP_MUL_MAT_ID }) {
4052
3281
  const ggml_op bias_op = op == GGML_OP_MUL_MAT ? GGML_OP_ADD : GGML_OP_ADD_ID;
4053
3282
 
3283
+ if (op == GGML_OP_MUL_MAT) {
3284
+ for (const bool with_bias : { false, true }) {
3285
+ const int gate_idx = i;
3286
+ const int gate_scale_idx = i + 1;
3287
+ const int gate_bias_idx = with_bias ? i + 2 : -1;
3288
+ const int up_idx = with_bias ? i + 3 : i + 2;
3289
+ const int up_scale_idx = up_idx + 1;
3290
+ const int up_bias_idx = with_bias ? up_idx + 2 : -1;
3291
+ const int glu_idx = with_bias ? up_idx + 3 : up_idx + 2;
3292
+
3293
+ const int out_nodes[] = { glu_idx };
3294
+ ggml_op ops[7];
3295
+ if (with_bias) {
3296
+ ops[0] = op;
3297
+ ops[1] = GGML_OP_MUL;
3298
+ ops[2] = bias_op;
3299
+ ops[3] = op;
3300
+ ops[4] = GGML_OP_MUL;
3301
+ ops[5] = bias_op;
3302
+ ops[6] = GGML_OP_GLU;
3303
+ } else {
3304
+ ops[0] = op;
3305
+ ops[1] = GGML_OP_MUL;
3306
+ ops[2] = op;
3307
+ ops[3] = GGML_OP_MUL;
3308
+ ops[4] = GGML_OP_GLU;
3309
+ }
3310
+ const int n_ops = with_bias ? 7 : 5;
3311
+
3312
+ if (!ggml_can_fuse_subgraph(cgraph, i, n_ops, ops, out_nodes, 1) ||
3313
+ !ggml_cuda_check_fusion_memory_ranges(cgraph, i, n_ops, out_nodes, 1)) {
3314
+ continue;
3315
+ }
3316
+
3317
+ ggml_tensor * gate_n = cgraph->nodes[gate_idx];
3318
+ ggml_tensor * gate_scale_n = cgraph->nodes[gate_scale_idx];
3319
+ ggml_tensor * gate_out_n = with_bias ? cgraph->nodes[gate_bias_idx] : gate_scale_n;
3320
+ ggml_tensor * up_n = cgraph->nodes[up_idx];
3321
+ ggml_tensor * up_scale_n = cgraph->nodes[up_scale_idx];
3322
+ ggml_tensor * up_out_n = with_bias ? cgraph->nodes[up_bias_idx] : up_scale_n;
3323
+ const ggml_tensor * glu = cgraph->nodes[glu_idx];
3324
+
3325
+ if (!ggml_cuda_should_fuse_mul_mat(up_n, gate_n, glu,
3326
+ with_bias ? up_out_n : nullptr, with_bias ? gate_out_n : nullptr, up_scale_n, gate_scale_n)) {
3327
+ continue;
3328
+ }
3329
+
3330
+ const ggml_tensor * gate_scale = get_mul_mat_scale(gate_scale_n, gate_n);
3331
+ const ggml_tensor * up_scale = get_mul_mat_scale(up_scale_n, up_n);
3332
+ if (!gate_scale || !up_scale) {
3333
+ continue;
3334
+ }
3335
+
3336
+ const ggml_tensor * up_bias = with_bias ? get_bias_tensor(up_out_n, up_scale_n, bias_op) : nullptr;
3337
+ const ggml_tensor * gate_bias = with_bias ? get_bias_tensor(gate_out_n, gate_scale_n, bias_op) : nullptr;
3338
+ if (with_bias && (!ggml_are_same_shape(gate_out_n->src[0], gate_out_n->src[1]) ||
3339
+ !ggml_are_same_shape(up_out_n->src[0], up_out_n->src[1]))) {
3340
+ continue;
3341
+ }
3342
+
3343
+ const ggml_tensor * src0 = up_n->src[0];
3344
+ const ggml_tensor * src1 = up_n->src[1];
3345
+ const ggml_tensor * ids = up_n->src[2];
3346
+
3347
+ ggml_cuda_mm_fusion_args_host fusion_data{};
3348
+ fusion_data.gate = gate_n->src[0];
3349
+ fusion_data.x_bias = up_bias;
3350
+ fusion_data.gate_bias = gate_bias;
3351
+ fusion_data.x_scale = up_scale;
3352
+ fusion_data.gate_scale = gate_scale;
3353
+ fusion_data.glu_op = ggml_get_glu_op(glu);
3354
+
3355
+ if (ggml_cuda_should_fuse_mul_mat_vec_q(up_n)) {
3356
+ ggml_cuda_mul_mat_vec_q(*cuda_ctx, src0, src1, ids, cgraph->nodes[glu_idx], &fusion_data);
3357
+ fused_mul_mat_vec = true;
3358
+ fused_node_count = n_ops;
3359
+ break;
3360
+ }
3361
+ }
3362
+
3363
+ if (fused_mul_mat_vec) {
3364
+ break;
3365
+ }
3366
+ } else {
3367
+ for (const bool with_bias : { false, true }) {
3368
+ const int gate_idx = i;
3369
+ const int gate_scale_idx = i + 4;
3370
+ const int gate_bias_idx = with_bias ? i + 5 : -1;
3371
+ const int up_idx = with_bias ? i + 6 : i + 5;
3372
+ const int up_scale_idx = up_idx + 4;
3373
+ const int up_bias_idx = with_bias ? up_idx + 5 : -1;
3374
+ const int glu_idx = with_bias ? up_idx + 6 : up_idx + 5;
3375
+
3376
+ const int out_nodes[] = { glu_idx };
3377
+ ggml_op ops[13];
3378
+ if (with_bias) {
3379
+ ops[0] = op;
3380
+ ops[1] = GGML_OP_RESHAPE;
3381
+ ops[2] = GGML_OP_REPEAT;
3382
+ ops[3] = GGML_OP_GET_ROWS;
3383
+ ops[4] = GGML_OP_MUL;
3384
+ ops[5] = bias_op;
3385
+ ops[6] = op;
3386
+ ops[7] = GGML_OP_RESHAPE;
3387
+ ops[8] = GGML_OP_REPEAT;
3388
+ ops[9] = GGML_OP_GET_ROWS;
3389
+ ops[10] = GGML_OP_MUL;
3390
+ ops[11] = bias_op;
3391
+ ops[12] = GGML_OP_GLU;
3392
+ } else {
3393
+ ops[0] = op;
3394
+ ops[1] = GGML_OP_RESHAPE;
3395
+ ops[2] = GGML_OP_REPEAT;
3396
+ ops[3] = GGML_OP_GET_ROWS;
3397
+ ops[4] = GGML_OP_MUL;
3398
+ ops[5] = op;
3399
+ ops[6] = GGML_OP_RESHAPE;
3400
+ ops[7] = GGML_OP_REPEAT;
3401
+ ops[8] = GGML_OP_GET_ROWS;
3402
+ ops[9] = GGML_OP_MUL;
3403
+ ops[10] = GGML_OP_GLU;
3404
+ }
3405
+ const int n_ops = with_bias ? 13 : 11;
3406
+
3407
+ if (!ggml_can_fuse_subgraph(cgraph, i, n_ops, ops, out_nodes, 1) ||
3408
+ !ggml_cuda_check_fusion_memory_ranges(cgraph, i, n_ops, out_nodes, 1)) {
3409
+ continue;
3410
+ }
3411
+
3412
+ ggml_tensor * gate_n = cgraph->nodes[gate_idx];
3413
+ ggml_tensor * gate_scale_n = cgraph->nodes[gate_scale_idx];
3414
+ ggml_tensor * gate_out_n = with_bias ? cgraph->nodes[gate_bias_idx] : gate_scale_n;
3415
+ ggml_tensor * up_n = cgraph->nodes[up_idx];
3416
+ ggml_tensor * up_scale_n = cgraph->nodes[up_scale_idx];
3417
+ ggml_tensor * up_out_n = with_bias ? cgraph->nodes[up_bias_idx] : up_scale_n;
3418
+ const ggml_tensor * glu = cgraph->nodes[glu_idx];
3419
+
3420
+ if (!ggml_cuda_should_fuse_mul_mat(up_n, gate_n, glu,
3421
+ with_bias ? up_out_n : nullptr, with_bias ? gate_out_n : nullptr, up_scale_n, gate_scale_n)) {
3422
+ continue;
3423
+ }
3424
+
3425
+ const ggml_tensor * gate_scale = get_mul_mat_id_scale(cgraph->nodes[gate_idx + 1], cgraph->nodes[gate_idx + 2],
3426
+ cgraph->nodes[gate_idx + 3], gate_scale_n, gate_n);
3427
+ const ggml_tensor * up_scale = get_mul_mat_id_scale(cgraph->nodes[up_idx + 1], cgraph->nodes[up_idx + 2],
3428
+ cgraph->nodes[up_idx + 3], up_scale_n, up_n);
3429
+ if (!gate_scale || !up_scale) {
3430
+ continue;
3431
+ }
3432
+
3433
+ const ggml_tensor * up_bias = with_bias ? get_bias_tensor(up_out_n, up_scale_n, bias_op) : nullptr;
3434
+ const ggml_tensor * gate_bias = with_bias ? get_bias_tensor(gate_out_n, gate_scale_n, bias_op) : nullptr;
3435
+
3436
+ const ggml_tensor * src0 = up_n->src[0];
3437
+ const ggml_tensor * src1 = up_n->src[1];
3438
+ const ggml_tensor * ids = up_n->src[2];
3439
+
3440
+ ggml_cuda_mm_fusion_args_host fusion_data{};
3441
+ fusion_data.gate = gate_n->src[0];
3442
+ fusion_data.x_bias = up_bias;
3443
+ fusion_data.gate_bias = gate_bias;
3444
+ fusion_data.x_scale = up_scale;
3445
+ fusion_data.gate_scale = gate_scale;
3446
+ fusion_data.glu_op = ggml_get_glu_op(glu);
3447
+
3448
+ if (ggml_cuda_should_fuse_mul_mat_vec_q(up_n)) {
3449
+ ggml_cuda_mul_mat_vec_q(*cuda_ctx, src0, src1, ids, cgraph->nodes[glu_idx], &fusion_data);
3450
+ fused_mul_mat_vec = true;
3451
+ fused_node_count = n_ops;
3452
+ break;
3453
+ }
3454
+ }
3455
+
3456
+ if (fused_mul_mat_vec) {
3457
+ break;
3458
+ }
3459
+ }
3460
+
4054
3461
  if (ggml_cuda_can_fuse(cgraph, i, { op, bias_op, op, bias_op, GGML_OP_GLU }, {})) {
4055
3462
  ggml_tensor * glu = cgraph->nodes[i + 4];
4056
3463
  ggml_tensor * gate_bias_n = glu->src[0];
@@ -4070,23 +3477,8 @@ static int ggml_cuda_try_fuse(ggml_backend_cuda_context * cuda_ctx, ggml_cgraph
4070
3477
  continue;
4071
3478
  }
4072
3479
 
4073
- auto get_bias_tensor = [](const ggml_tensor * bias_node, const ggml_tensor * mul_node, ggml_op op_bias) {
4074
- if (op_bias == GGML_OP_ADD) {
4075
- if (bias_node->src[0] == mul_node) {
4076
- return bias_node->src[1];
4077
- }
4078
- if (bias_node->src[1] == mul_node) {
4079
- return bias_node->src[0];
4080
- }
4081
- return (ggml_tensor *) nullptr;
4082
- }
4083
- GGML_ASSERT(op_bias == GGML_OP_ADD_ID);
4084
- GGML_ASSERT(bias_node->src[0] == mul_node);
4085
- return bias_node->src[1];
4086
- };
4087
-
4088
- ggml_tensor * up_bias_tensor = get_bias_tensor(up_bias_n, up_n, bias_op);
4089
- ggml_tensor * gate_bias_tensor = get_bias_tensor(gate_bias_n, gate_n, bias_op);
3480
+ const ggml_tensor * up_bias_tensor = get_bias_tensor(up_bias_n, up_n, bias_op);
3481
+ const ggml_tensor * gate_bias_tensor = get_bias_tensor(gate_bias_n, gate_n, bias_op);
4090
3482
 
4091
3483
  if (!up_bias_tensor || !gate_bias_tensor) {
4092
3484
  continue;
@@ -4174,7 +3566,95 @@ static int ggml_cuda_try_fuse(ggml_backend_cuda_context * cuda_ctx, ggml_cgraph
4174
3566
  fused_mul_mat_vec = false;
4175
3567
  fused_node_count = 0;
4176
3568
 
4177
- // gate + add + glu + up + add
3569
+ // mul_mat + scale + optional bias
3570
+ for (ggml_op op : { GGML_OP_MUL_MAT, GGML_OP_MUL_MAT_ID }) {
3571
+ const ggml_op bias_op = op == GGML_OP_MUL_MAT ? GGML_OP_ADD : GGML_OP_ADD_ID;
3572
+
3573
+ for (const bool with_bias : { false, true }) {
3574
+ const int n_ops = op == GGML_OP_MUL_MAT ? (with_bias ? 3 : 2) : (with_bias ? 6 : 5);
3575
+ const int out_nodes[] = { i + n_ops - 1 };
3576
+ ggml_op ops[6];
3577
+ if (op == GGML_OP_MUL_MAT) {
3578
+ if (with_bias) {
3579
+ ops[0] = op;
3580
+ ops[1] = GGML_OP_MUL;
3581
+ ops[2] = bias_op;
3582
+ } else {
3583
+ ops[0] = op;
3584
+ ops[1] = GGML_OP_MUL;
3585
+ }
3586
+ } else {
3587
+ if (with_bias) {
3588
+ ops[0] = op;
3589
+ ops[1] = GGML_OP_RESHAPE;
3590
+ ops[2] = GGML_OP_REPEAT;
3591
+ ops[3] = GGML_OP_GET_ROWS;
3592
+ ops[4] = GGML_OP_MUL;
3593
+ ops[5] = bias_op;
3594
+ } else {
3595
+ ops[0] = op;
3596
+ ops[1] = GGML_OP_RESHAPE;
3597
+ ops[2] = GGML_OP_REPEAT;
3598
+ ops[3] = GGML_OP_GET_ROWS;
3599
+ ops[4] = GGML_OP_MUL;
3600
+ }
3601
+ }
3602
+
3603
+ if (!ggml_can_fuse_subgraph(cgraph, i, n_ops, ops, out_nodes, 1) ||
3604
+ !ggml_cuda_check_fusion_memory_ranges(cgraph, i, n_ops, out_nodes, 1)) {
3605
+ continue;
3606
+ }
3607
+
3608
+ ggml_tensor * mm_node = cgraph->nodes[i];
3609
+ ggml_tensor * scale_node = op == GGML_OP_MUL_MAT ? cgraph->nodes[i + 1] : cgraph->nodes[i + 4];
3610
+ ggml_tensor * out_node = with_bias ? cgraph->nodes[i + n_ops - 1] : scale_node;
3611
+
3612
+ const ggml_tensor * scale = nullptr;
3613
+ if (op == GGML_OP_MUL_MAT) {
3614
+ scale = get_mul_mat_scale(scale_node, mm_node);
3615
+ } else {
3616
+ scale = get_mul_mat_id_scale(cgraph->nodes[i + 1], cgraph->nodes[i + 2], cgraph->nodes[i + 3], scale_node, mm_node);
3617
+ }
3618
+ if (!scale) {
3619
+ continue;
3620
+ }
3621
+
3622
+ const ggml_tensor * bias = with_bias ? get_bias_tensor(out_node, scale_node, bias_op) : nullptr;
3623
+ if (with_bias && !bias) {
3624
+ continue;
3625
+ }
3626
+ if (with_bias && bias_op == GGML_OP_ADD && !ggml_are_same_shape(out_node->src[0], out_node->src[1])) {
3627
+ continue;
3628
+ }
3629
+ if (with_bias && bias_op == GGML_OP_ADD_ID && out_node->src[2] != mm_node->src[2]) {
3630
+ continue;
3631
+ }
3632
+
3633
+ const ggml_tensor * src0 = mm_node->src[0];
3634
+ const ggml_tensor * src1 = mm_node->src[1];
3635
+ const ggml_tensor * ids = mm_node->src[2];
3636
+
3637
+ ggml_cuda_mm_fusion_args_host fusion_data{};
3638
+ fusion_data.x_bias = bias;
3639
+ fusion_data.x_scale = scale;
3640
+
3641
+ if (ggml_cuda_should_fuse_mul_mat_vec_q(mm_node)) {
3642
+ ggml_cuda_mul_mat_vec_q(*cuda_ctx, src0, src1, ids, out_node, &fusion_data);
3643
+ fused_mul_mat_vec = true;
3644
+ fused_node_count = n_ops;
3645
+ break;
3646
+ }
3647
+ }
3648
+ if (fused_mul_mat_vec) {
3649
+ break;
3650
+ }
3651
+ }
3652
+
3653
+ if (fused_mul_mat_vec) {
3654
+ return fused_node_count - 1;
3655
+ }
3656
+
3657
+ // mul_mat + add
4178
3658
  for (ggml_op op : { GGML_OP_MUL_MAT, GGML_OP_MUL_MAT_ID }) {
4179
3659
  const ggml_op bias_op = op == GGML_OP_MUL_MAT ? GGML_OP_ADD : GGML_OP_ADD_ID;
4180
3660
 
@@ -4405,15 +3885,9 @@ static void ggml_cuda_graph_evaluate_and_capture(ggml_backend_cuda_context * cud
4405
3885
  }
4406
3886
  }
4407
3887
 
4408
- #ifdef GGML_CUDA_DEBUG
4409
- const int nodes_fused = i - prev_i - 1;
4410
- if (nodes_fused > 0) {
4411
- GGML_LOG_INFO("nodes_fused: %d\n", nodes_fused);
4412
- }
4413
- #endif
4414
3888
  prev_i = i;
4415
3889
 
4416
- if (ggml_is_empty(node) || node->op == GGML_OP_RESHAPE || node->op == GGML_OP_TRANSPOSE || node->op == GGML_OP_VIEW || node->op == GGML_OP_PERMUTE || node->op == GGML_OP_NONE) {
3890
+ if (ggml_cuda_is_view_or_noop(node)) {
4417
3891
  continue;
4418
3892
  }
4419
3893
 
@@ -4424,6 +3898,12 @@ static void ggml_cuda_graph_evaluate_and_capture(ggml_backend_cuda_context * cud
4424
3898
  int nodes_to_skip = ggml_cuda_try_fuse(cuda_ctx, cgraph, i);
4425
3899
 
4426
3900
  if (nodes_to_skip != 0) {
3901
+ #ifdef GGML_CUDA_DEBUG
3902
+ const int last_fused = i + nodes_to_skip;
3903
+ GGML_LOG_INFO("nodes_fused: %d, first: %s (%s), last: %s (%s)\n",
3904
+ nodes_to_skip + 1, ggml_op_name(node->op), node->name,
3905
+ ggml_op_name(cgraph->nodes[last_fused]->op), cgraph->nodes[last_fused]->name);
3906
+ #endif
4427
3907
  i += nodes_to_skip;
4428
3908
  continue;
4429
3909
  }
@@ -4433,7 +3913,7 @@ static void ggml_cuda_graph_evaluate_and_capture(ggml_backend_cuda_context * cud
4433
3913
  if (node->src[j] != nullptr) {
4434
3914
  assert(node->src[j]->buffer);
4435
3915
  assert(node->src[j]->buffer->buft == ggml_backend_cuda_buffer_type(cuda_ctx->device) ||
4436
- ggml_backend_buft_is_cuda_split(node->src[j]->buffer->buft) || (integrated && ggml_backend_buft_is_cuda_host(node->src[j]->buffer->buft)));
3916
+ (integrated && ggml_backend_buft_is_cuda_host(node->src[j]->buffer->buft)));
4437
3917
  }
4438
3918
  }
4439
3919
  #else
@@ -4916,6 +4396,14 @@ void ggml_backend_cuda_unregister_host_buffer(void * buffer) {
4916
4396
 
4917
4397
  // backend device
4918
4398
 
4399
+ struct ggml_backend_cuda_device_context {
4400
+ int device;
4401
+ std::string name;
4402
+ std::string description;
4403
+ std::string pci_bus_id;
4404
+ int op_offload_min_batch_size;
4405
+ };
4406
+
4919
4407
  static const char * ggml_backend_cuda_device_get_name(ggml_backend_dev_t dev) {
4920
4408
  ggml_backend_cuda_device_context * ctx = (ggml_backend_cuda_device_context *)dev->context;
4921
4409
  return ctx->name.c_str();
@@ -5004,11 +4492,6 @@ static bool ggml_backend_cuda_get_available_uma_memory(long * available_memory_k
5004
4492
 
5005
4493
  static void ggml_backend_cuda_device_get_memory(ggml_backend_dev_t dev, size_t * free, size_t * total) {
5006
4494
  ggml_backend_cuda_device_context * ctx = (ggml_backend_cuda_device_context *)dev->context;
5007
-
5008
- #if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
5009
- std::lock_guard<std::mutex> lock(ctx->device_mutex);
5010
- #endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
5011
-
5012
4495
  ggml_cuda_set_device(ctx->device);
5013
4496
  CUDA_CHECK(cudaMemGetInfo(free, total));
5014
4497
 
@@ -5035,13 +4518,6 @@ static void ggml_backend_cuda_device_get_memory(ggml_backend_dev_t dev, size_t *
5035
4518
  }
5036
4519
  #endif // defined(__linux__)
5037
4520
 
5038
- #if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
5039
- // If no backends or buffers are active, the cudaMemGetInfo call above lazily created a CUDA
5040
- // context that permanently consumes VRAM. Reset the device to free it.
5041
- if (ctx->active_count == 0) {
5042
- CUDA_CHECK(cudaDeviceReset());
5043
- }
5044
- #endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
5045
4521
  }
5046
4522
 
5047
4523
  static enum ggml_backend_dev_type ggml_backend_cuda_device_get_type(ggml_backend_dev_t dev) {
@@ -5099,15 +4575,6 @@ static ggml_backend_buffer_type_t ggml_backend_cuda_device_get_host_buffer_type(
5099
4575
  static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const ggml_tensor * op) {
5100
4576
  ggml_backend_cuda_device_context * dev_ctx = (ggml_backend_cuda_device_context *) dev->context;
5101
4577
 
5102
- // split buffers can only be used with GGML_OP_MUL_MAT
5103
- if (op->op != GGML_OP_MUL_MAT) {
5104
- for (int i = 0; i < GGML_MAX_SRC; i++) {
5105
- if (op->src[i] && op->src[i]->buffer && ggml_backend_buft_is_cuda_split(op->src[i]->buffer->buft)) {
5106
- return false;
5107
- }
5108
- }
5109
- }
5110
-
5111
4578
  // check if all the sources are allocated on this device
5112
4579
  for (int i = 0; i < GGML_MAX_SRC; i++) {
5113
4580
  if (op->src[i] && op->src[i]->buffer && ggml_backend_buft_is_cuda(op->src[i]->buffer->buft)) {
@@ -5168,19 +4635,8 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
5168
4635
  {
5169
4636
  struct ggml_tensor * a = op->src[0];
5170
4637
  struct ggml_tensor * b = op->src[1];
5171
- if (a->buffer && ggml_backend_buft_is_cuda_split(a->buffer->buft)) {
5172
- if (a->ne[2] > 1 || a->ne[3] > 1) {
5173
- return false;
5174
- }
5175
- // for small weight matrices the active device can end up without any rows, don't use row split in those cases
5176
- // this avoids some edge cases (and the performance would not be good anyways)
5177
- ggml_backend_cuda_split_buffer_type_context * buft_ctx = (ggml_backend_cuda_split_buffer_type_context *) a->buffer->buft->context;
5178
- int64_t row_low;
5179
- int64_t row_high;
5180
- get_row_split(&row_low, &row_high, a, buft_ctx->tensor_split, dev_ctx->device);
5181
- if (row_low == row_high) {
5182
- return false;
5183
- }
4638
+ if (a->nb[0] != ggml_element_size(a) || b->nb[0] != ggml_element_size(b)) {
4639
+ return false; // TODO this could in principle be implemented though currently there is no use case.
5184
4640
  }
5185
4641
  if (b->type == GGML_TYPE_F16 && a->type != GGML_TYPE_F16) {
5186
4642
  return false;
@@ -5256,10 +4712,16 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
5256
4712
  } break;
5257
4713
  case GGML_OP_SET_ROWS:
5258
4714
  {
5259
- return (op->type == GGML_TYPE_F32 || op->type == GGML_TYPE_F16 || op->type == GGML_TYPE_BF16 ||
5260
- op->type == GGML_TYPE_Q4_0 || op->type == GGML_TYPE_Q4_1 || op->type == GGML_TYPE_Q5_0 ||
5261
- op->type == GGML_TYPE_Q5_1 || op->type == GGML_TYPE_Q8_0 || op->type == GGML_TYPE_IQ4_NL) &&
5262
- op->src[0]->type == GGML_TYPE_F32 &&
4715
+ return (
4716
+ (
4717
+ (op->type == GGML_TYPE_F32 || op->type == GGML_TYPE_F16 || op->type == GGML_TYPE_BF16 ||
4718
+ op->type == GGML_TYPE_Q4_0 || op->type == GGML_TYPE_Q4_1 || op->type == GGML_TYPE_Q5_0 ||
4719
+ op->type == GGML_TYPE_Q5_1 || op->type == GGML_TYPE_Q8_0 || op->type == GGML_TYPE_IQ4_NL) &&
4720
+ op->src[0]->type == GGML_TYPE_F32
4721
+ ) || (
4722
+ op->type == GGML_TYPE_F16 && op->src[0]->type == GGML_TYPE_F16
4723
+ )
4724
+ ) &&
5263
4725
  (op->src[1]->type == GGML_TYPE_I64 || op->src[1]->type == GGML_TYPE_I32);
5264
4726
  } break;
5265
4727
  case GGML_OP_SET:
@@ -5337,8 +4799,9 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
5337
4799
  } break;
5338
4800
  case GGML_OP_REPEAT:
5339
4801
  {
4802
+ // the CUDA REPEAT path only implements F32/F16; other types assert at runtime
5340
4803
  ggml_type src0_type = op->src[0]->type;
5341
- return src0_type != GGML_TYPE_I32 && src0_type != GGML_TYPE_I16;
4804
+ return src0_type == GGML_TYPE_F32 || src0_type == GGML_TYPE_F16;
5342
4805
  } break;
5343
4806
  case GGML_OP_REPEAT_BACK:
5344
4807
  return op->type == GGML_TYPE_F32 && (op->src[0]->ne[2]*op->src[0]->ne[3]) <= (1 << 15);
@@ -5348,12 +4811,24 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
5348
4811
  ggml_type src1_type = op->src[1]->type;
5349
4812
  return src0_type == src1_type &&
5350
4813
  src0_type == op->type &&
5351
- !ggml_is_quantized(src0_type) &&
5352
- ggml_blck_size(src0_type) == 1 &&
5353
- (ggml_type_size(src0_type) == 1 ||
5354
- ggml_type_size(src0_type) == 2 ||
5355
- ggml_type_size(src0_type) == 4 ||
5356
- ggml_type_size(src0_type) == 8);
4814
+ (
4815
+ (
4816
+ ggml_is_quantized(src0_type) &&
4817
+ ggml_is_contiguous(op->src[0]) &&
4818
+ ggml_is_contiguous(op->src[1]) &&
4819
+ op->src[0]->ne[0] % ggml_blck_size(src0_type) == 0 &&
4820
+ op->src[1]->ne[0] % ggml_blck_size(src0_type) == 0
4821
+ ) || (
4822
+ !ggml_is_quantized(src0_type) &&
4823
+ ggml_blck_size(src0_type) == 1 &&
4824
+ (
4825
+ ggml_type_size(src0_type) == 1 ||
4826
+ ggml_type_size(src0_type) == 2 ||
4827
+ ggml_type_size(src0_type) == 4 ||
4828
+ ggml_type_size(src0_type) == 8
4829
+ )
4830
+ )
4831
+ );
5357
4832
  } break;
5358
4833
  case GGML_OP_CONV_TRANSPOSE_1D:
5359
4834
  {
@@ -5364,13 +4839,21 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
5364
4839
  }
5365
4840
  return false;
5366
4841
  } break;
4842
+ case GGML_OP_COL2IM_1D:
4843
+ {
4844
+ ggml_type src0_type = op->src[0]->type;
4845
+ return (src0_type == GGML_TYPE_F32 || src0_type == GGML_TYPE_F16 || src0_type == GGML_TYPE_BF16) &&
4846
+ op->type == src0_type &&
4847
+ ggml_is_contiguous(op->src[0]) &&
4848
+ ggml_is_contiguous(op);
4849
+ } break;
5367
4850
  case GGML_OP_SILU_BACK:
5368
4851
  return ggml_is_contiguous(op->src[0]) && op->src[0]->type == GGML_TYPE_F32;
5369
4852
  break;
5370
4853
  case GGML_OP_NORM:
5371
4854
  case GGML_OP_RMS_NORM:
5372
4855
  case GGML_OP_L2_NORM:
5373
- return true;
4856
+ return ggml_is_contiguous_rows(op->src[0]);
5374
4857
  case GGML_OP_RMS_NORM_BACK:
5375
4858
  return ggml_is_contiguous(op->src[0]);
5376
4859
  break;
@@ -5434,7 +4917,9 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
5434
4917
  case GGML_OP_IM2COL:
5435
4918
  case GGML_OP_IM2COL_3D:
5436
4919
  case GGML_OP_CONV_2D:
4920
+ return true;
5437
4921
  case GGML_OP_CONV_2D_DW:
4922
+ return op->src[0]->type == GGML_TYPE_F32;
5438
4923
  case GGML_OP_CONV_TRANSPOSE_2D:
5439
4924
  case GGML_OP_POOL_2D:
5440
4925
  return true;
@@ -5494,7 +4979,7 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
5494
4979
  static bool ggml_backend_cuda_device_supports_buft(ggml_backend_dev_t dev, ggml_backend_buffer_type_t buft) {
5495
4980
  ggml_backend_cuda_device_context * dev_ctx = (ggml_backend_cuda_device_context *) dev->context;
5496
4981
  const bool integrated = ggml_cuda_info().devices[dev_ctx->device].integrated;
5497
- return (((ggml_backend_buft_is_cuda(buft) || ggml_backend_buft_is_cuda_split(buft)) && buft->device == dev) || (integrated && ggml_backend_buft_is_cuda_host(buft)));
4982
+ return (ggml_backend_buft_is_cuda(buft) && buft->device == dev) || (integrated && ggml_backend_buft_is_cuda_host(buft));
5498
4983
  }
5499
4984
 
5500
4985
  static int64_t get_op_batch_size(const ggml_tensor * op) {
@@ -5618,10 +5103,6 @@ static ggml_backend_feature * ggml_backend_cuda_get_features(ggml_backend_reg_t
5618
5103
  features.push_back({ "USE_GRAPHS", "1" });
5619
5104
  #endif
5620
5105
 
5621
- #ifdef GGML_CUDA_PEER_MAX_BATCH_SIZE
5622
- features.push_back({ "PEER_MAX_BATCH_SIZE", STRINGIFY(GGML_CUDA_PEER_MAX_BATCH_SIZE) });
5623
- #endif
5624
-
5625
5106
  #ifdef GGML_CUDA_FA_ALL_QUANTS
5626
5107
  features.push_back({ "FA_ALL_QUANTS", "1" });
5627
5108
  #endif
@@ -5660,9 +5141,6 @@ static void * ggml_backend_cuda_reg_get_proc_address(ggml_backend_reg_t reg, con
5660
5141
  if (strcmp(name, "ggml_backend_comm_allreduce_tensor") == 0) {
5661
5142
  return (void *)ggml_backend_cuda_comm_allreduce_tensor;
5662
5143
  }
5663
- if (strcmp(name, "ggml_backend_split_buffer_type") == 0) {
5664
- return (void *)ggml_backend_cuda_split_buffer_type;
5665
- }
5666
5144
  if (strcmp(name, "ggml_backend_register_host_buffer") == 0) {
5667
5145
  return (void *)ggml_backend_cuda_register_host_buffer;
5668
5146
  }
@@ -5744,21 +5222,13 @@ ggml_backend_t ggml_backend_cuda_init(int device) {
5744
5222
  return nullptr;
5745
5223
  }
5746
5224
 
5747
- ggml_backend_dev_t dev = ggml_backend_reg_dev_get(ggml_backend_cuda_reg(), device);
5748
-
5749
5225
  ggml_backend_t cuda_backend = new ggml_backend {
5750
5226
  /* .guid = */ ggml_backend_cuda_guid(),
5751
5227
  /* .iface = */ ggml_backend_cuda_interface,
5752
- /* .device = */ dev,
5228
+ /* .device = */ ggml_backend_reg_dev_get(ggml_backend_cuda_reg(), device),
5753
5229
  /* .context = */ ctx,
5754
5230
  };
5755
5231
 
5756
- #if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
5757
- ggml_backend_cuda_device_context * dev_ctx = (ggml_backend_cuda_device_context *) dev->context;
5758
- std::lock_guard<std::mutex> lock(dev_ctx->device_mutex);
5759
- dev_ctx->active_count++;
5760
- #endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
5761
-
5762
5232
  return cuda_backend;
5763
5233
  }
5764
5234