cohere-transcribe 0.1.0
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 +7 -0
- data/CHANGELOG.md +21 -0
- data/LICENSE.txt +201 -0
- data/NOTICE +5 -0
- data/README.md +265 -0
- data/THIRD_PARTY_NOTICES.md +67 -0
- data/exe/cohere-transcribe +8 -0
- data/exe/cohere-transcribe-doctor +8 -0
- data/ext/cohere_transcribe_native/CMakeLists.txt +262 -0
- data/ext/cohere_transcribe_native/README.md +26 -0
- data/ext/cohere_transcribe_native/audio_abi.cpp +1416 -0
- data/ext/cohere_transcribe_native/audio_exports.macos +5 -0
- data/ext/cohere_transcribe_native/audio_exports.map +10 -0
- data/ext/cohere_transcribe_native/cohere_abi.cpp +1209 -0
- data/ext/cohere_transcribe_native/exports.macos +40 -0
- data/ext/cohere_transcribe_native/exports.map +45 -0
- data/ext/cohere_transcribe_native/extconf.rb +89 -0
- data/ext/cohere_transcribe_native/test/abi_smoke.rb +232 -0
- data/ext/cohere_transcribe_native/test/audio_matrix_smoke.cpp +121 -0
- data/ext/cohere_transcribe_native/test/audio_reliability_smoke.cpp +198 -0
- data/ext/cohere_transcribe_native/test/native_abi_reliability_smoke.cpp +186 -0
- data/ext/cohere_transcribe_native/test/native_batch_projection_probe.rb +81 -0
- data/ext/cohere_transcribe_native/test/native_cancellation_smoke.cpp +194 -0
- data/lib/cohere/transcribe/alignment/ATTRIBUTION.md +23 -0
- data/lib/cohere/transcribe/alignment/LICENSE.ctc-forced-aligner +407 -0
- data/lib/cohere/transcribe/alignment/LICENSE.torchaudio +25 -0
- data/lib/cohere/transcribe/alignment/LICENSE.uroman +26 -0
- data/lib/cohere/transcribe/alignment/aligner.rb +476 -0
- data/lib/cohere/transcribe/alignment/ctc.rb +224 -0
- data/lib/cohere/transcribe/alignment/text.rb +237 -0
- data/lib/cohere/transcribe/alignment/uroman_data.rb +4950 -0
- data/lib/cohere/transcribe/api.rb +173 -0
- data/lib/cohere/transcribe/asr/batching.rb +472 -0
- data/lib/cohere/transcribe/asr/failure_policy.rb +112 -0
- data/lib/cohere/transcribe/asr/native.rb +676 -0
- data/lib/cohere/transcribe/audio/ATTRIBUTION.md +8 -0
- data/lib/cohere/transcribe/audio/LICENSE.auditok +21 -0
- data/lib/cohere/transcribe/audio/decoder.rb +315 -0
- data/lib/cohere/transcribe/audio/ffmpeg_native.rb +248 -0
- data/lib/cohere/transcribe/audio/segmentation.rb +260 -0
- data/lib/cohere/transcribe/cli.rb +727 -0
- data/lib/cohere/transcribe/configuration.rb +282 -0
- data/lib/cohere/transcribe/constants.rb +14 -0
- data/lib/cohere/transcribe/dense_converter.rb +548 -0
- data/lib/cohere/transcribe/doctor.rb +576 -0
- data/lib/cohere/transcribe/errors.rb +57 -0
- data/lib/cohere/transcribe/gguf_writer.rb +268 -0
- data/lib/cohere/transcribe/hub.rb +436 -0
- data/lib/cohere/transcribe/input.rb +110 -0
- data/lib/cohere/transcribe/licenses/crispasr.txt +21 -0
- data/lib/cohere/transcribe/loader.rb +128 -0
- data/lib/cohere/transcribe/model_identity.rb +440 -0
- data/lib/cohere/transcribe/output/publication.rb +1118 -0
- data/lib/cohere/transcribe/output/rendering.rb +105 -0
- data/lib/cohere/transcribe/output/timing.rb +86 -0
- data/lib/cohere/transcribe/python_text.rb +70 -0
- data/lib/cohere/transcribe/pytorch_checkpoint.rb +1180 -0
- data/lib/cohere/transcribe/runtime/engine.rb +1676 -0
- data/lib/cohere/transcribe/runtime/model_provider.rb +390 -0
- data/lib/cohere/transcribe/runtime/precision.rb +57 -0
- data/lib/cohere/transcribe/runtime/preparation.rb +215 -0
- data/lib/cohere/transcribe/runtime/resources.rb +165 -0
- data/lib/cohere/transcribe/runtime/word_pipeline.rb +364 -0
- data/lib/cohere/transcribe/safetensors.rb +579 -0
- data/lib/cohere/transcribe/state/checkpoint.rb +224 -0
- data/lib/cohere/transcribe/state/contracts.rb +141 -0
- data/lib/cohere/transcribe/state/io.rb +727 -0
- data/lib/cohere/transcribe/state/locking.rb +211 -0
- data/lib/cohere/transcribe/state/manifest.rb +155 -0
- data/lib/cohere/transcribe/state.rb +7 -0
- data/lib/cohere/transcribe/types.rb +535 -0
- data/lib/cohere/transcribe/vad/ATTRIBUTION.md +14 -0
- data/lib/cohere/transcribe/vad/LICENSE.faster-whisper +21 -0
- data/lib/cohere/transcribe/vad/LICENSE.silero-vad +21 -0
- data/lib/cohere/transcribe/vad/silero.rb +344 -0
- data/lib/cohere/transcribe/vad/silero_vad_v6.onnx +0 -0
- data/lib/cohere/transcribe/vad/timestamps.rb +219 -0
- data/lib/cohere/transcribe/version.rb +7 -0
- data/lib/cohere/transcribe.rb +26 -0
- data/sig/cohere/transcribe.rbs +250 -0
- data/vendor/crispasr/AUTHORS +510 -0
- data/vendor/crispasr/LICENSE +21 -0
- data/vendor/crispasr/UPSTREAM.md +9 -0
- data/vendor/crispasr/VERSION +1 -0
- data/vendor/crispasr/ggml/AUTHORS +335 -0
- data/vendor/crispasr/ggml/CMakeLists.txt +512 -0
- data/vendor/crispasr/ggml/LICENSE +21 -0
- data/vendor/crispasr/ggml/README.md +49 -0
- data/vendor/crispasr/ggml/cmake/FindNCCL.cmake +36 -0
- data/vendor/crispasr/ggml/cmake/GitVars.cmake +22 -0
- data/vendor/crispasr/ggml/cmake/common.cmake +50 -0
- data/vendor/crispasr/ggml/cmake/ggml-config.cmake.in +191 -0
- data/vendor/crispasr/ggml/ggml.pc.in +10 -0
- data/vendor/crispasr/ggml/include/ggml-alloc.h +85 -0
- data/vendor/crispasr/ggml/include/ggml-backend.h +431 -0
- data/vendor/crispasr/ggml/include/ggml-blas.h +25 -0
- data/vendor/crispasr/ggml/include/ggml-cann.h +123 -0
- data/vendor/crispasr/ggml/include/ggml-cpp.h +39 -0
- data/vendor/crispasr/ggml/include/ggml-cpu.h +151 -0
- data/vendor/crispasr/ggml/include/ggml-cuda.h +50 -0
- data/vendor/crispasr/ggml/include/ggml-hexagon.h +19 -0
- data/vendor/crispasr/ggml/include/ggml-metal.h +61 -0
- data/vendor/crispasr/ggml/include/ggml-opencl.h +26 -0
- data/vendor/crispasr/ggml/include/ggml-openvino.h +37 -0
- data/vendor/crispasr/ggml/include/ggml-opt.h +256 -0
- data/vendor/crispasr/ggml/include/ggml-rpc.h +35 -0
- data/vendor/crispasr/ggml/include/ggml-sycl.h +49 -0
- data/vendor/crispasr/ggml/include/ggml-virtgpu.h +14 -0
- data/vendor/crispasr/ggml/include/ggml-vulkan.h +29 -0
- data/vendor/crispasr/ggml/include/ggml-webgpu.h +19 -0
- data/vendor/crispasr/ggml/include/ggml-zdnn.h +17 -0
- data/vendor/crispasr/ggml/include/ggml-zendnn.h +22 -0
- data/vendor/crispasr/ggml/include/ggml.h +2887 -0
- data/vendor/crispasr/ggml/include/gguf.h +204 -0
- data/vendor/crispasr/ggml/src/CMakeLists.txt +493 -0
- data/vendor/crispasr/ggml/src/ggml-alloc.c +1323 -0
- data/vendor/crispasr/ggml/src/ggml-backend-dl.cpp +48 -0
- data/vendor/crispasr/ggml/src/ggml-backend-dl.h +44 -0
- data/vendor/crispasr/ggml/src/ggml-backend-impl.h +275 -0
- data/vendor/crispasr/ggml/src/ggml-backend-meta.cpp +2145 -0
- data/vendor/crispasr/ggml/src/ggml-backend-reg.cpp +586 -0
- data/vendor/crispasr/ggml/src/ggml-backend.cpp +2437 -0
- data/vendor/crispasr/ggml/src/ggml-common.h +1900 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/CMakeLists.txt +718 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/amx/amx.cpp +249 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/amx/amx.h +8 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/amx/common.h +115 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/amx/mmq.cpp +2512 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/amx/mmq.h +10 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/arm/cpu-feats.cpp +98 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/arm/quants.c +4244 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/arm/repack.cpp +5156 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/loongarch/quants.c +2158 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/powerpc/cpu-feats.cpp +82 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/powerpc/quants.c +2304 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/riscv/cpu-feats.cpp +38 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/riscv/quants.c +4455 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/riscv/repack.cpp +1703 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/s390/cpu-feats.cpp +50 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/s390/quants.c +1465 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/wasm/quants.c +1220 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/x86/cpu-feats.cpp +327 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/x86/quants.c +3970 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch/x86/repack.cpp +6407 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/arch-fallback.h +349 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/binary-ops.cpp +154 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/binary-ops.h +16 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/cmake/FindSIMD.cmake +100 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/common.h +95 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/ggml-cpu-impl.h +539 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/ggml-cpu.c +3791 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/ggml-cpu.cpp +703 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/hbm.cpp +55 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/hbm.h +8 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/kleidiai/kernels.cpp +939 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/kleidiai/kernels.h +90 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/kleidiai/kleidiai.cpp +1513 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/kleidiai/kleidiai.h +17 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/llamafile/sgemm.cpp +4051 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/llamafile/sgemm.h +25 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/ops.cpp +11662 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/ops.h +121 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/quants.c +1288 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/quants.h +103 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/repack.cpp +4836 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/repack.h +245 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/simd-gemm.h +226 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/simd-mappings.h +1329 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/spacemit/ime.cpp +1025 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/spacemit/ime.h +13 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/spacemit/ime1_kernels.cpp +3196 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/spacemit/ime_kernels.h +26 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/traits.cpp +36 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/traits.h +38 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/unary-ops.cpp +336 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/unary-ops.h +35 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/vec.cpp +681 -0
- data/vendor/crispasr/ggml/src/ggml-cpu/vec.h +1606 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/CMakeLists.txt +272 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/acc.cu +61 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/acc.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/add-id.cu +58 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/add-id.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/arange.cu +34 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/arange.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/argmax.cu +91 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/argmax.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/argsort.cu +265 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/argsort.cuh +19 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/binbcast.cu +534 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/binbcast.cuh +12 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/clamp.cu +45 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/clamp.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/col2im-1d.cu +81 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/col2im-1d.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/common.cuh +1489 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/concat.cu +204 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/concat.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv-transpose-1d.cu +97 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv-transpose-1d.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv2d-dw.cu +161 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv2d-dw.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv2d-transpose.cu +115 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv2d-transpose.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv2d.cu +166 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/conv2d.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/convert.cu +892 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/convert.cuh +66 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/count-equal.cu +64 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/count-equal.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cp-async.cuh +57 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cpy-utils.cuh +217 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cpy.cu +581 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cpy.cuh +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cross-entropy-loss.cu +177 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cross-entropy-loss.cuh +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cumsum.cu +307 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/cumsum.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/dequantize.cuh +99 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/diag.cu +77 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/diag.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/diagmask.cu +40 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/diagmask.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn-common.cuh +1212 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn-mma-f16.cuh +1860 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn-tile.cu +57 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn-tile.cuh +1309 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn-vec.cuh +600 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn-wmma-f16.cu +696 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn-wmma-f16.cuh +51 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn.cu +620 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fattn.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fill.cu +37 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/fill.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/gated_delta_net.cu +273 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/gated_delta_net.cuh +4 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/getrows.cu +332 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/getrows.cuh +15 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/ggml-cuda.cu +5580 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/gla.cu +93 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/gla.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/im2col.cu +274 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/im2col.cuh +6 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mean.cu +75 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mean.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mma.cuh +1333 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmf.cu +191 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmf.cuh +908 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmid.cu +164 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmid.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmq.cu +372 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmq.cuh +4175 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmvf.cu +862 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmvf.cuh +14 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmvq.cu +1161 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/mmvq.cuh +16 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/norm.cu +756 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/norm.cuh +20 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/opt-step-adamw.cu +78 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/opt-step-adamw.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/opt-step-sgd.cu +49 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/opt-step-sgd.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/out-prod.cu +68 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/out-prod.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/pad.cu +106 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/pad.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/pad_reflect_1d.cu +91 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/pad_reflect_1d.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/pool2d.cu +94 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/pool2d.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/quantize.cu +443 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/quantize.cuh +41 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/reduce_rows.cuh +39 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/roll.cu +67 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/roll.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/rope.cu +665 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/rope.cuh +9 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/scale.cu +34 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/scale.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/set-rows.cu +330 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/set-rows.cuh +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/set.cu +39 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/set.cuh +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/softcap.cu +34 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/softcap.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/softmax.cu +472 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/softmax.cuh +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/solve_tri.cu +275 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/solve_tri.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/ssm-conv.cu +197 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/ssm-conv.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/ssm-scan.cu +342 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/ssm-scan.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/sum.cu +41 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/sum.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/sumrows.cu +43 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/sumrows.cuh +4 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_1-ncols2_16.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_1-ncols2_32.cu +6 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_1-ncols2_8.cu +11 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_16-ncols2_1.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_16-ncols2_2.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_16-ncols2_4.cu +12 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_2-ncols2_16.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_2-ncols2_32.cu +6 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_2-ncols2_4.cu +12 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_2-ncols2_8.cu +11 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_32-ncols2_1.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_32-ncols2_2.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_4-ncols2_16.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_4-ncols2_2.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_4-ncols2_4.cu +12 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_4-ncols2_8.cu +11 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_64-ncols2_1.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_8-ncols2_1.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_8-ncols2_2.cu +10 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_8-ncols2_4.cu +12 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-mma-f16-instance-ncols1_8-ncols2_8.cu +11 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq112-dv112.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq128-dv128.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq256-dv256.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq320-dv256.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq40-dv40.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq512-dv512.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq576-dv512.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq64-dv64.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq72-dv72.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq80-dv80.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-tile-instance-dkq96-dv96.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-bf16-bf16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-bf16-f16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-bf16-q4_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-bf16-q4_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-bf16-q5_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-bf16-q5_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-bf16-q8_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-f16-bf16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-f16-f16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-f16-q4_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-f16-q4_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-f16-q5_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-f16-q5_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-f16-q8_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_0-bf16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_0-f16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_0-q4_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_0-q4_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_0-q5_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_0-q5_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_0-q8_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_1-bf16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_1-f16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_1-q4_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_1-q4_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_1-q5_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_1-q5_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q4_1-q8_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_0-bf16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_0-f16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_0-q4_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_0-q4_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_0-q5_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_0-q5_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_0-q8_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_1-bf16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_1-f16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_1-q4_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_1-q4_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_1-q5_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_1-q5_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q5_1-q8_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q8_0-bf16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q8_0-f16.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q8_0-q4_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q8_0-q4_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q8_0-q5_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q8_0-q5_1.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/fattn-vec-instance-q8_0-q8_0.cu +7 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_1.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_10.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_11.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_12.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_13.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_14.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_15.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_16.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_2.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_3.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_4.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_5.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_6.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_7.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_8.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmf-instance-ncols_9.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq1_s.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq2_s.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq2_xs.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq2_xxs.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq3_s.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq3_xxs.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq4_nl.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-iq4_xs.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-mxfp4.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-nvfp4.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q1_0.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q2_k.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q3_k.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q4_0.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q4_1.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q4_k.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q5_0.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q5_1.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q5_k.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q6_k.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/template-instances/mmq-instance-q8_0.cu +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/top-k.cu +95 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/top-k.cuh +3 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/topk-moe.cu +415 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/topk-moe.cuh +27 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/tri.cu +136 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/tri.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/tsembd.cu +47 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/tsembd.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/unary.cu +644 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/unary.cuh +116 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/upscale.cu +293 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/upscale.cuh +5 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/vecdotq.cuh +1317 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/vendors/cuda.h +28 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/vendors/hip.h +306 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/vendors/musa.h +148 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/wkv.cu +199 -0
- data/vendor/crispasr/ggml/src/ggml-cuda/wkv.cuh +7 -0
- data/vendor/crispasr/ggml/src/ggml-impl.h +783 -0
- data/vendor/crispasr/ggml/src/ggml-metal/CMakeLists.txt +124 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-common.cpp +457 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-common.h +52 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-context.h +41 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-context.m +778 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-device.cpp +2117 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-device.h +299 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-device.m +2093 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-impl.h +1267 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-ops.cpp +5023 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal-ops.h +111 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal.cpp +954 -0
- data/vendor/crispasr/ggml/src/ggml-metal/ggml-metal.metal +11756 -0
- data/vendor/crispasr/ggml/src/ggml-opt.cpp +1094 -0
- data/vendor/crispasr/ggml/src/ggml-quants.c +5491 -0
- data/vendor/crispasr/ggml/src/ggml-quants.h +112 -0
- data/vendor/crispasr/ggml/src/ggml-threading.cpp +12 -0
- data/vendor/crispasr/ggml/src/ggml-threading.h +14 -0
- data/vendor/crispasr/ggml/src/ggml.c +7925 -0
- data/vendor/crispasr/ggml/src/ggml.cpp +26 -0
- data/vendor/crispasr/ggml/src/gguf.cpp +1556 -0
- data/vendor/crispasr/src/cohere-arch.h +137 -0
- data/vendor/crispasr/src/cohere.cpp +5642 -0
- data/vendor/crispasr/src/cohere.h +327 -0
- data/vendor/crispasr/src/cohere_batch_planner.h +82 -0
- data/vendor/crispasr/src/cohere_chunking.h +64 -0
- data/vendor/crispasr/src/cohere_decoder_batch_layout.h +60 -0
- data/vendor/crispasr/src/cohere_encoder_padded_layout.h +27 -0
- data/vendor/crispasr/src/cohere_frontend.cpp +189 -0
- data/vendor/crispasr/src/cohere_frontend.h +31 -0
- data/vendor/crispasr/src/cohere_ragged_controller.h +149 -0
- data/vendor/crispasr/src/cohere_token_renderer.h +181 -0
- data/vendor/crispasr/src/core/attention.h +924 -0
- data/vendor/crispasr/src/core/audio_chunking.h +97 -0
- data/vendor/crispasr/src/core/beam_decode.h +486 -0
- data/vendor/crispasr/src/core/cpu_ops.h +135 -0
- data/vendor/crispasr/src/core/gguf_loader.cpp +1021 -0
- data/vendor/crispasr/src/core/gguf_loader.h +216 -0
- data/vendor/crispasr/src/core/gpu_backend_pref.h +119 -0
- data/vendor/crispasr/src/core/mel.cpp +519 -0
- data/vendor/crispasr/src/core/mel.h +265 -0
- data/vendor/crispasr/src/core/ngram_loop_fix.h +173 -0
- data/vendor/crispasr/src/core/repetition_loop_guard.h +54 -0
- data/vendor/crispasr/src/crispasr_imatrix.cpp +255 -0
- data/vendor/crispasr/src/crispasr_imatrix.h +38 -0
- metadata +596 -0
|
@@ -0,0 +1,2093 @@
|
|
|
1
|
+
#import "ggml-metal-device.h"
|
|
2
|
+
|
|
3
|
+
#import "ggml-impl.h"
|
|
4
|
+
|
|
5
|
+
#include <Foundation/Foundation.h>
|
|
6
|
+
|
|
7
|
+
#include <Metal/Metal.h>
|
|
8
|
+
|
|
9
|
+
#include <stdatomic.h>
|
|
10
|
+
|
|
11
|
+
#ifndef TARGET_OS_VISION
|
|
12
|
+
#define TARGET_OS_VISION 0
|
|
13
|
+
#endif
|
|
14
|
+
|
|
15
|
+
// create residency sets only on macOS >= 15.0
|
|
16
|
+
#if !TARGET_CPU_X86_64 && TARGET_OS_OSX && __MAC_OS_X_VERSION_MAX_ALLOWED >= 150000 || \
|
|
17
|
+
TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 180000 || \
|
|
18
|
+
TARGET_OS_TV && __TV_OS_VERSION_MAX_ALLOWED >= 180000 || \
|
|
19
|
+
TARGET_OS_VISION && __VISION_OS_VERSION_MAX_ALLOWED >= 200000
|
|
20
|
+
#define GGML_METAL_HAS_RESIDENCY_SETS 1
|
|
21
|
+
#endif
|
|
22
|
+
|
|
23
|
+
// overload of MTLGPUFamilyMetalX (not available in some environments)
|
|
24
|
+
static const NSInteger MTLGPUFamilyMetal3_GGML = 5001;
|
|
25
|
+
static const NSInteger MTLGPUFamilyMetal4_GGML = 5002;
|
|
26
|
+
|
|
27
|
+
#if !GGML_METAL_EMBED_LIBRARY
|
|
28
|
+
// Here to assist with NSBundle Path Hack
|
|
29
|
+
@interface GGMLMetalClass : NSObject
|
|
30
|
+
@end
|
|
31
|
+
@implementation GGMLMetalClass
|
|
32
|
+
@end
|
|
33
|
+
#endif
|
|
34
|
+
|
|
35
|
+
//
|
|
36
|
+
// MTLFunctionConstantValues wrapper
|
|
37
|
+
//
|
|
38
|
+
|
|
39
|
+
struct ggml_metal_cv {
|
|
40
|
+
MTLFunctionConstantValues * obj;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
ggml_metal_cv_t ggml_metal_cv_init(void) {
|
|
44
|
+
ggml_metal_cv_t res = calloc(1, sizeof(struct ggml_metal_cv));
|
|
45
|
+
|
|
46
|
+
res->obj = [[MTLFunctionConstantValues alloc] init];
|
|
47
|
+
|
|
48
|
+
return res;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
void ggml_metal_cv_free(ggml_metal_cv_t cv) {
|
|
52
|
+
[cv->obj release];
|
|
53
|
+
free(cv);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
void ggml_metal_cv_set_int16(ggml_metal_cv_t cv, int16_t value, int32_t idx) {
|
|
57
|
+
[cv->obj setConstantValue:&value type:MTLDataTypeShort atIndex:idx];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
void ggml_metal_cv_set_int32(ggml_metal_cv_t cv, int32_t value, int32_t idx) {
|
|
61
|
+
[cv->obj setConstantValue:&value type:MTLDataTypeInt atIndex:idx];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
void ggml_metal_cv_set_bool(ggml_metal_cv_t cv, bool value, int32_t idx) {
|
|
65
|
+
[cv->obj setConstantValue:&value type:MTLDataTypeBool atIndex:idx];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
//
|
|
69
|
+
// MTLComputePipelineState wrapper
|
|
70
|
+
//
|
|
71
|
+
|
|
72
|
+
struct ggml_metal_pipeline {
|
|
73
|
+
id<MTLComputePipelineState> obj;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
ggml_metal_pipeline_t ggml_metal_pipeline_init(void) {
|
|
77
|
+
ggml_metal_pipeline_t res = calloc(1, sizeof(struct ggml_metal_pipeline));
|
|
78
|
+
|
|
79
|
+
*res = (struct ggml_metal_pipeline) {
|
|
80
|
+
/*.obj =*/ nil,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return res;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
void ggml_metal_pipeline_free(ggml_metal_pipeline_t pipeline) {
|
|
87
|
+
[pipeline->obj release];
|
|
88
|
+
|
|
89
|
+
free(pipeline);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
int ggml_metal_pipeline_max_theads_per_threadgroup(struct ggml_metal_pipeline_with_params pipeline) {
|
|
93
|
+
return pipeline.pipeline->obj.maxTotalThreadsPerThreadgroup;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// CrispASR patch (PLAN #88 / CrisperWeaver §5.18): forward
|
|
97
|
+
// declarations for the pipeline-cache accessors. The full
|
|
98
|
+
// `struct ggml_metal_device` lives further down in this file
|
|
99
|
+
// because of historical ordering; the library functions above
|
|
100
|
+
// can't peek into it directly, so they go through these tiny
|
|
101
|
+
// accessors. Both return nil / no-op when caching is disabled.
|
|
102
|
+
static id<MTLBinaryArchive> crispasr_metal_device_archive(ggml_metal_device_t dev);
|
|
103
|
+
static void crispasr_metal_device_mark_archive_dirty(ggml_metal_device_t dev);
|
|
104
|
+
|
|
105
|
+
struct ggml_metal_library {
|
|
106
|
+
id<MTLLibrary> obj;
|
|
107
|
+
|
|
108
|
+
ggml_metal_device_t dev;
|
|
109
|
+
ggml_metal_pipelines_t pipelines; // cache of compiled pipelines
|
|
110
|
+
|
|
111
|
+
NSLock * lock;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
ggml_metal_library_t ggml_metal_library_init(ggml_metal_device_t dev) {
|
|
115
|
+
id<MTLLibrary> library = nil;
|
|
116
|
+
id<MTLDevice> device = ggml_metal_device_get_obj(dev);
|
|
117
|
+
|
|
118
|
+
// load library
|
|
119
|
+
//
|
|
120
|
+
// - first check if the library is embedded
|
|
121
|
+
// - then check if the library is in the bundle
|
|
122
|
+
// - if not found, load the source and compile it
|
|
123
|
+
// - if that fails, return NULL
|
|
124
|
+
//
|
|
125
|
+
// TODO: move to a function
|
|
126
|
+
{
|
|
127
|
+
const int64_t t_start = ggml_time_us();
|
|
128
|
+
|
|
129
|
+
NSError * error = nil;
|
|
130
|
+
NSString * src = nil;
|
|
131
|
+
|
|
132
|
+
#if GGML_METAL_EMBED_LIBRARY
|
|
133
|
+
GGML_LOG_INFO("%s: using embedded metal library\n", __func__);
|
|
134
|
+
|
|
135
|
+
extern const char ggml_metallib_start[];
|
|
136
|
+
extern const char ggml_metallib_end[];
|
|
137
|
+
|
|
138
|
+
src = [[NSString alloc] initWithBytes:ggml_metallib_start length:(ggml_metallib_end-ggml_metallib_start) encoding:NSUTF8StringEncoding];
|
|
139
|
+
#else
|
|
140
|
+
|
|
141
|
+
#ifdef SWIFT_PACKAGE
|
|
142
|
+
NSBundle * bundle = SWIFTPM_MODULE_BUNDLE;
|
|
143
|
+
#else
|
|
144
|
+
NSBundle * bundle = [NSBundle bundleForClass:[GGMLMetalClass class]];
|
|
145
|
+
#endif
|
|
146
|
+
|
|
147
|
+
NSString * path_lib = [bundle pathForResource:@"default" ofType:@"metallib"];
|
|
148
|
+
if (path_lib == nil) {
|
|
149
|
+
// Try to find the resource in the directory where the current binary located.
|
|
150
|
+
NSString * bin_cur = [[NSProcessInfo processInfo] arguments][0];
|
|
151
|
+
NSString * bin_dir = [bin_cur stringByDeletingLastPathComponent];
|
|
152
|
+
|
|
153
|
+
NSString * path_lib_default = [NSString pathWithComponents:@[bin_dir, @"default.metallib"]];
|
|
154
|
+
if ([[NSFileManager defaultManager] isReadableFileAtPath:path_lib_default]) {
|
|
155
|
+
GGML_LOG_INFO("%s: found '%s'\n", __func__, [path_lib_default UTF8String]);
|
|
156
|
+
|
|
157
|
+
NSDictionary * atts = [[NSFileManager defaultManager] attributesOfItemAtPath:path_lib_default error:&error];
|
|
158
|
+
if (atts && atts[NSFileType] == NSFileTypeSymbolicLink) {
|
|
159
|
+
// Optionally, if this is a symlink, try to resolve it.
|
|
160
|
+
path_lib_default = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:path_lib_default error:&error];
|
|
161
|
+
if (path_lib_default && [path_lib_default length] > 0 && ![[path_lib_default substringToIndex:1] isEqualToString:@"/"]) {
|
|
162
|
+
// It is a relative path, adding the binary directory as directory prefix.
|
|
163
|
+
path_lib_default = [NSString pathWithComponents:@[bin_dir, path_lib_default]];
|
|
164
|
+
}
|
|
165
|
+
if (!path_lib_default || ![[NSFileManager defaultManager] isReadableFileAtPath:path_lib_default]) {
|
|
166
|
+
// Link to the resource could not be resolved.
|
|
167
|
+
path_lib_default = nil;
|
|
168
|
+
} else {
|
|
169
|
+
GGML_LOG_INFO("%s: symlink resolved '%s'\n", __func__, [path_lib_default UTF8String]);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
} else {
|
|
173
|
+
// The resource couldn't be found in the binary's directory.
|
|
174
|
+
path_lib_default = nil;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
path_lib = path_lib_default;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (path_lib != nil) {
|
|
181
|
+
// pre-compiled library found
|
|
182
|
+
NSURL * libURL = [NSURL fileURLWithPath:path_lib];
|
|
183
|
+
GGML_LOG_INFO("%s: loading '%s'\n", __func__, [path_lib UTF8String]);
|
|
184
|
+
|
|
185
|
+
library = [device newLibraryWithURL:libURL error:&error];
|
|
186
|
+
if (error) {
|
|
187
|
+
GGML_LOG_ERROR("%s: error: %s\n", __func__, [[error description] UTF8String]);
|
|
188
|
+
return nil;
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
GGML_LOG_INFO("%s: default.metallib not found, loading from source\n", __func__);
|
|
192
|
+
|
|
193
|
+
NSString * path_source;
|
|
194
|
+
NSString * path_resource = [[NSProcessInfo processInfo].environment objectForKey:@"GGML_METAL_PATH_RESOURCES"];
|
|
195
|
+
|
|
196
|
+
GGML_LOG_INFO("%s: GGML_METAL_PATH_RESOURCES = %s\n", __func__, path_resource ? [path_resource UTF8String] : "nil");
|
|
197
|
+
|
|
198
|
+
if (path_resource) {
|
|
199
|
+
path_source = [path_resource stringByAppendingPathComponent:@"ggml-metal.metal"];
|
|
200
|
+
} else {
|
|
201
|
+
path_source = [bundle pathForResource:@"ggml-metal" ofType:@"metal"];
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (path_source == nil) {
|
|
205
|
+
GGML_LOG_WARN("%s: error: could not use bundle path to find ggml-metal.metal, falling back to trying cwd\n", __func__);
|
|
206
|
+
path_source = @"ggml-metal.metal";
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
GGML_LOG_INFO("%s: loading '%s'\n", __func__, [path_source UTF8String]);
|
|
210
|
+
|
|
211
|
+
src = [NSString stringWithContentsOfFile:path_source encoding:NSUTF8StringEncoding error:&error];
|
|
212
|
+
if (error) {
|
|
213
|
+
GGML_LOG_ERROR("%s: error: %s\n", __func__, [[error description] UTF8String]);
|
|
214
|
+
return nil;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
#endif
|
|
218
|
+
|
|
219
|
+
if (!library) {
|
|
220
|
+
@autoreleasepool {
|
|
221
|
+
// dictionary of preprocessor macros
|
|
222
|
+
NSMutableDictionary * prep = [NSMutableDictionary dictionary];
|
|
223
|
+
|
|
224
|
+
if (ggml_metal_device_get_props(dev)->has_bfloat) {
|
|
225
|
+
[prep setObject:@"1" forKey:@"GGML_METAL_HAS_BF16"];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (ggml_metal_device_get_props(dev)->has_tensor) {
|
|
229
|
+
[prep setObject:@"1" forKey:@"GGML_METAL_HAS_TENSOR"];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
#if GGML_METAL_EMBED_LIBRARY
|
|
233
|
+
[prep setObject:@"1" forKey:@"GGML_METAL_EMBED_LIBRARY"];
|
|
234
|
+
#endif
|
|
235
|
+
|
|
236
|
+
MTLCompileOptions * options = [MTLCompileOptions new];
|
|
237
|
+
options.preprocessorMacros = prep;
|
|
238
|
+
|
|
239
|
+
// CrispASR patch (#83): disable fast-math when CRISPASR_METAL_STRICT_FP=1.
|
|
240
|
+
// Fast-math allows the compiler to fuse multiplies (FMA can be more
|
|
241
|
+
// accurate, but operand reordering may downconvert F32 to F16-precision
|
|
242
|
+
// intermediates inside `dot()` and other built-ins). Strict FP gives
|
|
243
|
+
// bit-identical CPU/GPU output for chatterbox K projection at the cost
|
|
244
|
+
// of some throughput.
|
|
245
|
+
if (getenv("CRISPASR_METAL_STRICT_FP")) {
|
|
246
|
+
[options setFastMathEnabled:NO];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
library = [device newLibraryWithSource:src options:options error:&error];
|
|
250
|
+
if (error) {
|
|
251
|
+
GGML_LOG_ERROR("%s: error: %s\n", __func__, [[error description] UTF8String]);
|
|
252
|
+
return nil;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
#if !__has_feature(objc_arc)
|
|
256
|
+
[options release];
|
|
257
|
+
#endif
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
#if GGML_METAL_EMBED_LIBRARY
|
|
262
|
+
[src release];
|
|
263
|
+
#endif // GGML_METAL_EMBED_LIBRARY
|
|
264
|
+
|
|
265
|
+
GGML_LOG_INFO("%s: loaded in %.3f sec\n", __func__, (ggml_time_us() - t_start) / 1e6);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
ggml_metal_library_t res = calloc(1, sizeof(struct ggml_metal_library));
|
|
269
|
+
|
|
270
|
+
res->obj = library;
|
|
271
|
+
res->dev = dev;
|
|
272
|
+
res->pipelines = ggml_metal_pipelines_init();
|
|
273
|
+
res->lock = [NSLock new];
|
|
274
|
+
|
|
275
|
+
return res;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
ggml_metal_library_t ggml_metal_library_init_from_source(ggml_metal_device_t dev, const char * source, bool verbose) {
|
|
279
|
+
if (source == NULL) {
|
|
280
|
+
GGML_LOG_ERROR("%s: source is NULL\n", __func__);
|
|
281
|
+
return NULL;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
id<MTLDevice> device = ggml_metal_device_get_obj(dev);
|
|
285
|
+
id<MTLLibrary> library = nil;
|
|
286
|
+
NSError * error = nil;
|
|
287
|
+
|
|
288
|
+
const int64_t t_start = ggml_time_us();
|
|
289
|
+
|
|
290
|
+
NSString * src = [[NSString alloc] initWithBytes:source
|
|
291
|
+
length:strlen(source)
|
|
292
|
+
encoding:NSUTF8StringEncoding];
|
|
293
|
+
if (!src) {
|
|
294
|
+
GGML_LOG_ERROR("%s: failed to create NSString from source\n", __func__);
|
|
295
|
+
return NULL;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
@autoreleasepool {
|
|
299
|
+
NSMutableDictionary * prep = [NSMutableDictionary dictionary];
|
|
300
|
+
|
|
301
|
+
MTLCompileOptions * options = [MTLCompileOptions new];
|
|
302
|
+
options.preprocessorMacros = prep;
|
|
303
|
+
|
|
304
|
+
library = [device newLibraryWithSource:src options:options error:&error];
|
|
305
|
+
if (error) {
|
|
306
|
+
if (verbose) {
|
|
307
|
+
GGML_LOG_ERROR("%s: error compiling source: %s\n", __func__, [[error description] UTF8String]);
|
|
308
|
+
} else {
|
|
309
|
+
GGML_LOG_ERROR("%s: error compiling source\n", __func__);
|
|
310
|
+
}
|
|
311
|
+
library = nil;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
[options release];
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
[src release];
|
|
318
|
+
|
|
319
|
+
if (!library) {
|
|
320
|
+
if (verbose) {
|
|
321
|
+
GGML_LOG_ERROR("%s: failed to create Metal library from source\n", __func__);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return NULL;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (verbose) {
|
|
328
|
+
GGML_LOG_INFO("%s: compiled in %.3f sec\n", __func__, (ggml_time_us() - t_start) / 1e6);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
ggml_metal_library_t res = calloc(1, sizeof(struct ggml_metal_library));
|
|
332
|
+
if (!res) {
|
|
333
|
+
GGML_LOG_ERROR("%s: calloc failed\n", __func__);
|
|
334
|
+
return NULL;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
res->obj = library;
|
|
338
|
+
res->dev = dev;
|
|
339
|
+
res->pipelines = ggml_metal_pipelines_init();
|
|
340
|
+
res->lock = [NSLock new];
|
|
341
|
+
|
|
342
|
+
return res;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
void ggml_metal_library_free(ggml_metal_library_t lib) {
|
|
346
|
+
if (!lib) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (lib->obj) {
|
|
351
|
+
[lib->obj release];
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
ggml_metal_pipelines_free(lib->pipelines);
|
|
355
|
+
|
|
356
|
+
[lib->lock release];
|
|
357
|
+
|
|
358
|
+
free(lib);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
ggml_metal_device_t ggml_metal_library_get_device(ggml_metal_library_t lib) {
|
|
362
|
+
return lib->dev;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
struct ggml_metal_pipeline_with_params ggml_metal_library_get_pipeline(ggml_metal_library_t lib, const char * name) {
|
|
366
|
+
[lib->lock lock];
|
|
367
|
+
|
|
368
|
+
struct ggml_metal_pipeline_with_params res = {
|
|
369
|
+
/*.pipeline =*/ nil,
|
|
370
|
+
/*.nsg =*/ 0,
|
|
371
|
+
/*.nr0 =*/ 0,
|
|
372
|
+
/*.nr1 =*/ 0,
|
|
373
|
+
/*.smem =*/ 0,
|
|
374
|
+
/*.c4 =*/ false,
|
|
375
|
+
/*.cnt =*/ false,
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
res.pipeline = ggml_metal_pipelines_get(lib->pipelines, name);
|
|
379
|
+
|
|
380
|
+
[lib->lock unlock];
|
|
381
|
+
|
|
382
|
+
return res;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
struct ggml_metal_pipeline_with_params ggml_metal_library_compile_pipeline(ggml_metal_library_t lib, const char * base, const char * name, ggml_metal_cv_t cv) {
|
|
386
|
+
struct ggml_metal_pipeline_with_params res = {
|
|
387
|
+
/*.pipeline =*/ nil,
|
|
388
|
+
/*.nsg =*/ 0,
|
|
389
|
+
/*.nr0 =*/ 0,
|
|
390
|
+
/*.nr1 =*/ 0,
|
|
391
|
+
/*.smem =*/ 0,
|
|
392
|
+
/*.c4 =*/ false,
|
|
393
|
+
/*.cnt =*/ false,
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
[lib->lock lock];
|
|
397
|
+
|
|
398
|
+
res.pipeline = ggml_metal_pipelines_get(lib->pipelines, name);
|
|
399
|
+
if (res.pipeline) {
|
|
400
|
+
[lib->lock unlock];
|
|
401
|
+
|
|
402
|
+
return res;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
@autoreleasepool {
|
|
406
|
+
NSError * error = nil;
|
|
407
|
+
|
|
408
|
+
NSString * base_func = [NSString stringWithUTF8String:base];
|
|
409
|
+
|
|
410
|
+
GGML_LOG_DEBUG("%s: compiling pipeline: base = '%s', name = '%s'\n", __func__, base, name);
|
|
411
|
+
|
|
412
|
+
id<MTLFunction> mtl_function;
|
|
413
|
+
if (!cv) {
|
|
414
|
+
mtl_function = [lib->obj newFunctionWithName:base_func];
|
|
415
|
+
} else {
|
|
416
|
+
mtl_function = [lib->obj newFunctionWithName:base_func constantValues:cv->obj error:&error];
|
|
417
|
+
}
|
|
418
|
+
if (!mtl_function) {
|
|
419
|
+
[lib->lock unlock];
|
|
420
|
+
|
|
421
|
+
GGML_LOG_ERROR("%s: failed to compile pipeline: base = '%s', name = '%s'\n", __func__, base, name);
|
|
422
|
+
if (error) {
|
|
423
|
+
GGML_LOG_ERROR("%s: %s\n", __func__, [[error description] UTF8String]);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return res;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
id<MTLDevice> device = ggml_metal_device_get_obj(lib->dev);
|
|
430
|
+
|
|
431
|
+
// CrispASR patch (PLAN #88 / CrisperWeaver §5.18): pipeline
|
|
432
|
+
// cache hookup. When the device's binary archive is open,
|
|
433
|
+
// attach it via `MTLComputePipelineDescriptor.binaryArchives`
|
|
434
|
+
// so Metal first checks the archive for a matching PSO and
|
|
435
|
+
// skips the shader compiler on hit. After successful
|
|
436
|
+
// creation we add the descriptor BACK to the archive so the
|
|
437
|
+
// next process startup sees it on disk. Failures here are
|
|
438
|
+
// intentionally non-fatal — pipeline compile already
|
|
439
|
+
// succeeded (`obj` is valid), and the worst case for an
|
|
440
|
+
// add-to-archive miss is a missed cache entry on the next
|
|
441
|
+
// run, not a broken inference today.
|
|
442
|
+
id<MTLComputePipelineState> obj = nil;
|
|
443
|
+
MTLComputePipelineDescriptor * pdesc = [MTLComputePipelineDescriptor new];
|
|
444
|
+
pdesc.computeFunction = mtl_function;
|
|
445
|
+
id<MTLBinaryArchive> archive = crispasr_metal_device_archive(lib->dev);
|
|
446
|
+
if (archive) {
|
|
447
|
+
pdesc.binaryArchives = @[archive];
|
|
448
|
+
}
|
|
449
|
+
obj = [device newComputePipelineStateWithDescriptor:pdesc
|
|
450
|
+
options:MTLPipelineOptionNone
|
|
451
|
+
reflection:nil
|
|
452
|
+
error:&error];
|
|
453
|
+
|
|
454
|
+
if (obj && archive) {
|
|
455
|
+
NSError * add_err = nil;
|
|
456
|
+
if ([archive addComputePipelineFunctionsWithDescriptor:pdesc error:&add_err]) {
|
|
457
|
+
crispasr_metal_device_mark_archive_dirty(lib->dev);
|
|
458
|
+
} else if (add_err) {
|
|
459
|
+
// Logged at DEBUG because some functions can't be
|
|
460
|
+
// archived (linker-resolved ones, MPS-backed paths)
|
|
461
|
+
// and that's neither rare nor a real problem.
|
|
462
|
+
GGML_LOG_DEBUG("%s: add-to-archive skipped for '%s': %s\n",
|
|
463
|
+
__func__, name, [[add_err description] UTF8String]);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
[pdesc release];
|
|
468
|
+
[mtl_function release];
|
|
469
|
+
|
|
470
|
+
if (!obj) {
|
|
471
|
+
[lib->lock unlock];
|
|
472
|
+
|
|
473
|
+
GGML_LOG_ERROR("%s: failed to create pipeline state: base = '%s', name = '%s'\n", __func__, base, name);
|
|
474
|
+
if (error) {
|
|
475
|
+
GGML_LOG_ERROR("%s: %s\n", __func__, [[error description] UTF8String]);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return res;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
GGML_LOG_DEBUG("%s: loaded %-40s %16p | th_max = %4d | th_width = %4d\n", __func__, name,
|
|
482
|
+
(void *) obj,
|
|
483
|
+
(int) obj.maxTotalThreadsPerThreadgroup,
|
|
484
|
+
(int) obj.threadExecutionWidth);
|
|
485
|
+
|
|
486
|
+
if (obj.maxTotalThreadsPerThreadgroup == 0 || obj.threadExecutionWidth == 0) {
|
|
487
|
+
[obj release];
|
|
488
|
+
|
|
489
|
+
[lib->lock unlock];
|
|
490
|
+
|
|
491
|
+
GGML_LOG_ERROR("%s: incompatible pipeline %s\n", __func__, name);
|
|
492
|
+
|
|
493
|
+
return res;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
res.pipeline = ggml_metal_pipeline_init();
|
|
497
|
+
res.pipeline->obj = obj;
|
|
498
|
+
|
|
499
|
+
ggml_metal_pipelines_add(lib->pipelines, name, res.pipeline);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
[lib->lock unlock];
|
|
503
|
+
|
|
504
|
+
return res;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
//
|
|
508
|
+
// MTLComputeCommandEncoder wrapper
|
|
509
|
+
//
|
|
510
|
+
|
|
511
|
+
struct ggml_metal_encoder {
|
|
512
|
+
id<MTLComputeCommandEncoder> obj;
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
ggml_metal_encoder_t ggml_metal_encoder_init(ggml_metal_cmd_buf_t cmd_buf_raw, bool concurrent) {
|
|
516
|
+
ggml_metal_encoder_t res = calloc(1, sizeof(struct ggml_metal_encoder));
|
|
517
|
+
|
|
518
|
+
id<MTLCommandBuffer> cmd_buf = (id<MTLCommandBuffer>) cmd_buf_raw;
|
|
519
|
+
|
|
520
|
+
if (concurrent) {
|
|
521
|
+
res->obj = [cmd_buf computeCommandEncoderWithDispatchType: MTLDispatchTypeConcurrent];
|
|
522
|
+
} else {
|
|
523
|
+
res->obj = [cmd_buf computeCommandEncoder];
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
[res->obj retain];
|
|
527
|
+
|
|
528
|
+
return res;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
void ggml_metal_encoder_free(ggml_metal_encoder_t encoder) {
|
|
532
|
+
[encoder->obj release];
|
|
533
|
+
free(encoder);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
void ggml_metal_encoder_debug_group_push(ggml_metal_encoder_t encoder, const char * name) {
|
|
537
|
+
[encoder->obj pushDebugGroup:[NSString stringWithCString:name encoding:NSUTF8StringEncoding]];
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
void ggml_metal_encoder_debug_group_pop (ggml_metal_encoder_t encoder) {
|
|
541
|
+
[encoder->obj popDebugGroup];
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
void ggml_metal_encoder_set_pipeline(ggml_metal_encoder_t encoder, struct ggml_metal_pipeline_with_params pipeline) {
|
|
545
|
+
[encoder->obj setComputePipelineState:pipeline.pipeline->obj];
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
void ggml_metal_encoder_set_bytes(ggml_metal_encoder_t encoder, void * data, size_t size, int idx) {
|
|
549
|
+
[encoder->obj setBytes:data length:size atIndex:idx];
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
void ggml_metal_encoder_set_buffer(ggml_metal_encoder_t encoder, struct ggml_metal_buffer_id buffer, int idx) {
|
|
553
|
+
[encoder->obj setBuffer:buffer.metal offset:buffer.offs atIndex:idx];
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
void ggml_metal_encoder_set_threadgroup_memory_size(ggml_metal_encoder_t encoder, size_t size, int idx) {
|
|
557
|
+
[encoder->obj setThreadgroupMemoryLength:size atIndex:idx];
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
void ggml_metal_encoder_dispatch_threadgroups(ggml_metal_encoder_t encoder, int tg0, int tg1, int tg2, int tptg0, int tptg1, int tptg2) {
|
|
561
|
+
[encoder->obj dispatchThreadgroups:MTLSizeMake(tg0, tg1, tg2) threadsPerThreadgroup:MTLSizeMake(tptg0, tptg1, tptg2)];
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
void ggml_metal_encoder_memory_barrier(ggml_metal_encoder_t encoder) {
|
|
565
|
+
[encoder->obj memoryBarrierWithScope:MTLBarrierScopeBuffers];
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
void ggml_metal_encoder_end_encoding(ggml_metal_encoder_t encoder) {
|
|
569
|
+
[encoder->obj endEncoding];
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
struct ggml_metal_device {
|
|
573
|
+
id<MTLDevice> mtl_device;
|
|
574
|
+
|
|
575
|
+
// a single global queue shared by all Metal backends
|
|
576
|
+
// technically not needed for devices with unified memory, but enables discrete GPUs support
|
|
577
|
+
// ref: https://github.com/ggml-org/llama.cpp/pull/15906
|
|
578
|
+
id<MTLCommandQueue> mtl_queue;
|
|
579
|
+
|
|
580
|
+
ggml_metal_rsets_t rsets;
|
|
581
|
+
|
|
582
|
+
ggml_metal_library_t library;
|
|
583
|
+
|
|
584
|
+
struct ggml_metal_device_props props;
|
|
585
|
+
|
|
586
|
+
// virtual address for GPU memory allocations
|
|
587
|
+
atomic_uintptr_t addr_virt;
|
|
588
|
+
|
|
589
|
+
// CrispASR patch (PLAN #88 / CrisperWeaver §5.18): persistent
|
|
590
|
+
// Metal pipeline cache via Apple's `MTLBinaryArchive`. When the
|
|
591
|
+
// process opens a Metal device for the first time, ggml-metal
|
|
592
|
+
// JITs every compute pipeline state object (PSO) from MSL source
|
|
593
|
+
// — that's the ~30–60 s "cold start" tax visible on every
|
|
594
|
+
// CrispASR / CrisperWeaver process spawn. The archive lets us
|
|
595
|
+
// serialise the compiled PSOs to disk on shutdown and reload
|
|
596
|
+
// them on the next launch, so the second+ run skips the JIT
|
|
597
|
+
// entirely for any shape the first run already touched.
|
|
598
|
+
//
|
|
599
|
+
// Storage layout: one `.archive` file per device, keyed by the
|
|
600
|
+
// device's user-visible name (spaces normalised to underscores).
|
|
601
|
+
// Default path is `~/Library/Caches/ggml-metal/<device>.archive`;
|
|
602
|
+
// override with `GGML_METAL_PIPELINE_CACHE`. Set
|
|
603
|
+
// `GGML_METAL_PIPELINE_CACHE_DISABLE=1` to skip the cache (e.g.
|
|
604
|
+
// when chasing a stale-PSO bug).
|
|
605
|
+
id<MTLBinaryArchive> binary_archive;
|
|
606
|
+
NSURL * binary_archive_url;
|
|
607
|
+
bool binary_archive_dirty; // true when we added at least one PSO since the last serialise
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
//
|
|
611
|
+
// MTLResidenceSet wrapper
|
|
612
|
+
//
|
|
613
|
+
|
|
614
|
+
struct ggml_metal_rsets {
|
|
615
|
+
NSLock * lock;
|
|
616
|
+
|
|
617
|
+
NSMutableArray * data;
|
|
618
|
+
|
|
619
|
+
// number of seconds since the last graph computation
|
|
620
|
+
// keep the residency sets wired for that amount of time to avoid being collected by the OS
|
|
621
|
+
int keep_alive_s;
|
|
622
|
+
|
|
623
|
+
// background heartbeat thread to keep the residency sets alive
|
|
624
|
+
atomic_bool d_stop;
|
|
625
|
+
atomic_int d_loop;
|
|
626
|
+
|
|
627
|
+
dispatch_group_t d_group;
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
ggml_metal_rsets_t ggml_metal_rsets_init(void) {
|
|
631
|
+
ggml_metal_rsets_t res = calloc(1, sizeof(struct ggml_metal_rsets));
|
|
632
|
+
|
|
633
|
+
res->lock = [[NSLock alloc] init];
|
|
634
|
+
res->data = [[NSMutableArray alloc] init];
|
|
635
|
+
|
|
636
|
+
// by default keep the memory wired for 3 minutes
|
|
637
|
+
res->keep_alive_s = 3*60;
|
|
638
|
+
|
|
639
|
+
const char * GGML_METAL_RESIDENCY_KEEP_ALIVE_S = getenv("GGML_METAL_RESIDENCY_KEEP_ALIVE_S");
|
|
640
|
+
if (GGML_METAL_RESIDENCY_KEEP_ALIVE_S) {
|
|
641
|
+
res->keep_alive_s = atoi(GGML_METAL_RESIDENCY_KEEP_ALIVE_S);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (res->keep_alive_s <= 0) {
|
|
645
|
+
res->keep_alive_s = 3*60;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
GGML_LOG_INFO("%s: creating a residency set collection (keep_alive = %d s)\n", __func__, res->keep_alive_s);
|
|
649
|
+
|
|
650
|
+
atomic_store_explicit(&res->d_stop, false, memory_order_relaxed);
|
|
651
|
+
atomic_store_explicit(&res->d_loop, 2*res->keep_alive_s, memory_order_relaxed);
|
|
652
|
+
|
|
653
|
+
res->d_group = dispatch_group_create();
|
|
654
|
+
|
|
655
|
+
// start a background thread that periodically requests residency for all the currently active sets in the collection
|
|
656
|
+
// the requests stop after a certain amount of time (keep_alive_s) of inactivity
|
|
657
|
+
dispatch_queue_t d_queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);
|
|
658
|
+
dispatch_group_async(res->d_group, d_queue, ^{
|
|
659
|
+
#if defined(GGML_METAL_HAS_RESIDENCY_SETS)
|
|
660
|
+
if (@available(macOS 15.0, iOS 18.0, tvOS 18.0, visionOS 2.0, *)) {
|
|
661
|
+
while (!atomic_load_explicit(&res->d_stop, memory_order_relaxed)) {
|
|
662
|
+
if (atomic_load_explicit(&res->d_loop, memory_order_relaxed) > 0) {
|
|
663
|
+
[res->lock lock];
|
|
664
|
+
|
|
665
|
+
for (int i = 0; i < (int) res->data.count; ++i) {
|
|
666
|
+
[res->data[i] requestResidency];
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
atomic_fetch_sub_explicit(&res->d_loop, 1, memory_order_relaxed);
|
|
670
|
+
|
|
671
|
+
[res->lock unlock];
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// half a second
|
|
675
|
+
usleep(500 * 1000);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
#endif
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
return res;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
void ggml_metal_rsets_free(ggml_metal_rsets_t rsets) {
|
|
685
|
+
if (rsets == NULL) {
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// note: if you hit this assert, most likely you haven't deallocated all Metal resources before exiting
|
|
690
|
+
GGML_ASSERT([rsets->data count] == 0);
|
|
691
|
+
|
|
692
|
+
atomic_store_explicit(&rsets->d_stop, true, memory_order_relaxed);
|
|
693
|
+
|
|
694
|
+
dispatch_group_wait(rsets->d_group, DISPATCH_TIME_FOREVER);
|
|
695
|
+
dispatch_release(rsets->d_group);
|
|
696
|
+
|
|
697
|
+
[rsets->data release];
|
|
698
|
+
[rsets->lock release];
|
|
699
|
+
|
|
700
|
+
free(rsets);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// ───────────────────────────────────────────────────────────────────
|
|
704
|
+
// CrispASR patch (PLAN #88 / CrisperWeaver §5.18): MTLBinaryArchive
|
|
705
|
+
// helpers for the persistent pipeline cache. Free functions kept
|
|
706
|
+
// file-static so they don't appear in the public ggml-metal ABI.
|
|
707
|
+
// ───────────────────────────────────────────────────────────────────
|
|
708
|
+
|
|
709
|
+
// Resolve the on-disk path for this device's pipeline archive.
|
|
710
|
+
// `GGML_METAL_PIPELINE_CACHE` (a directory) overrides the default
|
|
711
|
+
// `~/Library/Caches/ggml-metal/`. The leaf filename is the device's
|
|
712
|
+
// `name` property with spaces normalised to underscores. Returns nil
|
|
713
|
+
// when path resolution failed entirely.
|
|
714
|
+
static NSURL * crispasr_metal_pipeline_cache_url(NSString * device_name) {
|
|
715
|
+
NSFileManager * fm = [NSFileManager defaultManager];
|
|
716
|
+
|
|
717
|
+
NSURL * cache_dir = nil;
|
|
718
|
+
const char * env_dir = getenv("GGML_METAL_PIPELINE_CACHE");
|
|
719
|
+
if (env_dir && env_dir[0] != '\0') {
|
|
720
|
+
cache_dir = [NSURL fileURLWithPath:[NSString stringWithUTF8String:env_dir]];
|
|
721
|
+
} else {
|
|
722
|
+
NSURL * libcache = [fm URLForDirectory:NSCachesDirectory
|
|
723
|
+
inDomain:NSUserDomainMask
|
|
724
|
+
appropriateForURL:nil
|
|
725
|
+
create:YES
|
|
726
|
+
error:nil];
|
|
727
|
+
if (!libcache) {
|
|
728
|
+
return nil;
|
|
729
|
+
}
|
|
730
|
+
cache_dir = [libcache URLByAppendingPathComponent:@"ggml-metal" isDirectory:YES];
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// Ensure the directory exists; first run will create it.
|
|
734
|
+
NSError * mkdir_err = nil;
|
|
735
|
+
if (![fm createDirectoryAtURL:cache_dir
|
|
736
|
+
withIntermediateDirectories:YES
|
|
737
|
+
attributes:nil
|
|
738
|
+
error:&mkdir_err]) {
|
|
739
|
+
GGML_LOG_WARN("%s: pipeline-cache dir %s unwritable (%s) — caching disabled\n",
|
|
740
|
+
__func__,
|
|
741
|
+
[[cache_dir path] UTF8String],
|
|
742
|
+
mkdir_err ? [[mkdir_err description] UTF8String] : "unknown");
|
|
743
|
+
return nil;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// Normalise the device name so it's a safe filename: lowercase
|
|
747
|
+
// spaces and ` / \ : * ? " | < >` are all replaced with `_`.
|
|
748
|
+
NSMutableCharacterSet * unsafe = [NSMutableCharacterSet whitespaceCharacterSet];
|
|
749
|
+
[unsafe addCharactersInString:@"/\\:*?\"|<>"];
|
|
750
|
+
NSArray<NSString *> * parts = [device_name componentsSeparatedByCharactersInSet:unsafe];
|
|
751
|
+
NSString * safe = [parts componentsJoinedByString:@"_"];
|
|
752
|
+
if (safe.length == 0) {
|
|
753
|
+
safe = @"unknown-device";
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
NSString * filename = [NSString stringWithFormat:@"%@.archive", safe];
|
|
757
|
+
return [cache_dir URLByAppendingPathComponent:filename];
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// Create or load the device's binary archive. On the first run
|
|
761
|
+
// (or after a delete) the file doesn't exist yet and we hand
|
|
762
|
+
// `MTLBinaryArchiveDescriptor` a nil URL — Metal returns a fresh,
|
|
763
|
+
// empty archive we'll fill in as pipelines compile. On subsequent
|
|
764
|
+
// runs the existing file gets mapped in; pipelines whose function
|
|
765
|
+
// hash is already serialised inside get loaded straight from disk.
|
|
766
|
+
//
|
|
767
|
+
// Sets `dev->binary_archive` + `dev->binary_archive_url`. Both stay
|
|
768
|
+
// nil when caching is disabled, the cache file is corrupt (load
|
|
769
|
+
// failed), or the device doesn't support binary archives.
|
|
770
|
+
static void crispasr_metal_pipeline_cache_open(ggml_metal_device_t dev) {
|
|
771
|
+
// MTLBinaryArchive + the descriptor-attached pipeline-creation
|
|
772
|
+
// form both require macOS 11.0 / iOS 14.0 / tvOS 14.0. Older
|
|
773
|
+
// systems silently skip caching (the rest of the code already
|
|
774
|
+
// handles `dev->binary_archive == nil` gracefully by falling
|
|
775
|
+
// back to the historical newComputePipelineStateWithFunction
|
|
776
|
+
// path inside the descriptor — Metal accepts a nil
|
|
777
|
+
// binaryArchives array).
|
|
778
|
+
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
|
779
|
+
// continue
|
|
780
|
+
} else {
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
const char * disable = getenv("GGML_METAL_PIPELINE_CACHE_DISABLE");
|
|
785
|
+
if (disable && disable[0] != '\0' && disable[0] != '0') {
|
|
786
|
+
GGML_LOG_INFO("%s: GGML_METAL_PIPELINE_CACHE_DISABLE set — skipping pipeline cache\n", __func__);
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
NSURL * url = crispasr_metal_pipeline_cache_url([dev->mtl_device name]);
|
|
791
|
+
if (!url) {
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
MTLBinaryArchiveDescriptor * desc = [MTLBinaryArchiveDescriptor new];
|
|
796
|
+
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:[url path]];
|
|
797
|
+
if (exists) {
|
|
798
|
+
desc.url = url;
|
|
799
|
+
} // else nil → fresh archive
|
|
800
|
+
|
|
801
|
+
NSError * err = nil;
|
|
802
|
+
id<MTLBinaryArchive> archive = [dev->mtl_device newBinaryArchiveWithDescriptor:desc error:&err];
|
|
803
|
+
[desc release];
|
|
804
|
+
|
|
805
|
+
if (!archive) {
|
|
806
|
+
// Failure is non-fatal — caching is purely a perf optimisation.
|
|
807
|
+
// The most common cause is a stale archive from a different
|
|
808
|
+
// ggml-metal build (kernel hashes changed); delete-and-retry
|
|
809
|
+
// with a fresh archive.
|
|
810
|
+
if (exists) {
|
|
811
|
+
GGML_LOG_WARN("%s: cached archive %s rejected by Metal (%s) — discarding and starting fresh\n",
|
|
812
|
+
__func__,
|
|
813
|
+
[[url path] UTF8String],
|
|
814
|
+
err ? [[err description] UTF8String] : "unknown");
|
|
815
|
+
[[NSFileManager defaultManager] removeItemAtURL:url error:nil];
|
|
816
|
+
err = nil;
|
|
817
|
+
MTLBinaryArchiveDescriptor * fresh = [MTLBinaryArchiveDescriptor new];
|
|
818
|
+
archive = [dev->mtl_device newBinaryArchiveWithDescriptor:fresh error:&err];
|
|
819
|
+
[fresh release];
|
|
820
|
+
}
|
|
821
|
+
if (!archive) {
|
|
822
|
+
GGML_LOG_WARN("%s: pipeline-cache init failed (%s) — caching disabled\n",
|
|
823
|
+
__func__,
|
|
824
|
+
err ? [[err description] UTF8String] : "unknown");
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
dev->binary_archive = archive; // retained by newBinary...
|
|
830
|
+
dev->binary_archive_url = [url retain];
|
|
831
|
+
dev->binary_archive_dirty = false;
|
|
832
|
+
GGML_LOG_INFO("%s: pipeline cache %s — %s\n",
|
|
833
|
+
__func__,
|
|
834
|
+
exists ? "loaded" : "created",
|
|
835
|
+
[[url path] UTF8String]);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// Flush the in-memory archive to disk. Called from
|
|
839
|
+
// `ggml_metal_device_free`. No-op when caching is disabled or
|
|
840
|
+
// nothing was added since the last serialise.
|
|
841
|
+
static void crispasr_metal_pipeline_cache_flush(ggml_metal_device_t dev) {
|
|
842
|
+
if (!dev->binary_archive || !dev->binary_archive_url || !dev->binary_archive_dirty) {
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
NSError * err = nil;
|
|
846
|
+
if ([dev->binary_archive serializeToURL:dev->binary_archive_url error:&err]) {
|
|
847
|
+
GGML_LOG_INFO("%s: pipeline cache serialised → %s\n",
|
|
848
|
+
__func__,
|
|
849
|
+
[[dev->binary_archive_url path] UTF8String]);
|
|
850
|
+
dev->binary_archive_dirty = false;
|
|
851
|
+
} else {
|
|
852
|
+
GGML_LOG_WARN("%s: pipeline cache serialise failed for %s (%s)\n",
|
|
853
|
+
__func__,
|
|
854
|
+
[[dev->binary_archive_url path] UTF8String],
|
|
855
|
+
err ? [[err description] UTF8String] : "unknown");
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
ggml_metal_device_t ggml_metal_device_init(int device) {
|
|
860
|
+
ggml_metal_device_t dev = calloc(1, sizeof(struct ggml_metal_device));
|
|
861
|
+
|
|
862
|
+
assert(dev != NULL);
|
|
863
|
+
|
|
864
|
+
if (dev->mtl_device == nil) {
|
|
865
|
+
dev->mtl_device = MTLCreateSystemDefaultDevice();
|
|
866
|
+
|
|
867
|
+
if (dev->mtl_device) {
|
|
868
|
+
dev->mtl_queue = [dev->mtl_device newCommandQueue];
|
|
869
|
+
if (dev->mtl_queue == nil) {
|
|
870
|
+
GGML_LOG_ERROR("%s: error: failed to create command queue\n", __func__);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// CrispASR patch (PLAN #88 / CrisperWeaver §5.18): open the
|
|
874
|
+
// pipeline cache before any PSO gets JIT'd — including the
|
|
875
|
+
// tensor-API-probe dummy_kernel further down. Cache hits
|
|
876
|
+
// skip the Metal shader compiler entirely; misses fall
|
|
877
|
+
// through to JIT and get added to the archive on the way
|
|
878
|
+
// out, so the next run starts warm.
|
|
879
|
+
crispasr_metal_pipeline_cache_open(dev);
|
|
880
|
+
|
|
881
|
+
dev->addr_virt = 0x000000400ULL;
|
|
882
|
+
|
|
883
|
+
dev->props.device = device;
|
|
884
|
+
dev->props.has_simdgroup_reduction = [dev->mtl_device supportsFamily:MTLGPUFamilyApple7];
|
|
885
|
+
dev->props.has_simdgroup_reduction |= [dev->mtl_device supportsFamily:MTLGPUFamilyMetal3_GGML];
|
|
886
|
+
|
|
887
|
+
dev->props.has_simdgroup_mm = [dev->mtl_device supportsFamily:MTLGPUFamilyApple7];
|
|
888
|
+
dev->props.has_unified_memory = dev->mtl_device.hasUnifiedMemory;
|
|
889
|
+
|
|
890
|
+
dev->props.has_bfloat = [dev->mtl_device supportsFamily:MTLGPUFamilyMetal3_GGML];
|
|
891
|
+
dev->props.has_bfloat |= [dev->mtl_device supportsFamily:MTLGPUFamilyApple6];
|
|
892
|
+
if (getenv("GGML_METAL_BF16_DISABLE") != NULL) {
|
|
893
|
+
dev->props.has_bfloat = false;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
dev->props.has_tensor = [dev->mtl_device supportsFamily:MTLGPUFamilyMetal4_GGML];
|
|
897
|
+
if (getenv("GGML_METAL_TENSOR_DISABLE") != NULL) {
|
|
898
|
+
dev->props.has_tensor = false;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// note: disable the tensor API by default for old chips because with the current implementation it is not useful
|
|
902
|
+
// - M2 Ultra: ~5% slower
|
|
903
|
+
// - M4, M4 Max: no significant difference
|
|
904
|
+
//
|
|
905
|
+
// TODO: try to update the tensor API kernels to at least match the simdgroup performance
|
|
906
|
+
if (getenv("GGML_METAL_TENSOR_ENABLE") == NULL &&
|
|
907
|
+
![[dev->mtl_device name] containsString:@"M5"] &&
|
|
908
|
+
![[dev->mtl_device name] containsString:@"M6"] &&
|
|
909
|
+
![[dev->mtl_device name] containsString:@"A19"] &&
|
|
910
|
+
![[dev->mtl_device name] containsString:@"A20"]) {
|
|
911
|
+
GGML_LOG_WARN("%s: tensor API disabled for pre-M5 and pre-A19 devices\n", __func__);
|
|
912
|
+
dev->props.has_tensor = false;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
// double-check that the tensor API compiles
|
|
916
|
+
if (dev->props.has_tensor) {
|
|
917
|
+
const char * src_tensor_f16 = "\n"
|
|
918
|
+
"#include <metal_stdlib> \n"
|
|
919
|
+
"#include <metal_tensor> \n"
|
|
920
|
+
"#include <MetalPerformancePrimitives/MetalPerformancePrimitives.h> \n"
|
|
921
|
+
" \n"
|
|
922
|
+
"using namespace metal; \n"
|
|
923
|
+
"using namespace mpp::tensor_ops; \n"
|
|
924
|
+
" \n"
|
|
925
|
+
"kernel void dummy_kernel( \n"
|
|
926
|
+
" tensor<device half, dextents<int32_t, 2>> A [[buffer(0)]], \n"
|
|
927
|
+
" tensor<device half, dextents<int32_t, 2>> B [[buffer(1)]], \n"
|
|
928
|
+
" device float * C [[buffer(2)]], \n"
|
|
929
|
+
" uint2 tgid [[threadgroup_position_in_grid]]) \n"
|
|
930
|
+
"{ \n"
|
|
931
|
+
" auto tA = A.slice(0, (int)tgid.y); \n"
|
|
932
|
+
" auto tB = B.slice((int)tgid.x, 0); \n"
|
|
933
|
+
" \n"
|
|
934
|
+
" matmul2d< \n"
|
|
935
|
+
" matmul2d_descriptor(16, 16, dynamic_extent), \n"
|
|
936
|
+
" execution_simdgroups<4>> mm; \n"
|
|
937
|
+
" \n"
|
|
938
|
+
" auto cT = mm.get_destination_cooperative_tensor<decltype(tA), decltype(tB), float>(); \n"
|
|
939
|
+
" \n"
|
|
940
|
+
" auto sA = tA.slice(0, 0); \n"
|
|
941
|
+
" auto sB = tB.slice(0, 0); \n"
|
|
942
|
+
" mm.run(sB, sA, cT); \n"
|
|
943
|
+
" \n"
|
|
944
|
+
" auto tC = tensor<device float, dextents<int32_t, 2>, tensor_inline>(C, dextents<int32_t, 2>(16, 16)); \n"
|
|
945
|
+
" \n"
|
|
946
|
+
" cT.store(tC); \n"
|
|
947
|
+
"}";
|
|
948
|
+
|
|
949
|
+
GGML_LOG_INFO("%s: testing tensor API for f16 support\n", __func__);
|
|
950
|
+
ggml_metal_library_t lib = ggml_metal_library_init_from_source(dev, src_tensor_f16, false);
|
|
951
|
+
if (lib == NULL) {
|
|
952
|
+
GGML_LOG_WARN("%s: - the tensor API is not supported in this environment - disabling\n", __func__);
|
|
953
|
+
dev->props.has_tensor = false;
|
|
954
|
+
} else {
|
|
955
|
+
struct ggml_metal_pipeline_with_params ppl = ggml_metal_library_compile_pipeline(lib, "dummy_kernel", "dummy_kernel", nil);
|
|
956
|
+
if (!ppl.pipeline) {
|
|
957
|
+
GGML_LOG_WARN("%s: - the tensor API is not supported in this environment - disabling\n", __func__);
|
|
958
|
+
dev->props.has_tensor = false;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
ggml_metal_library_free(lib);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// try to compile a dummy kernel to determine if the tensor API is supported for bfloat
|
|
966
|
+
if (dev->props.has_tensor && dev->props.has_bfloat) {
|
|
967
|
+
const char * src_tensor_bf16 = "\n"
|
|
968
|
+
"#include <metal_stdlib> \n"
|
|
969
|
+
"#include <metal_tensor> \n"
|
|
970
|
+
"#include <MetalPerformancePrimitives/MetalPerformancePrimitives.h> \n"
|
|
971
|
+
" \n"
|
|
972
|
+
"using namespace metal; \n"
|
|
973
|
+
"using namespace mpp::tensor_ops; \n"
|
|
974
|
+
" \n"
|
|
975
|
+
"kernel void dummy_kernel( \n"
|
|
976
|
+
" tensor<device bfloat, dextents<int32_t, 2>> A [[buffer(0)]], \n"
|
|
977
|
+
" tensor<device bfloat, dextents<int32_t, 2>> B [[buffer(1)]], \n"
|
|
978
|
+
" device float * C [[buffer(2)]], \n"
|
|
979
|
+
" uint2 tgid [[threadgroup_position_in_grid]]) \n"
|
|
980
|
+
"{ \n"
|
|
981
|
+
" auto tA = A.slice(0, (int)tgid.y); \n"
|
|
982
|
+
" auto tB = B.slice((int)tgid.x, 0); \n"
|
|
983
|
+
" \n"
|
|
984
|
+
" matmul2d< \n"
|
|
985
|
+
" matmul2d_descriptor(16, 16, dynamic_extent), \n"
|
|
986
|
+
" execution_simdgroups<4>> mm; \n"
|
|
987
|
+
" \n"
|
|
988
|
+
" auto cT = mm.get_destination_cooperative_tensor<decltype(tA), decltype(tB), float>(); \n"
|
|
989
|
+
" \n"
|
|
990
|
+
" auto sA = tA.slice(0, 0); \n"
|
|
991
|
+
" auto sB = tB.slice(0, 0); \n"
|
|
992
|
+
" mm.run(sB, sA, cT); \n"
|
|
993
|
+
" \n"
|
|
994
|
+
" auto tC = tensor<device float, dextents<int32_t, 2>, tensor_inline>(C, dextents<int32_t, 2>(16, 16)); \n"
|
|
995
|
+
" \n"
|
|
996
|
+
" cT.store(tC); \n"
|
|
997
|
+
"}";
|
|
998
|
+
|
|
999
|
+
GGML_LOG_INFO("%s: testing tensor API for bfloat support\n", __func__);
|
|
1000
|
+
ggml_metal_library_t lib = ggml_metal_library_init_from_source(dev, src_tensor_bf16, false);
|
|
1001
|
+
if (lib == NULL) {
|
|
1002
|
+
GGML_LOG_WARN("%s: - the tensor API does not support bfloat - disabling bfloat support\n", __func__);
|
|
1003
|
+
dev->props.has_bfloat = false;
|
|
1004
|
+
} else {
|
|
1005
|
+
struct ggml_metal_pipeline_with_params ppl = ggml_metal_library_compile_pipeline(lib, "dummy_kernel", "dummy_kernel", nil);
|
|
1006
|
+
if (!ppl.pipeline) {
|
|
1007
|
+
GGML_LOG_WARN("%s: - the tensor API does not support bfloat - disabling bfloat support\n", __func__);
|
|
1008
|
+
dev->props.has_bfloat = false;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
ggml_metal_library_free(lib);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
dev->props.use_residency_sets = true;
|
|
1016
|
+
#if defined(GGML_METAL_HAS_RESIDENCY_SETS)
|
|
1017
|
+
dev->props.use_residency_sets = getenv("GGML_METAL_NO_RESIDENCY") == nil;
|
|
1018
|
+
#endif
|
|
1019
|
+
|
|
1020
|
+
dev->props.use_shared_buffers = dev->props.has_unified_memory;
|
|
1021
|
+
#if TARGET_OS_OSX
|
|
1022
|
+
// In case of eGPU, shared memory may be preferable.
|
|
1023
|
+
dev->props.use_shared_buffers |= [dev->mtl_device location] == MTLDeviceLocationExternal;
|
|
1024
|
+
#endif
|
|
1025
|
+
if (getenv("GGML_METAL_SHARED_BUFFERS_DISABLE") != NULL) {
|
|
1026
|
+
dev->props.use_shared_buffers = false;
|
|
1027
|
+
}
|
|
1028
|
+
if (getenv("GGML_METAL_SHARED_BUFFERS_ENABLE") != NULL) {
|
|
1029
|
+
dev->props.use_shared_buffers = true;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
dev->props.supports_gpu_family_apple7 = [dev->mtl_device supportsFamily:MTLGPUFamilyApple7];
|
|
1033
|
+
|
|
1034
|
+
dev->props.op_offload_min_batch_size = getenv("GGML_OP_OFFLOAD_MIN_BATCH") ? atoi(getenv("GGML_OP_OFFLOAD_MIN_BATCH")) : 32;
|
|
1035
|
+
|
|
1036
|
+
dev->props.max_buffer_size = dev->mtl_device.maxBufferLength;
|
|
1037
|
+
dev->props.max_theadgroup_memory_size = dev->mtl_device.maxThreadgroupMemoryLength;
|
|
1038
|
+
if (@available(macOS 10.12, iOS 16.0, *)) {
|
|
1039
|
+
dev->props.max_working_set_size = dev->mtl_device.recommendedMaxWorkingSetSize;
|
|
1040
|
+
} else {
|
|
1041
|
+
dev->props.max_working_set_size = dev->mtl_device.maxBufferLength;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
snprintf(dev->props.name, sizeof(dev->props.name), "%s%d", "MTL", device);
|
|
1045
|
+
snprintf(dev->props.desc, sizeof(dev->props.desc), "%s", [[dev->mtl_device name] UTF8String]);
|
|
1046
|
+
|
|
1047
|
+
dev->library = ggml_metal_library_init(dev);
|
|
1048
|
+
if (!dev->library) {
|
|
1049
|
+
GGML_LOG_ERROR("%s: error: failed to create library\n", __func__);
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
if (dev->props.use_residency_sets) {
|
|
1053
|
+
dev->rsets = ggml_metal_rsets_init();
|
|
1054
|
+
} else {
|
|
1055
|
+
dev->rsets = nil;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
// print MTL GPU family:
|
|
1059
|
+
GGML_LOG_INFO("%s: GPU name: %s (%s)\n", __func__, dev->props.name, dev->props.desc);
|
|
1060
|
+
|
|
1061
|
+
// determine max supported GPU family
|
|
1062
|
+
// https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
|
|
1063
|
+
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
|
|
1064
|
+
{
|
|
1065
|
+
for (int i = MTLGPUFamilyApple1 + 20; i >= MTLGPUFamilyApple1; --i) {
|
|
1066
|
+
if ([dev->mtl_device supportsFamily:i]) {
|
|
1067
|
+
GGML_LOG_INFO("%s: GPU family: MTLGPUFamilyApple%d (%d)\n", __func__, i - (int) MTLGPUFamilyApple1 + 1, i);
|
|
1068
|
+
break;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
for (int i = MTLGPUFamilyCommon1 + 5; i >= MTLGPUFamilyCommon1; --i) {
|
|
1073
|
+
if ([dev->mtl_device supportsFamily:i]) {
|
|
1074
|
+
GGML_LOG_INFO("%s: GPU family: MTLGPUFamilyCommon%d (%d)\n", __func__, i - (int) MTLGPUFamilyCommon1 + 1, i);
|
|
1075
|
+
break;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
for (int i = MTLGPUFamilyMetal3_GGML + 5; i >= MTLGPUFamilyMetal3_GGML; --i) {
|
|
1080
|
+
if ([dev->mtl_device supportsFamily:i]) {
|
|
1081
|
+
GGML_LOG_INFO("%s: GPU family: MTLGPUFamilyMetal%d (%d)\n", __func__, i - (int) MTLGPUFamilyMetal3_GGML + 3, i);
|
|
1082
|
+
break;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
GGML_LOG_INFO("%s: simdgroup reduction = %s\n", __func__, dev->props.has_simdgroup_reduction ? "true" : "false");
|
|
1088
|
+
GGML_LOG_INFO("%s: simdgroup matrix mul. = %s\n", __func__, dev->props.has_simdgroup_mm ? "true" : "false");
|
|
1089
|
+
GGML_LOG_INFO("%s: has unified memory = %s\n", __func__, dev->props.has_unified_memory ? "true" : "false");
|
|
1090
|
+
GGML_LOG_INFO("%s: has bfloat = %s\n", __func__, dev->props.has_bfloat ? "true" : "false");
|
|
1091
|
+
GGML_LOG_INFO("%s: has tensor = %s\n", __func__, dev->props.has_tensor ? "true" : "false");
|
|
1092
|
+
GGML_LOG_INFO("%s: use residency sets = %s\n", __func__, dev->props.use_residency_sets ? "true" : "false");
|
|
1093
|
+
GGML_LOG_INFO("%s: use shared buffers = %s\n", __func__, dev->props.use_shared_buffers ? "true" : "false");
|
|
1094
|
+
|
|
1095
|
+
#if TARGET_OS_OSX || (TARGET_OS_IOS && __clang_major__ >= 15)
|
|
1096
|
+
if (@available(macOS 10.12, iOS 16.0, *)) {
|
|
1097
|
+
GGML_LOG_INFO("%s: recommendedMaxWorkingSetSize = %8.2f MB\n", __func__, dev->props.max_working_set_size / 1e6);
|
|
1098
|
+
}
|
|
1099
|
+
#endif
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
return dev;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
void ggml_metal_device_free(ggml_metal_device_t dev) {
|
|
1107
|
+
assert(dev != NULL);
|
|
1108
|
+
|
|
1109
|
+
// CrispASR patch (PLAN #88 / CrisperWeaver §5.18): flush the
|
|
1110
|
+
// binary archive BEFORE the library + device go away. Once
|
|
1111
|
+
// `mtl_device` is released we can't talk to the archive any
|
|
1112
|
+
// more. The flush is a no-op when nothing was added since the
|
|
1113
|
+
// last serialise — typical for read-only "warm" runs.
|
|
1114
|
+
crispasr_metal_pipeline_cache_flush(dev);
|
|
1115
|
+
if (dev->binary_archive) {
|
|
1116
|
+
[dev->binary_archive release];
|
|
1117
|
+
dev->binary_archive = nil;
|
|
1118
|
+
}
|
|
1119
|
+
if (dev->binary_archive_url) {
|
|
1120
|
+
[dev->binary_archive_url release];
|
|
1121
|
+
dev->binary_archive_url = nil;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
ggml_metal_rsets_free(dev->rsets);
|
|
1125
|
+
|
|
1126
|
+
ggml_metal_library_free(dev->library);
|
|
1127
|
+
dev->library = NULL;
|
|
1128
|
+
|
|
1129
|
+
if (dev->mtl_queue) {
|
|
1130
|
+
[dev->mtl_queue release];
|
|
1131
|
+
dev->mtl_queue = nil;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
if (dev->mtl_device) {
|
|
1135
|
+
[dev->mtl_device release];
|
|
1136
|
+
dev->mtl_device = nil;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
free(dev);
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
void * ggml_metal_device_get_obj(ggml_metal_device_t dev) {
|
|
1143
|
+
return dev->mtl_device;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
void * ggml_metal_device_get_queue(ggml_metal_device_t dev) {
|
|
1147
|
+
return dev->mtl_queue;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
// CrispASR patch (PLAN #88 / CrisperWeaver §5.18): the pipeline-
|
|
1151
|
+
// cache accessors. Kept file-static + forward-declared near the
|
|
1152
|
+
// top of this file so the library-compile path (above the struct
|
|
1153
|
+
// definition) can read/write the archive without seeing the
|
|
1154
|
+
// internals.
|
|
1155
|
+
static id<MTLBinaryArchive> crispasr_metal_device_archive(ggml_metal_device_t dev) {
|
|
1156
|
+
return dev ? dev->binary_archive : nil;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
static void crispasr_metal_device_mark_archive_dirty(ggml_metal_device_t dev) {
|
|
1160
|
+
if (dev) {
|
|
1161
|
+
dev->binary_archive_dirty = true;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
ggml_metal_library_t ggml_metal_device_get_library(ggml_metal_device_t dev) {
|
|
1166
|
+
return dev->library;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
void ggml_metal_device_rsets_add(ggml_metal_device_t dev, ggml_metal_rset_t rset) {
|
|
1170
|
+
if (rset == nil) {
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
GGML_ASSERT(dev->rsets);
|
|
1175
|
+
|
|
1176
|
+
[dev->rsets->lock lock];
|
|
1177
|
+
|
|
1178
|
+
[dev->rsets->data addObject:rset];
|
|
1179
|
+
|
|
1180
|
+
[dev->rsets->lock unlock];
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
void ggml_metal_device_rsets_rm(ggml_metal_device_t dev, ggml_metal_rset_t rset) {
|
|
1184
|
+
if (rset == nil) {
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
GGML_ASSERT(dev->rsets);
|
|
1189
|
+
|
|
1190
|
+
[dev->rsets->lock lock];
|
|
1191
|
+
|
|
1192
|
+
[dev->rsets->data removeObject:rset];
|
|
1193
|
+
|
|
1194
|
+
[dev->rsets->lock unlock];
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
void ggml_metal_device_rsets_keep_alive(ggml_metal_device_t dev) {
|
|
1198
|
+
if (dev->rsets == NULL) {
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
atomic_store_explicit(&dev->rsets->d_loop, 2*dev->rsets->keep_alive_s, memory_order_relaxed);
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
struct ggml_metal_event {
|
|
1206
|
+
void * obj; // id<MTLSharedEvent>
|
|
1207
|
+
|
|
1208
|
+
atomic_int value;
|
|
1209
|
+
};
|
|
1210
|
+
|
|
1211
|
+
void ggml_metal_event_encode_signal(ggml_metal_event_t ev, ggml_metal_cmd_buf_t cmd_buf_raw) {
|
|
1212
|
+
id<MTLSharedEvent> event = (id<MTLSharedEvent>)ev->obj;
|
|
1213
|
+
|
|
1214
|
+
id<MTLCommandBuffer> cmd_buf = (id<MTLCommandBuffer>) cmd_buf_raw;
|
|
1215
|
+
|
|
1216
|
+
[cmd_buf encodeSignalEvent:event value:atomic_fetch_add_explicit(&ev->value, 1, memory_order_relaxed) + 1];
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
void ggml_metal_event_encode_wait(ggml_metal_event_t ev, ggml_metal_cmd_buf_t cmd_buf_raw) {
|
|
1220
|
+
id<MTLSharedEvent> event = (id<MTLSharedEvent>)ev->obj;
|
|
1221
|
+
|
|
1222
|
+
id<MTLCommandBuffer> cmd_buf = (id<MTLCommandBuffer>) cmd_buf_raw;
|
|
1223
|
+
|
|
1224
|
+
[cmd_buf encodeWaitForEvent:event value:atomic_load_explicit(&ev->value, memory_order_relaxed)];
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
ggml_metal_event_t ggml_metal_device_event_init(ggml_metal_device_t dev) {
|
|
1228
|
+
id<MTLSharedEvent> event = [dev->mtl_device newSharedEvent];
|
|
1229
|
+
|
|
1230
|
+
ggml_metal_event_t ev = calloc(1, sizeof(struct ggml_metal_event));
|
|
1231
|
+
|
|
1232
|
+
ev->obj = (__bridge void *)event;
|
|
1233
|
+
ev->value = 0;
|
|
1234
|
+
|
|
1235
|
+
return ev;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
void ggml_metal_device_event_free(ggml_metal_device_t dev, ggml_metal_event_t ev) {
|
|
1239
|
+
id<MTLSharedEvent> event = ev->obj;
|
|
1240
|
+
[event release];
|
|
1241
|
+
|
|
1242
|
+
free(ev);
|
|
1243
|
+
|
|
1244
|
+
GGML_UNUSED(dev);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
void ggml_metal_device_event_synchronize(ggml_metal_device_t dev, ggml_metal_event_t ev) {
|
|
1248
|
+
id<MTLSharedEvent> event = ev->obj;
|
|
1249
|
+
const bool res = [event waitUntilSignaledValue:atomic_load_explicit(&ev->value, memory_order_relaxed) timeoutMS:60000];
|
|
1250
|
+
if (!res) {
|
|
1251
|
+
GGML_ABORT("%s: failed to wait for event\n", __func__);
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
GGML_UNUSED(dev);
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
void ggml_metal_device_get_memory(ggml_metal_device_t dev, size_t * free, size_t * total) {
|
|
1258
|
+
if (@available(macOS 10.12, iOS 16.0, *)) {
|
|
1259
|
+
*total = dev->mtl_device.recommendedMaxWorkingSetSize;
|
|
1260
|
+
*free = *total - dev->mtl_device.currentAllocatedSize;
|
|
1261
|
+
} else {
|
|
1262
|
+
*free = 0;
|
|
1263
|
+
*total = 0;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
bool ggml_metal_device_supports_op(ggml_metal_device_t dev, const struct ggml_tensor * op) {
|
|
1268
|
+
const bool has_simdgroup_mm = dev->props.has_simdgroup_mm;
|
|
1269
|
+
const bool has_simdgroup_reduction = dev->props.has_simdgroup_reduction;
|
|
1270
|
+
const bool has_bfloat = dev->props.has_bfloat;
|
|
1271
|
+
|
|
1272
|
+
if (!has_bfloat) {
|
|
1273
|
+
if (op->type == GGML_TYPE_BF16) {
|
|
1274
|
+
return false;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
for (size_t i = 0, n = 3; i < n; ++i) {
|
|
1278
|
+
if (op->src[i] != NULL && op->src[i]->type == GGML_TYPE_BF16) {
|
|
1279
|
+
return false;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
switch (op->op) {
|
|
1285
|
+
case GGML_OP_SCALE:
|
|
1286
|
+
case GGML_OP_FILL:
|
|
1287
|
+
case GGML_OP_CLAMP:
|
|
1288
|
+
case GGML_OP_SQR:
|
|
1289
|
+
case GGML_OP_SQRT:
|
|
1290
|
+
case GGML_OP_SIN:
|
|
1291
|
+
case GGML_OP_COS:
|
|
1292
|
+
case GGML_OP_LOG:
|
|
1293
|
+
return ggml_is_contiguous_rows(op->src[0]) && (op->src[0]->type == GGML_TYPE_F32 || op->src[0]->type == GGML_TYPE_F16);
|
|
1294
|
+
case GGML_OP_UNARY:
|
|
1295
|
+
switch (ggml_get_unary_op(op)) {
|
|
1296
|
+
case GGML_UNARY_OP_TANH:
|
|
1297
|
+
case GGML_UNARY_OP_RELU:
|
|
1298
|
+
case GGML_UNARY_OP_SIGMOID:
|
|
1299
|
+
case GGML_UNARY_OP_GELU:
|
|
1300
|
+
case GGML_UNARY_OP_GELU_ERF:
|
|
1301
|
+
case GGML_UNARY_OP_GELU_QUICK:
|
|
1302
|
+
case GGML_UNARY_OP_SILU:
|
|
1303
|
+
case GGML_UNARY_OP_ELU:
|
|
1304
|
+
case GGML_UNARY_OP_NEG:
|
|
1305
|
+
case GGML_UNARY_OP_ABS:
|
|
1306
|
+
case GGML_UNARY_OP_SGN:
|
|
1307
|
+
case GGML_UNARY_OP_STEP:
|
|
1308
|
+
case GGML_UNARY_OP_HARDSWISH:
|
|
1309
|
+
case GGML_UNARY_OP_HARDSIGMOID:
|
|
1310
|
+
case GGML_UNARY_OP_EXP:
|
|
1311
|
+
case GGML_UNARY_OP_SOFTPLUS:
|
|
1312
|
+
case GGML_UNARY_OP_EXPM1:
|
|
1313
|
+
case GGML_UNARY_OP_FLOOR:
|
|
1314
|
+
case GGML_UNARY_OP_CEIL:
|
|
1315
|
+
case GGML_UNARY_OP_ROUND:
|
|
1316
|
+
case GGML_UNARY_OP_TRUNC:
|
|
1317
|
+
case GGML_UNARY_OP_XIELU:
|
|
1318
|
+
return ggml_is_contiguous_rows(op->src[0]) && (op->src[0]->type == GGML_TYPE_F32 || op->src[0]->type == GGML_TYPE_F16);
|
|
1319
|
+
default:
|
|
1320
|
+
return false;
|
|
1321
|
+
}
|
|
1322
|
+
case GGML_OP_GLU:
|
|
1323
|
+
switch (ggml_get_glu_op(op)) {
|
|
1324
|
+
case GGML_GLU_OP_REGLU:
|
|
1325
|
+
case GGML_GLU_OP_GEGLU:
|
|
1326
|
+
case GGML_GLU_OP_SWIGLU:
|
|
1327
|
+
case GGML_GLU_OP_SWIGLU_OAI:
|
|
1328
|
+
case GGML_GLU_OP_GEGLU_ERF:
|
|
1329
|
+
case GGML_GLU_OP_GEGLU_QUICK:
|
|
1330
|
+
case GGML_GLU_OP_SIGLU:
|
|
1331
|
+
return ggml_is_contiguous_1(op->src[0]) && op->src[0]->type == GGML_TYPE_F32;
|
|
1332
|
+
default:
|
|
1333
|
+
return false;
|
|
1334
|
+
}
|
|
1335
|
+
case GGML_OP_NONE:
|
|
1336
|
+
case GGML_OP_RESHAPE:
|
|
1337
|
+
case GGML_OP_VIEW:
|
|
1338
|
+
case GGML_OP_TRANSPOSE:
|
|
1339
|
+
case GGML_OP_PERMUTE:
|
|
1340
|
+
case GGML_OP_CONCAT:
|
|
1341
|
+
return true;
|
|
1342
|
+
case GGML_OP_ADD:
|
|
1343
|
+
case GGML_OP_SUB:
|
|
1344
|
+
case GGML_OP_MUL:
|
|
1345
|
+
case GGML_OP_DIV:
|
|
1346
|
+
case GGML_OP_ADD_ID:
|
|
1347
|
+
case GGML_OP_ACC:
|
|
1348
|
+
return ggml_is_contiguous_rows(op->src[0]) && ggml_is_contiguous_rows(op->src[1]) && op->src[0]->type == GGML_TYPE_F32;
|
|
1349
|
+
case GGML_OP_REPEAT:
|
|
1350
|
+
case GGML_OP_CONV_TRANSPOSE_1D:
|
|
1351
|
+
return true;
|
|
1352
|
+
// CrispASR patch (PR #160 col2im_1d) — MUST RE-APPLY after ggml bump.
|
|
1353
|
+
case GGML_OP_COL2IM_1D:
|
|
1354
|
+
return op->src[0]->type == GGML_TYPE_F32 || op->src[0]->type == GGML_TYPE_F16;
|
|
1355
|
+
// CrispASR patch (PR #07-metal-aa-snake-beta) — MUST RE-APPLY after ggml bump.
|
|
1356
|
+
case GGML_OP_AA_SNAKE_BETA:
|
|
1357
|
+
return op->src[0]->type == GGML_TYPE_F32 &&
|
|
1358
|
+
op->src[1]->type == GGML_TYPE_F32 &&
|
|
1359
|
+
op->src[2]->type == GGML_TYPE_F32 &&
|
|
1360
|
+
op->src[3]->type == GGML_TYPE_F32 &&
|
|
1361
|
+
op->src[4]->type == GGML_TYPE_F32 &&
|
|
1362
|
+
op->type == GGML_TYPE_F32 &&
|
|
1363
|
+
ggml_is_contiguous(op->src[0]) &&
|
|
1364
|
+
ggml_is_contiguous(op);
|
|
1365
|
+
case GGML_OP_CONV_TRANSPOSE_2D:
|
|
1366
|
+
return ggml_is_contiguous(op->src[0]) && ggml_is_contiguous(op->src[1]) &&
|
|
1367
|
+
(op->src[0]->type == GGML_TYPE_F16 || op->src[0]->type == GGML_TYPE_F32) &&
|
|
1368
|
+
op->src[1]->type == GGML_TYPE_F32 &&
|
|
1369
|
+
op->type == GGML_TYPE_F32;
|
|
1370
|
+
case GGML_OP_CONV_3D:
|
|
1371
|
+
return ggml_is_contiguous(op->src[0]) &&
|
|
1372
|
+
ggml_is_contiguous(op->src[1]) &&
|
|
1373
|
+
(op->src[0]->type == GGML_TYPE_F16 || op->src[0]->type == GGML_TYPE_F32) &&
|
|
1374
|
+
op->src[1]->type == GGML_TYPE_F32;
|
|
1375
|
+
case GGML_OP_SUM:
|
|
1376
|
+
return has_simdgroup_reduction && ggml_is_contiguous(op->src[0]);
|
|
1377
|
+
case GGML_OP_TRI:
|
|
1378
|
+
return ggml_is_contiguous_rows(op->src[0]);
|
|
1379
|
+
case GGML_OP_SUM_ROWS:
|
|
1380
|
+
case GGML_OP_CUMSUM:
|
|
1381
|
+
case GGML_OP_MEAN:
|
|
1382
|
+
case GGML_OP_SOFT_MAX:
|
|
1383
|
+
case GGML_OP_GROUP_NORM:
|
|
1384
|
+
case GGML_OP_L2_NORM:
|
|
1385
|
+
return has_simdgroup_reduction && ggml_is_contiguous_rows(op->src[0]);
|
|
1386
|
+
case GGML_OP_COUNT_EQUAL:
|
|
1387
|
+
return has_simdgroup_reduction &&
|
|
1388
|
+
op->src[0]->type == GGML_TYPE_I32 &&
|
|
1389
|
+
op->src[1]->type == GGML_TYPE_I32 &&
|
|
1390
|
+
op->type == GGML_TYPE_I64;
|
|
1391
|
+
case GGML_OP_ARGMAX:
|
|
1392
|
+
return has_simdgroup_reduction;
|
|
1393
|
+
case GGML_OP_NORM:
|
|
1394
|
+
case GGML_OP_RMS_NORM:
|
|
1395
|
+
return has_simdgroup_reduction && (ggml_is_contiguous_rows(op->src[0]));
|
|
1396
|
+
case GGML_OP_ROPE:
|
|
1397
|
+
return true;
|
|
1398
|
+
case GGML_OP_IM2COL:
|
|
1399
|
+
return ggml_is_contiguous(op->src[1]) && op->src[1]->type == GGML_TYPE_F32 && (op->type == GGML_TYPE_F16 || op->type == GGML_TYPE_F32);
|
|
1400
|
+
case GGML_OP_CONV_2D:
|
|
1401
|
+
return ggml_is_contiguous(op->src[0]) &&
|
|
1402
|
+
op->src[1]->type == GGML_TYPE_F32 &&
|
|
1403
|
+
op->type == GGML_TYPE_F32 &&
|
|
1404
|
+
(op->src[0]->type == GGML_TYPE_F16 || op->src[0]->type == GGML_TYPE_F32);
|
|
1405
|
+
case GGML_OP_UPSCALE:
|
|
1406
|
+
return op->src[0]->type == GGML_TYPE_F32;
|
|
1407
|
+
case GGML_OP_POOL_1D:
|
|
1408
|
+
return ggml_is_contiguous(op->src[0]) && op->src[0]->type == GGML_TYPE_F32;
|
|
1409
|
+
case GGML_OP_POOL_2D:
|
|
1410
|
+
return op->src[0]->type == GGML_TYPE_F32;
|
|
1411
|
+
case GGML_OP_PAD:
|
|
1412
|
+
// TODO: add circular padding support for metal, see https://github.com/ggml-org/llama.cpp/pull/16985
|
|
1413
|
+
if (ggml_get_op_params_i32(op, 8) != 0) {
|
|
1414
|
+
return false;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
return (ggml_get_op_params_i32(op, 0) == 0) && (ggml_get_op_params_i32(op, 2) == 0) &&
|
|
1418
|
+
(ggml_get_op_params_i32(op, 4) == 0) && (ggml_get_op_params_i32(op, 6) == 0);
|
|
1419
|
+
case GGML_OP_PAD_REFLECT_1D:
|
|
1420
|
+
case GGML_OP_TIMESTEP_EMBEDDING:
|
|
1421
|
+
case GGML_OP_LEAKY_RELU:
|
|
1422
|
+
return op->src[0]->type == GGML_TYPE_F32;
|
|
1423
|
+
case GGML_OP_ARGSORT:
|
|
1424
|
+
case GGML_OP_TOP_K:
|
|
1425
|
+
case GGML_OP_ARANGE:
|
|
1426
|
+
case GGML_OP_ROLL:
|
|
1427
|
+
return true;
|
|
1428
|
+
case GGML_OP_FLASH_ATTN_EXT:
|
|
1429
|
+
// CrispASR patch (#83): if the op carries PREC_F32, refuse to
|
|
1430
|
+
// run it on Metal — Apple's FA kernel uses simdgroup_half8x8
|
|
1431
|
+
// tiles for Q×K^T regardless of K type, leaking ~1e-4 drift vs
|
|
1432
|
+
// CPU's full-F32 attention. Returning false routes the op to
|
|
1433
|
+
// the CPU backend via the scheduler. Used by chatterbox T3
|
|
1434
|
+
// (which sets PREC_F32 on every flash_attn_ext) so that the
|
|
1435
|
+
// attention output is bit-identical CPU/GPU when paired with
|
|
1436
|
+
// kernel_mul_mv_q4_K_q8_K. Other backends ignore PREC_F32 by
|
|
1437
|
+
// design (it's only meaningful in this scope).
|
|
1438
|
+
{
|
|
1439
|
+
const enum ggml_prec fa_prec = (enum ggml_prec) ggml_get_op_params_i32(op, 3);
|
|
1440
|
+
if (fa_prec == GGML_PREC_F32) {
|
|
1441
|
+
return false;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
// for new head sizes, add checks here
|
|
1445
|
+
if (op->src[0]->ne[0] != 32 &&
|
|
1446
|
+
op->src[0]->ne[0] != 40 &&
|
|
1447
|
+
op->src[0]->ne[0] != 48 &&
|
|
1448
|
+
op->src[0]->ne[0] != 64 &&
|
|
1449
|
+
op->src[0]->ne[0] != 72 &&
|
|
1450
|
+
op->src[0]->ne[0] != 80 &&
|
|
1451
|
+
op->src[0]->ne[0] != 96 &&
|
|
1452
|
+
op->src[0]->ne[0] != 112 &&
|
|
1453
|
+
op->src[0]->ne[0] != 128 &&
|
|
1454
|
+
op->src[0]->ne[0] != 192 &&
|
|
1455
|
+
op->src[0]->ne[0] != 256 &&
|
|
1456
|
+
op->src[0]->ne[0] != 320 &&
|
|
1457
|
+
op->src[0]->ne[0] != 512 &&
|
|
1458
|
+
op->src[0]->ne[0] != 576) {
|
|
1459
|
+
return false;
|
|
1460
|
+
}
|
|
1461
|
+
if (op->src[1]->type != op->src[2]->type) {
|
|
1462
|
+
return false;
|
|
1463
|
+
}
|
|
1464
|
+
switch (op->src[1]->type) {
|
|
1465
|
+
case GGML_TYPE_F32:
|
|
1466
|
+
case GGML_TYPE_F16:
|
|
1467
|
+
case GGML_TYPE_Q8_0:
|
|
1468
|
+
case GGML_TYPE_Q4_0:
|
|
1469
|
+
case GGML_TYPE_Q4_1:
|
|
1470
|
+
case GGML_TYPE_Q5_0:
|
|
1471
|
+
case GGML_TYPE_Q5_1:
|
|
1472
|
+
break;
|
|
1473
|
+
case GGML_TYPE_BF16:
|
|
1474
|
+
if (!has_bfloat) {
|
|
1475
|
+
return false;
|
|
1476
|
+
}
|
|
1477
|
+
break;
|
|
1478
|
+
default:
|
|
1479
|
+
return false;
|
|
1480
|
+
}
|
|
1481
|
+
return has_simdgroup_mm; // TODO: over-restricted for vec-kernels
|
|
1482
|
+
case GGML_OP_SSM_CONV:
|
|
1483
|
+
case GGML_OP_SSM_SCAN:
|
|
1484
|
+
return has_simdgroup_reduction;
|
|
1485
|
+
case GGML_OP_RWKV_WKV6:
|
|
1486
|
+
case GGML_OP_RWKV_WKV7:
|
|
1487
|
+
return true;
|
|
1488
|
+
case GGML_OP_GATED_DELTA_NET:
|
|
1489
|
+
return has_simdgroup_reduction && op->src[2]->ne[0] % 32 == 0;
|
|
1490
|
+
case GGML_OP_SOLVE_TRI:
|
|
1491
|
+
case GGML_OP_MUL_MAT:
|
|
1492
|
+
case GGML_OP_MUL_MAT_ID:
|
|
1493
|
+
return has_simdgroup_reduction && op->src[0]->type != GGML_TYPE_NVFP4;
|
|
1494
|
+
case GGML_OP_SET:
|
|
1495
|
+
case GGML_OP_CPY:
|
|
1496
|
+
case GGML_OP_DUP:
|
|
1497
|
+
case GGML_OP_CONT:
|
|
1498
|
+
{
|
|
1499
|
+
switch (op->src[0]->type) {
|
|
1500
|
+
case GGML_TYPE_F32:
|
|
1501
|
+
switch (op->type) {
|
|
1502
|
+
case GGML_TYPE_F32:
|
|
1503
|
+
case GGML_TYPE_F16:
|
|
1504
|
+
case GGML_TYPE_BF16:
|
|
1505
|
+
case GGML_TYPE_Q8_0:
|
|
1506
|
+
case GGML_TYPE_Q1_0:
|
|
1507
|
+
case GGML_TYPE_Q4_0:
|
|
1508
|
+
case GGML_TYPE_Q4_1:
|
|
1509
|
+
case GGML_TYPE_Q5_0:
|
|
1510
|
+
case GGML_TYPE_Q5_1:
|
|
1511
|
+
case GGML_TYPE_IQ4_NL:
|
|
1512
|
+
case GGML_TYPE_I32:
|
|
1513
|
+
return true;
|
|
1514
|
+
default:
|
|
1515
|
+
return false;
|
|
1516
|
+
}
|
|
1517
|
+
case GGML_TYPE_F16:
|
|
1518
|
+
switch (op->type) {
|
|
1519
|
+
case GGML_TYPE_F32:
|
|
1520
|
+
case GGML_TYPE_F16:
|
|
1521
|
+
return true;
|
|
1522
|
+
default:
|
|
1523
|
+
return false;
|
|
1524
|
+
}
|
|
1525
|
+
case GGML_TYPE_BF16:
|
|
1526
|
+
switch (op->type) {
|
|
1527
|
+
case GGML_TYPE_F32:
|
|
1528
|
+
case GGML_TYPE_BF16:
|
|
1529
|
+
return true;
|
|
1530
|
+
default:
|
|
1531
|
+
return false;
|
|
1532
|
+
}
|
|
1533
|
+
case GGML_TYPE_Q1_0:
|
|
1534
|
+
case GGML_TYPE_Q4_0:
|
|
1535
|
+
case GGML_TYPE_Q4_1:
|
|
1536
|
+
case GGML_TYPE_Q5_0:
|
|
1537
|
+
case GGML_TYPE_Q5_1:
|
|
1538
|
+
case GGML_TYPE_Q8_0:
|
|
1539
|
+
switch (op->type) {
|
|
1540
|
+
case GGML_TYPE_F32:
|
|
1541
|
+
case GGML_TYPE_F16:
|
|
1542
|
+
return true;
|
|
1543
|
+
default:
|
|
1544
|
+
return false;
|
|
1545
|
+
}
|
|
1546
|
+
case GGML_TYPE_I32:
|
|
1547
|
+
return op->type == GGML_TYPE_F32 || op->type == GGML_TYPE_I32;
|
|
1548
|
+
default:
|
|
1549
|
+
return false;
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1552
|
+
case GGML_OP_GET_ROWS:
|
|
1553
|
+
return op->src[0]->type != GGML_TYPE_NVFP4;
|
|
1554
|
+
case GGML_OP_SET_ROWS:
|
|
1555
|
+
{
|
|
1556
|
+
if (op->src[0]->type != GGML_TYPE_F32) {
|
|
1557
|
+
return false;
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
switch (op->type) {
|
|
1561
|
+
case GGML_TYPE_F32:
|
|
1562
|
+
case GGML_TYPE_F16:
|
|
1563
|
+
case GGML_TYPE_BF16:
|
|
1564
|
+
case GGML_TYPE_Q8_0:
|
|
1565
|
+
case GGML_TYPE_Q4_0:
|
|
1566
|
+
case GGML_TYPE_Q4_1:
|
|
1567
|
+
case GGML_TYPE_Q5_0:
|
|
1568
|
+
case GGML_TYPE_Q5_1:
|
|
1569
|
+
case GGML_TYPE_IQ4_NL:
|
|
1570
|
+
return true;
|
|
1571
|
+
default:
|
|
1572
|
+
return false;
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1575
|
+
case GGML_OP_DIAG:
|
|
1576
|
+
return true;
|
|
1577
|
+
case GGML_OP_OPT_STEP_ADAMW:
|
|
1578
|
+
case GGML_OP_OPT_STEP_SGD:
|
|
1579
|
+
return has_simdgroup_reduction;
|
|
1580
|
+
default:
|
|
1581
|
+
return false;
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
const struct ggml_metal_device_props * ggml_metal_device_get_props(ggml_metal_device_t dev) {
|
|
1586
|
+
return &dev->props;
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
//
|
|
1590
|
+
// device buffers
|
|
1591
|
+
//
|
|
1592
|
+
|
|
1593
|
+
// max memory buffers that can be mapped to the device
|
|
1594
|
+
#define GGML_METAL_MAX_BUFFERS 64
|
|
1595
|
+
|
|
1596
|
+
struct ggml_metal_buffer_wrapper {
|
|
1597
|
+
void * data;
|
|
1598
|
+
size_t size;
|
|
1599
|
+
|
|
1600
|
+
id<MTLBuffer> metal;
|
|
1601
|
+
};
|
|
1602
|
+
|
|
1603
|
+
struct ggml_metal_buffer {
|
|
1604
|
+
void * all_data;
|
|
1605
|
+
size_t all_size;
|
|
1606
|
+
|
|
1607
|
+
// if false, the Metal buffer data is allocated in private GPU memory and is not shared with the host
|
|
1608
|
+
bool is_shared;
|
|
1609
|
+
bool owned;
|
|
1610
|
+
|
|
1611
|
+
// multiple buffers are used only to avoid the maximum buffer size limitation when using mmap
|
|
1612
|
+
int n_buffers;
|
|
1613
|
+
struct ggml_metal_buffer_wrapper buffers[GGML_METAL_MAX_BUFFERS];
|
|
1614
|
+
|
|
1615
|
+
bool use_residency_sets;
|
|
1616
|
+
|
|
1617
|
+
// optional MTLResidencySet
|
|
1618
|
+
// note: cannot use explicitly "id<MTLResidencySet>" here because it is not available on certain OSes
|
|
1619
|
+
id rset;
|
|
1620
|
+
|
|
1621
|
+
// pointers to global device
|
|
1622
|
+
ggml_metal_device_t dev;
|
|
1623
|
+
};
|
|
1624
|
+
|
|
1625
|
+
static void ggml_metal_log_allocated_size(id<MTLDevice> device, size_t size_aligned) {
|
|
1626
|
+
#ifndef GGML_METAL_NDEBUG
|
|
1627
|
+
#if TARGET_OS_OSX || (TARGET_OS_IOS && __clang_major__ >= 15)
|
|
1628
|
+
if (@available(macOS 10.12, iOS 16.0, *)) {
|
|
1629
|
+
GGML_LOG_DEBUG("%s: allocated buffer, size = %8.2f MiB, (%8.2f / %8.2f)\n",
|
|
1630
|
+
__func__,
|
|
1631
|
+
size_aligned / 1024.0 / 1024.0,
|
|
1632
|
+
device.currentAllocatedSize / 1024.0 / 1024.0,
|
|
1633
|
+
device.recommendedMaxWorkingSetSize / 1024.0 / 1024.0);
|
|
1634
|
+
|
|
1635
|
+
if (device.currentAllocatedSize > device.recommendedMaxWorkingSetSize) {
|
|
1636
|
+
GGML_LOG_WARN("%s: warning: current allocated size is greater than the recommended max working set size\n", __func__);
|
|
1637
|
+
}
|
|
1638
|
+
} else {
|
|
1639
|
+
GGML_LOG_INFO("%s: allocated buffer, size = %8.2f MiB, (%8.2f)\n",
|
|
1640
|
+
__func__,
|
|
1641
|
+
size_aligned / 1024.0 / 1024.0,
|
|
1642
|
+
device.currentAllocatedSize / 1024.0 / 1024.0);
|
|
1643
|
+
}
|
|
1644
|
+
#endif
|
|
1645
|
+
#endif
|
|
1646
|
+
GGML_UNUSED(device);
|
|
1647
|
+
GGML_UNUSED(size_aligned);
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
// rset init
|
|
1651
|
+
static bool ggml_metal_buffer_rset_init(ggml_metal_buffer_t buf) {
|
|
1652
|
+
buf->rset = nil;
|
|
1653
|
+
|
|
1654
|
+
if (!buf->use_residency_sets) {
|
|
1655
|
+
return true;
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
#if defined(GGML_METAL_HAS_RESIDENCY_SETS)
|
|
1659
|
+
if (@available(macOS 15.0, iOS 18.0, tvOS 18.0, visionOS 2.0, *)) {
|
|
1660
|
+
MTLResidencySetDescriptor * desc = [[MTLResidencySetDescriptor alloc] init];
|
|
1661
|
+
desc.label = @"ggml_metal";
|
|
1662
|
+
desc.initialCapacity = buf->n_buffers;
|
|
1663
|
+
|
|
1664
|
+
NSError * error;
|
|
1665
|
+
buf->rset = [buf->dev->mtl_device newResidencySetWithDescriptor:desc error:&error];
|
|
1666
|
+
if (error) {
|
|
1667
|
+
GGML_LOG_ERROR("%s: error: %s\n", __func__, [[error description] UTF8String]);
|
|
1668
|
+
[desc release];
|
|
1669
|
+
return false;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
[desc release];
|
|
1673
|
+
|
|
1674
|
+
for (int i = 0; i < buf->n_buffers; i++) {
|
|
1675
|
+
[buf->rset addAllocation:buf->buffers[i].metal];
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
[buf->rset commit];
|
|
1679
|
+
[buf->rset requestResidency];
|
|
1680
|
+
|
|
1681
|
+
return true;
|
|
1682
|
+
}
|
|
1683
|
+
#endif
|
|
1684
|
+
|
|
1685
|
+
return true;
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
// rset free
|
|
1689
|
+
static void ggml_metal_buffer_rset_free(ggml_metal_buffer_t buf) {
|
|
1690
|
+
#if defined(GGML_METAL_HAS_RESIDENCY_SETS)
|
|
1691
|
+
if (@available(macOS 15.0, iOS 18.0, tvOS 18.0, visionOS 2.0, *)) {
|
|
1692
|
+
if (buf->rset) {
|
|
1693
|
+
[buf->rset endResidency];
|
|
1694
|
+
[buf->rset removeAllAllocations];
|
|
1695
|
+
[buf->rset release];
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
#else
|
|
1699
|
+
GGML_UNUSED(buf);
|
|
1700
|
+
#endif
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
static void * ggml_metal_host_malloc(size_t n) {
|
|
1704
|
+
void * data = NULL;
|
|
1705
|
+
|
|
1706
|
+
#if TARGET_OS_OSX
|
|
1707
|
+
kern_return_t err = vm_allocate((vm_map_t) mach_task_self(), (void *) &data, n, VM_FLAGS_ANYWHERE);
|
|
1708
|
+
if (err != KERN_SUCCESS) {
|
|
1709
|
+
GGML_LOG_ERROR("%s: error: vm_allocate failed\n", __func__);
|
|
1710
|
+
return NULL;
|
|
1711
|
+
}
|
|
1712
|
+
#else
|
|
1713
|
+
const int result = posix_memalign((void **) &data, sysconf(_SC_PAGESIZE), n);
|
|
1714
|
+
if (result != 0) {
|
|
1715
|
+
GGML_LOG_ERROR("%s: error: posix_memalign failed\n", __func__);
|
|
1716
|
+
return NULL;
|
|
1717
|
+
}
|
|
1718
|
+
#endif
|
|
1719
|
+
|
|
1720
|
+
return data;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
ggml_metal_buffer_t ggml_metal_buffer_init(ggml_metal_device_t dev, size_t size, bool shared) {
|
|
1724
|
+
ggml_metal_buffer_t res = calloc(1, sizeof(struct ggml_metal_buffer));
|
|
1725
|
+
|
|
1726
|
+
res->dev = dev;
|
|
1727
|
+
|
|
1728
|
+
const size_t size_page = sysconf(_SC_PAGESIZE);
|
|
1729
|
+
|
|
1730
|
+
size_t size_aligned = size;
|
|
1731
|
+
if ((size_aligned % size_page) != 0) {
|
|
1732
|
+
size_aligned += (size_page - (size_aligned % size_page));
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
const struct ggml_metal_device_props * props_dev = ggml_metal_device_get_props(dev);
|
|
1736
|
+
|
|
1737
|
+
shared = shared && props_dev->use_shared_buffers;
|
|
1738
|
+
|
|
1739
|
+
// allocate shared buffer if the device supports it and it is required by the buffer type
|
|
1740
|
+
if (shared) {
|
|
1741
|
+
res->all_data = ggml_metal_host_malloc(size_aligned);
|
|
1742
|
+
res->is_shared = true;
|
|
1743
|
+
} else {
|
|
1744
|
+
// use virtual address
|
|
1745
|
+
res->all_data = (void *) atomic_fetch_add_explicit(&dev->addr_virt, size_aligned, memory_order_relaxed);
|
|
1746
|
+
res->is_shared = false;
|
|
1747
|
+
}
|
|
1748
|
+
res->all_size = size_aligned;
|
|
1749
|
+
|
|
1750
|
+
res->owned = true;
|
|
1751
|
+
|
|
1752
|
+
res->n_buffers = 1;
|
|
1753
|
+
|
|
1754
|
+
if (res->all_data != NULL) {
|
|
1755
|
+
res->buffers[0].size = size;
|
|
1756
|
+
res->buffers[0].metal = nil;
|
|
1757
|
+
|
|
1758
|
+
if (size_aligned > 0) {
|
|
1759
|
+
if (props_dev->use_shared_buffers && shared) {
|
|
1760
|
+
res->buffers[0].metal = [res->dev->mtl_device newBufferWithBytesNoCopy:res->all_data
|
|
1761
|
+
length:size_aligned
|
|
1762
|
+
options:MTLResourceStorageModeShared
|
|
1763
|
+
deallocator:nil];
|
|
1764
|
+
} else {
|
|
1765
|
+
res->buffers[0].metal = [res->dev->mtl_device newBufferWithLength:size_aligned options:MTLResourceStorageModePrivate];
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
res->buffers[0].data = res->all_data;
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
if (size_aligned > 0 && (res->all_data == NULL || res->buffers[0].metal == nil)) {
|
|
1773
|
+
GGML_LOG_ERROR("%s: error: failed to allocate buffer, size = %8.2f MiB\n", __func__, size_aligned / 1024.0 / 1024.0);
|
|
1774
|
+
free(res);
|
|
1775
|
+
return NULL;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
res->use_residency_sets = props_dev->use_residency_sets;
|
|
1779
|
+
|
|
1780
|
+
if (!ggml_metal_buffer_rset_init(res)) {
|
|
1781
|
+
GGML_LOG_ERROR("%s: error: failed to initialize residency set\n", __func__);
|
|
1782
|
+
free(res);
|
|
1783
|
+
return NULL;
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
ggml_metal_device_rsets_add(dev, res->rset);
|
|
1787
|
+
|
|
1788
|
+
//ggml_metal_log_allocated_size(device, size_aligned);
|
|
1789
|
+
|
|
1790
|
+
return res;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
ggml_metal_buffer_t ggml_metal_buffer_map(ggml_metal_device_t dev, void * ptr, size_t size, size_t max_tensor_size) {
|
|
1794
|
+
ggml_metal_buffer_t res = calloc(1, sizeof(struct ggml_metal_buffer));
|
|
1795
|
+
|
|
1796
|
+
res->dev = dev;
|
|
1797
|
+
|
|
1798
|
+
res->all_data = ptr;
|
|
1799
|
+
res->all_size = size;
|
|
1800
|
+
|
|
1801
|
+
res->is_shared = true;
|
|
1802
|
+
res->owned = false;
|
|
1803
|
+
|
|
1804
|
+
res->n_buffers = 0;
|
|
1805
|
+
|
|
1806
|
+
const size_t size_page = sysconf(_SC_PAGESIZE);
|
|
1807
|
+
|
|
1808
|
+
// page-align the data ptr
|
|
1809
|
+
{
|
|
1810
|
+
const uintptr_t offs = (uintptr_t) ptr % size_page;
|
|
1811
|
+
ptr = (void *) ((char *) ptr - offs);
|
|
1812
|
+
size += offs;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
size_t size_aligned = size;
|
|
1816
|
+
if ((size_aligned % size_page) != 0) {
|
|
1817
|
+
size_aligned += (size_page - (size_aligned % size_page));
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
const struct ggml_metal_device_props * props_dev = ggml_metal_device_get_props(dev);
|
|
1821
|
+
|
|
1822
|
+
// the buffer fits into the max buffer size allowed by the device
|
|
1823
|
+
if (size_aligned <= props_dev->max_buffer_size) {
|
|
1824
|
+
res->buffers[res->n_buffers].data = ptr;
|
|
1825
|
+
res->buffers[res->n_buffers].size = size;
|
|
1826
|
+
res->buffers[res->n_buffers].metal = nil;
|
|
1827
|
+
|
|
1828
|
+
if (size_aligned > 0) {
|
|
1829
|
+
res->buffers[res->n_buffers].metal = [res->dev->mtl_device newBufferWithBytesNoCopy:ptr length:size_aligned options:MTLResourceStorageModeShared deallocator:nil];
|
|
1830
|
+
|
|
1831
|
+
if (res->buffers[res->n_buffers].metal == nil) {
|
|
1832
|
+
GGML_LOG_ERROR("%s: error: failed to allocate buffer, size = %8.2f MiB\n", __func__, size_aligned / 1024.0 / 1024.0);
|
|
1833
|
+
free(res);
|
|
1834
|
+
return NULL;
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
ggml_metal_log_allocated_size(res->dev->mtl_device, size_aligned);
|
|
1839
|
+
|
|
1840
|
+
++res->n_buffers;
|
|
1841
|
+
} else {
|
|
1842
|
+
// this overlap between the views will guarantee that the tensor with the maximum size will fully fit into
|
|
1843
|
+
// one of the views
|
|
1844
|
+
const size_t size_ovlp = ((max_tensor_size + size_page - 1) / size_page + 1) * size_page; // round-up 2 pages just in case
|
|
1845
|
+
const size_t size_step = props_dev->max_buffer_size - size_ovlp;
|
|
1846
|
+
const size_t size_view = props_dev->max_buffer_size;
|
|
1847
|
+
|
|
1848
|
+
for (size_t i = 0; i < size; i += size_step) {
|
|
1849
|
+
const size_t size_step_aligned = (i + size_view <= size) ? size_view : (size_aligned - i);
|
|
1850
|
+
|
|
1851
|
+
res->buffers[res->n_buffers].data = (void *) ((uint8_t *) ptr + i);
|
|
1852
|
+
res->buffers[res->n_buffers].size = size_step_aligned;
|
|
1853
|
+
res->buffers[res->n_buffers].metal = nil;
|
|
1854
|
+
|
|
1855
|
+
if (size_step_aligned > 0) {
|
|
1856
|
+
res->buffers[res->n_buffers].metal = [res->dev->mtl_device newBufferWithBytesNoCopy:(void *) ((uint8_t *) ptr + i) length:size_step_aligned options:MTLResourceStorageModeShared deallocator:nil];
|
|
1857
|
+
|
|
1858
|
+
if (res->buffers[res->n_buffers].metal == nil) {
|
|
1859
|
+
GGML_LOG_ERROR("%s: error: failed to allocate buffer, size = %8.2f MiB\n", __func__, size_step_aligned / 1024.0 / 1024.0);
|
|
1860
|
+
free(res);
|
|
1861
|
+
return NULL;
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
ggml_metal_log_allocated_size(res->dev->mtl_device, size_step_aligned);
|
|
1866
|
+
|
|
1867
|
+
if (i + size_step < size) {
|
|
1868
|
+
GGML_LOG_INFO("\n");
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
++res->n_buffers;
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
res->use_residency_sets = props_dev->use_residency_sets;
|
|
1876
|
+
|
|
1877
|
+
if (!ggml_metal_buffer_rset_init(res)) {
|
|
1878
|
+
GGML_LOG_ERROR("%s: error: failed to initialize residency set\n", __func__);
|
|
1879
|
+
free(res);
|
|
1880
|
+
return NULL;
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
ggml_metal_device_rsets_add(dev, res->rset);
|
|
1884
|
+
|
|
1885
|
+
return res;
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
void ggml_metal_buffer_free(ggml_metal_buffer_t buf) {
|
|
1889
|
+
ggml_metal_device_rsets_rm(buf->dev, buf->rset);
|
|
1890
|
+
|
|
1891
|
+
for (int i = 0; i < buf->n_buffers; i++) {
|
|
1892
|
+
[buf->buffers[i].metal release];
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
ggml_metal_buffer_rset_free(buf);
|
|
1896
|
+
|
|
1897
|
+
if (buf->is_shared && buf->owned) {
|
|
1898
|
+
#if TARGET_OS_OSX
|
|
1899
|
+
vm_deallocate((vm_map_t)mach_task_self(), (vm_address_t)buf->all_data, buf->all_size);
|
|
1900
|
+
#else
|
|
1901
|
+
free(buf->all_data);
|
|
1902
|
+
#endif
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
free(buf);
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
void * ggml_metal_buffer_get_base(ggml_metal_buffer_t buf) {
|
|
1909
|
+
return buf->all_data;
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
bool ggml_metal_buffer_is_shared(ggml_metal_buffer_t buf) {
|
|
1913
|
+
return buf->is_shared;
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
void ggml_metal_buffer_memset_tensor(ggml_metal_buffer_t buf, struct ggml_tensor * tensor, uint8_t value, size_t offset, size_t size) {
|
|
1917
|
+
if (buf->is_shared) {
|
|
1918
|
+
memset((char *) tensor->data + offset, value, size);
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
@autoreleasepool {
|
|
1923
|
+
// dst
|
|
1924
|
+
struct ggml_metal_buffer_id bid_dst = ggml_metal_buffer_get_id(buf, tensor);
|
|
1925
|
+
bid_dst.offs += offset;
|
|
1926
|
+
|
|
1927
|
+
id<MTLCommandBuffer> cmd_buf = [buf->dev->mtl_queue commandBufferWithUnretainedReferences];
|
|
1928
|
+
|
|
1929
|
+
{
|
|
1930
|
+
id<MTLBlitCommandEncoder> encoder = [cmd_buf blitCommandEncoder];
|
|
1931
|
+
|
|
1932
|
+
[encoder fillBuffer:bid_dst.metal
|
|
1933
|
+
range:NSMakeRange(bid_dst.offs, bid_dst.offs + size)
|
|
1934
|
+
value:value];
|
|
1935
|
+
|
|
1936
|
+
[encoder endEncoding];
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
[cmd_buf commit];
|
|
1940
|
+
[cmd_buf waitUntilCompleted];
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
void ggml_metal_buffer_set_tensor(ggml_metal_buffer_t buf, struct ggml_tensor * tensor, const void * data, size_t offset, size_t size) {
|
|
1945
|
+
if (buf->is_shared && !getenv("CRISPASR_FORCE_BLIT_COPY")) {
|
|
1946
|
+
memcpy((char *) tensor->data + offset, data, size);
|
|
1947
|
+
// CrispASR debug (#83 r9 follow-up #5): probe CPU/GPU cache coherency
|
|
1948
|
+
// hypothesis. CRISPASR_FORCE_DMB=1 inserts a full memory barrier
|
|
1949
|
+
// after the host memcpy so the GPU is guaranteed to observe the
|
|
1950
|
+
// writes when the subsequent Metal command buffer executes.
|
|
1951
|
+
if (getenv("CRISPASR_FORCE_DMB")) {
|
|
1952
|
+
__sync_synchronize();
|
|
1953
|
+
}
|
|
1954
|
+
return;
|
|
1955
|
+
}
|
|
1956
|
+
// CrispASR debug (#83 r9 follow-up #5): if CRISPASR_FORCE_BLIT_COPY=1,
|
|
1957
|
+
// use the blit-encoder path even for shared-mode buffers, so the GPU
|
|
1958
|
+
// executes a copy command that the next compute submission waits on.
|
|
1959
|
+
|
|
1960
|
+
@autoreleasepool {
|
|
1961
|
+
// src
|
|
1962
|
+
void * data_ptr = (void *)(uintptr_t) data; // "const cast" the src data
|
|
1963
|
+
id<MTLBuffer> buf_src = [buf->dev->mtl_device newBufferWithBytesNoCopy:data_ptr
|
|
1964
|
+
length:size
|
|
1965
|
+
options:MTLResourceStorageModeShared
|
|
1966
|
+
deallocator:nil];
|
|
1967
|
+
|
|
1968
|
+
GGML_ASSERT(buf_src);
|
|
1969
|
+
|
|
1970
|
+
// dst
|
|
1971
|
+
struct ggml_metal_buffer_id bid_dst = ggml_metal_buffer_get_id(buf, tensor);
|
|
1972
|
+
bid_dst.offs += offset;
|
|
1973
|
+
|
|
1974
|
+
// note: for experimentation purposes, here we use a semaphore to wait for the copy to complete
|
|
1975
|
+
// this is alternative to waitUntilCompleted, which should be faster, but don't seem to make much difference
|
|
1976
|
+
dispatch_semaphore_t completion_semaphore = dispatch_semaphore_create(0);
|
|
1977
|
+
|
|
1978
|
+
id<MTLCommandBuffer> cmd_buf = [buf->dev->mtl_queue commandBufferWithUnretainedReferences];
|
|
1979
|
+
|
|
1980
|
+
{
|
|
1981
|
+
id<MTLBlitCommandEncoder> encoder = [cmd_buf blitCommandEncoder];
|
|
1982
|
+
|
|
1983
|
+
[encoder copyFromBuffer:buf_src
|
|
1984
|
+
sourceOffset:0
|
|
1985
|
+
toBuffer:bid_dst.metal
|
|
1986
|
+
destinationOffset:bid_dst.offs
|
|
1987
|
+
size:size];
|
|
1988
|
+
|
|
1989
|
+
[encoder endEncoding];
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
[cmd_buf addCompletedHandler:^(id<MTLCommandBuffer> cb) {
|
|
1993
|
+
// TODO: can check for errors here
|
|
1994
|
+
GGML_UNUSED(cb);
|
|
1995
|
+
|
|
1996
|
+
dispatch_semaphore_signal(completion_semaphore);
|
|
1997
|
+
}];
|
|
1998
|
+
|
|
1999
|
+
[cmd_buf commit];
|
|
2000
|
+
|
|
2001
|
+
dispatch_semaphore_wait(completion_semaphore, DISPATCH_TIME_FOREVER);
|
|
2002
|
+
dispatch_release(completion_semaphore);
|
|
2003
|
+
|
|
2004
|
+
//[cmd_buf waitUntilCompleted];
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
void ggml_metal_buffer_get_tensor(ggml_metal_buffer_t buf, const struct ggml_tensor * tensor, void * data, size_t offset, size_t size) {
|
|
2009
|
+
if (buf->is_shared) {
|
|
2010
|
+
memcpy(data, (const char *) tensor->data + offset, size);
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
@autoreleasepool {
|
|
2015
|
+
// src
|
|
2016
|
+
struct ggml_metal_buffer_id bid_src = ggml_metal_buffer_get_id(buf, tensor);
|
|
2017
|
+
bid_src.offs += offset;
|
|
2018
|
+
|
|
2019
|
+
// dst
|
|
2020
|
+
id<MTLBuffer> buf_dst = [buf->dev->mtl_device newBufferWithBytesNoCopy:data
|
|
2021
|
+
length:size
|
|
2022
|
+
options:MTLResourceStorageModeShared
|
|
2023
|
+
deallocator:nil];
|
|
2024
|
+
|
|
2025
|
+
GGML_ASSERT(buf_dst);
|
|
2026
|
+
|
|
2027
|
+
id<MTLCommandBuffer> cmd_buf = [buf->dev->mtl_queue commandBufferWithUnretainedReferences];
|
|
2028
|
+
|
|
2029
|
+
{
|
|
2030
|
+
id<MTLBlitCommandEncoder> encoder = [cmd_buf blitCommandEncoder];
|
|
2031
|
+
|
|
2032
|
+
[encoder copyFromBuffer:bid_src.metal
|
|
2033
|
+
sourceOffset:bid_src.offs
|
|
2034
|
+
toBuffer:buf_dst
|
|
2035
|
+
destinationOffset:0
|
|
2036
|
+
size:size];
|
|
2037
|
+
|
|
2038
|
+
[encoder endEncoding];
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
[cmd_buf commit];
|
|
2042
|
+
[cmd_buf waitUntilCompleted];
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
void ggml_metal_buffer_clear(ggml_metal_buffer_t buf, uint8_t value) {
|
|
2047
|
+
if (buf->is_shared) {
|
|
2048
|
+
memset(buf->all_data, value, buf->all_size);
|
|
2049
|
+
return;
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
@autoreleasepool {
|
|
2053
|
+
id<MTLCommandBuffer> cmd_buf = [buf->dev->mtl_queue commandBufferWithUnretainedReferences];
|
|
2054
|
+
|
|
2055
|
+
{
|
|
2056
|
+
id<MTLBlitCommandEncoder> encoder = [cmd_buf blitCommandEncoder];
|
|
2057
|
+
|
|
2058
|
+
[encoder fillBuffer:buf->buffers[0].metal
|
|
2059
|
+
range:NSMakeRange(0, buf->buffers[0].size)
|
|
2060
|
+
value:value];
|
|
2061
|
+
|
|
2062
|
+
[encoder endEncoding];
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
[cmd_buf commit];
|
|
2066
|
+
[cmd_buf waitUntilCompleted];
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
struct ggml_metal_buffer_id ggml_metal_buffer_get_id(ggml_metal_buffer_t buf, const struct ggml_tensor * t) {
|
|
2071
|
+
struct ggml_metal_buffer_id res = { nil, 0 };
|
|
2072
|
+
|
|
2073
|
+
const int64_t tsize = ggml_nbytes(t);
|
|
2074
|
+
|
|
2075
|
+
// find the view that contains the tensor fully
|
|
2076
|
+
for (int i = 0; i < buf->n_buffers; ++i) {
|
|
2077
|
+
const int64_t ioffs = (int64_t) t->data - (int64_t) buf->buffers[i].data;
|
|
2078
|
+
|
|
2079
|
+
//GGML_LOG_INFO("ioffs = %10ld, tsize = %10ld, sum = %10ld, buf->buffers[%d].size = %10ld\n", ioffs, tsize, ioffs + tsize, i, buf->buffers[i].size);
|
|
2080
|
+
if (ioffs >= 0 && ioffs + tsize <= (int64_t) buf->buffers[i].size) {
|
|
2081
|
+
res.metal = buf->buffers[i].metal;
|
|
2082
|
+
res.offs = (size_t) ioffs;
|
|
2083
|
+
|
|
2084
|
+
//GGML_LOG_INFO("%s: tensor '%16s', offs = %8ld\n", __func__, t->name, *offs);
|
|
2085
|
+
|
|
2086
|
+
return res;
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
GGML_LOG_ERROR("%s: error: tensor '%s' buffer is nil\n", __func__, t->name);
|
|
2091
|
+
|
|
2092
|
+
return res;
|
|
2093
|
+
}
|