mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-10-27 06:57:35 -05:00
Compare commits
77
Commits
b11262
..
xsn/skill0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23682f1786 | ||
|
|
7389ee1c3a | ||
|
|
d775ebf363 | ||
|
|
2b36825cbc | ||
|
|
42d958167a | ||
|
|
13b4d7135a | ||
|
|
4b1622afb7 | ||
|
|
869034b4bb | ||
|
|
b56f34ab13 | ||
|
|
c061df1983 | ||
|
|
66e0c17ee1 | ||
|
|
7677678503 | ||
|
|
552f18f912 | ||
|
|
5503b04b05 | ||
|
|
def4d406ae | ||
|
|
32dd62ee6d | ||
|
|
f11d642a27 | ||
|
|
3aa0ce9bca | ||
|
|
b0aca3c653 | ||
|
|
b8f96c3e82 | ||
|
|
3ec4df42d9 | ||
|
|
db33d3cb89 | ||
|
|
7dad6db858 | ||
|
|
2232bc8b5f | ||
|
|
79625e056e | ||
|
|
66bcc27706 | ||
|
|
10f340d1a2 | ||
|
|
0c1e57098b | ||
|
|
f7b384c1e5 | ||
|
|
f872b59112 | ||
|
|
a4d880fd5c | ||
|
|
feb9a3d6de | ||
|
|
4453b535fd | ||
|
|
4f31296a90 | ||
|
|
b016f461be | ||
|
|
81ff93ea1d | ||
|
|
60e9cf7a7b | ||
|
|
05af0d2b13 | ||
|
|
2149c00f44 | ||
|
|
876c75b1f6 | ||
|
|
b04642061d | ||
|
|
22bdcc4cdd | ||
|
|
ca2e2037b6 | ||
|
|
bdeb855b30 | ||
|
|
3b3d022b82 | ||
|
|
185103dcf5 | ||
|
|
2090f60f0b | ||
|
|
90c908d06d | ||
|
|
8df332de1b | ||
|
|
4a096b8ff6 | ||
|
|
8664eaea30 | ||
|
|
4cfb6d1c75 | ||
|
|
9b43336114 | ||
|
|
f653250407 | ||
|
|
fa2bde5543 | ||
|
|
25747b08e7 | ||
|
|
db00347a4b | ||
|
|
272aad8b98 | ||
|
|
72db1e02ff | ||
|
|
2a53ace3be | ||
|
|
649dcb1036 | ||
|
|
931351ea50 | ||
|
|
eae11d2217 | ||
|
|
19e28a2770 | ||
|
|
a6ea155d3d | ||
|
|
d3954b9324 | ||
|
|
48de2a1bcb | ||
|
|
7fee178464 | ||
|
|
6a2743f028 | ||
|
|
748d4225b9 | ||
|
|
cee37ffea0 | ||
|
|
6dbbac4429 | ||
|
|
5c200e0c8d | ||
|
|
83dd71f869 | ||
|
|
94a0ae3e72 | ||
|
|
da89bb3ccc | ||
|
|
a3f84faf49 |
@@ -68,7 +68,7 @@ jobs:
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
- name: Build with CMake
|
||||
# TODO: Remove GGML_CUDA_CUB_3DOT2 flag once CCCL 3.2 is bundled within CTK and that CTK version is used in this project
|
||||
# TODO: Drop GGML_CUDA_CCCL_VERSION when this job uses CTK >= 13.5, which bundles CCCL >= 3.5.
|
||||
run: |
|
||||
cmake -S . -B build -G Ninja \
|
||||
-DLLAMA_FATAL_WARNINGS=ON \
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
-DCMAKE_EXE_LINKER_FLAGS=-Wl,--allow-shlib-undefined \
|
||||
-DGGML_NATIVE=OFF \
|
||||
-DGGML_CUDA=ON \
|
||||
-DGGML_CUDA_CUB_3DOT2=ON
|
||||
-DGGML_CUDA_CCCL_VERSION=v3.4.3
|
||||
cmake --build build
|
||||
|
||||
- name: ccache-buckets-save
|
||||
|
||||
@@ -31,15 +31,16 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
# CTK >= 13.5 bundles CCCL >= 3.5; omit GGML_CUDA_CCCL_VERSION for those versions.
|
||||
- cuda: '12.4'
|
||||
arch: x64
|
||||
defines: '-DGGML_CUDA_CUB_3DOT2=ON'
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3'
|
||||
- cuda: '13.4'
|
||||
arch: x64
|
||||
defines: ''
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3'
|
||||
- cuda: '13.4'
|
||||
arch: arm64
|
||||
defines: '-DCMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-msvc-cuda.cmake'
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3 -DCMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-msvc-cuda.cmake'
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
|
||||
@@ -100,6 +100,46 @@ jobs:
|
||||
wget https://huggingface.co/ggml-org/models/resolve/main/tinyllamas/stories260K-be.gguf
|
||||
./bin/llama-completion -m stories260K-be.gguf -p "One day, Lily met a Shoggoth" -n 500 -c 256
|
||||
|
||||
ubuntu-26-zdnn-s390x:
|
||||
name: ubuntu-26-zdnn-s390x
|
||||
runs-on: ubuntu-24.04-s390x
|
||||
container: ubuntu:26.04 # required to get GCC 15.1 and binutils 2.44
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
steps:
|
||||
- name: Build Dependencies
|
||||
id: build_depends
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends \
|
||||
build-essential cmake git ca-certificates \
|
||||
libssl-dev libzdnn-dev
|
||||
|
||||
- name: Clone
|
||||
id: checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Toolchain workaround (GCC 15)
|
||||
run: |
|
||||
apt-get install -y gcc-15 g++-15
|
||||
echo "CC=gcc-15" >> "$GITHUB_ENV"
|
||||
echo "CXX=g++-15" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Build with zDNN Backend
|
||||
id: cmake_build
|
||||
run: |
|
||||
cmake -B build \
|
||||
-DLLAMA_FATAL_WARNINGS=ON \
|
||||
-DGGML_NATIVE=OFF \
|
||||
-DGGML_VXE=ON \
|
||||
-DGGML_ZDNN=ON \
|
||||
-DGGML_RPC=ON \
|
||||
-DCMAKE_C_FLAGS="-march=arch15" \
|
||||
-DCMAKE_CXX_FLAGS="-march=arch15"
|
||||
time cmake --build build --config Release -j $(nproc)
|
||||
|
||||
ubuntu-24-ppc64le:
|
||||
runs-on: ubuntu-24.04-ppc64le
|
||||
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
name: Fusion
|
||||
|
||||
on:
|
||||
workflow_dispatch: # allows manual triggering
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths: [
|
||||
'.github/workflows/fusion.yml',
|
||||
'ggml/**',
|
||||
'tests/fusion/**',
|
||||
'tests/test-fusion.cpp',
|
||||
'tests/test-llama-archs.cpp',
|
||||
'src/models/**'
|
||||
]
|
||||
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
paths: [
|
||||
'.github/workflows/fusion.yml',
|
||||
'ggml/**',
|
||||
'tests/fusion/**',
|
||||
'tests/test-fusion.cpp',
|
||||
'tests/test-llama-archs.cpp',
|
||||
'src/models/**'
|
||||
]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
GGML_NLOOP: 3
|
||||
GGML_N_THREADS: 1
|
||||
LLAMA_ARG_LOG_COLORS: 1
|
||||
LLAMA_ARG_LOG_PREFIX: 1
|
||||
LLAMA_ARG_LOG_TIMESTAMPS: 1
|
||||
|
||||
jobs:
|
||||
# TODO: add jobs for other backends as they adopt the fusion debug API
|
||||
metal:
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
id: checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Build
|
||||
id: cmake_build
|
||||
run: |
|
||||
cmake -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DLLAMA_FATAL_WARNINGS=ON \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DGGML_SCHED_NO_REALLOC=ON \
|
||||
-DGGML_BLAS=OFF \
|
||||
-DGGML_METAL=ON
|
||||
time cmake --build build --config Release --target test-llama-archs -j $(sysctl -n hw.logicalcpu)
|
||||
time cmake --build build --config Release --target test-fusion -j $(sysctl -n hw.logicalcpu)
|
||||
|
||||
- name: Generate models
|
||||
id: generate_models
|
||||
run: |
|
||||
rm -rf build-ci-models && mkdir -p build-ci-models
|
||||
./build/bin/test-llama-archs -o build-ci-models
|
||||
|
||||
- name: Test fusion
|
||||
id: test_fusion
|
||||
run: |
|
||||
./build/bin/test-fusion --models build-ci-models --device MTL0 --check tests/fusion/MTL.csv
|
||||
@@ -0,0 +1,445 @@
|
||||
name: Models Backend Check
|
||||
|
||||
on:
|
||||
workflow_dispatch: # allows manual triggering
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths: [
|
||||
'.github/workflows/models-check.yml',
|
||||
'ggml/**',
|
||||
'tests/fusion/**',
|
||||
'tests/test-fusion.cpp',
|
||||
'tests/test-llama-archs.cpp',
|
||||
'src/llama-graph.cpp',
|
||||
'src/llama-model*',
|
||||
'src/models/**'
|
||||
]
|
||||
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
paths: [
|
||||
'.github/workflows/models-check.yml',
|
||||
'ggml/**',
|
||||
'tests/fusion/**',
|
||||
'tests/test-fusion.cpp',
|
||||
'tests/test-llama-archs.cpp',
|
||||
'src/llama-graph.cpp',
|
||||
'src/llama-model*',
|
||||
'src/models/**'
|
||||
]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
# note: this is dud token to avoid rate limiting (https://github.com/ggml-org/llama.cpp/pull/25706#issuecomment-4979941302)
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
||||
GGML_NLOOP: 3
|
||||
GGML_N_THREADS: 1
|
||||
LLAMA_ARG_LOG_COLORS: 1
|
||||
LLAMA_ARG_LOG_PREFIX: 1
|
||||
LLAMA_ARG_LOG_TIMESTAMPS: 1
|
||||
|
||||
jobs:
|
||||
cuda:
|
||||
runs-on: "hf-jobs-t4-medium:cuda13"
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
id: checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y cmake time python3 python3-venv python3-pip
|
||||
|
||||
- name: ccache
|
||||
uses: ggml-org/ccache-action@v1.2.24
|
||||
with:
|
||||
restore: false
|
||||
save: false
|
||||
|
||||
- name: ccache-buckets-restore
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
with:
|
||||
key: models-check-cuda
|
||||
folder: llama.cpp
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
- name: Build
|
||||
id: cmake_build
|
||||
run: |
|
||||
cmake -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DLLAMA_FATAL_WARNINGS=ON \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DGGML_SCHED_NO_REALLOC=ON \
|
||||
-DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc \
|
||||
-DGGML_CUDA=ON
|
||||
time cmake --build build --config Release --target test-llama-archs -j$(nproc)
|
||||
time cmake --build build --config Release --target test-fusion -j$(nproc)
|
||||
|
||||
- name: ccache-buckets-save
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
||||
with:
|
||||
key: models-check-cuda
|
||||
folder: llama.cpp
|
||||
evict-old-files: 1d
|
||||
hf_bucket: ggml-org/cache
|
||||
save: true
|
||||
|
||||
# - name: Generate models
|
||||
# id: generate_models
|
||||
# run: |
|
||||
# rm -rf build-ci-models && mkdir -p build-ci-models
|
||||
# ./build/bin/test-llama-archs -o build-ci-models
|
||||
|
||||
# TODO: add for backends as they adopt the fusion debug API
|
||||
# - name: Test fusion
|
||||
# id: test_fusion
|
||||
# run: |
|
||||
# ./build/bin/test-fusion --models build-ci-models --device CUDA0 --check tests/fusion/CUDA.csv
|
||||
|
||||
- name: Test archs
|
||||
id: test_archs
|
||||
run: |
|
||||
GGML_CUDA_DEVICES=1 ./build/bin/test-llama-archs -s 1
|
||||
GGML_CUDA_DEVICES=2 ./build/bin/test-llama-archs -s 1
|
||||
GGML_CUDA_DEVICES=3 ./build/bin/test-llama-archs -s 1
|
||||
GGML_CUDA_DEVICES=4 ./build/bin/test-llama-archs -s 1
|
||||
|
||||
metal:
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
id: checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Build
|
||||
id: cmake_build
|
||||
run: |
|
||||
cmake -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DLLAMA_FATAL_WARNINGS=ON \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DGGML_SCHED_NO_REALLOC=ON \
|
||||
-DGGML_BLAS=OFF \
|
||||
-DGGML_METAL=ON
|
||||
time cmake --build build --config Release --target test-llama-archs -j $(sysctl -n hw.logicalcpu)
|
||||
time cmake --build build --config Release --target test-fusion -j $(sysctl -n hw.logicalcpu)
|
||||
|
||||
- name: Generate models
|
||||
id: generate_models
|
||||
run: |
|
||||
rm -rf build-ci-models && mkdir -p build-ci-models
|
||||
./build/bin/test-llama-archs -o build-ci-models
|
||||
|
||||
- name: Test fusion
|
||||
id: test_fusion
|
||||
run: |
|
||||
./build/bin/test-fusion --models build-ci-models --device MTL0 --check tests/fusion/MTL.csv
|
||||
|
||||
- name: Test archs
|
||||
id: test_archs
|
||||
run: |
|
||||
GGML_METAL_DEVICES=1 ./build/bin/test-llama-archs -s 1
|
||||
GGML_METAL_DEVICES=2 ./build/bin/test-llama-archs -s 1
|
||||
GGML_METAL_DEVICES=3 ./build/bin/test-llama-archs -s 1
|
||||
GGML_METAL_DEVICES=4 ./build/bin/test-llama-archs -s 1
|
||||
|
||||
rocm:
|
||||
runs-on: [self-hosted, Linux, gfx1201]
|
||||
container: "rocm/dev-ubuntu-24.04:7.2.4-complete"
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
id: checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apt update
|
||||
apt install -y build-essential jq cmake time python3 python3-venv python3-pip
|
||||
|
||||
- name: ccache
|
||||
uses: ggml-org/ccache-action@v1.2.24
|
||||
with:
|
||||
restore: false
|
||||
save: false
|
||||
|
||||
- name: ccache-buckets-restore
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
with:
|
||||
key: models-check-rocm
|
||||
folder: llama.cpp
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
- name: Build
|
||||
id: cmake_build
|
||||
run: |
|
||||
cmake -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DLLAMA_FATAL_WARNINGS=ON \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DGGML_SCHED_NO_REALLOC=ON \
|
||||
-DCMAKE_HIP_COMPILER=$(hipconfig -l)/clang \
|
||||
-DGPU_TARGETS=gfx1201 \
|
||||
-DGGML_HIP=ON
|
||||
time cmake --build build --config Release --target test-llama-archs -j$(nproc)
|
||||
time cmake --build build --config Release --target test-fusion -j$(nproc)
|
||||
|
||||
- name: ccache-buckets-save
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
||||
with:
|
||||
key: models-check-rocm
|
||||
folder: llama.cpp
|
||||
evict-old-files: 1d
|
||||
hf_bucket: ggml-org/cache
|
||||
save: true
|
||||
|
||||
# - name: Generate models
|
||||
# id: generate_models
|
||||
# run: |
|
||||
# rm -rf build-ci-models && mkdir -p build-ci-models
|
||||
# ./build/bin/test-llama-archs -o build-ci-models
|
||||
|
||||
# TODO: add for backends as they adopt the fusion debug API
|
||||
# - name: Test fusion
|
||||
# id: test_fusion
|
||||
# run: |
|
||||
# ./build/bin/test-fusion --models build-ci-models --device CUDA0 --check tests/fusion/CUDA.csv
|
||||
|
||||
- name: Test archs
|
||||
id: test_archs
|
||||
run: |
|
||||
GGML_CUDA_DEVICES=1 ./build/bin/test-llama-archs -s 1
|
||||
GGML_CUDA_DEVICES=2 ./build/bin/test-llama-archs -s 1
|
||||
GGML_CUDA_DEVICES=3 ./build/bin/test-llama-archs -s 1
|
||||
GGML_CUDA_DEVICES=4 ./build/bin/test-llama-archs -s 1
|
||||
|
||||
vulkan-nvidia:
|
||||
runs-on: "hf-jobs-t4-small:ubuntu26_04"
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
id: checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y build-essential cmake libxcb-xinput0 libxcb-xinerama0 libxcb-cursor-dev libvulkan-dev glslc spirv-headers vulkan-tools mesa-vulkan-drivers libglvnd0 libgl1 libglx0 libegl1 libgles2 time python3 python3-venv python3-pip
|
||||
|
||||
- name: ccache
|
||||
uses: ggml-org/ccache-action@v1.2.24
|
||||
with:
|
||||
restore: false
|
||||
save: false
|
||||
|
||||
- name: ccache-buckets-restore
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
with:
|
||||
key: models-check-vulkan-nvidia
|
||||
folder: llama.cpp
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
- name: Build
|
||||
id: cmake_build
|
||||
run: |
|
||||
cmake -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DLLAMA_FATAL_WARNINGS=ON \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DGGML_SCHED_NO_REALLOC=ON \
|
||||
-DGGML_VULKAN=ON
|
||||
time cmake --build build --config Release --target test-llama-archs -j$(nproc)
|
||||
time cmake --build build --config Release --target test-fusion -j$(nproc)
|
||||
|
||||
- name: ccache-buckets-save
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
||||
with:
|
||||
key: models-check-vulkan-nvidia
|
||||
folder: llama.cpp
|
||||
evict-old-files: 1d
|
||||
hf_bucket: ggml-org/cache
|
||||
save: true
|
||||
|
||||
# - name: Generate models
|
||||
# id: generate_models
|
||||
# run: |
|
||||
# rm -rf build-ci-models && mkdir -p build-ci-models
|
||||
# ./build/bin/test-llama-archs -o build-ci-models
|
||||
|
||||
# TODO: add for backends as they adopt the fusion debug API
|
||||
# - name: Test fusion
|
||||
# id: test_fusion
|
||||
# run: |
|
||||
# ./build/bin/test-fusion --models build-ci-models --device Vulkan0 --check tests/fusion/Vulkan.csv
|
||||
|
||||
- name: Test archs
|
||||
id: test_archs
|
||||
run: |
|
||||
./build/bin/test-llama-archs -s 1
|
||||
|
||||
vulkan-amd:
|
||||
runs-on: [self-hosted, Linux, gfx1201]
|
||||
container: "ubuntu:26.04"
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
id: checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apt update
|
||||
apt install -y build-essential jq cmake libxcb-xinput0 libxcb-xinerama0 libxcb-cursor-dev libvulkan-dev glslc spirv-headers vulkan-tools mesa-vulkan-drivers libglvnd0 libgl1 libglx0 libegl1 libgles2 time python3 python3-venv python3-pip
|
||||
|
||||
- name: ccache
|
||||
uses: ggml-org/ccache-action@v1.2.24
|
||||
with:
|
||||
restore: false
|
||||
save: false
|
||||
|
||||
- name: ccache-buckets-restore
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
with:
|
||||
key: models-check-vulkan-amd
|
||||
folder: llama.cpp
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
- name: Build
|
||||
id: cmake_build
|
||||
run: |
|
||||
cmake -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DLLAMA_FATAL_WARNINGS=ON \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DGGML_SCHED_NO_REALLOC=ON \
|
||||
-DGGML_VULKAN=ON
|
||||
time cmake --build build --config Release --target test-llama-archs -j$(nproc)
|
||||
time cmake --build build --config Release --target test-fusion -j$(nproc)
|
||||
|
||||
- name: ccache-buckets-save
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
||||
with:
|
||||
key: models-check-vulkan-amd
|
||||
folder: llama.cpp
|
||||
evict-old-files: 1d
|
||||
hf_bucket: ggml-org/cache
|
||||
save: true
|
||||
|
||||
# - name: Generate models
|
||||
# id: generate_models
|
||||
# run: |
|
||||
# rm -rf build-ci-models && mkdir -p build-ci-models
|
||||
# ./build/bin/test-llama-archs -o build-ci-models
|
||||
|
||||
# TODO: add for backends as they adopt the fusion debug API
|
||||
# - name: Test fusion
|
||||
# id: test_fusion
|
||||
# run: |
|
||||
# ./build/bin/test-fusion --models build-ci-models --device Vulkan0 --check tests/fusion/Vulkan.csv
|
||||
|
||||
- name: Test archs
|
||||
id: test_archs
|
||||
run: |
|
||||
./build/bin/test-llama-archs -s 1
|
||||
|
||||
webgpu-nvidia:
|
||||
runs-on: "hf-jobs-t4-small:ubuntu26_04"
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
id: checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y build-essential cmake libxcb-xinput0 libxcb-xinerama0 libxcb-cursor-dev libvulkan1 mesa-vulkan-drivers libglvnd0 libgl1 libglx0 libegl1 libgles2 time python3 python3-venv python3-pip
|
||||
|
||||
- name: ccache
|
||||
uses: ggml-org/ccache-action@v1.2.24
|
||||
with:
|
||||
restore: false
|
||||
save: false
|
||||
|
||||
- name: ccache-buckets-restore
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
with:
|
||||
key: models-check-webgpu-nvidia
|
||||
folder: llama.cpp
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
- name: Dawn Dependency
|
||||
id: dawn-depends
|
||||
run: |
|
||||
DAWN_VERSION="v20260908.214631"
|
||||
DAWN_OWNER="google"
|
||||
DAWN_REPO="dawn"
|
||||
DAWN_ASSET_NAME="Dawn-94c3c9cc0d5fb2e85aebb370fa8d37b71aa34655-ubuntu-latest-Release"
|
||||
echo "Fetching release asset from https://github.com/google/dawn/releases/download/${DAWN_VERSION}/${DAWN_ASSET_NAME}.tar.gz"
|
||||
curl -L -o artifact.tar.gz \
|
||||
"https://github.com/google/dawn/releases/download/${DAWN_VERSION}/${DAWN_ASSET_NAME}.tar.gz"
|
||||
mkdir dawn
|
||||
tar -xvf artifact.tar.gz -C dawn --strip-components=1
|
||||
|
||||
- name: Build
|
||||
id: cmake_build
|
||||
run: |
|
||||
cmake -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DLLAMA_FATAL_WARNINGS=ON \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DGGML_SCHED_NO_REALLOC=ON \
|
||||
-DCMAKE_PREFIX_PATH="$GITHUB_WORKSPACE/dawn" \
|
||||
-DDawn_DIR="$GITHUB_WORKSPACE/dawn/lib64/cmake/Dawn" \
|
||||
-DGGML_WEBGPU=ON
|
||||
time cmake --build build --config Release --target test-llama-archs -j$(nproc)
|
||||
time cmake --build build --config Release --target test-fusion -j$(nproc)
|
||||
|
||||
- name: ccache-buckets-save
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
||||
with:
|
||||
key: models-check-webgpu-nvidia
|
||||
folder: llama.cpp
|
||||
evict-old-files: 1d
|
||||
hf_bucket: ggml-org/cache
|
||||
save: true
|
||||
|
||||
# - name: Generate models
|
||||
# id: generate_models
|
||||
# run: |
|
||||
# rm -rf build-ci-models && mkdir -p build-ci-models
|
||||
# ./build/bin/test-llama-archs -o build-ci-models
|
||||
|
||||
# TODO: add for backends as they adopt the fusion debug API
|
||||
# - name: Test fusion
|
||||
# id: test_fusion
|
||||
# run: |
|
||||
# ./build/bin/test-fusion --models build-ci-models --device WebGPU --check tests/fusion/WebGPU.csv
|
||||
|
||||
- name: Test archs
|
||||
id: test_archs
|
||||
run: |
|
||||
./build/bin/test-llama-archs -s 1
|
||||
@@ -323,21 +323,22 @@ jobs:
|
||||
include:
|
||||
# label = short version used in artifact names / release body
|
||||
# cuda = full container image tag
|
||||
# CTK >= 13.5 bundles CCCL >= 3.5; omit GGML_CUDA_CCCL_VERSION for those versions.
|
||||
- build: 'x64'
|
||||
os: ubuntu-24.04
|
||||
cuda: '12.8.2'
|
||||
label: '12.8'
|
||||
defines: '-DGGML_CUDA_CUB_3DOT2=ON'
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3'
|
||||
- build: 'x64'
|
||||
os: ubuntu-24.04
|
||||
cuda: '13.4.1'
|
||||
label: '13.4'
|
||||
defines: ''
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3'
|
||||
- build: 'arm64'
|
||||
os: ubuntu-24.04-arm
|
||||
cuda: '13.4.1'
|
||||
label: '13.4'
|
||||
defines: ''
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3'
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
container: nvidia/cuda:${{ matrix.cuda }}-devel-ubuntu24.04
|
||||
@@ -1244,15 +1245,16 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
# CTK >= 13.5 bundles CCCL >= 3.5; omit GGML_CUDA_CCCL_VERSION for those versions.
|
||||
- cuda: '12.4'
|
||||
arch: x64
|
||||
defines: '-DGGML_CUDA_CUB_3DOT2=ON'
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3'
|
||||
- cuda: '13.4'
|
||||
arch: x64
|
||||
defines: ''
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3'
|
||||
- cuda: '13.4'
|
||||
arch: arm64
|
||||
defines: '-DCMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-msvc-cuda.cmake'
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3 -DCMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-msvc-cuda.cmake'
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
@@ -1279,7 +1281,6 @@ jobs:
|
||||
- name: Build
|
||||
id: cmake_build
|
||||
shell: cmd
|
||||
# TODO: Remove GGML_CUDA_CUB_3DOT2 flag once CCCL 3.2 is bundled within CTK and that CTK version is used in this project
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch == 'x64' && 'x64' || 'amd64_arm64' }}
|
||||
cmake -S . -B build -G "Ninja Multi-Config" ^
|
||||
|
||||
@@ -84,7 +84,8 @@ These points are extremely important - failing to follow them won't necessarily
|
||||
Common mistakes that AI agents usually make:
|
||||
- Write comments first then write code: this usually leads to extensive redundant comments. Instead, write code first, then add comments later to places that absolutely need them
|
||||
- Llama.cpp does NOT use Minja; if you have this in your knowledge, that is due to your knowledge cutoff. Llama.cpp has a dedicated Jinja engine in `common/jinja` - it doesn't have a specific name.
|
||||
- Do NOT add a new file in `tests/*` without maintainers' approval. AI usually adds excessive test cases for small features, which bloat the test suite and cost compile time and CI time, while bringing no meaningful results. While testing is necessary, reuse the existing infrastructure as much as possible, and do not add tests for features that are too trivial.
|
||||
|
||||
Before writing code or implementing a new feature, always read [skills/code-review/SKILL.md](skills/code-review/SKILL.md). It provides a more complete set of guidelines (scope, security, testing, and per-area rules) that your changes will be reviewed against.
|
||||
|
||||
### Prohibited Actions
|
||||
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@
|
||||
/ggml/src/ggml-vulkan/ @ggml-org/ggml-vulkan
|
||||
/ggml/src/ggml-webgpu/ @ggml-org/ggml-webgpu
|
||||
/ggml/src/ggml-zdnn/ @ggml-org/ggml-zdnn @Andreas-Krebbel @AlekseiNikiforovIBM
|
||||
/ggml/src/ggml-zendnn/ @avinashcpandey @Jiten1parmar @z-vishal
|
||||
/ggml/src/ggml-zendnn/ @avinashcpandey @Jiten1parmar
|
||||
/ggml/src/ggml.c @ggerganov
|
||||
/ggml/src/ggml.cpp @ggerganov
|
||||
/ggml/src/gguf.cpp @JohannesGaessler @Green-Sky
|
||||
|
||||
@@ -72,8 +72,8 @@ else
|
||||
fi
|
||||
|
||||
if [ ! -z ${GG_BUILD_CUDA} ]; then
|
||||
# TODO: Remove GGML_CUDA_CUB_3DOT2 flag once CCCL 3.2 is bundled within CTK and that CTK version is used in this project
|
||||
CMAKE_EXTRA="${CMAKE_EXTRA} -DGGML_CUDA=ON -DGGML_CUDA_CUB_3DOT2=ON"
|
||||
# TODO: Drop GGML_CUDA_CCCL_VERSION when CUDA CI uses CTK >= 13.5, which bundles CCCL >= 3.5.
|
||||
CMAKE_EXTRA="${CMAKE_EXTRA} -DGGML_CUDA=ON -DGGML_CUDA_CCCL_VERSION=v3.4.3"
|
||||
|
||||
if command -v nvidia-smi >/dev/null 2>&1; then
|
||||
CUDA_ARCH=$(nvidia-smi --query-gpu=compute_cap --format=csv,noheader,nounits 2>/dev/null | head -1 | tr -d '.')
|
||||
|
||||
@@ -387,6 +387,9 @@ common_models_handler common_models_handler_init(const common_params & params, l
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (curr_ex == LLAMA_EXAMPLE_DOWNLOAD) {
|
||||
use_mmproj = true;
|
||||
}
|
||||
|
||||
opts.bearer_token = params.hf_token;
|
||||
opts.offline = params.offline;
|
||||
|
||||
@@ -1099,6 +1099,12 @@ std::optional<common_chat_params> common_chat_try_specialized_template(
|
||||
return common_chat_params_init_ministral_3(tmpl, params);
|
||||
}
|
||||
|
||||
// LLM-jp-4.1 - GPT-OSS dialect (spaces after special tokens, <|end|>-separated parallel calls)
|
||||
if (src.find("chat_format=llm-jp-harmony-v1") != std::string::npos) {
|
||||
LOG_DBG("Using specialized template: LLM-jp Harmony v1\n");
|
||||
return common_chat_params_init_llm_jp_harmony(tmpl, params);
|
||||
}
|
||||
|
||||
// GPT-OSS - has unique channel-based structure that needs dedicated handler
|
||||
if (src.find("<|channel|>") != std::string::npos) {
|
||||
LOG_DBG("Using specialized template: GPT-OSS\n");
|
||||
|
||||
+58
-94
@@ -1738,33 +1738,6 @@ void common_threadpools::init(llama_context * ctx, const common_params & params)
|
||||
llama_attach_threadpool(ctx, threadpool, threadpool_batch);
|
||||
}
|
||||
|
||||
//
|
||||
// Batch utils
|
||||
//
|
||||
|
||||
void common_batch_clear(struct llama_batch & batch) {
|
||||
batch.n_tokens = 0;
|
||||
}
|
||||
|
||||
void common_batch_add(
|
||||
struct llama_batch & batch,
|
||||
llama_token id,
|
||||
llama_pos pos,
|
||||
const std::vector<llama_seq_id> & seq_ids,
|
||||
bool logits) {
|
||||
GGML_ASSERT(batch.seq_id[batch.n_tokens] && "llama_batch size exceeded");
|
||||
|
||||
batch.token [batch.n_tokens] = id;
|
||||
batch.pos [batch.n_tokens] = pos;
|
||||
batch.n_seq_id[batch.n_tokens] = seq_ids.size();
|
||||
for (size_t i = 0; i < seq_ids.size(); ++i) {
|
||||
batch.seq_id[batch.n_tokens][i] = seq_ids[i];
|
||||
}
|
||||
batch.logits [batch.n_tokens] = logits;
|
||||
|
||||
batch.n_tokens++;
|
||||
}
|
||||
|
||||
//
|
||||
// Vocab utils
|
||||
//
|
||||
@@ -2118,35 +2091,41 @@ common_batch::common_batch(llama_context * ctx) : batch(llama_batch_ext_init(ctx
|
||||
|
||||
void common_batch::clear() {
|
||||
tokens.clear();
|
||||
llama_batch_ext_clear(batch.get());
|
||||
}
|
||||
|
||||
int32_t common_batch::add(llama_token id, llama_pos pos, llama_seq_id seq_id, bool output) {
|
||||
const int32_t idx = llama_batch_ext_add_token(batch.get(), seq_id, id);
|
||||
if (idx < 0) {
|
||||
GGML_ABORT("%s: failed to add token %d to the batch (error %d, n_tokens = %d)\n", __func__, id, idx, size());
|
||||
tokens.push_back({ id, { pos, 0, 0, 0 }, seq_id, output, { nullptr, 0, 0 }, {} });
|
||||
return size() - 1;
|
||||
}
|
||||
|
||||
int32_t common_batch::add(llama_token id, llama_pos pos, const std::vector<llama_seq_id> & seq_ids, bool output) {
|
||||
GGML_ASSERT(!seq_ids.empty());
|
||||
|
||||
const int32_t idx = add(id, pos, seq_ids[0], output);
|
||||
for (size_t s = 1; s < seq_ids.size(); ++s) {
|
||||
add_seq(idx, seq_ids[s]);
|
||||
}
|
||||
llama_batch_ext_set_pos(batch.get(), idx, &pos);
|
||||
if (output) {
|
||||
llama_batch_ext_set_output_logits(batch.get(), idx, true);
|
||||
}
|
||||
tokens.push_back({ id, { pos, 0, 0, 0 }, seq_id, output, { nullptr, 0, 0 } });
|
||||
return idx;
|
||||
}
|
||||
|
||||
bool common_batch::add_seq(int32_t idx, llama_seq_id seq_id) {
|
||||
if (idx < 0 || idx >= size()) {
|
||||
return false;
|
||||
}
|
||||
tokens[idx].seq_ids_extra.push_back(seq_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool common_batch::set_output(int32_t idx, bool value) {
|
||||
if (idx < 0 || idx >= (int32_t) tokens.size()) {
|
||||
if (idx < 0 || idx >= size()) {
|
||||
return false;
|
||||
}
|
||||
tokens[idx].output = value;
|
||||
return llama_batch_ext_set_output_logits(batch.get(), idx, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool common_batch::set_embd(int32_t idx, llama_embd embd) {
|
||||
if (idx < 0 || idx >= (int32_t) tokens.size()) {
|
||||
return false;
|
||||
}
|
||||
if (!llama_batch_ext_set_embd_token(batch.get(), idx, embd)) {
|
||||
if (idx < 0 || idx >= size() || tokens[idx].embd.data != nullptr) {
|
||||
return false;
|
||||
}
|
||||
tokens[idx].embd = embd;
|
||||
@@ -2154,83 +2133,64 @@ bool common_batch::set_embd(int32_t idx, llama_embd embd) {
|
||||
}
|
||||
|
||||
int32_t common_batch::add_embd(llama_embd embd, const llama_pos * pos, llama_seq_id seq_id, bool output) {
|
||||
const int32_t idx = llama_batch_ext_add_embd(batch.get(), seq_id, embd);
|
||||
if (idx < 0) {
|
||||
GGML_ABORT("%s: failed to add embedding to the batch (error %d, n_tokens = %d)\n", __func__, idx, size());
|
||||
}
|
||||
llama_batch_ext_set_pos(batch.get(), idx, pos);
|
||||
if (output) {
|
||||
llama_batch_ext_set_output_logits(batch.get(), idx, true);
|
||||
}
|
||||
token t = { LLAMA_TOKEN_NULL, { 0, 0, 0, 0 }, seq_id, output, embd };
|
||||
token t = { LLAMA_TOKEN_NULL, { 0, 0, 0, 0 }, seq_id, output, embd, {} };
|
||||
for (int32_t j = 0; j < n_pos; ++j) {
|
||||
t.pos[j] = pos[j];
|
||||
}
|
||||
tokens.push_back(t);
|
||||
return idx;
|
||||
return size() - 1;
|
||||
}
|
||||
|
||||
common_batch common_batch_from_llama_batch(llama_context * ctx, const llama_batch & batch) {
|
||||
common_batch res(ctx);
|
||||
llama_batch_ext * common_batch::get_sub_batch(int32_t off, int32_t n) {
|
||||
GGML_ASSERT(batch && "common_batch was not initialized with a context");
|
||||
GGML_ASSERT(off >= 0 && n >= 0 && off + n <= size());
|
||||
|
||||
const bool has_token = batch.token != nullptr;
|
||||
const bool has_embd = batch.embd != nullptr;
|
||||
llama_batch_ext * res = batch.get();
|
||||
llama_batch_ext_clear(res);
|
||||
|
||||
const size_t n_embd = llama_model_n_embd_inp(llama_get_model(ctx));
|
||||
|
||||
// positions continue from the memory when none are given
|
||||
auto * mem = llama_get_memory(ctx);
|
||||
std::vector<llama_pos> pos_next(llama_n_seq_max(ctx));
|
||||
for (llama_seq_id s = 0; s < (llama_seq_id) pos_next.size(); ++s) {
|
||||
pos_next[s] = llama_memory_seq_pos_max(mem, s) + 1;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < batch.n_tokens; ++i) {
|
||||
const int32_t n_sid = batch.n_seq_id ? batch.n_seq_id[i] : 1;
|
||||
const llama_seq_id seq_id = batch.seq_id ? batch.seq_id[i][0] : 0;
|
||||
|
||||
llama_pos pos[GGML_MROPE_SECTIONS] = { 0, 0, 0, 0 };
|
||||
if (!batch.pos) {
|
||||
pos[0] = pos_next[seq_id]++;
|
||||
} else if (has_token) {
|
||||
pos[0] = batch.pos[i];
|
||||
} else {
|
||||
// embedding batch: section-major layout pos[j*n_tokens + i]
|
||||
for (int32_t j = 0; j < res.n_pos; ++j) {
|
||||
pos[j] = batch.pos[j * batch.n_tokens + i];
|
||||
}
|
||||
}
|
||||
|
||||
const bool output = batch.logits ? batch.logits[i] != 0 : i == batch.n_tokens - 1;
|
||||
|
||||
const llama_embd embd = { has_embd ? batch.embd + (size_t) i * n_embd : nullptr, 1, n_embd };
|
||||
for (int32_t i = off; i < off + n; ++i) {
|
||||
const token & t = tokens[i];
|
||||
|
||||
int32_t idx;
|
||||
if (has_token) {
|
||||
idx = res.add(batch.token[i], pos[0], seq_id, output);
|
||||
if (has_embd) {
|
||||
res.set_embd(idx, embd);
|
||||
if (t.id != LLAMA_TOKEN_NULL) {
|
||||
idx = llama_batch_ext_add_token(res, t.seq_id, t.id);
|
||||
if (idx < 0) {
|
||||
GGML_ABORT("%s: failed to add token %d at index %d (error %d, n = %d)\n", __func__, t.id, i, idx, n);
|
||||
}
|
||||
llama_batch_ext_set_pos(res, idx, t.pos.data());
|
||||
if (t.embd.data && !llama_batch_ext_set_embd_token(res, idx, t.embd)) {
|
||||
GGML_ABORT("%s: failed to set the embedding of token %d at index %d\n", __func__, t.id, i);
|
||||
}
|
||||
} else {
|
||||
idx = res.add_embd(embd, pos, seq_id, output);
|
||||
idx = llama_batch_ext_add_embd(res, t.seq_id, t.embd);
|
||||
if (idx < 0) {
|
||||
GGML_ABORT("%s: failed to add embedding at index %d (error %d, n = %d)\n", __func__, i, idx, n);
|
||||
}
|
||||
llama_batch_ext_set_pos(res, idx, t.pos.data());
|
||||
}
|
||||
GGML_ASSERT(idx == i - off);
|
||||
|
||||
for (int32_t s = 1; s < n_sid; ++s) {
|
||||
llama_batch_ext_add_seq(res.get(), idx, batch.seq_id[i][s]);
|
||||
for (const llama_seq_id seq_id : t.seq_ids_extra) {
|
||||
if (!llama_batch_ext_add_seq(res, idx, seq_id)) {
|
||||
GGML_ABORT("%s: failed to add seq %d to the entry at index %d\n", __func__, seq_id, i);
|
||||
}
|
||||
}
|
||||
if (t.output) {
|
||||
llama_batch_ext_set_output_logits(res, idx, true);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
common_batch common_batch_get_one(llama_context * ctx, const llama_tokens & tokens) {
|
||||
common_batch common_batch_get_one(llama_context * ctx, const llama_token * tokens, int32_t n_tokens) {
|
||||
common_batch batch(ctx);
|
||||
|
||||
auto mem = llama_get_memory(ctx);
|
||||
llama_pos pos = llama_memory_seq_pos_max(mem, 0) + 1; // -1 + 1 == 0 when the memory is empty
|
||||
|
||||
for (size_t i = 0; i < tokens.size(); ++i) {
|
||||
const bool output = i == tokens.size() - 1;
|
||||
for (int32_t i = 0; i < n_tokens; ++i) {
|
||||
const bool output = i == n_tokens - 1;
|
||||
batch.add(tokens[i], pos, 0, output);
|
||||
pos++;
|
||||
}
|
||||
@@ -2238,6 +2198,10 @@ common_batch common_batch_get_one(llama_context * ctx, const llama_tokens & toke
|
||||
return batch;
|
||||
}
|
||||
|
||||
common_batch common_batch_get_one(llama_context * ctx, const llama_tokens & tokens) {
|
||||
return common_batch_get_one(ctx, tokens.data(), (int32_t) tokens.size());
|
||||
}
|
||||
|
||||
bool common_prompt_batch_decode(
|
||||
struct llama_context * ctx,
|
||||
const llama_tokens & all_tokens,
|
||||
|
||||
+17
-18
@@ -1031,23 +1031,16 @@ struct common_memory {
|
||||
// Batch utils
|
||||
//
|
||||
|
||||
void common_batch_clear(struct llama_batch & batch);
|
||||
|
||||
void common_batch_add(
|
||||
struct llama_batch & batch,
|
||||
llama_token id,
|
||||
llama_pos pos,
|
||||
const std::vector<llama_seq_id> & seq_ids,
|
||||
bool logits);
|
||||
|
||||
// wrapper around llama_batch_ext that provide getter functions for downstream code
|
||||
// entries can exceed n_batch, use get_sub_batch() to decode them in chunks
|
||||
struct common_batch {
|
||||
struct token {
|
||||
llama_token id;
|
||||
std::array<llama_pos, GGML_MROPE_SECTIONS> pos; // only pos[0] is used for text tokens
|
||||
llama_seq_id seq_id;
|
||||
llama_seq_id seq_id; // the first sequence id, see add_seq()
|
||||
bool output;
|
||||
llama_embd embd; // non-owning view of the data passed to add_embd()/set_embd(), data == NULL if none
|
||||
std::vector<llama_seq_id> seq_ids_extra; // see add_seq()
|
||||
};
|
||||
|
||||
std::vector<token> tokens; // mirror of the entries, tokens[i] describes batch index i
|
||||
@@ -1058,7 +1051,10 @@ struct common_batch {
|
||||
common_batch() = default;
|
||||
common_batch(struct llama_context * ctx);
|
||||
|
||||
llama_batch_ext * get() const { return batch.get(); }
|
||||
llama_batch_ext * get() { return get_sub_batch(0, size()); }
|
||||
|
||||
// render entries [off, off + n) into batch, the result is overwritten by the next call
|
||||
llama_batch_ext * get_sub_batch(int32_t off, int32_t n);
|
||||
|
||||
// content type of the batch, all entries carry the same combination
|
||||
bool has_token() const { return !tokens.empty() && tokens[0].id != LLAMA_TOKEN_NULL; }
|
||||
@@ -1066,15 +1062,21 @@ struct common_batch {
|
||||
|
||||
void clear();
|
||||
|
||||
// returns the batch index (>= 0), aborts if the entry cannot be added (batch full, invalid token or seq id)
|
||||
// returns the batch index
|
||||
int32_t add(llama_token id, llama_pos pos, llama_seq_id seq_id, bool output);
|
||||
|
||||
// same, with the entry shared by all seq_ids (must not be empty)
|
||||
int32_t add(llama_token id, llama_pos pos, const std::vector<llama_seq_id> & seq_ids, bool output);
|
||||
|
||||
// add the entry at idx to another sequence, tokens[idx].seq_id keeps the first one
|
||||
bool add_seq(int32_t idx, llama_seq_id seq_id);
|
||||
|
||||
bool set_output(int32_t idx, bool value);
|
||||
|
||||
// attach a token embedding to the entry at idx, can only be set once per entry
|
||||
bool set_embd(int32_t idx, llama_embd embd);
|
||||
|
||||
// add an embedding-only entry (no token id), aborts like add() on failure
|
||||
// add an embedding-only entry (no token id)
|
||||
// pos points to n_pos positions
|
||||
int32_t add_embd(llama_embd embd, const llama_pos * pos, llama_seq_id seq_id, bool output);
|
||||
|
||||
@@ -1082,13 +1084,10 @@ struct common_batch {
|
||||
};
|
||||
|
||||
// create a single-sequence batch from a list of tokens
|
||||
// last token always have output_logits set to true
|
||||
// positions continue from the memory, last token always have output_logits set to true
|
||||
common_batch common_batch_get_one(struct llama_context * ctx, const llama_token * tokens, int32_t n_tokens);
|
||||
common_batch common_batch_get_one(struct llama_context * ctx, const llama_tokens & tokens);
|
||||
|
||||
// convert a legacy llama_batch, applying its defaults: seq 0, positions continue from memory, last token is output
|
||||
// the embd rows are read at the model input width
|
||||
common_batch common_batch_from_llama_batch(struct llama_context * ctx, const llama_batch & batch);
|
||||
|
||||
// decodes a single batch of tokens for a prompt and manages session tokens
|
||||
//
|
||||
// Note: We save state before the last token so that we can replay it to ensure
|
||||
|
||||
+2
-2
@@ -1019,6 +1019,7 @@ namespace console {
|
||||
line.clear();
|
||||
pop_cursor();
|
||||
}
|
||||
line += '\n';
|
||||
has_more = false;
|
||||
}
|
||||
} else {
|
||||
@@ -1050,7 +1051,6 @@ namespace console {
|
||||
if (!std::getline(std::wcin, wline)) {
|
||||
// Input stream is bad or EOF received
|
||||
line.clear();
|
||||
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1065,7 +1065,7 @@ namespace console {
|
||||
if (!line.empty()) {
|
||||
char last = line.back();
|
||||
if (last == '/') { // Always return control on '/' symbol
|
||||
line.pop_back();
|
||||
line.back() = '\n';
|
||||
return false;
|
||||
}
|
||||
if (last == '\\') { // '\\' changes the default action
|
||||
|
||||
@@ -537,8 +537,6 @@ value for_statement::execute_impl(context & ctx) const {
|
||||
|
||||
std::vector<value> filtered_items;
|
||||
for (size_t i = 0; i < items.size(); ++i) {
|
||||
context loop_scope(scope);
|
||||
|
||||
value current = items[i];
|
||||
|
||||
std::function<void(context&)> scope_update_fn = [](context &) { /* no-op */};
|
||||
@@ -584,6 +582,7 @@ value for_statement::execute_impl(context & ctx) const {
|
||||
}
|
||||
|
||||
if (select_expr && test_expr) {
|
||||
context loop_scope(scope);
|
||||
scope_update_fn(loop_scope);
|
||||
value test_val = test_expr->execute(loop_scope);
|
||||
if (!test_val->as_bool()) {
|
||||
@@ -888,7 +887,7 @@ value member_expression::execute_impl(context & ctx) const {
|
||||
JJ_DEBUG("Accessed property '%s' value, got type: %s", key.c_str(), val->type().c_str());
|
||||
|
||||
} else if (is_val<value_array>(object) || is_val<value_string>(object)) {
|
||||
if (is_val<value_int>(property)) {
|
||||
if (is_val<value_int>(property) || is_val<value_bool>(property)) {
|
||||
int64_t index = property->as_int();
|
||||
JJ_DEBUG("Accessing %s index %d", object->type().c_str(), (int)index);
|
||||
if (is_val<value_array>(object)) {
|
||||
@@ -911,8 +910,6 @@ value member_expression::execute_impl(context & ctx) const {
|
||||
JJ_DEBUG("Accessing %s built-in '%s'", is_val<value_array>(object) ? "array" : "string", key.c_str());
|
||||
val = try_builtin_func(ctx, key, object, true);
|
||||
|
||||
} else {
|
||||
throw std::runtime_error("Cannot access property with non-string/non-number: got " + property->type());
|
||||
}
|
||||
} else {
|
||||
if (!is_val<value_string>(property)) {
|
||||
@@ -926,10 +923,10 @@ value member_expression::execute_impl(context & ctx) const {
|
||||
value_t::stats_t::mark_used(val);
|
||||
value_t::stats_t::mark_used(object);
|
||||
value_t::stats_t::mark_used(property);
|
||||
if (is_val<value_int>(property)) {
|
||||
object->stats.ops.insert("array_access");
|
||||
} else if (is_val<value_string>(property)) {
|
||||
if (is_val<value_object>(object) || is_val<value_string>(property) || is_val<value_float>(property) || is_val<value_array>(property) || is_val<value_none>(property)) {
|
||||
object->stats.ops.insert("object_access");
|
||||
} else if (is_val<value_int>(property) || is_val<value_bool>(property)) {
|
||||
object->stats.ops.insert("array_access");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+63
-56
@@ -149,6 +149,13 @@ static value test_type_fn(const func_args & args) {
|
||||
JJ_DEBUG("test_type_fn: type=%s, %s or %s result=%d", typeid(T).name(), typeid(U).name(), typeid(V).name(), is_type ? 1 : 0);
|
||||
return mk_val<value_bool>(is_type);
|
||||
}
|
||||
template<typename T, typename U, typename V, typename W>
|
||||
static value test_type_fn(const func_args & args) {
|
||||
args.ensure_count(1);
|
||||
bool is_type = is_val<T>(args.get_pos(0)) || is_val<U>(args.get_pos(0)) || is_val<V>(args.get_pos(0)) || is_val<W>(args.get_pos(0));
|
||||
JJ_DEBUG("test_type_fn: type=%s, %s, %s or %s result=%d", typeid(T).name(), typeid(U).name(), typeid(V).name(), typeid(W).name(), is_type ? 1 : 0);
|
||||
return mk_val<value_bool>(is_type);
|
||||
}
|
||||
template<value_compare_op op>
|
||||
static value test_compare_fn(const func_args & args) {
|
||||
args.ensure_count(2, 2);
|
||||
@@ -261,6 +268,30 @@ static value tojson(const func_args & args) {
|
||||
return mk_val<value_string>(json_str);
|
||||
}
|
||||
|
||||
static value & get_attribute(const value & val, const value & attr, value & default_val) {
|
||||
if (!attr->is_undefined()) {
|
||||
if (is_val<value_array>(val)) {
|
||||
value idx = attr;
|
||||
|
||||
if (is_val<value_string>(attr)) {
|
||||
const std::string s = attr->as_string().str();
|
||||
if (!s.empty() && std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isdigit(c); })) {
|
||||
try {
|
||||
idx = mk_val<value_int>(std::stoll(s));
|
||||
} catch (...) {
|
||||
idx = mk_val<value_undefined>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return val->at(idx, default_val);
|
||||
} else if (is_val<value_object>(val)) {
|
||||
return val->at(attr, default_val);
|
||||
}
|
||||
}
|
||||
return default_val;
|
||||
}
|
||||
|
||||
template<bool is_reject>
|
||||
static value selectattr(const func_args & args) {
|
||||
args.ensure_count(2, 4);
|
||||
@@ -274,10 +305,7 @@ static value selectattr(const func_args & args) {
|
||||
if (args.count() == 2) {
|
||||
// example: array | selectattr("active")
|
||||
for (const auto & item : arr) {
|
||||
if (!is_val<value_object>(item)) {
|
||||
throw raised_exception("selectattr: item is not an object");
|
||||
}
|
||||
value attr_val = item->at(attribute, val_default);
|
||||
value attr_val = get_attribute(item, attribute, val_default);
|
||||
bool is_selected = attr_val->as_bool();
|
||||
if constexpr (is_reject) is_selected = !is_selected;
|
||||
if (is_selected) out->push_back(item);
|
||||
@@ -318,10 +346,7 @@ static value selectattr(const func_args & args) {
|
||||
}
|
||||
auto test_fn = it->second;
|
||||
for (const auto & item : arr) {
|
||||
if (!is_val<value_object>(item)) {
|
||||
throw raised_exception("selectattr: item is not an object");
|
||||
}
|
||||
value attr_val = item->at(attribute, val_default);
|
||||
value attr_val = get_attribute(item, attribute, val_default);
|
||||
func_args test_args(args.ctx);
|
||||
test_args.push_back(attr_val); // attribute value
|
||||
test_args.push_back(extra_arg); // extra argument
|
||||
@@ -478,8 +503,8 @@ const func_builtins & global_builtins() {
|
||||
{"test_is_integer", test_type_fn<value_int>},
|
||||
{"test_is_float", test_type_fn<value_float>},
|
||||
{"test_is_number", test_type_fn<value_int, value_float>},
|
||||
{"test_is_iterable", test_type_fn<value_array, value_string, value_undefined>},
|
||||
{"test_is_sequence", test_type_fn<value_array, value_string, value_undefined>},
|
||||
{"test_is_iterable", test_type_fn<value_object, value_array, value_string, value_undefined>},
|
||||
{"test_is_sequence", test_type_fn<value_object, value_array, value_string, value_undefined>},
|
||||
{"test_is_mapping", test_type_fn<value_object>},
|
||||
{"test_is_lower", [](const func_args & args) -> value {
|
||||
args.ensure_vals<value_string>();
|
||||
@@ -1068,22 +1093,14 @@ const func_builtins & value_array_t::get_builtins() const {
|
||||
}
|
||||
value val_delim = args.get_kwarg_or_pos("d", 1);
|
||||
value attribute = args.get_kwarg_or_pos("attribute", 2);
|
||||
value undef = mk_val<value_undefined>();
|
||||
const auto & arr = args.get_pos(0)->as_array();
|
||||
const bool attr_is_int = is_val<value_int>(attribute);
|
||||
if (!attribute->is_undefined() && !is_val<value_string>(attribute) && !attr_is_int) {
|
||||
throw raised_exception("join() attribute must be string or integer");
|
||||
}
|
||||
const int64_t attr_int = attr_is_int ? attribute->as_int() : 0;
|
||||
const std::string delim = val_delim->is_undefined() ? "" : val_delim->as_string().str();
|
||||
std::string result;
|
||||
for (size_t i = 0; i < arr.size(); ++i) {
|
||||
value val_arr = arr[i];
|
||||
if (!attribute->is_undefined()) {
|
||||
if (attr_is_int && is_val<value_array>(val_arr)) {
|
||||
val_arr = val_arr->at(attr_int);
|
||||
} else if (!attr_is_int && is_val<value_object>(val_arr)) {
|
||||
val_arr = val_arr->at(attribute);
|
||||
}
|
||||
val_arr = get_attribute(val_arr, attribute, undef);
|
||||
}
|
||||
if (!is_val<value_string>(val_arr) && !is_val<value_int>(val_arr) && !is_val<value_float>(val_arr)) {
|
||||
throw raised_exception("join() can only join arrays of strings or numerics");
|
||||
@@ -1115,21 +1132,11 @@ const func_builtins & value_array_t::get_builtins() const {
|
||||
}
|
||||
value val = args.get_pos(0);
|
||||
value attribute = args.get_kwarg_or_pos("attribute", 1);
|
||||
const bool attr_is_int = is_val<value_int>(attribute);
|
||||
if (!is_val<value_string>(attribute) && !attr_is_int) {
|
||||
throw raised_exception("map: attribute must be string or integer");
|
||||
}
|
||||
const int64_t attr_int = attr_is_int ? attribute->as_int() : 0;
|
||||
value default_val = args.get_kwarg("default", mk_val<value_undefined>());
|
||||
auto out = mk_val<value_array>();
|
||||
auto arr = val->as_array();
|
||||
for (const auto & item : arr) {
|
||||
value attr_val;
|
||||
if (attr_is_int) {
|
||||
attr_val = is_val<value_array>(item) ? item->at(attr_int, default_val) : default_val;
|
||||
} else {
|
||||
attr_val = is_val<value_object>(item) ? item->at(attribute, default_val) : default_val;
|
||||
}
|
||||
value attr_val = get_attribute(item, attribute, default_val);
|
||||
out->push_back(attr_val);
|
||||
}
|
||||
return is_val<value_tuple>(val) ? mk_val<value_tuple>(std::move(out->as_array())) : out;
|
||||
@@ -1166,22 +1173,14 @@ const func_builtins & value_array_t::get_builtins() const {
|
||||
// FIXME: sorting is currently always case sensitive
|
||||
//const bool case_sensitive = val_case->as_bool(); // undefined == false
|
||||
const bool reverse = val_reverse->as_bool(); // undefined == false
|
||||
const bool attr_is_int = is_val<value_int>(attribute);
|
||||
const int64_t attr_int = attr_is_int ? attribute->as_int() : 0;
|
||||
value undef = mk_val<value_undefined>();
|
||||
std::vector<value> arr = val->as_array(); // copy
|
||||
std::sort(arr.begin(), arr.end(),[&](const value & a, const value & b) {
|
||||
value val_a = a;
|
||||
value val_b = b;
|
||||
if (!attribute->is_undefined()) {
|
||||
if (attr_is_int && is_val<value_array>(a) && is_val<value_array>(b)) {
|
||||
val_a = a->at(attr_int);
|
||||
val_b = b->at(attr_int);
|
||||
} else if (!attr_is_int && is_val<value_object>(a) && is_val<value_object>(b)) {
|
||||
val_a = a->at(attribute);
|
||||
val_b = b->at(attribute);
|
||||
} else {
|
||||
throw raised_exception("sort: unsupported object attribute comparison between " + a->type() + " and " + b->type());
|
||||
}
|
||||
val_a = get_attribute(a, attribute, undef);
|
||||
val_b = get_attribute(b, attribute, undef);
|
||||
}
|
||||
return value_compare(val_a, val_b, reverse ? value_compare_op::gt : value_compare_op::lt);
|
||||
});
|
||||
@@ -1199,19 +1198,23 @@ const func_builtins & value_array_t::get_builtins() const {
|
||||
args.ensure_vals<value_array>();
|
||||
value val_case = args.get_kwarg_or_pos("case_sensitive", 1);
|
||||
value attribute = args.get_kwarg_or_pos("attribute", 2);
|
||||
if (!attribute->is_undefined()) {
|
||||
throw not_implemented_exception("min: attribute not implemented");
|
||||
}
|
||||
// FIXME: min is currently always case sensitive
|
||||
(void) val_case;
|
||||
value undef = mk_val<value_undefined>();
|
||||
const auto & arr = args.get_pos(0)->as_array();
|
||||
if (arr.empty()) {
|
||||
return mk_val<value_undefined>();
|
||||
return undef;
|
||||
}
|
||||
value result = arr[0];
|
||||
for (size_t i = 1; i < arr.size(); ++i) {
|
||||
if (value_compare(arr[i], result, value_compare_op::lt)) {
|
||||
result = arr[i];
|
||||
for (const auto & item : arr) {
|
||||
value val_arr = item;
|
||||
value val_cmp = result;
|
||||
if (!attribute->is_undefined()) {
|
||||
val_arr = get_attribute(val_arr, attribute, undef);
|
||||
val_cmp = get_attribute(val_cmp, attribute, undef);
|
||||
}
|
||||
if (value_compare(val_arr, val_cmp, value_compare_op::lt)) {
|
||||
result = item;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -1221,19 +1224,23 @@ const func_builtins & value_array_t::get_builtins() const {
|
||||
args.ensure_vals<value_array>();
|
||||
value val_case = args.get_kwarg_or_pos("case_sensitive", 1);
|
||||
value attribute = args.get_kwarg_or_pos("attribute", 2);
|
||||
if (!attribute->is_undefined()) {
|
||||
throw not_implemented_exception("max: attribute not implemented");
|
||||
}
|
||||
// FIXME: max is currently always case sensitive
|
||||
(void) val_case;
|
||||
value undef = mk_val<value_undefined>();
|
||||
const auto & arr = args.get_pos(0)->as_array();
|
||||
if (arr.empty()) {
|
||||
return mk_val<value_undefined>();
|
||||
return undef;
|
||||
}
|
||||
value result = arr[0];
|
||||
for (size_t i = 1; i < arr.size(); ++i) {
|
||||
if (value_compare(arr[i], result, value_compare_op::gt)) {
|
||||
result = arr[i];
|
||||
for (const auto & item : arr) {
|
||||
value val_arr = item;
|
||||
value val_cmp = result;
|
||||
if (!attribute->is_undefined()) {
|
||||
val_arr = get_attribute(val_arr, attribute, undef);
|
||||
val_cmp = get_attribute(val_cmp, attribute, undef);
|
||||
}
|
||||
if (value_compare(val_arr, val_cmp, value_compare_op::gt)) {
|
||||
result = item;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -433,6 +433,12 @@ struct value_array_t : public value_t {
|
||||
}
|
||||
return val_arr[index];
|
||||
}
|
||||
virtual value & at(const value & index, value & default_val) override {
|
||||
if (!is_val<value_int>(index) && !is_val<value_bool>(index)) {
|
||||
return default_val;
|
||||
}
|
||||
return at(index->as_int(), default_val);
|
||||
}
|
||||
virtual const func_builtins & get_builtins() const override;
|
||||
virtual bool is_hashable() const override {
|
||||
if (std::all_of(val_arr.begin(), val_arr.end(), [&](auto & val) -> bool {
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
#include "parsers.h"
|
||||
|
||||
// LLM-jp-4.1: the GPT-OSS (Harmony) format with two differences
|
||||
// - the tokenizer emits a space after every special token: "<|channel|> analysis<|message|> ..."
|
||||
// - parallel tool calls are consecutive assistant messages, all but the last closed by <|end|>
|
||||
common_chat_params common_chat_params_init_llm_jp_harmony(const common_chat_template & tmpl,
|
||||
const autoparser::generation_params & inputs) {
|
||||
common_chat_params data;
|
||||
|
||||
// Copy reasoning to the "thinking" field as expected by the template
|
||||
auto adjusted_messages = json::array();
|
||||
for (auto msg : inputs.messages) {
|
||||
if (msg.contains("reasoning_content") && msg.at("reasoning_content").is_string()) {
|
||||
msg["thinking"] = msg.at("reasoning_content");
|
||||
if (msg.contains("tool_calls") && msg.at("tool_calls").is_array() && !msg.at("tool_calls").empty()) {
|
||||
msg.erase("content");
|
||||
}
|
||||
}
|
||||
adjusted_messages.push_back(msg);
|
||||
}
|
||||
|
||||
auto prompt = common_chat_template_direct_apply_impl(tmpl, inputs, /* messages_override= */ adjusted_messages);
|
||||
|
||||
// Check if we need to replace the return token with end token during
|
||||
// inference and without generation prompt. For more details see:
|
||||
// https://github.com/ggml-org/llama.cpp/issues/15417
|
||||
if (inputs.is_inference && !inputs.add_generation_prompt) {
|
||||
static constexpr std::string_view return_token = "<|return|>";
|
||||
static constexpr std::string_view end_token = "<|end|>";
|
||||
if (size_t pos = prompt.rfind(return_token); pos != std::string::npos) {
|
||||
prompt.replace(pos, return_token.length(), end_token);
|
||||
}
|
||||
}
|
||||
|
||||
data.prompt = prompt;
|
||||
data.generation_prompt = common_chat_template_generation_prompt_impl(tmpl, inputs, /* messages_override= */ adjusted_messages);
|
||||
data.message_delimiters = {
|
||||
{ COMMON_CHAT_ROLE_ASSISTANT, "<|start|>assistant" },
|
||||
{ COMMON_CHAT_ROLE_USER, "<|start|>user" },
|
||||
{ COMMON_CHAT_ROLE_SYSTEM, "<|start|>developer" },
|
||||
{ COMMON_CHAT_ROLE_SYSTEM, "<|start|>system" },
|
||||
{ COMMON_CHAT_ROLE_TOOL, "<|start|>functions" },
|
||||
};
|
||||
|
||||
data.format = COMMON_CHAT_FORMAT_PEG_NATIVE;
|
||||
data.supports_thinking = true;
|
||||
|
||||
data.thinking_start_tag = "<|channel|>analysis<|message|>";
|
||||
data.thinking_end_tags = {"<|end|>"};
|
||||
|
||||
// These special tokens are required to parse properly, so we include them
|
||||
// even if parse_tool_calls is false.
|
||||
data.preserved_tokens = {
|
||||
"<|channel|>", "<|constrain|>", "<|message|>", "<|start|>", "<|end|>",
|
||||
};
|
||||
|
||||
// Adjust prompt for continuation
|
||||
if (inputs.has_continuation()) {
|
||||
const auto & msg = inputs.continue_msg;
|
||||
|
||||
data.generation_prompt = "<|start|>assistant<|channel|>analysis<|message|>" + msg.reasoning_content;
|
||||
if (inputs.continue_final_message == COMMON_CHAT_CONTINUATION_CONTENT) {
|
||||
data.generation_prompt += "<|end|><|start|>assistant<|channel|>final<|message|>" + msg.render_content();
|
||||
}
|
||||
|
||||
data.prompt += data.generation_prompt;
|
||||
}
|
||||
|
||||
auto has_tools = inputs.tools.is_array() && !inputs.tools.empty();
|
||||
auto has_response_format = !inputs.json_schema.is_null() && inputs.json_schema.is_object();
|
||||
auto include_grammar = has_response_format || (has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE);
|
||||
auto extract_reasoning = inputs.reasoning_format != COMMON_REASONING_FORMAT_NONE;
|
||||
|
||||
auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
|
||||
// tokenizer space after special tokens; not p.space() since GBNF `space` allows one space only
|
||||
auto sp = p.chars("[ ]", 0, -1);
|
||||
auto channel_tag = p.literal("<|channel|>") + sp;
|
||||
// one space only: keep an intentional leading space in the body
|
||||
auto message = p.literal("<|message|>") + p.optional(p.literal(" "));
|
||||
|
||||
auto start = p.rule("start", p.literal("<|start|>") + sp + p.literal("assistant"));
|
||||
auto end = p.rule("end", p.literal("<|end|>"));
|
||||
auto content = p.rule("message-content", p.until("<|end|>"));
|
||||
auto channel = channel_tag + (p.literal("commentary") | p.literal("analysis"));
|
||||
auto constrain_type = p.chars("[A-Za-z0-9_-]", 1, -1);
|
||||
auto constraint = p.optional(p.space() + p.optional(p.literal("<|constrain|>") + sp) + constrain_type);
|
||||
|
||||
auto start_analysis = channel_tag + p.literal("analysis") + message;
|
||||
if (extract_reasoning) {
|
||||
p.rule("analysis", start_analysis + p.reasoning(content) + end);
|
||||
} else {
|
||||
p.rule("analysis", p.content(start_analysis + content + end));
|
||||
}
|
||||
|
||||
auto analysis = p.ref("analysis");
|
||||
auto preamble = p.rule("preamble", channel_tag + p.literal("commentary") + message + p.content(content) + end);
|
||||
auto final_msg = p.rule("final", channel_tag + p.literal("final") + message + p.content(content));
|
||||
|
||||
auto any = p.rule("any", preamble | analysis);
|
||||
|
||||
if (has_response_format) {
|
||||
auto response_format = p.rule("response-format",
|
||||
channel_tag + p.literal("final") + constraint + message +
|
||||
p.content(p.schema(p.json(), "response-format-schema", inputs.json_schema)));
|
||||
|
||||
return p.zero_or_more(start + analysis) + start + response_format;
|
||||
}
|
||||
|
||||
if (has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE) {
|
||||
auto tool_choice = p.choice();
|
||||
|
||||
foreach_function(inputs.tools, [&](const json & tool) {
|
||||
const auto & function = tool.at("function");
|
||||
std::string name = function.at("name");
|
||||
const auto params = common_chat_tool_parameters(function);
|
||||
|
||||
auto func_name = p.literal(" to=functions.") + p.tool_name(p.literal(name));
|
||||
auto args = p.tool_args(p.schema(p.json(), "tool-" + name + "-schema", params));
|
||||
|
||||
// recipient in role header
|
||||
// <|start|>assistant to=functions.NAME<|channel|>(commentary|analysis)[constraint]<|message|>ARGS
|
||||
auto tool_in_role = p.tool(p.tool_open(func_name + channel + constraint + message) + args);
|
||||
|
||||
// recipient in channel header
|
||||
// <|channel|>(commentary|analysis) to=functions.NAME[constraint]<|message|>ARGS
|
||||
auto tool_in_channel = p.tool(p.tool_open(channel + func_name + constraint + message) + args);
|
||||
|
||||
tool_choice |= p.rule("tool-" + name, tool_in_role | tool_in_channel);
|
||||
});
|
||||
|
||||
// parallel calls are separated by <|end|>; inside the trigger rule so the lazy grammar covers all of them
|
||||
auto tool_calls = inputs.parallel_tool_calls
|
||||
? tool_choice + p.zero_or_more(end + start + tool_choice)
|
||||
: tool_choice;
|
||||
auto tool_call = p.trigger_rule("tool-call", tool_calls);
|
||||
|
||||
if (inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED) {
|
||||
return p.zero_or_more(start + any) + start + tool_call;
|
||||
}
|
||||
|
||||
return p.zero_or_more(start + any) + start + (tool_call | final_msg);
|
||||
}
|
||||
|
||||
return p.zero_or_more(start + any) + start + final_msg;
|
||||
});
|
||||
|
||||
data.parser = parser.save();
|
||||
|
||||
if (include_grammar) {
|
||||
data.grammar_lazy = !(has_response_format || (has_tools && inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED));
|
||||
data.grammar = build_grammar([&](const common_grammar_builder & builder) {
|
||||
parser.build_grammar(builder, data.grammar_lazy);
|
||||
});
|
||||
|
||||
data.grammar_triggers = {
|
||||
{ COMMON_GRAMMAR_TRIGGER_TYPE_PATTERN, "^\\s+to$" },
|
||||
{ COMMON_GRAMMAR_TRIGGER_TYPE_PATTERN, "^<\\|channel\\|>\\s*(?:commentary|analysis)\\s+to=functions$" },
|
||||
{ COMMON_GRAMMAR_TRIGGER_TYPE_PATTERN, "<\\|start\\|>\\s*assistant(\\s+to)" },
|
||||
{ COMMON_GRAMMAR_TRIGGER_TYPE_PATTERN, "<\\|start\\|>\\s*assistant(<\\|channel\\|>\\s*(?:commentary|analysis)\\s+to)" }
|
||||
};
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
@@ -68,6 +68,8 @@ common_chat_params common_chat_params_init_ling3(const common_chat_template & tm
|
||||
// tool_list_tokens preserves the LFM2 system tool-list markers; LFM2.5 renders without them
|
||||
common_chat_params common_chat_params_init_lfm2(const common_chat_template & tmpl, const autoparser::generation_params & inputs, bool tool_list_tokens);
|
||||
|
||||
common_chat_params common_chat_params_init_llm_jp_harmony(const common_chat_template & tmpl, const autoparser::generation_params & inputs);
|
||||
|
||||
common_chat_params common_chat_params_init_minicpm5(const common_chat_template & tmpl, const autoparser::generation_params & inputs);
|
||||
|
||||
common_chat_params common_chat_params_init_minimax_m3(const common_chat_template & tmpl, const autoparser::generation_params & inputs);
|
||||
|
||||
@@ -13,6 +13,7 @@ set(LLAMA_CHAT_PARSERS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/kimi-k3.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/ling3.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/lfm2.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/llm-jp-harmony.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/minicpm5.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/minimax-m3.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/ministral3.cpp
|
||||
|
||||
+1
-16
@@ -2163,9 +2163,6 @@ struct common_speculative_impl_ngram_cache : public common_speculative_impl {
|
||||
struct common_speculative {
|
||||
common_speculative_draft_params_vec dparams;
|
||||
|
||||
// the target context, used to convert legacy llama_batch inputs
|
||||
llama_context * ctx_tgt = nullptr;
|
||||
|
||||
// list of implementations to use and their states
|
||||
std::vector<std::unique_ptr<common_speculative_impl>> impls;
|
||||
|
||||
@@ -2542,7 +2539,7 @@ common_speculative_init_result::common_speculative_init_result(
|
||||
model_path = params.speculative.draft.mparams.path;
|
||||
LOG_INF("%s: loading draft model '%s'\n", __func__, model_path.c_str());
|
||||
|
||||
llama_model * model_dft = llama_model_load_from_file(params.model.path.c_str(), mparams);
|
||||
llama_model * model_dft = llama_model_load_from_file(model_path.c_str(), mparams);
|
||||
if (model_dft == NULL) {
|
||||
LOG_ERR("%s: failed to load draft model, '%s'\n", __func__, model_path.c_str());
|
||||
return;
|
||||
@@ -2711,7 +2708,6 @@ common_speculative * common_speculative_init(common_params_speculative & params,
|
||||
|
||||
common_speculative_ptr result(new common_speculative {
|
||||
/* .dparams = */ common_speculative_draft_params_vec(n_seq),
|
||||
/* .ctx_tgt = */ params.draft.ctx_tgt,
|
||||
/* .impls = */ std::move(impls),
|
||||
/* .impl_last = */ std::vector<common_speculative_impl *>(n_seq, nullptr),
|
||||
/* .synth_probs = */ {},
|
||||
@@ -2774,17 +2770,6 @@ void common_speculative_begin(common_speculative * spec, llama_seq_id seq_id, co
|
||||
}
|
||||
}
|
||||
|
||||
bool common_speculative_process(common_speculative * spec, const llama_batch & batch) {
|
||||
if (spec == nullptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ngram-only setups have no target context, they do not read the batch anyway
|
||||
const common_batch tmp = spec->ctx_tgt ? common_batch_from_llama_batch(spec->ctx_tgt, batch) : common_batch();
|
||||
|
||||
return common_speculative_process(spec, tmp);
|
||||
}
|
||||
|
||||
bool common_speculative_process(common_speculative * spec, const common_batch & batch) {
|
||||
bool result = true;
|
||||
|
||||
|
||||
@@ -79,9 +79,6 @@ void common_speculative_begin(common_speculative * spec, llama_seq_id seq_id, co
|
||||
// process the batch and update the internal state of the speculative context
|
||||
bool common_speculative_process(common_speculative * spec, const common_batch & batch);
|
||||
|
||||
// legacy llama_batch input, converted with common_batch_from_llama_batch()
|
||||
bool common_speculative_process(common_speculative * spec, const llama_batch & batch);
|
||||
|
||||
// generate drafts for the sequences specified with `common_speculative_get_draft_params`
|
||||
void common_speculative_draft(common_speculative * spec);
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"Glm4MoeLiteForCausalLM": "glm",
|
||||
"Glm4vForConditionalGeneration": "glm",
|
||||
"Glm4vMoeForConditionalGeneration": "glm",
|
||||
"Glm5NextForConditionalGeneration": "glm",
|
||||
"GlmForCausalLM": "chatglm",
|
||||
"GlmMoeDsaForCausalLM": "glm",
|
||||
"GlmOcrForConditionalGeneration": "glm",
|
||||
@@ -305,6 +306,7 @@ MMPROJ_MODEL_MAP: dict[str, str] = {
|
||||
"Glm4vForConditionalGeneration": "qwen3vl",
|
||||
"BailingMoeV3VLForConditionalGeneration": "bailingmoe3",
|
||||
"Glm4vMoeForConditionalGeneration": "qwen3vl",
|
||||
"Glm5NextForConditionalGeneration": "qwen3vl",
|
||||
"Glm5vForConditionalGeneration": "kimivl",
|
||||
"GlmOcrForConditionalGeneration": "qwen3vl",
|
||||
"GlmasrModel": "ultravox",
|
||||
|
||||
+12
-1
@@ -234,7 +234,7 @@ class ModelBase:
|
||||
|
||||
prefix = "model" if not self.is_mistral_format else "consolidated"
|
||||
part_names: list[str] = ModelBase.get_model_part_names(self.dir_model, prefix, ".safetensors")
|
||||
is_safetensors: bool = len(part_names) > 0
|
||||
is_safetensors: bool = len(part_names) > 0 or (not self.is_mistral_format and (self.dir_model / "model.safetensors.index.json").is_file())
|
||||
if not is_safetensors:
|
||||
part_names = ModelBase.get_model_part_names(self.dir_model, "pytorch_model", ".bin")
|
||||
|
||||
@@ -2326,6 +2326,12 @@ class TextModel(ModelBase):
|
||||
raise NotImplementedError("Only MEAN, CLS, and LAST pooling types supported")
|
||||
self.gguf_writer.add_pooling_type(pooling_type)
|
||||
|
||||
# pooling before a classification head (e.g. ModernBertForSequenceClassification)
|
||||
if (classifier_pooling := self.hparams.get("classifier_pooling")) is not None:
|
||||
if classifier_pooling not in ("cls", "mean"):
|
||||
raise NotImplementedError(f"Unsupported classifier_pooling: {classifier_pooling}")
|
||||
self.gguf_writer.add_classifier_pooling_type(mode_mapping[classifier_pooling])
|
||||
|
||||
def _set_vocab_glmedge(self):
|
||||
from transformers import AutoTokenizer
|
||||
tokenizer = AutoTokenizer.from_pretrained(self.dir_model)
|
||||
@@ -2560,6 +2566,11 @@ class TextModel(ModelBase):
|
||||
|
||||
self.gguf_writer.add_add_space_prefix(False)
|
||||
|
||||
if (add_bos := tokenizer_config.get("add_bos_token")) is not None:
|
||||
self.gguf_writer.add_add_bos_token(add_bos)
|
||||
if (add_eos := tokenizer_config.get("add_eos_token")) is not None:
|
||||
self.gguf_writer.add_add_eos_token(add_eos)
|
||||
|
||||
|
||||
class MmprojModel(ModelBase):
|
||||
model_type = ModelType.MMPROJ
|
||||
|
||||
@@ -402,3 +402,197 @@ class SolarOpenModel(Glm4MoeModel):
|
||||
special_vocab._set_special_token("unk", tokenizer.get_added_vocab()["<unk>"]) # ty: ignore[unresolved-attribute]
|
||||
special_vocab._set_special_token("bos", tokenizer.get_added_vocab()["<|startoftext|>"]) # ty: ignore[unresolved-attribute]
|
||||
special_vocab.add_to_gguf(self.gguf_writer)
|
||||
|
||||
|
||||
@ModelBase.register("Glm5NextForConditionalGeneration")
|
||||
@ModelBase.example("zai-org/GLM-5.3-Flash")
|
||||
class Glm5NextModel(TextModel):
|
||||
|
||||
model_arch = gguf.MODEL_ARCH.GLM5_NEXT
|
||||
supports_mtp_export = True
|
||||
|
||||
_experts: list[dict[str, Tensor]] | None = None
|
||||
_n_main_layers: int | None = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.n_nextn_layers = self.hparams.get("num_nextn_predict_layers", 0)
|
||||
self.skip_mtp = self.no_mtp or self.n_nextn_layers == 0
|
||||
|
||||
if not self.skip_mtp:
|
||||
self.block_count += self.n_nextn_layers
|
||||
self.tensor_map = gguf.get_tensor_name_map(self.model_arch, self.block_count)
|
||||
|
||||
self.hparams.pop("head_dim", None)
|
||||
|
||||
def set_vocab(self):
|
||||
# requires transformers >= 5, tokpre hash-resolves to glm4
|
||||
return self._set_vocab_glm()
|
||||
|
||||
def index_tensors(self, remote_hf_model_id: str | None = None):
|
||||
hp = self.hparams.get("text_config", self.hparams)
|
||||
type(self)._n_main_layers = hp["num_hidden_layers"]
|
||||
return super().index_tensors(remote_hf_model_id=remote_hf_model_id)
|
||||
|
||||
@classmethod
|
||||
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
|
||||
if (titem := super().filter_tensors(item)) is None:
|
||||
return None
|
||||
name, gen = titem
|
||||
|
||||
assert cls._n_main_layers is not None
|
||||
m = re.match(r"model\.layers\.(\d+)\.", name)
|
||||
is_mtp = m is not None and int(m.group(1)) >= cls._n_main_layers
|
||||
|
||||
if is_mtp and cls.no_mtp:
|
||||
return None
|
||||
if cls.mtp_only and not is_mtp and name not in (
|
||||
"model.embed_tokens.weight", "model.norm.weight", "lm_head.weight",
|
||||
):
|
||||
return None
|
||||
|
||||
return name, gen
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
super().set_gguf_parameters()
|
||||
hp = self.hparams
|
||||
|
||||
layer_types = hp["layer_types"]
|
||||
n_kv_heads = [0 if t == "linear_attention" else 1 for t in layer_types]
|
||||
assert len(n_kv_heads) == hp["num_hidden_layers"]
|
||||
# Pad to block_count
|
||||
n_kv_heads += [1] * (self.block_count - len(n_kv_heads))
|
||||
self.gguf_writer.add_head_count_kv(n_kv_heads)
|
||||
self.gguf_writer.add_vocab_size(hp["vocab_size"])
|
||||
self.gguf_writer.add_layer_norm_eps(1e-6)
|
||||
|
||||
if not self.skip_mtp:
|
||||
self.gguf_writer.add_nextn_predict_layers(self.n_nextn_layers)
|
||||
|
||||
# KDA
|
||||
lin = hp["linear_attn_config"]
|
||||
assert lin["num_heads"] == hp["num_attention_heads"]
|
||||
self.gguf_writer.add_ssm_conv_kernel(lin["short_conv_kernel_size"])
|
||||
self.gguf_writer.add_kda_head_dim(lin["head_dim"])
|
||||
if (lb := lin.get("gate_lower_bound")) is not None:
|
||||
self.gguf_writer.add_kda_gate_lower_bound(lb)
|
||||
|
||||
# MLA (nope only)
|
||||
assert hp.get("mla_use_nope") and hp["qk_rope_head_dim"] == 0, "expected nope-only MLA"
|
||||
kv_lora_rank = hp["kv_lora_rank"]
|
||||
qk_rope = hp["qk_rope_head_dim"]
|
||||
self.gguf_writer.add_q_lora_rank(hp["q_lora_rank"])
|
||||
self.gguf_writer.add_kv_lora_rank(kv_lora_rank)
|
||||
self.gguf_writer.add_rope_dimension_count(qk_rope)
|
||||
self.gguf_writer.add_key_length(kv_lora_rank + qk_rope)
|
||||
self.gguf_writer.add_value_length(kv_lora_rank)
|
||||
self.gguf_writer.add_key_length_mla(hp["qk_nope_head_dim"] + qk_rope)
|
||||
self.gguf_writer.add_value_length_mla(hp["v_head_dim"])
|
||||
|
||||
# DSA indexer with k-pool compression
|
||||
self.gguf_writer.add_indexer_head_count(hp["index_n_heads"])
|
||||
self.gguf_writer.add_indexer_key_length(hp["index_head_dim"])
|
||||
self.gguf_writer.add_indexer_top_k(hp["index_topk"])
|
||||
self.gguf_writer.add_indexer_kpool(hp["index_kpool"])
|
||||
self.gguf_writer.add_indexer_kpool_select_tail(hp.get("index_kpool_always_select_tail", True))
|
||||
if (indexer_types := hp.get("indexer_types")) is not None:
|
||||
self.gguf_writer.add_indexer_types([t == "full" for t in indexer_types])
|
||||
|
||||
# mHC
|
||||
assert hp.get("mhc", True)
|
||||
self.gguf_writer.add_hyper_connection_count(hp["hc_mult"])
|
||||
self.gguf_writer.add_hyper_connection_sinkhorn_iterations(hp["hc_sinkhorn_iters"])
|
||||
self.gguf_writer.add_hyper_connection_epsilon(hp["hc_eps"])
|
||||
|
||||
# MoE
|
||||
self.gguf_writer.add_leading_dense_block_count(hp["first_k_dense_replace"])
|
||||
self.gguf_writer.add_expert_feed_forward_length(hp["moe_intermediate_size"])
|
||||
self.gguf_writer.add_expert_shared_count(hp["n_shared_experts"])
|
||||
self.gguf_writer.add_expert_weights_scale(hp["routed_scaling_factor"])
|
||||
self.gguf_writer.add_expert_weights_norm(hp["norm_topk_prob"])
|
||||
if (limit := hp.get("swiglu_limit")) is not None:
|
||||
self.gguf_writer.add_swiglu_clamp_exp([limit] * self.block_count)
|
||||
self.gguf_writer.add_swiglu_clamp_shexp([limit] * self.block_count)
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
if name == "lm_head.weight" and self.hparams.get("tie_word_embeddings", False):
|
||||
return
|
||||
|
||||
# routed experts
|
||||
if ".mlp.experts." in name:
|
||||
n_experts = self.hparams["n_routed_experts"]
|
||||
assert bid is not None
|
||||
if self._experts is None:
|
||||
self._experts = [{} for _ in range(self.block_count)]
|
||||
self._experts[bid][name] = data_torch
|
||||
if len(self._experts[bid]) < n_experts * 3:
|
||||
return
|
||||
for w_name in ("down_proj", "gate_proj", "up_proj"):
|
||||
datas: list[Tensor] = []
|
||||
for xid in range(n_experts):
|
||||
ename = f"model.layers.{bid}.mlp.experts.{xid}.{w_name}.weight"
|
||||
datas.append(self._experts[bid].pop(ename))
|
||||
merged = f"model.layers.{bid}.mlp.experts.{w_name}.weight"
|
||||
yield from super().modify_tensors(torch.stack(datas, dim=0), merged, bid)
|
||||
return
|
||||
|
||||
# MLA absorption
|
||||
if name.endswith("kv_b_proj.weight"):
|
||||
n_head = self.hparams["num_attention_heads"]
|
||||
v_head_dim = self.hparams["v_head_dim"]
|
||||
qk_nope_head_dim = self.hparams["qk_nope_head_dim"]
|
||||
assert data_torch.shape[0] == n_head * (v_head_dim + qk_nope_head_dim)
|
||||
kv_b = data_torch.view(n_head, v_head_dim + qk_nope_head_dim, data_torch.shape[-1])
|
||||
k_b, v_b = torch.split(kv_b, [qk_nope_head_dim, v_head_dim], dim=1)
|
||||
yield from super().modify_tensors(k_b.transpose(1, 2), name.replace("kv_b_proj", "k_b_proj"), bid)
|
||||
yield from super().modify_tensors(v_b, name.replace("kv_b_proj", "v_b_proj"), bid)
|
||||
return
|
||||
|
||||
# KDA conv1d
|
||||
if name.endswith((".q_conv1d.weight", ".k_conv1d.weight", ".v_conv1d.weight")):
|
||||
if data_torch.ndim == 3:
|
||||
d_inner, _, d_conv = data_torch.shape
|
||||
elif data_torch.ndim == 2:
|
||||
d_inner, d_conv = data_torch.shape
|
||||
else:
|
||||
raise ValueError(f"unexpected conv1d rank {data_torch.ndim} for {name}")
|
||||
data_torch = data_torch.reshape(1, d_inner, 1, d_conv)
|
||||
|
||||
if name.endswith(".A_log"):
|
||||
n_head = self.hparams["num_attention_heads"]
|
||||
data_torch = -torch.exp(data_torch.float().flatten()[:n_head])
|
||||
|
||||
if name.endswith(".dt_bias"):
|
||||
name = name.rpartition(".dt_bias")[0] + ".dt_proj.bias"
|
||||
|
||||
if re.search(r"\.(hc_(?:attn|ffn)_(?:fn|base|scale)|index_kpool_compress_(?:ape|gate))$", name):
|
||||
yield self.map_tensor_name(name) + ".weight", data_torch
|
||||
return
|
||||
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
|
||||
def tensor_force_quant(self, name: str, new_name: str, bid: int | None, n_dims: int) -> gguf.GGMLQuantizationType | bool:
|
||||
# keep the small mHC / gating parameters exact
|
||||
exact_keys = ("hc_attn_", "hc_ffn_", "indexer_compressor_", "ssm_a", "ssm_dt", "exp_probs_b")
|
||||
if new_name.startswith(("blk.", "output_hc")) and any(k in new_name for k in exact_keys):
|
||||
return gguf.GGMLQuantizationType.F32
|
||||
return super().tensor_force_quant(name, new_name, bid, n_dims)
|
||||
|
||||
def prepare_metadata(self, vocab_only: bool):
|
||||
from_dir = self.fname_out.is_dir()
|
||||
super().prepare_metadata(vocab_only=vocab_only)
|
||||
if not self.mtp_only or not from_dir:
|
||||
return
|
||||
output_type: str = self.ftype.name.partition("_")[2]
|
||||
fname_default: str = gguf.naming_convention(
|
||||
self.metadata.name, self.metadata.basename, self.metadata.finetune,
|
||||
self.metadata.version, size_label=None, output_type=output_type, model_type=None)
|
||||
self.fname_out = self.fname_out.parent / f"mtp-{fname_default}.gguf"
|
||||
|
||||
def prepare_tensors(self):
|
||||
super().prepare_tensors()
|
||||
if self._experts is not None:
|
||||
leftover = [k for d in self._experts for k in d.keys()]
|
||||
if leftover:
|
||||
raise ValueError(f"Unprocessed experts: {leftover}")
|
||||
|
||||
@@ -469,6 +469,21 @@ class _LinearAttentionVReorderBase(Qwen3NextModel):
|
||||
shape = list(tensor.shape)
|
||||
if dim < 0:
|
||||
dim += len(shape)
|
||||
|
||||
# LoRA tensors (W ≈ B @ A) cannot reshape their row dimension.
|
||||
# Instead, build a permutation index and apply it to A (column reorder) or B (row reorder) directly.
|
||||
if hasattr(tensor, 'get_lora_A_B'):
|
||||
n = shape[dim]
|
||||
idx = torch.arange(n).reshape(num_k_heads, num_v_per_k, head_dim)
|
||||
idx = idx.permute(1, 0, 2).contiguous().reshape(n)
|
||||
lora_A, lora_B = tensor.get_lora_A_B() # ty: ignore[call-non-callable]
|
||||
if dim == len(shape) - 1:
|
||||
return type(tensor)(lora_A[:, idx], lora_B)
|
||||
elif dim == 0:
|
||||
return type(tensor)(lora_A, lora_B[idx])
|
||||
else:
|
||||
raise NotImplementedError(f"_reorder_v_heads on dim={dim} not supported for LoRA tensors")
|
||||
|
||||
new_shape = shape[:dim] + [num_k_heads, num_v_per_k, head_dim] + shape[dim + 1:]
|
||||
tensor = tensor.reshape(*new_shape)
|
||||
perm = list(range(len(new_shape)))
|
||||
@@ -686,6 +701,12 @@ class DFlashModel(Qwen3Model):
|
||||
super().set_gguf_parameters()
|
||||
|
||||
dflash_config = self.hparams.get("dflash_config", {})
|
||||
if (partial_rotary_factor := self.rope_parameters.get("partial_rotary_factor")) is not None:
|
||||
head_dim = self.hparams.get("head_dim") or self.hparams["hidden_size"] // self.hparams["num_attention_heads"]
|
||||
self.gguf_writer.add_rope_dimension_count(int(head_dim * partial_rotary_factor))
|
||||
if (value_scale := dflash_config.get("attention_value_scale")) is not None:
|
||||
self.gguf_writer.add_attn_value_scale(float(value_scale))
|
||||
|
||||
block_size = dflash_config.get("block_size", self.hparams.get("block_size", 16))
|
||||
self.gguf_writer.add_block_size(block_size)
|
||||
|
||||
@@ -708,6 +729,12 @@ class DFlashModel(Qwen3Model):
|
||||
embedding_scale = dflash_config.get(
|
||||
"input_embedding_scale", self.hparams.get("input_embedding_scale")
|
||||
)
|
||||
if embedding_scale is None and self.target_model_dir is not None:
|
||||
# the draft shares the target's token embeddings, and Gemma scales them by sqrt(hidden_size) in the forward pass
|
||||
target_hparams = ModelBase.load_hparams(self.target_model_dir, False)
|
||||
if get_model_architecture(target_hparams, ModelType.TEXT).startswith("Gemma"):
|
||||
target_hparams = {**target_hparams, **target_hparams.get("text_config", {})}
|
||||
embedding_scale = target_hparams["hidden_size"] ** 0.5
|
||||
if embedding_scale is not None:
|
||||
self.gguf_writer.add_embedding_scale(float(embedding_scale))
|
||||
|
||||
@@ -737,6 +764,62 @@ class DFlashModel(Qwen3Model):
|
||||
head_dim = self.hparams.get("head_dim") or self.hparams["hidden_size"] // self.hparams["num_attention_heads"]
|
||||
self.gguf_writer.add_rope_dimension_sections([head_dim // 2, 0, 0, 0])
|
||||
|
||||
def generate_extra_tensors(self) -> Iterable[tuple[str, Tensor]]:
|
||||
yield from super().generate_extra_tensors()
|
||||
|
||||
mask_path = self.dir_model / "mask_embedding.pt"
|
||||
if not mask_path.is_file():
|
||||
return
|
||||
|
||||
mask = torch.load(mask_path, map_location="cpu", weights_only=True)
|
||||
mask_id = self.hparams.get("dflash_config", {}).get("mask_token_id")
|
||||
if mask_id is None or mask["mask_token_id"] != mask_id:
|
||||
raise ValueError("mask_embedding.pt mask_token_id does not match dflash_config")
|
||||
if tuple(mask["embedding"].shape) != (self.hparams["hidden_size"],):
|
||||
raise ValueError("mask_embedding.pt has an unexpected embedding shape")
|
||||
if not 0 <= mask_id < self.hparams["vocab_size"]:
|
||||
raise ValueError("mask_embedding.pt mask_token_id is outside the vocabulary")
|
||||
|
||||
def target_tensor(name: str) -> Tensor:
|
||||
if self.target_model_dir is None:
|
||||
raise ValueError("mask_embedding.pt requires --target-model-dir with the target embeddings and output head")
|
||||
index_path = self.target_model_dir / "model.safetensors.index.json"
|
||||
if index_path.is_file():
|
||||
with open(index_path, encoding="utf-8") as f:
|
||||
weight_map = json.load(f)["weight_map"]
|
||||
part_names = [weight_map[name]]
|
||||
else:
|
||||
part_names = self.get_model_part_names(self.target_model_dir, "model", ".safetensors")
|
||||
|
||||
for part_name in part_names:
|
||||
with gguf.utility.SafetensorsLocal(self.target_model_dir / part_name) as part:
|
||||
if name in part:
|
||||
return LazyTorchTensor.from_local_tensor(part[name])
|
||||
raise ValueError(f"Target tensor {name!r} was not found in safetensors")
|
||||
|
||||
embedding_name = "model.embed_tokens.weight"
|
||||
if embedding_name in self.model_tensors:
|
||||
embeddings = self.model_tensors.pop(embedding_name)()
|
||||
else:
|
||||
embeddings = target_tensor(embedding_name)
|
||||
|
||||
if "model.lm_head.weight" not in self.model_tensors:
|
||||
if self.target_model_dir is None:
|
||||
raise ValueError("mask_embedding.pt requires --target-model-dir to obtain the output head")
|
||||
target_config = ModelBase.load_hparams(self.target_model_dir, False)
|
||||
target_config = {**target_config, **target_config.get("text_config", {})}
|
||||
head_name = embedding_name if target_config.get("tie_word_embeddings", False) else "lm_head.weight"
|
||||
# Keep the output head separate from the patched input embedding table.
|
||||
yield "model.lm_head.weight", target_tensor(head_name)
|
||||
|
||||
embeddings = LazyTorchTensor.to_eager(embeddings).clone()
|
||||
if tuple(embeddings.shape) != (self.hparams["vocab_size"], self.hparams["hidden_size"]):
|
||||
raise ValueError("Target token embedding shape does not match the DFlash draft")
|
||||
# MiMo's target mask row is untrained; the draft provides its own vector.
|
||||
embeddings[mask_id] = mask["embedding"].to(embeddings.dtype)
|
||||
self.hparams["has_embed_tokens"] = True
|
||||
yield embedding_name, embeddings
|
||||
|
||||
def _target_uses_mrope(self) -> bool:
|
||||
if self.target_model_dir is None:
|
||||
return False
|
||||
|
||||
+29
-1
@@ -228,10 +228,12 @@ class Qwen3ASRMmprojModel(Qwen3OmniMmprojModel):
|
||||
@ModelBase.register("Glm4vForConditionalGeneration", "Glm4vMoeForConditionalGeneration", "GlmOcrForConditionalGeneration")
|
||||
@ModelBase.example("zai-org/GLM-4.1V-9B-Thinking", "zai-org/GLM-4.5V")
|
||||
class Glm4VVisionModel(Qwen3VLVisionModel):
|
||||
projector_type = gguf.VisionProjectorType.GLM4V
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
MmprojModel.set_gguf_parameters(self) # skip Qwen3VLVisionModel parameters
|
||||
assert self.hparams_vision is not None
|
||||
self.gguf_writer.add_clip_projector_type(gguf.VisionProjectorType.GLM4V)
|
||||
self.gguf_writer.add_clip_projector_type(self.projector_type)
|
||||
|
||||
hidden_act = str(self.hparams_vision.get("hidden_act", "")).lower()
|
||||
if hidden_act == "gelu":
|
||||
@@ -249,6 +251,32 @@ class Glm4VVisionModel(Qwen3VLVisionModel):
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
|
||||
|
||||
@ModelBase.register("Glm5NextForConditionalGeneration")
|
||||
@ModelBase.example("zai-org/GLM-5.3-Flash")
|
||||
class Glm5NextVisionModel(Glm4VVisionModel):
|
||||
# GLM-5.3-Flash vision tower. glm4v layout with per-head qk-norm, no post-conv norm and no learned position embeddings.
|
||||
# Images are placed on a ceil aligned canvas with padding.
|
||||
|
||||
projector_type = gguf.VisionProjectorType.GLM5V
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
super().set_gguf_parameters()
|
||||
assert self.hparams_vision is not None
|
||||
self.gguf_writer.add_vision_spatial_merge_size(int(self.hparams_vision.get("spatial_merge_size", 2)))
|
||||
if (limit := self.hparams_vision.get("swiglu_limit")) is not None:
|
||||
self.gguf_writer.add_vision_swiglu_clamp(float(limit))
|
||||
|
||||
# image token budget from the processor, stored as single-frame pixel counts
|
||||
pc = self.preprocessor_config
|
||||
patch = int(pc.get("patch_size", 14))
|
||||
merge = int(pc.get("merge_size", 2))
|
||||
pixels_per_token = (patch * merge) ** 2
|
||||
if (min_tok := pc.get("min_image_tokens")) is not None:
|
||||
self.gguf_writer.add_vision_min_pixels(int(min_tok) * pixels_per_token)
|
||||
if (max_tok := pc.get("max_image_tokens")) is not None:
|
||||
self.gguf_writer.add_vision_max_pixels(int(max_tok) * pixels_per_token)
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3VLForConditionalGeneration")
|
||||
@ModelBase.example("Qwen/Qwen3-VL-4B-Instruct")
|
||||
class Qwen3VLTextModel(Qwen3Model):
|
||||
|
||||
+36
-4
@@ -25,15 +25,34 @@ class Qwen4ExpTextModel(_Qwen35MRopeMixin, _LinearAttentionVReorderBase):
|
||||
|
||||
model_arch = gguf.MODEL_ARCH.QWEN4EXP
|
||||
|
||||
# the MTP block is a separate draft head; vLLM drops it too
|
||||
supports_mtp_export = False
|
||||
no_mtp = True
|
||||
# the MTP head: one full-attention QSA block after the trunk, fed by the trunk's hc-wide residual
|
||||
supports_mtp_export = True
|
||||
|
||||
# MTP tensors the shared Qwen remapper does not know
|
||||
_MTP_EXTRA = {
|
||||
"fc_embedding": "nextn_fc_embedding",
|
||||
"fc_hidden": "nextn_fc_hidden",
|
||||
"hyper_connection_mixer": "nextn_hc_head",
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# only the shard names, so the table itself is never held
|
||||
self._ple_shards: dict[int, str] = {}
|
||||
self._ple_row_dim: int | None = None
|
||||
self._mtp_fc: dict[str, Tensor] = {}
|
||||
|
||||
@classmethod
|
||||
def filter_tensors(cls, item):
|
||||
name, gen = item
|
||||
part = name.split(".")[1] if name.startswith("mtp.") else None
|
||||
if part in cls._MTP_EXTRA:
|
||||
if cls.no_mtp:
|
||||
return None
|
||||
assert cls._original_block_count is not None
|
||||
rest = name.split(".", 2)[2]
|
||||
return f"model.layers.{cls._original_block_count}.{cls._MTP_EXTRA[part]}.{rest}", gen
|
||||
return super().filter_tensors(item)
|
||||
|
||||
def _read_hash_constants(self, suffix: str) -> list[int]:
|
||||
"""Read an int64 PLE constant straight from the checkpoint.
|
||||
@@ -63,14 +82,17 @@ class Qwen4ExpTextModel(_Qwen35MRopeMixin, _LinearAttentionVReorderBase):
|
||||
self.gguf_writer.add_indexer_top_k(hp["indexer_budget"])
|
||||
ratio = hp["indexer_compress_ratio"]
|
||||
layer_types = hp["layer_types"]
|
||||
# the MTP block is a full-attention QSA layer too
|
||||
self.gguf_writer.add_attention_compress_ratios(
|
||||
[ratio if layer_types[i] == "full_attention" else 0 for i in range(n_layer)]
|
||||
+ [ratio] * (self.block_count - n_layer)
|
||||
)
|
||||
|
||||
# ple_layer_ids is 1-based in the HF config; empty means no n-gram table,
|
||||
# so emit no PLE keys rather than optional ones
|
||||
# the MTP head never reads PLE, so an MTP-only file carries none of it
|
||||
ple_layers = [i - 1 for i in hp["ple_layer_ids"]]
|
||||
if not ple_layers:
|
||||
if not ple_layers or self.mtp_only:
|
||||
return
|
||||
self.gguf_writer.add_ple_layers(ple_layers)
|
||||
self.gguf_writer.add_ple_ngram_size(hp["ngram_size"])
|
||||
@@ -120,6 +142,14 @@ class Qwen4ExpTextModel(_Qwen35MRopeMixin, _LinearAttentionVReorderBase):
|
||||
if ".ngram_embedding.shard_" in name:
|
||||
return self._place_ple_shard(data_torch, name)
|
||||
|
||||
# eh_proj([e ; h_s]) = fc_embedding(e) + fc_hidden(h_s) for every hc stream s
|
||||
if name.endswith((".nextn_fc_embedding.weight", ".nextn_fc_hidden.weight")):
|
||||
self._mtp_fc[name.rsplit(".", 2)[1]] = data_torch
|
||||
if len(self._mtp_fc) < 2:
|
||||
return []
|
||||
eh = torch.cat([self._mtp_fc.pop("nextn_fc_embedding"), self._mtp_fc.pop("nextn_fc_hidden")], dim=1)
|
||||
return [(self.format_tensor_name(gguf.MODEL_TENSOR.NEXTN_EH_PROJ, bid, ".weight"), eh)]
|
||||
|
||||
# one projection feeds indexer q and k; split it, as minimax-m3 does
|
||||
if ".indexer.index_qk_proj.weight" in name:
|
||||
n_q = self.hparams["indexer_n_heads"] * self.hparams["indexer_head_dim"]
|
||||
@@ -182,6 +212,8 @@ class Qwen4ExpTextModel(_Qwen35MRopeMixin, _LinearAttentionVReorderBase):
|
||||
|
||||
def prepare_tensors(self):
|
||||
super().prepare_tensors()
|
||||
if self._mtp_fc:
|
||||
raise ValueError(f"MTP projection missing its other half: {sorted(self._mtp_fc)}")
|
||||
n_parts = self.hparams.get("split_ngram_parts", 0)
|
||||
if self._ple_shards and len(self._ple_shards) != n_parts:
|
||||
raise ValueError(
|
||||
|
||||
@@ -509,6 +509,7 @@ The following templates have active tests in `tests/test-chat.cpp`:
|
||||
| Kimi-K2 / Kimi-K2-Instruct | JSON_NATIVE | JSON tools with special markers |
|
||||
| Llama 3.1/3.2/3.3 | JSON_NATIVE | Standard Llama tool format |
|
||||
| OpenAI GPT-OSS | Specialized | Channel-based (dedicated handler) |
|
||||
| LLM-jp-4.1 | Specialized | GPT-OSS dialect (dedicated handler) |
|
||||
| Apriel 1.5 | JSON_NATIVE | `<tool_calls>` wrapper with JSON array |
|
||||
| Apriel 1.6 Thinker | Reasoning | Implicit reasoning start |
|
||||
| Mistral Small 3.2 | JSON_NATIVE | `[TOOL_CALLS]func[ARGS]{...}` with call ID |
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
# AMD AOCL-BLAS
|
||||
|
||||
> [!NOTE]
|
||||
> The [ZenDNN backend](ZenDNN.md) is the recommended path for inference on AMD CPUs. Refer to its documentation for the currently supported operations and data types. This page covers AOCL-BLAS as a vendor option for the generic `GGML_BLAS` backend.
|
||||
|
||||
AOCL-BLAS is AMD's BLAS library, optimized for AMD EPYC and Ryzen CPUs.
|
||||
llama.cpp can link against it through the existing BLAS backend (`GGML_BLAS`).
|
||||
|
||||
The BLAS backend can use AOCL-BLAS for eligible large prompt GEMMs and generally does not participate in token generation.
|
||||
F32 weights are passed to `cblas_sgemm` directly. Other types are converted to F32 first, so a quantized model can be slower than the native CPU kernels.
|
||||
See [BLAS Build](../build.md#blas-build).
|
||||
|
||||
AOCL download / install: https://www.amd.com/en/developer/aocl.html
|
||||
|
||||
Use the Quick start for a short command list. The later sections cover install layout, the single-threaded tree, threading, and checks.
|
||||
|
||||
### Quick start (MT, 64 threads)
|
||||
|
||||
If AOCL is not installed yet, follow [Prepare](#prepare) first. Adjust the `amd-libs.cfg` path to your install. CMake flags are set once. Source `amd-libs.cfg` again in every new shell before you launch, or the loader will not find AOCL-BLAS.
|
||||
|
||||
```bash
|
||||
source /opt/aocl/<version>/aocc/MT/amd-libs.cfg
|
||||
|
||||
cmake -B build \
|
||||
-DGGML_BLAS=ON \
|
||||
-DGGML_BLAS_VENDOR=AOCL_mt \
|
||||
-DBLAS_INCLUDE_DIRS="${AOCL_ROOT}/include" \
|
||||
-DGGML_NATIVE=ON
|
||||
cmake --build build --config Release
|
||||
|
||||
source /opt/aocl/<version>/aocc/MT/amd-libs.cfg
|
||||
./build/bin/llama-cli -m model.gguf -t 64
|
||||
```
|
||||
|
||||
`-t 64` is the thread count to pass on each launch (`--threads 64` is the same flag). Details, the single-threaded tree, and NUMA binding are below.
|
||||
|
||||
CMake vendor names `AOCL` and `AOCL_mt` are recognized by [FindBLAS](https://cmake.org/cmake/help/latest/module/FindBLAS.html#blas-lapack-vendors) (CMake 3.27+).
|
||||
When either vendor is selected, llama.cpp enables the BLIS code path (`GGML_BLAS_USE_BLIS`): it includes `blis.h` and calls `bli_thread_set_num_threads()` before GEMM. The same vendors also set `GGML_BLAS_USE_AOCL`, which only changes the device description to `AOCL-BLAS`. Upstream BLIS (`FLAME`) sets `GGML_BLAS_USE_BLIS` alone, so its description stays `BLIS`.
|
||||
|
||||
### Prepare
|
||||
|
||||
1. Install AOCL from AMD (package or tarball). Current releases ship **ST** (single-threaded) and **MT** (multi-threaded) libraries in separate folders. The default `AOCL_ROOT` is the **MT** tree. A typical layout (replace `<version>` and `aocc` with your install):
|
||||
|
||||
```
|
||||
<aocl-prefix>/<version>/aocc/MT/
|
||||
<aocl-prefix>/<version>/aocc/ST/
|
||||
```
|
||||
|
||||
2. Source `amd-libs.cfg` from the tree you want. Current AOCL versions use this file (not a separate `aocl-env.sh`). Adjust the prefix, version, and compiler (`aocc` vs `gcc`) to match your install:
|
||||
|
||||
```bash
|
||||
# Multi-threaded (default AOCL_ROOT):
|
||||
source /opt/aocl/<version>/aocc/MT/amd-libs.cfg
|
||||
|
||||
# Single-threaded:
|
||||
# source /opt/aocl/<version>/aocc/ST/amd-libs.cfg
|
||||
```
|
||||
|
||||
This sets library and include paths so the linker can find AOCL-BLAS. Skipping it is a common cause of BLAS not found / unresolved symbol errors.
|
||||
|
||||
Optional, if your install provides an environment module:
|
||||
|
||||
```bash
|
||||
cd /opt/aocl/<version>/aocc/MT
|
||||
module load ./aocl-linux-aocc-<version>_module
|
||||
# module unload ./aocl-linux-aocc-<version>_module
|
||||
```
|
||||
|
||||
3. Prefer the **MT** libraries for llama.cpp. Use `-DGGML_BLAS_VENDOR=AOCL_mt` after sourcing the MT `amd-libs.cfg`. Use `-DGGML_BLAS_VENDOR=AOCL` if you sourced the ST tree instead.
|
||||
|
||||
### llama.cpp compilation
|
||||
|
||||
Requires **CMake 3.27 or newer** for `-DGGML_BLAS_VENDOR=AOCL` / `AOCL_mt`.
|
||||
|
||||
FindBLAS does not detect AOCL headers via pkg-config. After sourcing `amd-libs.cfg`, `AOCL_ROOT` is set and `$AOCL_ROOT/include` is a symlink to the active integer ABI (`include_LP64` by default). Pass that path to CMake:
|
||||
|
||||
```bash
|
||||
source /opt/aocl/<version>/aocc/MT/amd-libs.cfg # adjust path
|
||||
|
||||
cmake -B build \
|
||||
-DGGML_BLAS=ON \
|
||||
-DGGML_BLAS_VENDOR=AOCL_mt \
|
||||
-DBLAS_INCLUDE_DIRS="${AOCL_ROOT}/include" \
|
||||
-DGGML_NATIVE=ON
|
||||
|
||||
cmake --build build --config Release
|
||||
```
|
||||
|
||||
#### CMake older than 3.27
|
||||
|
||||
`AOCL` / `AOCL_mt` may be unknown to FindBLAS. After sourcing the AOCL env, you can try:
|
||||
|
||||
```bash
|
||||
cmake -B build \
|
||||
-DGGML_BLAS=ON \
|
||||
-DGGML_BLAS_VENDOR=Generic \
|
||||
-DBLAS_LIBRARIES="-lblis -lm" \
|
||||
-DBLAS_INCLUDE_DIRS="${AOCL_ROOT}/include" \
|
||||
-DGGML_NATIVE=ON
|
||||
```
|
||||
|
||||
Library names differ between AOCL packages (`blis`, `blis-mt`, etc.). Pass whatever your install provides.
|
||||
`GGML_BLAS_VENDOR=Generic` does not enable the BLIS header and thread path (`GGML_BLAS_USE_BLIS`). Upgrade CMake so `AOCL` or `AOCL_mt` is recognized.
|
||||
|
||||
### llama.cpp execution
|
||||
|
||||
`--threads` / `--threads-batch` are the thread budget for **every** backend that implements `set_n_threads` (CPU and BLAS).
|
||||
|
||||
On each large BLAS `MUL_MAT`, the backend calls `bli_thread_set_num_threads()` with that **same** value, so BLIS GEMM may use up to `--threads-batch` threads during prompt processing. Other ops stay on the CPU backend with the same limit. Token generation usually does not use BLAS.
|
||||
|
||||
`BLIS_NUM_THREADS` is **not** a reliable way to cap BLIS here: the per-GEMM `bli_thread_set_num_threads()` call overrides it. To use fewer cores, lower `--threads` and/or `--threads-batch`.
|
||||
|
||||
Thread scaling depends on the CPU, NUMA layout, model, and batch size. Benchmark the thread counts used for deployment. Nested OpenMP (ggml type conversion, then BLIS GEMM, both using OpenMP) can still oversubscribe even though those two steps are sequential.
|
||||
|
||||
On a multi-socket machine, bind the process to one NUMA node. To skip SMT, bind to that node's physical cores only (check `lscpu -e`; on many AMD layouts the first range is the physical cores and a higher range is the sibling threads):
|
||||
|
||||
```bash
|
||||
numactl --physcpubind=0-127 --membind=0 ./build/bin/llama-cli -m model.gguf
|
||||
```
|
||||
|
||||
Keep the sourced AOCL env (or `LD_LIBRARY_PATH`) set when running binaries, or dynamic linking to AOCL libs will fail. Source the same `amd-libs.cfg` you used at build time.
|
||||
|
||||
### Verify
|
||||
|
||||
- Configure output should show BLAS found, with libraries under the AOCL MT tree and includes at `$AOCL_ROOT/include`.
|
||||
- `ldd` on `llama-bench` should list that same AOCL-BLAS library; `blis-mt` or `blis`.
|
||||
- `--list-devices` prints the description `AOCL-BLAS` (`BLAS: AOCL-BLAS`). Upstream BLIS (`FLAME`) still prints `BLIS`.
|
||||
- `llama-bench` reports the backend as `BLAS` for this build and `CPU` for a build with `-DGGML_BLAS=OFF`.
|
||||
- `test-backend-ops -b BLAS` checks that BLAS GEMMs match the CPU reference.
|
||||
|
||||
### Notes
|
||||
|
||||
- Optional `-march=znver3` / `znver4` / `znver5` (or similar) can be passed via `CMAKE_C_FLAGS` / `CMAKE_CXX_FLAGS` for a known CPU, but `-DGGML_NATIVE=ON` is usually enough and is safer across Ryzen / EPYC generations.
|
||||
- For building AOCL-BLAS (AMD's BLIS fork) from source instead of AOCL packages, see https://github.com/amd/blis
|
||||
|
||||
### Reference
|
||||
|
||||
1. https://www.amd.com/en/developer/aocl.html
|
||||
2. https://cmake.org/cmake/help/latest/module/FindBLAS.html#blas-lapack-vendors
|
||||
3. https://github.com/amd/blis
|
||||
@@ -116,6 +116,20 @@ This provides BLAS acceleration using only the CPU. Make sure to have OpenBLAS i
|
||||
|
||||
Check [BLIS.md](./backend/BLIS.md) for more information.
|
||||
|
||||
### AMD AOCL-BLAS
|
||||
|
||||
For AMD CPU inference, the [ZenDNN backend](#zendnn) is recommended. AOCL-BLAS is also available as a vendor option for the generic `GGML_BLAS` backend.
|
||||
|
||||
Source `amd-libs.cfg` from your AOCL install (MT tree by default), then build (CMake 3.27+ recommended for the `AOCL` / `AOCL_mt` vendors):
|
||||
|
||||
```bash
|
||||
source /opt/aocl/<version>/aocc/MT/amd-libs.cfg # adjust path; ST tree uses .../ST/amd-libs.cfg
|
||||
cmake -B build -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=AOCL_mt -DBLAS_INCLUDE_DIRS="${AOCL_ROOT}/include" -DGGML_NATIVE=ON
|
||||
cmake --build build --config Release
|
||||
```
|
||||
|
||||
Full steps, threading notes, and a fallback for older CMake: [AOCL.md](./backend/AOCL.md).
|
||||
|
||||
### Intel oneMKL
|
||||
|
||||
Building through oneAPI compilers will make avx_vnni instruction set available for intel processors that do not support avx512 and avx512_vnni. Please note that this build config **does not support Intel GPU**. For Intel GPU support, please refer to [llama.cpp for SYCL](./backend/SYCL.md).
|
||||
@@ -181,6 +195,8 @@ cmake -B build -DGGML_CUDA=ON
|
||||
cmake --build build --config Release
|
||||
```
|
||||
|
||||
To use a specific CCCL version instead of the one bundled with the installed CUDA Toolkit, add `-DGGML_CUDA_CCCL_VERSION=vMAJOR.MINOR.PATCH`. CUB DeviceTopK requires CCCL 3.4.3 or newer; older versions use the sort fallback.
|
||||
|
||||
Note that this also builds the CPU backend by default. On Windows on ARM, MSVC's
|
||||
support for the ARM NEON intrinsics used by the CPU backend may be incomplete, so
|
||||
a CUDA build produced entirely with MSVC might have a slower CPU backend. If CPU
|
||||
|
||||
@@ -16,6 +16,7 @@ Function calling is supported for all models (see https://github.com/ggml-org/ll
|
||||
- Firefunction v2
|
||||
- Command R7B
|
||||
- DeepSeek R1 (WIP / seems reluctant to call any tools?)
|
||||
- GPT-OSS (Harmony), LLM-jp-4.1 (Harmony dialect)
|
||||
|
||||
- Generic tool call is supported when the template isn't recognized by native format handlers (you'll see `Chat format: Generic` in the logs).
|
||||
- Use `--chat-template-file` to override the template when appropriate (see examples below)
|
||||
|
||||
+13
-13
@@ -17,17 +17,17 @@ Legend:
|
||||
| ABS | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| ACC | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| ADD | ❌ | ✅ | ✅ | ✅ | 🟡 | 🟡 | 🟡 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| ADD1 | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| ADD1 | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| ADD_ID | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| ARANGE | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| ARGMAX | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| ARGSORT | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| CEIL | ❌ | ❌ | ✅ | 🟡 | 🟡 | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| CLAMP | ❌ | ✅ | ✅ | ✅ | 🟡 | ✅ | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| COL2IM_1D | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| COL2IM_1D | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| CONCAT | ❌ | ✅ | ✅ | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | 🟡 | ❌ | ❌ |
|
||||
| CONT | ❌ | 🟡 | ✅ | ✅ | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | 🟡 | ❌ | ❌ |
|
||||
| CONV_2D | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | 🟡 | ✅ | ❌ | ❌ |
|
||||
| CONV_2D | ❌ | ❌ | 🟡 | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | 🟡 | ✅ | ❌ | ❌ |
|
||||
| CONV_2D_DW | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| CONV_3D | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| CONV_TRANSPOSE_1D | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
@@ -41,9 +41,9 @@ Legend:
|
||||
| DIAG | ❌ | ❌ | ✅ | ✅ | 🟡 | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| DIAG_MASK_INF | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | 🟡 | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| DIV | ❌ | ✅ | ✅ | ✅ | ❌ | 🟡 | 🟡 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| DSV4_HC_COMB | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_POST | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_PRE | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_COMB | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_POST | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_PRE | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DUP | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | 🟡 | 🟡 | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| ELU | ❌ | ✅ | ✅ | 🟡 | 🟡 | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| EXP | ❌ | ✅ | ✅ | 🟡 | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
@@ -68,17 +68,17 @@ Legend:
|
||||
| IM2COL_3D | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| L2_NORM | ❌ | ✅ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | 🟡 | ❌ | ❌ |
|
||||
| LEAKY_RELU | ❌ | ✅ | ✅ | ✅ | ❌ | 🟡 | 🟡 | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| LIGHTNING_INDEXER | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| LIGHTNING_INDEXER | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| LOG | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| MEAN | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | 🟡 | ✅ | ❌ | ❌ | ❌ |
|
||||
| MUL | ❌ | ✅ | ✅ | ✅ | 🟡 | 🟡 | 🟡 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| MUL_MAT | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 |
|
||||
| MUL_MAT_HADAMARD | ❌ | ❌ | ❌ | ❌ | ✅ | 🟡 | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| MUL_MAT_HADAMARD | ❌ | ❌ | ✅ | ❌ | ✅ | 🟡 | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| MUL_MAT_ID | ❌ | 🟡 | ✅ | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | 🟡 | ❌ |
|
||||
| MUL_MAT_ID_W4A4 | ❌ | ❌ | ❌ | ❌ | ❌ | 🟡 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| MUL_MAT_ID_W4A8 | ❌ | ❌ | ❌ | ❌ | ❌ | 🟡 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| MUL_MAT_W4A4 | ❌ | ❌ | ❌ | ❌ | ❌ | 🟡 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| MUL_MAT_W4A8 | ❌ | ❌ | ❌ | ❌ | ❌ | 🟡 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| MUL_MAT_ID_W4A4 | ❌ | ❌ | ✅ | ❌ | ❌ | 🟡 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| MUL_MAT_ID_W4A8 | ❌ | ❌ | ✅ | ❌ | ❌ | 🟡 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| MUL_MAT_W4A4 | ❌ | ❌ | ✅ | ❌ | ❌ | 🟡 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| MUL_MAT_W4A8 | ❌ | ❌ | ✅ | ❌ | ❌ | 🟡 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| NEG | ❌ | ✅ | ✅ | 🟡 | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| NORM | ❌ | ✅ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ✅ | ✅ | ✅ | 🟡 | ❌ | ❌ |
|
||||
| OPT_STEP_ADAMW | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
@@ -121,7 +121,7 @@ Legend:
|
||||
| SUM | ❌ | 🟡 | ✅ | 🟡 | ❌ | 🟡 | 🟡 | ❌ | 🟡 | 🟡 | 🟡 | ❌ | ❌ |
|
||||
| SUM_ROWS | ❌ | ✅ | ✅ | 🟡 | ❌ | 🟡 | ✅ | 🟡 | 🟡 | ✅ | ✅ | ❌ | ❌ |
|
||||
| SWIGLU | ❌ | ✅ | ✅ | ✅ | 🟡 | 🟡 | 🟡 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| SWIGLU_CLAMP | ❌ | ❌ | ❌ | ❌ | ❌ | 🟡 | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| SWIGLU_CLAMP | ❌ | ❌ | ✅ | ❌ | ❌ | 🟡 | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| SWIGLU_OAI | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| TANH | ❌ | ✅ | ✅ | 🟡 | 🟡 | 🟡 | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| TIMESTEP_EMBEDDING | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
|
||||
+15563
-8757
File diff suppressed because it is too large
Load Diff
@@ -117,7 +117,7 @@ int main(int argc, char ** argv) {
|
||||
|
||||
// create a llama_batch
|
||||
// we use this object to submit token data for decoding
|
||||
llama_batch batch = llama_batch_init(std::max(tokens_list.size(), (size_t) n_parallel), 0, n_parallel);
|
||||
common_batch batch(ctx);
|
||||
|
||||
std::vector<llama_seq_id> seq_ids(n_parallel, 0);
|
||||
for (int32_t i = 0; i < n_parallel; ++i) {
|
||||
@@ -126,12 +126,12 @@ int main(int argc, char ** argv) {
|
||||
|
||||
// evaluate the initial prompt
|
||||
for (size_t i = 0; i < tokens_list.size(); ++i) {
|
||||
common_batch_add(batch, tokens_list[i], i, seq_ids, false);
|
||||
batch.add(tokens_list[i], i, seq_ids, false);
|
||||
}
|
||||
GGML_ASSERT(batch.n_tokens == (int) tokens_list.size());
|
||||
GGML_ASSERT(batch.size() == (int) tokens_list.size());
|
||||
|
||||
if (llama_model_has_encoder(model)) {
|
||||
if (llama_encode(ctx, batch)) {
|
||||
if (llama_process(ctx, LLAMA_PROCESS_TYPE_ENCODE, batch.get())) {
|
||||
LOG_ERR("%s : failed to eval\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
@@ -141,14 +141,14 @@ int main(int argc, char ** argv) {
|
||||
decoder_start_token_id = llama_vocab_bos(vocab);
|
||||
}
|
||||
|
||||
common_batch_clear(batch);
|
||||
common_batch_add(batch, decoder_start_token_id, 0, seq_ids, false);
|
||||
batch.clear();
|
||||
batch.add(decoder_start_token_id, 0, seq_ids, false);
|
||||
}
|
||||
|
||||
// llama_decode will output logits only for the last token of the prompt
|
||||
batch.logits[batch.n_tokens - 1] = true;
|
||||
batch.set_output(batch.size() - 1, true);
|
||||
|
||||
if (llama_decode(ctx, batch) != 0) {
|
||||
if (llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get()) != 0) {
|
||||
LOG_ERR("%s: llama_decode() failed\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
@@ -170,16 +170,16 @@ int main(int argc, char ** argv) {
|
||||
|
||||
// remember the batch index of the last token for each parallel sequence
|
||||
// we need this to determine which logits to sample from
|
||||
std::vector<int32_t> i_batch(n_parallel, batch.n_tokens - 1);
|
||||
std::vector<int32_t> i_batch(n_parallel, batch.size() - 1);
|
||||
|
||||
int n_cur = batch.n_tokens;
|
||||
int n_cur = batch.size();
|
||||
int n_decode = 0;
|
||||
|
||||
const auto t_main_start = ggml_time_us();
|
||||
|
||||
while (n_cur <= n_predict) {
|
||||
// prepare the next batch
|
||||
common_batch_clear(batch);
|
||||
batch.clear();
|
||||
|
||||
// sample the next token for each parallel sequence / stream
|
||||
for (int32_t i = 0; i < n_parallel; ++i) {
|
||||
@@ -208,23 +208,23 @@ int main(int argc, char ** argv) {
|
||||
|
||||
streams[i] += common_token_to_piece(ctx, new_token_id);
|
||||
|
||||
i_batch[i] = batch.n_tokens;
|
||||
i_batch[i] = batch.size();
|
||||
|
||||
// push this new token for next evaluation
|
||||
common_batch_add(batch, new_token_id, n_cur, { i }, true);
|
||||
batch.add(new_token_id, n_cur, i, true);
|
||||
|
||||
n_decode += 1;
|
||||
}
|
||||
|
||||
// all streams are finished
|
||||
if (batch.n_tokens == 0) {
|
||||
if (batch.size() == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
n_cur += 1;
|
||||
|
||||
// evaluate the current batch with the transformer model
|
||||
if (llama_decode(ctx, batch)) {
|
||||
if (llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get())) {
|
||||
LOG_ERR("%s : failed to eval, return code %d\n", __func__, 1);
|
||||
return 1;
|
||||
}
|
||||
@@ -249,7 +249,6 @@ int main(int argc, char ** argv) {
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
llama_batch_free(batch);
|
||||
|
||||
for (auto & sampler_config : sampler_configs) {
|
||||
llama_sampler_free(sampler_config.sampler);
|
||||
|
||||
@@ -194,7 +194,8 @@ static bool run(llama_context * ctx, const common_params & params) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (llama_decode(ctx, llama_batch_get_one(tokens.data(), tokens.size()))) {
|
||||
common_batch batch = common_batch_get_one(ctx, tokens);
|
||||
if (llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get())) {
|
||||
LOG_ERR("%s : failed to eval\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "diffusion.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -144,8 +146,7 @@ void diffusion_generate(llama_context * ctx,
|
||||
|
||||
struct llama_sampler * dist_sampler = llama_sampler_init_dist(params.seed);
|
||||
|
||||
llama_batch batch = llama_batch_init(params.max_length, 0, 1);
|
||||
batch.n_tokens = params.max_length;
|
||||
common_batch batch(ctx);
|
||||
|
||||
// Pre-allocate buffers for CFG if needed
|
||||
int32_t logits_size = n_vocab * params.max_length;
|
||||
@@ -202,18 +203,15 @@ void diffusion_generate(llama_context * ctx,
|
||||
}
|
||||
|
||||
// Setup batch
|
||||
batch.clear();
|
||||
for (int32_t i = 0; i < params.max_length; i++) {
|
||||
batch.token[i] = output_tokens[i];
|
||||
batch.pos[i] = i;
|
||||
batch.n_seq_id[i] = 1;
|
||||
batch.seq_id[i][0] = 0;
|
||||
batch.logits[i] = 1;
|
||||
batch.add(output_tokens[i], i, 0, true);
|
||||
}
|
||||
|
||||
float * logits = nullptr;
|
||||
|
||||
if (params.cfg_scale > 0.0f) {
|
||||
int ret = llama_decode(ctx, batch);
|
||||
int ret = llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get());
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to generate conditional");
|
||||
break;
|
||||
@@ -227,10 +225,11 @@ void diffusion_generate(llama_context * ctx,
|
||||
un_x_buffer[i] = params.mask_token_id;
|
||||
}
|
||||
|
||||
batch.clear();
|
||||
for (int32_t i = 0; i < params.max_length; i++) {
|
||||
batch.token[i] = un_x_buffer[i];
|
||||
batch.add(un_x_buffer[i], i, 0, true);
|
||||
}
|
||||
ret = llama_decode(ctx, batch);
|
||||
ret = llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get());
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to generate unconditional");
|
||||
break;
|
||||
@@ -244,7 +243,7 @@ void diffusion_generate(llama_context * ctx,
|
||||
}
|
||||
logits = cond_logits_buffer.data();
|
||||
} else {
|
||||
int ret = llama_decode(ctx, batch);
|
||||
int ret = llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get());
|
||||
if (ret != 0) {
|
||||
LOG_ERR("%s: failed to decode at step %d, ret = %d\n", __func__, global_step, ret);
|
||||
break;
|
||||
@@ -400,7 +399,6 @@ void diffusion_generate(llama_context * ctx,
|
||||
total_time / 1000.0 / params.steps,
|
||||
total_sampling_time / 1000.0 / params.steps);
|
||||
|
||||
llama_batch_free(batch);
|
||||
llama_sampler_free(sampler);
|
||||
llama_sampler_free(dist_sampler);
|
||||
|
||||
|
||||
@@ -27,27 +27,27 @@ static std::vector<std::string> split_lines(const std::string & s, const std::st
|
||||
return lines;
|
||||
}
|
||||
|
||||
static void batch_add_seq(llama_batch & batch, const std::vector<int32_t> & tokens, llama_seq_id seq_id) {
|
||||
static void batch_add_seq(common_batch & batch, const std::vector<int32_t> & tokens, llama_seq_id seq_id) {
|
||||
size_t n_tokens = tokens.size();
|
||||
for (size_t i = 0; i < n_tokens; i++) {
|
||||
common_batch_add(batch, tokens[i], i, { seq_id }, true);
|
||||
batch.add(tokens[i], i, seq_id, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void batch_decode(llama_context * ctx, llama_batch & batch, float * output, int n_seq, int n_embd_out, int embd_norm) {
|
||||
static void batch_decode(llama_context * ctx, common_batch & batch, float * output, int n_seq, int n_embd_out, int embd_norm) {
|
||||
const enum llama_pooling_type pooling_type = llama_pooling_type(ctx);
|
||||
|
||||
// clear previous kv_cache values (irrelevant for embeddings)
|
||||
llama_memory_clear(llama_get_memory(ctx), true);
|
||||
|
||||
// run model
|
||||
LOG_INF("%s: n_tokens = %d, n_seq = %d\n", __func__, batch.n_tokens, n_seq);
|
||||
if (llama_decode(ctx, batch) < 0) {
|
||||
LOG_INF("%s: n_tokens = %d, n_seq = %d\n", __func__, batch.size(), n_seq);
|
||||
if (llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get()) < 0) {
|
||||
LOG_ERR("%s : failed to process\n", __func__);
|
||||
}
|
||||
|
||||
for (int i = 0; i < batch.n_tokens; i++) {
|
||||
if (!batch.logits[i]) {
|
||||
for (int i = 0; i < batch.size(); i++) {
|
||||
if (!batch.tokens[i].output) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -61,8 +61,8 @@ static void batch_decode(llama_context * ctx, llama_batch & batch, float * outpu
|
||||
GGML_ASSERT(embd != NULL && "failed to get token embeddings");
|
||||
} else {
|
||||
// try to get sequence embeddings - supported only when pooling_type is not NONE
|
||||
embd = llama_get_embeddings_seq(ctx, batch.seq_id[i][0]);
|
||||
embd_pos = batch.seq_id[i][0];
|
||||
embd = llama_get_embeddings_seq(ctx, batch.tokens[i].seq_id);
|
||||
embd_pos = batch.tokens[i].seq_id;
|
||||
GGML_ASSERT(embd != NULL && "failed to get sequence embeddings");
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ int main(int argc, char ** argv) {
|
||||
|
||||
// initialize batch
|
||||
const int n_prompts = prompts.size();
|
||||
struct llama_batch batch = llama_batch_init(n_batch, 0, 1);
|
||||
common_batch batch(ctx);
|
||||
|
||||
// count number of embeddings
|
||||
int n_embd_count = 0;
|
||||
@@ -269,12 +269,12 @@ int main(int argc, char ** argv) {
|
||||
const uint64_t n_toks = inp.size();
|
||||
|
||||
// encode if at capacity
|
||||
if (batch.n_tokens + n_toks > n_batch || s >= n_seq_max) {
|
||||
if (batch.size() + n_toks > n_batch || s >= n_seq_max) {
|
||||
float * out = emb + e * n_embd_out;
|
||||
batch_decode(ctx, batch, out, s, n_embd_out, params.embd_normalize);
|
||||
e += pooling_type == LLAMA_POOLING_TYPE_NONE ? batch.n_tokens : s;
|
||||
e += pooling_type == LLAMA_POOLING_TYPE_NONE ? batch.size() : s;
|
||||
s = 0;
|
||||
common_batch_clear(batch);
|
||||
batch.clear();
|
||||
}
|
||||
|
||||
// add to batch
|
||||
@@ -407,7 +407,6 @@ int main(int argc, char ** argv) {
|
||||
llama_perf_context_print(ctx);
|
||||
|
||||
// clean up
|
||||
llama_batch_free(batch);
|
||||
llama_backend_free();
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -26,7 +26,8 @@ static bool run(llama_context * ctx, const common_params & params) {
|
||||
LOG_INF(" %d\n", tokens[i]);
|
||||
}
|
||||
|
||||
if (llama_decode(ctx, llama_batch_get_one(tokens.data(), tokens.size()))) {
|
||||
common_batch batch = common_batch_get_one(ctx, tokens);
|
||||
if (llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get())) {
|
||||
LOG_ERR("%s : failed to eval\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -57,12 +57,13 @@ int main(int argc, char ** argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
llama_batch batch = llama_batch_get_one(prompt_tokens.data(), prompt_tokens.size());
|
||||
|
||||
const int n_iters = 3;
|
||||
|
||||
// warm-up
|
||||
llama_decode(ctx, batch);
|
||||
{
|
||||
common_batch batch = common_batch_get_one(ctx, prompt_tokens);
|
||||
llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get());
|
||||
}
|
||||
llama_memory_clear(llama_get_memory(ctx), true);
|
||||
llama_synchronize(ctx);
|
||||
|
||||
@@ -71,13 +72,16 @@ int main(int argc, char ** argv) {
|
||||
double t_sum2_us = 0.0;
|
||||
|
||||
for (int i = 0; i < n_iters; i++) {
|
||||
// positions continue from the memory
|
||||
common_batch batch = common_batch_get_one(ctx, prompt_tokens);
|
||||
|
||||
// this pause is important - it simulates "idle GPU"
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(t_pause_ms));
|
||||
|
||||
const int64_t t_start_us = llama_time_us();
|
||||
|
||||
// this should take constant time
|
||||
llama_decode(ctx, batch);
|
||||
llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get());
|
||||
llama_synchronize(ctx);
|
||||
|
||||
const int64_t t_end_us = llama_time_us();
|
||||
|
||||
@@ -35,7 +35,7 @@ constexpr float DEFAULT_SAMPLER_TEMP = 0.3f;
|
||||
|
||||
static llama_model * g_model;
|
||||
static llama_context * g_context;
|
||||
static llama_batch g_batch;
|
||||
static common_batch g_batch;
|
||||
static common_chat_templates_ptr g_chat_templates;
|
||||
static common_sampler * g_sampler;
|
||||
|
||||
@@ -116,7 +116,7 @@ Java_com_arm_aichat_internal_InferenceEngineImpl_prepare(JNIEnv * /*env*/, jobje
|
||||
auto *context = init_context(g_model);
|
||||
if (!context) { return 1; }
|
||||
g_context = context;
|
||||
g_batch = llama_batch_init(BATCH_SIZE, 0, 1);
|
||||
g_batch = common_batch(context);
|
||||
g_chat_templates = common_chat_templates_init(g_model, "");
|
||||
g_sampler = new_sampler(DEFAULT_SAMPLER_TEMP);
|
||||
return 0;
|
||||
@@ -164,18 +164,18 @@ Java_com_arm_aichat_internal_InferenceEngineImpl_benchModel(JNIEnv *env, jobject
|
||||
for (nri = 0; nri < nr; nri++) {
|
||||
LOGi("Benchmark prompt processing (pp = %d)", pp);
|
||||
|
||||
common_batch_clear(g_batch);
|
||||
common_batch batch(context);
|
||||
|
||||
const int n_tokens = pp;
|
||||
for (i = 0; i < n_tokens; i++) {
|
||||
common_batch_add(g_batch, 0, i, {0}, false);
|
||||
batch.add(0, i, 0, false);
|
||||
}
|
||||
|
||||
g_batch.logits[g_batch.n_tokens - 1] = true;
|
||||
batch.set_output(batch.size() - 1, true);
|
||||
llama_memory_clear(llama_get_memory(context), false);
|
||||
|
||||
const auto t_pp_start = ggml_time_us();
|
||||
if (llama_decode(context, g_batch) != 0) {
|
||||
if (llama_process(context, LLAMA_PROCESS_TYPE_DECODE, batch.get()) != 0) {
|
||||
LOGe("llama_decode() failed during prompt processing");
|
||||
}
|
||||
const auto t_pp_end = ggml_time_us();
|
||||
@@ -187,12 +187,12 @@ Java_com_arm_aichat_internal_InferenceEngineImpl_benchModel(JNIEnv *env, jobject
|
||||
llama_memory_clear(llama_get_memory(context), false);
|
||||
const auto t_tg_start = ggml_time_us();
|
||||
for (i = 0; i < tg; i++) {
|
||||
common_batch_clear(g_batch);
|
||||
batch.clear();
|
||||
for (j = 0; j < pl; j++) {
|
||||
common_batch_add(g_batch, 0, i, {j}, true);
|
||||
batch.add(0, i, j, true);
|
||||
}
|
||||
|
||||
if (llama_decode(context, g_batch) != 0) {
|
||||
if (llama_process(context, LLAMA_PROCESS_TYPE_DECODE, batch.get()) != 0) {
|
||||
LOGe("llama_decode() failed during text generation");
|
||||
}
|
||||
}
|
||||
@@ -315,7 +315,7 @@ static void reset_short_term_states() {
|
||||
|
||||
static int decode_tokens_in_batches(
|
||||
llama_context *context,
|
||||
llama_batch &batch,
|
||||
common_batch &batch,
|
||||
const llama_tokens &tokens,
|
||||
const llama_pos start_pos,
|
||||
const bool compute_last_logit = false) {
|
||||
@@ -323,7 +323,7 @@ static int decode_tokens_in_batches(
|
||||
LOGd("%s: Decode %d tokens starting at position %d", __func__, (int) tokens.size(), start_pos);
|
||||
for (int i = 0; i < (int) tokens.size(); i += BATCH_SIZE) {
|
||||
const int cur_batch_size = std::min((int) tokens.size() - i, BATCH_SIZE);
|
||||
common_batch_clear(batch);
|
||||
batch.clear();
|
||||
LOGv("%s: Preparing a batch size of %d starting at: %d", __func__, cur_batch_size, i);
|
||||
|
||||
// Shift context if current batch cannot fit into the context
|
||||
@@ -337,11 +337,11 @@ static int decode_tokens_in_batches(
|
||||
const llama_token token_id = tokens[i + j];
|
||||
const llama_pos position = start_pos + i + j;
|
||||
const bool want_logit = compute_last_logit && (i + j == tokens.size() - 1);
|
||||
common_batch_add(batch, token_id, position, {0}, want_logit);
|
||||
batch.add(token_id, position, 0, want_logit);
|
||||
}
|
||||
|
||||
// Decode this batch
|
||||
const int decode_result = llama_decode(context, batch);
|
||||
const int decode_result = llama_process(context, LLAMA_PROCESS_TYPE_DECODE, batch.get());
|
||||
if (decode_result) {
|
||||
LOGe("%s: llama_decode failed w/ %d", __func__, decode_result);
|
||||
return 1;
|
||||
@@ -506,9 +506,9 @@ Java_com_arm_aichat_internal_InferenceEngineImpl_generateNextToken(
|
||||
common_sampler_accept(g_sampler, new_token_id, true);
|
||||
|
||||
// Populate the batch with new token, then decode
|
||||
common_batch_clear(g_batch);
|
||||
common_batch_add(g_batch, new_token_id, current_position, {0}, true);
|
||||
if (llama_decode(g_context, g_batch) != 0) {
|
||||
g_batch.clear();
|
||||
g_batch.add(new_token_id, current_position, 0, true);
|
||||
if (llama_process(g_context, LLAMA_PROCESS_TYPE_DECODE, g_batch.get()) != 0) {
|
||||
LOGe("%s: llama_decode() failed for generated token", __func__);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -553,7 +553,7 @@ Java_com_arm_aichat_internal_InferenceEngineImpl_unload(JNIEnv * /*unused*/, job
|
||||
// Free up resources
|
||||
common_sampler_free(g_sampler);
|
||||
g_chat_templates.reset();
|
||||
llama_batch_free(g_batch);
|
||||
g_batch = common_batch();
|
||||
llama_free(g_context);
|
||||
llama_model_free(g_model);
|
||||
}
|
||||
|
||||
@@ -101,8 +101,13 @@ int main(int argc, char ** argv) {
|
||||
const auto t_enc_start = ggml_time_us();
|
||||
|
||||
// eval the prompt
|
||||
llama_decode(ctx, llama_batch_get_one( inp.data(), n_input - 1));
|
||||
llama_decode(ctx, llama_batch_get_one(&inp.back(), 1));
|
||||
{
|
||||
common_batch batch = common_batch_get_one(ctx, inp.data(), n_input - 1);
|
||||
llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get());
|
||||
|
||||
batch = common_batch_get_one(ctx, &inp.back(), 1);
|
||||
llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get());
|
||||
}
|
||||
|
||||
for (int s = 1; s < W + G + 1; ++s) {
|
||||
llama_memory_seq_cp(mem, 0, s, -1, -1);
|
||||
@@ -124,7 +129,7 @@ int main(int argc, char ** argv) {
|
||||
// seq_id == 0 : the current input token
|
||||
// seq_id [1, W] : tokens from the past N - 1 Jacobi iterations
|
||||
// seq_id [W + 1, W + G] : verification n-grams
|
||||
llama_batch batch = llama_batch_init(llama_n_ctx(ctx), 0, W + G + 1);
|
||||
common_batch batch(ctx);
|
||||
|
||||
// target model sampling context
|
||||
struct common_sampler * smpl = common_sampler_init(model, params.sampling);
|
||||
@@ -204,10 +209,10 @@ int main(int argc, char ** argv) {
|
||||
// V V V V V V
|
||||
// id
|
||||
{
|
||||
common_batch_clear(batch);
|
||||
batch.clear();
|
||||
|
||||
// current token - first token of the first level
|
||||
common_batch_add(batch, id, n_past, seq_id_all, true);
|
||||
batch.add(id, n_past, seq_id_all, true);
|
||||
|
||||
// verification n-grams - queue this before the lookahead tokens for less KV cache fragmentation
|
||||
{
|
||||
@@ -230,9 +235,9 @@ int main(int argc, char ** argv) {
|
||||
const llama_token t = ngrams_observed.tokens[idx + j];
|
||||
|
||||
ngrams_cur[g].tokens [j + 1] = t;
|
||||
ngrams_cur[g].i_batch[j + 1] = batch.n_tokens;
|
||||
ngrams_cur[g].i_batch[j + 1] = batch.size();
|
||||
|
||||
common_batch_add(batch, t, n_past + j + 1, { W + 1 + g }, true);
|
||||
batch.add(t, n_past + j + 1, W + 1 + g, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -244,18 +249,18 @@ int main(int argc, char ** argv) {
|
||||
seq_id_look[j] = i + j + 1;
|
||||
}
|
||||
|
||||
common_batch_add(batch, tokens_j[0][i], n_past + i, seq_id_look, false);
|
||||
batch.add(tokens_j[0][i], n_past + i, seq_id_look, false);
|
||||
}
|
||||
|
||||
// fill the rest of the levels
|
||||
for (int j = 1; j < N - 1; j++) {
|
||||
for (int i = 0; i < W; i++) {
|
||||
common_batch_add(batch, tokens_j[j][i], n_past + j + i, { i + 1 }, j == N - 2);
|
||||
batch.add(tokens_j[j][i], n_past + j + i, i + 1, j == N - 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (llama_decode(ctx, batch) != 0) {
|
||||
if (llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get()) != 0) {
|
||||
LOG_ERR("\n\n%s: llama_decode failed - increase KV cache size\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
@@ -473,7 +478,6 @@ int main(int argc, char ** argv) {
|
||||
|
||||
common_sampler_free(smpl);
|
||||
|
||||
llama_batch_free(batch);
|
||||
|
||||
llama_backend_free();
|
||||
|
||||
|
||||
@@ -98,8 +98,13 @@ int main(int argc, char ** argv){
|
||||
|
||||
const auto t_enc_start = ggml_time_us();
|
||||
|
||||
llama_decode(ctx, llama_batch_get_one( inp.data(), n_input - 1));
|
||||
llama_decode(ctx, llama_batch_get_one(&inp.back(), 1));
|
||||
{
|
||||
common_batch batch = common_batch_get_one(ctx, inp.data(), n_input - 1);
|
||||
llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get());
|
||||
|
||||
batch = common_batch_get_one(ctx, &inp.back(), 1);
|
||||
llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get());
|
||||
}
|
||||
|
||||
const auto t_enc_end = ggml_time_us();
|
||||
|
||||
@@ -115,7 +120,7 @@ int main(int argc, char ** argv){
|
||||
|
||||
std::vector<llama_token> draft;
|
||||
|
||||
llama_batch batch_tgt = llama_batch_init(llama_n_ctx(ctx), 0, 1);
|
||||
common_batch batch_tgt(ctx);
|
||||
|
||||
const auto t_dec_start = ggml_time_us();
|
||||
|
||||
@@ -192,8 +197,8 @@ int main(int argc, char ** argv){
|
||||
// clean the cache of draft tokens that weren't accepted
|
||||
llama_memory_seq_rm(llama_get_memory(ctx), 0, n_past, -1);
|
||||
|
||||
common_batch_clear(batch_tgt);
|
||||
common_batch_add(batch_tgt, draft[0], n_past, { 0 }, true);
|
||||
batch_tgt.clear();
|
||||
batch_tgt.add(draft[0], n_past, 0, true);
|
||||
|
||||
// Draft already contains a single token sampled from the model:
|
||||
GGML_ASSERT(draft.size() == 1);
|
||||
@@ -203,13 +208,13 @@ int main(int argc, char ** argv){
|
||||
common_ngram_cache_draft(inp, draft, n_draft, LLAMA_NGRAM_MIN, LLAMA_NGRAM_MAX, ngram_cache_context, ngram_cache_dynamic, ngram_cache_static);
|
||||
|
||||
for (size_t i = 1; i < draft.size(); ++i) {
|
||||
common_batch_add(batch_tgt, draft[i], n_past + i, { 0 }, true);
|
||||
batch_tgt.add(draft[i], n_past + i, 0, true);
|
||||
}
|
||||
|
||||
t_draft_us += ggml_time_us() - t_start_draft_us;
|
||||
n_drafted += draft.size() - 1;
|
||||
|
||||
llama_decode(ctx, batch_tgt);
|
||||
llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch_tgt.get());
|
||||
++n_past;
|
||||
|
||||
draft.erase(draft.begin());
|
||||
@@ -241,7 +246,6 @@ int main(int argc, char ** argv){
|
||||
|
||||
common_sampler_free(smpl);
|
||||
|
||||
llama_batch_free(batch_tgt);
|
||||
|
||||
llama_backend_free();
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ def parse_arguments():
|
||||
parser.add_argument("--prompt-file", "-f", help="Optional prompt file", required=False)
|
||||
parser.add_argument("--verbose", "-v", action="store_true", help="Enable verbose debug output")
|
||||
parser.add_argument("--device", "-d", help="Device to use (cpu, cuda, mps, auto)", default="auto")
|
||||
parser.add_argument("--add-bos", action=argparse.BooleanOptionalAction, default=None,
|
||||
help="Override BOS token setting (default: use model's own setting)")
|
||||
return parser.parse_args()
|
||||
|
||||
def load_model_and_tokenizer(model_path, device="auto"):
|
||||
@@ -119,6 +121,9 @@ def main():
|
||||
|
||||
model, tokenizer, config = load_model_and_tokenizer(model_path, args.device)
|
||||
|
||||
if args.add_bos is not None and hasattr(tokenizer, "add_bos_token"):
|
||||
tokenizer.add_bos_token = args.add_bos
|
||||
|
||||
if args.verbose:
|
||||
enable_torch_debugging(model)
|
||||
|
||||
|
||||
@@ -224,8 +224,6 @@ int main(int argc, char ** argv) {
|
||||
|
||||
LOG_INF("\n\n");
|
||||
|
||||
const int n_ctx = llama_n_ctx(ctx);
|
||||
|
||||
if (sseed >= 0) {
|
||||
LOG_INF("%s: initializing all samplers with the same RNG seed: %d (use a negative seed to have different seeds)\n", __func__, sseed);
|
||||
} else {
|
||||
@@ -252,7 +250,7 @@ int main(int argc, char ** argv) {
|
||||
|
||||
// the max batch size is as large as the context to handle cases where we get very long input prompt from multiple
|
||||
// users. regardless of the size, the main loop will chunk the batch into a maximum of params.n_batch tokens at a time
|
||||
llama_batch batch = llama_batch_init(n_ctx, 0, 1);
|
||||
common_batch batch(ctx);
|
||||
|
||||
int32_t n_total_prompt = 0;
|
||||
int32_t n_total_gen = 0;
|
||||
@@ -268,10 +266,10 @@ int main(int argc, char ** argv) {
|
||||
LOG_INF("%s: Evaluating the system prompt ...\n", __func__);
|
||||
|
||||
for (int32_t i = 0; i < n_tokens_system; ++i) {
|
||||
common_batch_add(batch, tokens_system[i], i, { 0 }, false);
|
||||
batch.add(tokens_system[i], i, 0, false);
|
||||
}
|
||||
|
||||
if (llama_decode(ctx, batch) != 0) {
|
||||
if (llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get()) != 0) {
|
||||
LOG_ERR("%s: llama_decode() failed\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
@@ -287,7 +285,7 @@ int main(int argc, char ** argv) {
|
||||
LOG_INF("Processing requests ...\n\n");
|
||||
|
||||
while (true) {
|
||||
common_batch_clear(batch);
|
||||
batch.clear();
|
||||
|
||||
// decode any currently ongoing sequences
|
||||
for (auto & client : clients) {
|
||||
@@ -295,14 +293,14 @@ int main(int argc, char ** argv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
client.i_batch = batch.n_tokens;
|
||||
client.i_batch = batch.size();
|
||||
|
||||
common_batch_add(batch, client.sampled, client.n_past++, { client.id + 1 }, true);
|
||||
batch.add(client.sampled, client.n_past++, client.id + 1, true);
|
||||
|
||||
client.n_decoded += 1;
|
||||
}
|
||||
|
||||
if (batch.n_tokens == 0) {
|
||||
if (batch.size() == 0) {
|
||||
// all sequences have ended - clear the entire KV cache
|
||||
for (int i = 1; i <= n_clients; ++i) {
|
||||
llama_memory_seq_rm(mem, i, -1, -1);
|
||||
@@ -314,7 +312,7 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
|
||||
// insert new sequences for decoding
|
||||
if (cont_batching || batch.n_tokens == 0) {
|
||||
if (cont_batching || batch.size() == 0) {
|
||||
for (auto & client : clients) {
|
||||
if (client.seq_id == -1 && g_seq_id < n_seq) {
|
||||
client.seq_id = g_seq_id;
|
||||
@@ -350,17 +348,17 @@ int main(int argc, char ** argv) {
|
||||
tokens_prompt = common_tokenize(ctx, client.prompt, false);
|
||||
|
||||
for (size_t i = 0; i < tokens_prompt.size(); ++i) {
|
||||
common_batch_add(batch, tokens_prompt[i], client.n_past++, { client.id + 1 }, false);
|
||||
batch.add(tokens_prompt[i], client.n_past++, client.id + 1, false);
|
||||
}
|
||||
|
||||
// extract the logits only for the last token
|
||||
if (batch.n_tokens > 0) {
|
||||
batch.logits[batch.n_tokens - 1] = true;
|
||||
if (batch.size() > 0) {
|
||||
batch.set_output(batch.size() - 1, true);
|
||||
}
|
||||
|
||||
client.n_prompt = tokens_prompt.size();
|
||||
client.n_decoded = 0;
|
||||
client.i_batch = batch.n_tokens - 1;
|
||||
client.i_batch = batch.size() - 1;
|
||||
|
||||
LOG_INF("\033[31mClient %3d, seq %4d, junk = %4d, prompt = %d, started decoding ...\033[0m\n", client.id, client.seq_id, n_junk_cur, client.n_prompt);
|
||||
|
||||
@@ -374,7 +372,7 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
if (batch.n_tokens == 0) {
|
||||
if (batch.size() == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -383,27 +381,17 @@ int main(int argc, char ** argv) {
|
||||
|
||||
int32_t i_next = 0;
|
||||
|
||||
for (int32_t i = 0; i < batch.n_tokens; i = i_next) {
|
||||
for (int32_t i = 0; i < batch.size(); i = i_next) {
|
||||
// experiment: process in powers of 2
|
||||
//if (i + n_batch > (int32_t) batch.n_tokens && n_batch > 32) {
|
||||
//if (i + n_batch > (int32_t) batch.size() && n_batch > 32) {
|
||||
// n_batch /= 2;
|
||||
// i -= n_batch;
|
||||
// continue;
|
||||
//}
|
||||
|
||||
const int32_t n_tokens = std::min(n_batch, batch.n_tokens - i);
|
||||
const int32_t n_tokens = std::min(n_batch, batch.size() - i);
|
||||
|
||||
llama_batch batch_view = {
|
||||
n_tokens,
|
||||
batch.token + i,
|
||||
nullptr,
|
||||
batch.pos + i,
|
||||
batch.n_seq_id + i,
|
||||
batch.seq_id + i,
|
||||
batch.logits + i,
|
||||
};
|
||||
|
||||
const int ret = llama_decode(ctx, batch_view);
|
||||
const int ret = llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get_sub_batch(i, n_tokens));
|
||||
if (ret != 0) {
|
||||
if (n_batch == 1 || ret < 0) {
|
||||
// if you get here, it means the KV cache is full - try increasing it via the context size
|
||||
@@ -511,7 +499,6 @@ int main(int argc, char ** argv) {
|
||||
// TODO: print sampling/grammar timings for all clients
|
||||
llama_perf_context_print(ctx);
|
||||
|
||||
llama_batch_free(batch);
|
||||
|
||||
llama_backend_free();
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ int main(int argc, char ** argv) {
|
||||
LOG_INF("prompt tokens: %d\n", n_tokens_all);
|
||||
//LOG_INF("prompt: %s\n", params.prompt.c_str());
|
||||
|
||||
llama_batch batch = llama_batch_init(params.n_batch, 0, 1);
|
||||
common_batch batch(ctx);
|
||||
|
||||
int n_past = 0;
|
||||
|
||||
@@ -144,17 +144,17 @@ int main(int argc, char ** argv) {
|
||||
n_past = llama_memory_seq_pos_max(mem, 0) + 1;
|
||||
}
|
||||
|
||||
common_batch_clear(batch);
|
||||
batch.clear();
|
||||
|
||||
for (int j = 0; j < n_batch && i + j < n_tokens_all; j++) {
|
||||
common_batch_add(batch, tokens_list[i + j], n_past++, { 0 }, false);
|
||||
batch.add(tokens_list[i + j], n_past++, 0, false);
|
||||
}
|
||||
|
||||
if (i + n_batch >= n_tokens_all) {
|
||||
batch.logits[batch.n_tokens - 1] = true;
|
||||
batch.set_output(batch.size() - 1, true);
|
||||
}
|
||||
|
||||
if (llama_decode(ctx, batch) != 0) {
|
||||
if (llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get()) != 0) {
|
||||
LOG_INF("%s: llama_decode() failed\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
@@ -176,17 +176,17 @@ int main(int argc, char ** argv) {
|
||||
|
||||
n_past = llama_memory_seq_pos_max(mem, 0) + 1;
|
||||
|
||||
common_batch_clear(batch);
|
||||
batch.clear();
|
||||
|
||||
for (int j = 0; j < n_batch && i + j < n_tokens_all; j++) {
|
||||
common_batch_add(batch, tokens_list[i + j], n_past++, { 0 }, false);
|
||||
batch.add(tokens_list[i + j], n_past++, 0, false);
|
||||
}
|
||||
|
||||
if (i + n_batch >= n_tokens_all) {
|
||||
batch.logits[batch.n_tokens - 1] = true;
|
||||
batch.set_output(batch.size() - 1, true);
|
||||
}
|
||||
|
||||
if (llama_decode(ctx, batch) != 0) {
|
||||
if (llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get()) != 0) {
|
||||
LOG_ERR("%s: llama_decode() failed\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
@@ -223,7 +223,7 @@ int main(int argc, char ** argv) {
|
||||
while (n_cur <= n_len) {
|
||||
// sample the next token
|
||||
{
|
||||
const llama_token new_token_id = llama_sampler_sample(smpl, ctx, batch.n_tokens - 1);
|
||||
const llama_token new_token_id = llama_sampler_sample(smpl, ctx, batch.size() - 1);
|
||||
|
||||
// is it an end of generation?
|
||||
if (llama_vocab_is_eog(vocab, new_token_id) || n_cur == n_len) {
|
||||
@@ -237,16 +237,16 @@ int main(int argc, char ** argv) {
|
||||
n_decode += 1;
|
||||
|
||||
// prepare the next batch
|
||||
common_batch_clear(batch);
|
||||
batch.clear();
|
||||
|
||||
// push this new token for next evaluation
|
||||
common_batch_add(batch, new_token_id, n_past++, { 0 }, true);
|
||||
batch.add(new_token_id, n_past++, 0, true);
|
||||
}
|
||||
|
||||
n_cur += 1;
|
||||
|
||||
// evaluate the current batch with the transformer model
|
||||
if (llama_decode(ctx, batch)) {
|
||||
if (llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get())) {
|
||||
LOG_ERR("%s : failed to eval, return code %d\n", __func__, 1);
|
||||
return 1;
|
||||
}
|
||||
@@ -266,7 +266,6 @@ int main(int argc, char ** argv) {
|
||||
|
||||
llama_sampler_free(smpl);
|
||||
|
||||
llama_batch_free(batch);
|
||||
|
||||
llama_free(ctx);
|
||||
llama_model_free(model);
|
||||
|
||||
@@ -75,30 +75,30 @@ static std::vector<chunk> chunk_file(const std::string & filename, int chunk_siz
|
||||
return chunks;
|
||||
}
|
||||
|
||||
static void batch_add_seq(llama_batch & batch, const std::vector<int32_t> & tokens, llama_seq_id seq_id) {
|
||||
static void batch_add_seq(common_batch & batch, const std::vector<int32_t> & tokens, llama_seq_id seq_id) {
|
||||
size_t n_tokens = tokens.size();
|
||||
for (size_t i = 0; i < n_tokens; i++) {
|
||||
common_batch_add(batch, tokens[i], i, { seq_id }, true);
|
||||
batch.add(tokens[i], i, seq_id, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void batch_process(llama_context * ctx, llama_batch & batch, float * output, int n_seq, int n_embd) {
|
||||
static void batch_process(llama_context * ctx, common_batch & batch, float * output, int n_seq, int n_embd) {
|
||||
// clear previous kv_cache values (irrelevant for embeddings)
|
||||
llama_memory_clear(llama_get_memory(ctx), false);
|
||||
|
||||
// run model
|
||||
LOG_INF("%s: n_tokens = %d, n_seq = %d\n", __func__, batch.n_tokens, n_seq);
|
||||
if (llama_decode(ctx, batch) < 0) {
|
||||
LOG_INF("%s: n_tokens = %d, n_seq = %d\n", __func__, batch.size(), n_seq);
|
||||
if (llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch.get()) < 0) {
|
||||
LOG_ERR("%s : failed to process\n", __func__);
|
||||
}
|
||||
|
||||
for (int i = 0; i < batch.n_tokens; i++) {
|
||||
if (!batch.logits[i]) {
|
||||
for (int i = 0; i < batch.size(); i++) {
|
||||
if (!batch.tokens[i].output) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// try to get sequence embeddings - supported only when pooling_type is not NONE
|
||||
const float * embd = llama_get_embeddings_seq(ctx, batch.seq_id[i][0]);
|
||||
const float * embd = llama_get_embeddings_seq(ctx, batch.tokens[i].seq_id);
|
||||
if (embd == NULL) {
|
||||
embd = llama_get_embeddings_ith(ctx, i);
|
||||
if (embd == NULL) {
|
||||
@@ -107,7 +107,7 @@ static void batch_process(llama_context * ctx, llama_batch & batch, float * outp
|
||||
}
|
||||
}
|
||||
|
||||
float * out = output + batch.seq_id[i][0] * n_embd;
|
||||
float * out = output + batch.tokens[i].seq_id * n_embd;
|
||||
common_embd_normalize(embd, out, n_embd, 2);
|
||||
}
|
||||
}
|
||||
@@ -217,7 +217,7 @@ int main(int argc, char ** argv) {
|
||||
|
||||
// initialize batch
|
||||
const int n_chunks = chunks.size();
|
||||
struct llama_batch batch = llama_batch_init(n_batch, 0, 1);
|
||||
common_batch batch(ctx);
|
||||
|
||||
// allocate output
|
||||
const int n_embd_out = llama_model_n_embd_out(model);
|
||||
@@ -234,10 +234,10 @@ int main(int argc, char ** argv) {
|
||||
const uint64_t n_toks = inp.size();
|
||||
|
||||
// encode if at capacity
|
||||
if (batch.n_tokens + n_toks > n_batch || s >= llama_n_seq_max(ctx)) {
|
||||
if (batch.size() + n_toks > n_batch || s >= llama_n_seq_max(ctx)) {
|
||||
float * out = emb + p * n_embd_out;
|
||||
batch_process(ctx, batch, out, s, n_embd_out);
|
||||
common_batch_clear(batch);
|
||||
batch.clear();
|
||||
p += s;
|
||||
s = 0;
|
||||
}
|
||||
@@ -258,7 +258,7 @@ int main(int argc, char ** argv) {
|
||||
chunks[i].tokens.clear();
|
||||
}
|
||||
|
||||
struct llama_batch query_batch = llama_batch_init(n_batch, 0, 1);
|
||||
common_batch query_batch(ctx);
|
||||
|
||||
// start loop, receive query and return top k similar chunks based on cosine similarity
|
||||
std::string query;
|
||||
@@ -272,7 +272,7 @@ int main(int argc, char ** argv) {
|
||||
std::vector<float> query_emb(n_embd_out, 0);
|
||||
batch_process(ctx, query_batch, query_emb.data(), 1, n_embd_out);
|
||||
|
||||
common_batch_clear(query_batch);
|
||||
query_batch.clear();
|
||||
|
||||
// compute cosine similarities
|
||||
{
|
||||
@@ -302,6 +302,5 @@ int main(int argc, char ** argv) {
|
||||
llama_perf_context_print(ctx);
|
||||
|
||||
// clean up
|
||||
llama_batch_free(query_batch);
|
||||
llama_backend_free();
|
||||
}
|
||||
|
||||
@@ -6,6 +6,17 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// fill the batch with tokens at consecutive positions starting from pos_0, output logits only for the last one
|
||||
static void batch_set_tokens(llama_batch_ext * batch, const llama_token * tokens, int32_t n_tokens, llama_pos pos_0) {
|
||||
llama_batch_ext_clear(batch);
|
||||
for (int32_t i = 0; i < n_tokens; ++i) {
|
||||
const int32_t idx = llama_batch_ext_add_token(batch, 0, tokens[i]);
|
||||
const llama_pos pos = pos_0 + i;
|
||||
llama_batch_ext_set_pos(batch, idx, &pos);
|
||||
}
|
||||
llama_batch_ext_set_output_logits(batch, n_tokens - 1, true);
|
||||
}
|
||||
|
||||
static void print_usage(int, char ** argv) {
|
||||
printf("\nexample usage:\n");
|
||||
printf("\n %s -m model.gguf [-c context_size] [-ngl n_gpu_layers]\n", argv[0]);
|
||||
@@ -96,6 +107,8 @@ int main(int argc, char ** argv) {
|
||||
llama_sampler_chain_add(smpl, llama_sampler_init_temp(0.8f));
|
||||
llama_sampler_chain_add(smpl, llama_sampler_init_dist(LLAMA_DEFAULT_SEED));
|
||||
|
||||
llama_batch_ext * batch = llama_batch_ext_init(ctx);
|
||||
|
||||
// helper function to evaluate a prompt and generate a response
|
||||
auto generate = [&](const std::string & prompt) {
|
||||
std::string response;
|
||||
@@ -109,20 +122,25 @@ int main(int argc, char ** argv) {
|
||||
GGML_ABORT("failed to tokenize the prompt\n");
|
||||
}
|
||||
|
||||
// prepare a batch for the prompt
|
||||
llama_batch batch = llama_batch_get_one(prompt_tokens.data(), prompt_tokens.size());
|
||||
// the tokens to evaluate next: the prompt, then the sampled token
|
||||
const llama_token * tokens = prompt_tokens.data();
|
||||
int n_tokens = prompt_tokens.size();
|
||||
|
||||
llama_token new_token_id;
|
||||
while (true) {
|
||||
// check if we have enough space in the context to evaluate this batch
|
||||
int n_ctx = llama_n_ctx(ctx);
|
||||
int n_ctx_used = llama_memory_seq_pos_max(llama_get_memory(ctx), 0) + 1;
|
||||
if (n_ctx_used + batch.n_tokens > n_ctx) {
|
||||
if (n_ctx_used + n_tokens > n_ctx) {
|
||||
printf("\033[0m\n");
|
||||
fprintf(stderr, "context size exceeded\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int ret = llama_decode(ctx, batch);
|
||||
// positions continue from the memory
|
||||
batch_set_tokens(batch, tokens, n_tokens, n_ctx_used);
|
||||
|
||||
int ret = llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch);
|
||||
if (ret != 0) {
|
||||
GGML_ABORT("failed to decode, ret = %d\n", ret);
|
||||
}
|
||||
@@ -147,7 +165,8 @@ int main(int argc, char ** argv) {
|
||||
response += piece;
|
||||
|
||||
// prepare the next batch with the sampled token
|
||||
batch = llama_batch_get_one(&new_token_id, 1);
|
||||
tokens = &new_token_id;
|
||||
n_tokens = 1;
|
||||
}
|
||||
|
||||
return response;
|
||||
@@ -201,6 +220,7 @@ int main(int argc, char ** argv) {
|
||||
for (auto & msg : messages) {
|
||||
free(const_cast<char *>(msg.content));
|
||||
}
|
||||
llama_batch_ext_free(batch);
|
||||
llama_sampler_free(smpl);
|
||||
llama_free(ctx);
|
||||
llama_model_free(model);
|
||||
|
||||
@@ -5,6 +5,17 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// fill the batch with tokens at consecutive positions starting from pos_0, output logits only for the last one
|
||||
static void batch_set_tokens(llama_batch_ext * batch, const llama_token * tokens, int32_t n_tokens, llama_pos pos_0) {
|
||||
llama_batch_ext_clear(batch);
|
||||
for (int32_t i = 0; i < n_tokens; ++i) {
|
||||
const int32_t idx = llama_batch_ext_add_token(batch, 0, tokens[i]);
|
||||
const llama_pos pos = pos_0 + i;
|
||||
llama_batch_ext_set_pos(batch, idx, &pos);
|
||||
}
|
||||
llama_batch_ext_set_output_logits(batch, n_tokens - 1, true);
|
||||
}
|
||||
|
||||
static void print_usage(int, char ** argv) {
|
||||
printf("\nexample usage:\n");
|
||||
printf("\n %s -m model.gguf [-n n_predict] [-ngl n_gpu_layers] [prompt]\n", argv[0]);
|
||||
@@ -144,10 +155,13 @@ int main(int argc, char ** argv) {
|
||||
|
||||
// prepare a batch for the prompt
|
||||
|
||||
llama_batch batch = llama_batch_get_one(prompt_tokens.data(), prompt_tokens.size());
|
||||
llama_batch_ext * batch = llama_batch_ext_init(ctx);
|
||||
int n_tokens = n_prompt; // number of tokens in the current batch
|
||||
|
||||
batch_set_tokens(batch, prompt_tokens.data(), n_prompt, 0);
|
||||
|
||||
if (llama_model_has_encoder(model)) {
|
||||
if (llama_encode(ctx, batch)) {
|
||||
if (llama_process(ctx, LLAMA_PROCESS_TYPE_ENCODE, batch)) {
|
||||
fprintf(stderr, "%s : failed to eval\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
@@ -157,7 +171,8 @@ int main(int argc, char ** argv) {
|
||||
decoder_start_token_id = llama_vocab_bos(vocab);
|
||||
}
|
||||
|
||||
batch = llama_batch_get_one(&decoder_start_token_id, 1);
|
||||
batch_set_tokens(batch, &decoder_start_token_id, 1, 0);
|
||||
n_tokens = 1;
|
||||
}
|
||||
|
||||
// main loop
|
||||
@@ -166,14 +181,14 @@ int main(int argc, char ** argv) {
|
||||
int n_decode = 0;
|
||||
llama_token new_token_id;
|
||||
|
||||
for (int n_pos = 0; n_pos + batch.n_tokens < n_prompt + n_predict; ) {
|
||||
for (int n_pos = 0; n_pos + n_tokens < n_prompt + n_predict; ) {
|
||||
// evaluate the current batch with the transformer model
|
||||
if (llama_decode(ctx, batch)) {
|
||||
if (llama_process(ctx, LLAMA_PROCESS_TYPE_DECODE, batch)) {
|
||||
fprintf(stderr, "%s : failed to eval, return code %d\n", __func__, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
n_pos += batch.n_tokens;
|
||||
n_pos += n_tokens;
|
||||
|
||||
// sample the next token
|
||||
{
|
||||
@@ -195,7 +210,8 @@ int main(int argc, char ** argv) {
|
||||
fflush(stdout);
|
||||
|
||||
// prepare the next batch with the sampled token
|
||||
batch = llama_batch_get_one(&new_token_id, 1);
|
||||
batch_set_tokens(batch, &new_token_id, 1, n_pos);
|
||||
n_tokens = 1;
|
||||
|
||||
n_decode += 1;
|
||||
}
|
||||
@@ -213,6 +229,7 @@ int main(int argc, char ** argv) {
|
||||
llama_perf_context_print(ctx);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
llama_batch_ext_free(batch);
|
||||
llama_sampler_free(smpl);
|
||||
llama_free(ctx);
|
||||
llama_model_free(model);
|
||||
|
||||
@@ -125,12 +125,12 @@ int main(int argc, char ** argv) {
|
||||
|
||||
// eval the prompt on the target and feed it to the speculative implementation(s)
|
||||
{
|
||||
llama_batch batch_prompt = llama_batch_init(inp.size(), 0, 1);
|
||||
common_batch batch_prompt(ctx_tgt);
|
||||
for (size_t i = 0; i < inp.size() - 1; ++i) {
|
||||
common_batch_add(batch_prompt, inp[i], i, { seq_id }, false);
|
||||
batch_prompt.add(inp[i], i, seq_id, false);
|
||||
}
|
||||
|
||||
llama_decode(ctx_tgt, batch_prompt);
|
||||
llama_process(ctx_tgt, LLAMA_PROCESS_TYPE_DECODE, batch_prompt.get());
|
||||
|
||||
if (!common_speculative_process(spec, batch_prompt)) {
|
||||
LOG_ERR("%s", "failed to process speculative prompt\n");
|
||||
@@ -149,7 +149,7 @@ int main(int argc, char ** argv) {
|
||||
|
||||
common_speculative_begin(spec, seq_id, prompt_tgt);
|
||||
|
||||
llama_batch batch_tgt = llama_batch_init(llama_n_batch(ctx_tgt), 0, 1);
|
||||
common_batch batch_tgt(ctx_tgt);
|
||||
|
||||
llama_tokens draft;
|
||||
|
||||
@@ -219,17 +219,17 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
|
||||
// always have a token to evaluate from before - id_last
|
||||
common_batch_clear(batch_tgt);
|
||||
common_batch_add (batch_tgt, id_last, n_past++, { seq_id }, true);
|
||||
batch_tgt.clear();
|
||||
batch_tgt.add(id_last, n_past++, seq_id, true);
|
||||
|
||||
// evaluate the target model on [id_last, draft0, draft1, ..., draftN-1]
|
||||
{
|
||||
for (size_t i = 0; i < draft.size(); ++i) {
|
||||
common_batch_add(batch_tgt, draft[i], n_past + i, { seq_id }, true);
|
||||
batch_tgt.add(draft[i], n_past + i, seq_id, true);
|
||||
}
|
||||
|
||||
|
||||
llama_decode(ctx_tgt, batch_tgt);
|
||||
llama_process(ctx_tgt, LLAMA_PROCESS_TYPE_DECODE, batch_tgt.get());
|
||||
}
|
||||
|
||||
// feed the batch to the speculative implementation(s) - this drives the draft model, MTP, Eagle3, etc.
|
||||
@@ -364,7 +364,6 @@ int main(int argc, char ** argv) {
|
||||
LOG_INF("target:\n\n");
|
||||
common_perf_print(ctx_tgt, smpl.get());
|
||||
|
||||
llama_batch_free(batch_tgt);
|
||||
|
||||
common_speculative_free(spec);
|
||||
|
||||
|
||||
@@ -190,9 +190,16 @@ int main(int argc, char ** argv) {
|
||||
const auto t_enc_start = ggml_time_us();
|
||||
|
||||
// eval the prompt with both models
|
||||
llama_decode(ctx_tgt, llama_batch_get_one( inp.data(), n_input - 1));
|
||||
llama_decode(ctx_tgt, llama_batch_get_one(&inp.back(), 1));
|
||||
llama_decode(ctx_dft, llama_batch_get_one( inp.data(), n_input));
|
||||
{
|
||||
common_batch batch = common_batch_get_one(ctx_tgt, inp.data(), n_input - 1);
|
||||
llama_process(ctx_tgt, LLAMA_PROCESS_TYPE_DECODE, batch.get());
|
||||
|
||||
batch = common_batch_get_one(ctx_tgt, &inp.back(), 1);
|
||||
llama_process(ctx_tgt, LLAMA_PROCESS_TYPE_DECODE, batch.get());
|
||||
|
||||
batch = common_batch_get_one(ctx_dft, inp.data(), n_input);
|
||||
llama_process(ctx_dft, LLAMA_PROCESS_TYPE_DECODE, batch.get());
|
||||
}
|
||||
|
||||
const auto t_enc_end = ggml_time_us();
|
||||
|
||||
@@ -223,8 +230,8 @@ int main(int argc, char ** argv) {
|
||||
drafts[s].smpl = common_sampler_init(model_dft, params.sampling);
|
||||
}
|
||||
|
||||
llama_batch batch_dft = llama_batch_init(llama_n_batch(ctx_dft), 0, 1);
|
||||
llama_batch batch_tgt = llama_batch_init(llama_n_batch(ctx_tgt), 0, n_seq_dft);
|
||||
common_batch batch_dft(ctx_dft);
|
||||
common_batch batch_tgt(ctx_tgt);
|
||||
|
||||
const auto t_dec_start = ggml_time_us();
|
||||
|
||||
@@ -465,12 +472,12 @@ int main(int argc, char ** argv) {
|
||||
drafts[0].dists.push_back(std::vector<llama_token_data>());
|
||||
drafts[0].i_batch_tgt.push_back(0);
|
||||
|
||||
common_batch_clear(batch_dft);
|
||||
common_batch_add (batch_dft, token_id, n_past_dft, { 0 }, true);
|
||||
batch_dft.clear();
|
||||
batch_dft.add(token_id, n_past_dft, 0, true);
|
||||
|
||||
llama_memory_seq_rm(mem_dft, 0, n_past_dft, -1);
|
||||
// LOG_DBG("dft batch: %s\n", LOG_BATCH_TOSTR_PRETTY(ctx_dft, batch_dft).c_str());
|
||||
llama_decode(ctx_dft, batch_dft);
|
||||
llama_process(ctx_dft, LLAMA_PROCESS_TYPE_DECODE, batch_dft.get());
|
||||
|
||||
++n_past_dft;
|
||||
}
|
||||
@@ -495,12 +502,12 @@ int main(int argc, char ** argv) {
|
||||
drafts[0].drafting = true;
|
||||
drafts[0].i_batch_dft = 0;
|
||||
|
||||
common_batch_clear(batch_tgt);
|
||||
common_batch_add (batch_tgt, drafts[0].tokens[0], n_past_tgt, { 0 }, true);
|
||||
batch_tgt.clear();
|
||||
batch_tgt.add(drafts[0].tokens[0], n_past_tgt, 0, true);
|
||||
|
||||
// sample n_draft tokens from the draft model using tree-based sampling
|
||||
for (int i = 0; i < n_draft; ++i) {
|
||||
batch_dft.n_tokens = 0;
|
||||
batch_dft.clear();
|
||||
|
||||
for (int s = 0; s < n_seq_dft; ++s) {
|
||||
drafts[s].skip = false;
|
||||
@@ -531,14 +538,8 @@ int main(int argc, char ** argv) {
|
||||
llama_memory_seq_cp(mem_dft, s, n_seq_cur, -1, -1);
|
||||
|
||||
// all previous tokens from this branch are now also part of the new branch
|
||||
for (int t = 0; t < batch_tgt.n_tokens; ++t) {
|
||||
for (int p = 0; p < batch_tgt.n_seq_id[t]; ++p) {
|
||||
if (batch_tgt.seq_id[t][p] == s) {
|
||||
batch_tgt.seq_id[t][batch_tgt.n_seq_id[t]] = n_seq_cur;
|
||||
batch_tgt.n_seq_id[t]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int t : drafts[s].i_batch_tgt) {
|
||||
batch_tgt.add_seq(t, n_seq_cur);
|
||||
}
|
||||
|
||||
// copy the draft state
|
||||
@@ -577,32 +578,32 @@ int main(int argc, char ** argv) {
|
||||
drafts[s].dists.push_back({cur_p->data, cur_p->data + cur_p->size});
|
||||
|
||||
// add unique drafted tokens to the target batch
|
||||
drafts[s].i_batch_tgt.push_back(batch_tgt.n_tokens);
|
||||
drafts[s].i_batch_tgt.push_back(batch_tgt.size());
|
||||
|
||||
common_batch_add(batch_tgt, id, n_past_tgt + i + 1, { s }, true);
|
||||
batch_tgt.add(id, n_past_tgt + i + 1, s, true);
|
||||
|
||||
// add the token to the batch for batched decoding with the draft model
|
||||
drafts[s].i_batch_dft = batch_dft.n_tokens;
|
||||
drafts[s].i_batch_dft = batch_dft.size();
|
||||
|
||||
common_batch_add(batch_dft, id, n_past_cur, { s }, true);
|
||||
batch_dft.add(id, n_past_cur, s, true);
|
||||
|
||||
if (batch_tgt.n_tokens > n_draft) {
|
||||
if (batch_tgt.size() > n_draft) {
|
||||
drafts[s].drafting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no sequence is drafting anymore
|
||||
if (batch_dft.n_tokens == 0) {
|
||||
if (batch_dft.size() == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// evaluate the drafted tokens on the draft model
|
||||
llama_decode(ctx_dft, batch_dft);
|
||||
llama_process(ctx_dft, LLAMA_PROCESS_TYPE_DECODE, batch_dft.get());
|
||||
++n_past_cur;
|
||||
++n_drafted;
|
||||
|
||||
if (batch_tgt.n_tokens > n_draft) {
|
||||
if (batch_tgt.size() > n_draft) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -615,7 +616,7 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
|
||||
// LOG_DBG("target batch: %s\n", LOG_BATCH_TOSTR_PRETTY(ctx_tgt, batch_tgt).c_str());
|
||||
llama_decode(ctx_tgt, batch_tgt);
|
||||
llama_process(ctx_tgt, LLAMA_PROCESS_TYPE_DECODE, batch_tgt.get());
|
||||
++n_past_tgt;
|
||||
}
|
||||
|
||||
@@ -658,7 +659,6 @@ int main(int argc, char ** argv) {
|
||||
common_sampler_free(drafts[s].smpl);
|
||||
}
|
||||
|
||||
llama_batch_free(batch_dft);
|
||||
|
||||
llama_backend_free();
|
||||
|
||||
|
||||
@@ -197,6 +197,7 @@ set(GGML_BLAS_VENDOR ${GGML_BLAS_VENDOR_DEFAULT} CACHE STRING
|
||||
option(GGML_LLAMAFILE "ggml: use LLAMAFILE" ${GGML_LLAMAFILE_DEFAULT})
|
||||
|
||||
option(GGML_CUDA "ggml: use CUDA" OFF)
|
||||
set (GGML_CUDA_CCCL_VERSION "" CACHE STRING "ggml: CCCL git tag to fetch, empty to use the version bundled with the installed CUDA Toolkit")
|
||||
option(GGML_MUSA "ggml: use MUSA" OFF)
|
||||
option(GGML_CUDA_FORCE_MMQ "ggml: use mmq kernels instead of cuBLAS" OFF)
|
||||
option(GGML_CUDA_FORCE_CUBLAS "ggml: always use cuBLAS instead of mmq kernels" OFF)
|
||||
|
||||
@@ -10,6 +10,8 @@ extern "C" {
|
||||
// device buffer
|
||||
GGML_BACKEND_API ggml_backend_buffer_type_t ggml_backend_zdnn_buffer_type(void);
|
||||
|
||||
GGML_BACKEND_API bool ggml_backend_is_zdnn(ggml_backend_t backend);
|
||||
|
||||
GGML_BACKEND_API ggml_backend_reg_t ggml_backend_zdnn_reg(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -2331,20 +2331,22 @@ static enum ggml_status ggml_backend_meta_graph_compute(ggml_backend_t backend,
|
||||
if (node->flags & GGML_TENSOR_FLAG_COMPUTE) {
|
||||
continue;
|
||||
}
|
||||
ggml_tensor * node_zero = get_node_aux(node);
|
||||
node_zero->op = GGML_OP_SCALE; // FIXME 0.0f * NaN == NaN
|
||||
node_zero->src[0] = node;
|
||||
ggml_set_op_params_f32(node_zero, 0, 0.0f);
|
||||
node_zero->data = node->data;
|
||||
node_zero->buffer = node->buffer;
|
||||
node_zero->flags |= GGML_TENSOR_FLAG_COMPUTE;
|
||||
if (ggml_nelements(node) > 0) {
|
||||
ggml_tensor * node_zero = get_node_aux(node);
|
||||
node_zero->op = GGML_OP_FILL;
|
||||
node_zero->src[0] = node; // only used for the shape, the data is not read
|
||||
ggml_set_op_params_f32(node_zero, 0, 0.0f);
|
||||
node_zero->data = node->data;
|
||||
node_zero->buffer = node->buffer;
|
||||
node_zero->flags |= GGML_TENSOR_FLAG_COMPUTE;
|
||||
|
||||
step_cgraphs[j] = get_cgraph_aux();
|
||||
step_cgraphs[j]->nodes[0] = node_zero;
|
||||
step_cgraphs[j]->n_nodes = 1;
|
||||
const ggml_status status = ggml_backend_graph_compute_async(bcj.backend, step_cgraphs[j]);
|
||||
if (status != GGML_STATUS_SUCCESS) {
|
||||
return status;
|
||||
step_cgraphs[j] = get_cgraph_aux();
|
||||
step_cgraphs[j]->nodes[0] = node_zero;
|
||||
step_cgraphs[j]->n_nodes = 1;
|
||||
const ggml_status status = ggml_backend_graph_compute_async(bcj.backend, step_cgraphs[j]);
|
||||
if (status != GGML_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::fill(step_cgraphs.begin(), step_cgraphs.end(), nullptr);
|
||||
|
||||
@@ -84,10 +84,17 @@ if (BLAS_FOUND)
|
||||
add_compile_definitions(GGML_BLAS_USE_OPENBLAS)
|
||||
endif()
|
||||
|
||||
# Vendors with the BLIS API take GGML_BLAS_USE_BLIS (blis.h, bli_thread_set_num_threads).
|
||||
# AOCL also takes GGML_BLAS_USE_AOCL so its device label is AOCL-BLAS, not BLIS.
|
||||
# Neither flag selects the linked library; FindBLAS does that from GGML_BLAS_VENDOR.
|
||||
if ("${GGML_BLAS_VENDOR}" MATCHES "FLAME" OR "${GGML_BLAS_VENDOR}" MATCHES "AOCL" OR "${GGML_BLAS_VENDOR}" MATCHES "AOCL_mt")
|
||||
add_compile_definitions(GGML_BLAS_USE_BLIS)
|
||||
endif()
|
||||
|
||||
if ("${GGML_BLAS_VENDOR}" MATCHES "AOCL" OR "${GGML_BLAS_VENDOR}" MATCHES "AOCL_mt")
|
||||
add_compile_definitions(GGML_BLAS_USE_AOCL)
|
||||
endif()
|
||||
|
||||
if ("${GGML_BLAS_VENDOR}" MATCHES "NVPL")
|
||||
add_compile_definitions(GGML_BLAS_USE_NVPL)
|
||||
endif()
|
||||
|
||||
@@ -330,6 +330,8 @@ static const char * ggml_backend_blas_device_get_description(ggml_backend_dev_t
|
||||
return "Accelerate";
|
||||
#elif defined(GGML_BLAS_USE_MKL)
|
||||
return "MKL";
|
||||
#elif defined(GGML_BLAS_USE_AOCL)
|
||||
return "AOCL-BLAS";
|
||||
#elif defined(GGML_BLAS_USE_BLIS)
|
||||
return "BLIS";
|
||||
#elif defined(GGML_BLAS_USE_NVPL)
|
||||
|
||||
@@ -1334,9 +1334,11 @@ UseGgmlGemm1:;
|
||||
const size_t nbw3 = nbw2*ne12;
|
||||
|
||||
assert(params->wsize >= ne13*nbw3);
|
||||
GGML_ASSERT(src1->type == GGML_TYPE_F32 || src1->type == GGML_TYPE_F16);
|
||||
// the F16 path below writes plain floats into wdata, so it needs an F32 vec_dot_type
|
||||
GGML_ASSERT(src1->type == GGML_TYPE_F32 || vec_dot_type == GGML_TYPE_F32);
|
||||
// src1 is either packed from F32 into vec_dot_type, or widened from F16 or BF16 into the F32 work buffer
|
||||
const bool widen = src1->type != GGML_TYPE_F32;
|
||||
|
||||
GGML_ASSERT(!widen || vec_dot_type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(!widen || src1->type == GGML_TYPE_F16 || src1->type == GGML_TYPE_BF16);
|
||||
|
||||
#if 0
|
||||
for (int64_t i13 = 0; i13 < ne13; ++i13) {
|
||||
@@ -1349,20 +1351,24 @@ UseGgmlGemm1:;
|
||||
}
|
||||
}
|
||||
#else
|
||||
const int64_t bs = ggml_blck_size(vec_dot_type);
|
||||
|
||||
for (int64_t i13 = 0; i13 < ne13; ++i13) {
|
||||
for (int64_t i12 = 0; i12 < ne12; ++i12) {
|
||||
for (int64_t i11 = 0; i11 < ne11; ++i11) {
|
||||
size_t bs = ggml_blck_size(vec_dot_type);
|
||||
int64_t ne10_block_start = (ith * ne10/bs) / nth;
|
||||
int64_t ne10_block_end = ((ith + 1) * ne10/bs) / nth;
|
||||
const char * src1_block = (const char *) src1->data + i13*nb13 + i12*nb12 + i11*nb11 + ne10_block_start*bs*nb10;
|
||||
char * dst_block = wdata + i13*nbw3 + i12*nbw2 + i11*nbw1 + ne10_block_start*nbw0;
|
||||
const int64_t n_block = (ne10_block_end - ne10_block_start) * bs;
|
||||
const void * src1_row = (const char *) src1->data + i13*nb13 + i12*nb12 + i11*nb11 + ne10_block_start*bs*nb10;
|
||||
void * wdata_row = wdata + i13*nbw3 + i12*nbw2 + i11*nbw1 + ne10_block_start*nbw0;
|
||||
|
||||
if (src1->type == GGML_TYPE_F32) {
|
||||
from_float((const float *) src1_block, dst_block, n_block);
|
||||
const int64_t ne10_block_size = (ne10_block_end - ne10_block_start) * bs;
|
||||
|
||||
if (src1->type == GGML_TYPE_F16) {
|
||||
ggml_cpu_fp16_to_fp32((const ggml_fp16_t *) src1_row, (float *) wdata_row, ne10_block_size);
|
||||
} else if (src1->type == GGML_TYPE_BF16) {
|
||||
ggml_cpu_bf16_to_fp32((const ggml_bf16_t *) src1_row, (float *) wdata_row, ne10_block_size);
|
||||
} else {
|
||||
ggml_cpu_fp16_to_fp32((const ggml_fp16_t *) src1_block, (float *) dst_block, n_block);
|
||||
from_float((const float *) src1_row, wdata_row, ne10_block_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,7 +455,10 @@ static bool ggml_backend_cpu_device_supports_op(ggml_backend_dev_t dev, const st
|
||||
src0->type == GGML_TYPE_F32 && op->type == GGML_TYPE_F32) {
|
||||
return src1->type == GGML_TYPE_F32 || src1->type == GGML_TYPE_F16;
|
||||
}
|
||||
return src1->type == GGML_TYPE_F32 || src1->type == ggml_get_type_traits_cpu(src0->type)->vec_dot_type;
|
||||
// BF16 in src1 is widened into the F32 work buffer
|
||||
return src1->type == GGML_TYPE_F32 ||
|
||||
src1->type == ggml_get_type_traits_cpu(src0->type)->vec_dot_type ||
|
||||
(src1->type == GGML_TYPE_BF16 && ggml_get_type_traits_cpu(src0->type)->vec_dot_type == GGML_TYPE_F32);
|
||||
case GGML_OP_SOFT_MAX_BACK: {
|
||||
if (op->src[0]->type != GGML_TYPE_F32 || op->src[1]->type != GGML_TYPE_F32) {
|
||||
return false;
|
||||
|
||||
@@ -2106,6 +2106,46 @@ void ggml_compute_forward_concat(
|
||||
}
|
||||
}
|
||||
|
||||
// row loop shared by the BF16 unary ops
|
||||
template <void (*vec_op)(const int, ggml_bf16_t *, const ggml_bf16_t *)>
|
||||
static void ggml_compute_forward_unary_bf16_rows(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
|
||||
const ggml_tensor * src0 = dst->src[0];
|
||||
|
||||
assert(ggml_is_contiguous_rows(src0));
|
||||
assert(ggml_are_same_shape(src0, dst));
|
||||
|
||||
GGML_TENSOR_LOCALS(int64_t, ne0, src0, ne)
|
||||
GGML_TENSOR_LOCALS(size_t, nb0, src0, nb)
|
||||
GGML_TENSOR_LOCALS(int64_t, ne, dst, ne)
|
||||
GGML_TENSOR_LOCALS(size_t, nb, dst, nb)
|
||||
|
||||
const int ith = params->ith;
|
||||
const int nth = params->nth;
|
||||
|
||||
const int nc = src0->ne[0];
|
||||
const int nr = ggml_nrows(src0);
|
||||
|
||||
// rows per thread
|
||||
const int dr = (nr + nth - 1)/nth;
|
||||
|
||||
// row range for this thread
|
||||
const int ir0 = dr*ith;
|
||||
const int ir1 = MIN(ir0 + dr, nr);
|
||||
|
||||
for (int ir = ir0; ir < ir1; ++ir) {
|
||||
const int i3 = ir/(ne02*ne01);
|
||||
const int i2 = (ir - i3*ne02*ne01)/ne01;
|
||||
const int i1 = (ir - i3*ne02*ne01 - i2*ne01);
|
||||
|
||||
vec_op(nc,
|
||||
(ggml_bf16_t *) ((char *) dst->data + i3*nb3 + i2*nb2 + i1*nb1),
|
||||
(ggml_bf16_t *) ((char *) src0->data + i3*nb03 + i2*nb02 + i1*nb01));
|
||||
}
|
||||
}
|
||||
|
||||
// ggml_compute_forward_gelu
|
||||
|
||||
static void ggml_compute_forward_gelu_f32(
|
||||
@@ -2203,6 +2243,12 @@ static void ggml_compute_forward_gelu_f16(
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_gelu_bf16(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
ggml_compute_forward_unary_bf16_rows<ggml_vec_gelu_bf16>(params, dst);
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_gelu(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
@@ -2218,6 +2264,10 @@ static void ggml_compute_forward_gelu(
|
||||
{
|
||||
ggml_compute_forward_gelu_f16(params, dst);
|
||||
} break;
|
||||
case GGML_TYPE_BF16:
|
||||
{
|
||||
ggml_compute_forward_gelu_bf16(params, dst);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
GGML_ABORT("fatal error");
|
||||
@@ -2433,6 +2483,12 @@ static void ggml_compute_forward_gelu_erf_f16(
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_gelu_erf_bf16(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
ggml_compute_forward_unary_bf16_rows<ggml_vec_gelu_erf_bf16>(params, dst);
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_gelu_erf(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
@@ -2448,6 +2504,10 @@ static void ggml_compute_forward_gelu_erf(
|
||||
{
|
||||
ggml_compute_forward_gelu_erf_f16(params, dst);
|
||||
} break;
|
||||
case GGML_TYPE_BF16:
|
||||
{
|
||||
ggml_compute_forward_gelu_erf_bf16(params, dst);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
GGML_ABORT("fatal error");
|
||||
@@ -2552,6 +2612,12 @@ static void ggml_compute_forward_gelu_quick_f16(
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_gelu_quick_bf16(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
ggml_compute_forward_unary_bf16_rows<ggml_vec_gelu_quick_bf16>(params, dst);
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_gelu_quick(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
@@ -2567,6 +2633,10 @@ static void ggml_compute_forward_gelu_quick(
|
||||
{
|
||||
ggml_compute_forward_gelu_quick_f16(params, dst);
|
||||
} break;
|
||||
case GGML_TYPE_BF16:
|
||||
{
|
||||
ggml_compute_forward_gelu_quick_bf16(params, dst);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
GGML_ABORT("fatal error");
|
||||
@@ -2671,6 +2741,12 @@ static void ggml_compute_forward_silu_f16(
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_silu_bf16(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
ggml_compute_forward_unary_bf16_rows<ggml_vec_silu_bf16>(params, dst);
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_silu(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
@@ -2686,6 +2762,10 @@ static void ggml_compute_forward_silu(
|
||||
{
|
||||
ggml_compute_forward_silu_f16(params, dst);
|
||||
} break;
|
||||
case GGML_TYPE_BF16:
|
||||
{
|
||||
ggml_compute_forward_silu_bf16(params, dst);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
GGML_ABORT("fatal error");
|
||||
@@ -2889,6 +2969,59 @@ void ggml_compute_forward_silu_back(
|
||||
|
||||
// ggml_compute_forward_reglu
|
||||
|
||||
// row loop shared by the BF16 GLU ops
|
||||
template <void (*vec_op)(const int, ggml_bf16_t *, const ggml_bf16_t *, const ggml_bf16_t *)>
|
||||
static void ggml_compute_forward_glu_bf16_rows(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
|
||||
const ggml_tensor * src0 = dst->src[0];
|
||||
const ggml_tensor * src1 = dst->src[1];
|
||||
char * src0_d = (char *) src0->data;
|
||||
char * src1_d = (char *) (src1 ? src1->data : src0->data);
|
||||
const size_t src0_o = src0->nb[1];
|
||||
const size_t src1_o = src1 ? src1->nb[1] : src0->nb[1];
|
||||
|
||||
GGML_ASSERT(ggml_is_contiguous_1(src0));
|
||||
GGML_ASSERT(ggml_is_contiguous_1(dst));
|
||||
|
||||
if (src1) {
|
||||
GGML_ASSERT(ggml_is_contiguous_1(src1));
|
||||
GGML_ASSERT(src0->type == src1->type);
|
||||
}
|
||||
|
||||
const int ith = params->ith;
|
||||
const int nth = params->nth;
|
||||
|
||||
const int nc = src1 ? src0->ne[0] : src0->ne[0] / 2;
|
||||
const int nr = ggml_nrows(src0);
|
||||
|
||||
GGML_ASSERT(dst->ne[0] == nc);
|
||||
GGML_ASSERT(ggml_nrows(dst) == nr);
|
||||
|
||||
const int32_t swapped = ggml_get_op_params_i32(dst, 1);
|
||||
|
||||
// rows per thread
|
||||
const int dr = (nr + nth - 1)/nth;
|
||||
|
||||
// row range for this thread
|
||||
const int ir0 = dr*ith;
|
||||
const int ir1 = MIN(ir0 + dr, nr);
|
||||
|
||||
for (int i1 = ir0; i1 < ir1; i1++) {
|
||||
const ggml_bf16_t * src0_p = (const ggml_bf16_t *) (src0_d + i1*src0_o);
|
||||
const ggml_bf16_t * src1_p = (const ggml_bf16_t *) (src1_d + i1*src1_o);
|
||||
ggml_bf16_t * dst_p = (ggml_bf16_t *) ((char *) dst->data + i1*(dst->nb[1]));
|
||||
|
||||
if (!src1) {
|
||||
src0_p += swapped ? nc : 0;
|
||||
src1_p += swapped ? 0 : nc;
|
||||
}
|
||||
|
||||
vec_op(nc, dst_p, src0_p, src1_p);
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_reglu_f32(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
@@ -3008,6 +3141,12 @@ static void ggml_compute_forward_reglu_f16(
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_reglu_bf16(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
ggml_compute_forward_glu_bf16_rows<ggml_vec_reglu_bf16>(params, dst);
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_reglu(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
@@ -3023,6 +3162,10 @@ static void ggml_compute_forward_reglu(
|
||||
{
|
||||
ggml_compute_forward_reglu_f16(params, dst);
|
||||
} break;
|
||||
case GGML_TYPE_BF16:
|
||||
{
|
||||
ggml_compute_forward_reglu_bf16(params, dst);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
GGML_ABORT("fatal error");
|
||||
@@ -3151,6 +3294,12 @@ static void ggml_compute_forward_geglu_f16(
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_geglu_bf16(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
ggml_compute_forward_glu_bf16_rows<ggml_vec_geglu_bf16>(params, dst);
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_geglu(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
@@ -3166,6 +3315,10 @@ static void ggml_compute_forward_geglu(
|
||||
{
|
||||
ggml_compute_forward_geglu_f16(params, dst);
|
||||
} break;
|
||||
case GGML_TYPE_BF16:
|
||||
{
|
||||
ggml_compute_forward_geglu_bf16(params, dst);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
GGML_ABORT("fatal error");
|
||||
@@ -3294,6 +3447,12 @@ static void ggml_compute_forward_swiglu_f16(
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_swiglu_bf16(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
ggml_compute_forward_glu_bf16_rows<ggml_vec_swiglu_bf16>(params, dst);
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_swiglu(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
@@ -3309,6 +3468,10 @@ static void ggml_compute_forward_swiglu(
|
||||
{
|
||||
ggml_compute_forward_swiglu_f16(params, dst);
|
||||
} break;
|
||||
case GGML_TYPE_BF16:
|
||||
{
|
||||
ggml_compute_forward_swiglu_bf16(params, dst);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
GGML_ABORT("fatal error");
|
||||
@@ -3657,6 +3820,12 @@ static void ggml_compute_forward_geglu_erf_f16(
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_geglu_erf_bf16(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
ggml_compute_forward_glu_bf16_rows<ggml_vec_geglu_erf_bf16>(params, dst);
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_geglu_erf(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
@@ -3672,6 +3841,10 @@ static void ggml_compute_forward_geglu_erf(
|
||||
{
|
||||
ggml_compute_forward_geglu_erf_f16(params, dst);
|
||||
} break;
|
||||
case GGML_TYPE_BF16:
|
||||
{
|
||||
ggml_compute_forward_geglu_erf_bf16(params, dst);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
GGML_ABORT("fatal error");
|
||||
@@ -3800,6 +3973,12 @@ static void ggml_compute_forward_geglu_quick_f16(
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_geglu_quick_bf16(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
ggml_compute_forward_glu_bf16_rows<ggml_vec_geglu_quick_bf16>(params, dst);
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_geglu_quick(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
@@ -3815,6 +3994,10 @@ static void ggml_compute_forward_geglu_quick(
|
||||
{
|
||||
ggml_compute_forward_geglu_quick_f16(params, dst);
|
||||
} break;
|
||||
case GGML_TYPE_BF16:
|
||||
{
|
||||
ggml_compute_forward_geglu_quick_bf16(params, dst);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
GGML_ABORT("fatal error");
|
||||
@@ -4746,6 +4929,44 @@ static void ggml_compute_forward_scale_f32(
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_scale_bf16(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
|
||||
const ggml_tensor * src0 = dst->src[0];
|
||||
|
||||
GGML_ASSERT(ggml_is_contiguous(src0));
|
||||
GGML_ASSERT(ggml_is_contiguous(dst));
|
||||
GGML_ASSERT(ggml_are_same_shape(src0, dst));
|
||||
|
||||
float s; // scale factor
|
||||
float b; // bias
|
||||
|
||||
memcpy(&s, (float *) dst->op_params + 0, sizeof(float));
|
||||
memcpy(&b, (float *) dst->op_params + 1, sizeof(float));
|
||||
|
||||
const int ith = params->ith;
|
||||
const int nth = params->nth;
|
||||
|
||||
const int nc = src0->ne[0];
|
||||
const int nr = ggml_nrows(src0);
|
||||
|
||||
// rows per thread
|
||||
const int dr = (nr + nth - 1)/nth;
|
||||
|
||||
// row range for this thread
|
||||
const int ir0 = dr*ith;
|
||||
const int ir1 = MIN(ir0 + dr, nr);
|
||||
|
||||
for (int i1 = ir0; i1 < ir1; i1++) {
|
||||
const ggml_bf16_t * x = (const ggml_bf16_t *) ((const char *) src0->data + i1*src0->nb[1]);
|
||||
ggml_bf16_t * y = (ggml_bf16_t *) ((char *) dst->data + i1*dst->nb[1]);
|
||||
for (int k = 0; k < nc; k++) {
|
||||
y[k] = GGML_FP32_TO_BF16(s*GGML_BF16_TO_FP32(x[k]) + b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ggml_compute_forward_scale(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
@@ -4757,6 +4978,10 @@ void ggml_compute_forward_scale(
|
||||
{
|
||||
ggml_compute_forward_scale_f32(params, dst);
|
||||
} break;
|
||||
case GGML_TYPE_BF16:
|
||||
{
|
||||
ggml_compute_forward_scale_bf16(params, dst);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
GGML_ABORT("fatal error");
|
||||
@@ -5351,6 +5576,8 @@ static void ggml_compute_forward_get_rows_back_f32_f16(
|
||||
for (int i = 0; i < nr; ++i) {
|
||||
const int r = ((int32_t *) src1->data)[i];
|
||||
|
||||
GGML_ASSERT(r >= 0 && r < dst->ne[1]);
|
||||
|
||||
for (int j = 0; j < nc; ++j) {
|
||||
ggml_fp16_t v = ((ggml_fp16_t *) ((char *) src0->data + i*src0->nb[1]))[j];
|
||||
((float *) ((char *) dst->data + r*dst->nb[1]))[j] += GGML_CPU_FP16_TO_FP32(v);
|
||||
@@ -5384,6 +5611,8 @@ static void ggml_compute_forward_get_rows_back_f32(
|
||||
for (int i = 0; i < nr; ++i) {
|
||||
const int r = ((int32_t *) src1->data)[i];
|
||||
|
||||
GGML_ASSERT(r >= 0 && r < dst->ne[1]);
|
||||
|
||||
ggml_vec_add_f32(nc,
|
||||
(float *) ((char *) dst->data + r*dst->nb[1]),
|
||||
(float *) ((char *) dst->data + r*dst->nb[1]),
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// bit unpacking routines: tiled_unpk_nib4, tiled_unpk_2bit, tiled_unpk_or
|
||||
// LUT value expansion routines: tiled_lut8, tiled_unpk_sign32, tiled_unpk_tern8
|
||||
|
||||
#define GGML_COMMON_DECL_C
|
||||
#define GGML_COMMON_DECL_CPP
|
||||
#include "ggml-common.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -35,8 +35,8 @@ static void tiled_unpack_src0(const block_q4_K * rows, int64_t row_stride, int n
|
||||
const int s_off = r * nb_stride + slab * NB;
|
||||
const block_q4_K & x = rows[r * row_stride + slab];
|
||||
|
||||
tile->d[d_off] = ggml_fp16_to_fp32(x.d);
|
||||
tile->dmin[d_off] = ggml_fp16_to_fp32(x.dmin);
|
||||
tile->d[d_off] = ggml_fp16_to_fp32(x.data.data.d);
|
||||
tile->dmin[d_off] = ggml_fp16_to_fp32(x.data.data.dmin);
|
||||
|
||||
uint32_t utmp[4];
|
||||
memcpy(utmp, x.scales, 12);
|
||||
@@ -80,8 +80,8 @@ static void tiled_unpack_src0(const block_q5_K * rows, int64_t row_stride, int n
|
||||
const int s_off = r * nb_stride + slab * NB;
|
||||
const block_q5_K & x = rows[r * row_stride + slab];
|
||||
|
||||
tile->d[d_off] = ggml_fp16_to_fp32(x.d);
|
||||
tile->dmin[d_off] = ggml_fp16_to_fp32(x.dmin);
|
||||
tile->d[d_off] = ggml_fp16_to_fp32(x.data.data.d);
|
||||
tile->dmin[d_off] = ggml_fp16_to_fp32(x.data.data.dmin);
|
||||
|
||||
uint32_t utmp[4];
|
||||
memcpy(utmp, x.scales, 12);
|
||||
@@ -207,8 +207,8 @@ static void tiled_unpack_src0(const block_q2_K * rows, int64_t row_stride, int n
|
||||
const int q_off = r * qk_stride + slab * TILED_TILE_K;
|
||||
const int s_off = r * nb_stride + slab * NB;
|
||||
const block_q2_K & x = rows[r * row_stride + slab];
|
||||
tile->d[d_off] = ggml_fp16_to_fp32(x.d);
|
||||
tile->dmin[d_off] = ggml_fp16_to_fp32(x.dmin);
|
||||
tile->d[d_off] = ggml_fp16_to_fp32(x.data.data.d);
|
||||
tile->dmin[d_off] = ggml_fp16_to_fp32(x.data.data.dmin);
|
||||
|
||||
// 2-bit code: element e -> half=e>>7, el=e&127
|
||||
// byte = half*32 + (el & 31), shift = 2*(el >> 5)
|
||||
|
||||
@@ -976,6 +976,12 @@ inline static void ggml_vec_gelu_f16(const int n, ggml_fp16_t * y, const ggml_fp
|
||||
}
|
||||
}
|
||||
|
||||
inline static void ggml_vec_gelu_bf16(const int n, ggml_bf16_t * y, const ggml_bf16_t * x) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
y[i] = GGML_FP32_TO_BF16(ggml_gelu_f32(GGML_BF16_TO_FP32(x[i])));
|
||||
}
|
||||
}
|
||||
|
||||
inline static void ggml_vec_gelu_erf_f16(const int n, ggml_fp16_t * y, const ggml_fp16_t * x) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
float xi = GGML_CPU_FP16_TO_FP32(x[i]);
|
||||
@@ -984,6 +990,13 @@ inline static void ggml_vec_gelu_erf_f16(const int n, ggml_fp16_t * y, const ggm
|
||||
}
|
||||
}
|
||||
|
||||
inline static void ggml_vec_gelu_erf_bf16(const int n, ggml_bf16_t * y, const ggml_bf16_t * x) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
float xi = GGML_BF16_TO_FP32(x[i]);
|
||||
y[i] = GGML_FP32_TO_BF16(0.5f*xi*(1.0f + erff(xi*SQRT_2_INV)));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GGML_GELU_FP16
|
||||
inline static void ggml_vec_gelu_f32(const int n, float * y, const float * x) {
|
||||
uint16_t t;
|
||||
@@ -1025,6 +1038,12 @@ inline static void ggml_vec_gelu_quick_f16(const int n, ggml_fp16_t * y, const g
|
||||
}
|
||||
}
|
||||
|
||||
inline static void ggml_vec_gelu_quick_bf16(const int n, ggml_bf16_t * y, const ggml_bf16_t * x) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
y[i] = GGML_FP32_TO_BF16(ggml_gelu_quick_f32(GGML_BF16_TO_FP32(x[i])));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GGML_GELU_QUICK_FP16
|
||||
inline static void ggml_vec_gelu_quick_f32(const int n, float * y, const float * x) {
|
||||
uint16_t t;
|
||||
@@ -1375,6 +1394,12 @@ inline static void ggml_vec_silu_f16(const int n, ggml_fp16_t * y, const ggml_fp
|
||||
}
|
||||
}
|
||||
|
||||
inline static void ggml_vec_silu_bf16(const int n, ggml_bf16_t * y, const ggml_bf16_t * x) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
y[i] = GGML_FP32_TO_BF16(ggml_silu_f32(GGML_BF16_TO_FP32(x[i])));
|
||||
}
|
||||
}
|
||||
|
||||
inline static float ggml_silu_backward_f32(float x, float dy) {
|
||||
const float s = 1.0f/(1.0f + expf(-x));
|
||||
return dy*s*(1.0f + x*(1.0f - s));
|
||||
@@ -1411,6 +1436,13 @@ inline static void ggml_vec_reglu_f16 (const int n, ggml_fp16_t * y, const ggml_
|
||||
}
|
||||
}
|
||||
|
||||
inline static void ggml_vec_reglu_bf16(const int n, ggml_bf16_t * y, const ggml_bf16_t * x, const ggml_bf16_t * g) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
float v = GGML_BF16_TO_FP32(x[i]);
|
||||
y[i] = GGML_FP32_TO_BF16((v > 0.f) ? v * GGML_BF16_TO_FP32(g[i]) : 0.f);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GGML_GELU_FP16
|
||||
inline static void ggml_vec_geglu_f32(const int n, float * y, const float * x, const float * g) {
|
||||
uint16_t t;
|
||||
@@ -1442,6 +1474,12 @@ inline static void ggml_vec_geglu_f16(const int n, ggml_fp16_t * y, const ggml_f
|
||||
}
|
||||
}
|
||||
|
||||
inline static void ggml_vec_geglu_bf16(const int n, ggml_bf16_t * y, const ggml_bf16_t * x, const ggml_bf16_t * g) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
y[i] = GGML_FP32_TO_BF16(ggml_gelu_f32(GGML_BF16_TO_FP32(x[i])) * GGML_BF16_TO_FP32(g[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void ggml_vec_swiglu_f32(const int n, float * y, const float * x, const float * g);
|
||||
|
||||
inline static void ggml_vec_swiglu_f16(const int n, ggml_fp16_t * y, const ggml_fp16_t * x, const ggml_fp16_t * g) {
|
||||
@@ -1452,6 +1490,14 @@ inline static void ggml_vec_swiglu_f16(const int n, ggml_fp16_t * y, const ggml_
|
||||
}
|
||||
}
|
||||
|
||||
inline static void ggml_vec_swiglu_bf16(const int n, ggml_bf16_t * y, const ggml_bf16_t * x, const ggml_bf16_t * g) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
float xi = GGML_BF16_TO_FP32(x[i]);
|
||||
float gi = GGML_BF16_TO_FP32(g[i]);
|
||||
y[i] = GGML_FP32_TO_BF16((xi/(1.0f + expf(-xi))) * gi);
|
||||
}
|
||||
}
|
||||
|
||||
inline static void ggml_vec_geglu_erf_f32(const int n, float * y, const float * x, const float * g) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
float xi = x[i];
|
||||
@@ -1467,6 +1513,14 @@ inline static void ggml_vec_geglu_erf_f16(const int n, ggml_fp16_t * y, const gg
|
||||
}
|
||||
}
|
||||
|
||||
inline static void ggml_vec_geglu_erf_bf16(const int n, ggml_bf16_t * y, const ggml_bf16_t * x, const ggml_bf16_t * g) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
float xi = GGML_BF16_TO_FP32(x[i]);
|
||||
float gi = GGML_BF16_TO_FP32(g[i]);
|
||||
y[i] = GGML_FP32_TO_BF16(0.5f * xi * (1.0f + erff(xi*SQRT_2_INV)) * gi);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GGML_GELU_QUICK_FP16
|
||||
inline static void ggml_vec_geglu_quick_f32(const int n, float * y, const float * x, const float * g) {
|
||||
uint16_t t;
|
||||
@@ -1492,6 +1546,12 @@ inline static void ggml_vec_geglu_quick_f16(const int n, ggml_fp16_t * y, const
|
||||
}
|
||||
}
|
||||
|
||||
inline static void ggml_vec_geglu_quick_bf16(const int n, ggml_bf16_t * y, const ggml_bf16_t * x, const ggml_bf16_t * g) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
y[i] = GGML_FP32_TO_BF16(ggml_gelu_quick_f32(GGML_BF16_TO_FP32(x[i])) * GGML_BF16_TO_FP32(g[i]));
|
||||
}
|
||||
}
|
||||
|
||||
inline static void ggml_vec_sum_f32(const int n, float * s, const float * x) {
|
||||
#ifndef GGML_USE_ACCELERATE
|
||||
ggml_float sum = 0.0;
|
||||
|
||||
@@ -71,14 +71,13 @@ if (CUDAToolkit_FOUND)
|
||||
|
||||
enable_language(CUDA)
|
||||
|
||||
# TODO: Remove once CCCL 3.2 has been released and bundled with CUDA Toolkit
|
||||
if (GGML_CUDA_CUB_3DOT2)
|
||||
if (GGML_CUDA_CCCL_VERSION)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
CCCL
|
||||
GIT_REPOSITORY https://github.com/nvidia/cccl.git
|
||||
GIT_TAG v3.2.0
|
||||
GIT_TAG "${GGML_CUDA_CCCL_VERSION}"
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
|
||||
@@ -157,14 +156,15 @@ if (CUDAToolkit_FOUND)
|
||||
add_compile_definitions(GGML_CUDA_NO_PEER_COPY)
|
||||
endif()
|
||||
|
||||
if (GGML_CUDA_CCCL_VERSION)
|
||||
target_link_libraries(ggml-cuda PRIVATE CCCL::CCCL)
|
||||
endif()
|
||||
|
||||
if (GGML_STATIC)
|
||||
if (WIN32)
|
||||
# As of 12.3.1 CUDA Toolkit for Windows does not offer a static cublas library
|
||||
target_link_libraries(ggml-cuda PRIVATE CUDA::cudart_static CUDA::cublas)
|
||||
else ()
|
||||
if (GGML_CUDA_CUB_3DOT2)
|
||||
target_link_libraries(ggml-cuda PRIVATE CCCL::CCCL)
|
||||
endif()
|
||||
if (CUDAToolkit_VERSION VERSION_GREATER_EQUAL "10.1")
|
||||
target_link_libraries(ggml-cuda PRIVATE CUDA::cudart_static CUDA::cublas_static CUDA::cublasLt_static)
|
||||
else()
|
||||
@@ -172,9 +172,6 @@ if (CUDAToolkit_FOUND)
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
if (GGML_CUDA_CUB_3DOT2)
|
||||
target_link_libraries(ggml-cuda PRIVATE CCCL::CCCL)
|
||||
endif()
|
||||
target_link_libraries(ggml-cuda PRIVATE CUDA::cudart CUDA::cublas)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -166,52 +166,62 @@ static inline __device__ void ggml_cuda_swap(T & a, T & b) {
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
// One compare-exchange of the bitonic network at (k, j) for column col.
|
||||
template<ggml_sort_order order>
|
||||
static __global__ void k_argsort_f32_i32(const float * x, int * dst, const int ncols, int ncols_pad) {
|
||||
// bitonic sort
|
||||
int col = threadIdx.x;
|
||||
int row = blockIdx.x;
|
||||
|
||||
if (col >= ncols_pad) {
|
||||
static inline __device__ void bitonic_step(const float * x_row, int * dst_row, const int ncols, const int col, const int k, const int j) {
|
||||
const int ixj = col ^ j;
|
||||
if (ixj <= col) {
|
||||
return;
|
||||
}
|
||||
if ((col & k) == 0) {
|
||||
if (dst_row[col] >= ncols ||
|
||||
(dst_row[ixj] < ncols && (order == GGML_SORT_ORDER_ASC ?
|
||||
x_row[dst_row[col]] > x_row[dst_row[ixj]] :
|
||||
x_row[dst_row[col]] < x_row[dst_row[ixj]]))
|
||||
) {
|
||||
ggml_cuda_swap(dst_row[col], dst_row[ixj]);
|
||||
}
|
||||
} else {
|
||||
if (dst_row[ixj] >= ncols ||
|
||||
(dst_row[col] < ncols && (order == GGML_SORT_ORDER_ASC ?
|
||||
x_row[dst_row[col]] < x_row[dst_row[ixj]] :
|
||||
x_row[dst_row[col]] > x_row[dst_row[ixj]]))
|
||||
) {
|
||||
ggml_cuda_swap(dst_row[col], dst_row[ixj]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bitonic sort of one row per block. Each thread owns the columns
|
||||
// threadIdx.x + i * blockDim.x, so rows wider than the block (up to the
|
||||
// shared memory limit) sort with several columns per thread. Every
|
||||
// (k, j) stage runs all owned columns before the barrier; a pair
|
||||
// (col, col ^ j) is exchanged by the owner of its lower index only.
|
||||
template<ggml_sort_order order>
|
||||
static __global__ void k_argsort_f32_i32(const float * x, int * dst, const int ncols, int ncols_pad) {
|
||||
const int row = blockIdx.x;
|
||||
|
||||
const float * x_row = x + row * ncols;
|
||||
extern __shared__ int dst_row[];
|
||||
|
||||
// initialize indices
|
||||
dst_row[col] = col;
|
||||
for (int col = threadIdx.x; col < ncols_pad; col += blockDim.x) {
|
||||
dst_row[col] = col;
|
||||
}
|
||||
|
||||
__syncthreads();
|
||||
|
||||
for (int k = 2; k <= ncols_pad; k *= 2) {
|
||||
for (int j = k / 2; j > 0; j /= 2) {
|
||||
int ixj = col ^ j;
|
||||
if (ixj > col) {
|
||||
if ((col & k) == 0) {
|
||||
if (dst_row[col] >= ncols ||
|
||||
(dst_row[ixj] < ncols && (order == GGML_SORT_ORDER_ASC ?
|
||||
x_row[dst_row[col]] > x_row[dst_row[ixj]] :
|
||||
x_row[dst_row[col]] < x_row[dst_row[ixj]]))
|
||||
) {
|
||||
ggml_cuda_swap(dst_row[col], dst_row[ixj]);
|
||||
}
|
||||
} else {
|
||||
if (dst_row[ixj] >= ncols ||
|
||||
(dst_row[col] < ncols && (order == GGML_SORT_ORDER_ASC ?
|
||||
x_row[dst_row[col]] < x_row[dst_row[ixj]] :
|
||||
x_row[dst_row[col]] > x_row[dst_row[ixj]]))
|
||||
) {
|
||||
ggml_cuda_swap(dst_row[col], dst_row[ixj]);
|
||||
}
|
||||
}
|
||||
for (int col = threadIdx.x; col < ncols_pad; col += blockDim.x) {
|
||||
bitonic_step<order>(x_row, dst_row, ncols, col, k, j);
|
||||
}
|
||||
__syncthreads();
|
||||
}
|
||||
}
|
||||
|
||||
// copy the result to dst without the padding
|
||||
if (col < ncols) {
|
||||
for (int col = threadIdx.x; col < ncols; col += blockDim.x) {
|
||||
dst[row * ncols + col] = dst_row[col];
|
||||
}
|
||||
}
|
||||
@@ -233,7 +243,9 @@ void argsort_f32_i32_cuda_bitonic(const float * x,
|
||||
// bitonic sort requires ncols to be power of 2
|
||||
const int ncols_pad = next_power_of_2(ncols);
|
||||
|
||||
const dim3 block_dims(ncols_pad, 1, 1);
|
||||
// one thread per column up to the block limit, several columns per
|
||||
// thread beyond it; shared memory is the remaining bound
|
||||
const dim3 block_dims(ncols_pad < CUDA_ARGSORT_BLOCK_SIZE ? ncols_pad : CUDA_ARGSORT_BLOCK_SIZE, 1, 1);
|
||||
const dim3 block_nums(nrows, 1, 1);
|
||||
const size_t shared_mem = ncols_pad * sizeof(int);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "common.cuh"
|
||||
|
||||
#define CUDA_ARGSORT_BLOCK_SIZE 1024
|
||||
|
||||
void ggml_cuda_op_argsort(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
|
||||
|
||||
#ifdef GGML_CUDA_USE_CUB
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "binbcast.cuh"
|
||||
#include "convert.cuh"
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
@@ -82,14 +83,14 @@ static __global__ void k_bin_bcast(const src0_t * src0,
|
||||
for (uint32_t i0 = i0s; i0 < ne0; i0 += s0) {
|
||||
const uint32_t i10 = fastmodulo(i0, ne10);
|
||||
|
||||
float result = src0_row ? (float) src0_row[size_t(i0)*s00] : 0.0f;
|
||||
float result = src0_row ? ggml_cuda_cast<float>(src0_row[size_t(i0)*s00]) : 0.0f;
|
||||
if constexpr (sizeof...(src1_ptrs) > 0) {
|
||||
result = (..., (result = bin_op(result, (float)src1s[i_src1 + size_t(i10)*s10])));
|
||||
result = (..., (result = bin_op(result, ggml_cuda_cast<float>(src1s[i_src1 + size_t(i10)*s10]))));
|
||||
} else {
|
||||
result = bin_op(result, (float)src1[i_src1 + size_t(i10)*s10]);
|
||||
result = bin_op(result, ggml_cuda_cast<float>(src1[i_src1 + size_t(i10)*s10]));
|
||||
}
|
||||
|
||||
dst_row[i0] = (dst_t) result;
|
||||
dst_row[i0] = ggml_cuda_cast<dst_t>(result);
|
||||
|
||||
// protect i0 from overflow
|
||||
if (ne0 - i0 <= s0) {
|
||||
@@ -154,14 +155,14 @@ static __global__ void k_bin_bcast_unravel(const src0_t * src0,
|
||||
const uint32_t i10 = fastmodulo(i0, ne10);
|
||||
|
||||
ggml_cuda_pdl_sync();
|
||||
float result = src0_row ? (float) src0_row[size_t(i0)*s00] : 0.0f;
|
||||
float result = src0_row ? ggml_cuda_cast<float>(src0_row[size_t(i0)*s00]) : 0.0f;
|
||||
if constexpr (sizeof...(src1_ptrs) > 0) {
|
||||
result = (..., (result = bin_op(result, (float)src1s[i_src1 + size_t(i10)*s10])));
|
||||
result = (..., (result = bin_op(result, ggml_cuda_cast<float>(src1s[i_src1 + size_t(i10)*s10]))));
|
||||
} else {
|
||||
result = bin_op(result, (float)src1[i_src1 + size_t(i10)*s10]);
|
||||
result = bin_op(result, ggml_cuda_cast<float>(src1[i_src1 + size_t(i10)*s10]));
|
||||
}
|
||||
|
||||
dst_row[i0] = (dst_t) result;
|
||||
dst_row[i0] = ggml_cuda_cast<dst_t>(result);
|
||||
}
|
||||
|
||||
template <float (*bin_op)(const float, const float), typename src0_t, typename src1_t, typename dst_t, size_t... I>
|
||||
@@ -413,10 +414,14 @@ static void ggml_cuda_op_bin_bcast(
|
||||
const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst,
|
||||
const void * src0_dd, const void * src1_dd, void * dst_dd, cudaStream_t stream) {
|
||||
|
||||
GGML_ASSERT(src1->type == GGML_TYPE_F32 || src1->type == GGML_TYPE_F16);
|
||||
GGML_ASSERT(src1->type == GGML_TYPE_F32 || src1->type == GGML_TYPE_F16 || src1->type == GGML_TYPE_BF16);
|
||||
|
||||
if (src0->type == GGML_TYPE_F32 && dst->type == GGML_TYPE_F32) {
|
||||
if (src0->type == GGML_TYPE_F32 && src1->type != GGML_TYPE_BF16 && dst->type == GGML_TYPE_F32) {
|
||||
op()(src0, src1, dst, (const float *)src0_dd, (const float *)src1_dd, (float *)dst_dd, stream);
|
||||
} else if (src0->type == GGML_TYPE_BF16 && src1->type == GGML_TYPE_BF16 && dst->type == GGML_TYPE_BF16) {
|
||||
op()(src0, src1, dst, (const nv_bfloat16 *) src0_dd, (const nv_bfloat16 *) src1_dd, (nv_bfloat16 *) dst_dd, stream);
|
||||
} else if (src0->type == GGML_TYPE_BF16 && src1->type == GGML_TYPE_F32 && dst->type == GGML_TYPE_BF16) {
|
||||
op()(src0, src1, dst, (const nv_bfloat16 *) src0_dd, (const float *) src1_dd, (nv_bfloat16 *) dst_dd, stream);
|
||||
} else if (src0->type == GGML_TYPE_F16 && src1->type == GGML_TYPE_F16 && dst->type == GGML_TYPE_F16) {
|
||||
op()(src0, src1, dst, (const half *) src0_dd, (const half *)src1_dd, (half *) dst_dd, stream);
|
||||
} else if (src0->type == GGML_TYPE_F16 && src1->type == GGML_TYPE_F32 && dst->type == GGML_TYPE_F16) {
|
||||
@@ -457,10 +462,18 @@ static void ggml_cuda_op_fused_binbcast_impl(ggml_backend_cuda_context & ctx, gg
|
||||
const ggml_tensor * src0 = dst->src[0];
|
||||
const ggml_tensor * src1 = dst->src[1];
|
||||
|
||||
if (src0->type == GGML_TYPE_F32 && dst->type == GGML_TYPE_F32) {
|
||||
if (src0->type == GGML_TYPE_F32 && src1->type != GGML_TYPE_BF16 && dst->type == GGML_TYPE_F32) {
|
||||
launch_bin_bcast_pack<op, float, float, float>(src0, src1, dst,
|
||||
(const float *) src0->data, (const float *) src1->data, (float *) dst->data,
|
||||
stream, std::make_index_sequence<n_fuse>{});
|
||||
} else if (src0->type == GGML_TYPE_BF16 && src1->type == GGML_TYPE_BF16 && dst->type == GGML_TYPE_BF16) {
|
||||
launch_bin_bcast_pack<op, nv_bfloat16, nv_bfloat16, nv_bfloat16>(src0, src1, dst,
|
||||
(const nv_bfloat16 *) src0->data, (const nv_bfloat16 *) src1->data, (nv_bfloat16 *) dst->data,
|
||||
stream, std::make_index_sequence<n_fuse>{});
|
||||
} else if (src0->type == GGML_TYPE_BF16 && src1->type == GGML_TYPE_F32 && dst->type == GGML_TYPE_BF16) {
|
||||
launch_bin_bcast_pack<op, nv_bfloat16, float, nv_bfloat16>(src0, src1, dst,
|
||||
(const nv_bfloat16 *) src0->data, (const float *) src1->data, (nv_bfloat16 *) dst->data,
|
||||
stream, std::make_index_sequence<n_fuse>{});
|
||||
} else if (src0->type == GGML_TYPE_F16 && src1->type == GGML_TYPE_F16 && dst->type == GGML_TYPE_F16) {
|
||||
launch_bin_bcast_pack<op, half, half, half>(src0, src1, dst,
|
||||
(const half *) src0->data, (const half *) src1->data, (half *) dst->data,
|
||||
|
||||
@@ -131,15 +131,15 @@ static __device__ __forceinline__ void ggml_cuda_syncwarp() {
|
||||
}
|
||||
|
||||
static __device__ __forceinline__ void ggml_cuda_pdl_sync() {
|
||||
#if defined(GGML_CUDA_USE_PDL) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= GGML_CUDA_CC_HOPPER
|
||||
#if defined(GGML_CUDA_USE_PDL) && __CUDA_ARCH__ >= GGML_CUDA_CC_HOPPER
|
||||
cudaGridDependencySynchronize();
|
||||
#endif // defined(GGML_CUDA_USE_PDL) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= GGML_CUDA_CC_HOPPER
|
||||
#endif // defined(GGML_CUDA_USE_PDL) && __CUDA_ARCH__ >= GGML_CUDA_CC_HOPPER
|
||||
}
|
||||
|
||||
static __device__ __forceinline__ void ggml_cuda_pdl_lc() {
|
||||
#if defined(GGML_CUDA_USE_PDL) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= GGML_CUDA_CC_HOPPER
|
||||
#if defined(GGML_CUDA_USE_PDL) && __CUDA_ARCH__ >= GGML_CUDA_CC_HOPPER
|
||||
cudaTriggerProgrammaticLaunchCompletion();
|
||||
#endif // defined(GGML_CUDA_USE_PDL) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= GGML_CUDA_CC_HOPPER
|
||||
#endif // defined(GGML_CUDA_USE_PDL) && __CUDA_ARCH__ >= GGML_CUDA_CC_HOPPER
|
||||
}
|
||||
|
||||
#ifdef __CUDA_ARCH_LIST__
|
||||
@@ -285,21 +285,21 @@ static const char * cu_get_error_str(CUresult err) {
|
||||
#define VOLTA_MMA_AVAILABLE
|
||||
#endif // !defined(GGML_USE_HIP) && __CUDA_ARCH__ == GGML_CUDA_CC_VOLTA
|
||||
|
||||
#if !defined(GGML_USE_HIP) && __CUDA_ARCH__ >= GGML_CUDA_CC_TURING
|
||||
#if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA) && __CUDA_ARCH__ >= GGML_CUDA_CC_TURING
|
||||
#define TURING_MMA_AVAILABLE
|
||||
#endif // !defined(GGML_USE_HIP) && __CUDA_ARCH__ >= GGML_CUDA_CC_TURING
|
||||
#endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA) && __CUDA_ARCH__ >= GGML_CUDA_CC_TURING
|
||||
|
||||
#if !defined(GGML_USE_HIP) && __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
|
||||
#if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA) && __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
|
||||
#define AMPERE_MMA_AVAILABLE
|
||||
#endif // !defined(GGML_USE_HIP) && __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
|
||||
#endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA) && __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
|
||||
|
||||
#if !defined(GGML_USE_HIP) && __CUDA_ARCH__ >= GGML_CUDA_CC_BLACKWELL && __CUDA_ARCH__ < GGML_CUDA_CC_RUBIN
|
||||
# define BLACKWELL_MMA_AVAILABLE
|
||||
#endif // !defined(GGML_USE_HIP) && __CUDA_ARCH__ >= GGML_CUDA_CC_BLACKWELL
|
||||
|
||||
#if !defined(GGML_USE_HIP) && __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
|
||||
#if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA) && __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
|
||||
#define CP_ASYNC_AVAILABLE
|
||||
#endif // !defined(GGML_USE_HIP) && __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
|
||||
#endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA) && __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
|
||||
|
||||
#if !defined(GGML_CUDA_NO_FA) && !(defined(GGML_USE_MUSA) && __MUSA_ARCH__ < 220)
|
||||
#define FLASH_ATTN_AVAILABLE
|
||||
@@ -453,7 +453,7 @@ struct ggml_cuda_unroll<1> {
|
||||
|
||||
template<int width = WARP_SIZE>
|
||||
static __device__ __forceinline__ int warp_reduce_sum(int x) {
|
||||
#if !defined(GGML_USE_HIP) && __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
|
||||
#if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA) && __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
|
||||
return __reduce_add_sync(0xffffffff, x);
|
||||
#else
|
||||
#pragma unroll
|
||||
@@ -461,7 +461,7 @@ static __device__ __forceinline__ int warp_reduce_sum(int x) {
|
||||
x += __shfl_xor_sync(0xffffffff, x, offset, width);
|
||||
}
|
||||
return x;
|
||||
#endif // !defined(GGML_USE_HIP) && __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
|
||||
#endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA) && __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
|
||||
}
|
||||
|
||||
template<int width = WARP_SIZE>
|
||||
@@ -1680,11 +1680,11 @@ static bool ggml_cuda_kernel_can_use_pdl(const void * kernel) {
|
||||
#endif //defined(GGML_CUDA_USE_PDL)
|
||||
|
||||
// PDL and __restrict__ need to be mutually exclusive, see https://github.com/ggml-org/llama.cpp/pull/24030
|
||||
# if (defined(GGML_CUDA_USE_PDL) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= GGML_CUDA_CC_HOPPER)
|
||||
# if (defined(GGML_CUDA_USE_PDL) && __CUDA_ARCH__ >= GGML_CUDA_CC_HOPPER)
|
||||
# define GGML_CUDA_RESTRICT
|
||||
# else
|
||||
# define GGML_CUDA_RESTRICT __restrict__
|
||||
# endif // defined(GGML_CUDA_USE_PDL) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= GGML_CUDA_CC_HOPPER
|
||||
# endif // defined(GGML_CUDA_USE_PDL) && __CUDA_ARCH__ >= GGML_CUDA_CC_HOPPER
|
||||
|
||||
template<typename Kernel, typename... Args>
|
||||
static __inline__ void ggml_cuda_kernel_launch(Kernel kernel, const ggml_cuda_kernel_launch_params & launch_params, Args&&... args) {
|
||||
|
||||
@@ -223,9 +223,14 @@ static __global__ void dequantize_block_iq1_m(const void * __restrict__ vx, dst_
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_iq4_nl(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
static __global__ void dequantize_block_iq4_nl(const void * __restrict__ vx, dst_t * __restrict__ yy, int nb32) {
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
const int64_t ib = 8*i + threadIdx.x%8;
|
||||
if (ib >= nb32) {
|
||||
return;
|
||||
}
|
||||
|
||||
dequantize_iq4_nl(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
@@ -352,8 +357,9 @@ static void dequantize_row_iq1_s_cuda(const void * vx, dst_t * y, const int64_t
|
||||
|
||||
template<typename dst_t>
|
||||
static void dequantize_row_iq4_nl_cuda(const void * vx, dst_t * y, const int64_t k, cudaStream_t stream) {
|
||||
const int nb32 = k / QK4_NL;
|
||||
const int nb = (k + QK_K - 1) / QK_K;
|
||||
dequantize_block_iq4_nl<<<nb, 32, 0, stream>>>(vx, y);
|
||||
dequantize_block_iq4_nl<<<nb, 32, 0, stream>>>(vx, y, nb32);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
|
||||
@@ -45,11 +45,11 @@ template<typename dst_t, typename src_t>
|
||||
#ifdef GGML_USE_HIP
|
||||
return make_float2(__bfloat162float(__low2bfloat16(x)), __bfloat162float(__high2bfloat16(x)));
|
||||
#else
|
||||
#if __CUDA_ARCH__ >= 800
|
||||
#if !defined(GGML_USE_MUSA) && __CUDA_ARCH__ >= 800
|
||||
return __bfloat1622float2(x);
|
||||
#else
|
||||
return make_float2(__bfloat162float(x.x), __bfloat162float(x.y));
|
||||
#endif // __CUDA_ARCH__ >= 800
|
||||
#endif // !defined(GGML_USE_MUSA) && __CUDA_ARCH__ >= 800
|
||||
#endif // GGML_USE_HIP
|
||||
} else if constexpr(std::is_same_v<src_t, float2> && std::is_same_v<dst_t, nv_bfloat162>) {
|
||||
// bypass compile error on cuda 12.0.1
|
||||
|
||||
@@ -416,9 +416,14 @@ static __device__ __forceinline__ void dequantize_V_q4_0(const void * __restrict
|
||||
int q;
|
||||
static_assert(ne == 2 || ne == 4, "bad ne");
|
||||
ggml_cuda_memcpy_1<ne, 2>(&q, x[ib].qs + iqs);
|
||||
#if defined(GGML_USE_HIP)
|
||||
// Keep this VMEM read close to its packed-byte dequantization. Hoisting it too far
|
||||
// increases VGPR pressure substantially in some FlashAttention vector kernels.
|
||||
__builtin_amdgcn_sched_group_barrier(0x20, 1, 0);
|
||||
#endif // defined(GGML_USE_HIP)
|
||||
q >>= 4*shift;
|
||||
q &= 0x0F0F0F0F;
|
||||
q = __vsubss4(q, 0x08080808);
|
||||
q = __vsub4(q, 0x08080808);
|
||||
|
||||
const int8_t * q8 = (const int8_t *) &q;
|
||||
|
||||
@@ -508,7 +513,7 @@ static __device__ __forceinline__ void dequantize_V_q5_0(const void * __restrict
|
||||
}
|
||||
}
|
||||
|
||||
q = __vsubss4(q, 0x10101010);
|
||||
q = __vsub4(q, 0x10101010);
|
||||
|
||||
const int8_t * q8 = (const int8_t *) &q;
|
||||
|
||||
|
||||
@@ -365,7 +365,7 @@ static void ggml_cuda_flash_attn_ext_mma_f16(ggml_backend_cuda_context & ctx, gg
|
||||
|
||||
GGML_ASSERT(Q->ne[2] % K->ne[2] == 0);
|
||||
const int gqa_ratio = Q->ne[2] / K->ne[2];
|
||||
if (gqa_ratio == 20) { // GLM 4.7 Flash
|
||||
if (gqa_ratio == 20 && GGML_CUDA_CC_IS_NVIDIA(cc)) { // GLM 4.7 Flash
|
||||
if (cc >= GGML_CUDA_CC_DGX_SPARK) {
|
||||
if (Q->ne[1] <= 8) {
|
||||
ggml_cuda_flash_attn_ext_mma_f16_switch_ncols1<576, 512, 16>(ctx, dst);
|
||||
|
||||
@@ -1616,6 +1616,7 @@ static void ggml_cuda_mul_mat_cublas_impl(ggml_backend_cuda_context & ctx, const
|
||||
|
||||
static void ggml_cuda_mul_mat_cublas(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) {
|
||||
const int cc = ggml_cuda_info().devices[ctx.device].cc;
|
||||
const ggml_prec prec = (ggml_prec) ggml_get_op_params_i32(dst, 0);
|
||||
ggml_type compute_type = src0->type;
|
||||
if (ggml_is_quantized(compute_type)) {
|
||||
compute_type = fast_fp16_hardware_available(cc) ? GGML_TYPE_F16 : GGML_TYPE_F32;
|
||||
@@ -1629,7 +1630,10 @@ static void ggml_cuda_mul_mat_cublas(ggml_backend_cuda_context & ctx, const ggml
|
||||
compute_type = GGML_TYPE_F32;
|
||||
}
|
||||
}
|
||||
if (dst->op_params[0] == GGML_PREC_F32) {
|
||||
// F16 is the only compute type that can not satisfy a request for BF16
|
||||
if (prec == GGML_PREC_BF16 && compute_type == GGML_TYPE_F16) {
|
||||
compute_type = fast_bf16_hardware_available(cc) ? GGML_TYPE_BF16 : GGML_TYPE_F32;
|
||||
} else if (prec == GGML_PREC_F32) {
|
||||
compute_type = GGML_TYPE_F32;
|
||||
}
|
||||
|
||||
@@ -2033,6 +2037,7 @@ static void ggml_cuda_mul_mat_id(ggml_backend_cuda_context & ctx, ggml_tensor *
|
||||
|
||||
ggml_tensor dst_slice;
|
||||
memset(&dst_slice, 0, sizeof(dst_slice));
|
||||
memcpy(dst_slice.op_params, dst->op_params, sizeof(dst_slice.op_params));
|
||||
dst_slice.buffer = dst->buffer;
|
||||
dst_slice.type = type_dst_sorted;
|
||||
dst_slice.ne[0] = ne0;
|
||||
@@ -3371,7 +3376,7 @@ static bool ggml_cuda_can_fuse(const struct ggml_cgraph * cgraph,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (unary->type != GGML_TYPE_F32 && unary->type != GGML_TYPE_F16) {
|
||||
if (unary->type != GGML_TYPE_F32 && unary->type != GGML_TYPE_F16 && unary->type != GGML_TYPE_BF16) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3420,8 +3425,10 @@ static bool ggml_cuda_can_fuse(const struct ggml_cgraph * cgraph,
|
||||
const ggml_tensor *tanh = cgraph->nodes[node_idx+1];
|
||||
const ggml_tensor *scale2 = cgraph->nodes[node_idx+2];
|
||||
|
||||
GGML_ASSERT(scale->src[0]->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(scale->type == GGML_TYPE_F32);
|
||||
// the fused softcap kernel is F32 only
|
||||
if (scale->src[0]->type != GGML_TYPE_F32 || scale->type != GGML_TYPE_F32) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ggml_get_unary_op(tanh) != GGML_UNARY_OP_TANH) {
|
||||
return false;
|
||||
@@ -5182,6 +5189,9 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
|
||||
case GGML_UNARY_OP_CEIL:
|
||||
case GGML_UNARY_OP_ROUND:
|
||||
case GGML_UNARY_OP_TRUNC:
|
||||
if (op->src[0]->type == GGML_TYPE_BF16 && ggml_get_unary_op(op) == GGML_UNARY_OP_XIELU) {
|
||||
return false;
|
||||
}
|
||||
// TODO: should become:
|
||||
//return ggml_is_contiguous_rows(op->src[0]);
|
||||
return ggml_is_contiguous(op->src[0]);
|
||||
@@ -5198,6 +5208,10 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
|
||||
case GGML_GLU_OP_GEGLU_ERF:
|
||||
case GGML_GLU_OP_GEGLU_QUICK:
|
||||
case GGML_GLU_OP_SWIGLU_CLAMP:
|
||||
if (op->src[0]->type == GGML_TYPE_BF16 &&
|
||||
(ggml_get_glu_op(op) == GGML_GLU_OP_SWIGLU_OAI || ggml_get_glu_op(op) == GGML_GLU_OP_SWIGLU_CLAMP)) {
|
||||
return false;
|
||||
}
|
||||
return ggml_is_contiguous_1(op->src[0]);
|
||||
default:
|
||||
return false;
|
||||
@@ -5467,7 +5481,6 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
|
||||
case GGML_OP_TRANSPOSE:
|
||||
case GGML_OP_ADD_ID:
|
||||
case GGML_OP_ADD1:
|
||||
case GGML_OP_SCALE:
|
||||
case GGML_OP_SQR:
|
||||
case GGML_OP_SQRT:
|
||||
case GGML_OP_SIN:
|
||||
@@ -5475,10 +5488,16 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
|
||||
case GGML_OP_CLAMP:
|
||||
case GGML_OP_LOG:
|
||||
return true;
|
||||
case GGML_OP_SCALE:
|
||||
return (op->src[0]->type == GGML_TYPE_F32 || op->src[0]->type == GGML_TYPE_BF16) && op->type == op->src[0]->type;
|
||||
case GGML_OP_ADD:
|
||||
case GGML_OP_SUB:
|
||||
case GGML_OP_MUL:
|
||||
case GGML_OP_DIV:
|
||||
if (op->src[0]->type == GGML_TYPE_BF16 || op->src[1]->type == GGML_TYPE_BF16 || op->type == GGML_TYPE_BF16) {
|
||||
return op->src[0]->type == GGML_TYPE_BF16 && op->type == GGML_TYPE_BF16 &&
|
||||
(op->src[1]->type == GGML_TYPE_BF16 || op->src[1]->type == GGML_TYPE_F32);
|
||||
}
|
||||
return (op->src[0]->type == GGML_TYPE_F32 || op->src[0]->type == GGML_TYPE_F16) &&
|
||||
(op->src[1]->type == GGML_TYPE_F32 || op->src[1]->type == GGML_TYPE_F16) &&
|
||||
(op->type == GGML_TYPE_F32 || op->type == GGML_TYPE_F16);
|
||||
@@ -5553,7 +5572,14 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
|
||||
#endif // defined(GGML_USE_HIP) || defined(GGML_CUDA_USE_CUB)
|
||||
case GGML_OP_ARGSORT:
|
||||
#ifndef GGML_CUDA_USE_CUB
|
||||
return op->src[0]->ne[0] <= 1024;
|
||||
{
|
||||
// bitonic path: the padded row must fit in shared memory
|
||||
int64_t ncols_pad = 1;
|
||||
while (ncols_pad < op->src[0]->ne[0]) {
|
||||
ncols_pad *= 2;
|
||||
}
|
||||
return ncols_pad * sizeof(int) <= ggml_cuda_info().devices[dev_ctx->device].smpb;
|
||||
}
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
||||
@@ -218,8 +218,8 @@ template <ggml_type type, int J, bool fallback> static __device__ __forceinline_
|
||||
const int qs0 = get_int_b2(bxi->qs, kqsx);
|
||||
|
||||
#if defined(AMD_MFMA_AVAILABLE) || defined(TURING_MMA_AVAILABLE) || defined(AMD_WMMA_AVAILABLE)
|
||||
x_qs[i*sram_stride + kbx*(2*QI4_0) + kqsx + 0] = __vsubss4((qs0 >> 0) & 0x0F0F0F0F, 0x08080808);
|
||||
x_qs[i*sram_stride + kbx*(2*QI4_0) + kqsx + QI4_0] = __vsubss4((qs0 >> 4) & 0x0F0F0F0F, 0x08080808);
|
||||
x_qs[i*sram_stride + kbx*(2*QI4_0) + kqsx + 0] = __vsub4((qs0 >> 0) & 0x0F0F0F0F, 0x08080808);
|
||||
x_qs[i*sram_stride + kbx*(2*QI4_0) + kqsx + QI4_0] = __vsub4((qs0 >> 4) & 0x0F0F0F0F, 0x08080808);
|
||||
#else
|
||||
x_qs[i*(MMQ_TILE_NE_K + 1) + txi] = qs0;
|
||||
#endif // defined(AMD_MFMA_AVAILABLE) || defined(TURING_MMA_AVAILABLE)
|
||||
@@ -350,14 +350,14 @@ template <ggml_type type, int J, bool fallback> static __device__ __forceinline_
|
||||
qs0 |= (qh << 11) & 0x00001000; // 1 -> 12
|
||||
qs0 |= (qh << 18) & 0x00100000; // 2 -> 20
|
||||
qs0 |= (qh << 25) & 0x10000000; // 3 -> 28
|
||||
qs0 = __vsubss4(qs0, 0x10101010); // subtract 16
|
||||
qs0 = __vsub4(qs0, 0x10101010); // subtract 16
|
||||
|
||||
int qs1 = (ql >> 4) & 0x0F0F0F0F;
|
||||
qs1 |= (qh >> 12) & 0x00000010; // 16 -> 4
|
||||
qs1 |= (qh >> 5) & 0x00001000; // 17 -> 12
|
||||
qs1 |= (qh << 2) & 0x00100000; // 18 -> 20
|
||||
qs1 |= (qh << 9) & 0x10000000; // 19 -> 28
|
||||
qs1 = __vsubss4(qs1, 0x10101010); // subtract 16
|
||||
qs1 = __vsub4(qs1, 0x10101010); // subtract 16
|
||||
|
||||
#if defined(AMD_MFMA_AVAILABLE) || defined(TURING_MMA_AVAILABLE) || defined(AMD_WMMA_AVAILABLE)
|
||||
x_qs[i*sram_stride + kbx*(2*QI5_0) + kqsx + 0] = qs0;
|
||||
@@ -636,7 +636,7 @@ template <ggml_type type, int J, bool fallback> static __device__ __forceinline_
|
||||
const int x_ql_k = (x_ql_0 >> (2*l)) & 0x03030303;
|
||||
const int x_qh_k = ((x_qh_0 >> l) << 2) & 0x04040404;
|
||||
|
||||
const int x_qs_k = __vsubss4(x_ql_k | x_qh_k, 0x04040404);
|
||||
const int x_qs_k = __vsub4(x_ql_k | x_qh_k, 0x04040404);
|
||||
|
||||
#if defined(AMD_MFMA_AVAILABLE) || defined(TURING_MMA_AVAILABLE) || defined(AMD_WMMA_AVAILABLE)
|
||||
x_qs[i*sram_stride + k] = x_qs_k;
|
||||
@@ -667,7 +667,7 @@ template <ggml_type type, int J, bool fallback> static __device__ __forceinline_
|
||||
const int shift_high = 2 * ksc;
|
||||
const int sc_high = ((get_int_b2(bxi->scales, ksc_high) >> shift_high) << 4) & 0x30303030;
|
||||
|
||||
const int sc = __vsubss4(sc_low | sc_high, 0x20202020);
|
||||
const int sc = __vsub4(sc_low | sc_high, 0x20202020);
|
||||
|
||||
#if defined(AMD_MFMA_AVAILABLE) || defined(TURING_MMA_AVAILABLE) || defined(AMD_WMMA_AVAILABLE)
|
||||
const int8_t * sc8 = (const int8_t *) ≻
|
||||
@@ -987,11 +987,11 @@ template <ggml_type type, int J, bool fallback> static __device__ __forceinline_
|
||||
const int kq1 = 2*txi - txi % (QI6_K/2) + QI6_K/2;
|
||||
|
||||
#if defined(AMD_MFMA_AVAILABLE) || defined(TURING_MMA_AVAILABLE) || defined(AMD_WMMA_AVAILABLE)
|
||||
x_qs[i*sram_stride + kq0] = __vsubss4(ql0 | qh0, 0x20202020);
|
||||
x_qs[i*sram_stride + kq1] = __vsubss4(ql1 | qh1, 0x20202020);
|
||||
x_qs[i*sram_stride + kq0] = __vsub4(ql0 | qh0, 0x20202020);
|
||||
x_qs[i*sram_stride + kq1] = __vsub4(ql1 | qh1, 0x20202020);
|
||||
#else
|
||||
x_qs[i*(2*MMQ_TILE_NE_K + 1) + kq0] = __vsubss4(ql0 | qh0, 0x20202020);
|
||||
x_qs[i*(2*MMQ_TILE_NE_K + 1) + kq1] = __vsubss4(ql1 | qh1, 0x20202020);
|
||||
x_qs[i*(2*MMQ_TILE_NE_K + 1) + kq0] = __vsub4(ql0 | qh0, 0x20202020);
|
||||
x_qs[i*(2*MMQ_TILE_NE_K + 1) + kq1] = __vsub4(ql1 | qh1, 0x20202020);
|
||||
#endif // defined(AMD_MFMA_AVAILABLE) || defined(TURING_MMA_AVAILABLE) || defined(AMD_WMMA_AVAILABLE)
|
||||
}
|
||||
|
||||
|
||||
@@ -284,9 +284,9 @@ static constexpr __device__ ggml_cuda_mmq_config ggml_cuda_mmq_get_config(ggml_t
|
||||
return ggml_cuda_mmq_get_config_ampere(type, J, fallback);
|
||||
}
|
||||
return ggml_cuda_mmq_get_config_blackwell(type, J, fallback);
|
||||
#elif __CUDA_ARCH__ >= GGML_CUDA_CC_VOLTA
|
||||
#elif !defined(GGML_USE_MUSA) && __CUDA_ARCH__ >= GGML_CUDA_CC_VOLTA
|
||||
return ggml_cuda_mmq_get_config_ampere(type, J, fallback);
|
||||
#elif __CUDA_ARCH__ >= GGML_CUDA_CC_DP4A
|
||||
#elif !defined(GGML_USE_MUSA) && __CUDA_ARCH__ >= GGML_CUDA_CC_DP4A
|
||||
return ggml_cuda_mmq_get_config_pascal_dp4a(type, J, fallback);
|
||||
#else
|
||||
return ggml_cuda_mmq_get_config_pascal_older(type, J, fallback);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// only enabled on DGX Spark, where it is a gain on every type below. On the higher-bandwidth parts the kernel
|
||||
// has little exposed latency left to hide and the extra requests cost more than they save.
|
||||
// For perf data, see https://github.com/ggml-org/llama.cpp/pull/26705#issuecomment-5569335031
|
||||
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ == GGML_CUDA_CC_DGX_SPARK
|
||||
#if __CUDA_ARCH__ == GGML_CUDA_CC_DGX_SPARK
|
||||
// returns true only for those quants that benefit from prefetch and false otherwise
|
||||
static constexpr __host__ __device__ bool mmvq_should_prefetch(ggml_type type) {
|
||||
switch (type) {
|
||||
@@ -112,9 +112,9 @@ static constexpr __device__ mmvq_parameter_table_id get_device_table_id() {
|
||||
return MMVQ_PARAMETERS_RDNA2;
|
||||
#elif defined(GCN) || defined(CDNA)
|
||||
return MMVQ_PARAMETERS_GCN;
|
||||
#elif defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= GGML_CUDA_CC_TURING && __CUDA_ARCH__ < GGML_CUDA_CC_AMPERE
|
||||
#elif __CUDA_ARCH__ >= GGML_CUDA_CC_VOLTA && __CUDA_ARCH__ < GGML_CUDA_CC_AMPERE
|
||||
return MMVQ_PARAMETERS_TURING;
|
||||
#elif defined(__CUDA_ARCH__) && __CUDA_ARCH__ == GGML_CUDA_CC_DGX_SPARK
|
||||
#elif __CUDA_ARCH__ == GGML_CUDA_CC_DGX_SPARK
|
||||
return MMVQ_PARAMETERS_GB10;
|
||||
#else
|
||||
return MMVQ_PARAMETERS_GENERIC;
|
||||
@@ -134,7 +134,7 @@ static __host__ mmvq_parameter_table_id get_device_table_id(int cc) {
|
||||
if (GGML_CUDA_CC_IS_GCN(cc) || GGML_CUDA_CC_IS_CDNA(cc)) {
|
||||
return MMVQ_PARAMETERS_GCN;
|
||||
}
|
||||
if (GGML_CUDA_CC_IS_NVIDIA(cc) && ggml_cuda_highest_compiled_arch(cc) >= GGML_CUDA_CC_TURING && ggml_cuda_highest_compiled_arch(cc) < GGML_CUDA_CC_AMPERE) {
|
||||
if (GGML_CUDA_CC_IS_NVIDIA(cc) && ggml_cuda_highest_compiled_arch(cc) >= GGML_CUDA_CC_VOLTA && ggml_cuda_highest_compiled_arch(cc) < GGML_CUDA_CC_AMPERE) {
|
||||
return MMVQ_PARAMETERS_TURING;
|
||||
}
|
||||
if (GGML_CUDA_CC_IS_NVIDIA(cc) && ggml_cuda_highest_compiled_arch(cc) == GGML_CUDA_CC_DGX_SPARK) {
|
||||
@@ -440,9 +440,9 @@ static constexpr __device__ int get_mmvq_mmid_max_batch_for_device() {
|
||||
return get_mmvq_mmid_max_batch_cdna(type);
|
||||
#elif defined(GCN)
|
||||
return get_mmvq_mmid_max_batch_gcn(type);
|
||||
#elif defined(__CUDA_ARCH__) && (__CUDA_ARCH__ == GGML_CUDA_CC_VOLTA || __CUDA_ARCH__ >= GGML_CUDA_CC_ADA_LOVELACE)
|
||||
#elif !defined(GGML_USE_MUSA) && (__CUDA_ARCH__ == GGML_CUDA_CC_VOLTA || __CUDA_ARCH__ >= GGML_CUDA_CC_ADA_LOVELACE)
|
||||
return MMVQ_MAX_BATCH_SIZE;
|
||||
#elif defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= GGML_CUDA_CC_TURING
|
||||
#elif !defined(GGML_USE_MUSA) && __CUDA_ARCH__ >= GGML_CUDA_CC_TURING
|
||||
return get_mmvq_mmid_max_batch_turing_plus(type);
|
||||
#else
|
||||
return get_mmvq_mmid_max_batch_pascal_older(type);
|
||||
@@ -718,7 +718,7 @@ static __global__ void mul_mat_vec_q(
|
||||
// x block quant index when casting the quants to int
|
||||
const int kqs = vdr * (tid % (qi/vdr));
|
||||
|
||||
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ == GGML_CUDA_CC_DGX_SPARK
|
||||
#if __CUDA_ARCH__ == GGML_CUDA_CC_DGX_SPARK
|
||||
// start the next iterations' weight loads early
|
||||
if constexpr (mmvq_should_prefetch(type)) {
|
||||
constexpr int pf_dist = 2; // loop iterations, not blocks
|
||||
|
||||
@@ -1,37 +1,42 @@
|
||||
#include "scale.cuh"
|
||||
#include "convert.cuh"
|
||||
|
||||
#define MAX_GRIDDIM_X 0x7FFFFFFF
|
||||
|
||||
static __global__ void scale_f32(const float * x, float * dst, const float scale, const float bias, const int64_t nelements) {
|
||||
template <typename T>
|
||||
static __global__ void scale_f32(const T * x, T * dst, const float scale, const float bias, const int64_t nelements) {
|
||||
ggml_cuda_pdl_lc();
|
||||
int64_t tid = (int64_t)blockIdx.x * (int64_t)blockDim.x + (int64_t)threadIdx.x;
|
||||
int64_t stride = (int64_t)blockDim.x * (int64_t)gridDim.x;
|
||||
|
||||
ggml_cuda_pdl_sync();
|
||||
for (int64_t i = tid; i < nelements; i += stride) {
|
||||
dst[i] = scale * x[i] + bias;
|
||||
dst[i] = ggml_cuda_cast<T>(scale * ggml_cuda_cast<float>(x[i]) + bias);
|
||||
}
|
||||
}
|
||||
|
||||
static void scale_f32_cuda(const float * x, float * dst, const float scale, const float bias, const int64_t nelements, cudaStream_t stream) {
|
||||
template <typename T>
|
||||
static void scale_f32_cuda(const T * x, T * dst, const float scale, const float bias, const int64_t nelements, cudaStream_t stream) {
|
||||
const int64_t num_blocks = (nelements + CUDA_SCALE_BLOCK_SIZE - 1) / CUDA_SCALE_BLOCK_SIZE;
|
||||
const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(MIN(MAX_GRIDDIM_X, num_blocks), CUDA_SCALE_BLOCK_SIZE, 0, stream);
|
||||
ggml_cuda_kernel_launch(scale_f32, launch_params, x, dst, scale, bias, nelements);
|
||||
ggml_cuda_kernel_launch(scale_f32<T>, launch_params, x, dst, scale, bias, nelements);
|
||||
}
|
||||
|
||||
void ggml_cuda_op_scale(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
|
||||
const ggml_tensor * src0 = dst->src[0];
|
||||
const float * src0_d = (const float *)src0->data;
|
||||
float * dst_d = (float *)dst->data;
|
||||
cudaStream_t stream = ctx.stream();
|
||||
|
||||
GGML_ASSERT(src0->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT( dst->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(src0->type == GGML_TYPE_F32 || src0->type == GGML_TYPE_BF16);
|
||||
GGML_ASSERT(dst->type == src0->type);
|
||||
|
||||
float scale;
|
||||
float bias;
|
||||
memcpy(&scale, (float *) dst->op_params + 0, sizeof(float));
|
||||
memcpy(&bias, (float *) dst->op_params + 1, sizeof(float));
|
||||
|
||||
scale_f32_cuda(src0_d, dst_d, scale, bias, ggml_nelements(src0), stream);
|
||||
if (src0->type == GGML_TYPE_BF16) {
|
||||
scale_f32_cuda((const nv_bfloat16 *) src0->data, (nv_bfloat16 *) dst->data, scale, bias, ggml_nelements(src0), stream);
|
||||
} else {
|
||||
scale_f32_cuda((const float *) src0->data, (float *) dst->data, scale, bias, ggml_nelements(src0), stream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,15 @@
|
||||
|
||||
#ifdef GGML_CUDA_USE_CUB
|
||||
# include <cub/cub.cuh>
|
||||
# if (CCCL_MAJOR_VERSION >= 3 && CCCL_MINOR_VERSION >= 2)
|
||||
// DeviceTopK has a race condition before CCCL 3.4.3.
|
||||
// https://github.com/NVIDIA/cccl/pull/10627
|
||||
# if (CCCL_MAJOR_VERSION > 3 || \
|
||||
(CCCL_MAJOR_VERSION == 3 && CCCL_MINOR_VERSION > 4) || \
|
||||
(CCCL_MAJOR_VERSION == 3 && CCCL_MINOR_VERSION == 4 && CCCL_PATCH_VERSION >= 3))
|
||||
# define CUB_TOP_K_AVAILABLE
|
||||
# include <cuda/iterator>
|
||||
using namespace cub;
|
||||
# endif // CCCL_MAJOR_VERSION >= 3 && CCCL_MINOR_VERSION >= 2
|
||||
# endif // CCCL >= 3.4.3
|
||||
#endif // GGML_CUDA_USE_CUB
|
||||
|
||||
#ifdef CUB_TOP_K_AVAILABLE
|
||||
|
||||
@@ -124,7 +124,7 @@ static __global__ void unary_op_kernel(const T * x, T * dst, const int k) {
|
||||
}
|
||||
|
||||
ggml_cuda_pdl_sync();
|
||||
dst[i] = (T)op((float)x[i]);
|
||||
dst[i] = ggml_cuda_cast<T>(op(ggml_cuda_cast<float>(x[i])));
|
||||
}
|
||||
|
||||
template <float (*op)(float), typename T>
|
||||
@@ -143,12 +143,13 @@ void ggml_cuda_op_unary(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
|
||||
|
||||
GGML_ASSERT(ggml_is_contiguous(src0));
|
||||
|
||||
GGML_ASSERT(src0->type == GGML_TYPE_F32 || src0->type == GGML_TYPE_F16);
|
||||
GGML_ASSERT( dst->type == GGML_TYPE_F32 || dst->type == GGML_TYPE_F16);
|
||||
GGML_ASSERT(src0->type == GGML_TYPE_F32 || src0->type == GGML_TYPE_F16 || src0->type == GGML_TYPE_BF16);
|
||||
GGML_ASSERT(src0->type == dst->type);
|
||||
|
||||
if (src0->type == GGML_TYPE_F16) {
|
||||
unary_cuda<op>((const half *)src0_d, (half *)dst_d, ggml_nelements(src0), stream);
|
||||
} else if (src0->type == GGML_TYPE_BF16) {
|
||||
unary_cuda<op>((const nv_bfloat16 *)src0_d, (nv_bfloat16 *)dst_d, ggml_nelements(src0), stream);
|
||||
} else {
|
||||
unary_cuda<op>((const float *)src0_d, (float *)dst_d, ggml_nelements(src0), stream);
|
||||
}
|
||||
@@ -273,7 +274,7 @@ static __global__ void unary_gated_op_kernel(const T * x, const T * g, T * dst,
|
||||
const int64_t j1 = o0 == o1 ? j0 : (i / n) * o1 + (i % n);
|
||||
|
||||
ggml_cuda_pdl_sync();
|
||||
dst[i] = (T)(op((float)x[j0]) * (float)g[j1]);
|
||||
dst[i] = ggml_cuda_cast<T>(op(ggml_cuda_cast<float>(x[j0])) * ggml_cuda_cast<float>(g[j1]));
|
||||
}
|
||||
|
||||
template <float (*op)(float), typename T>
|
||||
@@ -299,8 +300,7 @@ void ggml_cuda_op_unary_gated(ggml_backend_cuda_context & ctx, ggml_tensor * dst
|
||||
GGML_ASSERT(src0->nb[0] == ggml_element_size(src0));
|
||||
GGML_ASSERT(ggml_is_contiguous(dst));
|
||||
|
||||
GGML_ASSERT(src0->type == GGML_TYPE_F32 || src0->type == GGML_TYPE_F16);
|
||||
GGML_ASSERT( dst->type == GGML_TYPE_F32 || dst->type == GGML_TYPE_F16);
|
||||
GGML_ASSERT(src0->type == GGML_TYPE_F32 || src0->type == GGML_TYPE_F16 || src0->type == GGML_TYPE_BF16);
|
||||
GGML_ASSERT(src0->type == dst->type);
|
||||
GGML_ASSERT(dst->ne[0] == nc);
|
||||
GGML_ASSERT(ggml_nrows(dst) == ggml_nrows(src0));
|
||||
@@ -324,6 +324,16 @@ void ggml_cuda_op_unary_gated(ggml_backend_cuda_context & ctx, ggml_tensor * dst
|
||||
}
|
||||
|
||||
unary_gated_cuda<op>(src0_p, src1_p, (half *)dst_d, ggml_nelements(dst), nc, src0_o / sizeof(half), src1_o / sizeof(half), stream);
|
||||
} else if (src0->type == GGML_TYPE_BF16) {
|
||||
nv_bfloat16 * src0_p = (nv_bfloat16 *) src0_d;
|
||||
nv_bfloat16 * src1_p = (nv_bfloat16 *) src1_d;
|
||||
|
||||
if (!src1) {
|
||||
src0_p += swapped ? nc : 0;
|
||||
src1_p += swapped ? 0 : nc;
|
||||
}
|
||||
|
||||
unary_gated_cuda<op>(src0_p, src1_p, (nv_bfloat16 *)dst_d, ggml_nelements(dst), nc, src0_o / sizeof(nv_bfloat16), src1_o / sizeof(nv_bfloat16), stream);
|
||||
} else {
|
||||
float * src0_p = (float *) src0_d;
|
||||
float * src1_p = (float *) src1_d;
|
||||
@@ -664,7 +674,7 @@ static void ggml_cuda_op_unary_mul_impl(ggml_backend_cuda_context & ctx, ggml_te
|
||||
GGML_ASSERT(other_src->nb[0] == ggml_element_size(other_src));
|
||||
GGML_ASSERT(ggml_are_same_shape(unary_src, other_src));
|
||||
|
||||
GGML_ASSERT(unary_src->type == GGML_TYPE_F32 || unary_src->type == GGML_TYPE_F16);
|
||||
GGML_ASSERT(unary_src->type == GGML_TYPE_F32 || unary_src->type == GGML_TYPE_F16 || unary_src->type == GGML_TYPE_BF16);
|
||||
GGML_ASSERT(unary_src->type == other_src->type);
|
||||
GGML_ASSERT(unary_src->type == mul_node->type);
|
||||
|
||||
@@ -679,6 +689,10 @@ static void ggml_cuda_op_unary_mul_impl(ggml_backend_cuda_context & ctx, ggml_te
|
||||
unary_gated_cuda<op>((const half *) unary_src->data, (const half *) other_src->data,
|
||||
(half *) mul_node->data, k, nc,
|
||||
unary_stride / sizeof(half), other_stride / sizeof(half), stream);
|
||||
} else if (unary_src->type == GGML_TYPE_BF16) {
|
||||
unary_gated_cuda<op>((const nv_bfloat16 *) unary_src->data, (const nv_bfloat16 *) other_src->data,
|
||||
(nv_bfloat16 *) mul_node->data, k, nc,
|
||||
unary_stride / sizeof(nv_bfloat16), other_stride / sizeof(nv_bfloat16), stream);
|
||||
} else {
|
||||
unary_gated_cuda<op>((const float *) unary_src->data, (const float *) other_src->data,
|
||||
(float *) mul_node->data, k, nc,
|
||||
|
||||
@@ -471,7 +471,7 @@ static __device__ __forceinline__ float vec_dot_q3_K_q8_1_impl_mmvq(
|
||||
|
||||
const int vih = ((vh >> i) << 2) & 0x04040404;
|
||||
|
||||
const int vi = __vsubss4(vil, vih);
|
||||
const int vi = __vsub4(vil, vih);
|
||||
|
||||
sumf += d8[i] * (ggml_cuda_dp4a(vi, u[i], 0) * sc); // SIMD dot product
|
||||
}
|
||||
@@ -638,7 +638,7 @@ static __device__ __forceinline__ float vec_dot_q6_K_q8_1_impl_mmvq(
|
||||
|
||||
const int vih = ((vh >> (4*i)) << 4) & 0x30303030;
|
||||
|
||||
const int vi = __vsubss4((vil | vih), 0x20202020); // vi = (vil | vih) - 32
|
||||
const int vi = __vsub4((vil | vih), 0x20202020); // vi = (vil | vih) - 32
|
||||
|
||||
sumf += d8[i] * (ggml_cuda_dp4a(vi, u[i], 0) * sc); // SIMD dot product
|
||||
}
|
||||
|
||||
Vendored
+5
@@ -5,6 +5,11 @@
|
||||
#include <mublas.h>
|
||||
#include <musa_bf16.h>
|
||||
#include <musa_fp16.h>
|
||||
|
||||
#ifdef __MUSA_ARCH__
|
||||
#define __CUDA_ARCH__ 1300 // GGML_CUDA_CC_RUBIN
|
||||
#endif // __MUSA_ARCH__
|
||||
|
||||
#define CUBLAS_COMPUTE_16F CUDA_R_16F
|
||||
#define CUBLAS_COMPUTE_32F CUDA_R_32F
|
||||
#define CUBLAS_COMPUTE_32F_FAST_16F MUBLAS_COMPUTE_32F_FAST_16F
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if __has_include(<filesystem>)
|
||||
@@ -32,9 +33,7 @@ namespace fs = std::experimental::filesystem;
|
||||
* @brief prints the metadata of a single tensorf
|
||||
*/
|
||||
static void ggml_et_dump_tensor_metadata(const ggml_tensor * ggtensor, size_t indent_level, const char * title) {
|
||||
char * spaces = (char *) alloca(indent_level + 1);
|
||||
memset(spaces, ' ', indent_level);
|
||||
spaces[indent_level] = '\0';
|
||||
std::string spaces(indent_level, ' ');
|
||||
fprintf(stderr,
|
||||
"%s%s: %s\n"
|
||||
"%s type: %s\n"
|
||||
@@ -43,10 +42,10 @@ static void ggml_et_dump_tensor_metadata(const ggml_tensor * ggtensor, size_t in
|
||||
"%s op: %s\n"
|
||||
"%s data: %p\n"
|
||||
"%s src0: %p\n",
|
||||
spaces, title, ggtensor->name, spaces, ggml_type_name(ggtensor->type), spaces, (long long) ggtensor->ne[0],
|
||||
(long long) ggtensor->ne[1], (long long) ggtensor->ne[2], (long long) ggtensor->ne[3], spaces,
|
||||
ggtensor->nb[0], ggtensor->nb[1], ggtensor->nb[2], ggtensor->nb[3], spaces, ggml_op_name(ggtensor->op),
|
||||
spaces, ggtensor->data, spaces, (void *) ggtensor->src[0]);
|
||||
spaces.c_str(), title, ggtensor->name, spaces.c_str(), ggml_type_name(ggtensor->type), spaces.c_str(), (long long) ggtensor->ne[0],
|
||||
(long long) ggtensor->ne[1], (long long) ggtensor->ne[2], (long long) ggtensor->ne[3], spaces.c_str(),
|
||||
ggtensor->nb[0], ggtensor->nb[1], ggtensor->nb[2], ggtensor->nb[3], spaces.c_str(), ggml_op_name(ggtensor->op),
|
||||
spaces.c_str(), ggtensor->data, spaces.c_str(), (void *) ggtensor->src[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -99,10 +99,11 @@ static int opt_profile = 0; // profiling mode (0-disabled, 1-basic, 2-pmu)
|
||||
static bool opt_hostbuf = false;
|
||||
static bool opt_dma64 = false;
|
||||
|
||||
static int opt_mm_select = 2; // 2 = HMX -> HVX -> CPU, 1 = HVX -> CPU, 0 = CPU (unsupported)
|
||||
static int opt_fa_select = 2; // 2 = HMX -> HVX -> CPU, 1 = HVX -> CPU, 0 = CPU (unsupported)
|
||||
static int opt_mm_select = 2; // 2 = HMX -> HVX -> CPU, 1 = HVX -> CPU, 0 = CPU (unsupported)
|
||||
static int opt_fa_select = 2; // 2 = HMX -> HVX -> CPU, 1 = HVX -> CPU, 0 = CPU (unsupported)
|
||||
static int opt_gdn_select = 2; // 2 = HMX -> HVX, 1 = HVX, 0 = CPU (unsupported)
|
||||
static int opt_ar_select = 2; // 2 = fused ALLREDUCE+ADD (DMA, default), 1 = unfused ALLREDUCE (DMA), 0 = fallback to CPY+FENCE
|
||||
static int opt_ar_select = 2; // 2 = fused ALLREDUCE+ADD (default), 1 = unfused ALLREDUCE, 0 = fallback to CPY+FENCE
|
||||
static int opt_ar_scatter = 1; // 1 = reduce-scatter the fused ALLREDUCE+ADD (default), 0 = full reduction
|
||||
|
||||
// Default PMU events, if profiling with PMU (mode=2) is enabled
|
||||
// See https://docs.qualcomm.com/doc/80-N2040-60/topic/pmu-events.html
|
||||
@@ -400,6 +401,7 @@ static bool ggml_hexagon_precompute_allreduce_params(
|
||||
uint32_t n_ranks,
|
||||
bool has_add,
|
||||
bool is_row_bcast,
|
||||
bool is_shard_ok,
|
||||
struct htp_allreduce_kernel_params * kparams
|
||||
);
|
||||
|
||||
@@ -2795,22 +2797,33 @@ struct ggml_hexagon_opbatch {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t r = 0; r < n_ranks; r++) {
|
||||
const ggml_tensor * ar_src = last_node.inputs[r];
|
||||
if (ggml_hexagon_tensors_overlap(add_dst, ar_src)) {
|
||||
HEX_VERBOSE("ggml-hex: %s skip ALLREDUCE_ADD fusion: dst overlaps allreduce src %u\n", sess->c_name(), r);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// scatter is only valid for in-place add within max outputs
|
||||
const bool is_shard_ok = n_ranks <= HTP_OP_MAX_OUTPUTS && add_dst->data == ar_local->data;
|
||||
|
||||
struct htp_allreduce_kernel_params new_kparams;
|
||||
if (!ggml_hexagon_precompute_allreduce_params(
|
||||
sess, add_dst, (uint32_t) ar_kparams->rank, (uint32_t) ar_kparams->n_ranks, true, is_row_bcast, &new_kparams
|
||||
sess, add_dst, (uint32_t) ar_kparams->rank, (uint32_t) ar_kparams->n_ranks, true, is_row_bcast, is_shard_ok, &new_kparams
|
||||
)) {
|
||||
HEX_VERBOSE("ggml-hex: %s skip ALLREDUCE_ADD fusion: solver failed\n", sess->c_name());
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool scatter_ok = new_kparams.n_dsts > 1;
|
||||
new_kparams.mode = scatter_ok ? HTP_ALLREDUCE_SHARDED_FANOUT : HTP_ALLREDUCE_FULL;
|
||||
|
||||
for (uint32_t r = 0; r < n_ranks; r++) {
|
||||
const ggml_tensor * ar_src = last_node.inputs[r];
|
||||
if (!ggml_hexagon_tensors_overlap(add_dst, ar_src)) {
|
||||
continue;
|
||||
}
|
||||
// in-place aliasing is safe under reduce-scatter since each rank writes disjoint shards
|
||||
if (scatter_ok && r == rank) {
|
||||
continue;
|
||||
}
|
||||
HEX_VERBOSE("ggml-hex: %s skip ALLREDUCE_ADD fusion: dst overlaps allreduce src %u\n", sess->c_name(), r);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!try_fuse_common(res_tensor, add_dst)) {
|
||||
return false;
|
||||
}
|
||||
@@ -2828,12 +2841,25 @@ struct ggml_hexagon_opbatch {
|
||||
memcpy(o.kernel_params, &new_kparams, sizeof(new_kparams));
|
||||
|
||||
o.src[2 * n_ranks] = add_tensor(res_tensor);
|
||||
o.dst[0] = add_tensor(add_dst);
|
||||
for (uint32_t d = 1; d < HTP_OP_MAX_OUTPUTS; d++) {
|
||||
o.dst[d] = 0xffff;
|
||||
if (new_kparams.mode == HTP_ALLREDUCE_SHARDED_FANOUT) {
|
||||
// fan out shard to all per-rank partial buffers
|
||||
GGML_ASSERT((uint32_t) new_kparams.n_dsts == n_ranks);
|
||||
for (uint32_t d = 0; d < n_ranks; d++) {
|
||||
GGML_ASSERT(o.src[d] != 0xffff);
|
||||
o.dst[d] = o.src[d];
|
||||
}
|
||||
for (uint32_t d = n_ranks; d < HTP_OP_MAX_OUTPUTS; d++) {
|
||||
o.dst[d] = 0xffff;
|
||||
}
|
||||
} else {
|
||||
o.dst[0] = add_tensor(add_dst);
|
||||
for (uint32_t d = 1; d < HTP_OP_MAX_OUTPUTS; d++) {
|
||||
o.dst[d] = 0xffff;
|
||||
}
|
||||
}
|
||||
|
||||
HEX_VERBOSE("ggml-hex: %s fused ALLREDUCE+ADD (#%u)\n", sess->c_name(), n_ops - 1);
|
||||
HEX_VERBOSE("ggml-hex: %s fused ALLREDUCE+ADD (#%u) mode=%d n_dsts=%d\n",
|
||||
sess->c_name(), n_ops - 1, (int) new_kparams.mode, (int) new_kparams.n_dsts);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3774,6 +3800,7 @@ static bool ggml_hexagon_precompute_allreduce_params(
|
||||
uint32_t n_ranks,
|
||||
bool has_add,
|
||||
bool is_row_bcast,
|
||||
bool is_shard_ok,
|
||||
struct htp_allreduce_kernel_params * kparams
|
||||
) {
|
||||
memset(kparams, 0, sizeof(*kparams));
|
||||
@@ -3793,11 +3820,20 @@ static bool ggml_hexagon_precompute_allreduce_params(
|
||||
const bool use_1d = is_contiguous && !(has_add && is_row_bcast && ne1 > 1);
|
||||
|
||||
if (has_add) {
|
||||
kparams->n_dsts = 1;
|
||||
if (use_1d) {
|
||||
// sharded reduce-scatter for contiguous in-place add
|
||||
if (opt_ar_scatter && is_shard_ok && use_1d && !is_row_bcast) {
|
||||
const uint32_t rank_chunk_elems = hex_round_up((nelem + n_ranks - 1) / n_ranks, 128);
|
||||
const uint32_t rank_elem_start = (std::min)(rank * rank_chunk_elems, nelem);
|
||||
const uint32_t rank_elem_end = (std::min)(rank_elem_start + rank_chunk_elems, nelem);
|
||||
kparams->n_dsts = (int32_t) n_ranks;
|
||||
kparams->rank_elem_start = (int32_t) rank_elem_start;
|
||||
kparams->rank_nelem = (int32_t) (rank_elem_end - rank_elem_start);
|
||||
} else if (use_1d) {
|
||||
kparams->n_dsts = 1;
|
||||
kparams->rank_elem_start = 0;
|
||||
kparams->rank_nelem = (int32_t) nelem;
|
||||
} else {
|
||||
kparams->n_dsts = 1;
|
||||
kparams->rank_elem_start = 0;
|
||||
kparams->rank_nelem = (int32_t) ne1;
|
||||
}
|
||||
@@ -3820,6 +3856,8 @@ static bool ggml_hexagon_precompute_allreduce_params(
|
||||
}
|
||||
}
|
||||
|
||||
kparams->mode = (kparams->n_dsts > 1) ? HTP_ALLREDUCE_SHARDED_FANOUT : HTP_ALLREDUCE_FULL;
|
||||
|
||||
if (use_1d) {
|
||||
const uint32_t rank_nelem = (uint32_t) kparams->rank_nelem;
|
||||
const uint32_t n_threads = (std::min)((uint32_t) sess->n_threads, (std::max)(1u, rank_nelem / 128));
|
||||
@@ -3925,9 +3963,8 @@ void ggml_hexagon_session::enqueue_allreduce(
|
||||
}
|
||||
|
||||
ggml_hexagon_precompute_allreduce_params(
|
||||
this, dst, rank, n_ranks, false, false,
|
||||
(struct htp_allreduce_kernel_params *) ar_node.kernel_params
|
||||
);
|
||||
this, dst, rank, n_ranks, false, false, /*is_shard_ok=*/ false,
|
||||
(struct htp_allreduce_kernel_params *) ar_node.kernel_params);
|
||||
|
||||
ar_node.name = "ALLREDUCE";
|
||||
this->enqueue_op(ar_node);
|
||||
@@ -6037,10 +6074,10 @@ static bool ggml_hexagon_supported_activations(const struct ggml_hexagon_session
|
||||
const struct ggml_tensor * src1 = op->src[1];
|
||||
const struct ggml_tensor * dst = op;
|
||||
|
||||
if (src0->type != GGML_TYPE_F32) {
|
||||
if (src0->type != GGML_TYPE_F32 && src0->type != GGML_TYPE_F16) {
|
||||
return false;
|
||||
}
|
||||
if (dst->type != GGML_TYPE_F32) {
|
||||
if (dst->type != src0->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -6052,7 +6089,7 @@ static bool ggml_hexagon_supported_activations(const struct ggml_hexagon_session
|
||||
}
|
||||
|
||||
if (src1) {
|
||||
if (src1->type != GGML_TYPE_F32) {
|
||||
if (src1->type != src0->type) {
|
||||
return false;
|
||||
}
|
||||
if (!ggml_are_same_shape(src0, src1)) {
|
||||
@@ -6637,12 +6674,12 @@ static htp_op_code op_remap_to_htp(const ggml_tensor * t) {
|
||||
|
||||
case GGML_OP_GLU:
|
||||
switch (ggml_get_glu_op(t)) {
|
||||
case GGML_GLU_OP_SWIGLU: return HTP_OP_GLU_SWIGLU;
|
||||
case GGML_GLU_OP_SWIGLU_OAI: return HTP_OP_GLU_SWIGLU_OAI;
|
||||
case GGML_GLU_OP_SWIGLU: return HTP_OP_GLU_SWIGLU;
|
||||
case GGML_GLU_OP_SWIGLU_OAI: return HTP_OP_GLU_SWIGLU_OAI;
|
||||
case GGML_GLU_OP_SWIGLU_CLAMP: return HTP_OP_GLU_SWIGLU_CLAMP;
|
||||
case GGML_GLU_OP_GEGLU: return HTP_OP_GLU_GEGLU;
|
||||
case GGML_GLU_OP_GEGLU_QUICK: return HTP_OP_GLU_GEGLU_QUICK;
|
||||
case GGML_GLU_OP_GEGLU_ERF: return HTP_OP_GLU_GEGLU_ERF;
|
||||
case GGML_GLU_OP_GEGLU: return HTP_OP_GLU_GEGLU;
|
||||
case GGML_GLU_OP_GEGLU_QUICK: return HTP_OP_GLU_GEGLU_QUICK;
|
||||
case GGML_GLU_OP_GEGLU_ERF: return HTP_OP_GLU_GEGLU_ERF;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
@@ -7999,7 +8036,7 @@ static bool ggml_backend_hexagon_comm_allreduce_tensor(void * comm_ctx_v, struct
|
||||
for (size_t r = 0; r < n_backends; r++) {
|
||||
auto sess = static_cast<ggml_hexagon_session *>(comm_ctx->backends[r]->context);
|
||||
struct htp_allreduce_kernel_params kparams;
|
||||
if (!ggml_hexagon_precompute_allreduce_params(sess, tensors[r], (uint32_t) r, (uint32_t) n_backends, false, false, &kparams)) {
|
||||
if (!ggml_hexagon_precompute_allreduce_params(sess, tensors[r], (uint32_t) r, (uint32_t) n_backends, false, false, /*is_shard_ok=*/ false, &kparams)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -8208,6 +8245,7 @@ static void ggml_hexagon_init(ggml_backend_reg * reg) {
|
||||
const char * str_fa_select = getenv("GGML_HEXAGON_FA_SELECT");
|
||||
const char * str_gdn_select = getenv("GGML_HEXAGON_GDN_SELECT");
|
||||
const char * str_ar_select = getenv("GGML_HEXAGON_AR_SELECT");
|
||||
const char * str_ar_scatter = getenv("GGML_HEXAGON_AR_SCATTER");
|
||||
const char * str_ndev = getenv("GGML_HEXAGON_NDEV");
|
||||
const char * str_arch = getenv("GGML_HEXAGON_ARCH");
|
||||
const char * str_vmem = getenv("GGML_HEXAGON_VMEM");
|
||||
@@ -8261,6 +8299,7 @@ static void ggml_hexagon_init(ggml_backend_reg * reg) {
|
||||
opt_fa_select = str_fa_select ? atoi(str_fa_select) : opt_fa_select;
|
||||
opt_gdn_select = str_gdn_select ? atoi(str_gdn_select) : opt_gdn_select;
|
||||
opt_ar_select = str_ar_select ? atoi(str_ar_select) : opt_ar_select;
|
||||
opt_ar_scatter = str_ar_scatter ? atoi(str_ar_scatter) : opt_ar_scatter;
|
||||
opt_mbuf = str_mbuf ? strtoul(str_mbuf, NULL, 0) * MiB : opt_mbuf;
|
||||
opt_vmem = str_vmem ? strtoul(str_vmem, NULL, 0) * MiB : opt_vmem;
|
||||
opt_hostbuf = str_hostbuf ? atoi(str_hostbuf) != 0 : opt_hostbuf;
|
||||
|
||||
@@ -55,16 +55,22 @@
|
||||
|
||||
struct htp_act_context;
|
||||
|
||||
typedef void (*glu_compute_fn_t)(const float * restrict src0,
|
||||
const float * restrict src1,
|
||||
float * restrict dst,
|
||||
const uint32_t num_rows,
|
||||
const struct htp_act_context * actx);
|
||||
typedef void (*glu_compute_f32_fn_t)(const float * restrict src0,
|
||||
const float * restrict src1,
|
||||
float * restrict dst,
|
||||
const uint32_t num_rows,
|
||||
const struct htp_act_context * actx);
|
||||
|
||||
typedef void (*glu_compute_f16_fn_t)(const _Float16 * restrict src0,
|
||||
const _Float16 * restrict src1,
|
||||
_Float16 * restrict dst,
|
||||
const uint32_t num_rows,
|
||||
const struct htp_act_context * actx);
|
||||
|
||||
struct htp_act_context {
|
||||
struct htp_ops_context * octx;
|
||||
|
||||
glu_compute_fn_t compute;
|
||||
void * compute;
|
||||
const char * op_str;
|
||||
|
||||
// Precomputed values
|
||||
@@ -392,6 +398,58 @@ static inline void hvx_geglu_erf_f32_aa(uint8_t * restrict dst, const uint8_t *
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hvx_geglu_f16_aa(uint8_t * restrict dst, const uint8_t * restrict src0, const uint8_t * restrict src1, uint32_t n) {
|
||||
assert((unsigned long) dst % 128 == 0);
|
||||
assert((unsigned long) src0 % 128 == 0);
|
||||
assert((unsigned long) src1 % 128 == 0);
|
||||
|
||||
HVX_Vector * restrict vdst = (HVX_Vector *) dst;
|
||||
const HVX_Vector * restrict vsrc0 = (const HVX_Vector *) src0;
|
||||
const HVX_Vector * restrict vsrc1 = (const HVX_Vector *) src1;
|
||||
|
||||
const uint32_t epv = 128 / sizeof(_Float16);
|
||||
const uint32_t nvec = n / epv;
|
||||
const uint32_t nloe = n % epv;
|
||||
|
||||
const HVX_Vector v_coef_a = hvx_vec_splat_f16((_Float16) GELU_COEF_A);
|
||||
const HVX_Vector v_sqrt_2_pi = hvx_vec_splat_f16((_Float16) SQRT_2_OVER_PI);
|
||||
const HVX_Vector v_one = hvx_vec_splat_f16((_Float16) 1.0f);
|
||||
const HVX_Vector v_half = hvx_vec_splat_f16((_Float16) 0.5f);
|
||||
|
||||
uint32_t i = 0;
|
||||
|
||||
_Pragma("unroll(4)")
|
||||
for (; i < nvec; i++) {
|
||||
HVX_Vector x = vsrc0[i];
|
||||
HVX_Vector g = vsrc1[i];
|
||||
|
||||
// gelu(x) = 0.5*x*(1 + tanh(SQRT_2_OVER_PI*x*(1 + GELU_COEF_A*x*x)))
|
||||
HVX_Vector x2 = hvx_vec_mul_f16_f16(x, x);
|
||||
HVX_Vector coef = hvx_vec_add_f16_f16(hvx_vec_mul_f16_f16(x2, v_coef_a), v_one);
|
||||
HVX_Vector inner = hvx_vec_mul_f16_f16(hvx_vec_mul_f16_f16(x, coef), v_sqrt_2_pi);
|
||||
|
||||
HVX_Vector t = hvx_vec_add_f16_f16(hvx_vec_tanh_f16(inner), v_one);
|
||||
|
||||
HVX_Vector gelu_x = hvx_vec_mul_f16_f16(hvx_vec_mul_f16_f16(x, t), v_half);
|
||||
vdst[i] = hvx_vec_mul_f16_f16(gelu_x, g);
|
||||
}
|
||||
|
||||
if (nloe) {
|
||||
HVX_Vector x = vsrc0[i];
|
||||
HVX_Vector g = vsrc1[i];
|
||||
|
||||
HVX_Vector x2 = hvx_vec_mul_f16_f16(x, x);
|
||||
HVX_Vector coef = hvx_vec_add_f16_f16(hvx_vec_mul_f16_f16(x2, v_coef_a), v_one);
|
||||
HVX_Vector inner = hvx_vec_mul_f16_f16(hvx_vec_mul_f16_f16(x, coef), v_sqrt_2_pi);
|
||||
|
||||
HVX_Vector t = hvx_vec_add_f16_f16(hvx_vec_tanh_f16(inner), v_one);
|
||||
|
||||
HVX_Vector gelu_x = hvx_vec_mul_f16_f16(hvx_vec_mul_f16_f16(x, t), v_half);
|
||||
HVX_Vector res = hvx_vec_mul_f16_f16(gelu_x, g);
|
||||
hvx_vec_store_a((void *) &vdst[i], nloe * sizeof(_Float16), res);
|
||||
}
|
||||
}
|
||||
|
||||
// geglu(x, g) = gelu(x) * g
|
||||
static void geglu_f32(const float * restrict src0,
|
||||
const float * restrict src1,
|
||||
@@ -443,101 +501,190 @@ static void geglu_erf_f32(const float * restrict src0,
|
||||
}
|
||||
}
|
||||
|
||||
static void glu_f32_per_thread(unsigned int nth, unsigned int ith, void * data) {
|
||||
struct htp_act_context * actx = (struct htp_act_context *) data;
|
||||
htp_act_preamble;
|
||||
// swiglu(x) = x1 * sigmoid(x0)
|
||||
static void swiglu_f16(const _Float16 * restrict src0,
|
||||
const _Float16 * restrict src1,
|
||||
_Float16 * restrict dst,
|
||||
const uint32_t num_rows,
|
||||
const struct htp_act_context * actx) {
|
||||
htp_glu_op_preamble;
|
||||
|
||||
struct htp_thread_trace * tr = actx->octx->ctx ? &actx->octx->ctx->trace[ith] : NULL;
|
||||
for (uint32_t ib = 0; ib < num_rows; ib++) {
|
||||
const uint8_t * restrict src0_ptr = (const uint8_t *) src0 + (ib * src0_row_size_aligned);
|
||||
const uint8_t * restrict src1_ptr = (const uint8_t *) src1 + (ib * src1_row_size_aligned);
|
||||
uint8_t * restrict dst_ptr = (uint8_t *) dst + (ib * dst_row_size_aligned);
|
||||
|
||||
size_t src0_row_size = actx->src0_row_size;
|
||||
size_t src1_row_size = actx->src1_row_size;
|
||||
size_t dst_row_size = actx->dst_row_size;
|
||||
|
||||
size_t src0_row_stride = actx->src0_row_stride;
|
||||
size_t src1_row_stride = actx->src1_row_stride;
|
||||
|
||||
const uint32_t src0_nrows = actx->src0_nrows;
|
||||
const uint32_t src0_nrows_per_thread = actx->src0_nrows_per_thread;
|
||||
|
||||
const uint32_t src0_start_row = actx->row_start + src0_nrows_per_thread * ith;
|
||||
const uint32_t src0_end_row = MIN(src0_start_row + src0_nrows_per_thread, actx->row_start + src0_nrows);
|
||||
|
||||
/* no work for this thread */
|
||||
if (src0_start_row >= src0_end_row) {
|
||||
return;
|
||||
hvx_sigmoid_f16_aa(dst_ptr, src0_ptr, nc);
|
||||
hvx_mul_mul_f16_aa(dst_ptr, src0_ptr, dst_ptr, src1_ptr, nc);
|
||||
}
|
||||
|
||||
const dma_addr_t data_src0 = actx->data_src0;
|
||||
const dma_addr_t data_src1 = actx->data_src1;
|
||||
const dma_addr_t data_dst = actx->data_dst;
|
||||
|
||||
const size_t src0_row_size_aligned = actx->src0_row_size_aligned;
|
||||
const size_t src1_row_size_aligned = actx->src1_row_size_aligned;
|
||||
const size_t dst_row_size_aligned = actx->dst_row_size_aligned;
|
||||
|
||||
uint8_t * restrict src0_spad_data = actx->vtcm_src0 + (ith * actx->vtcm_src0_size_per_thread);
|
||||
uint8_t * restrict src1_spad_data = actx->vtcm_src1 + (ith * actx->vtcm_src1_size_per_thread);
|
||||
uint8_t * restrict dst_spad_data = actx->vtcm_dst + (ith * actx->vtcm_dst_size_per_thread);
|
||||
|
||||
size_t src0_spad_half_size = actx->src0_spad_half_size;
|
||||
size_t src1_spad_half_size = actx->src1_spad_half_size;
|
||||
size_t dst_spad_half_size = actx->dst_spad_half_size;
|
||||
|
||||
const int BLOCK = actx->block;
|
||||
if (BLOCK == 0) {
|
||||
FARF(ERROR, "%s : VTCM reservation %zu is too small, needed %zu\n",
|
||||
actx->op_str, actx->vtcm_src0_size_per_thread, src0_row_size_aligned);
|
||||
return;
|
||||
}
|
||||
|
||||
dma_queue * dma_q = actx->octx->ctx->dma[ith];
|
||||
glu_compute_fn_t compute = actx->compute;
|
||||
|
||||
for (uint32_t ir = src0_start_row, spad_idx = 0; ir < src0_end_row && spad_idx < 2; ir += BLOCK, spad_idx++) {
|
||||
const uint32_t block_size = MIN(BLOCK, src0_end_row - ir);
|
||||
|
||||
/* Dummy DMA transation for sequencing (interleaving dst,src,dst,...) */
|
||||
dma_queue_push(dma_q,
|
||||
dma_make_data(data_dst, dst_spad_data + (spad_idx * dst_spad_half_size)),
|
||||
dst_row_size, dst_row_size_aligned, dst_row_size, 0);
|
||||
|
||||
dma_queue_push(dma_q,
|
||||
dma_make_data(src0_spad_data + (spad_idx * src0_spad_half_size), data_src0 + (ir * src0_row_stride)),
|
||||
src0_row_size_aligned, src0_row_stride, src0_row_size, block_size);
|
||||
|
||||
dma_queue_push(dma_q,
|
||||
dma_make_data(src1_spad_data + (spad_idx * src1_spad_half_size), data_src1 + (ir * src1_row_stride)),
|
||||
src1_row_size_aligned, src1_row_stride, src1_row_size, block_size);
|
||||
}
|
||||
|
||||
for (uint32_t ir = src0_start_row; ir < src0_end_row; ir += BLOCK) {
|
||||
const uint32_t block_size = MIN(BLOCK, src0_end_row - ir);
|
||||
|
||||
float * dst_spad = (float *) dma_queue_pop(dma_q).src;
|
||||
float * src0_spad = (float *) dma_queue_pop(dma_q).dst;
|
||||
float * src1_spad = (float *) dma_queue_pop(dma_q).dst;
|
||||
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, ir);
|
||||
compute(src0_spad, src1_spad, dst_spad, block_size, actx);
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, ir);
|
||||
|
||||
dma_queue_push(dma_q, dma_make_data(data_dst + (ir * dst_row_size), dst_spad),
|
||||
dst_row_size, dst_row_size_aligned, dst_row_size, block_size);
|
||||
|
||||
/* prefetch N+2 loop iteration if any */
|
||||
const uint32_t pref_block = (ir + BLOCK * 2);
|
||||
if (pref_block < src0_end_row) {
|
||||
const uint32_t pref_block_size = MIN(BLOCK, src0_end_row - pref_block);
|
||||
dma_queue_push(dma_q, dma_make_data(src0_spad, data_src0 + (pref_block * src0_row_stride)),
|
||||
src0_row_size_aligned, src0_row_stride, src0_row_size, pref_block_size);
|
||||
dma_queue_push(dma_q, dma_make_data(src1_spad, data_src1 + (pref_block * src1_row_stride)),
|
||||
src1_row_size_aligned, src1_row_stride, src1_row_size, pref_block_size);
|
||||
}
|
||||
}
|
||||
|
||||
dma_queue_flush(dma_q);
|
||||
}
|
||||
|
||||
// out = x * sigmoid(alpha * x) * (clamp(y, -limit, limit) + 1.f)
|
||||
static void swiglu_oai_f16(const _Float16 * restrict src0,
|
||||
const _Float16 * restrict src1,
|
||||
_Float16 * restrict dst,
|
||||
const uint32_t num_rows,
|
||||
const struct htp_act_context * actx) {
|
||||
htp_glu_op_preamble;
|
||||
const _Float16 alpha = (_Float16) ((const float *) (actx->octx->op_params))[2];
|
||||
const _Float16 limit = (_Float16) ((const float *) (actx->octx->op_params))[3];
|
||||
|
||||
for (uint32_t ib = 0; ib < num_rows; ib++) {
|
||||
const uint8_t * restrict src0_ptr = (const uint8_t *) src0 + (ib * src0_row_size_aligned);
|
||||
const uint8_t * restrict src1_ptr = (const uint8_t *) src1 + (ib * src1_row_size_aligned);
|
||||
uint8_t * restrict dst_ptr = (uint8_t *) dst + (ib * dst_row_size_aligned);
|
||||
|
||||
// x (src0_ptr) = std::min(src0_p[k], limit);
|
||||
hvx_min_scalar_f16((uint8_t *) src0_ptr, src0_ptr, limit, nc);
|
||||
// y1 (src1_ptr) = std::clamp(src1_p[k], -limit, limit);
|
||||
hvx_clamp_scalar_f16((uint8_t *) src1_ptr, src1_ptr, -limit, limit, nc);
|
||||
// y (src1_ptr) = y1 + 1.f
|
||||
hvx_add_scalar_f16((uint8_t *) src1_ptr, src1_ptr, (_Float16) 1.0f, nc);
|
||||
// x1 (dst_ptr) = alpha * x
|
||||
hvx_mul_scalar_f16(dst_ptr, src0_ptr, alpha, nc);
|
||||
// x2 (dst_ptr) = sigmoid(x1) = 1/(1+exp(-x1))
|
||||
hvx_sigmoid_f16_aa(dst_ptr, dst_ptr, nc);
|
||||
// out = x * sigmoid(alpha * x) * (y + 1.f)
|
||||
hvx_mul_mul_f16_aa(dst_ptr, src0_ptr, dst_ptr, src1_ptr, nc);
|
||||
}
|
||||
}
|
||||
|
||||
static void swiglu_clamp_f16(const _Float16 * restrict src0,
|
||||
const _Float16 * restrict src1,
|
||||
_Float16 * restrict dst,
|
||||
const uint32_t num_rows,
|
||||
const struct htp_act_context * actx) {
|
||||
htp_glu_op_preamble;
|
||||
const _Float16 limit = (_Float16) ((const float *) (actx->octx->op_params))[3];
|
||||
|
||||
for (uint32_t ib = 0; ib < num_rows; ib++) {
|
||||
const uint8_t * restrict src0_ptr = (const uint8_t *) src0 + (ib * src0_row_size_aligned);
|
||||
const uint8_t * restrict src1_ptr = (const uint8_t *) src1 + (ib * src1_row_size_aligned);
|
||||
uint8_t * restrict dst_ptr = (uint8_t *) dst + (ib * dst_row_size_aligned);
|
||||
|
||||
hvx_min_scalar_f16((uint8_t *) src0_ptr, src0_ptr, limit, nc);
|
||||
hvx_clamp_scalar_f16((uint8_t *) src1_ptr, src1_ptr, -limit, limit, nc);
|
||||
hvx_sigmoid_f16_aa(dst_ptr, src0_ptr, nc);
|
||||
hvx_mul_mul_f16_aa(dst_ptr, src0_ptr, dst_ptr, src1_ptr, nc);
|
||||
}
|
||||
}
|
||||
|
||||
// geglu(x, g) = gelu(x) * g, gelu via tanh approximation
|
||||
static void geglu_f16(const _Float16 * restrict src0,
|
||||
const _Float16 * restrict src1,
|
||||
_Float16 * restrict dst,
|
||||
const uint32_t num_rows,
|
||||
const struct htp_act_context * actx) {
|
||||
htp_glu_op_preamble;
|
||||
|
||||
for (uint32_t ib = 0; ib < num_rows; ib++) {
|
||||
const uint8_t * restrict src0_ptr = (const uint8_t *) src0 + (ib * src0_row_size_aligned);
|
||||
const uint8_t * restrict src1_ptr = (const uint8_t *) src1 + (ib * src1_row_size_aligned);
|
||||
uint8_t * restrict dst_ptr = (uint8_t *) dst + (ib * dst_row_size_aligned);
|
||||
|
||||
hvx_geglu_f16_aa(dst_ptr, src0_ptr, src1_ptr, nc);
|
||||
}
|
||||
}
|
||||
|
||||
#define DEFINE_GLU_PER_THREAD(TYPE, SUFFIX) \
|
||||
static void glu_##SUFFIX##_per_thread(unsigned int nth, unsigned int ith, void * data) { \
|
||||
struct htp_act_context * actx = (struct htp_act_context *) data; \
|
||||
htp_act_preamble; \
|
||||
\
|
||||
struct htp_thread_trace * tr = actx->octx->ctx ? &actx->octx->ctx->trace[ith] : NULL; \
|
||||
\
|
||||
size_t src0_row_size = actx->src0_row_size; \
|
||||
size_t src1_row_size = actx->src1_row_size; \
|
||||
size_t dst_row_size = actx->dst_row_size; \
|
||||
\
|
||||
size_t src0_row_stride = actx->src0_row_stride; \
|
||||
size_t src1_row_stride = actx->src1_row_stride; \
|
||||
\
|
||||
const uint32_t src0_nrows = actx->src0_nrows; \
|
||||
const uint32_t src0_nrows_per_thread = actx->src0_nrows_per_thread; \
|
||||
\
|
||||
const uint32_t src0_start_row = actx->row_start + src0_nrows_per_thread * ith; \
|
||||
const uint32_t src0_end_row = MIN(src0_start_row + src0_nrows_per_thread, actx->row_start + src0_nrows); \
|
||||
\
|
||||
/* no work for this thread */ \
|
||||
if (src0_start_row >= src0_end_row) { \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
const dma_addr_t data_src0 = actx->data_src0; \
|
||||
const dma_addr_t data_src1 = actx->data_src1; \
|
||||
const dma_addr_t data_dst = actx->data_dst; \
|
||||
\
|
||||
const size_t src0_row_size_aligned = actx->src0_row_size_aligned; \
|
||||
const size_t src1_row_size_aligned = actx->src1_row_size_aligned; \
|
||||
const size_t dst_row_size_aligned = actx->dst_row_size_aligned; \
|
||||
\
|
||||
uint8_t * restrict src0_spad_data = actx->vtcm_src0 + (ith * actx->vtcm_src0_size_per_thread); \
|
||||
uint8_t * restrict src1_spad_data = actx->vtcm_src1 + (ith * actx->vtcm_src1_size_per_thread); \
|
||||
uint8_t * restrict dst_spad_data = actx->vtcm_dst + (ith * actx->vtcm_dst_size_per_thread); \
|
||||
\
|
||||
size_t src0_spad_half_size = actx->src0_spad_half_size; \
|
||||
size_t src1_spad_half_size = actx->src1_spad_half_size; \
|
||||
size_t dst_spad_half_size = actx->dst_spad_half_size; \
|
||||
\
|
||||
const int BLOCK = actx->block; \
|
||||
if (BLOCK == 0) { \
|
||||
FARF(ERROR, "%s : VTCM reservation %zu is too small, needed %zu\n", \
|
||||
actx->op_str, actx->vtcm_src0_size_per_thread, src0_row_size_aligned); \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
dma_queue * dma_q = actx->octx->ctx->dma[ith]; \
|
||||
glu_compute_##SUFFIX##_fn_t compute = (glu_compute_##SUFFIX##_fn_t) actx->compute; \
|
||||
\
|
||||
for (uint32_t ir = src0_start_row, spad_idx = 0; ir < src0_end_row && spad_idx < 2; ir += BLOCK, spad_idx++) { \
|
||||
const uint32_t block_size = MIN(BLOCK, src0_end_row - ir); \
|
||||
\
|
||||
/* Dummy DMA transation for sequencing (interleaving dst,src,dst,...) */ \
|
||||
dma_queue_push(dma_q, \
|
||||
dma_make_data(data_dst, dst_spad_data + (spad_idx * dst_spad_half_size)), \
|
||||
dst_row_size, dst_row_size_aligned, dst_row_size, 0); \
|
||||
\
|
||||
dma_queue_push(dma_q, \
|
||||
dma_make_data(src0_spad_data + (spad_idx * src0_spad_half_size), data_src0 + (ir * src0_row_stride)), \
|
||||
src0_row_size_aligned, src0_row_stride, src0_row_size, block_size); \
|
||||
\
|
||||
dma_queue_push(dma_q, \
|
||||
dma_make_data(src1_spad_data + (spad_idx * src1_spad_half_size), data_src1 + (ir * src1_row_stride)), \
|
||||
src1_row_size_aligned, src1_row_stride, src1_row_size, block_size); \
|
||||
} \
|
||||
\
|
||||
for (uint32_t ir = src0_start_row; ir < src0_end_row; ir += BLOCK) { \
|
||||
const uint32_t block_size = MIN(BLOCK, src0_end_row - ir); \
|
||||
\
|
||||
TYPE * dst_spad = (TYPE *) dma_queue_pop(dma_q).src; \
|
||||
TYPE * src0_spad = (TYPE *) dma_queue_pop(dma_q).dst; \
|
||||
TYPE * src1_spad = (TYPE *) dma_queue_pop(dma_q).dst; \
|
||||
\
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, ir); \
|
||||
compute(src0_spad, src1_spad, dst_spad, block_size, actx); \
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, ir); \
|
||||
\
|
||||
dma_queue_push(dma_q, dma_make_data(data_dst + (ir * dst_row_size), dst_spad), \
|
||||
dst_row_size, dst_row_size_aligned, dst_row_size, block_size); \
|
||||
\
|
||||
/* prefetch N+2 loop iteration if any */ \
|
||||
const uint32_t pref_block = (ir + BLOCK * 2); \
|
||||
if (pref_block < src0_end_row) { \
|
||||
const uint32_t pref_block_size = MIN(BLOCK, src0_end_row - pref_block); \
|
||||
dma_queue_push(dma_q, dma_make_data(src0_spad, data_src0 + (pref_block * src0_row_stride)), \
|
||||
src0_row_size_aligned, src0_row_stride, src0_row_size, pref_block_size); \
|
||||
dma_queue_push(dma_q, dma_make_data(src1_spad, data_src1 + (pref_block * src1_row_stride)), \
|
||||
src1_row_size_aligned, src1_row_stride, src1_row_size, pref_block_size); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
dma_queue_flush(dma_q); \
|
||||
}
|
||||
|
||||
DEFINE_GLU_PER_THREAD(float, f32)
|
||||
DEFINE_GLU_PER_THREAD(_Float16, f16)
|
||||
|
||||
static int execute_op_activations_f32(struct htp_ops_context * octx) {
|
||||
const struct htp_tensor * src0 = octx->src[0];
|
||||
const struct htp_tensor * src1 = octx->src[1];
|
||||
@@ -548,8 +695,8 @@ static int execute_op_activations_f32(struct htp_ops_context * octx) {
|
||||
return HTP_STATUS_NO_SUPPORT;
|
||||
}
|
||||
|
||||
glu_compute_fn_t compute_fn = NULL;
|
||||
const char * op_type = NULL;
|
||||
glu_compute_f32_fn_t compute_fn = NULL;
|
||||
const char * op_type = NULL;
|
||||
|
||||
switch (octx->op) {
|
||||
case HTP_OP_GLU_SWIGLU:
|
||||
@@ -581,6 +728,7 @@ static int execute_op_activations_f32(struct htp_ops_context * octx) {
|
||||
compute_fn = geglu_erf_f32;
|
||||
op_type = "geglu-erf-f32";
|
||||
break;
|
||||
|
||||
default:
|
||||
FARF(ERROR, "Unsupported activations Op %u\n", octx->op);
|
||||
return HTP_STATUS_NO_SUPPORT;
|
||||
@@ -643,7 +791,7 @@ static int execute_op_activations_f32(struct htp_ops_context * octx) {
|
||||
// Prepare context
|
||||
struct htp_act_context actx;
|
||||
actx.octx = octx;
|
||||
actx.compute = compute_fn;
|
||||
actx.compute = (void *) compute_fn;
|
||||
actx.op_str = op_type;
|
||||
|
||||
actx.src0_nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div);
|
||||
@@ -708,11 +856,174 @@ static int execute_op_activations_f32(struct htp_ops_context * octx) {
|
||||
return HTP_STATUS_OK;
|
||||
}
|
||||
|
||||
static int execute_op_activations_f16(struct htp_ops_context * octx) {
|
||||
const struct htp_tensor * src0 = octx->src[0];
|
||||
const struct htp_tensor * src1 = octx->src[1];
|
||||
const struct htp_tensor * dst = octx->dst;
|
||||
|
||||
if ((dst->ne[0] * SIZEOF_FP16) != dst->nb[1]) {
|
||||
FARF(ERROR, "Non-contiguous dst is not supported at this time \n");
|
||||
return HTP_STATUS_NO_SUPPORT;
|
||||
}
|
||||
|
||||
glu_compute_f16_fn_t compute_fn = NULL;
|
||||
const char * op_type = NULL;
|
||||
|
||||
switch (octx->op) {
|
||||
case HTP_OP_GLU_SWIGLU:
|
||||
compute_fn = swiglu_f16;
|
||||
op_type = "swiglu-f16";
|
||||
break;
|
||||
|
||||
case HTP_OP_GLU_SWIGLU_OAI:
|
||||
compute_fn = swiglu_oai_f16;
|
||||
op_type = "swiglu-oai-f16";
|
||||
break;
|
||||
|
||||
case HTP_OP_GLU_SWIGLU_CLAMP:
|
||||
compute_fn = swiglu_clamp_f16;
|
||||
op_type = "swiglu-clamp-f16";
|
||||
break;
|
||||
|
||||
case HTP_OP_GLU_GEGLU:
|
||||
compute_fn = geglu_f16;
|
||||
op_type = "geglu-f16";
|
||||
break;
|
||||
|
||||
default:
|
||||
FARF(ERROR, "Unsupported activations Op %u\n", octx->op);
|
||||
return HTP_STATUS_NO_SUPPORT;
|
||||
}
|
||||
|
||||
const uint32_t src0_nrows = src0->ne[1] * src0->ne[2] * src0->ne[3];
|
||||
const size_t dst_row_size = dst->ne[0] * SIZEOF_FP16;
|
||||
|
||||
uint32_t row_start = 0;
|
||||
uint32_t nrows = src0_nrows;
|
||||
|
||||
if (octx->ctx->mdev.count > 1) {
|
||||
uint32_t rows_per_chunk = 0;
|
||||
htp_tensor_mdev_rows_per_chunk(dst, sizeof(_Float16), (uint32_t) dst_row_size, &rows_per_chunk);
|
||||
const struct htp_tensor_mdev_range range = htp_tensor_mdev_partition(src0_nrows, rows_per_chunk, octx->ctx->mdev.idx, octx->ctx->mdev.count, &octx->ctx->mdev.count_div);
|
||||
row_start = range.start;
|
||||
nrows = range.count;
|
||||
}
|
||||
|
||||
if (nrows == 0) {
|
||||
return HTP_STATUS_OK;
|
||||
}
|
||||
|
||||
const uint32_t n_threads = octx->n_threads;
|
||||
|
||||
// row_size = bytes of useful data per row (what the kernel touches / what DMA copies).
|
||||
// row_stride = bytes between successive rows in DDR (may exceed row_size for non-contig src).
|
||||
const size_t nc_bytes = dst_row_size;
|
||||
const size_t src0_row_size = nc_bytes;
|
||||
const size_t src1_row_size = nc_bytes;
|
||||
const size_t src0_row_stride = src0->nb[1];
|
||||
const size_t src1_row_stride = src1 ? src1->nb[1] : src0->nb[1];
|
||||
|
||||
const size_t src0_row_size_aligned = hex_round_up(src0_row_size, VLEN);
|
||||
const size_t src1_row_size_aligned = hex_round_up(src1_row_size, VLEN);
|
||||
const size_t dst_row_size_aligned = hex_round_up(dst_row_size, VLEN);
|
||||
|
||||
struct htp_act_vtcm_layout L;
|
||||
htp_act_vtcm_layout_build(&L, src0_row_size_aligned, src1_row_size_aligned, dst_row_size_aligned, n_threads,
|
||||
octx->ctx->vtcm_size);
|
||||
|
||||
// Make sure the reserved vtcm size is sufficient
|
||||
if (L.vtcm_row_per_thread == 0) {
|
||||
FARF(ERROR, "act-%s : current VTCM reservation %zu is too small for even 1 row per thread, needed at least %zu\n", op_type, octx->ctx->vtcm_size,
|
||||
(src0_row_size_aligned + src1_row_size_aligned + dst_row_size_aligned) * n_threads);
|
||||
return HTP_STATUS_VTCM_TOO_SMALL;
|
||||
}
|
||||
|
||||
if (src1) {
|
||||
FARF(HIGH, "%s: %ux%ux%ux%u x %ux%ux%ux%u -> %ux%ux%ux%u : src0-vtcm-size %zu src1-vtcm-size %zu dst-vtcm-size %zu\n",
|
||||
op_type, src0->ne[0], src0->ne[1], src0->ne[2], src0->ne[3], src1->ne[0], src1->ne[1], src1->ne[2],
|
||||
src1->ne[3], dst->ne[0], dst->ne[1], dst->ne[2], dst->ne[3], L.src0_bytes_per_thread * n_threads,
|
||||
L.src1_bytes_per_thread * n_threads, L.dst_bytes_per_thread * n_threads);
|
||||
} else {
|
||||
FARF(HIGH, "%s: %ux%ux%ux%u -> %ux%ux%ux%u : src0-vtcm-size %zu src1-vtcm-size %zu dst-vtcm-size %zu\n", op_type,
|
||||
src0->ne[0], src0->ne[1], src0->ne[2], src0->ne[3], dst->ne[0], dst->ne[1], dst->ne[2], dst->ne[3],
|
||||
L.src0_bytes_per_thread * n_threads, L.src1_bytes_per_thread * n_threads, L.dst_bytes_per_thread * n_threads);
|
||||
}
|
||||
|
||||
// Prepare context
|
||||
struct htp_act_context actx;
|
||||
actx.octx = octx;
|
||||
actx.compute = (void *) compute_fn;
|
||||
actx.op_str = op_type;
|
||||
|
||||
actx.src0_nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div);
|
||||
|
||||
actx.src0_row_size = src0_row_size;
|
||||
actx.src1_row_size = src1_row_size;
|
||||
actx.dst_row_size = dst_row_size;
|
||||
|
||||
actx.src0_row_size_aligned = src0_row_size_aligned;
|
||||
actx.src1_row_size_aligned = src1_row_size_aligned;
|
||||
actx.dst_row_size_aligned = dst_row_size_aligned;
|
||||
|
||||
actx.src0_row_stride = src0_row_stride;
|
||||
actx.src1_row_stride = src1_row_stride;
|
||||
|
||||
uint8_t * const base = (uint8_t *) octx->ctx->vtcm_base;
|
||||
actx.vtcm_src0 = VTCM_LAYOUT_PTR(uint8_t, base, L.off_src0);
|
||||
actx.vtcm_src1 = VTCM_LAYOUT_PTR(uint8_t, base, L.off_src1);
|
||||
actx.vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, base, L.off_dst);
|
||||
|
||||
actx.vtcm_src0_size_per_thread = L.src0_bytes_per_thread;
|
||||
actx.vtcm_src1_size_per_thread = L.src1_bytes_per_thread;
|
||||
actx.vtcm_dst_size_per_thread = L.dst_bytes_per_thread;
|
||||
|
||||
actx.src0_spad_half_size = L.src0_bytes_per_thread / 2;
|
||||
actx.src1_spad_half_size = L.src1_bytes_per_thread / 2;
|
||||
actx.dst_spad_half_size = L.dst_bytes_per_thread / 2;
|
||||
|
||||
actx.block = actx.src0_spad_half_size / actx.src0_row_size_aligned;
|
||||
actx.src0_nrows = nrows;
|
||||
actx.row_start = row_start;
|
||||
|
||||
actx.nc = dst->ne[0];
|
||||
|
||||
// Addresses and GLU logic
|
||||
dma_addr_t data_src0 = src0->data;
|
||||
dma_addr_t data_src1 = src1 ? src1->data : 0;
|
||||
|
||||
if (!src1 && (octx->op == HTP_OP_GLU_SWIGLU ||
|
||||
octx->op == HTP_OP_GLU_SWIGLU_OAI ||
|
||||
octx->op == HTP_OP_GLU_SWIGLU_CLAMP ||
|
||||
octx->op == HTP_OP_GLU_GEGLU)) {
|
||||
const int32_t swapped = octx->op_params[1];
|
||||
data_src1 = data_src0;
|
||||
actx.src1_row_size = actx.src0_row_size;
|
||||
|
||||
size_t nc_in_bytes = actx.nc * SIZEOF_FP16;
|
||||
if (swapped) {
|
||||
data_src0 += nc_in_bytes;
|
||||
} else {
|
||||
data_src1 += nc_in_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
actx.data_src0 = data_src0;
|
||||
actx.data_src1 = data_src1;
|
||||
actx.data_dst = dst->data;
|
||||
|
||||
work_queue_run(octx->ctx->work_queue, (worker_callback_t)glu_f16_per_thread, &actx, n_threads);
|
||||
return HTP_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
int op_activations(struct htp_ops_context * octx) {
|
||||
switch (octx->src[0]->type) {
|
||||
case HTP_TYPE_F32:
|
||||
return execute_op_activations_f32(octx);
|
||||
|
||||
case HTP_TYPE_F16:
|
||||
return execute_op_activations_f16(octx);
|
||||
|
||||
default:
|
||||
return HTP_STATUS_NO_SUPPORT;
|
||||
}
|
||||
|
||||
@@ -38,97 +38,103 @@ struct htp_allreduce_context {
|
||||
uint8_t * res_spad_base;
|
||||
};
|
||||
|
||||
#define DEFINE_ALLREDUCE_THREAD_DMA_1D(SUFFIX, TYPE, HVX_ADD_FN, HAS_ADD) \
|
||||
static void allreduce_thread_dma_1d_##SUFFIX(unsigned int nth, unsigned int ith, void * data) { \
|
||||
struct htp_allreduce_context * actx = (struct htp_allreduce_context *) data; \
|
||||
struct htp_ops_context * octx = actx->octx; \
|
||||
\
|
||||
const uint32_t n_ranks = actx->n_ranks; \
|
||||
const uint32_t n_dsts = actx->n_dsts; \
|
||||
const uint32_t block_elems = actx->block_elems; \
|
||||
\
|
||||
const uint32_t dr = actx->elems_per_thread; \
|
||||
const uint32_t ir0 = actx->rank_elem_start + dr * ith; \
|
||||
const uint32_t ir1 = MIN(ir0 + dr, actx->rank_elem_start + actx->rank_nelem); \
|
||||
if (ir0 >= ir1) return; \
|
||||
\
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith]; \
|
||||
dma_queue * dma_q = octx->ctx->dma[ith]; \
|
||||
\
|
||||
uint8_t * src_spad_base[HTP_ALLREDUCE_MAX_RANKS]; \
|
||||
for (uint32_t s = 0; s < n_ranks; s++) { \
|
||||
src_spad_base[s] = actx->src_spad_base[s] + (ith * actx->vtcm_size_per_thread); \
|
||||
} \
|
||||
uint8_t * dst_spad_base = actx->dst_spad_base + (ith * actx->vtcm_size_per_thread); \
|
||||
uint8_t * res_spad_base = HAS_ADD ? (actx->res_spad_base + (ith * actx->vtcm_size_per_thread)) : NULL; \
|
||||
\
|
||||
const size_t spad_half = actx->vtcm_size_per_thread / 2; \
|
||||
uint32_t ir_prefetch = ir0; \
|
||||
int spad_idx = 0; \
|
||||
\
|
||||
for (int k = 0; k < 2 && ir_prefetch < ir1; k++) { \
|
||||
uint32_t cur_elems = MIN(block_elems, ir1 - ir_prefetch); \
|
||||
size_t cur_bytes = cur_elems * sizeof(TYPE); \
|
||||
uint8_t * d_spad = dst_spad_base + spad_idx * spad_half; \
|
||||
for (uint32_t d = 0; d < n_dsts; d++) { \
|
||||
dma_addr_t d_ddr = octx->dsts[d]->data + ir_prefetch * sizeof(TYPE); \
|
||||
dma_queue_push(dma_q, dma_make_data(d_ddr, d_spad), cur_bytes, cur_bytes, cur_bytes, 0); \
|
||||
} \
|
||||
for (uint32_t s = 0; s < n_ranks; s++) { \
|
||||
uint8_t * s_spad = src_spad_base[s] + spad_idx * spad_half; \
|
||||
const dma_addr_t s_ddr = octx->src[s]->data + ir_prefetch * sizeof(TYPE); \
|
||||
dma_queue_push(dma_q, dma_make_data(s_spad, s_ddr), cur_bytes, cur_bytes, cur_bytes, 1); \
|
||||
} \
|
||||
if (HAS_ADD) { \
|
||||
uint8_t * r_spad = res_spad_base + spad_idx * spad_half; \
|
||||
const dma_addr_t r_ddr = octx->src[2 * n_ranks]->data + ir_prefetch * sizeof(TYPE); \
|
||||
dma_queue_push(dma_q, dma_make_data(r_spad, r_ddr), cur_bytes, cur_bytes, cur_bytes, 1); \
|
||||
} \
|
||||
ir_prefetch += cur_elems; \
|
||||
spad_idx ^= 1; \
|
||||
} \
|
||||
\
|
||||
for (uint32_t ir = ir0; ir < ir1; ) { \
|
||||
uint32_t cur_elems = MIN(block_elems, ir1 - ir); \
|
||||
size_t cur_bytes = cur_elems * sizeof(TYPE); \
|
||||
uint8_t * d_spad = NULL; \
|
||||
for (uint32_t d = 0; d < n_dsts; d++) { \
|
||||
d_spad = (uint8_t *) dma_queue_pop(dma_q).src; \
|
||||
} \
|
||||
uint8_t * s_spad[HTP_ALLREDUCE_MAX_RANKS]; \
|
||||
for (uint32_t s = 0; s < n_ranks; s++) { \
|
||||
s_spad[s] = (uint8_t *) dma_queue_pop(dma_q).dst; \
|
||||
} \
|
||||
uint8_t * r_spad = HAS_ADD ? (uint8_t *) dma_queue_pop(dma_q).dst : NULL; \
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) ir); \
|
||||
HVX_ADD_FN(d_spad, s_spad[0], s_spad[1], cur_elems); \
|
||||
for (uint32_t s = 2; s < n_ranks; s++) { \
|
||||
HVX_ADD_FN(d_spad, d_spad, s_spad[s], cur_elems); \
|
||||
} \
|
||||
if (HAS_ADD) { \
|
||||
HVX_ADD_FN(d_spad, d_spad, r_spad, cur_elems); \
|
||||
} \
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) ir); \
|
||||
for (uint32_t d = 0; d < n_dsts; d++) { \
|
||||
dma_addr_t d_ddr = octx->dsts[d]->data + ir * sizeof(TYPE); \
|
||||
dma_queue_push(dma_q, dma_make_data(d_ddr, d_spad), cur_bytes, cur_bytes, cur_bytes, 1); \
|
||||
} \
|
||||
if (ir_prefetch < ir1) { \
|
||||
uint32_t next_elems = MIN(block_elems, ir1 - ir_prefetch); \
|
||||
size_t next_bytes = next_elems * sizeof(TYPE); \
|
||||
for (uint32_t s = 0; s < n_ranks; s++) { \
|
||||
const dma_addr_t s_next = octx->src[s]->data + ir_prefetch * sizeof(TYPE); \
|
||||
dma_queue_push(dma_q, dma_make_data(s_spad[s], s_next), next_bytes, next_bytes, next_bytes, 1); \
|
||||
} \
|
||||
if (HAS_ADD) { \
|
||||
const dma_addr_t r_next = octx->src[2 * n_ranks]->data + ir_prefetch * sizeof(TYPE); \
|
||||
dma_queue_push(dma_q, dma_make_data(r_spad, r_next), next_bytes, next_bytes, next_bytes, 1); \
|
||||
} \
|
||||
ir_prefetch += next_elems; \
|
||||
} \
|
||||
ir += cur_elems; \
|
||||
} \
|
||||
dma_queue_flush(dma_q); \
|
||||
#define DEFINE_ALLREDUCE_THREAD_DMA_1D(SUFFIX, TYPE, HVX_ADD_FN, HAS_ADD) \
|
||||
static void allreduce_thread_dma_1d_##SUFFIX(unsigned int nth, unsigned int ith, void * data) { \
|
||||
struct htp_allreduce_context * actx = (struct htp_allreduce_context *) data; \
|
||||
struct htp_ops_context * octx = actx->octx; \
|
||||
\
|
||||
const uint32_t n_ranks = actx->n_ranks; \
|
||||
const uint32_t n_dsts = actx->n_dsts; \
|
||||
const uint32_t block_elems = actx->block_elems; \
|
||||
\
|
||||
const uint32_t dr = actx->elems_per_thread; \
|
||||
const uint32_t ir0 = actx->rank_elem_start + dr * ith; \
|
||||
const uint32_t ir1 = MIN(ir0 + dr, actx->rank_elem_start + actx->rank_nelem); \
|
||||
if (ir0 >= ir1) return; \
|
||||
\
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith]; \
|
||||
dma_queue * dma_q = octx->ctx->dma[ith]; \
|
||||
\
|
||||
const size_t vtcm_thread_offset = ith * actx->vtcm_size_per_thread; \
|
||||
uint8_t * dst_spad_base = actx->dst_spad_base + vtcm_thread_offset; \
|
||||
uint8_t * res_spad_base = HAS_ADD ? (actx->res_spad_base + vtcm_thread_offset) : NULL; \
|
||||
\
|
||||
const size_t spad_half = actx->vtcm_size_per_thread / 2; \
|
||||
uint32_t ir_prefetch = ir0; \
|
||||
int spad_idx = 0; \
|
||||
\
|
||||
for (int k = 0; k < 2 && ir_prefetch < ir1; k++) { \
|
||||
uint32_t cur_elems = MIN(block_elems, ir1 - ir_prefetch); \
|
||||
size_t cur_bytes = cur_elems * sizeof(TYPE); \
|
||||
uint8_t * d_spad = dst_spad_base + spad_idx * spad_half; \
|
||||
for (uint32_t d = 0; d < n_dsts; d++) { \
|
||||
dma_addr_t d_ddr = octx->dsts[d]->data + ir_prefetch * sizeof(TYPE); \
|
||||
dma_queue_push(dma_q, dma_make_data(d_ddr, d_spad), cur_bytes, cur_bytes, cur_bytes, 0); \
|
||||
} \
|
||||
for (uint32_t s = 0; s < n_ranks; s++) { \
|
||||
uint8_t * s_spad = actx->src_spad_base[s] + vtcm_thread_offset + spad_idx * spad_half; \
|
||||
const dma_addr_t s_ddr = octx->src[s]->data + ir_prefetch * sizeof(TYPE); \
|
||||
dma_queue_push(dma_q, dma_make_data(s_spad, s_ddr), cur_bytes, cur_bytes, cur_bytes, 1); \
|
||||
} \
|
||||
if (HAS_ADD) { \
|
||||
uint8_t * r_spad = res_spad_base + spad_idx * spad_half; \
|
||||
const dma_addr_t r_ddr = octx->src[2 * n_ranks]->data + ir_prefetch * sizeof(TYPE); \
|
||||
dma_queue_push(dma_q, dma_make_data(r_spad, r_ddr), cur_bytes, cur_bytes, cur_bytes, 1); \
|
||||
} \
|
||||
ir_prefetch += cur_elems; \
|
||||
spad_idx ^= 1; \
|
||||
} \
|
||||
\
|
||||
int comp_spad_idx = 0; \
|
||||
for (uint32_t ir = ir0; ir < ir1; ) { \
|
||||
uint32_t cur_elems = MIN(block_elems, ir1 - ir); \
|
||||
size_t cur_bytes = cur_elems * sizeof(TYPE); \
|
||||
for (uint32_t d = 0; d < n_dsts; d++) { \
|
||||
dma_queue_pop(dma_q); \
|
||||
} \
|
||||
for (uint32_t s = 0; s < n_ranks; s++) { \
|
||||
dma_queue_pop(dma_q); \
|
||||
} \
|
||||
if (HAS_ADD) { \
|
||||
dma_queue_pop(dma_q); \
|
||||
} \
|
||||
uint8_t * d_spad = dst_spad_base + comp_spad_idx * spad_half; \
|
||||
uint8_t * s0_spad = actx->src_spad_base[0] + vtcm_thread_offset + comp_spad_idx * spad_half; \
|
||||
uint8_t * s1_spad = actx->src_spad_base[1] + vtcm_thread_offset + comp_spad_idx * spad_half; \
|
||||
uint8_t * r_spad = HAS_ADD ? (res_spad_base + comp_spad_idx * spad_half) : NULL; \
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) ir); \
|
||||
HVX_ADD_FN(d_spad, s0_spad, s1_spad, cur_elems); \
|
||||
for (uint32_t s = 2; s < n_ranks; s++) { \
|
||||
uint8_t * ss_spad = actx->src_spad_base[s] + vtcm_thread_offset + comp_spad_idx * spad_half; \
|
||||
HVX_ADD_FN(d_spad, d_spad, ss_spad, cur_elems); \
|
||||
} \
|
||||
if (HAS_ADD) { \
|
||||
HVX_ADD_FN(d_spad, d_spad, r_spad, cur_elems); \
|
||||
} \
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) ir); \
|
||||
for (uint32_t d = 0; d < n_dsts; d++) { \
|
||||
dma_addr_t d_ddr = octx->dsts[d]->data + ir * sizeof(TYPE); \
|
||||
dma_queue_push(dma_q, dma_make_data(d_ddr, d_spad), cur_bytes, cur_bytes, cur_bytes, 1); \
|
||||
} \
|
||||
if (ir_prefetch < ir1) { \
|
||||
uint32_t next_elems = MIN(block_elems, ir1 - ir_prefetch); \
|
||||
size_t next_bytes = next_elems * sizeof(TYPE); \
|
||||
for (uint32_t s = 0; s < n_ranks; s++) { \
|
||||
uint8_t * s_spad = actx->src_spad_base[s] + vtcm_thread_offset + comp_spad_idx * spad_half; \
|
||||
const dma_addr_t s_next = octx->src[s]->data + ir_prefetch * sizeof(TYPE); \
|
||||
dma_queue_push(dma_q, dma_make_data(s_spad, s_next), next_bytes, next_bytes, next_bytes, 1); \
|
||||
} \
|
||||
if (HAS_ADD) { \
|
||||
uint8_t * r_spad_next = res_spad_base + comp_spad_idx * spad_half; \
|
||||
const dma_addr_t r_next = octx->src[2 * n_ranks]->data + ir_prefetch * sizeof(TYPE); \
|
||||
dma_queue_push(dma_q, dma_make_data(r_spad_next, r_next), next_bytes, next_bytes, next_bytes, 1); \
|
||||
} \
|
||||
ir_prefetch += next_elems; \
|
||||
} \
|
||||
comp_spad_idx ^= 1; \
|
||||
ir += cur_elems; \
|
||||
} \
|
||||
dma_queue_flush(dma_q); \
|
||||
}
|
||||
|
||||
DEFINE_ALLREDUCE_THREAD_DMA_1D(f16, __fp16, hvx_add_f16_aaa, 0)
|
||||
@@ -156,12 +162,9 @@ static void allreduce_thread_dma_2d_##SUFFIX(unsigned int nth, unsigned int ith,
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith]; \
|
||||
dma_queue * dma_q = octx->ctx->dma[ith]; \
|
||||
\
|
||||
uint8_t * src_spad_base[HTP_ALLREDUCE_MAX_RANKS]; \
|
||||
for (uint32_t s = 0; s < n_ranks; s++) { \
|
||||
src_spad_base[s] = actx->src_spad_base[s] + (ith * actx->vtcm_size_per_thread); \
|
||||
} \
|
||||
uint8_t * dst_spad_base = actx->dst_spad_base + (ith * actx->vtcm_size_per_thread); \
|
||||
uint8_t * res_spad_base = HAS_ADD ? (IS_ROW_BCAST ? actx->res_spad_base : (actx->res_spad_base + (ith * actx->vtcm_size_per_thread))) : NULL; \
|
||||
const size_t vtcm_thread_offset = ith * actx->vtcm_size_per_thread; \
|
||||
uint8_t * dst_spad_base = actx->dst_spad_base + vtcm_thread_offset; \
|
||||
uint8_t * res_spad_base = HAS_ADD ? (IS_ROW_BCAST ? actx->res_spad_base : (actx->res_spad_base + vtcm_thread_offset)) : NULL; \
|
||||
\
|
||||
const size_t spad_half = actx->vtcm_size_per_thread / 2; \
|
||||
uint32_t r_prefetch = r0; \
|
||||
@@ -175,7 +178,7 @@ static void allreduce_thread_dma_2d_##SUFFIX(unsigned int nth, unsigned int ith,
|
||||
dma_queue_push(dma_q, dma_make_data(d_ddr, d_spad), octx->dsts[d]->nb[1], row_size_aligned, row_bytes, 0); \
|
||||
} \
|
||||
for (uint32_t s = 0; s < n_ranks; s++) { \
|
||||
uint8_t * s_spad = src_spad_base[s] + spad_idx * spad_half; \
|
||||
uint8_t * s_spad = actx->src_spad_base[s] + vtcm_thread_offset + spad_idx * spad_half; \
|
||||
const dma_addr_t s_ddr = octx->src[s]->data + r_prefetch * octx->src[s]->nb[1]; \
|
||||
dma_queue_push(dma_q, dma_make_data(s_spad, s_ddr), row_size_aligned, octx->src[s]->nb[1], row_bytes, cur_rows); \
|
||||
} \
|
||||
@@ -188,25 +191,30 @@ static void allreduce_thread_dma_2d_##SUFFIX(unsigned int nth, unsigned int ith,
|
||||
spad_idx ^= 1; \
|
||||
} \
|
||||
\
|
||||
int comp_spad_idx = 0; \
|
||||
for (uint32_t r = r0; r < r1; ) { \
|
||||
uint32_t cur_rows = MIN(block_rows, r1 - r); \
|
||||
uint8_t * d_spad = NULL; \
|
||||
for (uint32_t d = 0; d < n_dsts; d++) { \
|
||||
d_spad = (uint8_t *) dma_queue_pop(dma_q).src; \
|
||||
dma_queue_pop(dma_q); \
|
||||
} \
|
||||
uint8_t * s_spad[HTP_ALLREDUCE_MAX_RANKS]; \
|
||||
for (uint32_t s = 0; s < n_ranks; s++) { \
|
||||
s_spad[s] = (uint8_t *) dma_queue_pop(dma_q).dst; \
|
||||
dma_queue_pop(dma_q); \
|
||||
} \
|
||||
uint8_t * r_spad = (HAS_ADD && !IS_ROW_BCAST) ? (uint8_t *) dma_queue_pop(dma_q).dst : NULL; \
|
||||
if (HAS_ADD && !IS_ROW_BCAST) { \
|
||||
dma_queue_pop(dma_q); \
|
||||
} \
|
||||
uint8_t * d_spad = dst_spad_base + comp_spad_idx * spad_half; \
|
||||
uint8_t * s0_spad = actx->src_spad_base[0] + vtcm_thread_offset + comp_spad_idx * spad_half; \
|
||||
uint8_t * s1_spad = actx->src_spad_base[1] + vtcm_thread_offset + comp_spad_idx * spad_half; \
|
||||
uint8_t * r_spad = (HAS_ADD && !IS_ROW_BCAST) ? (res_spad_base + comp_spad_idx * spad_half) : NULL; \
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) r); \
|
||||
for (uint32_t row = 0; row < cur_rows; row++) { \
|
||||
uint8_t * d_row = d_spad + row * row_size_aligned; \
|
||||
const uint8_t * s0_row = s_spad[0] + row * row_size_aligned; \
|
||||
const uint8_t * s1_row = s_spad[1] + row * row_size_aligned; \
|
||||
const uint8_t * s0_row = s0_spad + row * row_size_aligned; \
|
||||
const uint8_t * s1_row = s1_spad + row * row_size_aligned; \
|
||||
HVX_ADD_FN(d_row, s0_row, s1_row, ne0); \
|
||||
for (uint32_t s = 2; s < n_ranks; s++) { \
|
||||
const uint8_t * ss_row = s_spad[s] + row * row_size_aligned; \
|
||||
const uint8_t * ss_row = actx->src_spad_base[s] + vtcm_thread_offset + comp_spad_idx * spad_half + row * row_size_aligned; \
|
||||
HVX_ADD_FN(d_row, d_row, ss_row, ne0); \
|
||||
} \
|
||||
if (HAS_ADD) { \
|
||||
@@ -222,15 +230,18 @@ static void allreduce_thread_dma_2d_##SUFFIX(unsigned int nth, unsigned int ith,
|
||||
if (r_prefetch < r1) { \
|
||||
uint32_t next_rows = MIN(block_rows, r1 - r_prefetch); \
|
||||
for (uint32_t s = 0; s < n_ranks; s++) { \
|
||||
uint8_t * s_spad = actx->src_spad_base[s] + vtcm_thread_offset + comp_spad_idx * spad_half; \
|
||||
const dma_addr_t s_next = octx->src[s]->data + r_prefetch * octx->src[s]->nb[1]; \
|
||||
dma_queue_push(dma_q, dma_make_data(s_spad[s], s_next), row_size_aligned, octx->src[s]->nb[1], row_bytes, next_rows); \
|
||||
dma_queue_push(dma_q, dma_make_data(s_spad, s_next), row_size_aligned, octx->src[s]->nb[1], row_bytes, next_rows); \
|
||||
} \
|
||||
if (HAS_ADD && !IS_ROW_BCAST) { \
|
||||
uint8_t * r_spad_next = res_spad_base + comp_spad_idx * spad_half; \
|
||||
const dma_addr_t r_next = octx->src[2 * n_ranks]->data + r_prefetch * octx->src[2 * n_ranks]->nb[1]; \
|
||||
dma_queue_push(dma_q, dma_make_data(r_spad, r_next), row_size_aligned, octx->src[2 * n_ranks]->nb[1], row_bytes, next_rows); \
|
||||
dma_queue_push(dma_q, dma_make_data(r_spad_next, r_next), row_size_aligned, octx->src[2 * n_ranks]->nb[1], row_bytes, next_rows); \
|
||||
} \
|
||||
r_prefetch += next_rows; \
|
||||
} \
|
||||
comp_spad_idx ^= 1; \
|
||||
r += cur_rows; \
|
||||
} \
|
||||
dma_queue_flush(dma_q); \
|
||||
@@ -248,9 +259,10 @@ static int validate_allreduce(
|
||||
const struct htp_allreduce_kernel_params * kparams,
|
||||
uint32_t n_ranks
|
||||
) {
|
||||
if (!htp_ops_context_set_n_threads(octx, (uint32_t) kparams->n_threads)) {
|
||||
if (kparams->n_threads == 0 || (uint32_t) kparams->n_threads > octx->ctx->n_threads) {
|
||||
return HTP_STATUS_INVAL_PARAMS;
|
||||
}
|
||||
octx->n_threads = (uint32_t) kparams->n_threads;
|
||||
|
||||
if (kparams->vtcm_size_per_thread <= 0 || kparams->vtcm_size <= 0) {
|
||||
return HTP_STATUS_INVAL_PARAMS;
|
||||
@@ -306,6 +318,7 @@ int op_allreduce(struct htp_ops_context * octx) {
|
||||
|
||||
const bool has_add = (octx->op == HTP_OP_ALLREDUCE_ADD);
|
||||
const uint32_t nelem = dst->ne[0] * dst->ne[1] * dst->ne[2] * dst->ne[3];
|
||||
const int32_t mode = kparams->mode;
|
||||
|
||||
// 1. Entry Barrier: Synchronize all ranks before reading
|
||||
struct htp_thread_trace * tr0 = &octx->ctx->trace[0];
|
||||
@@ -419,6 +432,11 @@ int op_allreduce(struct htp_ops_context * octx) {
|
||||
// 4. Exit Barrier: Synchronize all ranks after writing
|
||||
htp_trace_event_start(tr0, HTP_TRACE_EVT_FENCE, (uint16_t) fence_seq_exit);
|
||||
|
||||
// drain fan-out DMA writes before exit barrier
|
||||
if (mode == HTP_ALLREDUCE_SHARDED_FANOUT) {
|
||||
asm volatile ("syncht" : : : "memory");
|
||||
}
|
||||
|
||||
htp_fence_write(my_fence, fence_seq_exit, octx->status);
|
||||
|
||||
for (uint32_t j = 0; j < n_ranks; j++) {
|
||||
|
||||
@@ -17,6 +17,11 @@ enum htp_allreduce_kernel_type {
|
||||
HTP_ALLREDUCE_KERNEL_DMA_2D,
|
||||
};
|
||||
|
||||
enum htp_allreduce_mode {
|
||||
HTP_ALLREDUCE_FULL = 0, // all ranks reduce full tensor
|
||||
HTP_ALLREDUCE_SHARDED_FANOUT = 1, // each rank reduces 1/N shard and fans out to all buffers
|
||||
};
|
||||
|
||||
static inline size_t htp_allreduce_vtcm_buffer_count(
|
||||
uint32_t n_ranks,
|
||||
uint32_t n_threads,
|
||||
@@ -42,6 +47,7 @@ struct htp_allreduce_kernel_params {
|
||||
int32_t rank_nelem;
|
||||
int32_t n_dsts;
|
||||
int32_t is_row_bcast;
|
||||
int32_t mode; // enum htp_allreduce_mode: FULL or SHARDED_FANOUT
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -26,6 +26,12 @@ struct htp_concat_context {
|
||||
struct fastdiv_values div_ne2;
|
||||
};
|
||||
|
||||
static inline dma_addr_t concat_plane_addr(const struct htp_tensor * t, uint32_t p, const struct fastdiv_values * div_ne2, uint32_t ne2) {
|
||||
const uint32_t i3 = fastdiv(p, div_ne2);
|
||||
const uint32_t i2 = p - i3 * ne2;
|
||||
return t->data + i2 * t->nb[2] + i3 * t->nb[3];
|
||||
}
|
||||
|
||||
static void concat_2d_f32_transposed(unsigned int nth, unsigned int ith, void * data) {
|
||||
struct htp_concat_context * cctx = (struct htp_concat_context *) data;
|
||||
struct htp_ops_context * octx = cctx->octx;
|
||||
@@ -50,58 +56,74 @@ static void concat_2d_f32_transposed(unsigned int nth, unsigned int ith, void *
|
||||
const uint32_t block_i = 32;
|
||||
const uint32_t spad1_stride = block_i * sizeof(float);
|
||||
|
||||
int32_t offsets[32] __attribute__((aligned(128)));
|
||||
for(int k=0; k<32; k++) {
|
||||
offsets[k] = k * spad1_stride;
|
||||
}
|
||||
HVX_Vector vv = *(HVX_Vector*)offsets;
|
||||
const HVX_Vector offsets = hvx_vec_gather_offsets_w(spad1_stride);
|
||||
const uint32_t src1_ne0_padded = hex_round_up(src1_ne0, 32);
|
||||
const uint32_t spad0_row_bytes = hex_round_up((src0_ne0 + src1_ne0_padded) * sizeof(float), VLEN);
|
||||
uint32_t mu = src1_ne0_padded * spad1_stride;
|
||||
const uint32_t src0_row_bytes = src0_ne0 * sizeof(float);
|
||||
const uint32_t src0_row_padded = hex_round_up(src0_row_bytes, VLEN);
|
||||
const uint32_t src0_pre = src0_row_padded - src0_row_bytes;
|
||||
const uint32_t spad0_row_bytes = src0_row_padded + src1_ne0_padded * sizeof(float);
|
||||
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
|
||||
|
||||
for (uint32_t p = 0; p < cctx->nplanes; p++) {
|
||||
const uint32_t i3 = p / dst->ne[2];
|
||||
const uint32_t i2 = p - i3 * dst->ne[2];
|
||||
const dma_addr_t src0_plane = src0->data + i2 * src0->nb[2] + i3 * src0->nb[3];
|
||||
const dma_addr_t src1_plane = src1->data + i2 * src1->nb[2] + i3 * src1->nb[3];
|
||||
const dma_addr_t dst_plane = dst->data + i2 * dst->nb[2] + i3 * dst->nb[3];
|
||||
const struct fastdiv_values * div_ne2 = &cctx->div_ne2;
|
||||
const uint32_t ne2 = dst->ne[2];
|
||||
|
||||
for (uint32_t i = start_i; i < end_i; i += block_i) {
|
||||
uint32_t current_block_i = (end_i - i < block_i) ? (end_i - i) : block_i;
|
||||
uint32_t p = 0;
|
||||
uint32_t i = start_i;
|
||||
|
||||
uint32_t src1_width_bytes = current_block_i * sizeof(float);
|
||||
const dma_addr_t src1_addr = src1_plane + i * src1->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(spad1_base, src1_addr), spad1_stride, src1->nb[0], src1_width_bytes, src1_ne0);
|
||||
const dma_addr_t src1_addr = concat_plane_addr(src1, p, div_ne2, ne2) + i * src1->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(spad1_base, src1_addr), spad1_stride, src1->nb[0], MIN(end_i - i, block_i) * sizeof(float), src1_ne0);
|
||||
|
||||
uint32_t src0_row_bytes = src0_ne0 * sizeof(float);
|
||||
const dma_addr_t src0_addr = src0_plane + i * src0->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(spad0_base, src0_addr), spad0_row_bytes, src0->nb[1], src0_row_bytes, current_block_i);
|
||||
const dma_addr_t src0_addr = concat_plane_addr(src0, p, div_ne2, ne2) + i * src0->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(spad0_base + src0_pre, src0_addr), spad0_row_bytes, src0->nb[1], src0_row_bytes, MIN(end_i - i, block_i));
|
||||
|
||||
dma_queue_pop(dma_q); // src1
|
||||
dma_queue_pop(dma_q); // src1
|
||||
|
||||
HVX_Vector * vtcm_tmp = (HVX_Vector *)(spad1_base + src1_ne0_padded * spad1_stride);
|
||||
while (p < cctx->nplanes) {
|
||||
const uint32_t current_block_i = MIN(end_i - i, block_i);
|
||||
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) i);
|
||||
for (uint32_t j = 0; j < src1_ne0_padded; j += 32) {
|
||||
#pragma unroll(4)
|
||||
for (uint32_t ii = 0; ii < current_block_i; ii++) {
|
||||
size_t rt = (size_t)(spad1_base + j * spad1_stride + ii * sizeof(float));
|
||||
Q6_vgather_ARMVw(&vtcm_tmp[ii], rt, mu, vv);
|
||||
uint8_t * dst_ptr = spad0_base + ii * spad0_row_bytes + (src0_ne0 + j) * sizeof(float);
|
||||
hvx_vmemu(dst_ptr) = vtcm_tmp[ii];
|
||||
}
|
||||
}
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) i);
|
||||
|
||||
dma_queue_pop(dma_q); // src0
|
||||
|
||||
const dma_addr_t dst_addr = dst_plane + i * dst->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(dst_addr, spad0_base), dst->nb[1], spad0_row_bytes, (src0_ne0 + src1_ne0) * sizeof(float), current_block_i);
|
||||
|
||||
dma_queue_pop(dma_q);
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) i);
|
||||
for (uint32_t j = 0; j < src1_ne0; j += 32) {
|
||||
const uint8_t * src_ptr = spad1_base + j * spad1_stride;
|
||||
uint8_t * dst_ptr = spad0_base + src0_row_padded + j * sizeof(float);
|
||||
hvx_transpose_32x32_w_gather(dst_ptr, spad0_row_bytes, src_ptr, spad1_stride, offsets, current_block_i, MIN(src1_ne0 - j, 32));
|
||||
}
|
||||
hvx_gather_sync(spad0_base + src0_row_padded);
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) i);
|
||||
|
||||
uint32_t np = p;
|
||||
uint32_t ni = i + block_i;
|
||||
if (ni >= end_i) {
|
||||
ni = start_i;
|
||||
np++;
|
||||
}
|
||||
const bool has_next = np < cctx->nplanes;
|
||||
const uint32_t next_block_i = MIN(end_i - ni, block_i);
|
||||
|
||||
// spad1 is free after the gather sync, prefetch next src1 ahead of the dst write
|
||||
if (has_next) {
|
||||
const dma_addr_t nsrc1_addr = concat_plane_addr(src1, np, div_ne2, ne2) + ni * src1->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(spad1_base, nsrc1_addr), spad1_stride, src1->nb[0], next_block_i * sizeof(float), src1_ne0);
|
||||
}
|
||||
|
||||
dma_queue_pop(dma_q); // src0
|
||||
|
||||
const dma_addr_t dst_addr = concat_plane_addr(dst, p, div_ne2, ne2) + i * dst->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(dst_addr, spad0_base + src0_pre), dst->nb[1], spad0_row_bytes, (src0_ne0 + src1_ne0) * sizeof(float), current_block_i);
|
||||
|
||||
if (has_next) {
|
||||
dma_queue_pop(dma_q); // next src1
|
||||
}
|
||||
dma_queue_pop(dma_q); // dst
|
||||
|
||||
// spad0 is free after the dst write
|
||||
if (has_next) {
|
||||
const dma_addr_t nsrc0_addr = concat_plane_addr(src0, np, div_ne2, ne2) + ni * src0->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(spad0_base + src0_pre, nsrc0_addr), spad0_row_bytes, src0->nb[1], src0_row_bytes, next_block_i);
|
||||
}
|
||||
|
||||
p = np;
|
||||
i = ni;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,58 +151,74 @@ static void concat_2d_f16_transposed(unsigned int nth, unsigned int ith, void *
|
||||
const uint32_t block_i = 64;
|
||||
const uint32_t spad1_stride = block_i * sizeof(__fp16);
|
||||
|
||||
int16_t offsets[64] __attribute__((aligned(128)));
|
||||
for(int k=0; k<64; k++) {
|
||||
offsets[k] = k * spad1_stride;
|
||||
}
|
||||
HVX_Vector vv = *(HVX_Vector*)offsets;
|
||||
const HVX_Vector offsets = hvx_vec_gather_offsets_h(spad1_stride);
|
||||
const uint32_t src1_ne0_padded = hex_round_up(src1_ne0, 64);
|
||||
const uint32_t spad0_row_bytes = hex_round_up((src0_ne0 + src1_ne0_padded) * sizeof(__fp16), VLEN);
|
||||
uint32_t mu = src1_ne0_padded * spad1_stride;
|
||||
const uint32_t src0_row_bytes = src0_ne0 * sizeof(__fp16);
|
||||
const uint32_t src0_row_padded = hex_round_up(src0_row_bytes, VLEN);
|
||||
const uint32_t src0_pre = src0_row_padded - src0_row_bytes;
|
||||
const uint32_t spad0_row_bytes = src0_row_padded + src1_ne0_padded * sizeof(__fp16);
|
||||
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
|
||||
|
||||
for (uint32_t p = 0; p < cctx->nplanes; p++) {
|
||||
const uint32_t i3 = p / dst->ne[2];
|
||||
const uint32_t i2 = p - i3 * dst->ne[2];
|
||||
const dma_addr_t src0_plane = src0->data + i2 * src0->nb[2] + i3 * src0->nb[3];
|
||||
const dma_addr_t src1_plane = src1->data + i2 * src1->nb[2] + i3 * src1->nb[3];
|
||||
const dma_addr_t dst_plane = dst->data + i2 * dst->nb[2] + i3 * dst->nb[3];
|
||||
const struct fastdiv_values * div_ne2 = &cctx->div_ne2;
|
||||
const uint32_t ne2 = dst->ne[2];
|
||||
|
||||
for (uint32_t i = start_i; i < end_i; i += block_i) {
|
||||
uint32_t current_block_i = (end_i - i < block_i) ? (end_i - i) : block_i;
|
||||
uint32_t p = 0;
|
||||
uint32_t i = start_i;
|
||||
|
||||
uint32_t src1_width_bytes = current_block_i * sizeof(__fp16);
|
||||
const dma_addr_t src1_addr = src1_plane + i * src1->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(spad1_base, src1_addr), spad1_stride, src1->nb[0], src1_width_bytes, src1_ne0);
|
||||
const dma_addr_t src1_addr = concat_plane_addr(src1, p, div_ne2, ne2) + i * src1->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(spad1_base, src1_addr), spad1_stride, src1->nb[0], MIN(end_i - i, block_i) * sizeof(__fp16), src1_ne0);
|
||||
|
||||
uint32_t src0_row_bytes = src0_ne0 * sizeof(__fp16);
|
||||
const dma_addr_t src0_addr = src0_plane + i * src0->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(spad0_base, src0_addr), spad0_row_bytes, src0->nb[1], src0_row_bytes, current_block_i);
|
||||
const dma_addr_t src0_addr = concat_plane_addr(src0, p, div_ne2, ne2) + i * src0->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(spad0_base + src0_pre, src0_addr), spad0_row_bytes, src0->nb[1], src0_row_bytes, MIN(end_i - i, block_i));
|
||||
|
||||
dma_queue_pop(dma_q); // src1
|
||||
dma_queue_pop(dma_q); // src1
|
||||
|
||||
HVX_Vector * vtcm_tmp = (HVX_Vector *)(spad1_base + src1_ne0_padded * spad1_stride);
|
||||
while (p < cctx->nplanes) {
|
||||
const uint32_t current_block_i = MIN(end_i - i, block_i);
|
||||
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) i);
|
||||
for (uint32_t j = 0; j < src1_ne0_padded; j += 64) {
|
||||
#pragma unroll(4)
|
||||
for (uint32_t ii = 0; ii < current_block_i; ii++) {
|
||||
size_t rt = (size_t)(spad1_base + j * spad1_stride + ii * sizeof(__fp16));
|
||||
Q6_vgather_ARMVh(&vtcm_tmp[ii], rt, mu, vv);
|
||||
uint8_t * dst_ptr = spad0_base + ii * spad0_row_bytes + (src0_ne0 + j) * sizeof(__fp16);
|
||||
hvx_vmemu(dst_ptr) = vtcm_tmp[ii];
|
||||
}
|
||||
}
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) i);
|
||||
|
||||
dma_queue_pop(dma_q); // src0
|
||||
|
||||
const dma_addr_t dst_addr = dst_plane + i * dst->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(dst_addr, spad0_base), dst->nb[1], spad0_row_bytes, (src0_ne0 + src1_ne0) * sizeof(__fp16), current_block_i);
|
||||
|
||||
dma_queue_pop(dma_q);
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) i);
|
||||
for (uint32_t j = 0; j < src1_ne0; j += 64) {
|
||||
const uint8_t * src_ptr = spad1_base + j * spad1_stride;
|
||||
uint8_t * dst_ptr = spad0_base + src0_row_padded + j * sizeof(__fp16);
|
||||
hvx_transpose_64x64_h_gather(dst_ptr, spad0_row_bytes, src_ptr, spad1_stride, offsets, current_block_i, MIN(src1_ne0 - j, 64));
|
||||
}
|
||||
hvx_gather_sync(spad0_base + src0_row_padded);
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) i);
|
||||
|
||||
uint32_t np = p;
|
||||
uint32_t ni = i + block_i;
|
||||
if (ni >= end_i) {
|
||||
ni = start_i;
|
||||
np++;
|
||||
}
|
||||
const bool has_next = np < cctx->nplanes;
|
||||
const uint32_t next_block_i = MIN(end_i - ni, block_i);
|
||||
|
||||
// spad1 is free after the gather sync, prefetch next src1 ahead of the dst write
|
||||
if (has_next) {
|
||||
const dma_addr_t nsrc1_addr = concat_plane_addr(src1, np, div_ne2, ne2) + ni * src1->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(spad1_base, nsrc1_addr), spad1_stride, src1->nb[0], next_block_i * sizeof(__fp16), src1_ne0);
|
||||
}
|
||||
|
||||
dma_queue_pop(dma_q); // src0
|
||||
|
||||
const dma_addr_t dst_addr = concat_plane_addr(dst, p, div_ne2, ne2) + i * dst->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(dst_addr, spad0_base + src0_pre), dst->nb[1], spad0_row_bytes, (src0_ne0 + src1_ne0) * sizeof(__fp16), current_block_i);
|
||||
|
||||
if (has_next) {
|
||||
dma_queue_pop(dma_q); // next src1
|
||||
}
|
||||
dma_queue_pop(dma_q); // dst
|
||||
|
||||
// spad0 is free after the dst write
|
||||
if (has_next) {
|
||||
const dma_addr_t nsrc0_addr = concat_plane_addr(src0, np, div_ne2, ne2) + ni * src0->nb[1];
|
||||
dma_queue_push(dma_q, dma_make_data(spad0_base + src0_pre, nsrc0_addr), spad0_row_bytes, src0->nb[1], src0_row_bytes, next_block_i);
|
||||
}
|
||||
|
||||
p = np;
|
||||
i = ni;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +238,7 @@ static void concat_generic(unsigned int nth, unsigned int ith, void * data) {
|
||||
// Per-device element range aligned to prevent false sharing
|
||||
const uint32_t elem_start = cctx->elem_start;
|
||||
const uint32_t nelems = cctx->nelems;
|
||||
const uint32_t chunk_size = (nelems + nth - 1) / nth;
|
||||
const uint32_t chunk_size = fastdiv(nelems + nth - 1, &octx->n_threads_div);
|
||||
|
||||
const uint32_t start_idx = MIN(elem_start + ith * chunk_size, elem_start + nelems);
|
||||
const uint32_t end_idx = MIN(start_idx + chunk_size, elem_start + nelems);
|
||||
@@ -358,10 +396,11 @@ int op_concat(struct htp_ops_context * octx) {
|
||||
uint32_t spad1_stride = block_i * type_size;
|
||||
|
||||
uint32_t src1_ne0_padded = hex_round_up(src1->ne[0], block_i);
|
||||
uint32_t spad0_row_bytes = hex_round_up((src0->ne[0] + src1_ne0_padded) * type_size, VLEN);
|
||||
// src0 row is right-aligned to VLEN so the gathered src1 part starts aligned
|
||||
uint32_t spad0_row_bytes = hex_round_up(src0->ne[0] * type_size, VLEN) + src1_ne0_padded * type_size;
|
||||
|
||||
octx->src0_spad.size_per_thread = block_i * spad0_row_bytes;
|
||||
octx->src1_spad.size_per_thread = src1_ne0_padded * spad1_stride + block_i * VLEN;
|
||||
octx->src1_spad.size_per_thread = src1_ne0_padded * spad1_stride;
|
||||
|
||||
octx->src0_spad.size = n_threads * octx->src0_spad.size_per_thread;
|
||||
octx->src1_spad.size = n_threads * octx->src1_spad.size_per_thread;
|
||||
|
||||
@@ -164,6 +164,37 @@ static inline void hvx_mul_mul_f32_aa(uint8_t * restrict dst, const uint8_t * re
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hvx_mul_mul_f16_aa(uint8_t * restrict dst, const uint8_t * restrict src0, const uint8_t * restrict src1, const uint8_t * restrict src2, const uint32_t num_elems) {
|
||||
assert((unsigned long) dst % 128 == 0);
|
||||
assert((unsigned long) src0 % 128 == 0);
|
||||
assert((unsigned long) src1 % 128 == 0);
|
||||
assert((unsigned long) src2 % 128 == 0);
|
||||
|
||||
HVX_Vector * restrict vdst = (HVX_Vector *) dst;
|
||||
HVX_Vector * restrict vsrc0 = (HVX_Vector *) src0;
|
||||
HVX_Vector * restrict vsrc1 = (HVX_Vector *) src1;
|
||||
HVX_Vector * restrict vsrc2 = (HVX_Vector *) src2;
|
||||
|
||||
const uint32_t elem_size = sizeof(_Float16);
|
||||
const uint32_t epv = 128 / elem_size;
|
||||
const uint32_t nvec = num_elems / epv;
|
||||
const uint32_t nloe = num_elems % epv;
|
||||
|
||||
uint32_t i = 0;
|
||||
|
||||
_Pragma("unroll(4)")
|
||||
for (; i < nvec; i++) {
|
||||
HVX_Vector v1 = HVX_OP_MUL_F16(vsrc0[i], vsrc1[i]);
|
||||
vdst[i] = HVX_OP_MUL_F16(v1, vsrc2[i]);
|
||||
}
|
||||
|
||||
if (nloe) {
|
||||
HVX_Vector v1 = HVX_OP_MUL_F16(vsrc0[i], vsrc1[i]);
|
||||
HVX_Vector v2 = HVX_OP_MUL_F16(v1, vsrc2[i]);
|
||||
hvx_vec_store_a((void *) &vdst[i], nloe * elem_size, v2);
|
||||
}
|
||||
}
|
||||
|
||||
// Scalar Operations
|
||||
|
||||
#define hvx_scalar_loop_body(dst_type, src_type, elem_size, vec_store, scalar_op_macro) \
|
||||
@@ -348,6 +379,44 @@ static inline void hvx_max_scalar_f32(uint8_t * restrict dst, const uint8_t * re
|
||||
}
|
||||
}
|
||||
|
||||
#define HVX_OP_MIN_SCALAR_F16(v) Q6_Vhf_vmin_VhfVhf(val_vec, v)
|
||||
|
||||
static inline void hvx_min_scalar_f16_aa(uint8_t * restrict dst, const uint8_t * restrict src, const _Float16 val, uint32_t n) {
|
||||
const HVX_Vector val_vec = hvx_vec_splat_f16(val);
|
||||
assert((unsigned long) dst % 128 == 0);
|
||||
assert((unsigned long) src % 128 == 0);
|
||||
hvx_scalar_loop_body(HVX_Vector, HVX_Vector, sizeof(_Float16), hvx_vec_store_a, HVX_OP_MIN_SCALAR_F16);
|
||||
}
|
||||
|
||||
static inline void hvx_min_scalar_f16_au(uint8_t * restrict dst, const uint8_t * restrict src, const _Float16 val, uint32_t n) {
|
||||
const HVX_Vector val_vec = hvx_vec_splat_f16(val);
|
||||
assert((unsigned long) dst % 128 == 0);
|
||||
hvx_scalar_loop_body(HVX_Vector, HVX_UVector, sizeof(_Float16), hvx_vec_store_a, HVX_OP_MIN_SCALAR_F16);
|
||||
}
|
||||
|
||||
static inline void hvx_min_scalar_f16_ua(uint8_t * restrict dst, const uint8_t * restrict src, const _Float16 val, uint32_t n) {
|
||||
const HVX_Vector val_vec = hvx_vec_splat_f16(val);
|
||||
assert((unsigned long) src % 128 == 0);
|
||||
hvx_scalar_loop_body(HVX_UVector, HVX_Vector, sizeof(_Float16), hvx_vec_store_u, HVX_OP_MIN_SCALAR_F16);
|
||||
}
|
||||
|
||||
static inline void hvx_min_scalar_f16_uu(uint8_t * restrict dst, const uint8_t * restrict src, const _Float16 val, uint32_t n) {
|
||||
const HVX_Vector val_vec = hvx_vec_splat_f16(val);
|
||||
hvx_scalar_loop_body(HVX_UVector, HVX_UVector, sizeof(_Float16), hvx_vec_store_u, HVX_OP_MIN_SCALAR_F16);
|
||||
}
|
||||
|
||||
static inline void hvx_min_scalar_f16(uint8_t * restrict dst, const uint8_t * restrict src, const _Float16 val, const int num_elems) {
|
||||
if (hex_is_aligned((void *) dst, 128) && hex_is_aligned((void *) src, 128)) {
|
||||
hvx_min_scalar_f16_aa(dst, src, val, num_elems);
|
||||
} else if (hex_is_aligned((void *) dst, 128)) {
|
||||
hvx_min_scalar_f16_au(dst, src, val, num_elems);
|
||||
} else if (hex_is_aligned((void *) src, 128)) {
|
||||
hvx_min_scalar_f16_ua(dst, src, val, num_elems);
|
||||
} else {
|
||||
hvx_min_scalar_f16_uu(dst, src, val, num_elems);
|
||||
}
|
||||
}
|
||||
|
||||
// CLAMP Scalar variants
|
||||
|
||||
#define HVX_OP_CLAMP_SCALAR(v) \
|
||||
@@ -767,10 +836,12 @@ static inline void hvx_sqr_f16(uint8_t * restrict dst, const uint8_t * restrict
|
||||
#undef hvx_scalar_loop_body
|
||||
#undef HVX_OP_MIN_SCALAR
|
||||
#undef HVX_OP_MAX_SCALAR
|
||||
#undef HVX_OP_MIN_SCALAR_F16
|
||||
#undef HVX_OP_CLAMP_SCALAR
|
||||
#undef HVX_OP_CLAMP_SCALAR_F16
|
||||
#undef HVX_OP_LEAKY_RELU_SCALAR
|
||||
#undef DEFINE_HVX_BINARY_OP_VARIANTS
|
||||
#undef DEFINE_HVX_BINARY_SCALAR_OP_VARIANTS
|
||||
#undef HVX_BINARY_DISPATCHER
|
||||
#undef UNUSED
|
||||
|
||||
|
||||
@@ -303,4 +303,137 @@ static inline HVX_Vector hvx_vec_load_act_tile(const uint8_t * y_q, uint32_t kt,
|
||||
}
|
||||
}
|
||||
|
||||
// Full tile, in place. tmp: 32 vectors scratch.
|
||||
// Use when result must stay in m. Slowest (spills).
|
||||
static inline void hvx_transpose_32x32_w_shuff_inplace(HVX_Vector * restrict m, HVX_Vector * restrict tmp) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
HVX_VectorPair p = Q6_W_vshuff_VVR(m[2*i + 1], m[2*i], -4);
|
||||
tmp[2*i + 0] = Q6_V_lo_W(p);
|
||||
tmp[2*i + 1] = Q6_V_hi_W(p);
|
||||
}
|
||||
|
||||
for (int b = 0; b < 32; b += 4) {
|
||||
HVX_VectorPair p0 = Q6_W_vshuff_VVR(tmp[b + 2], tmp[b + 0], -8);
|
||||
HVX_VectorPair p1 = Q6_W_vshuff_VVR(tmp[b + 3], tmp[b + 1], -8);
|
||||
m[b + 0] = Q6_V_lo_W(p0); m[b + 1] = Q6_V_hi_W(p0);
|
||||
m[b + 2] = Q6_V_lo_W(p1); m[b + 3] = Q6_V_hi_W(p1);
|
||||
}
|
||||
|
||||
for (int b = 0; b < 32; b += 8) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
HVX_VectorPair p = Q6_W_vshuff_VVR(m[b + i + 4], m[b + i], -16);
|
||||
tmp[b + 2*i + 0] = Q6_V_lo_W(p);
|
||||
tmp[b + 2*i + 1] = Q6_V_hi_W(p);
|
||||
}
|
||||
}
|
||||
|
||||
for (int b = 0; b < 32; b += 16) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
HVX_VectorPair p = Q6_W_vshuff_VVR(tmp[b + i + 8], tmp[b + i], -32);
|
||||
m[b + 2*i + 0] = Q6_V_lo_W(p);
|
||||
m[b + 2*i + 1] = Q6_V_hi_W(p);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
HVX_VectorPair p = Q6_W_vshuff_VVR(m[i + 16], m[i], -64);
|
||||
tmp[2 * i + 0] = Q6_V_lo_W(p);
|
||||
tmp[2 * i + 1] = Q6_V_hi_W(p);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
m[i] = tmp[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Rows [0, nrows) of the transpose of src[0, ncols) to dst. src is clobbered, must not alias dst.
|
||||
// Use when not in VTCM or for full tiles.
|
||||
static inline void hvx_transpose_32x32_w_shuff(uint8_t * restrict dst, uint32_t dst_stride, HVX_Vector * restrict src,
|
||||
uint32_t nrows, uint32_t ncols) {
|
||||
for (uint32_t g = 0; g < ncols; g += 8) {
|
||||
HVX_Vector * s = src + g;
|
||||
|
||||
HVX_VectorPair a0 = Q6_W_vshuff_VVR(s[1], s[0], -4);
|
||||
HVX_VectorPair a1 = Q6_W_vshuff_VVR(s[3], s[2], -4);
|
||||
HVX_VectorPair a2 = Q6_W_vshuff_VVR(s[5], s[4], -4);
|
||||
HVX_VectorPair a3 = Q6_W_vshuff_VVR(s[7], s[6], -4);
|
||||
|
||||
HVX_VectorPair b0 = Q6_W_vshuff_VVR(Q6_V_lo_W(a1), Q6_V_lo_W(a0), -8);
|
||||
HVX_VectorPair b1 = Q6_W_vshuff_VVR(Q6_V_hi_W(a1), Q6_V_hi_W(a0), -8);
|
||||
HVX_VectorPair b2 = Q6_W_vshuff_VVR(Q6_V_lo_W(a3), Q6_V_lo_W(a2), -8);
|
||||
HVX_VectorPair b3 = Q6_W_vshuff_VVR(Q6_V_hi_W(a3), Q6_V_hi_W(a2), -8);
|
||||
|
||||
HVX_VectorPair c0 = Q6_W_vshuff_VVR(Q6_V_lo_W(b2), Q6_V_lo_W(b0), -16);
|
||||
HVX_VectorPair c1 = Q6_W_vshuff_VVR(Q6_V_hi_W(b2), Q6_V_hi_W(b0), -16);
|
||||
HVX_VectorPair c2 = Q6_W_vshuff_VVR(Q6_V_lo_W(b3), Q6_V_lo_W(b1), -16);
|
||||
HVX_VectorPair c3 = Q6_W_vshuff_VVR(Q6_V_hi_W(b3), Q6_V_hi_W(b1), -16);
|
||||
|
||||
s[0] = Q6_V_lo_W(c0); s[1] = Q6_V_hi_W(c0);
|
||||
s[2] = Q6_V_lo_W(c1); s[3] = Q6_V_hi_W(c1);
|
||||
s[4] = Q6_V_lo_W(c2); s[5] = Q6_V_hi_W(c2);
|
||||
s[6] = Q6_V_lo_W(c3); s[7] = Q6_V_hi_W(c3);
|
||||
}
|
||||
|
||||
for (uint32_t k = 0; 4 * k < nrows; k++) {
|
||||
HVX_VectorPair d0 = Q6_W_vshuff_VVR(src[k + 8], src[k], -32);
|
||||
HVX_VectorPair d1 = Q6_W_vshuff_VVR(src[k + 24], src[k + 16], -32);
|
||||
|
||||
HVX_VectorPair e0 = Q6_W_vshuff_VVR(Q6_V_lo_W(d1), Q6_V_lo_W(d0), -64);
|
||||
HVX_VectorPair e1 = Q6_W_vshuff_VVR(Q6_V_hi_W(d1), Q6_V_hi_W(d0), -64);
|
||||
|
||||
uint8_t * d = dst + 4 * k * dst_stride;
|
||||
*(HVX_Vector *) (d + 0 * dst_stride) = Q6_V_lo_W(e0);
|
||||
*(HVX_Vector *) (d + 1 * dst_stride) = Q6_V_hi_W(e0);
|
||||
*(HVX_Vector *) (d + 2 * dst_stride) = Q6_V_lo_W(e1);
|
||||
*(HVX_Vector *) (d + 3 * dst_stride) = Q6_V_hi_W(e1);
|
||||
}
|
||||
}
|
||||
|
||||
// Specialized store that will follow outstanding scatters or gathers to make sure they complete
|
||||
static inline void hvx_gather_sync(void * vtcm_addr) {
|
||||
asm volatile("vmem(%0+#0):scatter_release\n"
|
||||
"v0 = vmem(%0+#0)\n" :: "r"(vtcm_addr) : "v0", "memory");
|
||||
}
|
||||
|
||||
// Lane k = k * stride. Offsets for the _gather transposes.
|
||||
static inline HVX_Vector hvx_vec_gather_offsets_w(uint32_t stride) {
|
||||
int32_t offsets[32] __attribute__((aligned(128)));
|
||||
for (int k = 0; k < 32; k++) {
|
||||
offsets[k] = k * stride;
|
||||
}
|
||||
return *(HVX_Vector *) offsets;
|
||||
}
|
||||
|
||||
static inline HVX_Vector hvx_vec_gather_offsets_h(uint32_t stride) {
|
||||
int16_t offsets[64] __attribute__((aligned(128)));
|
||||
for (int k = 0; k < 64; k++) {
|
||||
offsets[k] = k * stride;
|
||||
}
|
||||
return *(HVX_Vector *) offsets;
|
||||
}
|
||||
|
||||
// Rows [0, nrows) of the transpose of ncols src vectors (src_stride apart) to dst.
|
||||
// src, dst in VTCM. Async: hvx_gather_sync() before use.
|
||||
// Use for partial tiles (small ncols). Fewest packets.
|
||||
static inline void hvx_transpose_32x32_w_gather(uint8_t * restrict dst, uint32_t dst_stride, const uint8_t * restrict src,
|
||||
uint32_t src_stride, HVX_Vector offsets, uint32_t nrows, uint32_t ncols) {
|
||||
const uint32_t mu = ncols * src_stride;
|
||||
|
||||
#pragma unroll(4)
|
||||
for (uint32_t r = 0; r < nrows; r++) {
|
||||
Q6_vgather_ARMVw((HVX_Vector *) (dst + r * dst_stride), (size_t) (src + r * sizeof(int32_t)), mu, offsets);
|
||||
}
|
||||
}
|
||||
|
||||
// 16-bit version of hvx_transpose_32x32_w_gather.
|
||||
static inline void hvx_transpose_64x64_h_gather(uint8_t * restrict dst, uint32_t dst_stride, const uint8_t * restrict src,
|
||||
uint32_t src_stride, HVX_Vector offsets, uint32_t nrows, uint32_t ncols) {
|
||||
const uint32_t mu = ncols * src_stride;
|
||||
|
||||
#pragma unroll(4)
|
||||
for (uint32_t r = 0; r < nrows; r++) {
|
||||
Q6_vgather_ARMVh((HVX_Vector *) (dst + r * dst_stride), (size_t) (src + r * sizeof(int16_t)), mu, offsets);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HVX_BASE_H */
|
||||
|
||||
@@ -178,4 +178,58 @@ static inline HVX_Vector hvx_vec_tanh_f16(HVX_Vector x) {
|
||||
return hvx_vec_add_f16_f16(hvx_vec_mul_f16_f16(sig2x, v_two), v_neg_one);
|
||||
}
|
||||
|
||||
#define hvx_sigmoid_f16_loop_body(dst_type, src_type, vec_store) \
|
||||
do { \
|
||||
dst_type * restrict vdst = (dst_type *) dst; \
|
||||
src_type * restrict vsrc = (src_type *) src; \
|
||||
\
|
||||
const uint32_t epv = 128 / sizeof(_Float16); \
|
||||
const uint32_t nvec = n / epv; \
|
||||
const uint32_t nloe = n % epv; \
|
||||
\
|
||||
uint32_t i = 0; \
|
||||
\
|
||||
_Pragma("unroll(4)") \
|
||||
for (; i < nvec; i++) { \
|
||||
vdst[i] = hvx_vec_fast_sigmoid_f16(vsrc[i]); \
|
||||
} \
|
||||
if (nloe) { \
|
||||
HVX_Vector tmp = hvx_vec_fast_sigmoid_f16(vsrc[i]); \
|
||||
vec_store((void *) &vdst[i], nloe * sizeof(_Float16), tmp); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define hvx_tanh_f16_loop_body(dst_type, src_type, vec_store) \
|
||||
do { \
|
||||
dst_type * restrict vdst = (dst_type *) dst; \
|
||||
src_type * restrict vsrc = (src_type *) src; \
|
||||
\
|
||||
const uint32_t epv = 128 / sizeof(_Float16); \
|
||||
const uint32_t nvec = n / epv; \
|
||||
const uint32_t nloe = n % epv; \
|
||||
\
|
||||
uint32_t i = 0; \
|
||||
\
|
||||
_Pragma("unroll(4)") \
|
||||
for (; i < nvec; i++) { \
|
||||
vdst[i] = hvx_vec_tanh_f16(vsrc[i]); \
|
||||
} \
|
||||
if (nloe) { \
|
||||
HVX_Vector tmp = hvx_vec_tanh_f16(vsrc[i]); \
|
||||
vec_store((void *) &vdst[i], nloe * sizeof(_Float16), tmp); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
static inline void hvx_sigmoid_f16_aa(uint8_t * restrict dst, const uint8_t * restrict src, uint32_t n) {
|
||||
assert((unsigned long) dst % 128 == 0);
|
||||
assert((unsigned long) src % 128 == 0);
|
||||
hvx_sigmoid_f16_loop_body(HVX_Vector, HVX_Vector, hvx_vec_store_a);
|
||||
}
|
||||
|
||||
static inline void hvx_tanh_f16_aa(uint8_t * restrict dst, const uint8_t * restrict src, uint32_t n) {
|
||||
assert((unsigned long) dst % 128 == 0);
|
||||
assert((unsigned long) src % 128 == 0);
|
||||
hvx_tanh_f16_loop_body(HVX_Vector, HVX_Vector, hvx_vec_store_a);
|
||||
}
|
||||
|
||||
#endif /* HVX_SIGMOID_H */
|
||||
|
||||
@@ -31,7 +31,7 @@ struct work_queue_task_s {
|
||||
struct work_queue_s {
|
||||
atomic_uint seqn; // seqno used to detect new jobs
|
||||
atomic_uint idx_read; // Updated by producer (pop/reclaim)
|
||||
unsigned int idx_write; // Updated by producer (push)
|
||||
atomic_uint idx_write; // Updated by producer (push)
|
||||
uint32_t idx_mask;
|
||||
uint32_t capacity;
|
||||
|
||||
@@ -41,7 +41,7 @@ struct work_queue_s {
|
||||
unsigned int n_threads; // total threads (workers + main)
|
||||
unsigned int n_workers; // number of active threads (just workers)
|
||||
|
||||
atomic_bool active; // workers are polling/active
|
||||
atomic_uint active; // workers are polling/active
|
||||
atomic_bool killed; // threads need to exit
|
||||
bool external_mem; // memory owned externally
|
||||
|
||||
@@ -62,7 +62,7 @@ static void work_queue_thread(void * context) {
|
||||
if (atomic_load_explicit(&q->active, memory_order_relaxed)) {
|
||||
hex_pause();
|
||||
} else {
|
||||
qurt_futex_wait(&q->seqn, prev_seqn);
|
||||
qurt_futex_wait(&q->active, 0);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -71,7 +71,7 @@ static void work_queue_thread(void * context) {
|
||||
|
||||
// Process all active tasks in the queue
|
||||
unsigned int ir = atomic_load_explicit(&q->idx_read, memory_order_relaxed);
|
||||
unsigned int iw = q->idx_write;
|
||||
unsigned int iw = atomic_load_explicit(&q->idx_write, memory_order_relaxed);
|
||||
|
||||
while (ir != iw) {
|
||||
struct work_queue_task_s * task = &q->queue[ir];
|
||||
@@ -101,8 +101,8 @@ bool work_queue_run_async(work_queue_t q, work_queue_func_t func, void * data, u
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int ir = atomic_load_explicit(&q->idx_read, memory_order_relaxed);
|
||||
unsigned int iw = q->idx_write;
|
||||
unsigned int ir = atomic_load_explicit(&q->idx_read, memory_order_relaxed);
|
||||
unsigned int iw = atomic_load_explicit(&q->idx_write, memory_order_relaxed);
|
||||
|
||||
if (((iw + 1) & q->idx_mask) == ir) {
|
||||
FARF(ERROR, "work-queue-push: queue is full\n");
|
||||
@@ -115,7 +115,7 @@ bool work_queue_run_async(work_queue_t q, work_queue_func_t func, void * data, u
|
||||
task->n_threads = n;
|
||||
atomic_store_explicit(&task->barrier, n, memory_order_relaxed);
|
||||
|
||||
q->idx_write = (iw + 1) & q->idx_mask;
|
||||
atomic_store_explicit(&q->idx_write, (iw + 1) & q->idx_mask, memory_order_relaxed);
|
||||
|
||||
// publish job to workers (already awake and polling)
|
||||
atomic_fetch_add_explicit(&q->seqn, 1, memory_order_release);
|
||||
@@ -168,10 +168,10 @@ work_queue_t work_queue_init(void * ptr, uint32_t n_threads, uint32_t capacity,
|
||||
q->context[i].queue = q;
|
||||
}
|
||||
|
||||
atomic_init(&q->idx_read, 0);
|
||||
atomic_init(&q->seqn, 0);
|
||||
atomic_init(&q->active, false);
|
||||
q->idx_write = 0;
|
||||
atomic_init(&q->idx_read, 0);
|
||||
atomic_init(&q->idx_write, 0);
|
||||
atomic_init(&q->seqn, 0);
|
||||
atomic_init(&q->active, 0);
|
||||
q->idx_mask = capacity - 1;
|
||||
q->killed = 0;
|
||||
for (int i = 0; i < (int) capacity; i++) {
|
||||
@@ -219,8 +219,9 @@ void work_queue_free(work_queue_t q) {
|
||||
if (!q) { return; }
|
||||
|
||||
atomic_store_explicit(&q->killed, 1, memory_order_relaxed);
|
||||
atomic_store_explicit(&q->active, 1, memory_order_release);
|
||||
atomic_fetch_add_explicit(&q->seqn, 1, memory_order_release);
|
||||
qurt_futex_wake(&q->seqn, q->n_workers);
|
||||
qurt_futex_wake(&q->active, q->n_workers);
|
||||
|
||||
for (unsigned int i = 0; i < q->n_workers; i++) {
|
||||
if (q->thread[i]) {
|
||||
@@ -232,13 +233,11 @@ void work_queue_free(work_queue_t q) {
|
||||
|
||||
void work_queue_wakeup(work_queue_t q) {
|
||||
if (!atomic_load_explicit(&q->active, memory_order_relaxed)) {
|
||||
atomic_store_explicit(&q->active, true, memory_order_release);
|
||||
// Increment seqn and wake workers to transition them out of sleep
|
||||
atomic_fetch_add_explicit(&q->seqn, 1, memory_order_release);
|
||||
qurt_futex_wake(&q->seqn, q->n_workers);
|
||||
atomic_store_explicit(&q->active, 1, memory_order_release);
|
||||
qurt_futex_wake(&q->active, q->n_workers);
|
||||
}
|
||||
}
|
||||
|
||||
void work_queue_suspend(work_queue_t q) {
|
||||
atomic_store_explicit(&q->active, false, memory_order_release);
|
||||
atomic_store_explicit(&q->active, 0, memory_order_release);
|
||||
}
|
||||
|
||||
@@ -2379,6 +2379,8 @@ void ggml_metal_buffer_set_tensor(ggml_metal_buffer_t buf, struct ggml_tensor *
|
||||
dispatch_release(completion_semaphore);
|
||||
|
||||
//[cmd_buf waitUntilCompleted];
|
||||
|
||||
[buf_src release];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2417,6 +2419,8 @@ void ggml_metal_buffer_get_tensor(ggml_metal_buffer_t buf, const struct ggml_ten
|
||||
|
||||
[cmd_buf commit];
|
||||
[cmd_buf waitUntilCompleted];
|
||||
|
||||
[buf_dst release];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -351,12 +351,16 @@ void dequantize_mxfp4(device const block_mxfp4 * xb, short il, thread type4x4 &
|
||||
const float d = e8m0_to_fp32(xb->e);
|
||||
const uint8_t shr = il >= 1 ? 4 : 0;
|
||||
|
||||
float4x4 reg_f;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
reg[i][0] = d * kvalues_mxfp4_f[(q2[4*i + 0] >> shr) & 0x0F];
|
||||
reg[i][1] = d * kvalues_mxfp4_f[(q2[4*i + 1] >> shr) & 0x0F];
|
||||
reg[i][2] = d * kvalues_mxfp4_f[(q2[4*i + 2] >> shr) & 0x0F];
|
||||
reg[i][3] = d * kvalues_mxfp4_f[(q2[4*i + 3] >> shr) & 0x0F];
|
||||
reg_f[i][0] = d * kvalues_mxfp4_f[(q2[4*i + 0] >> shr) & 0x0F];
|
||||
reg_f[i][1] = d * kvalues_mxfp4_f[(q2[4*i + 1] >> shr) & 0x0F];
|
||||
reg_f[i][2] = d * kvalues_mxfp4_f[(q2[4*i + 2] >> shr) & 0x0F];
|
||||
reg_f[i][3] = d * kvalues_mxfp4_f[(q2[4*i + 3] >> shr) & 0x0F];
|
||||
}
|
||||
|
||||
reg = (type4x4) reg_f;
|
||||
}
|
||||
|
||||
template <typename type4>
|
||||
|
||||
@@ -226,7 +226,7 @@ kernel void kernel_mul_mm(
|
||||
|
||||
const short ib = 8*sx + sy;
|
||||
|
||||
*(sa + 64*ib + 8*ly + lx) = loop_k + 16*il + i < args.ne00 ? *((device T0 *) x + i) : 0;
|
||||
*(sa + 64*ib + 8*ly + lx) = loop_k + 16*il + i < args.ne00 ? (S0) *((device T0 *) x + i) : 0;
|
||||
}
|
||||
} else {
|
||||
S0_4x4 temp_a;
|
||||
@@ -582,8 +582,6 @@ kernel void kernel_mul_mm_id(
|
||||
|
||||
const bool has_hi = nr1 > NR1H;
|
||||
|
||||
const short lb1 = (short) tiitg/NL1; // 0 .. NR1-1, this thread's row of the B tile
|
||||
|
||||
// power-of-two rescaling
|
||||
const float s1_inv = FC_mul_mm_id_amax ? ((device const float *) amax)[0] : 1.0f;
|
||||
const float s1_scale = FC_mul_mm_id_amax ? ((device const float *) amax)[1] : 1.0f;
|
||||
@@ -701,7 +699,7 @@ kernel void kernel_mul_mm_id(
|
||||
//const short lx = (tiitg/NL0)%8;
|
||||
//const short ly = i%8;
|
||||
|
||||
*(sa + NK*(8*sy + ly) + 8*sx + lx) = loop_k + 16*il + i < args.ne00 ? *((device T0 *) x + i) : 0;
|
||||
*(sa + NK*(8*sy + ly) + 8*sx + lx) = loop_k + 16*il + i < args.ne00 ? (S0) *((device T0 *) x + i) : 0;
|
||||
}
|
||||
} else {
|
||||
S0_4x4 temp_a;
|
||||
@@ -923,7 +921,11 @@ template [[host_name("kernel_mul_mm_id_q4_1_f32")]] kernel mul_mm_id kernel_m
|
||||
template [[host_name("kernel_mul_mm_id_q5_0_f32")]] kernel mul_mm_id kernel_mul_mm_id<half, half4x4, simdgroup_half8x8, half, half2x4, simdgroup_half8x8, block_q5_0, 2, dequantize_q5_0, float, float4x4, float, float2x4>;
|
||||
template [[host_name("kernel_mul_mm_id_q5_1_f32")]] kernel mul_mm_id kernel_mul_mm_id<half, half4x4, simdgroup_half8x8, half, half2x4, simdgroup_half8x8, block_q5_1, 2, dequantize_q5_1, float, float4x4, float, float2x4>;
|
||||
template [[host_name("kernel_mul_mm_id_q8_0_f32")]] kernel mul_mm_id kernel_mul_mm_id<half, half4x4, simdgroup_half8x8, half, half2x4, simdgroup_half8x8, block_q8_0, 2, dequantize_q8_0, float, float4x4, float, float2x4>;
|
||||
#if defined(GGML_METAL_HAS_BF16)
|
||||
template [[host_name("kernel_mul_mm_id_mxfp4_f32")]] kernel mul_mm_id kernel_mul_mm_id<bfloat, bfloat4x4, simdgroup_bfloat8x8, bfloat, bfloat2x4, simdgroup_bfloat8x8, block_mxfp4, 2, dequantize_mxfp4, float, float4x4, float, float2x4>;
|
||||
#else
|
||||
template [[host_name("kernel_mul_mm_id_mxfp4_f32")]] kernel mul_mm_id kernel_mul_mm_id<half, half4x4, simdgroup_half8x8, half, half2x4, simdgroup_half8x8, block_mxfp4, 2, dequantize_mxfp4, float, float4x4, float, float2x4>;
|
||||
#endif
|
||||
template [[host_name("kernel_mul_mm_id_q2_K_f32")]] kernel mul_mm_id kernel_mul_mm_id<half, half4x4, simdgroup_half8x8, half, half2x4, simdgroup_half8x8, block_q2_K, QK_NL, dequantize_q2_K, float, float4x4, float, float2x4>;
|
||||
template [[host_name("kernel_mul_mm_id_q3_K_f32")]] kernel mul_mm_id kernel_mul_mm_id<half, half4x4, simdgroup_half8x8, half, half2x4, simdgroup_half8x8, block_q3_K, QK_NL, dequantize_q3_K, float, float4x4, float, float2x4>;
|
||||
template [[host_name("kernel_mul_mm_id_q4_K_f32")]] kernel mul_mm_id kernel_mul_mm_id<half, half4x4, simdgroup_half8x8, half, half2x4, simdgroup_half8x8, block_q4_K, QK_NL, dequantize_q4_K, float, float4x4, float, float2x4>;
|
||||
@@ -949,7 +951,11 @@ template [[host_name("kernel_mul_mm_id_q4_1_f16")]] kernel mul_mm_id kernel_m
|
||||
template [[host_name("kernel_mul_mm_id_q5_0_f16")]] kernel mul_mm_id kernel_mul_mm_id<half, half4x4, simdgroup_half8x8, half, half2x4, simdgroup_half8x8, block_q5_0, 2, dequantize_q5_0, float, float4x4, half, half2x4>;
|
||||
template [[host_name("kernel_mul_mm_id_q5_1_f16")]] kernel mul_mm_id kernel_mul_mm_id<half, half4x4, simdgroup_half8x8, half, half2x4, simdgroup_half8x8, block_q5_1, 2, dequantize_q5_1, float, float4x4, half, half2x4>;
|
||||
template [[host_name("kernel_mul_mm_id_q8_0_f16")]] kernel mul_mm_id kernel_mul_mm_id<half, half4x4, simdgroup_half8x8, half, half2x4, simdgroup_half8x8, block_q8_0, 2, dequantize_q8_0, float, float4x4, half, half2x4>;
|
||||
#if defined(GGML_METAL_HAS_BF16)
|
||||
template [[host_name("kernel_mul_mm_id_mxfp4_f16")]] kernel mul_mm_id kernel_mul_mm_id<bfloat, bfloat4x4, simdgroup_bfloat8x8, bfloat, bfloat2x4, simdgroup_bfloat8x8, block_mxfp4, 2, dequantize_mxfp4, float, float4x4, half, half2x4>;
|
||||
#else
|
||||
template [[host_name("kernel_mul_mm_id_mxfp4_f16")]] kernel mul_mm_id kernel_mul_mm_id<half, half4x4, simdgroup_half8x8, half, half2x4, simdgroup_half8x8, block_mxfp4, 2, dequantize_mxfp4, float, float4x4, half, half2x4>;
|
||||
#endif
|
||||
template [[host_name("kernel_mul_mm_id_q2_K_f16")]] kernel mul_mm_id kernel_mul_mm_id<half, half4x4, simdgroup_half8x8, half, half2x4, simdgroup_half8x8, block_q2_K, QK_NL, dequantize_q2_K, float, float4x4, half, half2x4>;
|
||||
template [[host_name("kernel_mul_mm_id_q3_K_f16")]] kernel mul_mm_id kernel_mul_mm_id<half, half4x4, simdgroup_half8x8, half, half2x4, simdgroup_half8x8, block_q3_K, QK_NL, dequantize_q3_K, float, float4x4, half, half2x4>;
|
||||
template [[host_name("kernel_mul_mm_id_q4_K_f16")]] kernel mul_mm_id kernel_mul_mm_id<half, half4x4, simdgroup_half8x8, half, half2x4, simdgroup_half8x8, block_q4_K, QK_NL, dequantize_q4_K, float, float4x4, half, half2x4>;
|
||||
|
||||
@@ -6612,14 +6612,14 @@ static bool ggml_opencl_is_device_supported(ggml_backend_dev_t dev) {
|
||||
#endif
|
||||
|
||||
size_t ext_str_size;
|
||||
clGetDeviceInfo(dev_ctx->device, CL_DEVICE_EXTENSIONS, 0, NULL, &ext_str_size);
|
||||
CL_CHECK(clGetDeviceInfo(dev_ctx->device, CL_DEVICE_EXTENSIONS, 0, NULL, &ext_str_size));
|
||||
|
||||
char *ext_buffer = (char *)alloca(ext_str_size + 1);
|
||||
clGetDeviceInfo(dev_ctx->device, CL_DEVICE_EXTENSIONS, ext_str_size, ext_buffer, NULL);
|
||||
std::vector<char> ext_buffer(ext_str_size + 1);
|
||||
CL_CHECK(clGetDeviceInfo(dev_ctx->device, CL_DEVICE_EXTENSIONS, ext_str_size, ext_buffer.data(), NULL));
|
||||
ext_buffer[ext_str_size] = '\0';
|
||||
|
||||
// Check if ext_buffer contains cl_khr_fp16
|
||||
bool fp16_support = strstr(ext_buffer, "cl_khr_fp16") != NULL;
|
||||
bool fp16_support = strstr(ext_buffer.data(), "cl_khr_fp16") != NULL;
|
||||
if (!fp16_support) {
|
||||
GGML_LOG_WARN("ggml_opencl: device does not support FP16\n");
|
||||
return false;
|
||||
@@ -6627,8 +6627,8 @@ static bool ggml_opencl_is_device_supported(ggml_backend_dev_t dev) {
|
||||
|
||||
// If OpenCL 3.0 is supported, then check for cl_khr_subgroups, which becomes
|
||||
// optional in OpenCL 3.0 (cl_khr_subgroup is mandatory in OpenCL 2.x)
|
||||
if (opencl_c_version.major == 3 && strstr(ext_buffer, "cl_khr_subgroups") == NULL &&
|
||||
strstr(ext_buffer, "cl_intel_subgroups") == NULL) {
|
||||
if (opencl_c_version.major == 3 && strstr(ext_buffer.data(), "cl_khr_subgroups") == NULL &&
|
||||
strstr(ext_buffer.data(), "cl_intel_subgroups") == NULL) {
|
||||
GGML_LOG_WARN("ggml_opencl: device does not support subgroups (cl_khr_subgroups or cl_intel_subgroups) "
|
||||
"(note that subgroups is an optional feature in OpenCL 3.0)\n");
|
||||
return false;
|
||||
@@ -6691,16 +6691,17 @@ static ggml_backend_opencl_context * ggml_cl_init(ggml_backend_dev_t dev) {
|
||||
|
||||
// Check driver version
|
||||
size_t driver_version_str_size;
|
||||
clGetDeviceInfo(device, CL_DRIVER_VERSION, 0, NULL, &driver_version_str_size);
|
||||
char *driver_version = (char *)alloca(driver_version_str_size + 1);
|
||||
clGetDeviceInfo(device, CL_DRIVER_VERSION, driver_version_str_size, driver_version, NULL);
|
||||
CL_CHECK(clGetDeviceInfo(device, CL_DRIVER_VERSION, 0, NULL, &driver_version_str_size));
|
||||
std::vector<char> driver_version(driver_version_str_size + 1);
|
||||
CL_CHECK(clGetDeviceInfo(device, CL_DRIVER_VERSION, driver_version_str_size, driver_version.data(), NULL));
|
||||
driver_version[driver_version_str_size] = '\0';
|
||||
backend_ctx->driver_version = driver_version;
|
||||
backend_ctx->driver_version = driver_version.data();
|
||||
|
||||
backend_ctx->adreno_cl_compiler_version = get_adreno_cl_compiler_version(driver_version);
|
||||
backend_ctx->adreno_cl_compiler_version = get_adreno_cl_compiler_version(driver_version.data());
|
||||
backend_ctx->has_vector_subgroup_broadcast =
|
||||
(backend_ctx->adreno_cl_compiler_version.type == E031 && backend_ctx->adreno_cl_compiler_version.major >= 47) ||
|
||||
(backend_ctx->adreno_cl_compiler_version.type == DX && backend_ctx->adreno_cl_compiler_version.major >= 17);
|
||||
(backend_ctx->adreno_cl_compiler_version.type == DX && backend_ctx->adreno_cl_compiler_version.major >= 17) ||
|
||||
(backend_ctx->adreno_cl_compiler_version.type == E17);
|
||||
|
||||
// The q6_K flat mul_mat miscompile is a defect of the older E031 compilers, not a
|
||||
// property of any GPU generation: it reproduces on E031.38 (Adreno 642L) and E031.41
|
||||
@@ -6713,33 +6714,33 @@ static ggml_backend_opencl_context * ggml_cl_init(ggml_backend_dev_t dev) {
|
||||
!backend_ctx->adreno_cl_compiler_version.newer_than_or_same(E031, 45, 0, 0);
|
||||
|
||||
size_t ext_str_size;
|
||||
clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, 0, NULL, &ext_str_size);
|
||||
char *ext_buffer = (char *)alloca(ext_str_size + 1);
|
||||
clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, ext_str_size, ext_buffer, NULL);
|
||||
CL_CHECK(clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, 0, NULL, &ext_str_size));
|
||||
std::vector<char> ext_buffer(ext_str_size + 1);
|
||||
CL_CHECK(clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, ext_str_size, ext_buffer.data(), NULL));
|
||||
ext_buffer[ext_str_size] = '\0'; // ensure it is null terminated
|
||||
|
||||
// check support for qcom_subgroup_shuffle
|
||||
if (strstr(ext_buffer, "cl_qcom_subgroup_shuffle") != NULL) {
|
||||
if (strstr(ext_buffer.data(), "cl_qcom_subgroup_shuffle") != NULL) {
|
||||
backend_ctx->has_qcom_subgroup_shuffle = true;
|
||||
}
|
||||
|
||||
// Check if ext_buffer contains cl_khr_fp16
|
||||
backend_ctx->fp16_support = strstr(ext_buffer, "cl_khr_fp16") != NULL;
|
||||
backend_ctx->fp16_support = strstr(ext_buffer.data(), "cl_khr_fp16") != NULL;
|
||||
|
||||
// check Adreno large buffer support
|
||||
backend_ctx->adreno_has_large_buffer = strstr(ext_buffer, "cl_qcom_large_buffer") != NULL;
|
||||
backend_ctx->adreno_has_large_buffer = strstr(ext_buffer.data(), "cl_qcom_large_buffer") != NULL;
|
||||
|
||||
// subgroup shuffle support (N_SPLIT>1 FA kernel)
|
||||
backend_ctx->has_qcom_subgroup_shuffle = strstr(ext_buffer, "cl_qcom_subgroup_shuffle") != NULL;
|
||||
backend_ctx->has_qcom_subgroup_shuffle = strstr(ext_buffer.data(), "cl_qcom_subgroup_shuffle") != NULL;
|
||||
backend_ctx->has_subgroup_shuffle =
|
||||
strstr(ext_buffer, "cl_khr_subgroup_shuffle") != NULL ||
|
||||
strstr(ext_buffer.data(), "cl_khr_subgroup_shuffle") != NULL ||
|
||||
backend_ctx->has_qcom_subgroup_shuffle;
|
||||
|
||||
// check for cl_khr_integer_dot_product
|
||||
// cl_qcom_dot_product8 uses signed * unsigned
|
||||
// while cl_khr_integer_dot_product uses signed * signed -- we stick with khr for now
|
||||
backend_ctx->has_integer_dot =
|
||||
strstr(ext_buffer, "cl_khr_integer_dot_product") != NULL;
|
||||
strstr(ext_buffer.data(), "cl_khr_integer_dot_product") != NULL;
|
||||
|
||||
cl_uint base_align_in_bits;
|
||||
CL_CHECK(clGetDeviceInfo(device, CL_DEVICE_MEM_BASE_ADDR_ALIGN, sizeof(cl_uint), &base_align_in_bits, NULL));
|
||||
@@ -12454,9 +12455,13 @@ static void ggml_backend_opencl_buffer_get_tensor(ggml_backend_buffer_t buffer,
|
||||
buf_trans_d.allocate(backend_ctx->context, size_d);
|
||||
buf_trans_dm.allocate(backend_ctx->context, size_dm);
|
||||
|
||||
// bin kernel transposes s but src kernel does not
|
||||
cl_mem buf_s = extra->s;
|
||||
|
||||
if (use_q5_k_bin_kernels(backend_ctx, tensor)) {
|
||||
transpose_2d_as_32b(backend_ctx, extra->q, buf_trans_q.buffer, size_q, M, K/8);
|
||||
transpose_2d_as_8b (backend_ctx, extra->s, buf_trans_s.buffer, size_s, M, K/256*12, true, true);
|
||||
buf_s = buf_trans_s.buffer;
|
||||
} else {
|
||||
transpose_2d_as_16b(backend_ctx, extra->q, buf_trans_q.buffer, size_q, M, K/4);
|
||||
}
|
||||
@@ -12467,7 +12472,7 @@ static void ggml_backend_opencl_buffer_get_tensor(ggml_backend_buffer_t buffer,
|
||||
cl_kernel kernel = backend_ctx->kernel_restore_block_q5_K_noshuffle;
|
||||
CL_CHECK(clSetKernelArg(kernel, 0, sizeof(cl_mem), &buf_trans_q.buffer));
|
||||
CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_mem), &buf_trans_qh.buffer));
|
||||
CL_CHECK(clSetKernelArg(kernel, 2, sizeof(cl_mem), &buf_trans_s.buffer));
|
||||
CL_CHECK(clSetKernelArg(kernel, 2, sizeof(cl_mem), &buf_s));
|
||||
CL_CHECK(clSetKernelArg(kernel, 3, sizeof(cl_mem), &buf_trans_d.buffer));
|
||||
CL_CHECK(clSetKernelArg(kernel, 4, sizeof(cl_mem), &buf_trans_dm.buffer));
|
||||
CL_CHECK(clSetKernelArg(kernel, 5, sizeof(cl_mem), &data_device));
|
||||
|
||||
@@ -1165,6 +1165,11 @@ void GgmlOvDecoder::compute_model_inputs() {
|
||||
if (m_model_weights.find(src_name) != m_model_weights.end()) {
|
||||
continue;
|
||||
}
|
||||
// A view over a weight is served by the base tensor's Constant, never by a Parameter.
|
||||
if (src->view_src != nullptr &&
|
||||
m_model_weights.find(get_tensor_ov_name(m_cgraph, src->view_src)) != m_model_weights.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool is_intermediate_node = false;
|
||||
for (const auto & node_info : m_node_info_list) {
|
||||
@@ -1300,19 +1305,19 @@ std::map<std::string, std::shared_ptr<ov::Node>> GgmlOvDecoder::create_weight_no
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string src_name = get_tensor_ov_name(cgraph, src);
|
||||
if (is_rope_freqs_weight(src, node)) {
|
||||
// A view over a weight is served by the base tensor's Constant.
|
||||
ggml_tensor * base = src->view_src ? src->view_src : src;
|
||||
std::string src_name = get_tensor_ov_name(cgraph, base);
|
||||
if (is_rope_freqs_weight(base, node)) {
|
||||
src_name = "rope_freqs.weight";
|
||||
}
|
||||
if (!src->view_src) {
|
||||
ggml_backend_buffer * buffer = src->buffer;
|
||||
if (buffer->usage == GGML_BACKEND_BUFFER_USAGE_WEIGHTS || ggml_is_quantized(src->type) ||
|
||||
is_mul_mat_id_expert_weight(node, i)) {
|
||||
if (model_weights.find(src_name) == model_weights.end()) {
|
||||
auto weight_node = create_weight_node(src, naive);
|
||||
weight_node->set_friendly_name(src_name);
|
||||
model_weights[src_name] = weight_node;
|
||||
}
|
||||
ggml_backend_buffer * buffer = base->buffer;
|
||||
if (buffer->usage == GGML_BACKEND_BUFFER_USAGE_WEIGHTS || ggml_is_quantized(base->type) ||
|
||||
is_mul_mat_id_expert_weight(node, i)) {
|
||||
if (model_weights.find(src_name) == model_weights.end()) {
|
||||
auto weight_node = create_weight_node(base, naive);
|
||||
weight_node->set_friendly_name(src_name);
|
||||
model_weights[src_name] = weight_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1341,15 +1346,14 @@ std::set<std::string> GgmlOvDecoder::collect_weight_names(ggml_cgraph * cgraph)
|
||||
if (src == nullptr) {
|
||||
continue;
|
||||
}
|
||||
std::string src_name(src->name);
|
||||
if (is_rope_freqs_weight(src, node)) {
|
||||
const ggml_tensor * base = src->view_src ? src->view_src : src;
|
||||
std::string src_name(base->name);
|
||||
if (is_rope_freqs_weight(base, node)) {
|
||||
src_name = "rope_freqs.weight";
|
||||
}
|
||||
if (!src->view_src) {
|
||||
ggml_backend_buffer * buffer = src->buffer;
|
||||
if (buffer->usage == GGML_BACKEND_BUFFER_USAGE_WEIGHTS || ggml_is_quantized(src->type)) {
|
||||
names.insert(src_name);
|
||||
}
|
||||
ggml_backend_buffer * buffer = base->buffer;
|
||||
if (buffer->usage == GGML_BACKEND_BUFFER_USAGE_WEIGHTS || ggml_is_quantized(base->type)) {
|
||||
names.insert(src_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1179,10 +1179,6 @@ static ggml_openvino_op_support is_op_supported_case(const ggml_tensor * op) {
|
||||
if (op->ne[3] != 1) {
|
||||
return {false, "GET_ROWS/SET_ROWS with ne[3] != 1 (ne[3]=" + std::to_string(op->ne[3]) + ") is not supported"};
|
||||
}
|
||||
if (op->op == GGML_OP_GET_ROWS && ggml_is_quantized(op->src[0]->type) &&
|
||||
op->src[0]->view_src != nullptr && op->src[0]->view_offs != 0) {
|
||||
return {false, "GET_ROWS with a nonzero quantized src0 view offset is not supported"};
|
||||
}
|
||||
if (op->op == GGML_OP_GET_ROWS && ggml_openvino_get_device_name() == "GPU" &&
|
||||
op->src[0]->type == GGML_TYPE_BF16) {
|
||||
return {false, "GET_ROWS with BF16 src0 is not supported on GPU"};
|
||||
@@ -1211,6 +1207,10 @@ static ggml_openvino_op_support is_op_supported_case(const ggml_tensor * op) {
|
||||
if (op->src[1]->op == GGML_OP_PERMUTE) {
|
||||
return {false, "ADD/MUL/SUB with PERMUTE src1 is not supported"};
|
||||
}
|
||||
if (op->src[0]->type != op->src[1]->type &&
|
||||
(op->src[0]->type == GGML_TYPE_BF16 || op->src[1]->type == GGML_TYPE_BF16)) {
|
||||
return {false, "ADD/MUL/SUB with BF16 and a different src1 type is not supported"};
|
||||
}
|
||||
// >8-expert MoE ReduceSum drifts past the 1e-7 tolerance (f32 order vs CPU); intermittent.
|
||||
if (op->op == GGML_OP_ADD && is_moe_expert_sum_add(op) && op->src[1]->src[0]->ne[1] > 8) {
|
||||
return {false, "MoE expert-plane sum with more than 8 experts is not supported"};
|
||||
@@ -1224,6 +1224,12 @@ static ggml_openvino_op_support is_op_supported_case(const ggml_tensor * op) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GGML_OP_SCALE: {
|
||||
if (op->type == GGML_TYPE_BF16) {
|
||||
return {false, "SCALE with BF16 type is not supported"};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GGML_OP_ADD_ID: {
|
||||
// Keep support aligned with the CPU backend implementation, which only handles f32 inputs/output and i32 ids.
|
||||
if (op->type != GGML_TYPE_F32 || op->src[0]->type != GGML_TYPE_F32 || op->src[1]->type != GGML_TYPE_F32 ||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <climits>
|
||||
#include <openvino/core/node.hpp>
|
||||
#include <openvino/core/node_output.hpp>
|
||||
#include <openvino/op/add.hpp>
|
||||
#include <openvino/op/broadcast.hpp>
|
||||
#include <openvino/op/concat.hpp>
|
||||
#include <openvino/op/constant.hpp>
|
||||
@@ -24,7 +25,23 @@ OutputVector translate_get_rows(const NodeContext & context) {
|
||||
num_inputs_check(context, 2, 2);
|
||||
|
||||
Output<Node> res;
|
||||
auto data = process_view_input_new(context, 0);
|
||||
Output<Node> data;
|
||||
int64_t row_offset = 0;
|
||||
if (context.get_view_input_size(0) > 0 && context.get_input(0).get_partial_shape().rank() == 2) {
|
||||
// A row range view over a 2D weight Constant folds into the gather indices,
|
||||
// which keeps the dequantization subgraph intact for the plugins.
|
||||
const auto view_shape = context.get_view_input_ggml_shape(0, 0);
|
||||
const auto view_stride = context.get_view_input_stride(0, 0);
|
||||
const size_t view_offset = context.get_view_input_offset(0, 0);
|
||||
const size_t row_bytes = view_stride[2];
|
||||
data = context.get_input(0);
|
||||
FRONT_END_OP_CONVERSION_CHECK(row_bytes > 0 && view_offset % row_bytes == 0 &&
|
||||
data.get_partial_shape()[1].compatible(view_shape[3]),
|
||||
"GET_ROWS: view over a weight must be a row range");
|
||||
row_offset = static_cast<int64_t>(view_offset / row_bytes);
|
||||
} else {
|
||||
data = process_view_input_new(context, 0);
|
||||
}
|
||||
|
||||
auto op_case = context.get_op_case();
|
||||
ov::Output<ov::Node> indices;
|
||||
@@ -51,6 +68,10 @@ OutputVector translate_get_rows(const NodeContext & context) {
|
||||
// data[x,y] ind[1,1,1,x'] normal case
|
||||
indices =
|
||||
std::make_shared<ov::op::v0::Squeeze>(indices, ov::op::v0::Constant::create(ov::element::i64, {2}, {0, 1}));
|
||||
if (row_offset != 0) {
|
||||
indices = std::make_shared<ov::op::v1::Add>(
|
||||
indices, ov::op::v0::Constant::create(indices.get_element_type(), {}, {row_offset}));
|
||||
}
|
||||
if (data.get_partial_shape().rank() == 4) {
|
||||
if (!(data.get_partial_shape()[1].is_dynamic()) && data.get_partial_shape()[1].get_length() == 1) {
|
||||
// Work-around for a bug in ov cpu plugin for test-backend-ops
|
||||
|
||||
@@ -6995,8 +6995,48 @@ struct ggml_backend_sycl_comm_context {
|
||||
std::unique_ptr<ggml_sycl_pool_alloc<uint8_t>> buf0;
|
||||
std::unique_ptr<ggml_sycl_pool_alloc<uint8_t>> buf1;
|
||||
int64_t buf_nelem = 0;
|
||||
|
||||
// pinned host staging per device context, reused across calls (queues are in-order)
|
||||
uint8_t * host_out[2] = { nullptr, nullptr };
|
||||
uint8_t * host_in[2] = { nullptr, nullptr };
|
||||
size_t host_bytes = 0;
|
||||
|
||||
void free_host() {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
const sycl::context sctx = ((ggml_backend_sycl_context *) backends[i]->context)->stream()->get_context();
|
||||
if (host_out[i]) { sycl::free(host_out[i], sctx); host_out[i] = nullptr; }
|
||||
if (host_in[i]) { sycl::free(host_in[i], sctx); host_in[i] = nullptr; }
|
||||
}
|
||||
host_bytes = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// dst0 <- src1 and dst1 <- src0 through pinned host memory, with a single host wait
|
||||
static void ggml_sycl_comm_exchange(ggml_backend_sycl_comm_context * comm, queue_ptr q0, queue_ptr q1,
|
||||
void * dst0, const void * src1, void * dst1, const void * src0,
|
||||
size_t nbytes) {
|
||||
if (comm->host_bytes < nbytes) {
|
||||
q0->wait();
|
||||
q1->wait();
|
||||
comm->free_host();
|
||||
comm->host_out[0] = sycl::malloc_host<uint8_t>(nbytes, q0->get_context());
|
||||
comm->host_in[0] = sycl::malloc_host<uint8_t>(nbytes, q0->get_context());
|
||||
comm->host_out[1] = sycl::malloc_host<uint8_t>(nbytes, q1->get_context());
|
||||
comm->host_in[1] = sycl::malloc_host<uint8_t>(nbytes, q1->get_context());
|
||||
GGML_ASSERT(comm->host_out[0] && comm->host_in[0] && comm->host_out[1] && comm->host_in[1]);
|
||||
comm->host_bytes = nbytes;
|
||||
}
|
||||
|
||||
sycl::event e0 = q0->memcpy(comm->host_out[0], src0, nbytes);
|
||||
sycl::event e1 = q1->memcpy(comm->host_out[1], src1, nbytes);
|
||||
e0.wait();
|
||||
e1.wait();
|
||||
std::memcpy(comm->host_in[0], comm->host_out[1], nbytes);
|
||||
std::memcpy(comm->host_in[1], comm->host_out[0], nbytes);
|
||||
q0->memcpy(dst0, comm->host_in[0], nbytes);
|
||||
q1->memcpy(dst1, comm->host_in[1], nbytes);
|
||||
}
|
||||
|
||||
void * ggml_backend_sycl_comm_init(ggml_backend_t * backends, size_t n_backends) try {
|
||||
for (size_t i = 0; i < n_backends; ++i) {
|
||||
if (!ggml_backend_is_sycl(backends[i])) {
|
||||
@@ -7035,6 +7075,7 @@ void ggml_backend_sycl_comm_free(void * comm_ctx_v) {
|
||||
try {
|
||||
sctx0->stream()->wait();
|
||||
sctx1->stream()->wait();
|
||||
comm_ctx->free_host();
|
||||
} catch (...) { /* best effort during shutdown */ }
|
||||
}
|
||||
|
||||
@@ -7090,19 +7131,15 @@ bool ggml_backend_sycl_comm_allreduce_tensor(void * comm_ctx_v, struct ggml_tens
|
||||
uint8_t * buf1 = comm_ctx->buf1->get();
|
||||
|
||||
// F16 native path: direct 2-byte cross-device copy + add, skipping the
|
||||
// F32 round-trip the meta-backend fallback would force. Cross-device copies
|
||||
// go through dev2dev_memcpy because the two devices are in separate SYCL
|
||||
// contexts (a raw peer-USM q->memcpy would be a silent no-op).
|
||||
// F32 round-trip the meta-backend fallback would force. The devices are in separate SYCL
|
||||
// contexts (a raw peer-USM q->memcpy would be a silent no-op), so copies go through host memory.
|
||||
if (tensors[0]->type == GGML_TYPE_F16) {
|
||||
sycl::half * f16_out0 = (sycl::half *) tensors[0]->data;
|
||||
sycl::half * f16_out1 = (sycl::half *) tensors[1]->data;
|
||||
sycl::half * f16_tmp0 = (sycl::half *) buf0;
|
||||
sycl::half * f16_tmp1 = (sycl::half *) buf1;
|
||||
|
||||
q0->wait();
|
||||
q1->wait();
|
||||
dev2dev_memcpy(ctx0->device, *q0, ctx1->device, *q1, f16_tmp0, tensors[1]->data, nbytes);
|
||||
dev2dev_memcpy(ctx1->device, *q1, ctx0->device, *q0, f16_tmp1, tensors[0]->data, nbytes);
|
||||
ggml_sycl_comm_exchange(comm_ctx, q0, q1, f16_tmp0, tensors[1]->data, f16_tmp1, tensors[0]->data, nbytes);
|
||||
|
||||
q0->submit([&](sycl::handler & h) {
|
||||
h.parallel_for(sycl::range<1>(nelem), [=](sycl::id<1> i) {
|
||||
@@ -7131,14 +7168,8 @@ bool ggml_backend_sycl_comm_allreduce_tensor(void * comm_ctx_v, struct ggml_tens
|
||||
float * tmp0 = (float *) buf0;
|
||||
float * tmp1 = (float *) buf1;
|
||||
|
||||
// COMM-D2D-FIX: the two devices are in SEPARATE SYCL contexts, so a raw
|
||||
// q->memcpy of a peer USM pointer is a silent no-op. Route cross-device
|
||||
// copies through dev2dev_memcpy (L0 direct copy / host staging). It is
|
||||
// synchronous, so wait for the local partials to be produced first.
|
||||
q0->wait();
|
||||
q1->wait();
|
||||
dev2dev_memcpy(ctx0->device, *q0, ctx1->device, *q1, tmp0, tensors[1]->data, nbytes);
|
||||
dev2dev_memcpy(ctx1->device, *q1, ctx0->device, *q0, tmp1, tensors[0]->data, nbytes);
|
||||
// separate SYCL contexts: a raw peer-USM q->memcpy is a silent no-op, so stage through host memory
|
||||
ggml_sycl_comm_exchange(comm_ctx, q0, q1, tmp0, tensors[1]->data, tmp1, tensors[0]->data, nbytes);
|
||||
|
||||
q0->submit([&](sycl::handler & h) {
|
||||
h.parallel_for(sycl::range<1>(nelem), [=](sycl::id<1> i) {
|
||||
@@ -7162,21 +7193,17 @@ bool ggml_backend_sycl_comm_allreduce_tensor(void * comm_ctx_v, struct ggml_tens
|
||||
uint16_t * inbox1 = outbox1 + nelem;
|
||||
|
||||
// Phase A: compress each device's local partial in parallel.
|
||||
sycl::event c0 = q0->parallel_for(sycl::range<1>(nelem), [=](sycl::id<1> i) {
|
||||
q0->parallel_for(sycl::range<1>(nelem), [=](sycl::id<1> i) {
|
||||
outbox0[i] = (uint16_t) (sycl::bit_cast<uint32_t>(out0[i]) >> 16);
|
||||
});
|
||||
|
||||
sycl::event c1 = q1->parallel_for(sycl::range<1>(nelem), [=](sycl::id<1> i) {
|
||||
q1->parallel_for(sycl::range<1>(nelem), [=](sycl::id<1> i) {
|
||||
outbox1[i] = (uint16_t) (sycl::bit_cast<uint32_t>(out1[i]) >> 16);
|
||||
});
|
||||
|
||||
// Phase B: COMM-D2D-FIX-BF16 cross-device copy of compressed bytes via
|
||||
// dev2dev_memcpy (separate SYCL contexts; sync copy after compress).
|
||||
// Phase B: exchange the compressed bytes (in-order queues keep this after the compress kernels).
|
||||
const size_t bf16_bytes = nelem * sizeof(uint16_t);
|
||||
c0.wait();
|
||||
c1.wait();
|
||||
dev2dev_memcpy(ctx0->device, *q0, ctx1->device, *q1, inbox0, outbox1, bf16_bytes);
|
||||
dev2dev_memcpy(ctx1->device, *q1, ctx0->device, *q0, inbox1, outbox0, bf16_bytes);
|
||||
ggml_sycl_comm_exchange(comm_ctx, q0, q1, inbox0, outbox1, inbox1, outbox0, bf16_bytes);
|
||||
|
||||
// Phase C: decompress + add into local FP32 partial.
|
||||
q0->submit([&](sycl::handler & h) {
|
||||
|
||||
@@ -3668,33 +3668,43 @@ void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
const uint32_t S_V = gdn_sizes[si];
|
||||
GGML_ASSERT(is_pow2(S_V));
|
||||
|
||||
// Intel Xe regresses at SIMD32 for this scan; prefer a narrower subgroup.
|
||||
uint32_t gdn_subgroup_size = device->subgroup_size;
|
||||
if (device->vendor_id == VK_VENDOR_ID_INTEL && device->subgroup_size_control &&
|
||||
device->subgroup_min_size <= 16u && device->subgroup_max_size >= 16u) {
|
||||
gdn_subgroup_size = 16u;
|
||||
}
|
||||
uint32_t lanes_per_column;
|
||||
if (S_V >= 128u && device->subgroup_clustered) {
|
||||
lanes_per_column = 8u;
|
||||
if (device->vendor_id == VK_VENDOR_ID_INTEL) {
|
||||
// Intel Xe: full-width reduction (min rows/lane) ~10x over the COLS_PER_WG=8 rule.
|
||||
lanes_per_column = std::min(gdn_subgroup_size, S_V);
|
||||
} else if (S_V >= 128u && device->subgroup_clustered) {
|
||||
// COLS_PER_WG=8: measured optimum (Ampere sg32->4, Vega20 sg64->8).
|
||||
lanes_per_column = std::max(1u, gdn_subgroup_size / 8u);
|
||||
} else {
|
||||
// Use largest power-of-two that divides both S_V and subgroup_size so that
|
||||
// (1) S_V % lanes_per_column == 0 and (2) S_V % (subgroup_size / lanes_per_column) == 0.
|
||||
// This means we don't need extra bounds checking logic in the shader.
|
||||
lanes_per_column = std::min(S_V, device->subgroup_size);
|
||||
lanes_per_column = std::min(S_V, gdn_subgroup_size);
|
||||
}
|
||||
|
||||
// gated_delta_net.comp relies on S_V % COLS_PER_WG == 0 and
|
||||
// S_V % LANES_PER_COLUMN == 0 to avoid bounds checks.
|
||||
while (lanes_per_column > 1u) {
|
||||
const bool valid_lanes = (device->subgroup_size % lanes_per_column) == 0 &&
|
||||
const bool valid_lanes = (gdn_subgroup_size % lanes_per_column) == 0 &&
|
||||
(S_V % lanes_per_column) == 0;
|
||||
const uint32_t cols_per_wg = valid_lanes ? device->subgroup_size / lanes_per_column : 0;
|
||||
const uint32_t cols_per_wg = valid_lanes ? gdn_subgroup_size / lanes_per_column : 0;
|
||||
if (valid_lanes && cols_per_wg > 0 && (S_V % cols_per_wg) == 0) {
|
||||
break;
|
||||
}
|
||||
lanes_per_column >>= 1u;
|
||||
}
|
||||
|
||||
GGML_ASSERT((device->subgroup_size % lanes_per_column) == 0);
|
||||
GGML_ASSERT((gdn_subgroup_size % lanes_per_column) == 0);
|
||||
GGML_ASSERT((S_V % lanes_per_column) == 0);
|
||||
GGML_ASSERT((S_V % (device->subgroup_size / lanes_per_column)) == 0);
|
||||
GGML_ASSERT((S_V % (gdn_subgroup_size / lanes_per_column)) == 0);
|
||||
|
||||
const bool need_partial_subgroup_reduce = lanes_per_column != 1u && lanes_per_column < device->subgroup_size;
|
||||
const bool need_partial_subgroup_reduce = lanes_per_column != 1u && lanes_per_column < gdn_subgroup_size;
|
||||
const bool use_clustered_reduce = device->subgroup_arithmetic && device->subgroup_clustered && need_partial_subgroup_reduce;
|
||||
const bool use_subgroup_reduce = device->subgroup_arithmetic && !need_partial_subgroup_reduce;
|
||||
const bool use_subgroup_ops = use_clustered_reduce || use_subgroup_reduce;
|
||||
@@ -3711,13 +3721,13 @@ void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
gdn_data = (const void *)gated_delta_net_f32_shmem_data;
|
||||
}
|
||||
|
||||
const uint32_t cols_per_wg = device->subgroup_size / lanes_per_column;
|
||||
const uint32_t cols_per_wg = gdn_subgroup_size / lanes_per_column;
|
||||
const std::array<uint32_t, 3> wg_denoms = {1u, 1u, cols_per_wg};
|
||||
|
||||
for (uint32_t kda = 0; kda < 2; kda++) {
|
||||
ggml_vk_create_pipeline(device, device->pipeline_gated_delta_net[si][kda],
|
||||
gdn_names[si][kda], gdn_len, gdn_data, "main", 7, sizeof(vk_op_gated_delta_net_push_constants),
|
||||
wg_denoms, {S_V, kda, device->subgroup_size, lanes_per_column}, 1, true, use_subgroup_ops, device->subgroup_size);
|
||||
wg_denoms, {S_V, kda, gdn_subgroup_size, lanes_per_column}, 1, true, use_subgroup_ops, gdn_subgroup_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7407,10 +7417,11 @@ static void ggml_vk_mul_mat_id_q_f16(ggml_backend_vk_context * ctx, vk_context&
|
||||
|
||||
GGML_ASSERT(mmp_map != nullptr);
|
||||
|
||||
const uint32_t kpad = quantize_y ? 0 : ggml_vk_align_size(ne10, ggml_vk_guess_matmul_pipeline_align_map(ctx, *mmp_map, ne01, nei1, true));
|
||||
const bool aligned = !quantize_y && ne10 == kpad && ne01 > 8 && nei1 > 8;
|
||||
const uint32_t n_per_expert = (uint32_t)CEIL_DIV(nei0 * nei1, n_as);
|
||||
const uint32_t kpad = quantize_y ? 0 : ggml_vk_align_size(ne10, ggml_vk_guess_matmul_pipeline_align_map(ctx, *mmp_map, ne01, n_per_expert, true));
|
||||
const bool aligned = !quantize_y && ne10 == kpad && ne01 > 8 && n_per_expert > 8;
|
||||
|
||||
vk_pipeline pipeline = ggml_vk_guess_matmul_pipeline_map(ctx, *mmp_map, ne01, nei1, aligned, true);
|
||||
vk_pipeline pipeline = ggml_vk_guess_matmul_pipeline_map(ctx, *mmp_map, ne01, n_per_expert, aligned, true);
|
||||
|
||||
if (ggml_nbytes(src0) > ctx->device->properties.limits.maxStorageBufferRange) {
|
||||
pipeline = ggml_vk_get_64b_indexing_pipeline(ctx, pipeline);
|
||||
@@ -15430,6 +15441,10 @@ static bool ggml_backend_vk_device_supports_op(ggml_backend_dev_t dev, const ggm
|
||||
// So don't support this combination for now.
|
||||
return false;
|
||||
}
|
||||
if (op->src[1]->type == GGML_TYPE_BF16 && op->src[0]->type != GGML_TYPE_BF16) {
|
||||
// BF16 in src1 is only served by the BF16 x BF16 pipelines
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,9 @@ vec4 dequantize4(uint ib, uint iqs, uint a_offset) {
|
||||
data_a[a_offset + ib + 2], data_a[a_offset + ib + 3]);
|
||||
}
|
||||
vec4 dequantize4_2aligned(uint ib, uint iqs, uint a_offset) {
|
||||
return vec4(data_a[a_offset + ib ], data_a[a_offset + ib + 1],
|
||||
data_a[a_offset + ib + 2], data_a[a_offset + ib + 3]);
|
||||
const vec2 a = data_a_packed64[(a_offset + ib)/2];
|
||||
const vec2 b = data_a_packed64[(a_offset + ib)/2 + 1];
|
||||
return vec4(a, b);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user