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.
- checksums.yaml +4 -4
- data/README.md +5 -4
- data/ext/options.rb +1 -1
- data/ext/ruby_whisper.c +0 -1
- data/ext/ruby_whisper.h +7 -1
- data/ext/ruby_whisper_context.c +50 -1
- data/ext/ruby_whisper_log_settable.h +1 -2
- data/ext/ruby_whisper_params.c +9 -8
- data/ext/ruby_whisper_transcribe.cpp +0 -19
- data/ext/ruby_whisper_vad_context.c +30 -10
- data/ext/ruby_whisper_vad_context_detect.cpp +8 -9
- data/ext/ruby_whisper_vad_params.c +4 -4
- data/ext/ruby_whisper_vad_segment.c +2 -2
- data/ext/sources/CMakeLists.txt +2 -1
- data/ext/sources/cmake/parakeet.pc.in +2 -2
- data/ext/sources/cmake/whisper.pc.in +2 -2
- data/ext/sources/examples/cli/cli.cpp +9 -1
- data/ext/sources/examples/common-ggml.cpp +2 -0
- data/ext/sources/examples/vad-speech-segments/speech.cpp +3 -2
- data/ext/sources/ggml/CMakeLists.txt +3 -4
- data/ext/sources/ggml/include/ggml-cuda.h +0 -3
- data/ext/sources/ggml/include/ggml-sycl.h +8 -0
- data/ext/sources/ggml/include/ggml.h +3 -1
- data/ext/sources/ggml/src/CMakeLists.txt +8 -1
- data/ext/sources/ggml/src/ggml-backend-meta.cpp +7 -4
- data/ext/sources/ggml/src/ggml-common.h +13 -2
- data/ext/sources/ggml/src/ggml-cpu/CMakeLists.txt +1 -1
- data/ext/sources/ggml/src/ggml-cpu/amx/mmq.cpp +5 -6
- data/ext/sources/ggml/src/ggml-cpu/arch/arm/quants.c +78 -4
- data/ext/sources/ggml/src/ggml-cpu/arch/x86/quants.c +142 -4
- data/ext/sources/ggml/src/ggml-cpu/arch-fallback.h +7 -2
- data/ext/sources/ggml/src/ggml-cpu/ggml-cpu.c +14 -0
- data/ext/sources/ggml/src/ggml-cpu/llamafile/sgemm.cpp +26 -19
- data/ext/sources/ggml/src/ggml-cpu/ops.cpp +129 -46
- data/ext/sources/ggml/src/ggml-cpu/quants.c +51 -0
- data/ext/sources/ggml/src/ggml-cpu/quants.h +3 -0
- data/ext/sources/ggml/src/ggml-cpu/simd-gemm.h +1 -1
- data/ext/sources/ggml/src/ggml-cpu/simd-mappings.h +11 -0
- data/ext/sources/ggml/src/ggml-cpu/vec.cpp +2 -2
- data/ext/sources/ggml/src/ggml-cuda/binbcast.cu +90 -46
- data/ext/sources/ggml/src/ggml-cuda/col2im-1d.cu +81 -0
- data/ext/sources/ggml/src/ggml-cuda/col2im-1d.cuh +3 -0
- data/ext/sources/ggml/src/ggml-cuda/common.cuh +4 -0
- data/ext/sources/ggml/src/ggml-cuda/concat.cu +33 -21
- data/ext/sources/ggml/src/ggml-cuda/conv-transpose-1d.cu +14 -12
- data/ext/sources/ggml/src/ggml-cuda/convert.cu +86 -34
- data/ext/sources/ggml/src/ggml-cuda/cpy.cu +80 -29
- data/ext/sources/ggml/src/ggml-cuda/fattn-common.cuh +9 -5
- data/ext/sources/ggml/src/ggml-cuda/fattn-mma-f16.cuh +4 -0
- data/ext/sources/ggml/src/ggml-cuda/fattn-tile.cuh +9 -5
- data/ext/sources/ggml/src/ggml-cuda/fattn.cu +27 -21
- data/ext/sources/ggml/src/ggml-cuda/gated_delta_net.cu +40 -25
- data/ext/sources/ggml/src/ggml-cuda/gated_delta_net.cuh +10 -0
- data/ext/sources/ggml/src/ggml-cuda/getrows.cu +15 -12
- data/ext/sources/ggml/src/ggml-cuda/ggml-cuda.cu +718 -1248
- data/ext/sources/ggml/src/ggml-cuda/mmq.cu +7 -0
- data/ext/sources/ggml/src/ggml-cuda/mmvq.cu +77 -40
- data/ext/sources/ggml/src/ggml-cuda/out-prod.cu +55 -12
- data/ext/sources/ggml/src/ggml-cuda/set-rows.cu +64 -4
- data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_16-ncols2_2.cu +1 -0
- data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_32-ncols2_2.cu +1 -0
- data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_4-ncols2_2.cu +1 -0
- data/ext/sources/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_8-ncols2_2.cu +1 -0
- data/ext/sources/ggml/src/ggml-cuda/topk-moe.cu +7 -1
- data/ext/sources/ggml/src/ggml-cuda/vendors/hip.h +1 -0
- data/ext/sources/ggml/src/ggml-cuda/vendors/musa.h +1 -0
- data/ext/sources/ggml/src/ggml-hexagon/CMakeLists.txt +0 -5
- data/ext/sources/ggml/src/ggml-hexagon/ggml-hexagon.cpp +1634 -1293
- data/ext/sources/ggml/src/ggml-hexagon/htp/CMakeLists.txt +11 -40
- data/ext/sources/ggml/src/ggml-hexagon/htp/cmake-toolchain.cmake +13 -15
- data/ext/sources/ggml/src/ggml-hexagon/htp/concat-ops.c +1 -1
- data/ext/sources/ggml/src/ggml-hexagon/htp/flash-attn-ops.c +1749 -399
- data/ext/sources/ggml/src/ggml-hexagon/htp/flash-attn-ops.h +303 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hex-common.h +80 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hex-dma.h +26 -23
- data/ext/sources/ggml/src/ggml-hexagon/htp/hex-profile.h +64 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hex-utils.h +1 -83
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-fa-kernels.h +555 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-mm-kernels-tiled.h +1303 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-queue.c +9 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-queue.h +27 -4
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-utils.h +59 -37
- data/ext/sources/ggml/src/ggml-hexagon/htp/htp-ctx.h +11 -3
- data/ext/sources/ggml/src/ggml-hexagon/htp/htp-ops.h +52 -12
- data/ext/sources/ggml/src/ggml-hexagon/htp/htp-vtcm.h +19 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/htp_iface.idl +2 -1
- data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-base.h +14 -30
- data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-exp.h +39 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-fa-kernels.h +232 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-mm-kernels-flat.h +1511 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-mm-kernels-tiled.h +1200 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/hvx-sigmoid.h +39 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/main.c +127 -32
- data/ext/sources/ggml/src/ggml-hexagon/htp/matmul-ops.c +3023 -4425
- data/ext/sources/ggml/src/ggml-hexagon/htp/matmul-ops.h +650 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp/rope-ops.c +48 -13
- data/ext/sources/ggml/src/ggml-hexagon/htp/ssm-conv.c +10 -9
- data/ext/sources/ggml/src/ggml-hexagon/htp/worker-pool.c +15 -3
- data/ext/sources/ggml/src/ggml-hexagon/htp/worker-pool.h +8 -0
- data/ext/sources/ggml/src/ggml-hexagon/htp-opnode.h +168 -50
- data/ext/sources/ggml/src/ggml-hexagon/libggml-htp.inf +0 -4
- data/ext/sources/ggml/src/ggml-hip/CMakeLists.txt +5 -0
- data/ext/sources/ggml/src/ggml-metal/ggml-metal-device.cpp +69 -5
- data/ext/sources/ggml/src/ggml-metal/ggml-metal-device.h +4 -1
- data/ext/sources/ggml/src/ggml-metal/ggml-metal-device.m +27 -6
- data/ext/sources/ggml/src/ggml-metal/ggml-metal-impl.h +38 -0
- data/ext/sources/ggml/src/ggml-metal/ggml-metal-ops.cpp +132 -2
- data/ext/sources/ggml/src/ggml-metal/ggml-metal-ops.h +2 -0
- data/ext/sources/ggml/src/ggml-metal/ggml-metal.metal +345 -87
- data/ext/sources/ggml/src/ggml-opencl/CMakeLists.txt +13 -0
- data/ext/sources/ggml/src/ggml-opencl/fa_tune.h +92 -0
- data/ext/sources/ggml/src/ggml-opencl/ggml-opencl.cpp +4060 -357
- data/ext/sources/ggml/src/ggml-opencl/kernels/cvt.cl +198 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f16.cl +81 -41
- data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32.cl +88 -39
- data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32_f16.cl +1995 -96
- data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32_q4_0.cl +1615 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_f32_q8_0.cl +1486 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/flash_attn_pre_f16.cl +156 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_f32_ns.cl +74 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q4_0_f32_ns.cl +74 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q4_1_f32_ns.cl +74 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q4_k_f32_ns.cl +71 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q5_0_f32_ns.cl +74 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q5_1_f32_ns.cl +74 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q5_k_f32_ns.cl +74 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_moe_q6_k_f32_ns.cl +74 -6
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q1_0_f32.cl +94 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q1_0_f32.cl +121 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q8_0_f32.cl +1 -1
- data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mm_q1_0_f32_l4_lm.cl +156 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mv_f16_f32_l4.cl +1149 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mv_q1_0_f32.cl +141 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/mul_mv_q1_0_f32_flat.cl +190 -0
- data/ext/sources/ggml/src/ggml-opencl/kernels/norm.cl +5 -2
- data/ext/sources/ggml/src/ggml-opencl/kernels/set_rows.cl +500 -0
- data/ext/sources/ggml/src/ggml-opencl/libdl.h +79 -0
- data/ext/sources/ggml/src/ggml-openvino/.clang-format +0 -5
- data/ext/sources/ggml/src/ggml-openvino/CMakeLists.txt +2 -4
- data/ext/sources/ggml/src/ggml-openvino/ggml-decoder.cpp +733 -130
- data/ext/sources/ggml/src/ggml-openvino/ggml-decoder.h +76 -23
- data/ext/sources/ggml/src/ggml-openvino/ggml-openvino-extra.cpp +57 -3
- data/ext/sources/ggml/src/ggml-openvino/ggml-openvino-extra.h +29 -8
- data/ext/sources/ggml/src/ggml-openvino/ggml-openvino.cpp +307 -59
- data/ext/sources/ggml/src/ggml-openvino/ggml-quants.cpp +66 -0
- data/ext/sources/ggml/src/ggml-openvino/ggml-quants.h +10 -4
- data/ext/sources/ggml/src/ggml-openvino/openvino/decoder.h +56 -16
- data/ext/sources/ggml/src/ggml-openvino/openvino/frontend.h +1 -1
- data/ext/sources/ggml/src/ggml-openvino/openvino/input_model.h +4 -4
- data/ext/sources/ggml/src/ggml-openvino/openvino/node_context.h +94 -37
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/add_id.cpp +76 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/argsort.cpp +47 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/clamp.cpp +33 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/concat.cpp +48 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/cont.cpp +8 -16
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/cpy.cpp +14 -1
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/div.cpp +146 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/flash_attn_ext.cpp +108 -21
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/gated_delta_net.cpp +282 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/gated_delta_net.hpp +65 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/get_rows.cpp +2 -9
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/glu_geglu.cpp +21 -7
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/glu_swiglu.cpp +41 -8
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/im2col.cpp +120 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/l2_norm.cpp +44 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/mul_mat_id.cpp +226 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/mulmat.cpp +19 -9
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/norm.cpp +58 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/pad.cpp +95 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/permute.cpp +58 -13
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/repeat.cpp +74 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/reshape.cpp +13 -6
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/rms_norm.cpp +1 -1
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/rope.cpp +134 -38
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/set_rows.cpp +3 -3
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/softmax.cpp +126 -49
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/ssm_conv.cpp +59 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/sum_rows.cpp +27 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/transpose.cpp +32 -1
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/unary_silu.cpp +1 -1
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/unary_softplus.cpp +38 -0
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/view.cpp +90 -25
- data/ext/sources/ggml/src/ggml-openvino/openvino/op_table.cpp +41 -23
- data/ext/sources/ggml/src/ggml-openvino/openvino/op_table.h +18 -5
- data/ext/sources/ggml/src/ggml-openvino/openvino/pass/mark_decompression_convert_constant_folding.h +1 -1
- data/ext/sources/ggml/src/ggml-openvino/openvino/translate_session.cpp +43 -40
- data/ext/sources/ggml/src/ggml-openvino/openvino/translate_session.h +5 -4
- data/ext/sources/ggml/src/ggml-openvino/openvino/utils.cpp +548 -3
- data/ext/sources/ggml/src/ggml-openvino/openvino/utils.h +28 -26
- data/ext/sources/ggml/src/ggml-openvino/utils.cpp +383 -94
- data/ext/sources/ggml/src/ggml-openvino/utils.h +11 -8
- data/ext/sources/ggml/src/ggml-quants.c +76 -0
- data/ext/sources/ggml/src/ggml-quants.h +3 -0
- data/ext/sources/ggml/src/ggml-sycl/CMakeLists.txt +5 -5
- data/ext/sources/ggml/src/ggml-sycl/backend.hpp +2 -0
- data/ext/sources/ggml/src/ggml-sycl/binbcast.cpp +12 -0
- data/ext/sources/ggml/src/ggml-sycl/col2im-1d.cpp +102 -0
- data/ext/sources/ggml/src/ggml-sycl/col2im-1d.hpp +8 -0
- data/ext/sources/ggml/src/ggml-sycl/common.cpp +6 -8
- data/ext/sources/ggml/src/ggml-sycl/common.hpp +19 -2
- data/ext/sources/ggml/src/ggml-sycl/concat.cpp +21 -1
- data/ext/sources/ggml/src/ggml-sycl/conv2d-dw.cpp +158 -0
- data/ext/sources/ggml/src/ggml-sycl/conv2d-dw.hpp +10 -0
- data/ext/sources/ggml/src/ggml-sycl/conv2d-transpose.cpp +125 -0
- data/ext/sources/ggml/src/ggml-sycl/conv2d-transpose.hpp +10 -0
- data/ext/sources/ggml/src/ggml-sycl/conv2d.cpp +150 -0
- data/ext/sources/ggml/src/ggml-sycl/conv2d.hpp +10 -0
- data/ext/sources/ggml/src/ggml-sycl/conv3d.cpp +224 -0
- data/ext/sources/ggml/src/ggml-sycl/conv3d.hpp +8 -0
- data/ext/sources/ggml/src/ggml-sycl/convert.cpp +6 -0
- data/ext/sources/ggml/src/ggml-sycl/cpy.cpp +706 -0
- data/ext/sources/ggml/src/ggml-sycl/cpy.hpp +281 -0
- data/ext/sources/ggml/src/ggml-sycl/cross_entropy_loss.cpp +255 -0
- data/ext/sources/ggml/src/ggml-sycl/cross_entropy_loss.hpp +7 -0
- data/ext/sources/ggml/src/ggml-sycl/dequantize.hpp +15 -0
- data/ext/sources/ggml/src/ggml-sycl/dmmv.cpp +492 -319
- data/ext/sources/ggml/src/ggml-sycl/dpct/helper.hpp +15 -7
- data/ext/sources/ggml/src/ggml-sycl/element_wise.cpp +215 -115
- data/ext/sources/ggml/src/ggml-sycl/element_wise.hpp +2 -0
- data/ext/sources/ggml/src/ggml-sycl/ggml-sycl.cpp +1006 -336
- data/ext/sources/ggml/src/ggml-sycl/mmvq.cpp +252 -67
- data/ext/sources/ggml/src/ggml-sycl/mmvq.hpp +17 -0
- data/ext/sources/ggml/src/ggml-sycl/norm.cpp +103 -49
- data/ext/sources/ggml/src/ggml-sycl/outprod.cpp +45 -9
- data/ext/sources/ggml/src/ggml-sycl/pool.cpp +185 -0
- data/ext/sources/ggml/src/ggml-sycl/pool.hpp +22 -0
- data/ext/sources/ggml/src/ggml-sycl/presets.hpp +3 -1
- data/ext/sources/ggml/src/ggml-sycl/set_rows.cpp +10 -2
- data/ext/sources/ggml/src/ggml-sycl/softmax.cpp +9 -10
- data/ext/sources/ggml/src/ggml-sycl/vecdotq.hpp +35 -0
- data/ext/sources/ggml/src/ggml-vulkan/CMakeLists.txt +5 -0
- data/ext/sources/ggml/src/ggml-vulkan/ggml-vulkan.cpp +833 -215
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/col2im_1d.comp +61 -0
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/conv2d_mm.comp +1 -1
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/conv3d_mm.comp +431 -0
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/diag.comp +3 -3
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/flash_attn.comp +1 -0
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/flash_attn_cm1.comp +1 -0
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/generic_unary_head.glsl +21 -19
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/get_rows_back.comp +25 -0
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/glu_head.glsl +23 -4
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/glu_main.glsl +14 -18
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/l2_norm.comp +4 -7
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mat_vecq.comp +21 -24
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mm.comp +31 -23
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mm_cm2.comp +6 -5
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/mul_mm_funcs.glsl +84 -67
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/norm.comp +10 -10
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/repeat_back.comp +3 -3
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/roll.comp +3 -3
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/tri.comp +3 -3
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/unary.comp +168 -0
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/vulkan-shaders-gen.cpp +121 -74
- data/ext/sources/ggml/src/ggml-webgpu/ggml-webgpu-shader-lib.hpp +26 -19
- data/ext/sources/ggml/src/ggml-webgpu/ggml-webgpu.cpp +31 -36
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/common_decls.tmpl +16 -2
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/flash_attn_vec_split.wgsl +7 -7
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/get_rows.wgsl +21 -0
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_decls.tmpl +439 -320
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_id_vec.wgsl +2 -2
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_vec.wgsl +45 -39
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_vec_acc.tmpl +586 -465
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/mul_mat_vec_q_acc.tmpl +63 -69
- data/ext/sources/ggml/src/ggml-webgpu/wgsl-shaders/quantize_q8.wgsl +14 -9
- data/ext/sources/ggml/src/ggml.c +36 -14
- data/ext/sources/include/whisper.h +21 -0
- data/ext/sources/src/whisper.cpp +164 -14
- data/lib/whisper/log_settable.rb +5 -8
- data/lib/whisper/model/uri.rb +0 -7
- data/sig/whisper.rbs +6 -0
- data/test/test_vad.rb +9 -0
- data/test/test_vad_context.rb +2 -2
- data/whispercpp.gemspec +1 -1
- metadata +62 -37
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-flash-attn-ops.c +0 -1878
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-matmul-ops.c +0 -2066
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-ops.c +0 -6
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-ops.h +0 -88
- data/ext/sources/ggml/src/ggml-hexagon/htp/hmx-profile.h +0 -34
- data/ext/sources/ggml/src/ggml-hexagon/htp/vtcm-utils.h +0 -16
- data/ext/sources/ggml/src/ggml-openvino/openvino/op/unary_gelu.cpp +0 -25
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/abs.comp +0 -21
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/ceil.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/clamp.comp +0 -17
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/cos.comp +0 -17
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/elu.comp +0 -27
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/exp.comp +0 -20
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/floor.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/gelu.comp +0 -25
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/gelu_erf.comp +0 -39
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/gelu_quick.comp +0 -23
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/hardsigmoid.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/hardswish.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/leaky_relu.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/neg.comp +0 -20
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/relu.comp +0 -21
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/round.comp +0 -29
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sgn.comp +0 -21
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sigmoid.comp +0 -20
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/silu.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sin.comp +0 -17
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/softplus.comp +0 -23
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/sqrt.comp +0 -17
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/square.comp +0 -17
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/step.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/tanh.comp +0 -20
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/trunc.comp +0 -22
- data/ext/sources/ggml/src/ggml-vulkan/vulkan-shaders/xielu.comp +0 -35
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
#include <unordered_map>
|
|
19
19
|
#include <regex>
|
|
20
20
|
#include <queue>
|
|
21
|
+
#include <algorithm>
|
|
21
22
|
|
|
22
23
|
#ifdef _WIN32
|
|
23
24
|
# include <sal.h>
|
|
@@ -41,6 +42,8 @@
|
|
|
41
42
|
#include "ggml-quants.h"
|
|
42
43
|
#include "htp-opnode.h"
|
|
43
44
|
#include "htp-ops.h"
|
|
45
|
+
#include "htp/matmul-ops.h"
|
|
46
|
+
#include "htp/flash-attn-ops.h"
|
|
44
47
|
#include "htp_iface.h"
|
|
45
48
|
#include "htp-drv.h"
|
|
46
49
|
|
|
@@ -51,7 +54,7 @@ using u32vec = std::vector<uint32_t>;
|
|
|
51
54
|
static int opt_arch = 0; // autodetect
|
|
52
55
|
static size_t opt_ndev = 1;
|
|
53
56
|
static size_t opt_nhvx = 0; // use all
|
|
54
|
-
static int
|
|
57
|
+
static int opt_nhmx = 1; // when set, enable HMX; when 0, use HVX only
|
|
55
58
|
static size_t opt_vmem = HTP_OP_MAX_VMEM_DEFAULT; // max available va space for buffer mappings
|
|
56
59
|
static size_t opt_mbuf = 1ul * 1024 * 1024 * 1024; // max buffer size
|
|
57
60
|
static int opt_etm = 0;
|
|
@@ -59,6 +62,9 @@ static int opt_verbose = 0;
|
|
|
59
62
|
static int opt_profile = 0; // profiling mode (0-disabled, 1-basic, 2-pmu)
|
|
60
63
|
static int opt_hostbuf = 1; // hostbuf ON by default
|
|
61
64
|
|
|
65
|
+
static int opt_mm_select = 3; // 3 = HMX -> Tiled -> Flat -> CPU, 2 = Tiled -> Flat -> CPU, 1 = Flat -> CPU
|
|
66
|
+
static int opt_fa_select = 2; // 2 = HMX -> HVX -> CPU, 1 = HVX -> CPU, 0 = CPU (unsupported)
|
|
67
|
+
|
|
62
68
|
// Default PMU events, if profiling with PMU (mode=2) is enabled
|
|
63
69
|
// See https://docs.qualcomm.com/doc/80-N2040-60/topic/pmu-events.html
|
|
64
70
|
// https://docs.qualcomm.com/doc/80-N2040-61/topic/hvx-pmu-events.html
|
|
@@ -68,21 +74,15 @@ static u32vec opt_pmu_evt { 0x3, 0x111, 0x100, 0x105, 0x240, 0x256, 0x7D, 0x8C }
|
|
|
68
74
|
static int opt_opstage = HTP_OPSTAGE_QUEUE | HTP_OPSTAGE_COMPUTE;
|
|
69
75
|
static int opt_opbatch = 1024; // max number of ops in a batch
|
|
70
76
|
static int opt_opqueue = 16; // max number of pending batches
|
|
77
|
+
static int opt_optrace = 0; // trace buffer size per thread (0 means default)
|
|
71
78
|
static int opt_oppoll = 0; // polling for batch completions
|
|
79
|
+
static int opt_opfusion = 1; // enable/disable op fusion
|
|
72
80
|
|
|
73
81
|
static std::regex* opt_opfilter = NULL; // regex of ops to not claim
|
|
74
82
|
|
|
75
83
|
#define HEX_VERBOSE(...) \
|
|
76
84
|
if (opt_verbose) GGML_LOG_DEBUG(__VA_ARGS__)
|
|
77
85
|
|
|
78
|
-
static inline uint64_t hex_is_aligned(void * addr, uint32_t align) {
|
|
79
|
-
return ((size_t) addr & (align - 1)) == 0;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
static inline size_t hex_round_up(size_t n, size_t m) {
|
|
83
|
-
return m * ((n + m - 1) / m);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
86
|
static const char * status_to_str(uint32_t status) {
|
|
87
87
|
switch (status) {
|
|
88
88
|
case HTP_STATUS_OK:
|
|
@@ -106,34 +106,94 @@ static void ggml_hexagon_dump_op_exec(const std::string &sess_name, const htp_op
|
|
|
106
106
|
if (!opt_verbose) return;
|
|
107
107
|
|
|
108
108
|
htp_opformat fmt(node);
|
|
109
|
-
GGML_LOG_DEBUG("ggml-hex: %s execute-op %s
|
|
110
|
-
node.op_name().c_str(), fmt.names, fmt.dims, fmt.types, fmt.strides, fmt.buffs, req_flags);
|
|
109
|
+
GGML_LOG_DEBUG("ggml-hex: %s execute-op %s|%s|%s|%s|%s|%s|%s|flags 0x%x\n", sess_name.c_str(),
|
|
110
|
+
node.op_name().c_str(), fmt.names, fmt.dims, fmt.types, fmt.strides, fmt.buffs, fmt.kparams, req_flags);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
static void ggml_hexagon_dump_op_supp(const std::string &sess_name, const struct ggml_tensor * op, bool supp) {
|
|
114
114
|
if (!opt_verbose) return;
|
|
115
115
|
|
|
116
116
|
htp_opformat fmt(htp_opformat(htp_opnode{const_cast<ggml_tensor*>(op), {}, HTP_OP_INVALID}));
|
|
117
|
-
GGML_LOG_DEBUG("ggml-hex: %s supports-op %s
|
|
117
|
+
GGML_LOG_DEBUG("ggml-hex: %s supports-op %s|%s|%s|%s|%s|%s|%s\n", sess_name.c_str(),
|
|
118
118
|
ggml_op_desc(op), fmt.names, fmt.dims, fmt.types, fmt.strides, fmt.buffs, supp ? "yes" : "no");
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
static const char * htp_event_name(uint16_t id) {
|
|
122
|
+
switch (id) {
|
|
123
|
+
case HTP_TRACE_EVT_DMA: return "DMA";
|
|
124
|
+
case HTP_TRACE_EVT_HVX_COMP: return "HVX_COMP";
|
|
125
|
+
case HTP_TRACE_EVT_HVX_A_QUANT: return "HVX_A_QUANT";
|
|
126
|
+
case HTP_TRACE_EVT_HVX_A_PREP: return "HVX_A_PREP";
|
|
127
|
+
case HTP_TRACE_EVT_HVX_W_DEQUANT: return "HVX_W_DEQUANT";
|
|
128
|
+
case HTP_TRACE_EVT_HVX_W_PREP: return "HVX_W_PREP";
|
|
129
|
+
case HTP_TRACE_EVT_HVX_O_PROC: return "HVX_O_PROC";
|
|
130
|
+
case HTP_TRACE_EVT_HVX_FA_QK: return "HVX_QK_FA";
|
|
131
|
+
case HTP_TRACE_EVT_HVX_FA_SFM: return "HVX_SFM_FA";
|
|
132
|
+
case HTP_TRACE_EVT_HVX_FA_Q_PREP: return "HVX_Q_PREP";
|
|
133
|
+
case HTP_TRACE_EVT_HVX_FA_K_PREP: return "HVX_K_PREP";
|
|
134
|
+
case HTP_TRACE_EVT_HVX_FA_V_PREP: return "HVX_V_PREP";
|
|
135
|
+
case HTP_TRACE_EVT_HMX_COMP: return "HMX_COMP";
|
|
136
|
+
default: return "UNKNOWN";
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
121
140
|
static void ggml_hexagon_dump_op_prof(const std::string &sess_name, const htp_opnode & node,
|
|
122
|
-
|
|
141
|
+
const htp_prof_desc & pd) {
|
|
123
142
|
if (!opt_profile) return;
|
|
124
143
|
|
|
144
|
+
uint32_t op_usec = pd.usecs;
|
|
145
|
+
uint32_t op_cycles = pd.cycles_stop - pd.cycles_start;
|
|
146
|
+
const uint32_t * pmu = pd.pmu;
|
|
147
|
+
|
|
125
148
|
char pmu_str[256] = "";
|
|
126
|
-
if (opt_profile
|
|
149
|
+
if (opt_profile == 2) {
|
|
127
150
|
static_assert(HTP_PROF_PMU_NCNT == 8, "current implementation assumes 8 PMU counters");
|
|
128
|
-
|
|
151
|
+
snprintf(pmu_str, sizeof(pmu_str), " pmu [%u,%u,%u,%u,%u,%u,%u,%u]",
|
|
129
152
|
pmu[0], pmu[1], pmu[2], pmu[3], pmu[4], pmu[5], pmu[6], pmu[7]);
|
|
130
153
|
}
|
|
131
154
|
|
|
132
155
|
htp_opformat fmt(node);
|
|
133
|
-
|
|
134
|
-
|
|
156
|
+
float mhz = op_usec > 0 ? (float) op_cycles / op_usec : 0.0f;
|
|
157
|
+
GGML_LOG_DEBUG("ggml-hex: %s profile-op %s|%s|%s|%s|%s|%s|usec %u cycles %u start %u mhz %.1f%s\n", sess_name.c_str(),
|
|
158
|
+
node.op_name().c_str(), fmt.names, fmt.dims, fmt.types, fmt.strides, fmt.kparams, op_usec, op_cycles, pd.cycles_start, mhz, pmu_str);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// **
|
|
162
|
+
|
|
163
|
+
static inline bool ggml_hexagon_is_repack_type(enum ggml_type type) {
|
|
164
|
+
return type == GGML_TYPE_Q4_0 || type == GGML_TYPE_Q4_1 ||
|
|
165
|
+
type == GGML_TYPE_Q8_0 || type == GGML_TYPE_IQ4_NL ||
|
|
166
|
+
type == GGML_TYPE_MXFP4;
|
|
135
167
|
}
|
|
136
168
|
|
|
169
|
+
static inline bool ggml_hexagon_is_hmx_weight_type(enum ggml_type type) {
|
|
170
|
+
return type == GGML_TYPE_F16 || type == GGML_TYPE_F32 || ggml_hexagon_is_repack_type(type);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
struct htp_mm_kernel_params;
|
|
174
|
+
struct ggml_hexagon_session;
|
|
175
|
+
static void ggml_hexagon_precompute_matmul_params(
|
|
176
|
+
const struct ggml_hexagon_session * sess,
|
|
177
|
+
const struct ggml_tensor * src0,
|
|
178
|
+
const struct ggml_tensor * src1,
|
|
179
|
+
const struct ggml_tensor * dst,
|
|
180
|
+
struct htp_mm_kernel_params * kparams
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
static void ggml_hexagon_precompute_fused_qkv_params(
|
|
184
|
+
const struct ggml_hexagon_session * sess,
|
|
185
|
+
const struct ggml_tensor * src0,
|
|
186
|
+
const struct ggml_tensor * src1,
|
|
187
|
+
struct htp_mm_kernel_params * kparams
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
static void ggml_hexagon_precompute_fused_ffn_params(
|
|
191
|
+
const struct ggml_hexagon_session * sess,
|
|
192
|
+
const struct ggml_tensor * src0,
|
|
193
|
+
const struct ggml_tensor * src1,
|
|
194
|
+
struct htp_mm_kernel_params * kparams
|
|
195
|
+
);
|
|
196
|
+
|
|
137
197
|
// ** backend sessions
|
|
138
198
|
|
|
139
199
|
struct ggml_hexagon_opbatch;
|
|
@@ -160,6 +220,18 @@ struct ggml_hexagon_session {
|
|
|
160
220
|
ggml_backend_buffer_type buffer_type = {};
|
|
161
221
|
ggml_backend_buffer_type repack_buffer_type = {};
|
|
162
222
|
|
|
223
|
+
uint32_t n_threads = 0;
|
|
224
|
+
uint32_t n_hvx = 0;
|
|
225
|
+
uint32_t n_hmx = 0;
|
|
226
|
+
uint64_t vtcm_size = 0;
|
|
227
|
+
size_t max_vmem = 0;
|
|
228
|
+
size_t max_bufsize = 0;
|
|
229
|
+
|
|
230
|
+
struct {
|
|
231
|
+
uint64_t uid = 0;
|
|
232
|
+
std::vector<htp_opnode> htp_nodes;
|
|
233
|
+
} cached_graph;
|
|
234
|
+
|
|
163
235
|
ggml_hexagon_session(int dev_id, ggml_backend_dev_t dev) noexcept(false);
|
|
164
236
|
~ggml_hexagon_session() noexcept(true);
|
|
165
237
|
|
|
@@ -305,47 +377,7 @@ static enum ggml_status ggml_backend_hexagon_buffer_init_tensor(ggml_backend_buf
|
|
|
305
377
|
return GGML_STATUS_SUCCESS;
|
|
306
378
|
}
|
|
307
379
|
|
|
308
|
-
//
|
|
309
|
-
struct x2_q4 {
|
|
310
|
-
int v[2];
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
static x2_q4 unpack_q4(uint8_t v) {
|
|
314
|
-
x2_q4 x = { (int) (v & 0x0f) - 8, (int) (v >> 4) - 8 };
|
|
315
|
-
return x;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
static void dump_block_q4_0(const block_q4_0 * b, int i) {
|
|
319
|
-
HEX_VERBOSE("ggml-hex: repack q4_0 %d: %d %d %d %d ... %d %d %d %d : %.6f\n", i, unpack_q4(b->qs[0]).v[0],
|
|
320
|
-
unpack_q4(b->qs[1]).v[0], unpack_q4(b->qs[2]).v[0], unpack_q4(b->qs[3]).v[0], unpack_q4(b->qs[12]).v[1],
|
|
321
|
-
unpack_q4(b->qs[13]).v[1], unpack_q4(b->qs[14]).v[1], unpack_q4(b->qs[15]).v[1],
|
|
322
|
-
GGML_FP16_TO_FP32(b->d));
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
static void dump_packed_block_q4x4x2(const uint8_t * v, unsigned int i, size_t k) {
|
|
326
|
-
static const int qk = QK_Q4_0x4x2;
|
|
327
|
-
const int dblk_size = 8 * 2; // 8x __fp16
|
|
328
|
-
const int qblk_size = qk / 2; // int4
|
|
329
|
-
const int qrow_size = k / 2; // int4 (not padded)
|
|
330
|
-
|
|
331
|
-
const uint8_t * v_q = v + 0; // quants first
|
|
332
|
-
const uint8_t * v_d = v + qrow_size; // then scales
|
|
333
|
-
|
|
334
|
-
const uint8_t * q = v_q + i * qblk_size;
|
|
335
|
-
const ggml_half * d = (const ggml_half *) (v_d + i * dblk_size);
|
|
336
|
-
|
|
337
|
-
HEX_VERBOSE("ggml-hex: repack q4x4x2-%d: %d %d %d %d ... %d %d %d %d ... %d %d %d %d : %.6f %.6f %.6f %.6f\n", i,
|
|
338
|
-
unpack_q4(q[0]).v[0], unpack_q4(q[1]).v[0], unpack_q4(q[2]).v[0], unpack_q4(q[3]).v[0],
|
|
339
|
-
unpack_q4(q[60]).v[0], unpack_q4(q[61]).v[0], unpack_q4(q[62]).v[0], unpack_q4(q[63]).v[0],
|
|
340
|
-
unpack_q4(q[124]).v[0], unpack_q4(q[125]).v[0], unpack_q4(q[126]).v[0], unpack_q4(q[127]).v[0],
|
|
341
|
-
GGML_FP16_TO_FP32(d[0]), GGML_FP16_TO_FP32(d[1]), GGML_FP16_TO_FP32(d[2]), GGML_FP16_TO_FP32(d[3]));
|
|
342
|
-
|
|
343
|
-
HEX_VERBOSE("ggml-hex: repack q4x4x2-%d: %d %d %d %d ... %d %d %d %d ... %d %d %d %d : %.6f %.6f %.6f %.6f\n",
|
|
344
|
-
i + 1, unpack_q4(q[0]).v[1], unpack_q4(q[1]).v[1], unpack_q4(q[2]).v[1], unpack_q4(q[3]).v[1],
|
|
345
|
-
unpack_q4(q[60]).v[1], unpack_q4(q[61]).v[1], unpack_q4(q[62]).v[1], unpack_q4(q[63]).v[1],
|
|
346
|
-
unpack_q4(q[124]).v[1], unpack_q4(q[125]).v[1], unpack_q4(q[126]).v[1], unpack_q4(q[127]).v[1],
|
|
347
|
-
GGML_FP16_TO_FP32(d[4]), GGML_FP16_TO_FP32(d[5]), GGML_FP16_TO_FP32(d[6]), GGML_FP16_TO_FP32(d[7]));
|
|
348
|
-
}
|
|
380
|
+
// ** Repack helpers for tiled quantized weights
|
|
349
381
|
|
|
350
382
|
static void unpack_q4_0_quants(uint8_t * qs, const block_q4_0 * x, unsigned int bi) {
|
|
351
383
|
static const int qk = QK4_0;
|
|
@@ -368,300 +400,6 @@ static void pack_q4_0_quants(block_q4_0 * x, const uint8_t * qs, unsigned int bi
|
|
|
368
400
|
}
|
|
369
401
|
}
|
|
370
402
|
|
|
371
|
-
static void repack_row_q4x4x2(uint8_t * y, const block_q4_0 * x, int64_t k) {
|
|
372
|
-
static const int qk = QK_Q4_0x4x2;
|
|
373
|
-
const int nb = (k + qk - 1) / qk; // number of blocks (padded)
|
|
374
|
-
const int nloe = k % qk; // leftovers
|
|
375
|
-
|
|
376
|
-
const int dblk_size = 8 * 2; // 8x __fp16
|
|
377
|
-
const int qblk_size = qk / 2; // int4
|
|
378
|
-
const int qrow_size = k / 2; // int4 (not padded to blocks)
|
|
379
|
-
|
|
380
|
-
uint8_t * y_q = y + 0; // quants first
|
|
381
|
-
uint8_t * y_d = y + qrow_size; // then scales
|
|
382
|
-
|
|
383
|
-
if (opt_verbose > 2) {
|
|
384
|
-
for (int i = 0; i < nb; i++) {
|
|
385
|
-
dump_block_q4_0(&x[i * 8 + 0], 0);
|
|
386
|
-
dump_block_q4_0(&x[i * 8 + 1], 1);
|
|
387
|
-
dump_block_q4_0(&x[i * 8 + 2], 2);
|
|
388
|
-
dump_block_q4_0(&x[i * 8 + 3], 3);
|
|
389
|
-
dump_block_q4_0(&x[i * 8 + 4], 4);
|
|
390
|
-
dump_block_q4_0(&x[i * 8 + 5], 5);
|
|
391
|
-
dump_block_q4_0(&x[i * 8 + 6], 6);
|
|
392
|
-
dump_block_q4_0(&x[i * 8 + 7], 7);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// Repack the quants
|
|
397
|
-
for (int i = 0; i < nb; i++) {
|
|
398
|
-
uint8_t qs[QK_Q4_0x4x2]; // unpacked quants
|
|
399
|
-
unpack_q4_0_quants(qs, &x[i * 8 + 0], 0);
|
|
400
|
-
unpack_q4_0_quants(qs, &x[i * 8 + 1], 1);
|
|
401
|
-
unpack_q4_0_quants(qs, &x[i * 8 + 2], 2);
|
|
402
|
-
unpack_q4_0_quants(qs, &x[i * 8 + 3], 3);
|
|
403
|
-
unpack_q4_0_quants(qs, &x[i * 8 + 4], 4);
|
|
404
|
-
unpack_q4_0_quants(qs, &x[i * 8 + 5], 5);
|
|
405
|
-
unpack_q4_0_quants(qs, &x[i * 8 + 6], 6);
|
|
406
|
-
unpack_q4_0_quants(qs, &x[i * 8 + 7], 7);
|
|
407
|
-
|
|
408
|
-
bool partial = (nloe && i == nb-1);
|
|
409
|
-
|
|
410
|
-
uint8_t * q = y_q + (i * qblk_size);
|
|
411
|
-
for (int j = 0; j < qk / 2; j++) {
|
|
412
|
-
q[j] = partial ? (qs[j*2+1] << 4) | qs[j*2+0] : (qs[j+128] << 4) | qs[j+000];
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
// Repack the scales
|
|
417
|
-
// Note: Do not combine with the loop above. For tensor sizes not multiple of 256 (QK_Q4_0x4x2)
|
|
418
|
-
// the last block is truncated and overridden by the scales.
|
|
419
|
-
for (int i = 0; i < nb; i++) {
|
|
420
|
-
// Repack the scales
|
|
421
|
-
ggml_half * d = (ggml_half *) (y_d + i * dblk_size);
|
|
422
|
-
d[0] = x[i * 8 + 0].d;
|
|
423
|
-
d[1] = x[i * 8 + 1].d;
|
|
424
|
-
d[2] = x[i * 8 + 2].d;
|
|
425
|
-
d[3] = x[i * 8 + 3].d;
|
|
426
|
-
d[4] = x[i * 8 + 4].d;
|
|
427
|
-
d[5] = x[i * 8 + 5].d;
|
|
428
|
-
d[6] = x[i * 8 + 6].d;
|
|
429
|
-
d[7] = x[i * 8 + 7].d;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
if (opt_verbose > 2) {
|
|
433
|
-
for (int i = 0; i < nb; i++) {
|
|
434
|
-
dump_packed_block_q4x4x2(y, i, k);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
static void unpack_row_q4x4x2(block_q4_0 * x, const uint8_t * y, int64_t k) {
|
|
440
|
-
static const int qk = QK_Q4_0x4x2;
|
|
441
|
-
const int nb = (k + qk - 1) / qk; // number of blocks (padded)
|
|
442
|
-
const int nloe = k % qk; // leftovers
|
|
443
|
-
|
|
444
|
-
const int dblk_size = 8 * 2; // 8x __fp16
|
|
445
|
-
const int qblk_size = qk / 2; // int4
|
|
446
|
-
const int qrow_size = k / 2; // int4 (not padded to blocks)
|
|
447
|
-
|
|
448
|
-
const uint8_t * y_q = y + 0; // quants first
|
|
449
|
-
const uint8_t * y_d = y + qrow_size; // then scales
|
|
450
|
-
|
|
451
|
-
if (opt_verbose > 2) {
|
|
452
|
-
for (int i = 0; i < nb; i++) {
|
|
453
|
-
dump_packed_block_q4x4x2(y, i, k);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// Unpack the quants
|
|
458
|
-
for (int i = 0; i < nb; i++) {
|
|
459
|
-
uint8_t qs[QK_Q4_0x4x2]; // unpacked quants
|
|
460
|
-
|
|
461
|
-
bool partial = (nloe && i == nb-1);
|
|
462
|
-
|
|
463
|
-
const uint8_t * q = y_q + (i * qblk_size);
|
|
464
|
-
for (int j = 0; j < qk / 2; j++) {
|
|
465
|
-
if (partial) {
|
|
466
|
-
qs[j*2+0] = q[j] & 0xf;
|
|
467
|
-
qs[j*2+1] = q[j] >> 4;
|
|
468
|
-
} else {
|
|
469
|
-
qs[j+000] = q[j] & 0xf;
|
|
470
|
-
qs[j+128] = q[j] >> 4;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
pack_q4_0_quants(&x[i * 8 + 0], qs, 0);
|
|
475
|
-
pack_q4_0_quants(&x[i * 8 + 1], qs, 1);
|
|
476
|
-
pack_q4_0_quants(&x[i * 8 + 2], qs, 2);
|
|
477
|
-
pack_q4_0_quants(&x[i * 8 + 3], qs, 3);
|
|
478
|
-
pack_q4_0_quants(&x[i * 8 + 4], qs, 4);
|
|
479
|
-
pack_q4_0_quants(&x[i * 8 + 5], qs, 5);
|
|
480
|
-
pack_q4_0_quants(&x[i * 8 + 6], qs, 6);
|
|
481
|
-
pack_q4_0_quants(&x[i * 8 + 7], qs, 7);
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
// Repack the scales
|
|
485
|
-
// Note: Do not combine with the loop above. For tensor sizes not multiple of 256 (QK_Q4_0x4x2)
|
|
486
|
-
// the last block is truncated and overridden by the scales.
|
|
487
|
-
for (int i = 0; i < nb; i++) {
|
|
488
|
-
// Unpack the scales
|
|
489
|
-
const ggml_half * d = (const ggml_half *) (y_d + i * dblk_size);
|
|
490
|
-
x[i * 8 + 0].d = d[0];
|
|
491
|
-
x[i * 8 + 1].d = d[1];
|
|
492
|
-
x[i * 8 + 2].d = d[2];
|
|
493
|
-
x[i * 8 + 3].d = d[3];
|
|
494
|
-
x[i * 8 + 4].d = d[4];
|
|
495
|
-
x[i * 8 + 5].d = d[5];
|
|
496
|
-
x[i * 8 + 6].d = d[6];
|
|
497
|
-
x[i * 8 + 7].d = d[7];
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
if (opt_verbose > 2) {
|
|
501
|
-
for (int i = 0; i < nb; i++) {
|
|
502
|
-
dump_block_q4_0(&x[i * 8 + 0], 0);
|
|
503
|
-
dump_block_q4_0(&x[i * 8 + 1], 1);
|
|
504
|
-
dump_block_q4_0(&x[i * 8 + 2], 2);
|
|
505
|
-
dump_block_q4_0(&x[i * 8 + 3], 3);
|
|
506
|
-
dump_block_q4_0(&x[i * 8 + 4], 4);
|
|
507
|
-
dump_block_q4_0(&x[i * 8 + 5], 5);
|
|
508
|
-
dump_block_q4_0(&x[i * 8 + 6], 6);
|
|
509
|
-
dump_block_q4_0(&x[i * 8 + 7], 7);
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
static void init_row_q4x4x2(block_q4_0 * x, int64_t k) {
|
|
515
|
-
static const int qk = QK_Q4_0x4x2;
|
|
516
|
-
const int nb = (k + qk - 1) / qk; // number of blocks (padded)
|
|
517
|
-
|
|
518
|
-
// Init the quants such that they unpack into zeros
|
|
519
|
-
uint8_t qs[QK_Q4_0x4x2]; // unpacked quants
|
|
520
|
-
memset(qs, 8, sizeof(qs));
|
|
521
|
-
|
|
522
|
-
for (int i = 0; i < nb; i++) {
|
|
523
|
-
pack_q4_0_quants(&x[i * 8 + 0], qs, 0);
|
|
524
|
-
pack_q4_0_quants(&x[i * 8 + 1], qs, 1);
|
|
525
|
-
pack_q4_0_quants(&x[i * 8 + 2], qs, 2);
|
|
526
|
-
pack_q4_0_quants(&x[i * 8 + 3], qs, 3);
|
|
527
|
-
pack_q4_0_quants(&x[i * 8 + 4], qs, 4);
|
|
528
|
-
pack_q4_0_quants(&x[i * 8 + 5], qs, 5);
|
|
529
|
-
pack_q4_0_quants(&x[i * 8 + 6], qs, 6);
|
|
530
|
-
pack_q4_0_quants(&x[i * 8 + 7], qs, 7);
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// Init the scales
|
|
534
|
-
// Note: Do not combine with the loop above. For tensor sizes not multiple of 256 (QK_Q4_0x4x2)
|
|
535
|
-
// the last block is truncated and overridden by the scales.
|
|
536
|
-
for (int i = 0; i < nb; i++) {
|
|
537
|
-
// Unpack the scales
|
|
538
|
-
x[i * 8 + 0].d = 0;
|
|
539
|
-
x[i * 8 + 1].d = 0;
|
|
540
|
-
x[i * 8 + 2].d = 0;
|
|
541
|
-
x[i * 8 + 3].d = 0;
|
|
542
|
-
x[i * 8 + 4].d = 0;
|
|
543
|
-
x[i * 8 + 5].d = 0;
|
|
544
|
-
x[i * 8 + 6].d = 0;
|
|
545
|
-
x[i * 8 + 7].d = 0;
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
// repack q4_0 data into q4x4x2 tensor
|
|
550
|
-
static void repack_q4_0_q4x4x2(ggml_tensor * t, const void * data, size_t size) {
|
|
551
|
-
int64_t nrows = ggml_nrows(t);
|
|
552
|
-
|
|
553
|
-
size_t row_size = ggml_row_size(t->type, t->ne[0]);
|
|
554
|
-
size_t row_size_pd = ggml_row_size(t->type, hex_round_up(t->ne[0], QK_Q4_0x4x2)); // extra elements for the pad
|
|
555
|
-
size_t row_size_rp = row_size_pd; // scratch must hold one full padded tile (qblk_size/2 quants + scales)
|
|
556
|
-
|
|
557
|
-
// Ensure we don't try to read more data than is available in the source buffer 'data'
|
|
558
|
-
// or write more than the tensor can hold.
|
|
559
|
-
const size_t total_tensor_size = (size_t)nrows * row_size;
|
|
560
|
-
const size_t n_bytes_to_copy = size < total_tensor_size ? size : total_tensor_size;
|
|
561
|
-
|
|
562
|
-
// Calculate how many full rows and how many remaining bytes we need to process.
|
|
563
|
-
const int64_t n_full_rows = n_bytes_to_copy / row_size;
|
|
564
|
-
const size_t n_rem_bytes = n_bytes_to_copy % row_size;
|
|
565
|
-
|
|
566
|
-
void * buf_pd = ggml_aligned_malloc(row_size_pd);
|
|
567
|
-
GGML_ASSERT(buf_pd != NULL);
|
|
568
|
-
|
|
569
|
-
void * buf_rp = ggml_aligned_malloc(row_size_rp);
|
|
570
|
-
GGML_ASSERT(buf_rp != NULL);
|
|
571
|
-
|
|
572
|
-
HEX_VERBOSE("ggml-hex: repack-q4_0-q4x4x2 %s : data %p size %zu dims %ldx%ld row-size %zu\n", t->name, data, size,
|
|
573
|
-
t->ne[0], nrows, row_size);
|
|
574
|
-
|
|
575
|
-
init_row_q4x4x2((block_q4_0 *) buf_pd, t->ne[0]); // init padded buffer to make sure the tail is all zeros
|
|
576
|
-
|
|
577
|
-
// 1. Process all the full rows
|
|
578
|
-
for (int64_t i = 0; i < n_full_rows; i++) {
|
|
579
|
-
const uint8_t * src = (const uint8_t *) data + (i * row_size);
|
|
580
|
-
uint8_t * dst = (uint8_t *) t->data + (i * row_size);
|
|
581
|
-
|
|
582
|
-
memcpy(buf_pd, src, row_size);
|
|
583
|
-
repack_row_q4x4x2((uint8_t *) buf_rp, (const block_q4_0 *) buf_pd, t->ne[0]);
|
|
584
|
-
memcpy(dst, buf_rp, row_size);
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
// 2. Process the final, potentially partial, row
|
|
588
|
-
if (n_rem_bytes > 0) {
|
|
589
|
-
const int64_t i = n_full_rows;
|
|
590
|
-
const uint8_t * src = (const uint8_t *) data + (i * row_size);
|
|
591
|
-
uint8_t * dst = (uint8_t *) t->data + (i * row_size);
|
|
592
|
-
|
|
593
|
-
// re-init the row because we are potentially copying a partial row
|
|
594
|
-
init_row_q4x4x2((block_q4_0 *) buf_pd, t->ne[0]);
|
|
595
|
-
|
|
596
|
-
// Copy only the remaining bytes from the source.
|
|
597
|
-
memcpy(buf_pd, src, n_rem_bytes);
|
|
598
|
-
|
|
599
|
-
// Repack the entire buffer
|
|
600
|
-
repack_row_q4x4x2((uint8_t *) buf_rp, (const block_q4_0 *) buf_pd, t->ne[0]);
|
|
601
|
-
|
|
602
|
-
// Write only the corresponding remaining bytes to the destination tensor.
|
|
603
|
-
memcpy(dst, buf_rp, n_rem_bytes);
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
ggml_aligned_free(buf_pd, row_size_pd);
|
|
607
|
-
ggml_aligned_free(buf_rp, row_size_rp);
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
// repack q4x4x2 tensor into q4_0 data
|
|
611
|
-
static void repack_q4x4x2_q4_0(void * data, const ggml_tensor * t, size_t size) {
|
|
612
|
-
int64_t nrows = ggml_nrows(t);
|
|
613
|
-
|
|
614
|
-
size_t row_size = ggml_row_size(t->type, t->ne[0]);
|
|
615
|
-
size_t row_size_pd = ggml_row_size(t->type, hex_round_up(t->ne[0], QK_Q4_0x4x2)); // extra elements for the pad
|
|
616
|
-
size_t row_size_rp = row_size_pd; // scratch must hold one full padded tile (qblk_size/2 quants + scales)
|
|
617
|
-
|
|
618
|
-
// Ensure we don't try to copy more data than the tensor actually contains.
|
|
619
|
-
const size_t total_tensor_size = (size_t)nrows * row_size;
|
|
620
|
-
const size_t n_bytes_to_copy = size < total_tensor_size ? size : total_tensor_size;
|
|
621
|
-
|
|
622
|
-
// Calculate how many full rows and how many remaining bytes we need to process.
|
|
623
|
-
const int64_t n_full_rows = n_bytes_to_copy / row_size;
|
|
624
|
-
const size_t n_rem_bytes = n_bytes_to_copy % row_size;
|
|
625
|
-
|
|
626
|
-
void * buf_pd = ggml_aligned_malloc(row_size_pd);
|
|
627
|
-
GGML_ASSERT(buf_pd != NULL);
|
|
628
|
-
|
|
629
|
-
void * buf_rp = ggml_aligned_malloc(row_size_rp);
|
|
630
|
-
GGML_ASSERT(buf_rp != NULL);
|
|
631
|
-
|
|
632
|
-
HEX_VERBOSE("ggml-hex: repack-q4x4x2-q4_0 %s : data %p size %zu dims %ldx%ld row-size %zu\n", t->name, data, size,
|
|
633
|
-
t->ne[0], nrows, row_size);
|
|
634
|
-
|
|
635
|
-
memset(buf_pd, 0, row_size_pd); // clear-out padded buffer to make sure the tail is all zeros
|
|
636
|
-
|
|
637
|
-
// 1. Process all the full rows
|
|
638
|
-
for (int64_t i = 0; i < n_full_rows; i++) {
|
|
639
|
-
const uint8_t * src = (const uint8_t *) t->data + (i * row_size);
|
|
640
|
-
uint8_t * dst = (uint8_t *) data + (i * row_size);
|
|
641
|
-
|
|
642
|
-
memcpy(buf_pd, src, row_size);
|
|
643
|
-
unpack_row_q4x4x2((block_q4_0 *) buf_rp, (const uint8_t *) buf_pd, t->ne[0]);
|
|
644
|
-
memcpy(dst, buf_rp, row_size);
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
// 2. Process the final, potentially partial, row
|
|
648
|
-
if (n_rem_bytes > 0) {
|
|
649
|
-
const int64_t i = n_full_rows;
|
|
650
|
-
const uint8_t * src = (const uint8_t *) t->data + (i * row_size);
|
|
651
|
-
uint8_t * dst = (uint8_t *) data + (i * row_size);
|
|
652
|
-
|
|
653
|
-
// We still need to read and unpack the entire source row because quantization is block-based.
|
|
654
|
-
memcpy(buf_pd, src, row_size);
|
|
655
|
-
unpack_row_q4x4x2((block_q4_0 *) buf_rp, (const uint8_t *) buf_pd, t->ne[0]);
|
|
656
|
-
|
|
657
|
-
// But we only copy the remaining number of bytes to the destination.
|
|
658
|
-
memcpy(dst, buf_rp, n_rem_bytes);
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
ggml_aligned_free(buf_pd, row_size_pd);
|
|
662
|
-
ggml_aligned_free(buf_rp, row_size_rp);
|
|
663
|
-
}
|
|
664
|
-
|
|
665
403
|
static void unpack_q4_1_quants(uint8_t * qs, const block_q4_1 * x, unsigned int bi) {
|
|
666
404
|
static const int qk = QK4_1;
|
|
667
405
|
|
|
@@ -683,603 +421,19 @@ static void pack_q4_1_quants(block_q4_1 * x, const uint8_t * qs, unsigned int bi
|
|
|
683
421
|
}
|
|
684
422
|
}
|
|
685
423
|
|
|
686
|
-
static void repack_row_q4_1x4x2(uint8_t * y, const block_q4_1 * x, int64_t k) {
|
|
687
|
-
static const int qk = QK_Q4_0x4x2;
|
|
688
|
-
const int nb = (k + qk - 1) / qk; // number of blocks (padded)
|
|
689
|
-
const int nloe = k % qk; // leftovers
|
|
690
|
-
|
|
691
|
-
const int dblk_size = 8 * 4; // 8x (d, m) __fp16 = 32 bytes
|
|
692
|
-
const int qblk_size = qk / 2; // int4 = 128 bytes
|
|
693
|
-
const int qrow_size = k / 2; // int4 (not padded to blocks)
|
|
694
|
-
|
|
695
|
-
uint8_t * y_q = y + 0; // quants first
|
|
696
|
-
uint8_t * y_d = y + qrow_size; // then scales/offsets
|
|
697
|
-
|
|
698
|
-
// Repack the quants
|
|
699
|
-
for (int i = 0; i < nb; i++) {
|
|
700
|
-
uint8_t qs[QK_Q4_0x4x2]; // unpacked quants
|
|
701
|
-
unpack_q4_1_quants(qs, &x[i * 8 + 0], 0);
|
|
702
|
-
unpack_q4_1_quants(qs, &x[i * 8 + 1], 1);
|
|
703
|
-
unpack_q4_1_quants(qs, &x[i * 8 + 2], 2);
|
|
704
|
-
unpack_q4_1_quants(qs, &x[i * 8 + 3], 3);
|
|
705
|
-
unpack_q4_1_quants(qs, &x[i * 8 + 4], 4);
|
|
706
|
-
unpack_q4_1_quants(qs, &x[i * 8 + 5], 5);
|
|
707
|
-
unpack_q4_1_quants(qs, &x[i * 8 + 6], 6);
|
|
708
|
-
unpack_q4_1_quants(qs, &x[i * 8 + 7], 7);
|
|
709
|
-
|
|
710
|
-
bool partial = (nloe && i == nb-1);
|
|
711
|
-
|
|
712
|
-
uint8_t * q = y_q + (i * qblk_size);
|
|
713
|
-
for (int j = 0; j < qk / 2; j++) {
|
|
714
|
-
q[j] = partial ? (qs[j*2+1] << 4) | qs[j*2+0] : (qs[j+128] << 4) | qs[j+000];
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
// Repack the scales and offsets
|
|
719
|
-
for (int i = 0; i < nb; i++) {
|
|
720
|
-
ggml_half * d_m = (ggml_half *) (y_d + i * dblk_size);
|
|
721
|
-
for (int j = 0; j < 8; j++) {
|
|
722
|
-
d_m[j * 2 + 0] = x[i * 8 + j].d;
|
|
723
|
-
d_m[j * 2 + 1] = x[i * 8 + j].m;
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
static void unpack_row_q4_1x4x2(block_q4_1 * x, const uint8_t * y, int64_t k) {
|
|
729
|
-
static const int qk = QK_Q4_0x4x2;
|
|
730
|
-
const int nb = (k + qk - 1) / qk; // number of blocks (padded)
|
|
731
|
-
const int nloe = k % qk; // leftovers
|
|
732
|
-
|
|
733
|
-
const int dblk_size = 8 * 4; // 8x (d, m) __fp16 = 32 bytes
|
|
734
|
-
const int qblk_size = qk / 2; // int4 = 128 bytes
|
|
735
|
-
const int qrow_size = k / 2; // int4 (not padded to blocks)
|
|
736
|
-
|
|
737
|
-
const uint8_t * y_q = y + 0; // quants first
|
|
738
|
-
const uint8_t * y_d = y + qrow_size; // then scales/offsets
|
|
739
|
-
|
|
740
|
-
// Unpack the quants
|
|
741
|
-
for (int i = 0; i < nb; i++) {
|
|
742
|
-
uint8_t qs[QK_Q4_0x4x2];
|
|
743
|
-
bool partial = (nloe && i == nb-1);
|
|
744
|
-
|
|
745
|
-
const uint8_t * q = y_q + (i * qblk_size);
|
|
746
|
-
for (int j = 0; j < qk / 2; j++) {
|
|
747
|
-
if (partial) {
|
|
748
|
-
qs[j*2+0] = q[j] & 0x0F;
|
|
749
|
-
qs[j*2+1] = q[j] >> 4;
|
|
750
|
-
} else {
|
|
751
|
-
qs[j+000] = q[j] & 0x0F;
|
|
752
|
-
qs[j+128] = q[j] >> 4;
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
pack_q4_1_quants(&x[i * 8 + 0], qs, 0);
|
|
757
|
-
pack_q4_1_quants(&x[i * 8 + 1], qs, 1);
|
|
758
|
-
pack_q4_1_quants(&x[i * 8 + 2], qs, 2);
|
|
759
|
-
pack_q4_1_quants(&x[i * 8 + 3], qs, 3);
|
|
760
|
-
pack_q4_1_quants(&x[i * 8 + 4], qs, 4);
|
|
761
|
-
pack_q4_1_quants(&x[i * 8 + 5], qs, 5);
|
|
762
|
-
pack_q4_1_quants(&x[i * 8 + 6], qs, 6);
|
|
763
|
-
pack_q4_1_quants(&x[i * 8 + 7], qs, 7);
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
// Unpack the scales and offsets
|
|
767
|
-
for (int i = 0; i < nb; i++) {
|
|
768
|
-
const ggml_half * d_m = (const ggml_half *) (y_d + i * dblk_size);
|
|
769
|
-
for (int j = 0; j < 8; j++) {
|
|
770
|
-
x[i * 8 + j].d = d_m[j * 2 + 0];
|
|
771
|
-
x[i * 8 + j].m = d_m[j * 2 + 1];
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
static void init_row_q4_1x4x2(block_q4_1 * x, int64_t k) {
|
|
777
|
-
static const int qk = QK_Q4_0x4x2;
|
|
778
|
-
const int nb = (k + qk - 1) / qk; // number of blocks (padded)
|
|
779
|
-
|
|
780
|
-
uint8_t qs[QK_Q4_0x4x2]; // unpacked quants
|
|
781
|
-
memset(qs, 0, sizeof(qs));
|
|
782
|
-
|
|
783
|
-
for (int i = 0; i < nb; i++) {
|
|
784
|
-
pack_q4_1_quants(&x[i * 8 + 0], qs, 0);
|
|
785
|
-
pack_q4_1_quants(&x[i * 8 + 1], qs, 1);
|
|
786
|
-
pack_q4_1_quants(&x[i * 8 + 2], qs, 2);
|
|
787
|
-
pack_q4_1_quants(&x[i * 8 + 3], qs, 3);
|
|
788
|
-
pack_q4_1_quants(&x[i * 8 + 4], qs, 4);
|
|
789
|
-
pack_q4_1_quants(&x[i * 8 + 5], qs, 5);
|
|
790
|
-
pack_q4_1_quants(&x[i * 8 + 6], qs, 6);
|
|
791
|
-
pack_q4_1_quants(&x[i * 8 + 7], qs, 7);
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
for (int i = 0; i < nb; i++) {
|
|
795
|
-
for (int j = 0; j < 8; j++) {
|
|
796
|
-
x[i * 8 + j].d = 0;
|
|
797
|
-
x[i * 8 + j].m = 0;
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
static void repack_q4_1_q4x4x2(ggml_tensor * t, const void * data, size_t size) {
|
|
803
|
-
int64_t nrows = ggml_nrows(t);
|
|
804
|
-
|
|
805
|
-
size_t row_size = ggml_row_size(t->type, t->ne[0]);
|
|
806
|
-
size_t row_size_pd = ggml_row_size(t->type, hex_round_up(t->ne[0], QK_Q4_0x4x2));
|
|
807
|
-
size_t row_size_rp = row_size_pd; // scratch must hold one full padded tile (qblk_size/2 quants + scales)
|
|
808
|
-
|
|
809
|
-
const size_t total_tensor_size = (size_t)nrows * row_size;
|
|
810
|
-
const size_t n_bytes_to_copy = size < total_tensor_size ? size : total_tensor_size;
|
|
811
|
-
|
|
812
|
-
const int64_t n_full_rows = n_bytes_to_copy / row_size;
|
|
813
|
-
const size_t n_rem_bytes = n_bytes_to_copy % row_size;
|
|
814
|
-
|
|
815
|
-
void * buf_pd = ggml_aligned_malloc(row_size_pd);
|
|
816
|
-
GGML_ASSERT(buf_pd != NULL);
|
|
817
|
-
|
|
818
|
-
void * buf_rp = ggml_aligned_malloc(row_size_rp);
|
|
819
|
-
GGML_ASSERT(buf_rp != NULL);
|
|
820
|
-
|
|
821
|
-
HEX_VERBOSE("ggml-hex: repack-q4_1-q4x4x2 %s : data %p size %zu dims %ldx%ld row-size %zu\n", t->name, data, size,
|
|
822
|
-
t->ne[0], nrows, row_size);
|
|
823
|
-
|
|
824
|
-
init_row_q4_1x4x2((block_q4_1 *) buf_pd, t->ne[0]);
|
|
825
|
-
|
|
826
|
-
for (int64_t i = 0; i < n_full_rows; i++) {
|
|
827
|
-
const uint8_t * src = (const uint8_t *) data + (i * row_size);
|
|
828
|
-
uint8_t * dst = (uint8_t *) t->data + (i * row_size);
|
|
829
|
-
|
|
830
|
-
memcpy(buf_pd, src, row_size);
|
|
831
|
-
repack_row_q4_1x4x2((uint8_t *) buf_rp, (const block_q4_1 *) buf_pd, t->ne[0]);
|
|
832
|
-
memcpy(dst, buf_rp, row_size);
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
if (n_rem_bytes > 0) {
|
|
836
|
-
const int64_t i = n_full_rows;
|
|
837
|
-
const uint8_t * src = (const uint8_t *) data + (i * row_size);
|
|
838
|
-
uint8_t * dst = (uint8_t *) t->data + (i * row_size);
|
|
839
|
-
|
|
840
|
-
init_row_q4_1x4x2((block_q4_1 *) buf_pd, t->ne[0]);
|
|
841
|
-
memcpy(buf_pd, src, n_rem_bytes);
|
|
842
|
-
repack_row_q4_1x4x2((uint8_t *) buf_rp, (const block_q4_1 *) buf_pd, t->ne[0]);
|
|
843
|
-
memcpy(dst, buf_rp, n_rem_bytes);
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
ggml_aligned_free(buf_pd, row_size_pd);
|
|
847
|
-
ggml_aligned_free(buf_rp, row_size_rp);
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
static void repack_q4x4x2_q4_1(void * data, const ggml_tensor * t, size_t size) {
|
|
851
|
-
int64_t nrows = ggml_nrows(t);
|
|
852
|
-
|
|
853
|
-
size_t row_size = ggml_row_size(t->type, t->ne[0]);
|
|
854
|
-
size_t row_size_pd = ggml_row_size(t->type, hex_round_up(t->ne[0], QK_Q4_0x4x2));
|
|
855
|
-
size_t row_size_rp = row_size_pd; // scratch must hold one full padded tile (qblk_size/2 quants + scales)
|
|
856
|
-
|
|
857
|
-
const size_t total_tensor_size = (size_t)nrows * row_size;
|
|
858
|
-
const size_t n_bytes_to_copy = size < total_tensor_size ? size : total_tensor_size;
|
|
859
|
-
|
|
860
|
-
const int64_t n_full_rows = n_bytes_to_copy / row_size;
|
|
861
|
-
const size_t n_rem_bytes = n_bytes_to_copy % row_size;
|
|
862
|
-
|
|
863
|
-
void * buf_pd = ggml_aligned_malloc(row_size_pd);
|
|
864
|
-
GGML_ASSERT(buf_pd != NULL);
|
|
865
|
-
|
|
866
|
-
void * buf_rp = ggml_aligned_malloc(row_size_rp);
|
|
867
|
-
GGML_ASSERT(buf_rp != NULL);
|
|
868
|
-
|
|
869
|
-
HEX_VERBOSE("ggml-hex: repack-q4x4x2-q4_1 %s : data %p size %zu dims %ldx%ld row-size %zu\n", t->name, data, size,
|
|
870
|
-
t->ne[0], nrows, row_size);
|
|
871
|
-
|
|
872
|
-
memset(buf_rp, 0, row_size_rp); // clear-out padded buffer to make sure the tail is all zeros
|
|
873
|
-
|
|
874
|
-
for (int64_t i = 0; i < n_full_rows; i++) {
|
|
875
|
-
const uint8_t * src = (const uint8_t *) t->data + (i * row_size);
|
|
876
|
-
uint8_t * dst = (uint8_t *) data + (i * row_size);
|
|
877
|
-
|
|
878
|
-
memcpy(buf_rp, src, row_size);
|
|
879
|
-
unpack_row_q4_1x4x2((block_q4_1 *) buf_pd, (const uint8_t *) buf_rp, t->ne[0]);
|
|
880
|
-
memcpy(dst, buf_pd, row_size);
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
if (n_rem_bytes > 0) {
|
|
884
|
-
const int64_t i = n_full_rows;
|
|
885
|
-
const uint8_t * src = (const uint8_t *) t->data + (i * row_size);
|
|
886
|
-
uint8_t * dst = (uint8_t *) data + (i * row_size);
|
|
887
|
-
|
|
888
|
-
// We still need to read and unpack the entire source row because quantization is block-based.
|
|
889
|
-
memcpy(buf_rp, src, row_size);
|
|
890
|
-
unpack_row_q4_1x4x2((block_q4_1 *) buf_pd, (const uint8_t *) buf_rp, t->ne[0]);
|
|
891
|
-
memcpy(dst, buf_pd, n_rem_bytes);
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
ggml_aligned_free(buf_pd, row_size_pd);
|
|
895
|
-
ggml_aligned_free(buf_rp, row_size_rp);
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
// ======== Q8x4x2 ====================
|
|
899
|
-
static void dump_block_q8_0(const block_q8_0 * b, int i) {
|
|
900
|
-
HEX_VERBOSE("ggml-hex: repack q8_0 %d: %d %d %d %d ... %d %d %d %d : %.6f\n", i, b->qs[0], b->qs[1], b->qs[2],
|
|
901
|
-
b->qs[3], b->qs[28], b->qs[29], b->qs[30], b->qs[31], GGML_FP16_TO_FP32(b->d));
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
static void dump_packed_block_q8x4x2(const uint8_t * v, unsigned int i, size_t k) {
|
|
905
|
-
static const int qk = QK_Q8_0x4x2;
|
|
906
|
-
const int dblk_size = 8 * 2; // 8x __fp16
|
|
907
|
-
const int qblk_size = qk; // int8
|
|
908
|
-
const int qrow_size = k; // int8 (not padded)
|
|
909
|
-
|
|
910
|
-
const uint8_t * v_q = v + 0; // quants first
|
|
911
|
-
const uint8_t * v_d = v + qrow_size; // then scales
|
|
912
|
-
|
|
913
|
-
const uint8_t * q = v_q + i * qblk_size;
|
|
914
|
-
const ggml_half * d = (const ggml_half *) (v_d + i * dblk_size);
|
|
915
|
-
|
|
916
|
-
HEX_VERBOSE("ggml-hex: repack q8x4x2-%d: %d %d %d %d ... %d %d %d %d ... %d %d %d %d : %.6f %.6f %.6f %.6f\n", i,
|
|
917
|
-
q[0], q[1], q[2], q[3], q[60], q[61], q[62], q[63], q[124], q[125], q[126], q[127],
|
|
918
|
-
GGML_FP16_TO_FP32(d[0]), GGML_FP16_TO_FP32(d[1]), GGML_FP16_TO_FP32(d[2]), GGML_FP16_TO_FP32(d[3]));
|
|
919
|
-
|
|
920
|
-
HEX_VERBOSE("ggml-hex: repack q8x4x2-%d: %d %d %d %d ... %d %d %d %d ... %d %d %d %d : %.6f %.6f %.6f %.6f\n",
|
|
921
|
-
i + 1, q[128], q[129], q[130], q[131], q[192], q[193], q[194], q[195], q[252], q[253], q[254], q[255],
|
|
922
|
-
GGML_FP16_TO_FP32(d[4]), GGML_FP16_TO_FP32(d[5]), GGML_FP16_TO_FP32(d[6]), GGML_FP16_TO_FP32(d[7]));
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
static void unpack_q8_0_quants(uint8_t * qs, const block_q8_0 * x, unsigned int bi) {
|
|
926
|
-
static const int qk = QK8_0;
|
|
927
|
-
|
|
928
|
-
for (unsigned int i = 0; i < qk; ++i) {
|
|
929
|
-
qs[bi * qk + i] = x->qs[i];
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
static void pack_q8_0_quants(block_q8_0 * x, const uint8_t * qs, unsigned int bi) {
|
|
934
|
-
static const int qk = QK8_0;
|
|
935
|
-
|
|
936
|
-
for (unsigned int i = 0; i < qk; ++i) {
|
|
937
|
-
x->qs[i] = qs[bi * qk + i];
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
static void repack_row_q8x4x2(uint8_t * y, const block_q8_0 * x, int64_t k) {
|
|
942
|
-
static const int qk = QK_Q8_0x4x2;
|
|
943
|
-
const int nb = (k + qk - 1) / qk; // number of blocks (padded)
|
|
944
|
-
|
|
945
|
-
const int dblk_size = 8 * 2; // 8x __fp16
|
|
946
|
-
const int qblk_size = qk; // int8
|
|
947
|
-
const int qrow_size = k; // int8 (not padded to blocks)
|
|
948
|
-
|
|
949
|
-
uint8_t * y_q = y + 0; // quants first
|
|
950
|
-
uint8_t * y_d = y + qrow_size; // then scales
|
|
951
|
-
|
|
952
|
-
if (opt_verbose > 2) {
|
|
953
|
-
for (int i = 0; i < nb; i++) {
|
|
954
|
-
dump_block_q8_0(&x[i * 8 + 0], 0);
|
|
955
|
-
dump_block_q8_0(&x[i * 8 + 1], 1);
|
|
956
|
-
dump_block_q8_0(&x[i * 8 + 2], 2);
|
|
957
|
-
dump_block_q8_0(&x[i * 8 + 3], 3);
|
|
958
|
-
dump_block_q8_0(&x[i * 8 + 4], 4);
|
|
959
|
-
dump_block_q8_0(&x[i * 8 + 5], 5);
|
|
960
|
-
dump_block_q8_0(&x[i * 8 + 6], 6);
|
|
961
|
-
dump_block_q8_0(&x[i * 8 + 7], 7);
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
// Repack the quants
|
|
966
|
-
for (int i = 0; i < nb; i++) {
|
|
967
|
-
uint8_t qs[QK_Q8_0x4x2]; // unpacked quants
|
|
968
|
-
|
|
969
|
-
unpack_q8_0_quants(qs, &x[i * 8 + 0], 0);
|
|
970
|
-
unpack_q8_0_quants(qs, &x[i * 8 + 1], 1);
|
|
971
|
-
unpack_q8_0_quants(qs, &x[i * 8 + 2], 2);
|
|
972
|
-
unpack_q8_0_quants(qs, &x[i * 8 + 3], 3);
|
|
973
|
-
unpack_q8_0_quants(qs, &x[i * 8 + 4], 4);
|
|
974
|
-
unpack_q8_0_quants(qs, &x[i * 8 + 5], 5);
|
|
975
|
-
unpack_q8_0_quants(qs, &x[i * 8 + 6], 6);
|
|
976
|
-
unpack_q8_0_quants(qs, &x[i * 8 + 7], 7);
|
|
977
|
-
|
|
978
|
-
uint8_t * q = y_q + (i * qblk_size);
|
|
979
|
-
for (int j = 0; j < qk; j++) {
|
|
980
|
-
q[j] = qs[j];
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
// Repack the scales
|
|
985
|
-
// Note: Do not combine with the loop above. For tensor sizes not multiple of 256 (QK_Q4_0x4x2)
|
|
986
|
-
// the last block is truncated and overridden by the scales.
|
|
987
|
-
for (int i = 0; i < nb; i++) {
|
|
988
|
-
// Repack the scales
|
|
989
|
-
ggml_half * d = (ggml_half *) (y_d + i * dblk_size);
|
|
990
|
-
d[0] = x[i * 8 + 0].d;
|
|
991
|
-
d[1] = x[i * 8 + 1].d;
|
|
992
|
-
d[2] = x[i * 8 + 2].d;
|
|
993
|
-
d[3] = x[i * 8 + 3].d;
|
|
994
|
-
d[4] = x[i * 8 + 4].d;
|
|
995
|
-
d[5] = x[i * 8 + 5].d;
|
|
996
|
-
d[6] = x[i * 8 + 6].d;
|
|
997
|
-
d[7] = x[i * 8 + 7].d;
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
if (opt_verbose > 2) {
|
|
1001
|
-
for (int i = 0; i < nb; i++) {
|
|
1002
|
-
dump_packed_block_q8x4x2(y, i, k);
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
static void unpack_row_q8x4x2(block_q8_0 * x, const uint8_t * y, int64_t k) {
|
|
1008
|
-
static const int qk = QK_Q8_0x4x2;
|
|
1009
|
-
const int nb = (k + qk - 1) / qk; // number of blocks (padded)
|
|
1010
|
-
|
|
1011
|
-
const int dblk_size = 8 * 2; // 8x __fp16
|
|
1012
|
-
const int qblk_size = qk; // int8
|
|
1013
|
-
const int qrow_size = k; // int8 (not padded to blocks)
|
|
1014
|
-
|
|
1015
|
-
const uint8_t * y_q = y + 0; // quants first
|
|
1016
|
-
const uint8_t * y_d = y + qrow_size; // then scales
|
|
1017
|
-
|
|
1018
|
-
if (opt_verbose > 2) {
|
|
1019
|
-
for (int i = 0; i < nb; i++) {
|
|
1020
|
-
dump_packed_block_q8x4x2(y, i, k);
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
// Unpack the quants
|
|
1025
|
-
for (int i = 0; i < nb; i++) {
|
|
1026
|
-
uint8_t qs[QK_Q4_0x4x2]; // unpacked quants
|
|
1027
|
-
|
|
1028
|
-
const uint8_t * q = y_q + (i * qblk_size);
|
|
1029
|
-
for (int j = 0; j < qk; j++) {
|
|
1030
|
-
qs[j] = q[j];
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
pack_q8_0_quants(&x[i * 8 + 0], qs, 0);
|
|
1034
|
-
pack_q8_0_quants(&x[i * 8 + 1], qs, 1);
|
|
1035
|
-
pack_q8_0_quants(&x[i * 8 + 2], qs, 2);
|
|
1036
|
-
pack_q8_0_quants(&x[i * 8 + 3], qs, 3);
|
|
1037
|
-
pack_q8_0_quants(&x[i * 8 + 4], qs, 4);
|
|
1038
|
-
pack_q8_0_quants(&x[i * 8 + 5], qs, 5);
|
|
1039
|
-
pack_q8_0_quants(&x[i * 8 + 6], qs, 6);
|
|
1040
|
-
pack_q8_0_quants(&x[i * 8 + 7], qs, 7);
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
// Repack the scales
|
|
1044
|
-
// Note: Do not combine with the loop above. For tensor sizes not multiple of 256 (QK_Q4_0x4x2)
|
|
1045
|
-
// the last block is truncated and overridden by the scales.
|
|
1046
|
-
for (int i = 0; i < nb; i++) {
|
|
1047
|
-
// Unpack the scales
|
|
1048
|
-
const ggml_half * d = (const ggml_half *) (y_d + i * dblk_size);
|
|
1049
|
-
x[i * 8 + 0].d = d[0];
|
|
1050
|
-
x[i * 8 + 1].d = d[1];
|
|
1051
|
-
x[i * 8 + 2].d = d[2];
|
|
1052
|
-
x[i * 8 + 3].d = d[3];
|
|
1053
|
-
x[i * 8 + 4].d = d[4];
|
|
1054
|
-
x[i * 8 + 5].d = d[5];
|
|
1055
|
-
x[i * 8 + 6].d = d[6];
|
|
1056
|
-
x[i * 8 + 7].d = d[7];
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
if (opt_verbose > 2) {
|
|
1060
|
-
for (int i = 0; i < nb; i++) {
|
|
1061
|
-
dump_block_q8_0(&x[i * 8 + 0], 0);
|
|
1062
|
-
dump_block_q8_0(&x[i * 8 + 1], 1);
|
|
1063
|
-
dump_block_q8_0(&x[i * 8 + 2], 2);
|
|
1064
|
-
dump_block_q8_0(&x[i * 8 + 3], 3);
|
|
1065
|
-
dump_block_q8_0(&x[i * 8 + 4], 4);
|
|
1066
|
-
dump_block_q8_0(&x[i * 8 + 5], 5);
|
|
1067
|
-
dump_block_q8_0(&x[i * 8 + 6], 6);
|
|
1068
|
-
dump_block_q8_0(&x[i * 8 + 7], 7);
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
static void init_row_q8x4x2(block_q8_0 * x, int64_t k) {
|
|
1074
|
-
static const int qk = QK_Q8_0x4x2;
|
|
1075
|
-
const int nb = (k + qk - 1) / qk; // number of blocks (padded)
|
|
1076
|
-
|
|
1077
|
-
// Init the quants such that they unpack into zeros
|
|
1078
|
-
uint8_t qs[QK_Q8_0x4x2]; // unpacked quants
|
|
1079
|
-
memset(qs, 0, sizeof(qs));
|
|
1080
|
-
|
|
1081
|
-
for (int i = 0; i < nb; i++) {
|
|
1082
|
-
pack_q8_0_quants(&x[i * 8 + 0], qs, 0);
|
|
1083
|
-
pack_q8_0_quants(&x[i * 8 + 1], qs, 1);
|
|
1084
|
-
pack_q8_0_quants(&x[i * 8 + 2], qs, 2);
|
|
1085
|
-
pack_q8_0_quants(&x[i * 8 + 3], qs, 3);
|
|
1086
|
-
pack_q8_0_quants(&x[i * 8 + 4], qs, 4);
|
|
1087
|
-
pack_q8_0_quants(&x[i * 8 + 5], qs, 5);
|
|
1088
|
-
pack_q8_0_quants(&x[i * 8 + 6], qs, 6);
|
|
1089
|
-
pack_q8_0_quants(&x[i * 8 + 7], qs, 7);
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
// Init the scales
|
|
1093
|
-
// Note: Do not combine with the loop above. For tensor sizes not multiple of 256 (QK_Q8_0x4x2)
|
|
1094
|
-
// the last block is truncated and overridden by the scales.
|
|
1095
|
-
for (int i = 0; i < nb; i++) {
|
|
1096
|
-
// Unpack the scales
|
|
1097
|
-
x[i * 8 + 0].d = 0;
|
|
1098
|
-
x[i * 8 + 1].d = 0;
|
|
1099
|
-
x[i * 8 + 2].d = 0;
|
|
1100
|
-
x[i * 8 + 3].d = 0;
|
|
1101
|
-
x[i * 8 + 4].d = 0;
|
|
1102
|
-
x[i * 8 + 5].d = 0;
|
|
1103
|
-
x[i * 8 + 6].d = 0;
|
|
1104
|
-
x[i * 8 + 7].d = 0;
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
// repack q8_0 data into q8x4x2 tensor
|
|
1109
|
-
static void repack_q8_0_q8x4x2(ggml_tensor * t, const void * data, size_t size) {
|
|
1110
|
-
int64_t nrows = ggml_nrows(t);
|
|
1111
|
-
|
|
1112
|
-
size_t row_size = ggml_row_size(t->type, t->ne[0]);
|
|
1113
|
-
size_t row_size_pd = ggml_row_size(t->type, hex_round_up(t->ne[0], QK_Q8_0x4x2)); // extra elements for the pad
|
|
1114
|
-
size_t row_size_rp = row_size_pd; // scratch must hold one full padded tile (qblk_size quants + scales)
|
|
1115
|
-
|
|
1116
|
-
// Ensure we don't try to read more data than is available in the source buffer 'data'
|
|
1117
|
-
// or write more than the tensor can hold.
|
|
1118
|
-
const size_t total_tensor_size = (size_t)nrows * row_size;
|
|
1119
|
-
const size_t n_bytes_to_copy = size < total_tensor_size ? size : total_tensor_size;
|
|
1120
|
-
|
|
1121
|
-
// Calculate how many full rows and how many remaining bytes we need to process.
|
|
1122
|
-
const int64_t n_full_rows = n_bytes_to_copy / row_size;
|
|
1123
|
-
const size_t n_rem_bytes = n_bytes_to_copy % row_size;
|
|
1124
|
-
|
|
1125
|
-
void * buf_pd = ggml_aligned_malloc(row_size_pd);
|
|
1126
|
-
GGML_ASSERT(buf_pd != NULL);
|
|
1127
|
-
|
|
1128
|
-
void * buf_rp = ggml_aligned_malloc(row_size_rp);
|
|
1129
|
-
GGML_ASSERT(buf_rp != NULL);
|
|
1130
|
-
|
|
1131
|
-
HEX_VERBOSE("ggml-hex: repack-q8_0-q8x4x2 %s : data %p size %zu dims %ldx%ld row-size %zu\n", t->name, data, size,
|
|
1132
|
-
t->ne[0], nrows, row_size);
|
|
1133
|
-
|
|
1134
|
-
init_row_q8x4x2((block_q8_0 *) buf_pd, t->ne[0]); // init padded buffer to make sure the tail is all zeros
|
|
1135
|
-
|
|
1136
|
-
// 1. Process all the full rows
|
|
1137
|
-
for (int64_t i = 0; i < n_full_rows; i++) {
|
|
1138
|
-
const uint8_t * src = (const uint8_t *) data + (i * row_size);
|
|
1139
|
-
uint8_t * dst = (uint8_t *) t->data + (i * row_size);
|
|
1140
|
-
|
|
1141
|
-
memcpy(buf_pd, src, row_size);
|
|
1142
|
-
repack_row_q8x4x2((uint8_t *) buf_rp, (const block_q8_0 *) buf_pd, t->ne[0]);
|
|
1143
|
-
memcpy(dst, buf_rp, row_size);
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
// 2. Process the final, potentially partial, row
|
|
1147
|
-
if (n_rem_bytes > 0) {
|
|
1148
|
-
const int64_t i = n_full_rows;
|
|
1149
|
-
const uint8_t * src = (const uint8_t *) data + (i * row_size);
|
|
1150
|
-
uint8_t * dst = (uint8_t *) t->data + (i * row_size);
|
|
1151
|
-
|
|
1152
|
-
// re-init the row because we are potentially copying a partial row
|
|
1153
|
-
init_row_q8x4x2((block_q8_0 *) buf_pd, t->ne[0]);
|
|
1154
|
-
|
|
1155
|
-
// Copy only the remaining bytes from the source.
|
|
1156
|
-
memcpy(buf_pd, src, n_rem_bytes);
|
|
1157
|
-
|
|
1158
|
-
// Repack the entire buffer
|
|
1159
|
-
repack_row_q8x4x2((uint8_t *) buf_rp, (const block_q8_0 *) buf_pd, t->ne[0]);
|
|
1160
|
-
|
|
1161
|
-
// Write only the corresponding remaining bytes to the destination tensor.
|
|
1162
|
-
memcpy(dst, buf_rp, n_rem_bytes);
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
ggml_aligned_free(buf_pd, row_size_pd);
|
|
1166
|
-
ggml_aligned_free(buf_rp, row_size_rp);
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
// repack q8x4x2 tensor into q8_0 data
|
|
1170
|
-
static void repack_q8x4x2_q8_0(void * data, const ggml_tensor * t, size_t size) {
|
|
1171
|
-
int64_t nrows = ggml_nrows(t);
|
|
1172
|
-
|
|
1173
|
-
size_t row_size = ggml_row_size(t->type, t->ne[0]);
|
|
1174
|
-
size_t row_size_pd = ggml_row_size(t->type, hex_round_up(t->ne[0], QK_Q8_0x4x2)); // extra elements for the pad
|
|
1175
|
-
size_t row_size_rp = row_size_pd; // scratch must hold one full padded tile (qblk_size quants + scales)
|
|
1176
|
-
|
|
1177
|
-
// Ensure we don't try to copy more data than the tensor actually contains.
|
|
1178
|
-
const size_t total_tensor_size = (size_t)nrows * row_size;
|
|
1179
|
-
const size_t n_bytes_to_copy = size < total_tensor_size ? size : total_tensor_size;
|
|
1180
|
-
|
|
1181
|
-
// Calculate how many full rows and how many remaining bytes we need to process.
|
|
1182
|
-
const int64_t n_full_rows = n_bytes_to_copy / row_size;
|
|
1183
|
-
const size_t n_rem_bytes = n_bytes_to_copy % row_size;
|
|
1184
|
-
|
|
1185
|
-
void * buf_pd = ggml_aligned_malloc(row_size_pd);
|
|
1186
|
-
GGML_ASSERT(buf_pd != NULL);
|
|
1187
|
-
|
|
1188
|
-
void * buf_rp = ggml_aligned_malloc(row_size_rp);
|
|
1189
|
-
GGML_ASSERT(buf_rp != NULL);
|
|
1190
|
-
|
|
1191
|
-
HEX_VERBOSE("ggml-hex: repack-q8x4x2-q8_0 %s : data %p size %zu dims %ldx%ld row-size %zu\n", t->name, data, size,
|
|
1192
|
-
t->ne[0], nrows, row_size);
|
|
1193
|
-
|
|
1194
|
-
memset(buf_pd, 0, row_size_pd); // clear-out padded buffer to make sure the tail is all zeros
|
|
1195
|
-
|
|
1196
|
-
// 1. Process all the full rows
|
|
1197
|
-
for (int64_t i = 0; i < n_full_rows; i++) {
|
|
1198
|
-
const uint8_t * src = (const uint8_t *) t->data + (i * row_size);
|
|
1199
|
-
uint8_t * dst = (uint8_t *) data + (i * row_size);
|
|
1200
|
-
|
|
1201
|
-
memcpy(buf_pd, src, row_size);
|
|
1202
|
-
unpack_row_q8x4x2((block_q8_0 *) buf_rp, (const uint8_t *) buf_pd, t->ne[0]);
|
|
1203
|
-
memcpy(dst, buf_rp, row_size);
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
// 2. Process the final, potentially partial, row
|
|
1207
|
-
if (n_rem_bytes > 0) {
|
|
1208
|
-
const int64_t i = n_full_rows;
|
|
1209
|
-
const uint8_t * src = (const uint8_t *) t->data + (i * row_size);
|
|
1210
|
-
uint8_t * dst = (uint8_t *) data + (i * row_size);
|
|
1211
|
-
|
|
1212
|
-
// We still need to read and unpack the entire source row because quantization is block-based.
|
|
1213
|
-
memcpy(buf_pd, src, row_size);
|
|
1214
|
-
unpack_row_q8x4x2((block_q8_0 *) buf_rp, (const uint8_t *) buf_pd, t->ne[0]);
|
|
1215
|
-
|
|
1216
|
-
// But we only copy the remaining number of bytes to the destination.
|
|
1217
|
-
memcpy(dst, buf_rp, n_rem_bytes);
|
|
1218
|
-
}
|
|
1219
|
-
|
|
1220
|
-
ggml_aligned_free(buf_pd, row_size_pd);
|
|
1221
|
-
ggml_aligned_free(buf_rp, row_size_rp);
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
// ======== MXFP4x4x2 ====================
|
|
1225
|
-
struct x2_mxfp4 {
|
|
1226
|
-
int v[2];
|
|
1227
|
-
};
|
|
1228
|
-
|
|
1229
|
-
static x2_mxfp4 unpack_mxfp4(uint8_t v) {
|
|
1230
|
-
x2_mxfp4 x;
|
|
1231
|
-
x.v[0] = kvalues_mxfp4[(v & 0x0f)];
|
|
1232
|
-
x.v[1] = kvalues_mxfp4[(v >> 4)];
|
|
1233
|
-
return x;
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
static void dump_block_mxfp4(const block_mxfp4 * b, int i) {
|
|
1237
|
-
HEX_VERBOSE("ggml-hex: repack mxfp4 %d: %d %d %d %d ... %d %d %d %d : %.6f\n", i, unpack_mxfp4(b->qs[0]).v[0],
|
|
1238
|
-
unpack_mxfp4(b->qs[1]).v[0], unpack_mxfp4(b->qs[2]).v[0], unpack_mxfp4(b->qs[3]).v[0],
|
|
1239
|
-
unpack_mxfp4(b->qs[12]).v[1], unpack_mxfp4(b->qs[13]).v[1], unpack_mxfp4(b->qs[14]).v[1],
|
|
1240
|
-
unpack_mxfp4(b->qs[15]).v[1], GGML_E8M0_TO_FP32_HALF(b->e));
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
static void dump_packed_block_mxfp4x4x2(const uint8_t * v, unsigned int i, size_t k) {
|
|
1244
|
-
static const int qk = QK_MXFP4x4x2;
|
|
1245
|
-
const int eblk_size = 8 * 1; // 8x E8M0
|
|
1246
|
-
const int qblk_size = qk / 2; // int4
|
|
1247
|
-
const int qrow_size = k / 2; // int4 (not padded)
|
|
1248
|
-
|
|
1249
|
-
const uint8_t * v_q = v + 0; // quants first
|
|
1250
|
-
const uint8_t * v_e = v + qrow_size; // then scales
|
|
1251
|
-
|
|
1252
|
-
const uint8_t * q = v_q + i * qblk_size;
|
|
1253
|
-
const uint8_t * e = (const uint8_t *) (v_e + i * eblk_size);
|
|
1254
|
-
|
|
1255
|
-
HEX_VERBOSE("ggml-hex: repack mxfp4x4x2-%d: %d %d %d %d ... %d %d %d %d ... %d %d %d %d : %.6f %.6f %.6f %.6f\n", i,
|
|
1256
|
-
unpack_mxfp4(q[0]).v[0], unpack_mxfp4(q[1]).v[0], unpack_mxfp4(q[2]).v[0], unpack_mxfp4(q[3]).v[0],
|
|
1257
|
-
unpack_mxfp4(q[60]).v[0], unpack_mxfp4(q[61]).v[0], unpack_mxfp4(q[62]).v[0], unpack_mxfp4(q[63]).v[0],
|
|
1258
|
-
unpack_mxfp4(q[124]).v[0], unpack_mxfp4(q[125]).v[0], unpack_mxfp4(q[126]).v[0],
|
|
1259
|
-
unpack_mxfp4(q[127]).v[0], GGML_E8M0_TO_FP32_HALF(e[0]), GGML_E8M0_TO_FP32_HALF(e[1]),
|
|
1260
|
-
GGML_E8M0_TO_FP32_HALF(e[2]), GGML_E8M0_TO_FP32_HALF(e[3]));
|
|
1261
|
-
|
|
1262
|
-
HEX_VERBOSE("ggml-hex: repack mxfp4x4x2-%d: %d %d %d %d ... %d %d %d %d ... %d %d %d %d : %.6f %.6f %.6f %.6f\n",
|
|
1263
|
-
i + 1, unpack_mxfp4(q[0]).v[1], unpack_mxfp4(q[1]).v[1], unpack_mxfp4(q[2]).v[1],
|
|
1264
|
-
unpack_mxfp4(q[3]).v[1], unpack_mxfp4(q[60]).v[1], unpack_mxfp4(q[61]).v[1], unpack_mxfp4(q[62]).v[1],
|
|
1265
|
-
unpack_mxfp4(q[63]).v[1], unpack_mxfp4(q[124]).v[1], unpack_mxfp4(q[125]).v[1],
|
|
1266
|
-
unpack_mxfp4(q[126]).v[1], unpack_mxfp4(q[127]).v[1], GGML_E8M0_TO_FP32_HALF(e[4]),
|
|
1267
|
-
GGML_E8M0_TO_FP32_HALF(e[5]), GGML_E8M0_TO_FP32_HALF(e[6]), GGML_E8M0_TO_FP32_HALF(e[7]));
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
424
|
static void unpack_mxfp4_quants(uint8_t * qs, const block_mxfp4 * x, unsigned int bi) {
|
|
1271
425
|
static const int qk = QK_MXFP4;
|
|
1272
426
|
|
|
1273
427
|
for (unsigned int i = 0; i < qk / 2; ++i) {
|
|
1274
|
-
const
|
|
1275
|
-
const
|
|
428
|
+
const int x0 = (x->qs[i] & 0x0F);
|
|
429
|
+
const int x1 = (x->qs[i] >> 4);
|
|
1276
430
|
qs[bi * qk + i + 0] = x0;
|
|
1277
431
|
qs[bi * qk + i + qk / 2] = x1;
|
|
1278
432
|
}
|
|
1279
433
|
}
|
|
1280
434
|
|
|
1281
435
|
static void pack_mxfp4_quants(block_mxfp4 * x, const uint8_t * qs, unsigned int bi) {
|
|
1282
|
-
static const int qk =
|
|
436
|
+
static const int qk = QK_MXFP4;
|
|
1283
437
|
|
|
1284
438
|
for (unsigned int i = 0; i < qk / 2; ++i) {
|
|
1285
439
|
const uint8_t x0 = qs[bi * qk + i + 0];
|
|
@@ -1288,299 +442,419 @@ static void pack_mxfp4_quants(block_mxfp4 * x, const uint8_t * qs, unsigned int
|
|
|
1288
442
|
}
|
|
1289
443
|
}
|
|
1290
444
|
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
const
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
445
|
+
// repack q4_0 data into q4_0_tiled tensor
|
|
446
|
+
static void repack_q4_0_tiled(ggml_tensor * t, const void * data, size_t size) {
|
|
447
|
+
const block_q4_0 * src_matrix = (const block_q4_0 *) data;
|
|
448
|
+
int64_t ne0 = t->ne[0];
|
|
449
|
+
int64_t ne1 = t->ne[1];
|
|
450
|
+
int64_t ne2 = t->ne[2];
|
|
451
|
+
int64_t ne3 = t->ne[3];
|
|
452
|
+
int64_t ne0_padded = hex_round_up(ne0, 32);
|
|
453
|
+
int64_t ne1_padded = hex_round_up(ne1, 32);
|
|
454
|
+
|
|
455
|
+
int n_col_tiles = ne1_padded / 32;
|
|
456
|
+
int n_k_tiles = ne0_padded / 32;
|
|
457
|
+
const size_t tile_size = HTP_MM_WEIGHT_TILE_SIZE_Q4_0;
|
|
458
|
+
const size_t matrix_size = n_col_tiles * n_k_tiles * tile_size;
|
|
459
|
+
|
|
460
|
+
for (int i3 = 0; i3 < ne3; i3++) {
|
|
461
|
+
for (int i2 = 0; i2 < ne2; i2++) {
|
|
462
|
+
const block_q4_0 * src_expert = src_matrix + (i3 * ne2 + i2) * (ne1 * (ne0 / 32));
|
|
463
|
+
uint8_t * matrix_dst = (uint8_t *) t->data + (i3 * ne2 + i2) * matrix_size;
|
|
464
|
+
|
|
465
|
+
for (int ct = 0; ct < n_col_tiles; ct++) {
|
|
466
|
+
for (int kt = 0; kt < n_k_tiles; kt++) {
|
|
467
|
+
uint8_t * tile_dst = matrix_dst + (ct * n_k_tiles + kt) * tile_size;
|
|
468
|
+
|
|
469
|
+
uint8_t tile_quants[32][32];
|
|
470
|
+
for (int row = 0; row < 32; row++) {
|
|
471
|
+
int64_t r = ct * 32 + row;
|
|
472
|
+
if (r < ne1 && kt < ne0 / 32) {
|
|
473
|
+
unpack_q4_0_quants(tile_quants[row], &src_expert[r * (ne0 / 32) + kt], 0);
|
|
474
|
+
} else {
|
|
475
|
+
memset(tile_quants[row], 8, 32);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
for (int cp = 0; cp < 16; cp++) {
|
|
480
|
+
for (int row = 0; row < 32; row++) {
|
|
481
|
+
tile_dst[cp * 32 + row] = (tile_quants[row][2 * cp + 1] << 4) | tile_quants[row][2 * cp];
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
ggml_half * scale_dst = (ggml_half *)(tile_dst + 512);
|
|
486
|
+
for (int row = 0; row < 32; row++) {
|
|
487
|
+
int64_t r = ct * 32 + row;
|
|
488
|
+
scale_dst[row] = (r < ne1 && kt < ne0 / 32) ? src_expert[r * (ne0 / 32) + kt].d : 0;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
1313
492
|
}
|
|
1314
493
|
}
|
|
494
|
+
}
|
|
1315
495
|
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
for (int
|
|
1333
|
-
|
|
496
|
+
// repack q4_0_tiled tensor into q4_0 data
|
|
497
|
+
static void repack_tiled_q4_0(void * data, const ggml_tensor * t, size_t size) {
|
|
498
|
+
block_q4_0 * dst_matrix = (block_q4_0 *) data;
|
|
499
|
+
int64_t ne0 = t->ne[0];
|
|
500
|
+
int64_t ne1 = t->ne[1];
|
|
501
|
+
int64_t ne2 = t->ne[2];
|
|
502
|
+
int64_t ne3 = t->ne[3];
|
|
503
|
+
int64_t ne0_padded = hex_round_up(ne0, 32);
|
|
504
|
+
int64_t ne1_padded = hex_round_up(ne1, 32);
|
|
505
|
+
|
|
506
|
+
int n_col_tiles = ne1_padded / 32;
|
|
507
|
+
int n_k_tiles = ne0_padded / 32;
|
|
508
|
+
const size_t tile_size = HTP_MM_WEIGHT_TILE_SIZE_Q4_0;
|
|
509
|
+
const size_t matrix_size = n_col_tiles * n_k_tiles * tile_size;
|
|
510
|
+
|
|
511
|
+
for (int i3 = 0; i3 < ne3; i3++) {
|
|
512
|
+
for (int i2 = 0; i2 < ne2; i2++) {
|
|
513
|
+
block_q4_0 * dst_expert = dst_matrix + (i3 * ne2 + i2) * (ne1 * (ne0 / 32));
|
|
514
|
+
const uint8_t * matrix_src = (const uint8_t *) t->data + (i3 * ne2 + i2) * matrix_size;
|
|
515
|
+
|
|
516
|
+
for (int ct = 0; ct < n_col_tiles; ct++) {
|
|
517
|
+
for (int kt = 0; kt < n_k_tiles; kt++) {
|
|
518
|
+
const uint8_t * tile_src = matrix_src + (ct * n_k_tiles + kt) * tile_size;
|
|
519
|
+
|
|
520
|
+
uint8_t tile_quants[32][32];
|
|
521
|
+
for (int cp = 0; cp < 16; cp++) {
|
|
522
|
+
for (int row = 0; row < 32; row++) {
|
|
523
|
+
uint8_t val = tile_src[cp * 32 + row];
|
|
524
|
+
tile_quants[row][2 * cp + 0] = val & 0x0F;
|
|
525
|
+
tile_quants[row][2 * cp + 1] = val >> 4;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
for (int row = 0; row < 32; row++) {
|
|
530
|
+
int64_t r = ct * 32 + row;
|
|
531
|
+
if (r < ne1 && kt < ne0 / 32) {
|
|
532
|
+
pack_q4_0_quants(&dst_expert[r * (ne0 / 32) + kt], tile_quants[row], 0);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const ggml_half * scale_src = (const ggml_half *)(tile_src + 512);
|
|
537
|
+
for (int row = 0; row < 32; row++) {
|
|
538
|
+
int64_t r = ct * 32 + row;
|
|
539
|
+
if (r < ne1 && kt < ne0 / 32) {
|
|
540
|
+
dst_expert[r * (ne0 / 32) + kt].d = scale_src[row];
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
1334
545
|
}
|
|
1335
546
|
}
|
|
547
|
+
}
|
|
1336
548
|
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
549
|
+
// repack q4_1 data into q4_1_tiled tensor
|
|
550
|
+
static void repack_q4_1_tiled(ggml_tensor * t, const void * data, size_t size) {
|
|
551
|
+
const block_q4_1 * src_matrix = (const block_q4_1 *) data;
|
|
552
|
+
int64_t ne0 = t->ne[0];
|
|
553
|
+
int64_t ne1 = t->ne[1];
|
|
554
|
+
int64_t ne2 = t->ne[2];
|
|
555
|
+
int64_t ne3 = t->ne[3];
|
|
556
|
+
int64_t ne0_padded = hex_round_up(ne0, 32);
|
|
557
|
+
int64_t ne1_padded = hex_round_up(ne1, 32);
|
|
558
|
+
|
|
559
|
+
int n_col_tiles = ne1_padded / 32;
|
|
560
|
+
int n_k_tiles = ne0_padded / 32;
|
|
561
|
+
const size_t tile_size = HTP_MM_WEIGHT_TILE_SIZE_Q4_1;
|
|
562
|
+
const size_t matrix_size = n_col_tiles * n_k_tiles * tile_size;
|
|
563
|
+
|
|
564
|
+
for (int i3 = 0; i3 < ne3; i3++) {
|
|
565
|
+
for (int i2 = 0; i2 < ne2; i2++) {
|
|
566
|
+
const block_q4_1 * src_expert = src_matrix + (i3 * ne2 + i2) * (ne1 * (ne0 / 32));
|
|
567
|
+
uint8_t * matrix_dst = (uint8_t *) t->data + (i3 * ne2 + i2) * matrix_size;
|
|
568
|
+
|
|
569
|
+
for (int ct = 0; ct < n_col_tiles; ct++) {
|
|
570
|
+
for (int kt = 0; kt < n_k_tiles; kt++) {
|
|
571
|
+
uint8_t * tile_dst = matrix_dst + (ct * n_k_tiles + kt) * tile_size;
|
|
572
|
+
|
|
573
|
+
uint8_t tile_quants[32][32];
|
|
574
|
+
for (int row = 0; row < 32; row++) {
|
|
575
|
+
int64_t r = ct * 32 + row;
|
|
576
|
+
if (r < ne1 && kt < ne0 / 32) {
|
|
577
|
+
unpack_q4_1_quants(tile_quants[row], &src_expert[r * (ne0 / 32) + kt], 0);
|
|
578
|
+
} else {
|
|
579
|
+
memset(tile_quants[row], 0, 32);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
for (int cp = 0; cp < 16; cp++) {
|
|
584
|
+
for (int row = 0; row < 32; row++) {
|
|
585
|
+
tile_dst[cp * 32 + row] = (tile_quants[row][2 * cp + 1] << 4) | tile_quants[row][2 * cp];
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
ggml_half * scale_dst = (ggml_half *)(tile_dst + 512);
|
|
590
|
+
for (int row = 0; row < 32; row++) {
|
|
591
|
+
int64_t r = ct * 32 + row;
|
|
592
|
+
if (r < ne1 && kt < ne0 / 32) {
|
|
593
|
+
scale_dst[2 * row + 0] = src_expert[r * (ne0 / 32) + kt].d;
|
|
594
|
+
scale_dst[2 * row + 1] = src_expert[r * (ne0 / 32) + kt].m;
|
|
595
|
+
} else {
|
|
596
|
+
scale_dst[2 * row + 0] = 0;
|
|
597
|
+
scale_dst[2 * row + 1] = 0;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
1356
602
|
}
|
|
1357
603
|
}
|
|
1358
604
|
}
|
|
1359
605
|
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
606
|
+
// repack q4_1_tiled tensor into q4_1 data
|
|
607
|
+
static void repack_tiled_q4_1(void * data, const ggml_tensor * t, size_t size) {
|
|
608
|
+
block_q4_1 * dst_matrix = (block_q4_1 *) data;
|
|
609
|
+
int64_t ne0 = t->ne[0];
|
|
610
|
+
int64_t ne1 = t->ne[1];
|
|
611
|
+
int64_t ne2 = t->ne[2];
|
|
612
|
+
int64_t ne3 = t->ne[3];
|
|
613
|
+
int64_t ne0_padded = hex_round_up(ne0, 32);
|
|
614
|
+
int64_t ne1_padded = hex_round_up(ne1, 32);
|
|
615
|
+
|
|
616
|
+
int n_col_tiles = ne1_padded / 32;
|
|
617
|
+
int n_k_tiles = ne0_padded / 32;
|
|
618
|
+
const size_t tile_size = HTP_MM_WEIGHT_TILE_SIZE_Q4_1;
|
|
619
|
+
const size_t matrix_size = n_col_tiles * n_k_tiles * tile_size;
|
|
620
|
+
|
|
621
|
+
for (int i3 = 0; i3 < ne3; i3++) {
|
|
622
|
+
for (int i2 = 0; i2 < ne2; i2++) {
|
|
623
|
+
block_q4_1 * dst_expert = dst_matrix + (i3 * ne2 + i2) * (ne1 * (ne0 / 32));
|
|
624
|
+
const uint8_t * matrix_src = (const uint8_t *) t->data + (i3 * ne2 + i2) * matrix_size;
|
|
625
|
+
|
|
626
|
+
for (int ct = 0; ct < n_col_tiles; ct++) {
|
|
627
|
+
for (int kt = 0; kt < n_k_tiles; kt++) {
|
|
628
|
+
const uint8_t * tile_src = matrix_src + (ct * n_k_tiles + kt) * tile_size;
|
|
629
|
+
|
|
630
|
+
uint8_t tile_quants[32][32];
|
|
631
|
+
for (int cp = 0; cp < 16; cp++) {
|
|
632
|
+
for (int row = 0; row < 32; row++) {
|
|
633
|
+
uint8_t val = tile_src[cp * 32 + row];
|
|
634
|
+
tile_quants[row][2 * cp + 0] = val & 0x0F;
|
|
635
|
+
tile_quants[row][2 * cp + 1] = val >> 4;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
for (int row = 0; row < 32; row++) {
|
|
640
|
+
int64_t r = ct * 32 + row;
|
|
641
|
+
if (r < ne1 && kt < ne0 / 32) {
|
|
642
|
+
pack_q4_1_quants(&dst_expert[r * (ne0 / 32) + kt], tile_quants[row], 0);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
const ggml_half * scale_src = (const ggml_half *)(tile_src + 512);
|
|
647
|
+
for (int row = 0; row < 32; row++) {
|
|
648
|
+
int64_t r = ct * 32 + row;
|
|
649
|
+
if (r < ne1 && kt < ne0 / 32) {
|
|
650
|
+
dst_expert[r * (ne0 / 32) + kt].d = scale_src[2 * row];
|
|
651
|
+
dst_expert[r * (ne0 / 32) + kt].m = scale_src[2 * row + 1];
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
1375
656
|
}
|
|
1376
657
|
}
|
|
658
|
+
}
|
|
1377
659
|
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
660
|
+
// repack q8_0 data into q8_0_tiled tensor
|
|
661
|
+
static void repack_q8_0_tiled(ggml_tensor * t, const void * data, size_t size) {
|
|
662
|
+
const block_q8_0 * src_matrix = (const block_q8_0 *) data;
|
|
663
|
+
int64_t ne0 = t->ne[0];
|
|
664
|
+
int64_t ne1 = t->ne[1];
|
|
665
|
+
int64_t ne2 = t->ne[2];
|
|
666
|
+
int64_t ne3 = t->ne[3];
|
|
667
|
+
int64_t ne0_padded = hex_round_up(ne0, 32);
|
|
668
|
+
int64_t ne1_padded = hex_round_up(ne1, 32);
|
|
669
|
+
|
|
670
|
+
int n_col_tiles = ne1_padded / 32;
|
|
671
|
+
int n_k_tiles = ne0_padded / 32;
|
|
672
|
+
const size_t tile_size = HTP_MM_WEIGHT_TILE_SIZE_Q8_0;
|
|
673
|
+
const size_t matrix_size = n_col_tiles * n_k_tiles * tile_size;
|
|
674
|
+
|
|
675
|
+
for (int i3 = 0; i3 < ne3; i3++) {
|
|
676
|
+
for (int i2 = 0; i2 < ne2; i2++) {
|
|
677
|
+
const block_q8_0 * src_expert = src_matrix + (i3 * ne2 + i2) * (ne1 * (ne0 / 32));
|
|
678
|
+
uint8_t * matrix_dst = (uint8_t *) t->data + (i3 * ne2 + i2) * matrix_size;
|
|
679
|
+
|
|
680
|
+
for (int ct = 0; ct < n_col_tiles; ct++) {
|
|
681
|
+
for (int kt = 0; kt < n_k_tiles; kt++) {
|
|
682
|
+
uint8_t * tile_dst = matrix_dst + (ct * n_k_tiles + kt) * tile_size;
|
|
683
|
+
|
|
684
|
+
for (int cp = 0; cp < 16; cp++) {
|
|
685
|
+
int col0 = cp * 2;
|
|
686
|
+
int col1 = col0 + 1;
|
|
687
|
+
for (int row = 0; row < 32; row++) {
|
|
688
|
+
int64_t r = ct * 32 + row;
|
|
689
|
+
const block_q8_0 * b = (r < ne1 && kt < ne0 / 32) ? &src_expert[r * (ne0 / 32) + kt] : NULL;
|
|
690
|
+
tile_dst[cp * 64 + 2 * row + 0] = b ? b->qs[col0] : 0;
|
|
691
|
+
tile_dst[cp * 64 + 2 * row + 1] = b ? b->qs[col1] : 0;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
ggml_half * scale_dst = (ggml_half *)(tile_dst + 1024);
|
|
696
|
+
for (int row = 0; row < 32; row++) {
|
|
697
|
+
int64_t r = ct * 32 + row;
|
|
698
|
+
scale_dst[row] = (r < ne1 && kt < ne0 / 32) ? src_expert[r * (ne0 / 32) + kt].d : 0;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
1392
701
|
}
|
|
1393
702
|
}
|
|
1394
|
-
|
|
1395
|
-
pack_mxfp4_quants(&x[i * 8 + 0], qs, 0);
|
|
1396
|
-
pack_mxfp4_quants(&x[i * 8 + 1], qs, 1);
|
|
1397
|
-
pack_mxfp4_quants(&x[i * 8 + 2], qs, 2);
|
|
1398
|
-
pack_mxfp4_quants(&x[i * 8 + 3], qs, 3);
|
|
1399
|
-
pack_mxfp4_quants(&x[i * 8 + 4], qs, 4);
|
|
1400
|
-
pack_mxfp4_quants(&x[i * 8 + 5], qs, 5);
|
|
1401
|
-
pack_mxfp4_quants(&x[i * 8 + 6], qs, 6);
|
|
1402
|
-
pack_mxfp4_quants(&x[i * 8 + 7], qs, 7);
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
|
-
// Repack the scales
|
|
1406
|
-
// Note: Do not combine with the loop above. For tensor sizes not multiple of 256 (QK_MXFP4_0x4x2)
|
|
1407
|
-
// the last block is truncated and overridden by the scales.
|
|
1408
|
-
for (int i = 0; i < nb; i++) {
|
|
1409
|
-
// Unpack the scales
|
|
1410
|
-
const uint8_t * e = (const uint8_t *) (y_e + i * eblk_size);
|
|
1411
|
-
x[i * 8 + 0].e = e[0];
|
|
1412
|
-
x[i * 8 + 1].e = e[1];
|
|
1413
|
-
x[i * 8 + 2].e = e[2];
|
|
1414
|
-
x[i * 8 + 3].e = e[3];
|
|
1415
|
-
x[i * 8 + 4].e = e[4];
|
|
1416
|
-
x[i * 8 + 5].e = e[5];
|
|
1417
|
-
x[i * 8 + 6].e = e[6];
|
|
1418
|
-
x[i * 8 + 7].e = e[7];
|
|
1419
|
-
}
|
|
1420
|
-
|
|
1421
|
-
if (opt_verbose > 2) {
|
|
1422
|
-
for (int i = 0; i < nb; i++) {
|
|
1423
|
-
dump_block_mxfp4(&x[i * 8 + 0], 0);
|
|
1424
|
-
dump_block_mxfp4(&x[i * 8 + 1], 1);
|
|
1425
|
-
dump_block_mxfp4(&x[i * 8 + 2], 2);
|
|
1426
|
-
dump_block_mxfp4(&x[i * 8 + 3], 3);
|
|
1427
|
-
dump_block_mxfp4(&x[i * 8 + 4], 4);
|
|
1428
|
-
dump_block_mxfp4(&x[i * 8 + 5], 5);
|
|
1429
|
-
dump_block_mxfp4(&x[i * 8 + 6], 6);
|
|
1430
|
-
dump_block_mxfp4(&x[i * 8 + 7], 7);
|
|
1431
|
-
}
|
|
1432
703
|
}
|
|
1433
704
|
}
|
|
1434
705
|
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
706
|
+
// repack q8_0_tiled tensor into q8_0 data
|
|
707
|
+
static void repack_tiled_q8_0(void * data, const ggml_tensor * t, size_t size) {
|
|
708
|
+
block_q8_0 * dst_matrix = (block_q8_0 *) data;
|
|
709
|
+
int64_t ne0 = t->ne[0];
|
|
710
|
+
int64_t ne1 = t->ne[1];
|
|
711
|
+
int64_t ne2 = t->ne[2];
|
|
712
|
+
int64_t ne3 = t->ne[3];
|
|
713
|
+
int64_t ne0_padded = hex_round_up(ne0, 32);
|
|
714
|
+
int64_t ne1_padded = hex_round_up(ne1, 32);
|
|
715
|
+
|
|
716
|
+
int n_col_tiles = ne1_padded / 32;
|
|
717
|
+
int n_k_tiles = ne0_padded / 32;
|
|
718
|
+
const size_t tile_size = HTP_MM_WEIGHT_TILE_SIZE_Q8_0;
|
|
719
|
+
const size_t matrix_size = n_col_tiles * n_k_tiles * tile_size;
|
|
720
|
+
|
|
721
|
+
for (int i3 = 0; i3 < ne3; i3++) {
|
|
722
|
+
for (int i2 = 0; i2 < ne2; i2++) {
|
|
723
|
+
block_q8_0 * dst_expert = dst_matrix + (i3 * ne2 + i2) * (ne1 * (ne0 / 32));
|
|
724
|
+
const uint8_t * matrix_src = (const uint8_t *) t->data + (i3 * ne2 + i2) * matrix_size;
|
|
725
|
+
|
|
726
|
+
for (int ct = 0; ct < n_col_tiles; ct++) {
|
|
727
|
+
for (int kt = 0; kt < n_k_tiles; kt++) {
|
|
728
|
+
const uint8_t * tile_src = matrix_src + (ct * n_k_tiles + kt) * tile_size;
|
|
729
|
+
|
|
730
|
+
for (int cp = 0; cp < 16; cp++) {
|
|
731
|
+
int col0 = cp * 2;
|
|
732
|
+
int col1 = col0 + 1;
|
|
733
|
+
for (int row = 0; row < 32; row++) {
|
|
734
|
+
int64_t r = ct * 32 + row;
|
|
735
|
+
if (r < ne1 && kt < ne0 / 32) {
|
|
736
|
+
block_q8_0 & b = dst_expert[r * (ne0 / 32) + kt];
|
|
737
|
+
b.qs[col0] = tile_src[cp * 64 + 2 * row + 0];
|
|
738
|
+
b.qs[col1] = tile_src[cp * 64 + 2 * row + 1];
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
const ggml_half * scale_src = (const ggml_half *)(tile_src + 1024);
|
|
744
|
+
for (int row = 0; row < 32; row++) {
|
|
745
|
+
int64_t r = ct * 32 + row;
|
|
746
|
+
if (r < ne1 && kt < ne0 / 32) {
|
|
747
|
+
dst_expert[r * (ne0 / 32) + kt].d = scale_src[row];
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
1467
753
|
}
|
|
1468
754
|
}
|
|
1469
755
|
|
|
1470
|
-
// repack mxfp4 data into
|
|
1471
|
-
static void
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
memcpy(buf_pd, src, n_rem_bytes);
|
|
1519
|
-
|
|
1520
|
-
// Repack the entire buffer (partial data + zero padding).
|
|
1521
|
-
repack_row_mxfp4x4x2((uint8_t *) buf_rp, (const block_mxfp4 *) buf_pd, t->ne[0]);
|
|
1522
|
-
|
|
1523
|
-
// Write only the corresponding remaining bytes to the destination tensor.
|
|
1524
|
-
memcpy(dst, buf_rp, n_rem_bytes);
|
|
756
|
+
// repack mxfp4 data into mxfp4_tiled tensor
|
|
757
|
+
static void repack_mxfp4_tiled(ggml_tensor * t, const void * data, size_t size) {
|
|
758
|
+
const block_mxfp4 * src_matrix = (const block_mxfp4 *) data;
|
|
759
|
+
int64_t ne0 = t->ne[0];
|
|
760
|
+
int64_t ne1 = t->ne[1];
|
|
761
|
+
int64_t ne2 = t->ne[2];
|
|
762
|
+
int64_t ne3 = t->ne[3];
|
|
763
|
+
int64_t ne0_padded = hex_round_up(ne0, 32);
|
|
764
|
+
int64_t ne1_padded = hex_round_up(ne1, 32);
|
|
765
|
+
|
|
766
|
+
int n_col_tiles = ne1_padded / 32;
|
|
767
|
+
int n_k_tiles = ne0_padded / 32;
|
|
768
|
+
const size_t tile_size = HTP_MM_WEIGHT_TILE_SIZE_MXFP4;
|
|
769
|
+
const size_t matrix_size = n_col_tiles * n_k_tiles * tile_size;
|
|
770
|
+
|
|
771
|
+
for (int i3 = 0; i3 < ne3; i3++) {
|
|
772
|
+
for (int i2 = 0; i2 < ne2; i2++) {
|
|
773
|
+
const block_mxfp4 * src_expert = src_matrix + (i3 * ne2 + i2) * (ne1 * (ne0 / 32));
|
|
774
|
+
uint8_t * matrix_dst = (uint8_t *) t->data + (i3 * ne2 + i2) * matrix_size;
|
|
775
|
+
|
|
776
|
+
for (int ct = 0; ct < n_col_tiles; ct++) {
|
|
777
|
+
for (int kt = 0; kt < n_k_tiles; kt++) {
|
|
778
|
+
uint8_t * tile_dst = matrix_dst + (ct * n_k_tiles + kt) * tile_size;
|
|
779
|
+
|
|
780
|
+
uint8_t tile_quants[32][32];
|
|
781
|
+
for (int row = 0; row < 32; row++) {
|
|
782
|
+
int64_t r = ct * 32 + row;
|
|
783
|
+
if (r < ne1 && kt < ne0 / 32) {
|
|
784
|
+
unpack_mxfp4_quants(tile_quants[row], &src_expert[r * (ne0 / 32) + kt], 0);
|
|
785
|
+
} else {
|
|
786
|
+
memset(tile_quants[row], 0, 32);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
for (int cp = 0; cp < 16; cp++) {
|
|
791
|
+
for (int row = 0; row < 32; row++) {
|
|
792
|
+
tile_dst[cp * 32 + row] = (tile_quants[row][2 * cp + 1] << 4) | tile_quants[row][2 * cp];
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
uint8_t * scale_dst = tile_dst + 512;
|
|
797
|
+
for (int row = 0; row < 32; row++) {
|
|
798
|
+
int64_t r = ct * 32 + row;
|
|
799
|
+
scale_dst[row] = (r < ne1 && kt < ne0 / 32) ? src_expert[r * (ne0 / 32) + kt].e : 0;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
1525
804
|
}
|
|
1526
|
-
|
|
1527
|
-
ggml_aligned_free(buf_pd, row_size_pd);
|
|
1528
|
-
ggml_aligned_free(buf_rp, row_size_rp);
|
|
1529
805
|
}
|
|
1530
806
|
|
|
1531
|
-
// repack
|
|
1532
|
-
static void
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
const
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
807
|
+
// repack mxfp4_tiled tensor into mxfp4 data
|
|
808
|
+
static void repack_tiled_mxfp4(void * data, const ggml_tensor * t, size_t size) {
|
|
809
|
+
block_mxfp4 * dst_matrix = (block_mxfp4 *) data;
|
|
810
|
+
int64_t ne0 = t->ne[0];
|
|
811
|
+
int64_t ne1 = t->ne[1];
|
|
812
|
+
int64_t ne2 = t->ne[2];
|
|
813
|
+
int64_t ne3 = t->ne[3];
|
|
814
|
+
int64_t ne0_padded = hex_round_up(ne0, 32);
|
|
815
|
+
int64_t ne1_padded = hex_round_up(ne1, 32);
|
|
816
|
+
|
|
817
|
+
int n_col_tiles = ne1_padded / 32;
|
|
818
|
+
int n_k_tiles = ne0_padded / 32;
|
|
819
|
+
const size_t tile_size = HTP_MM_WEIGHT_TILE_SIZE_MXFP4;
|
|
820
|
+
const size_t matrix_size = n_col_tiles * n_k_tiles * tile_size;
|
|
821
|
+
|
|
822
|
+
for (int i3 = 0; i3 < ne3; i3++) {
|
|
823
|
+
for (int i2 = 0; i2 < ne2; i2++) {
|
|
824
|
+
block_mxfp4 * dst_expert = dst_matrix + (i3 * ne2 + i2) * (ne1 * (ne0 / 32));
|
|
825
|
+
const uint8_t * matrix_src = (const uint8_t *) t->data + (i3 * ne2 + i2) * matrix_size;
|
|
826
|
+
|
|
827
|
+
for (int ct = 0; ct < n_col_tiles; ct++) {
|
|
828
|
+
for (int kt = 0; kt < n_k_tiles; kt++) {
|
|
829
|
+
const uint8_t * tile_src = matrix_src + (ct * n_k_tiles + kt) * tile_size;
|
|
830
|
+
|
|
831
|
+
uint8_t tile_quants[32][32];
|
|
832
|
+
for (int cp = 0; cp < 16; cp++) {
|
|
833
|
+
for (int row = 0; row < 32; row++) {
|
|
834
|
+
uint8_t val = tile_src[cp * 32 + row];
|
|
835
|
+
tile_quants[row][2 * cp + 0] = val & 0x0F;
|
|
836
|
+
tile_quants[row][2 * cp + 1] = val >> 4;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
for (int row = 0; row < 32; row++) {
|
|
841
|
+
int64_t r = ct * 32 + row;
|
|
842
|
+
if (r < ne1 && kt < ne0 / 32) {
|
|
843
|
+
pack_mxfp4_quants(&dst_expert[r * (ne0 / 32) + kt], tile_quants[row], 0);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
const uint8_t * scale_src = tile_src + 512;
|
|
848
|
+
for (int row = 0; row < 32; row++) {
|
|
849
|
+
int64_t r = ct * 32 + row;
|
|
850
|
+
if (r < ne1 && kt < ne0 / 32) {
|
|
851
|
+
dst_expert[r * (ne0 / 32) + kt].e = scale_src[row];
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
1580
857
|
}
|
|
1581
|
-
|
|
1582
|
-
ggml_aligned_free(buf_pd, row_size_pd);
|
|
1583
|
-
ggml_aligned_free(buf_rp, row_size_rp);
|
|
1584
858
|
}
|
|
1585
859
|
|
|
1586
860
|
static void ggml_backend_hexagon_buffer_set_tensor(ggml_backend_buffer_t buffer,
|
|
@@ -1597,32 +871,32 @@ static void ggml_backend_hexagon_buffer_set_tensor(ggml_backend_buffer_t buffer,
|
|
|
1597
871
|
case GGML_TYPE_Q4_0:
|
|
1598
872
|
GGML_ASSERT(offset == 0);
|
|
1599
873
|
GGML_ASSERT(offset + size <= ggml_nbytes(tensor));
|
|
1600
|
-
|
|
874
|
+
repack_q4_0_tiled(tensor, data, size);
|
|
1601
875
|
break;
|
|
1602
876
|
|
|
1603
877
|
case GGML_TYPE_Q4_1:
|
|
1604
878
|
GGML_ASSERT(offset == 0);
|
|
1605
879
|
GGML_ASSERT(offset + size <= ggml_nbytes(tensor));
|
|
1606
|
-
|
|
880
|
+
repack_q4_1_tiled(tensor, data, size);
|
|
1607
881
|
break;
|
|
1608
882
|
|
|
1609
883
|
case GGML_TYPE_Q8_0:
|
|
1610
884
|
GGML_ASSERT(offset == 0);
|
|
1611
885
|
GGML_ASSERT(offset + size <= ggml_nbytes(tensor));
|
|
1612
|
-
|
|
886
|
+
repack_q8_0_tiled(tensor, data, size);
|
|
1613
887
|
break;
|
|
1614
888
|
|
|
1615
889
|
case GGML_TYPE_IQ4_NL:
|
|
1616
890
|
GGML_ASSERT(offset == 0);
|
|
1617
891
|
GGML_ASSERT(offset + size <= ggml_nbytes(tensor));
|
|
1618
892
|
// IQ4_NL has identical block layout to Q4_0 (ggml_half d + uint8_t qs[16])
|
|
1619
|
-
|
|
893
|
+
repack_q4_0_tiled(tensor, data, size);
|
|
1620
894
|
break;
|
|
1621
895
|
|
|
1622
896
|
case GGML_TYPE_MXFP4:
|
|
1623
897
|
GGML_ASSERT(offset == 0);
|
|
1624
898
|
GGML_ASSERT(offset + size <= ggml_nbytes(tensor));
|
|
1625
|
-
|
|
899
|
+
repack_mxfp4_tiled(tensor, data, size);
|
|
1626
900
|
break;
|
|
1627
901
|
|
|
1628
902
|
default:
|
|
@@ -1645,31 +919,31 @@ static void ggml_backend_hexagon_buffer_get_tensor(ggml_backend_buffer_t buffer,
|
|
|
1645
919
|
case GGML_TYPE_Q4_0:
|
|
1646
920
|
GGML_ASSERT(offset == 0);
|
|
1647
921
|
GGML_ASSERT(offset + size <= ggml_nbytes(tensor));
|
|
1648
|
-
|
|
922
|
+
repack_tiled_q4_0(data, tensor, size);
|
|
1649
923
|
break;
|
|
1650
924
|
|
|
1651
925
|
case GGML_TYPE_Q4_1:
|
|
1652
926
|
GGML_ASSERT(offset == 0);
|
|
1653
927
|
GGML_ASSERT(offset + size <= ggml_nbytes(tensor));
|
|
1654
|
-
|
|
928
|
+
repack_tiled_q4_1(data, tensor, size);
|
|
1655
929
|
break;
|
|
1656
930
|
|
|
1657
931
|
case GGML_TYPE_Q8_0:
|
|
1658
932
|
GGML_ASSERT(offset == 0);
|
|
1659
933
|
GGML_ASSERT(offset + size <= ggml_nbytes(tensor));
|
|
1660
|
-
|
|
934
|
+
repack_tiled_q8_0(data, tensor, size);
|
|
1661
935
|
break;
|
|
1662
936
|
|
|
1663
937
|
case GGML_TYPE_IQ4_NL:
|
|
1664
938
|
GGML_ASSERT(offset == 0);
|
|
1665
939
|
GGML_ASSERT(offset + size <= ggml_nbytes(tensor));
|
|
1666
|
-
|
|
940
|
+
repack_tiled_q4_0(data, tensor, size);
|
|
1667
941
|
break;
|
|
1668
942
|
|
|
1669
943
|
case GGML_TYPE_MXFP4:
|
|
1670
944
|
GGML_ASSERT(offset == 0);
|
|
1671
945
|
GGML_ASSERT(offset + size <= ggml_nbytes(tensor));
|
|
1672
|
-
|
|
946
|
+
repack_tiled_mxfp4(data, tensor, size);
|
|
1673
947
|
break;
|
|
1674
948
|
|
|
1675
949
|
default:
|
|
@@ -1747,12 +1021,19 @@ static size_t ggml_backend_hexagon_buffer_type_get_alignment(ggml_backend_buffer
|
|
|
1747
1021
|
}
|
|
1748
1022
|
|
|
1749
1023
|
static size_t ggml_backend_hexagon_buffer_type_get_alloc_size(ggml_backend_buffer_type_t buft, const struct ggml_tensor * t) {
|
|
1024
|
+
if (t->type == GGML_TYPE_Q4_0 || t->type == GGML_TYPE_Q4_1 || t->type == GGML_TYPE_Q8_0 || t->type == GGML_TYPE_IQ4_NL || t->type == GGML_TYPE_MXFP4) {
|
|
1025
|
+
int64_t ne0 = hex_round_up(t->ne[0], 32);
|
|
1026
|
+
int64_t ne1 = hex_round_up(t->ne[1], 32);
|
|
1027
|
+
int64_t ne2 = t->ne[2];
|
|
1028
|
+
int64_t ne3 = t->ne[3];
|
|
1029
|
+
return ggml_row_size(t->type, ne0) * ne1 * ne2 * ne3;
|
|
1030
|
+
}
|
|
1750
1031
|
return ggml_nbytes(t);
|
|
1751
1032
|
}
|
|
1752
1033
|
|
|
1753
1034
|
static size_t ggml_backend_hexagon_buffer_type_get_max_size(ggml_backend_buffer_type_t buffer_type) {
|
|
1754
|
-
|
|
1755
|
-
|
|
1035
|
+
auto * context = static_cast<ggml_backend_hexagon_buffer_type_context *>(buffer_type->context);
|
|
1036
|
+
return context->sess->max_bufsize;
|
|
1756
1037
|
}
|
|
1757
1038
|
|
|
1758
1039
|
static bool ggml_backend_hexagon_buffer_type_is_host(ggml_backend_buffer_type_t buft) {
|
|
@@ -1783,6 +1064,17 @@ static ggml_backend_buffer_type_i ggml_backend_hexagon_repack_buffer_type_interf
|
|
|
1783
1064
|
/* .is_host = */ ggml_backend_hexagon_repack_buffer_type_is_host,
|
|
1784
1065
|
};
|
|
1785
1066
|
|
|
1067
|
+
static bool ggml_backend_buffer_is_hexagon(const struct ggml_backend_buffer * b) {
|
|
1068
|
+
return b->buft->iface.get_alignment == ggml_backend_hexagon_buffer_type_get_alignment;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
static inline bool ggml_backend_buffer_is_hexagon_repack(const struct ggml_backend_buffer * b) {
|
|
1072
|
+
if (!opt_hostbuf) {
|
|
1073
|
+
return ggml_backend_buffer_is_hexagon(b);
|
|
1074
|
+
}
|
|
1075
|
+
return b->buft->iface.alloc_buffer == ggml_backend_hexagon_repack_buffer_type_alloc_buffer;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1786
1078
|
struct ggml_hexagon_opbatch {
|
|
1787
1079
|
ggml_hexagon_session* sess;
|
|
1788
1080
|
|
|
@@ -1863,14 +1155,25 @@ struct ggml_hexagon_opbatch {
|
|
|
1863
1155
|
|
|
1864
1156
|
b_vmem += b.size;
|
|
1865
1157
|
|
|
1866
|
-
HEX_VERBOSE("ggml-hex: add-buffer #%u : fd %d base %p size %zu : vmem %zu\n", bi, b.fd, (void*) sbuf->base, (size_t) b.size, b_vmem);
|
|
1158
|
+
HEX_VERBOSE("ggml-hex: %s add-buffer #%u : fd %d base %p size %zu : vmem %zu\n", sess->c_name(), bi, b.fd, (void*) sbuf->base, (size_t) b.size, b_vmem);
|
|
1867
1159
|
|
|
1868
1160
|
return bi;
|
|
1869
1161
|
}
|
|
1870
1162
|
|
|
1871
1163
|
bool same_shape(const htp_tensor * h, const ggml_tensor * t) const {
|
|
1872
|
-
|
|
1873
|
-
|
|
1164
|
+
int64_t ne0 = t->ne[0];
|
|
1165
|
+
int64_t ne1 = t->ne[1];
|
|
1166
|
+
const bool is_repack = ggml_backend_buffer_is_hexagon_repack(t->buffer) && ggml_hexagon_is_repack_type(t->type);
|
|
1167
|
+
if (is_repack) {
|
|
1168
|
+
ne0 = hex_round_up(ne0, 32);
|
|
1169
|
+
ne1 = hex_round_up(ne1, 32);
|
|
1170
|
+
}
|
|
1171
|
+
int64_t nb1 = is_repack ? ggml_row_size(t->type, ne0) : t->nb[1];
|
|
1172
|
+
int64_t nb2 = is_repack ? nb1 * ne1 : t->nb[2];
|
|
1173
|
+
int64_t nb3 = is_repack ? nb2 * t->ne[2] : t->nb[3];
|
|
1174
|
+
|
|
1175
|
+
return (h->ne[0] == ne0) && (h->ne[1] == ne1) && (h->ne[2] == t->ne[2]) && (h->ne[3] == t->ne[3]) &&
|
|
1176
|
+
(h->nb[0] == t->nb[0]) && (h->nb[1] == nb1) && (h->nb[2] == nb2) && (h->nb[3] == nb3);
|
|
1874
1177
|
}
|
|
1875
1178
|
|
|
1876
1179
|
// add tensor and return its index
|
|
@@ -1901,19 +1204,35 @@ struct ggml_hexagon_opbatch {
|
|
|
1901
1204
|
htp_tensor &h = h_tens[ti];
|
|
1902
1205
|
h.bi = add_buffer(sbuf);
|
|
1903
1206
|
h.data = t_offset;
|
|
1904
|
-
h.size = t_size;
|
|
1905
1207
|
h.type = t->type;
|
|
1906
|
-
|
|
1907
|
-
|
|
1208
|
+
|
|
1209
|
+
const bool is_repack = ggml_backend_buffer_is_hexagon_repack(t->buffer) && ggml_hexagon_is_repack_type(t->type);
|
|
1210
|
+
if (is_repack) {
|
|
1211
|
+
h.ne[0] = hex_round_up(t->ne[0], 32);
|
|
1212
|
+
h.ne[1] = hex_round_up(t->ne[1], 32);
|
|
1213
|
+
h.ne[2] = t->ne[2];
|
|
1214
|
+
h.ne[3] = t->ne[3];
|
|
1215
|
+
|
|
1216
|
+
h.nb[0] = t->nb[0];
|
|
1217
|
+
h.nb[1] = ggml_row_size(t->type, h.ne[0]);
|
|
1218
|
+
h.nb[2] = h.nb[1] * h.ne[1];
|
|
1219
|
+
h.nb[3] = h.nb[2] * h.ne[2];
|
|
1220
|
+
h.size = h.nb[3] * h.ne[3];
|
|
1221
|
+
t_size = h.size;
|
|
1222
|
+
} else {
|
|
1223
|
+
h.size = t_size;
|
|
1224
|
+
h.ne[0] = t->ne[0]; h.ne[1] = t->ne[1]; h.ne[2] = t->ne[2]; h.ne[3] = t->ne[3];
|
|
1225
|
+
h.nb[0] = t->nb[0]; h.nb[1] = t->nb[1]; h.nb[2] = t->nb[2]; h.nb[3] = t->nb[3];
|
|
1226
|
+
}
|
|
1908
1227
|
|
|
1909
1228
|
h.flags = 0;
|
|
1910
1229
|
if (ggml_backend_buffer_get_usage(t->buffer) == GGML_BACKEND_BUFFER_USAGE_COMPUTE) {
|
|
1911
1230
|
h.flags |= HTP_TENSOR_COMPUTE;
|
|
1912
1231
|
}
|
|
1913
1232
|
|
|
1914
|
-
HEX_VERBOSE("ggml-hex: add-tensor #%u %s : bi %d data %p offset %zu size %zu flags 0x%x : %zu:%zu:%zu:%zu\n",
|
|
1233
|
+
HEX_VERBOSE("ggml-hex: %s add-tensor #%u %s : bi %d data %p offset %zu size %zu flags 0x%x : %zu:%zu:%zu:%zu\n", sess->c_name(),
|
|
1915
1234
|
ti, t->name, h.bi, (void*) t->data, (size_t) t_offset, t_size, h.flags,
|
|
1916
|
-
(size_t)
|
|
1235
|
+
(size_t) h.ne[0], (size_t) h.ne[1], (size_t) h.ne[2], (size_t) h.ne[3]);
|
|
1917
1236
|
|
|
1918
1237
|
return ti;
|
|
1919
1238
|
}
|
|
@@ -1942,7 +1261,9 @@ struct ggml_hexagon_opbatch {
|
|
|
1942
1261
|
for (const auto * src : node.get_inputs()) {
|
|
1943
1262
|
fit_tensor(src);
|
|
1944
1263
|
}
|
|
1945
|
-
|
|
1264
|
+
for (const auto * output : node.get_outputs()) {
|
|
1265
|
+
fit_tensor(output);
|
|
1266
|
+
}
|
|
1946
1267
|
|
|
1947
1268
|
if ((extra_bufs + n_bufs) > n_bufs_max) return false;
|
|
1948
1269
|
if ((extra_tens + n_tens) > n_tens_max) return false;
|
|
@@ -1961,7 +1282,8 @@ struct ggml_hexagon_opbatch {
|
|
|
1961
1282
|
ops[n] = node;
|
|
1962
1283
|
|
|
1963
1284
|
htp_op_desc &o = h_ops[n];
|
|
1964
|
-
memcpy(
|
|
1285
|
+
memcpy(o.params, node.node->op_params, sizeof(node.node->op_params));
|
|
1286
|
+
memcpy(o.kernel_params, node.kernel_params, sizeof(o.kernel_params));
|
|
1965
1287
|
o.opcode = node.opcode;
|
|
1966
1288
|
o.flags = 0;
|
|
1967
1289
|
|
|
@@ -1969,13 +1291,17 @@ struct ggml_hexagon_opbatch {
|
|
|
1969
1291
|
o.flags |= HTP_OPFLAGS_SKIP_COMPUTE;
|
|
1970
1292
|
}
|
|
1971
1293
|
|
|
1972
|
-
ggml_hexagon_dump_op_exec(sess->c_name(),
|
|
1294
|
+
ggml_hexagon_dump_op_exec(sess->c_name(), ops[n], o.flags);
|
|
1973
1295
|
|
|
1974
1296
|
auto inputs = node.get_inputs();
|
|
1975
1297
|
for (unsigned int i=0; i < HTP_OP_MAX_INPUTS; i++) {
|
|
1976
|
-
o.src[i] = (i < inputs.size() && inputs[i])
|
|
1298
|
+
o.src[i] = (i < inputs.size() && inputs[i]) ? add_tensor(inputs[i]) : 0xffff;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
auto outputs = node.get_outputs();
|
|
1302
|
+
for (unsigned int i=0; i < HTP_OP_MAX_OUTPUTS; i++) {
|
|
1303
|
+
o.dst[i] = (i < outputs.size() && outputs[i]) ? add_tensor(outputs[i]) : 0xffff;
|
|
1977
1304
|
}
|
|
1978
|
-
o.dst = add_tensor(node.dst());
|
|
1979
1305
|
}
|
|
1980
1306
|
};
|
|
1981
1307
|
|
|
@@ -1986,19 +1312,25 @@ struct ggml_hexagon_opqueue {
|
|
|
1986
1312
|
|
|
1987
1313
|
using opvec = std::vector<htp_opnode>;
|
|
1988
1314
|
|
|
1989
|
-
std::queue<unsigned int> done;
|
|
1990
|
-
std::vector<opvec> op_cache;
|
|
1991
|
-
std::vector<uint64_t> start_usec;
|
|
1315
|
+
std::queue<unsigned int> done; // completed batch ids
|
|
1316
|
+
std::vector<opvec> op_cache; // per batch op cache
|
|
1317
|
+
std::vector<uint64_t> start_usec; // per batch start time
|
|
1992
1318
|
|
|
1993
1319
|
ggml_hexagon_opqueue(ggml_hexagon_session *sess, size_t batch_size, size_t depth) {
|
|
1994
1320
|
size_t n_bufs = HTP_OP_MAX_BUFS;
|
|
1995
1321
|
size_t n_ops = batch_size;
|
|
1996
|
-
size_t n_tensors = n_ops + n_ops * HTP_OP_MAX_INPUTS;
|
|
1322
|
+
size_t n_tensors = n_ops * HTP_OP_MAX_OUTPUTS + n_ops * HTP_OP_MAX_INPUTS;
|
|
1323
|
+
|
|
1324
|
+
size_t tr_size = 0;
|
|
1325
|
+
if (opt_profile == 3) {
|
|
1326
|
+
tr_size = (HTP_MAX_NTHREADS + 1) * opt_optrace * sizeof(htp_trace_desc);
|
|
1327
|
+
}
|
|
1997
1328
|
|
|
1998
1329
|
shm_blk_size = sizeof(htp_buf_desc) * n_bufs +
|
|
1999
1330
|
sizeof(htp_tensor) * n_tensors +
|
|
2000
1331
|
sizeof(htp_op_desc) * n_ops +
|
|
2001
|
-
sizeof(htp_prof_desc) * n_ops
|
|
1332
|
+
sizeof(htp_prof_desc) * n_ops +
|
|
1333
|
+
tr_size;
|
|
2002
1334
|
|
|
2003
1335
|
shm_buf = new ggml_hexagon_shared_buffer(sess, shm_blk_size * depth, true /* pinned */);
|
|
2004
1336
|
|
|
@@ -2042,11 +1374,19 @@ struct ggml_hexagon_opqueue {
|
|
|
2042
1374
|
const size_t o_size = sizeof(htp_op_desc) * req.n_ops;
|
|
2043
1375
|
const size_t p_size = sizeof(htp_prof_desc) * req.n_ops;
|
|
2044
1376
|
|
|
1377
|
+
size_t tr_size = 0;
|
|
1378
|
+
if (opt_profile == 3) {
|
|
1379
|
+
req.n_traces = opt_optrace;
|
|
1380
|
+
tr_size = (HTP_MAX_NTHREADS + 1) * req.n_traces * sizeof(htp_trace_desc);
|
|
1381
|
+
} else {
|
|
1382
|
+
req.n_traces = 0;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
2045
1385
|
dbuf.ptr = shm_buf->base + (req.id * shm_blk_size);
|
|
2046
1386
|
dbuf.fd = shm_buf->fd;
|
|
2047
1387
|
dbuf.flags = DSPQUEUE_BUFFER_FLAG_FLUSH_SENDER | DSPQUEUE_BUFFER_FLAG_INVALIDATE_RECIPIENT;
|
|
2048
1388
|
dbuf.offset = (uint8_t*) dbuf.ptr - (uint8_t*) shm_buf->base;
|
|
2049
|
-
dbuf.size = b_size + t_size + o_size + p_size;
|
|
1389
|
+
dbuf.size = b_size + t_size + o_size + p_size + tr_size;
|
|
2050
1390
|
|
|
2051
1391
|
GGML_ASSERT(dbuf.size <= shm_blk_size);
|
|
2052
1392
|
|
|
@@ -2092,7 +1432,14 @@ struct ggml_hexagon_opqueue {
|
|
|
2092
1432
|
const size_t o_size = sizeof(htp_op_desc) * rsp.n_ops;
|
|
2093
1433
|
const size_t p_size = sizeof(htp_prof_desc) * rsp.n_ops;
|
|
2094
1434
|
|
|
2095
|
-
|
|
1435
|
+
size_t tr_size = 0;
|
|
1436
|
+
uint32_t n_traces = 0;
|
|
1437
|
+
if (opt_profile == 3) {
|
|
1438
|
+
n_traces = opt_optrace;
|
|
1439
|
+
tr_size = (HTP_MAX_NTHREADS + 1) * n_traces * sizeof(htp_trace_desc);
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
const size_t m_size = b_size + t_size + o_size + p_size + tr_size;
|
|
2096
1443
|
GGML_ASSERT(m_size <= shm_blk_size);
|
|
2097
1444
|
|
|
2098
1445
|
HEX_VERBOSE("ggml-hex: %s op-queue pop batch #%u : n-bufs %u n-tensors %u n-ops %u : m-size %zu b-size %zu t-size %zu o-size %zu\n",
|
|
@@ -2111,13 +1458,62 @@ struct ggml_hexagon_opqueue {
|
|
|
2111
1458
|
GGML_ASSERT(rsp.n_ops <= ops.size());
|
|
2112
1459
|
|
|
2113
1460
|
const htp_prof_desc * pd = (const htp_prof_desc *) p_ptr;
|
|
1461
|
+
|
|
1462
|
+
const htp_trace_desc * trace_events = nullptr;
|
|
1463
|
+
|
|
1464
|
+
if (opt_profile == 3) {
|
|
1465
|
+
trace_events = (const htp_trace_desc *) (p_ptr + p_size);
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
uint32_t trace_idx[HTP_MAX_NTHREADS + 1] = {0};
|
|
1469
|
+
uint32_t valid_cnt[HTP_MAX_NTHREADS + 1] = {0};
|
|
1470
|
+
|
|
1471
|
+
if (opt_profile == 3) {
|
|
1472
|
+
for (uint32_t t = 0; t <= HTP_MAX_NTHREADS; t++) {
|
|
1473
|
+
uint32_t count = rsp.n_traces[t];
|
|
1474
|
+
valid_cnt[t] = count > n_traces ? n_traces : count;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
|
|
2114
1478
|
for (uint32_t i = 0; i < rsp.n_ops; i++) {
|
|
2115
1479
|
htp_usec += pd[i].usecs;
|
|
2116
|
-
|
|
1480
|
+
|
|
1481
|
+
ggml_hexagon_dump_op_prof(shm_buf->sess->name, ops[i], pd[i]);
|
|
1482
|
+
|
|
1483
|
+
if (opt_profile == 3) {
|
|
1484
|
+
uint32_t op_duration = pd[i].cycles_stop - pd[i].cycles_start;
|
|
1485
|
+
|
|
1486
|
+
for (uint32_t t = 0; t <= HTP_MAX_NTHREADS; t++) {
|
|
1487
|
+
while (trace_idx[t] < valid_cnt[t]) {
|
|
1488
|
+
const auto & e = trace_events[t * n_traces + trace_idx[t]];
|
|
1489
|
+
uint32_t offset = e.cycles - pd[i].cycles_start;
|
|
1490
|
+
if (offset >= 0x80000000) {
|
|
1491
|
+
trace_idx[t]++;
|
|
1492
|
+
continue;
|
|
1493
|
+
}
|
|
1494
|
+
if (offset > op_duration) {
|
|
1495
|
+
break;
|
|
1496
|
+
}
|
|
1497
|
+
bool is_stop = (e.info & 0x8000) != 0;
|
|
1498
|
+
uint16_t info = e.info & 0x7FFF;
|
|
1499
|
+
GGML_LOG_DEBUG("ggml-hex: %s trace-op %s: thread %u event %s info %u %s %u\n",
|
|
1500
|
+
shm_buf->sess->c_name(), ops[i].op_name().c_str(), t, htp_event_name(e.id), info, is_stop ? "stop" : "start", e.cycles);
|
|
1501
|
+
trace_idx[t]++;
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
char evt_str[256] = "";
|
|
1508
|
+
if (opt_profile == 3) {
|
|
1509
|
+
snprintf(evt_str, sizeof(evt_str), " evt [%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u]",
|
|
1510
|
+
rsp.n_traces[0], rsp.n_traces[1], rsp.n_traces[2], rsp.n_traces[3],
|
|
1511
|
+
rsp.n_traces[4], rsp.n_traces[5], rsp.n_traces[6], rsp.n_traces[7],
|
|
1512
|
+
rsp.n_traces[8], rsp.n_traces[9], rsp.n_traces[10]);
|
|
2117
1513
|
}
|
|
2118
1514
|
|
|
2119
|
-
GGML_LOG_DEBUG("ggml-hex: %s profile-batch n-ops %u batch-dur-usec %lld htp-ops-usec %u\n",
|
|
2120
|
-
shm_buf->sess->c_name(), rsp.n_ops, (long long) batch_usec, htp_usec);
|
|
1515
|
+
GGML_LOG_DEBUG("ggml-hex: %s profile-batch n-ops %u batch-dur-usec %lld htp-ops-usec %u%s\n",
|
|
1516
|
+
shm_buf->sess->c_name(), rsp.n_ops, (long long) batch_usec, htp_usec, evt_str);
|
|
2121
1517
|
}
|
|
2122
1518
|
}
|
|
2123
1519
|
};
|
|
@@ -2134,6 +1530,7 @@ void ggml_hexagon_session::flush_pending(bool all) {
|
|
|
2134
1530
|
|
|
2135
1531
|
// Read response packet from queue
|
|
2136
1532
|
const uint32_t timeo = opt_oppoll ? 0 : DSPQUEUE_TIMEOUT;
|
|
1533
|
+
|
|
2137
1534
|
int err = dspqueue_read(this->queue, &flags, 1, &n_dbufs, &dbuf, sizeof(rsp), &rsp_size, (uint8_t *) &rsp, timeo);
|
|
2138
1535
|
if (err == AEE_EEXPIRED) {
|
|
2139
1536
|
continue;
|
|
@@ -2314,6 +1711,31 @@ void ggml_hexagon_session::allocate(int dev_id) noexcept(false) {
|
|
|
2314
1711
|
|
|
2315
1712
|
this->valid_handle = true;
|
|
2316
1713
|
|
|
1714
|
+
// Query HW info and resolve session options
|
|
1715
|
+
this->max_bufsize = opt_mbuf;
|
|
1716
|
+
{
|
|
1717
|
+
unsigned int hw_n_threads = 0;
|
|
1718
|
+
unsigned int hw_n_hvx = 0;
|
|
1719
|
+
unsigned int hw_n_hmx = 0;
|
|
1720
|
+
unsigned long long hw_vtcm_size = 0;
|
|
1721
|
+
int hw_err = htp_iface_hwinfo(this->handle, &hw_n_threads, &hw_n_hvx, &hw_n_hmx, &hw_vtcm_size);
|
|
1722
|
+
if (hw_err == 0) {
|
|
1723
|
+
this->n_threads = opt_nhvx > 0 ? (uint32_t)opt_nhvx : (uint32_t)hw_n_threads;
|
|
1724
|
+
this->n_hvx = opt_nhvx > 0 ? (uint32_t)opt_nhvx : (uint32_t)hw_n_hvx;
|
|
1725
|
+
this->n_hmx = (opt_nhmx != 0) ? (uint32_t)hw_n_hmx : 0;
|
|
1726
|
+
this->vtcm_size = (uint64_t)hw_vtcm_size;
|
|
1727
|
+
GGML_LOG_INFO("ggml-hex: %s hwinfo: threads %u, hvx %u, hmx %u, vtcm %llu MB\n",
|
|
1728
|
+
this->c_name(), this->n_threads, this->n_hvx, this->n_hmx,
|
|
1729
|
+
(unsigned long long)(this->vtcm_size / (1024 * 1024)));
|
|
1730
|
+
} else {
|
|
1731
|
+
GGML_LOG_WARN("ggml-hex: %s failed to query hwinfo (0x%x), using defaults\n", this->c_name(), hw_err);
|
|
1732
|
+
this->n_threads = opt_nhvx > 0 ? (uint32_t)opt_nhvx : 8;
|
|
1733
|
+
this->n_hvx = opt_nhvx > 0 ? (uint32_t)opt_nhvx : 8;
|
|
1734
|
+
this->n_hmx = (opt_nhmx != 0) ? 1 : 0;
|
|
1735
|
+
this->vtcm_size = 8 * 1024 * 1024;
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
|
|
2317
1739
|
// Enable FastRPC QoS mode
|
|
2318
1740
|
{
|
|
2319
1741
|
struct remote_rpc_control_latency l;
|
|
@@ -2378,11 +1800,12 @@ void ggml_hexagon_session::allocate(int dev_id) noexcept(false) {
|
|
|
2378
1800
|
opt_vmem = ggml_hexagon_measure_max_vmem(this);
|
|
2379
1801
|
GGML_LOG_INFO("ggml-hex: %s measured max vmem %zu\n", this->c_name(), opt_vmem);
|
|
2380
1802
|
}
|
|
1803
|
+
this->max_vmem = opt_vmem;
|
|
2381
1804
|
|
|
2382
|
-
this->op_batch = new ggml_hexagon_opbatch(this, opt_opbatch,
|
|
1805
|
+
this->op_batch = new ggml_hexagon_opbatch(this, opt_opbatch, this->max_vmem);
|
|
2383
1806
|
|
|
2384
1807
|
// Start dspqueue/opbatch processing
|
|
2385
|
-
err = htp_iface_start(this->handle, dev_id, this->queue_id, opt_nhvx,
|
|
1808
|
+
err = htp_iface_start(this->handle, dev_id, this->queue_id, opt_nhvx, opt_nhmx, this->max_vmem);
|
|
2386
1809
|
if (err != 0) {
|
|
2387
1810
|
GGML_LOG_ERROR("ggml-hex: %s failed to start session: 0x%08x\n", this->c_name(), (unsigned) err);
|
|
2388
1811
|
throw std::runtime_error("ggml-hex: iface start failed (see log for details)");
|
|
@@ -2463,15 +1886,161 @@ ggml_hexagon_session::~ggml_hexagon_session() noexcept(true) {
|
|
|
2463
1886
|
|
|
2464
1887
|
// ** backend interface
|
|
2465
1888
|
|
|
2466
|
-
static bool
|
|
2467
|
-
|
|
1889
|
+
static bool ggml_hexagon_flash_attn_is_hmx_eligible(
|
|
1890
|
+
const struct ggml_hexagon_session * sess,
|
|
1891
|
+
const struct ggml_tensor * q,
|
|
1892
|
+
const struct ggml_tensor * k,
|
|
1893
|
+
const struct ggml_tensor * v,
|
|
1894
|
+
const struct ggml_tensor * sinks
|
|
1895
|
+
) {
|
|
1896
|
+
if (sess->n_hmx == 0) {
|
|
1897
|
+
return false;
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
if (opt_fa_select < 2) {
|
|
1901
|
+
return false;
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
if (k->type != GGML_TYPE_F16 || v->type != GGML_TYPE_F16) {
|
|
1905
|
+
return false;
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
const uint32_t DK = q->ne[0];
|
|
1909
|
+
const uint32_t DV = v->ne[0];
|
|
1910
|
+
|
|
1911
|
+
if (DK % 64 != 0 || DV % 64 != 0) {
|
|
1912
|
+
return false;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
// Fall back to HVX for small token counts if head dimension is small (DK <= 128)
|
|
1916
|
+
const uint32_t neq1 = q->ne[1];
|
|
1917
|
+
if (DK <= 128 && neq1 < 5) {
|
|
1918
|
+
return false;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
return true;
|
|
2468
1922
|
}
|
|
2469
1923
|
|
|
2470
|
-
static
|
|
2471
|
-
|
|
2472
|
-
|
|
1924
|
+
static bool ggml_hexagon_precompute_flash_attn_params(
|
|
1925
|
+
const struct ggml_hexagon_session * sess,
|
|
1926
|
+
const struct ggml_tensor * op,
|
|
1927
|
+
struct htp_fa_kernel_params * kparams
|
|
1928
|
+
) {
|
|
1929
|
+
if (opt_fa_select < 1) {
|
|
1930
|
+
return false;
|
|
2473
1931
|
}
|
|
2474
|
-
|
|
1932
|
+
|
|
1933
|
+
memset(kparams, 0, sizeof(*kparams));
|
|
1934
|
+
|
|
1935
|
+
const struct ggml_tensor * q = op->src[0];
|
|
1936
|
+
const struct ggml_tensor * k = op->src[1];
|
|
1937
|
+
const struct ggml_tensor * v = op->src[2];
|
|
1938
|
+
const struct ggml_tensor * mask = op->src[3];
|
|
1939
|
+
const struct ggml_tensor * dst = op;
|
|
1940
|
+
|
|
1941
|
+
const uint32_t neq0 = q->ne[0]; // head_dim (DK)
|
|
1942
|
+
const uint32_t neq1 = q->ne[1]; // n_tokens
|
|
1943
|
+
const uint32_t neq2 = q->ne[2]; // n_heads
|
|
1944
|
+
|
|
1945
|
+
const uint32_t nek1 = k->ne[1]; // kv_len
|
|
1946
|
+
|
|
1947
|
+
const uint32_t nev0 = v->ne[0]; // head_dim (DV)
|
|
1948
|
+
|
|
1949
|
+
const uint32_t DK = neq0;
|
|
1950
|
+
const uint32_t DV = nev0;
|
|
1951
|
+
|
|
1952
|
+
const uint32_t n_kv_heads = k->ne[2];
|
|
1953
|
+
const uint32_t G = neq2 / n_kv_heads;
|
|
1954
|
+
|
|
1955
|
+
float scale = 1.0f;
|
|
1956
|
+
float max_bias = 0.0f;
|
|
1957
|
+
float logit_softcap = 0.0f;
|
|
1958
|
+
memcpy(&scale, &op->op_params[0], sizeof(float));
|
|
1959
|
+
memcpy(&max_bias, &op->op_params[1], sizeof(float));
|
|
1960
|
+
memcpy(&logit_softcap, &op->op_params[2], sizeof(float));
|
|
1961
|
+
|
|
1962
|
+
if (logit_softcap != 0.0f) {
|
|
1963
|
+
scale /= logit_softcap;
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
kparams->scale = scale;
|
|
1967
|
+
kparams->max_bias = max_bias;
|
|
1968
|
+
kparams->logit_softcap = logit_softcap;
|
|
1969
|
+
|
|
1970
|
+
kparams->is_q_fp32 = (q->type == GGML_TYPE_F32) ? 1 : 0;
|
|
1971
|
+
kparams->is_dst_fp32 = (dst->type == GGML_TYPE_F32) ? 1 : 0;
|
|
1972
|
+
kparams->G = G;
|
|
1973
|
+
|
|
1974
|
+
const uint32_t n_head = q->ne[2];
|
|
1975
|
+
kparams->n_head_log2 = 1u << (uint32_t) std::floor(std::log2(n_head));
|
|
1976
|
+
kparams->m0 = std::pow(2.0f, -(max_bias) / kparams->n_head_log2);
|
|
1977
|
+
kparams->m1 = std::pow(2.0f, -(max_bias / 2.0f) / kparams->n_head_log2);
|
|
1978
|
+
|
|
1979
|
+
// Check HMX eligibility
|
|
1980
|
+
const struct ggml_tensor * sinks = op->src[4];
|
|
1981
|
+
if (ggml_hexagon_flash_attn_is_hmx_eligible(sess, q, k, v, sinks)) {
|
|
1982
|
+
size_t Br = 0, Bc = 0;
|
|
1983
|
+
int ret = hmx_fa_find_chunk_size(&Br, &Bc, G, DK, DV, neq1, nek1, sess->vtcm_size, sess->n_threads);
|
|
1984
|
+
if (ret == 0) {
|
|
1985
|
+
kparams->kernel_type = HTP_FA_KERNEL_HMX;
|
|
1986
|
+
kparams->Br = Br;
|
|
1987
|
+
kparams->Bc = Bc;
|
|
1988
|
+
kparams->n_kv_blocks = (nek1 + Bc - 1) / Bc;
|
|
1989
|
+
kparams->n_threads = (kparams->n_kv_blocks >= 3 && sess->n_threads >= 2) ? sess->n_threads : 1;
|
|
1990
|
+
|
|
1991
|
+
kparams->u.hmx.g_br = hex_align_up(G * Br, 32);
|
|
1992
|
+
kparams->u.hmx.pipeline = (kparams->n_kv_blocks >= 3 && sess->n_threads >= 2) ? 1 : 0;
|
|
1993
|
+
kparams->vtcm_size = hmx_fa_compute_vtcm_usage(G, DK, DV, Br, Bc, kparams->n_threads, kparams->u.hmx.pipeline != 0);
|
|
1994
|
+
|
|
1995
|
+
const size_t row_vec_bytes = hex_align_up(Bc * sizeof(uint16_t), 256);
|
|
1996
|
+
kparams->u.hmx.row_buf_stride = row_vec_bytes / 128; // HVX vector is 128 bytes
|
|
1997
|
+
|
|
1998
|
+
const size_t m_line_bytes = hex_align_up(Bc * sizeof(uint16_t), 128);
|
|
1999
|
+
kparams->u.hmx.mask_buf_row_stride = m_line_bytes / sizeof(uint16_t);
|
|
2000
|
+
kparams->u.hmx.mask_broadcast = (mask != nullptr && mask->ne[2] == 1) ? 1 : 0;
|
|
2001
|
+
kparams->u.hmx.div_G = init_fastdiv_values(G);
|
|
2002
|
+
if (mask) {
|
|
2003
|
+
kparams->src3_div2 = init_fastdiv_values(mask->ne[2]);
|
|
2004
|
+
kparams->src3_div3 = init_fastdiv_values(mask->ne[3]);
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
kparams->qrows = 0;
|
|
2008
|
+
kparams->qrows_per_thread = 0;
|
|
2009
|
+
return true;
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
|
|
2013
|
+
// Fallback to HVX
|
|
2014
|
+
kparams->kernel_type = HTP_FA_KERNEL_HVX;
|
|
2015
|
+
kparams->Br = 1;
|
|
2016
|
+
kparams->Bc = 64; // FLASH_ATTN_BLOCK_SIZE
|
|
2017
|
+
kparams->n_kv_blocks = (k->ne[1] + 64 - 1) / 64;
|
|
2018
|
+
kparams->n_threads = sess->n_threads;
|
|
2019
|
+
|
|
2020
|
+
const size_t size_q_row_padded = hex_round_up(q->ne[0] * (kparams->is_q_fp32 ? 4 : 2), 128);
|
|
2021
|
+
const size_t size_k_row_padded = hex_round_up(k->ne[0] * 2, 128);
|
|
2022
|
+
const size_t size_v_row_padded = hex_round_up(v->ne[0] * 2, 128);
|
|
2023
|
+
|
|
2024
|
+
kparams->vtcm_size = hvx_fa_compute_vtcm_usage(DK, DV, kparams->is_q_fp32 != 0, mask != nullptr, sess->n_threads);
|
|
2025
|
+
|
|
2026
|
+
kparams->u.hvx.size_q_row_padded = size_q_row_padded;
|
|
2027
|
+
kparams->u.hvx.size_k_row_padded = size_k_row_padded;
|
|
2028
|
+
kparams->u.hvx.size_v_row_padded = size_v_row_padded;
|
|
2029
|
+
kparams->u.hvx.src0_div21 = init_fastdiv_values(q->ne[2] * q->ne[1]);
|
|
2030
|
+
kparams->u.hvx.src0_div1 = init_fastdiv_values(q->ne[1]);
|
|
2031
|
+
kparams->broadcast_rk2 = init_fastdiv_values(q->ne[2]/k->ne[2]);
|
|
2032
|
+
kparams->broadcast_rk3 = init_fastdiv_values(q->ne[3]/k->ne[3]);
|
|
2033
|
+
kparams->broadcast_rv2 = init_fastdiv_values(q->ne[2]/v->ne[2]);
|
|
2034
|
+
kparams->broadcast_rv3 = init_fastdiv_values(q->ne[3]/v->ne[3]);
|
|
2035
|
+
if (mask) {
|
|
2036
|
+
kparams->src3_div2 = init_fastdiv_values(mask->ne[2]);
|
|
2037
|
+
kparams->src3_div3 = init_fastdiv_values(mask->ne[3]);
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
kparams->qrows = q->ne[1] * q->ne[2] * q->ne[3];
|
|
2041
|
+
kparams->qrows_per_thread = (kparams->qrows + sess->n_threads - 1) / sess->n_threads;
|
|
2042
|
+
|
|
2043
|
+
return true;
|
|
2475
2044
|
}
|
|
2476
2045
|
|
|
2477
2046
|
static bool ggml_hexagon_supported_flash_attn_ext(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
|
@@ -2506,6 +2075,17 @@ static bool ggml_hexagon_supported_flash_attn_ext(const struct ggml_hexagon_sess
|
|
|
2506
2075
|
return false;
|
|
2507
2076
|
}
|
|
2508
2077
|
|
|
2078
|
+
struct htp_fa_kernel_params kparams;
|
|
2079
|
+
if (!ggml_hexagon_precompute_flash_attn_params(sess, op, &kparams)) {
|
|
2080
|
+
return false;
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
if ((size_t) kparams.vtcm_size > sess->vtcm_size) {
|
|
2084
|
+
HEX_VERBOSE("ggml-hex: skip flash_attn_ext because VTCM needed (%d) > budget (%zu)\n",
|
|
2085
|
+
kparams.vtcm_size, sess->vtcm_size);
|
|
2086
|
+
return false;
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2509
2089
|
return true;
|
|
2510
2090
|
}
|
|
2511
2091
|
|
|
@@ -2563,6 +2143,592 @@ static bool ggml_hexagon_supported_gated_delta_net(const struct ggml_hexagon_ses
|
|
|
2563
2143
|
return true;
|
|
2564
2144
|
}
|
|
2565
2145
|
|
|
2146
|
+
static bool ggml_hexagon_matmul_is_hmx_eligible(
|
|
2147
|
+
const struct ggml_tensor * src0,
|
|
2148
|
+
const struct ggml_tensor * src1,
|
|
2149
|
+
const struct ggml_tensor * dst,
|
|
2150
|
+
int ne01_padded,
|
|
2151
|
+
bool is_matmul_id,
|
|
2152
|
+
bool is_batched
|
|
2153
|
+
) {
|
|
2154
|
+
const int ne00 = src0->ne[0];
|
|
2155
|
+
const int ne11 = src1->ne[1];
|
|
2156
|
+
const int ne12 = src1->ne[2];
|
|
2157
|
+
const int wtype = src0->type;
|
|
2158
|
+
|
|
2159
|
+
// HMX weight tile requires N to be 32-aligned.
|
|
2160
|
+
if (ne01_padded % 32 != 0) {
|
|
2161
|
+
return false;
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
// HMX supports F16, F32, and repack quantized types.
|
|
2165
|
+
if (!ggml_hexagon_is_hmx_weight_type((ggml_type) wtype)) {
|
|
2166
|
+
return false;
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
// HMX paths require K aligned to 32.
|
|
2170
|
+
if (ne00 % 32 != 0) {
|
|
2171
|
+
return false;
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
// Quantized HMX kernels only handle flat 2D matmul (or matmul_id wrapping flat 2D matmuls).
|
|
2175
|
+
if (!is_matmul_id && is_batched && wtype != GGML_TYPE_F16) {
|
|
2176
|
+
return false;
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
// HMX assumes contiguous row-major layout.
|
|
2180
|
+
if (src0->nb[0] > src0->nb[1] || src1->nb[0] > src1->nb[1]) {
|
|
2181
|
+
return false;
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
// M alignment: Use HMX when M > HTP_MM_HMX_MIN_NROWS
|
|
2185
|
+
const int m = is_matmul_id ? ne12 : ne11;
|
|
2186
|
+
if (m <= HTP_MM_HMX_MIN_NROWS) {
|
|
2187
|
+
return false;
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
return true;
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
static bool ggml_hexagon_precompute_hmx_mm_params(
|
|
2194
|
+
const struct ggml_hexagon_session * sess,
|
|
2195
|
+
const struct ggml_tensor * src0,
|
|
2196
|
+
const struct ggml_tensor * src1,
|
|
2197
|
+
const struct ggml_tensor * dst,
|
|
2198
|
+
int wtype,
|
|
2199
|
+
int ne00_padded,
|
|
2200
|
+
int ne01_padded,
|
|
2201
|
+
int ne02,
|
|
2202
|
+
int ne11,
|
|
2203
|
+
int ne12,
|
|
2204
|
+
int ne11_padded,
|
|
2205
|
+
bool is_matmul_id,
|
|
2206
|
+
bool is_batched,
|
|
2207
|
+
size_t vtcm_budget,
|
|
2208
|
+
struct htp_mm_kernel_params * kparams
|
|
2209
|
+
) {
|
|
2210
|
+
const int aligned_tile_size = htp_mm_get_weight_aligned_tile_size(wtype);
|
|
2211
|
+
const bool pipeline = is_matmul_id ? false : htp_mm_hmx_pipeline(ne11);
|
|
2212
|
+
const int n_threads = (int)sess->n_threads;
|
|
2213
|
+
const int ne10 = src1->ne[0];
|
|
2214
|
+
|
|
2215
|
+
const bool is_batched_val = is_matmul_id ? false : is_batched;
|
|
2216
|
+
const int group_size = (ne02 > 0 ? ne12 / ne02 : 1);
|
|
2217
|
+
|
|
2218
|
+
size_t m_chunk = 0;
|
|
2219
|
+
size_t n_chunk = 0;
|
|
2220
|
+
size_t vtcm_size = 0;
|
|
2221
|
+
bool use_grouped = false;
|
|
2222
|
+
int act_threads_selected = 0;
|
|
2223
|
+
|
|
2224
|
+
if (is_batched_val && wtype == GGML_TYPE_F16 && group_size > 1) {
|
|
2225
|
+
// Try grouped path first
|
|
2226
|
+
const bool use_dma_activation = (src1->nb[1]/sizeof(float) > (size_t)ne00_padded);
|
|
2227
|
+
size_t best_mblocks = SIZE_MAX;
|
|
2228
|
+
int best_act_threads = 0;
|
|
2229
|
+
size_t best_m_chunk = 0;
|
|
2230
|
+
size_t best_n_chunk = 0;
|
|
2231
|
+
size_t best_vtcm_size = 0;
|
|
2232
|
+
|
|
2233
|
+
int act_threads = n_threads;
|
|
2234
|
+
while (act_threads >= 1) {
|
|
2235
|
+
const size_t f32_scratch_size = use_dma_activation ? hex_align_up(act_threads * HTP_MM_DMA_ACT_MULTIPLIER * ne00_padded * sizeof(float), HTP_MM_HMX_TILE_SIZE) : 0;
|
|
2236
|
+
size_t group_overhead = 256 + f32_scratch_size;
|
|
2237
|
+
size_t group_size_per_n, group_size_per_m, group_size_per_mn;
|
|
2238
|
+
htp_mm_hmx_get_batched_chunk_costs(ne00_padded, group_size, &group_size_per_n, &group_size_per_m, &group_size_per_mn);
|
|
2239
|
+
|
|
2240
|
+
size_t m_chunk_candidate = 0;
|
|
2241
|
+
size_t n_chunk_candidate = 0;
|
|
2242
|
+
size_t vtcm_size_candidate = 0;
|
|
2243
|
+
|
|
2244
|
+
if (htp_mm_hmx_compute_chunks(vtcm_budget, group_overhead, group_size_per_n, group_size_per_m, group_size_per_mn, hex_align_up(ne11, 32), ne01_padded,
|
|
2245
|
+
(size_t) ne01_padded * HTP_MM_HMX_COST_W_DEQUANT, (size_t) ne11 * HTP_MM_HMX_COST_A_CONVERT,
|
|
2246
|
+
&m_chunk_candidate, &n_chunk_candidate, &vtcm_size_candidate) == 0) {
|
|
2247
|
+
size_t exact_size = htp_mm_hmx_get_batched_vtcm_size(wtype, ne00_padded, m_chunk_candidate, n_chunk_candidate, group_size, use_dma_activation, pipeline, act_threads);
|
|
2248
|
+
if (exact_size <= vtcm_budget) {
|
|
2249
|
+
size_t mblocks = ((size_t) ne11 + m_chunk_candidate - 1) / m_chunk_candidate;
|
|
2250
|
+
if (mblocks < best_mblocks || (mblocks == best_mblocks && act_threads > best_act_threads)) {
|
|
2251
|
+
best_mblocks = mblocks;
|
|
2252
|
+
best_act_threads = act_threads;
|
|
2253
|
+
best_m_chunk = m_chunk_candidate;
|
|
2254
|
+
best_n_chunk = n_chunk_candidate;
|
|
2255
|
+
best_vtcm_size = exact_size;
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
if (act_threads == 1) {
|
|
2260
|
+
act_threads = 0;
|
|
2261
|
+
} else {
|
|
2262
|
+
act_threads /= 2;
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
if (best_act_threads > 0) {
|
|
2267
|
+
m_chunk = best_m_chunk;
|
|
2268
|
+
n_chunk = best_n_chunk;
|
|
2269
|
+
vtcm_size = best_vtcm_size;
|
|
2270
|
+
act_threads_selected = best_act_threads;
|
|
2271
|
+
use_grouped = true;
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
if (!use_grouped) {
|
|
2276
|
+
// Fallback to simple 2D path (group_size = 1)
|
|
2277
|
+
size_t best_mblocks = SIZE_MAX;
|
|
2278
|
+
int best_act_threads = 0;
|
|
2279
|
+
size_t best_m_chunk = 0;
|
|
2280
|
+
size_t best_n_chunk = 0;
|
|
2281
|
+
size_t best_vtcm_size = 0;
|
|
2282
|
+
|
|
2283
|
+
// For MUL_MAT_ID the kernel runs one 2D matmul per expert, with M equal to the number of rows routed to that expert.
|
|
2284
|
+
// A single expert can receive up to all routed rows (dst->ne[1]*dst->ne[2] = n_expert_used*n_tokens), so size the chunk
|
|
2285
|
+
// search for that upper bound rather than ne12 (token positions only).
|
|
2286
|
+
// We recompute m_chunk per expert against the actual count in the NPU kernel.
|
|
2287
|
+
const int m_id_rows = (int) ((size_t) dst->ne[1] * dst->ne[2]);
|
|
2288
|
+
const int m_for_chunks = is_matmul_id ? hex_align_up(m_id_rows, 32) : ne11_padded;
|
|
2289
|
+
const int m_for_cost = is_matmul_id ? m_id_rows : ne11;
|
|
2290
|
+
|
|
2291
|
+
int act_threads = n_threads;
|
|
2292
|
+
while (act_threads >= 1) {
|
|
2293
|
+
const size_t act_f32_size = is_matmul_id ? 0 : hex_align_up(act_threads * HTP_MM_DMA_ACT_MULTIPLIER * ne00_padded * sizeof(float), HTP_MM_HMX_TILE_SIZE);
|
|
2294
|
+
size_t simple_2d_overhead = 256 + act_f32_size;
|
|
2295
|
+
size_t simple_2d_size_per_n, simple_2d_size_per_m, simple_2d_size_per_mn;
|
|
2296
|
+
htp_mm_hmx_get_2d_chunk_costs(wtype, ne00_padded, pipeline, aligned_tile_size, &simple_2d_size_per_n, &simple_2d_size_per_m, &simple_2d_size_per_mn);
|
|
2297
|
+
|
|
2298
|
+
size_t m_chunk_candidate = 0;
|
|
2299
|
+
size_t n_chunk_candidate = 0;
|
|
2300
|
+
size_t vtcm_size_candidate = 0;
|
|
2301
|
+
|
|
2302
|
+
if (htp_mm_hmx_compute_chunks(vtcm_budget, simple_2d_overhead, simple_2d_size_per_n, simple_2d_size_per_m, simple_2d_size_per_mn, m_for_chunks, ne01_padded,
|
|
2303
|
+
(size_t) ne01_padded * HTP_MM_HMX_COST_W_DEQUANT, (size_t) m_for_cost * HTP_MM_HMX_COST_A_CONVERT,
|
|
2304
|
+
&m_chunk_candidate, &n_chunk_candidate, &vtcm_size_candidate) == 0) {
|
|
2305
|
+
size_t exact_size = htp_mm_hmx_get_2d_vtcm_size(wtype, ne00_padded, m_chunk_candidate, n_chunk_candidate, pipeline, is_matmul_id ? 0 : act_threads, aligned_tile_size);
|
|
2306
|
+
if (exact_size <= vtcm_budget) {
|
|
2307
|
+
size_t mblocks = ((size_t) m_for_cost + m_chunk_candidate - 1) / m_chunk_candidate;
|
|
2308
|
+
if (mblocks < best_mblocks || (mblocks == best_mblocks && act_threads > best_act_threads)) {
|
|
2309
|
+
best_mblocks = mblocks;
|
|
2310
|
+
best_act_threads = act_threads;
|
|
2311
|
+
best_m_chunk = m_chunk_candidate;
|
|
2312
|
+
best_n_chunk = n_chunk_candidate;
|
|
2313
|
+
best_vtcm_size = exact_size;
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
if (act_threads == 1) {
|
|
2318
|
+
act_threads = 0;
|
|
2319
|
+
} else {
|
|
2320
|
+
act_threads /= 2;
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
if (best_act_threads > 0) {
|
|
2325
|
+
m_chunk = best_m_chunk;
|
|
2326
|
+
n_chunk = best_n_chunk;
|
|
2327
|
+
vtcm_size = best_vtcm_size;
|
|
2328
|
+
act_threads_selected = best_act_threads;
|
|
2329
|
+
} else {
|
|
2330
|
+
return false;
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
kparams->n_hmx = 1;
|
|
2335
|
+
kparams->pipeline = pipeline ? 1 : 0;
|
|
2336
|
+
kparams->m_chunk = m_chunk;
|
|
2337
|
+
kparams->n_chunk = n_chunk;
|
|
2338
|
+
kparams->n_threads = n_threads;
|
|
2339
|
+
kparams->n_act_threads = act_threads_selected;
|
|
2340
|
+
kparams->tile_size = htp_mm_get_weight_tile_size(wtype);
|
|
2341
|
+
kparams->aligned_tile_size = aligned_tile_size;
|
|
2342
|
+
kparams->src1_row_size = (wtype == GGML_TYPE_Q4_1) ? htp_mm_q8_1_tiled_row_size(ne10) : htp_mm_q8_0_tiled_row_size(ne10);
|
|
2343
|
+
kparams->vtcm_size = vtcm_size;
|
|
2344
|
+
kparams->vtcm_src0_size = 0;
|
|
2345
|
+
kparams->vtcm_src1_size = 0;
|
|
2346
|
+
kparams->vtcm_dst_size = 0;
|
|
2347
|
+
|
|
2348
|
+
if (is_batched && !is_matmul_id) {
|
|
2349
|
+
kparams->kernel_type = HTP_MM_KERNEL_HMX_F16_BATCHED;
|
|
2350
|
+
} else {
|
|
2351
|
+
kparams->kernel_type = HTP_MM_KERNEL_HMX_2D;
|
|
2352
|
+
}
|
|
2353
|
+
return true;
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
static void ggml_hexagon_precompute_hvx_mm_params(
|
|
2357
|
+
const struct ggml_hexagon_session * sess,
|
|
2358
|
+
const struct ggml_tensor * src0,
|
|
2359
|
+
const struct ggml_tensor * src1,
|
|
2360
|
+
const struct ggml_tensor * dst,
|
|
2361
|
+
int wtype,
|
|
2362
|
+
int ne02,
|
|
2363
|
+
int ne03,
|
|
2364
|
+
int ne10,
|
|
2365
|
+
int ne11,
|
|
2366
|
+
int ne12,
|
|
2367
|
+
int ne13,
|
|
2368
|
+
bool is_matmul_id,
|
|
2369
|
+
size_t vtcm_budget,
|
|
2370
|
+
struct htp_mm_kernel_params * kparams
|
|
2371
|
+
) {
|
|
2372
|
+
kparams->n_hmx = 0;
|
|
2373
|
+
|
|
2374
|
+
const bool is_quant = (wtype != GGML_TYPE_F16 && wtype != GGML_TYPE_F32);
|
|
2375
|
+
const int src1_nrows = ne11 * ne12 * ne13;
|
|
2376
|
+
|
|
2377
|
+
if (is_quant) {
|
|
2378
|
+
// Quantized HVX
|
|
2379
|
+
kparams->tile_size = htp_mm_get_weight_tile_size(wtype);
|
|
2380
|
+
kparams->aligned_tile_size = htp_mm_get_weight_aligned_tile_size(wtype);
|
|
2381
|
+
|
|
2382
|
+
const bool k_align = (ne10 % 32 == 0);
|
|
2383
|
+
|
|
2384
|
+
if (is_matmul_id) {
|
|
2385
|
+
kparams->kernel_type = (src1_nrows < (int) sess->n_threads) ? HTP_MM_KERNEL_HVX_QUANT_BLOCK : HTP_MM_KERNEL_HVX_QUANT_ROW;
|
|
2386
|
+
kparams->src1_row_size = (wtype == GGML_TYPE_Q4_1) ? htp_mm_q8_1_tiled_row_size(ne10) : htp_mm_q8_0_tiled_row_size(ne10);
|
|
2387
|
+
|
|
2388
|
+
struct htp_mm_hvx_vtcm_layout L;
|
|
2389
|
+
uint32_t max_prefetch = (src1_nrows > HTP_MM_HMX_MIN_NROWS) ? 2 : 16;
|
|
2390
|
+
uint32_t best_n_prefetch = 2;
|
|
2391
|
+
for (uint32_t d = max_prefetch; d >= 2; d /= 2) {
|
|
2392
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2393
|
+
&L, kparams->kernel_type, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2394
|
+
0, src0->nb[1], 0, d, true, false, false
|
|
2395
|
+
);
|
|
2396
|
+
if (L.total_bytes <= vtcm_budget) {
|
|
2397
|
+
best_n_prefetch = d;
|
|
2398
|
+
break;
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
if (best_n_prefetch == 2 && L.total_bytes > vtcm_budget) {
|
|
2402
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2403
|
+
&L, kparams->kernel_type, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2404
|
+
0, src0->nb[1], 0, 2, true, false, false
|
|
2405
|
+
);
|
|
2406
|
+
}
|
|
2407
|
+
kparams->n_prefetch = best_n_prefetch;
|
|
2408
|
+
kparams->vtcm_size = L.total_bytes;
|
|
2409
|
+
kparams->vtcm_src0_size = L.src0_bytes;
|
|
2410
|
+
kparams->vtcm_src1_size = L.src1_bytes;
|
|
2411
|
+
kparams->vtcm_dst_size = L.dst_bytes;
|
|
2412
|
+
} else {
|
|
2413
|
+
bool try_tiled = (k_align && opt_mm_select >= 2);
|
|
2414
|
+
if (try_tiled) {
|
|
2415
|
+
kparams->src1_row_size = (wtype == GGML_TYPE_Q4_1) ? htp_mm_q8_1_tiled_row_size(ne10) : htp_mm_q8_0_tiled_row_size(ne10);
|
|
2416
|
+
if (src1_nrows < (int)sess->n_threads) {
|
|
2417
|
+
kparams->kernel_type = HTP_MM_KERNEL_HVX_QUANT_BLOCK;
|
|
2418
|
+
} else {
|
|
2419
|
+
kparams->kernel_type = HTP_MM_KERNEL_HVX_QUANT_ROW;
|
|
2420
|
+
}
|
|
2421
|
+
|
|
2422
|
+
struct htp_mm_hvx_vtcm_layout L;
|
|
2423
|
+
uint32_t max_prefetch = (src1_nrows > HTP_MM_HMX_MIN_NROWS) ? 2 : 16;
|
|
2424
|
+
uint32_t best_n_prefetch = 2;
|
|
2425
|
+
for (uint32_t d = max_prefetch; d >= 2; d /= 2) {
|
|
2426
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2427
|
+
&L, kparams->kernel_type, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2428
|
+
dst->nb[1], src0->nb[1], src1->nb[1], d, false, false, false
|
|
2429
|
+
);
|
|
2430
|
+
if (L.total_bytes <= vtcm_budget) {
|
|
2431
|
+
best_n_prefetch = d;
|
|
2432
|
+
break;
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
if (best_n_prefetch == 2 && L.total_bytes > vtcm_budget) {
|
|
2436
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2437
|
+
&L, kparams->kernel_type, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2438
|
+
dst->nb[1], src0->nb[1], src1->nb[1], 2, false, false, false
|
|
2439
|
+
);
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
kparams->n_prefetch = best_n_prefetch;
|
|
2443
|
+
|
|
2444
|
+
if (L.total_bytes <= vtcm_budget) {
|
|
2445
|
+
kparams->vtcm_size = L.total_bytes;
|
|
2446
|
+
kparams->vtcm_src0_size = L.src0_bytes;
|
|
2447
|
+
kparams->vtcm_src1_size = L.src1_bytes;
|
|
2448
|
+
kparams->vtcm_dst_size = L.dst_bytes;
|
|
2449
|
+
goto done_quant;
|
|
2450
|
+
}
|
|
2451
|
+
HEX_VERBOSE("ggml-hex: %s HVX tiled path VTCM size needed (%zu) > budget (%zu), falling back to HVX flat\n", sess->name.c_str(), L.total_bytes, vtcm_budget);
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
// Flat HVX fallback
|
|
2455
|
+
{
|
|
2456
|
+
kparams->src1_row_size = (wtype == GGML_TYPE_Q4_1) ? htp_mm_q8_1_flat_row_size(ne10) : htp_mm_q8_0_flat_row_size(ne10);
|
|
2457
|
+
kparams->kernel_type = HTP_MM_KERNEL_HVX_QUANT_ROW_FLAT;
|
|
2458
|
+
|
|
2459
|
+
struct htp_mm_hvx_vtcm_layout L;
|
|
2460
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2461
|
+
&L, kparams->kernel_type, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2462
|
+
dst->nb[1], src0->nb[1], src1->nb[1], 16, false, false, false
|
|
2463
|
+
);
|
|
2464
|
+
|
|
2465
|
+
kparams->n_prefetch = 16;
|
|
2466
|
+
kparams->vtcm_size = L.total_bytes;
|
|
2467
|
+
kparams->vtcm_src0_size = L.src0_bytes;
|
|
2468
|
+
kparams->vtcm_src1_size = L.src1_bytes;
|
|
2469
|
+
kparams->vtcm_dst_size = L.dst_bytes;
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
done_quant:;
|
|
2474
|
+
} else if (wtype == GGML_TYPE_F16) {
|
|
2475
|
+
// F16 HVX
|
|
2476
|
+
const bool is_batched = (ne02 > 1) || (ne03 > 1);
|
|
2477
|
+
const bool is_permuted = ggml_is_permuted(src0) || ggml_is_permuted(src1);
|
|
2478
|
+
|
|
2479
|
+
struct htp_mm_hvx_vtcm_layout L;
|
|
2480
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2481
|
+
&L, HTP_MM_KERNEL_HVX_F16_F16_VTCM, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2482
|
+
dst->nb[1], src0->nb[1], src1->nb[1], 16, false, false, false
|
|
2483
|
+
);
|
|
2484
|
+
|
|
2485
|
+
if (!is_batched && !is_permuted && L.total_bytes <= vtcm_budget) {
|
|
2486
|
+
kparams->kernel_type = HTP_MM_KERNEL_HVX_F16_F16_VTCM;
|
|
2487
|
+
kparams->src1_row_size = hex_round_up(ne10 * 2, 128);
|
|
2488
|
+
kparams->vtcm_size = L.total_bytes;
|
|
2489
|
+
kparams->vtcm_src0_size = L.src0_bytes;
|
|
2490
|
+
kparams->vtcm_src1_size = L.src1_bytes;
|
|
2491
|
+
kparams->vtcm_dst_size = L.dst_bytes;
|
|
2492
|
+
kparams->n_prefetch = 16;
|
|
2493
|
+
} else {
|
|
2494
|
+
if (src1->type == GGML_TYPE_F32) {
|
|
2495
|
+
kparams->kernel_type = HTP_MM_KERNEL_HVX_F16_F32_DDR;
|
|
2496
|
+
} else {
|
|
2497
|
+
kparams->kernel_type = HTP_MM_KERNEL_HVX_F16_F16_DDR;
|
|
2498
|
+
}
|
|
2499
|
+
kparams->src1_row_size = src1->nb[1];
|
|
2500
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2501
|
+
&L, kparams->kernel_type, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2502
|
+
dst->nb[1], src0->nb[1], src1->nb[1], 16, false, false, false
|
|
2503
|
+
);
|
|
2504
|
+
kparams->vtcm_size = L.total_bytes;
|
|
2505
|
+
kparams->vtcm_src0_size = L.src0_bytes;
|
|
2506
|
+
kparams->vtcm_src1_size = L.src1_bytes;
|
|
2507
|
+
kparams->vtcm_dst_size = L.dst_bytes;
|
|
2508
|
+
kparams->n_prefetch = 16;
|
|
2509
|
+
}
|
|
2510
|
+
} else {
|
|
2511
|
+
// F32 HVX
|
|
2512
|
+
const bool is_batched = (ne02 > 1) || (ne03 > 1);
|
|
2513
|
+
const bool is_permuted = ggml_is_permuted(src0) || ggml_is_permuted(src1);
|
|
2514
|
+
|
|
2515
|
+
struct htp_mm_hvx_vtcm_layout L;
|
|
2516
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2517
|
+
&L, HTP_MM_KERNEL_HVX_F32_F32_VTCM, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2518
|
+
dst->nb[1], src0->nb[1], src1->nb[1], 16, false, false, false
|
|
2519
|
+
);
|
|
2520
|
+
|
|
2521
|
+
if (!is_batched && !is_permuted && L.total_bytes <= vtcm_budget) {
|
|
2522
|
+
kparams->kernel_type = HTP_MM_KERNEL_HVX_F32_F32_VTCM;
|
|
2523
|
+
kparams->src1_row_size = hex_round_up(ne10 * 4, 128);
|
|
2524
|
+
kparams->vtcm_size = L.total_bytes;
|
|
2525
|
+
kparams->vtcm_src0_size = L.src0_bytes;
|
|
2526
|
+
kparams->vtcm_src1_size = L.src1_bytes;
|
|
2527
|
+
kparams->vtcm_dst_size = L.dst_bytes;
|
|
2528
|
+
kparams->n_prefetch = 16;
|
|
2529
|
+
} else {
|
|
2530
|
+
kparams->kernel_type = HTP_MM_KERNEL_HVX_F32_F32_DDR;
|
|
2531
|
+
kparams->src1_row_size = src1->nb[1];
|
|
2532
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2533
|
+
&L, kparams->kernel_type, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2534
|
+
dst->nb[1], src0->nb[1], src1->nb[1], 16, false, false, false
|
|
2535
|
+
);
|
|
2536
|
+
kparams->vtcm_size = L.total_bytes;
|
|
2537
|
+
kparams->vtcm_src0_size = L.src0_bytes;
|
|
2538
|
+
kparams->vtcm_src1_size = L.src1_bytes;
|
|
2539
|
+
kparams->vtcm_dst_size = L.dst_bytes;
|
|
2540
|
+
kparams->n_prefetch = 16;
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
static void ggml_hexagon_precompute_matmul_params(
|
|
2546
|
+
const struct ggml_hexagon_session * sess,
|
|
2547
|
+
const struct ggml_tensor * src0,
|
|
2548
|
+
const struct ggml_tensor * src1,
|
|
2549
|
+
const struct ggml_tensor * dst,
|
|
2550
|
+
struct htp_mm_kernel_params * kparams
|
|
2551
|
+
) {
|
|
2552
|
+
memset(kparams, 0, sizeof(*kparams));
|
|
2553
|
+
|
|
2554
|
+
const int ne00 = src0->ne[0];
|
|
2555
|
+
const int ne01 = src0->ne[1];
|
|
2556
|
+
const int ne02 = src0->ne[2];
|
|
2557
|
+
const int ne03 = src0->ne[3];
|
|
2558
|
+
|
|
2559
|
+
const int ne10 = src1->ne[0];
|
|
2560
|
+
const int ne11 = src1->ne[1];
|
|
2561
|
+
const int ne12 = src1->ne[2];
|
|
2562
|
+
const int ne13 = src1->ne[3];
|
|
2563
|
+
|
|
2564
|
+
const int wtype = src0->type;
|
|
2565
|
+
const bool is_repack = ggml_hexagon_is_repack_type((ggml_type) wtype);
|
|
2566
|
+
const int ne00_padded = is_repack ? hex_round_up(ne00, 32) : ne00;
|
|
2567
|
+
const int ne01_padded = is_repack ? hex_round_up(ne01, 32) : ne01;
|
|
2568
|
+
const int ne11_padded = hex_round_up(ne11, 32);
|
|
2569
|
+
|
|
2570
|
+
const bool is_matmul_id = (dst->op == GGML_OP_MUL_MAT_ID);
|
|
2571
|
+
const bool is_batched = (ne02 * ne03 > 1 || ne12 * ne13 > 1);
|
|
2572
|
+
|
|
2573
|
+
const size_t vtcm_budget = sess->vtcm_size;
|
|
2574
|
+
|
|
2575
|
+
// Check HMX eligibility and try precomputing HMX parameters
|
|
2576
|
+
bool hmx_enabled = (sess->n_hmx > 0) && (opt_mm_select >= 3);
|
|
2577
|
+
if (hmx_enabled && ggml_hexagon_matmul_is_hmx_eligible(src0, src1, dst, ne01_padded, is_matmul_id, is_batched)) {
|
|
2578
|
+
if (ggml_hexagon_precompute_hmx_mm_params(sess, src0, src1, dst, wtype, ne00_padded, ne01_padded, ne02, ne11, ne12, ne11_padded, is_matmul_id, is_batched, vtcm_budget, kparams)) {
|
|
2579
|
+
goto finalize;
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
|
|
2583
|
+
// Fallback to HVX parameter computation
|
|
2584
|
+
ggml_hexagon_precompute_hvx_mm_params(sess, src0, src1, dst, wtype, ne02, ne03, ne10, ne11, ne12, ne13, is_matmul_id, vtcm_budget, kparams);
|
|
2585
|
+
|
|
2586
|
+
finalize:
|
|
2587
|
+
kparams->div_ne12_ne1 = init_fastdiv_values(ne12 * ne11);
|
|
2588
|
+
kparams->div_ne1 = init_fastdiv_values(ne11);
|
|
2589
|
+
kparams->div_r2 = init_fastdiv_values(ne02 > 0 ? ne12 / ne02 : 1);
|
|
2590
|
+
kparams->div_r3 = init_fastdiv_values(ne03 > 0 ? ne13 / ne03 : 1);
|
|
2591
|
+
kparams->div_ne11 = init_fastdiv_values(ne11);
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2594
|
+
static void ggml_hexagon_precompute_fused_qkv_params(
|
|
2595
|
+
const struct ggml_hexagon_session * sess,
|
|
2596
|
+
const struct ggml_tensor * src0, // Wk
|
|
2597
|
+
const struct ggml_tensor * src1, // x
|
|
2598
|
+
struct htp_mm_kernel_params * kparams
|
|
2599
|
+
) {
|
|
2600
|
+
memset(kparams, 0, sizeof(*kparams));
|
|
2601
|
+
|
|
2602
|
+
const int wtype = src0->type;
|
|
2603
|
+
const bool is_repack = ggml_hexagon_is_repack_type((ggml_type) wtype);
|
|
2604
|
+
|
|
2605
|
+
const int ne10 = src1->ne[0];
|
|
2606
|
+
const int src1_nrows = src1->ne[1] * src1->ne[2] * src1->ne[3];
|
|
2607
|
+
const size_t src1_row_size = (wtype == GGML_TYPE_Q4_1) ? htp_mm_q8_1_tiled_row_size(ne10) : htp_mm_q8_0_tiled_row_size(ne10);
|
|
2608
|
+
const size_t src0_row_size = src0->nb[1];
|
|
2609
|
+
|
|
2610
|
+
uint32_t best_n_prefetch = 16;
|
|
2611
|
+
|
|
2612
|
+
if (is_repack) {
|
|
2613
|
+
const uint32_t max_prefetch = (src1_nrows > HTP_MM_HMX_MIN_NROWS) ? 2 : 16;
|
|
2614
|
+
best_n_prefetch = 2;
|
|
2615
|
+
for (uint32_t d = max_prefetch; d >= 2; d /= 2) {
|
|
2616
|
+
struct htp_mm_hvx_vtcm_layout L;
|
|
2617
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2618
|
+
&L, HTP_MM_KERNEL_HVX_QUANT_ROW, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2619
|
+
0, src0_row_size, src1_row_size, d, false, true, false
|
|
2620
|
+
);
|
|
2621
|
+
if (L.total_bytes <= sess->vtcm_size) {
|
|
2622
|
+
best_n_prefetch = d;
|
|
2623
|
+
break;
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
|
|
2628
|
+
struct htp_mm_hvx_vtcm_layout L;
|
|
2629
|
+
bool try_tiled = (opt_mm_select >= 2);
|
|
2630
|
+
|
|
2631
|
+
// Test tiled first
|
|
2632
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2633
|
+
&L, HTP_MM_KERNEL_HVX_QUANT_ROW, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2634
|
+
0, src0_row_size, src1_row_size, best_n_prefetch, false, true, false
|
|
2635
|
+
);
|
|
2636
|
+
|
|
2637
|
+
if (try_tiled && L.total_bytes <= sess->vtcm_size) {
|
|
2638
|
+
kparams->kernel_type = HTP_MM_KERNEL_HVX_QUANT_ROW;
|
|
2639
|
+
kparams->vtcm_src0_size = L.src0_bytes;
|
|
2640
|
+
kparams->vtcm_src1_size = L.src1_bytes;
|
|
2641
|
+
kparams->vtcm_src2_size = L.src2_bytes;
|
|
2642
|
+
kparams->vtcm_src3_size = L.src3_bytes;
|
|
2643
|
+
kparams->vtcm_dst_size = L.dst_bytes;
|
|
2644
|
+
kparams->vtcm_size = L.total_bytes;
|
|
2645
|
+
kparams->n_prefetch = best_n_prefetch;
|
|
2646
|
+
} else {
|
|
2647
|
+
kparams->kernel_type = HTP_MM_KERNEL_HVX_QUANT_ROW_FLAT;
|
|
2648
|
+
size_t flat_src1_row_size = (wtype == GGML_TYPE_Q4_1) ? htp_mm_q8_1_flat_row_size(ne10) : htp_mm_q8_0_flat_row_size(ne10);
|
|
2649
|
+
|
|
2650
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2651
|
+
&L, HTP_MM_KERNEL_HVX_QUANT_ROW_FLAT, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2652
|
+
0, src0_row_size, flat_src1_row_size, best_n_prefetch, false, true, false
|
|
2653
|
+
);
|
|
2654
|
+
kparams->vtcm_src0_size = L.src0_bytes;
|
|
2655
|
+
kparams->vtcm_src1_size = L.src1_bytes;
|
|
2656
|
+
kparams->vtcm_src2_size = L.src2_bytes;
|
|
2657
|
+
kparams->vtcm_src3_size = L.src3_bytes;
|
|
2658
|
+
kparams->vtcm_dst_size = L.dst_bytes;
|
|
2659
|
+
kparams->vtcm_size = L.total_bytes;
|
|
2660
|
+
kparams->n_prefetch = best_n_prefetch;
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2664
|
+
static void ggml_hexagon_precompute_fused_ffn_params(
|
|
2665
|
+
const struct ggml_hexagon_session * sess,
|
|
2666
|
+
const struct ggml_tensor * src0, // Wgate
|
|
2667
|
+
const struct ggml_tensor * src1, // y
|
|
2668
|
+
struct htp_mm_kernel_params * kparams
|
|
2669
|
+
) {
|
|
2670
|
+
memset(kparams, 0, sizeof(*kparams));
|
|
2671
|
+
|
|
2672
|
+
const int wtype = src0->type;
|
|
2673
|
+
const bool is_repack = ggml_hexagon_is_repack_type((ggml_type) wtype);
|
|
2674
|
+
|
|
2675
|
+
const int ne10 = src1->ne[0];
|
|
2676
|
+
const int src1_nrows = src1->ne[1] * src1->ne[2] * src1->ne[3];
|
|
2677
|
+
const size_t src1_row_size = (wtype == GGML_TYPE_Q4_1) ? htp_mm_q8_1_tiled_row_size(ne10) : htp_mm_q8_0_tiled_row_size(ne10);
|
|
2678
|
+
const size_t src0_row_size = src0->nb[1];
|
|
2679
|
+
|
|
2680
|
+
uint32_t best_n_prefetch = 16;
|
|
2681
|
+
|
|
2682
|
+
if (is_repack) {
|
|
2683
|
+
const uint32_t max_prefetch = (src1_nrows > HTP_MM_HMX_MIN_NROWS) ? 2 : 16;
|
|
2684
|
+
best_n_prefetch = 2;
|
|
2685
|
+
for (uint32_t d = max_prefetch; d >= 2; d /= 2) {
|
|
2686
|
+
struct htp_mm_hvx_vtcm_layout L;
|
|
2687
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2688
|
+
&L, HTP_MM_KERNEL_HVX_QUANT_ROW, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2689
|
+
0, src0_row_size, src1_row_size, d, false, false, true
|
|
2690
|
+
);
|
|
2691
|
+
if (L.total_bytes <= sess->vtcm_size) {
|
|
2692
|
+
best_n_prefetch = d;
|
|
2693
|
+
break;
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2698
|
+
struct htp_mm_hvx_vtcm_layout L;
|
|
2699
|
+
bool try_tiled = (opt_mm_select >= 2);
|
|
2700
|
+
|
|
2701
|
+
// Test tiled first
|
|
2702
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2703
|
+
&L, HTP_MM_KERNEL_HVX_QUANT_ROW, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2704
|
+
0, src0_row_size, src1_row_size, best_n_prefetch, false, false, true
|
|
2705
|
+
);
|
|
2706
|
+
|
|
2707
|
+
if (try_tiled && L.total_bytes <= sess->vtcm_size) {
|
|
2708
|
+
kparams->kernel_type = HTP_MM_KERNEL_HVX_QUANT_ROW;
|
|
2709
|
+
kparams->vtcm_src0_size = L.src0_bytes;
|
|
2710
|
+
kparams->vtcm_src1_size = L.src1_bytes;
|
|
2711
|
+
kparams->vtcm_src2_size = L.src2_bytes;
|
|
2712
|
+
kparams->vtcm_dst_size = L.dst_bytes;
|
|
2713
|
+
kparams->vtcm_size = L.total_bytes;
|
|
2714
|
+
kparams->n_prefetch = best_n_prefetch;
|
|
2715
|
+
} else {
|
|
2716
|
+
kparams->kernel_type = HTP_MM_KERNEL_HVX_QUANT_ROW_FLAT;
|
|
2717
|
+
size_t flat_src1_row_size = (wtype == GGML_TYPE_Q4_1) ? htp_mm_q8_1_flat_row_size(ne10) : htp_mm_q8_0_flat_row_size(ne10);
|
|
2718
|
+
|
|
2719
|
+
htp_mm_hvx_vtcm_layout_build(
|
|
2720
|
+
&L, HTP_MM_KERNEL_HVX_QUANT_ROW_FLAT, wtype, ne10, src1_nrows, sess->n_threads,
|
|
2721
|
+
0, src0_row_size, flat_src1_row_size, best_n_prefetch, false, false, true
|
|
2722
|
+
);
|
|
2723
|
+
kparams->vtcm_src0_size = L.src0_bytes;
|
|
2724
|
+
kparams->vtcm_src1_size = L.src1_bytes;
|
|
2725
|
+
kparams->vtcm_src2_size = L.src2_bytes;
|
|
2726
|
+
kparams->vtcm_dst_size = L.dst_bytes;
|
|
2727
|
+
kparams->vtcm_size = L.total_bytes;
|
|
2728
|
+
kparams->n_prefetch = best_n_prefetch;
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2566
2732
|
static bool ggml_hexagon_supported_mul_mat(const struct ggml_hexagon_session * sess, const struct ggml_tensor * dst) {
|
|
2567
2733
|
const struct ggml_tensor * src0 = dst->src[0];
|
|
2568
2734
|
const struct ggml_tensor * src1 = dst->src[1];
|
|
@@ -2585,12 +2751,13 @@ static bool ggml_hexagon_supported_mul_mat(const struct ggml_hexagon_session * s
|
|
|
2585
2751
|
return false;
|
|
2586
2752
|
}
|
|
2587
2753
|
|
|
2588
|
-
|
|
2589
|
-
|
|
2754
|
+
// hardcoded limit to refuse the lm-head for now
|
|
2755
|
+
if (src0->ne[1] > 32768) {
|
|
2756
|
+
return false;
|
|
2590
2757
|
}
|
|
2591
2758
|
|
|
2592
|
-
if (
|
|
2593
|
-
return false; // no
|
|
2759
|
+
if (src1->ne[2] != 1 || src1->ne[3] != 1) {
|
|
2760
|
+
return false; // no broadcasting (for now)
|
|
2594
2761
|
}
|
|
2595
2762
|
|
|
2596
2763
|
// src0 (weights) must be repacked
|
|
@@ -2601,16 +2768,11 @@ static bool ggml_hexagon_supported_mul_mat(const struct ggml_hexagon_session * s
|
|
|
2601
2768
|
|
|
2602
2769
|
case GGML_TYPE_F16:
|
|
2603
2770
|
if (src0->nb[1] < src0->nb[0]) {
|
|
2604
|
-
GGML_LOG_DEBUG("ggml_hexagon_supported_mul_mat: permuted F16 src0 not supported\n");
|
|
2605
2771
|
return false;
|
|
2606
2772
|
}
|
|
2607
2773
|
if (src1->ne[2] < src0->ne[2] || src1->ne[3] < src0->ne[3]) {
|
|
2608
|
-
GGML_LOG_DEBUG("ggml_hexagon_supported_mul_mat: src1 broadcasting not supported\n");
|
|
2609
2774
|
return false;
|
|
2610
2775
|
}
|
|
2611
|
-
if (ggml_nrows(src1) > 1024) {
|
|
2612
|
-
return false; // no huge batches (for now)
|
|
2613
|
-
}
|
|
2614
2776
|
break;
|
|
2615
2777
|
|
|
2616
2778
|
case GGML_TYPE_F32:
|
|
@@ -2618,22 +2780,24 @@ static bool ggml_hexagon_supported_mul_mat(const struct ggml_hexagon_session * s
|
|
|
2618
2780
|
return false;
|
|
2619
2781
|
}
|
|
2620
2782
|
if (src0->nb[1] < src0->nb[0]) {
|
|
2621
|
-
GGML_LOG_DEBUG("ggml_hexagon_supported_mul_mat: permuted F32 src0 not supported\n");
|
|
2622
2783
|
return false;
|
|
2623
2784
|
}
|
|
2624
2785
|
if (src1->ne[2] < src0->ne[2] || src1->ne[3] < src0->ne[3]) {
|
|
2625
|
-
GGML_LOG_DEBUG("ggml_hexagon_supported_mul_mat: src1 broadcasting not supported\n");
|
|
2626
2786
|
return false;
|
|
2627
2787
|
}
|
|
2628
|
-
if (ggml_nrows(src1) > 1024) {
|
|
2629
|
-
return false; // no huge batches (for now)
|
|
2630
|
-
}
|
|
2631
2788
|
break;
|
|
2632
2789
|
|
|
2633
2790
|
default:
|
|
2634
2791
|
return false;
|
|
2635
2792
|
}
|
|
2636
2793
|
|
|
2794
|
+
struct htp_mm_kernel_params kparams;
|
|
2795
|
+
ggml_hexagon_precompute_matmul_params(sess, src0, src1, dst, &kparams);
|
|
2796
|
+
if ((size_t)kparams.vtcm_size > sess->vtcm_size) {
|
|
2797
|
+
HEX_VERBOSE("ggml-hex: %s supported MUL_MAT VTCM size needed (%d) > budget (%zu)\n", sess->c_name(), kparams.vtcm_size, sess->vtcm_size);
|
|
2798
|
+
return false;
|
|
2799
|
+
}
|
|
2800
|
+
|
|
2637
2801
|
return true;
|
|
2638
2802
|
}
|
|
2639
2803
|
|
|
@@ -2667,6 +2831,13 @@ static bool ggml_hexagon_supported_mul_mat_id(const struct ggml_hexagon_session
|
|
|
2667
2831
|
return false;
|
|
2668
2832
|
}
|
|
2669
2833
|
|
|
2834
|
+
struct htp_mm_kernel_params kparams;
|
|
2835
|
+
ggml_hexagon_precompute_matmul_params(sess, src0, src1, dst, &kparams);
|
|
2836
|
+
if ((size_t)kparams.vtcm_size > sess->vtcm_size) {
|
|
2837
|
+
HEX_VERBOSE("ggml-hex: %s supported MUL_MAT_ID VTCM size needed (%d) > budget (%zu)\n", sess->c_name(), kparams.vtcm_size, sess->vtcm_size);
|
|
2838
|
+
return false;
|
|
2839
|
+
}
|
|
2840
|
+
|
|
2670
2841
|
return true;
|
|
2671
2842
|
}
|
|
2672
2843
|
|
|
@@ -2934,8 +3105,12 @@ static bool ggml_hexagon_supported_rope(const struct ggml_hexagon_session * sess
|
|
|
2934
3105
|
|
|
2935
3106
|
int mode = op_params[2];
|
|
2936
3107
|
|
|
3108
|
+
// n_dims == ne0/2, so the rotation spans the full row
|
|
2937
3109
|
if (mode == GGML_ROPE_TYPE_VISION) {
|
|
2938
|
-
|
|
3110
|
+
const int n_dims = op_params[1];
|
|
3111
|
+
if (n_dims != (int) (op->src[0]->ne[0] / 2)) {
|
|
3112
|
+
return false;
|
|
3113
|
+
}
|
|
2939
3114
|
}
|
|
2940
3115
|
if (mode & 1) {
|
|
2941
3116
|
return false;
|
|
@@ -2966,16 +3141,23 @@ static bool ggml_hexagon_supported_rope(const struct ggml_hexagon_session * sess
|
|
|
2966
3141
|
}
|
|
2967
3142
|
|
|
2968
3143
|
if (src2) {
|
|
2969
|
-
if (!ggml_is_contiguous(
|
|
2970
|
-
!ggml_is_contiguous(dst)) {
|
|
3144
|
+
if (!ggml_is_contiguous(src1) || !ggml_is_contiguous(src2)) {
|
|
2971
3145
|
return false;
|
|
2972
3146
|
}
|
|
2973
3147
|
} else {
|
|
2974
|
-
if (!ggml_is_contiguous(
|
|
3148
|
+
if (!ggml_is_contiguous(src1)) {
|
|
2975
3149
|
return false;
|
|
2976
3150
|
}
|
|
2977
3151
|
}
|
|
2978
3152
|
|
|
3153
|
+
// src0/dst elements within a row must be contiguous (nb[0] == sizeof(float)).
|
|
3154
|
+
// nb[1] may exceed ne[0]*sizeof(float) when the tensor is a strided view of a larger one
|
|
3155
|
+
if (src0->nb[0] != sizeof(float) || dst->nb[0] != sizeof(float)) {
|
|
3156
|
+
return false;
|
|
3157
|
+
}
|
|
3158
|
+
if (src0->nb[1] < src0->ne[0] * sizeof(float) || dst->nb[1] < dst->ne[0] * sizeof(float)) {
|
|
3159
|
+
return false;
|
|
3160
|
+
}
|
|
2979
3161
|
return true;
|
|
2980
3162
|
}
|
|
2981
3163
|
|
|
@@ -3198,47 +3380,197 @@ static inline bool op_is_compute(ggml_tensor *node)
|
|
|
3198
3380
|
return !ggml_op_is_empty(node->op) && !ggml_is_empty(node) && (node->flags & GGML_TENSOR_FLAG_COMPUTE);
|
|
3199
3381
|
}
|
|
3200
3382
|
|
|
3383
|
+
static bool mm_is_hmx_eligible(const ggml_tensor * t) {
|
|
3384
|
+
if (opt_nhmx == 0) { return false; }
|
|
3385
|
+
|
|
3386
|
+
const ggml_tensor * src0 = t->src[0];
|
|
3387
|
+
const ggml_tensor * src1 = t->src[1];
|
|
3388
|
+
|
|
3389
|
+
const int wtype = src0->type;
|
|
3390
|
+
const bool is_repack = ggml_hexagon_is_repack_type((ggml_type) wtype);
|
|
3391
|
+
const bool is_matmul_id = (t->op == GGML_OP_MUL_MAT_ID);
|
|
3392
|
+
const bool is_batched = (src0->ne[2] * src0->ne[3] > 1 || src1->ne[2] * src1->ne[3] > 1);
|
|
3393
|
+
|
|
3394
|
+
const int ne01_padded = is_repack ? hex_round_up(src0->ne[1], 32) : src0->ne[1];
|
|
3395
|
+
|
|
3396
|
+
return ggml_hexagon_matmul_is_hmx_eligible(src0, src1, t, ne01_padded, is_matmul_id, is_batched);
|
|
3397
|
+
}
|
|
3398
|
+
|
|
3399
|
+
static bool is_mergeable_mul_mat(const ggml_tensor * t) {
|
|
3400
|
+
if (!t || t->op != GGML_OP_MUL_MAT) return false;
|
|
3401
|
+
if (t->src[1]->type != GGML_TYPE_F32) return false;
|
|
3402
|
+
return ggml_is_quantized(t->src[0]->type) && !mm_is_hmx_eligible(t);
|
|
3403
|
+
}
|
|
3404
|
+
|
|
3405
|
+
static bool is_mergeable_mul_mat_pair(const ggml_tensor * n1, const ggml_tensor * n2) {
|
|
3406
|
+
if (!is_mergeable_mul_mat(n1) || !is_mergeable_mul_mat(n2)) {
|
|
3407
|
+
return false;
|
|
3408
|
+
}
|
|
3409
|
+
if (n1->src[1] != n2->src[1]) {
|
|
3410
|
+
return false;
|
|
3411
|
+
}
|
|
3412
|
+
if (n1->src[0]->ne[0] != n2->src[0]->ne[0] ||
|
|
3413
|
+
n1->src[0]->ne[1] != n2->src[0]->ne[1]) {
|
|
3414
|
+
return false;
|
|
3415
|
+
}
|
|
3416
|
+
if (n1->src[0]->type != n2->src[0]->type) {
|
|
3417
|
+
return false;
|
|
3418
|
+
}
|
|
3419
|
+
return true;
|
|
3420
|
+
}
|
|
3421
|
+
|
|
3422
|
+
static bool is_qkv_mergeable(const ggml_tensor * n_q, const ggml_tensor * n_k, const ggml_tensor * n_v) {
|
|
3423
|
+
if (!is_mergeable_mul_mat(n_q) || !is_mergeable_mul_mat(n_k) || !is_mergeable_mul_mat(n_v)) {
|
|
3424
|
+
return false;
|
|
3425
|
+
}
|
|
3426
|
+
if (n_q->src[1] != n_k->src[1] || n_q->src[1] != n_v->src[1]) {
|
|
3427
|
+
return false;
|
|
3428
|
+
}
|
|
3429
|
+
if (n_q->src[0]->type != n_k->src[0]->type || n_q->src[0]->type != n_v->src[0]->type) {
|
|
3430
|
+
return false;
|
|
3431
|
+
}
|
|
3432
|
+
if (n_k->src[0]->ne[0] != n_v->src[0]->ne[0] ||
|
|
3433
|
+
n_k->src[0]->ne[1] != n_v->src[0]->ne[1]) {
|
|
3434
|
+
return false;
|
|
3435
|
+
}
|
|
3436
|
+
if (n_q->src[0]->ne[0] != n_k->src[0]->ne[0]) {
|
|
3437
|
+
return false;
|
|
3438
|
+
}
|
|
3439
|
+
return true;
|
|
3440
|
+
}
|
|
3441
|
+
|
|
3442
|
+
static bool try_fuse_node(const ggml_hexagon_session * sess, const ggml_cgraph * graph, int & i, std::vector<htp_opnode> & nodes) {
|
|
3443
|
+
if (!opt_opfusion) {
|
|
3444
|
+
return false;
|
|
3445
|
+
}
|
|
3446
|
+
|
|
3447
|
+
ggml_tensor * n = graph->nodes[i];
|
|
3448
|
+
ggml_tensor * next_node = (i + 1 < graph->n_nodes) ? graph->nodes[i + 1] : nullptr;
|
|
3449
|
+
|
|
3450
|
+
if (n->op == GGML_OP_RMS_NORM && next_node) {
|
|
3451
|
+
if (next_node->op == GGML_OP_MUL && op_is_compute(next_node) && ggml_can_fuse(graph, i, { GGML_OP_RMS_NORM, GGML_OP_MUL })) {
|
|
3452
|
+
htp_opnode node(n, {}, HTP_OP_RMS_NORM_MUL);
|
|
3453
|
+
node.add_fused(next_node);
|
|
3454
|
+
nodes.push_back(std::move(node));
|
|
3455
|
+
i++; // skip the fused MUL node
|
|
3456
|
+
return true;
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
|
|
3460
|
+
if (is_mergeable_mul_mat(n)) {
|
|
3461
|
+
ggml_tensor * n1 = (i + 1 < graph->n_nodes) ? graph->nodes[i + 1] : nullptr;
|
|
3462
|
+
ggml_tensor * n2 = (i + 2 < graph->n_nodes) ? graph->nodes[i + 2] : nullptr;
|
|
3463
|
+
if (is_qkv_mergeable(n, n1, n2)) {
|
|
3464
|
+
struct htp_mm_kernel_params kparams;
|
|
3465
|
+
ggml_hexagon_precompute_fused_qkv_params(sess, n1->src[0], n1->src[1], &kparams);
|
|
3466
|
+
if ((size_t)kparams.vtcm_size <= sess->vtcm_size) {
|
|
3467
|
+
// Reorder to KVQ: K (n1), V (n2), Q (n)
|
|
3468
|
+
htp_opnode node(n1, {}, HTP_OP_MUL_MAT_QKV);
|
|
3469
|
+
node.add_fused(n2, true);
|
|
3470
|
+
node.add_fused(n, true);
|
|
3471
|
+
memcpy(node.kernel_params, &kparams, sizeof(kparams));
|
|
3472
|
+
nodes.push_back(std::move(node));
|
|
3473
|
+
i += 2;
|
|
3474
|
+
return true;
|
|
3475
|
+
} else {
|
|
3476
|
+
HEX_VERBOSE("ggml-hex: skip QKV fusion because VTCM needed (%d) > budget (%zu)\n",
|
|
3477
|
+
kparams.vtcm_size, sess->vtcm_size);
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3480
|
+
if (is_mergeable_mul_mat_pair(n, n1)) {
|
|
3481
|
+
struct htp_mm_kernel_params kparams;
|
|
3482
|
+
ggml_hexagon_precompute_fused_ffn_params(sess, n->src[0], n->src[1], &kparams);
|
|
3483
|
+
if ((size_t)kparams.vtcm_size <= sess->vtcm_size) {
|
|
3484
|
+
htp_opnode node(n, {}, HTP_OP_MUL_MAT_FFN);
|
|
3485
|
+
node.add_fused(n1, true);
|
|
3486
|
+
memcpy(node.kernel_params, &kparams, sizeof(kparams));
|
|
3487
|
+
nodes.push_back(std::move(node));
|
|
3488
|
+
i += 1;
|
|
3489
|
+
return true;
|
|
3490
|
+
} else {
|
|
3491
|
+
HEX_VERBOSE("ggml-hex: skip FFN fusion because VTCM needed (%d) > budget (%zu)\n",
|
|
3492
|
+
kparams.vtcm_size, sess->vtcm_size);
|
|
3493
|
+
}
|
|
3494
|
+
}
|
|
3495
|
+
}
|
|
3496
|
+
|
|
3497
|
+
if (n->op == GGML_OP_MUL_MAT && next_node) {
|
|
3498
|
+
if (next_node->op == GGML_OP_ADD && op_is_compute(next_node) && ggml_can_fuse(graph, i, { GGML_OP_MUL_MAT, GGML_OP_ADD })) {
|
|
3499
|
+
if (next_node->src[0] == n || next_node->src[1] == n) {
|
|
3500
|
+
struct htp_mm_kernel_params kparams;
|
|
3501
|
+
ggml_hexagon_precompute_matmul_params(sess, n->src[0], n->src[1], next_node, &kparams);
|
|
3502
|
+
if ((size_t)kparams.vtcm_size <= sess->vtcm_size) {
|
|
3503
|
+
htp_opnode node(n, {}, HTP_OP_MUL_MAT_ADD);
|
|
3504
|
+
node.add_fused(next_node);
|
|
3505
|
+
memcpy(node.kernel_params, &kparams, sizeof(kparams));
|
|
3506
|
+
nodes.push_back(std::move(node));
|
|
3507
|
+
i += 1;
|
|
3508
|
+
return true;
|
|
3509
|
+
} else {
|
|
3510
|
+
HEX_VERBOSE("ggml-hex: skip MUL_MAT_ADD fusion because VTCM needed (%d) > budget (%zu)\n",
|
|
3511
|
+
kparams.vtcm_size, sess->vtcm_size);
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
}
|
|
3516
|
+
|
|
3517
|
+
return false;
|
|
3518
|
+
}
|
|
3519
|
+
|
|
3201
3520
|
static ggml_status ggml_backend_hexagon_graph_compute(ggml_backend_t backend, ggml_cgraph * graph) {
|
|
3202
3521
|
auto sess = static_cast<ggml_hexagon_session *>(backend->context);
|
|
3203
3522
|
|
|
3204
3523
|
HEX_VERBOSE("ggml-hex: %s graph-compute n_nodes %d\n", sess->c_name(), graph->n_nodes);
|
|
3205
3524
|
|
|
3206
|
-
std::vector<htp_opnode>
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
// Fusion
|
|
3210
|
-
for (int i = 0; i < graph->n_nodes; ++i) {
|
|
3211
|
-
ggml_tensor * n = graph->nodes[i];
|
|
3212
|
-
if (!op_is_compute(n)) {
|
|
3213
|
-
continue;
|
|
3214
|
-
}
|
|
3525
|
+
const std::vector<htp_opnode> * nodes_ptr = nullptr;
|
|
3526
|
+
std::vector<htp_opnode> computed_nodes;
|
|
3215
3527
|
|
|
3216
|
-
|
|
3528
|
+
// Check for cache hit
|
|
3529
|
+
bool cache_hit = (graph->uid != 0 && sess->cached_graph.uid == graph->uid);
|
|
3530
|
+
if (cache_hit) {
|
|
3531
|
+
nodes_ptr = &sess->cached_graph.htp_nodes;
|
|
3532
|
+
} else {
|
|
3533
|
+
computed_nodes.reserve(graph->n_nodes);
|
|
3217
3534
|
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3535
|
+
// Fuse and finalize
|
|
3536
|
+
for (int i = 0; i < graph->n_nodes; ++i) {
|
|
3537
|
+
ggml_tensor * n = graph->nodes[i];
|
|
3538
|
+
if (!op_is_compute(n)) {
|
|
3539
|
+
continue;
|
|
3540
|
+
}
|
|
3223
3541
|
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
node.add_fused(next_node);
|
|
3227
|
-
node.opcode = HTP_OP_RMS_NORM_MUL;
|
|
3228
|
-
i++; // skip the fused MUL node
|
|
3542
|
+
if (try_fuse_node(sess, graph, i, computed_nodes)) {
|
|
3543
|
+
continue;
|
|
3229
3544
|
}
|
|
3230
|
-
}
|
|
3231
3545
|
|
|
3232
|
-
|
|
3546
|
+
htp_opnode node(n, {}, HTP_OP_INVALID);
|
|
3233
3547
|
node.opcode = op_remap_to_htp(n);
|
|
3548
|
+
if (node.opcode == HTP_OP_MUL_MAT || node.opcode == HTP_OP_MUL_MAT_ID) {
|
|
3549
|
+
ggml_hexagon_precompute_matmul_params(sess,
|
|
3550
|
+
node.node->src[0], node.node->src[1], node.node,
|
|
3551
|
+
(struct htp_mm_kernel_params *)node.kernel_params
|
|
3552
|
+
);
|
|
3553
|
+
} else if (node.opcode == HTP_OP_FLASH_ATTN_EXT) {
|
|
3554
|
+
ggml_hexagon_precompute_flash_attn_params(sess,
|
|
3555
|
+
node.node,
|
|
3556
|
+
(struct htp_fa_kernel_params *)node.kernel_params
|
|
3557
|
+
);
|
|
3558
|
+
}
|
|
3559
|
+
computed_nodes.push_back(std::move(node));
|
|
3234
3560
|
}
|
|
3235
3561
|
|
|
3236
|
-
|
|
3562
|
+
if (graph->uid != 0) {
|
|
3563
|
+
sess->cached_graph.uid = graph->uid;
|
|
3564
|
+
sess->cached_graph.htp_nodes = std::move(computed_nodes);
|
|
3565
|
+
nodes_ptr = &sess->cached_graph.htp_nodes;
|
|
3566
|
+
} else {
|
|
3567
|
+
nodes_ptr = &computed_nodes;
|
|
3568
|
+
}
|
|
3237
3569
|
}
|
|
3238
3570
|
|
|
3239
3571
|
// Queue and execute
|
|
3240
3572
|
if (opt_opstage & HTP_OPSTAGE_QUEUE) {
|
|
3241
|
-
for (const auto & node :
|
|
3573
|
+
for (const auto & node : *nodes_ptr) {
|
|
3242
3574
|
sess->enqueue_op(node);
|
|
3243
3575
|
}
|
|
3244
3576
|
}
|
|
@@ -3901,15 +4233,20 @@ static void ggml_hexagon_init(ggml_backend_reg * reg) {
|
|
|
3901
4233
|
const char * str_opbatch = getenv("GGML_HEXAGON_OPBATCH");
|
|
3902
4234
|
const char * str_opqueue = getenv("GGML_HEXAGON_OPQUEUE");
|
|
3903
4235
|
const char * str_oppoll = getenv("GGML_HEXAGON_OPPOLL");
|
|
4236
|
+
const char * str_opfusion = getenv("GGML_HEXAGON_OPFUSION");
|
|
3904
4237
|
const char * str_opfilter = getenv("GGML_HEXAGON_OPFILTER");
|
|
3905
4238
|
const char * str_profile = getenv("GGML_HEXAGON_PROFILE");
|
|
3906
4239
|
const char * str_etm = getenv("GGML_HEXAGON_ETM");
|
|
3907
4240
|
const char * str_nhvx = getenv("GGML_HEXAGON_NHVX");
|
|
3908
4241
|
const char * str_use_hmx = getenv("GGML_HEXAGON_USE_HMX");
|
|
4242
|
+
const char * str_nhmx = getenv("GGML_HEXAGON_NHMX");
|
|
4243
|
+
const char * str_mm_select = getenv("GGML_HEXAGON_MM_SELECT");
|
|
4244
|
+
const char * str_fa_select = getenv("GGML_HEXAGON_FA_SELECT");
|
|
3909
4245
|
const char * str_ndev = getenv("GGML_HEXAGON_NDEV");
|
|
3910
4246
|
const char * str_arch = getenv("GGML_HEXAGON_ARCH");
|
|
3911
4247
|
const char * str_vmem = getenv("GGML_HEXAGON_VMEM");
|
|
3912
4248
|
const char * str_mbuf = getenv("GGML_HEXAGON_MBUF");
|
|
4249
|
+
const char * str_optrace = getenv("GGML_HEXAGON_OPTRACE");
|
|
3913
4250
|
|
|
3914
4251
|
// Init Arch first since it affects other defaults
|
|
3915
4252
|
if (!str_arch) {
|
|
@@ -3938,11 +4275,15 @@ static void ggml_hexagon_init(ggml_backend_reg * reg) {
|
|
|
3938
4275
|
opt_opstage = str_opstage ? strtoul(str_opstage, NULL, 0) : opt_opstage;
|
|
3939
4276
|
opt_opbatch = str_opbatch ? strtoul(str_opbatch, NULL, 0) : opt_opbatch;
|
|
3940
4277
|
opt_opqueue = str_opqueue ? strtoul(str_opqueue, NULL, 0) : opt_opqueue;
|
|
4278
|
+
opt_optrace = str_optrace ? strtoul(str_optrace, NULL, 0) : (opt_opbatch * 128);
|
|
3941
4279
|
opt_oppoll = str_oppoll ? strtoul(str_oppoll, NULL, 0) : opt_oppoll;
|
|
4280
|
+
opt_opfusion = str_opfusion ? atoi(str_opfusion) : opt_opfusion;
|
|
3942
4281
|
opt_profile = str_profile ? atoi(str_profile) : 0;
|
|
3943
4282
|
opt_etm = str_etm ? atoi(str_etm) : 0;
|
|
3944
4283
|
opt_nhvx = str_nhvx ? strtoul(str_nhvx, NULL, 0) : opt_nhvx;
|
|
3945
|
-
|
|
4284
|
+
opt_nhmx = str_nhmx ? atoi(str_nhmx) : (str_use_hmx ? atoi(str_use_hmx) : opt_nhmx);
|
|
4285
|
+
opt_mm_select = str_mm_select ? atoi(str_mm_select) : opt_mm_select;
|
|
4286
|
+
opt_fa_select = str_fa_select ? atoi(str_fa_select) : opt_fa_select;
|
|
3946
4287
|
opt_ndev = str_ndev ? strtoul(str_ndev, NULL, 0) : opt_ndev;
|
|
3947
4288
|
opt_hostbuf = str_hostbuf ? atoi(str_hostbuf) : opt_hostbuf;
|
|
3948
4289
|
opt_mbuf = str_mbuf ? strtoul(str_mbuf, NULL, 0) * MiB : opt_mbuf;
|