Skip to content

Commit 2aba569

Browse files
inforithmicswhyvlDSLstandardyeongbbatomaThomas
authored
Vulkan based on ollama#9650 (ollama#11835)
* implement the vulkan C backend * add support in gpu.go * add support in gen_linux.sh * it builds * fix segfault * fix compilation * fix free memory monitor * fix total memory monitor * update gpu.go * fix build * fix check_perfmon len * remove cap_get_bound check * fix vulkan handle releasing * fix build on federa 40 * fix vulkan on windows * making amdgpu work on arm achitecutre with vulkan * add x86_64 lines in VulkanGlobs and capLinuxGlobs * add aarch64 lines in vulkanGlobs and capLinuxGlobs * Fix variable name * Add vulkan build patch from @jmorganca * Sync vendored ggml to add Vulkan support * Updated dockerfile whyvl#7 (comment) Signed-off-by: Vadim Grinco <[email protected]> * Installing rocm library Signed-off-by: Vadim Grinco <[email protected]> * This version works well built based on this: whyvl#7 (comment) Signed-off-by: Vadim Grinco <[email protected]> * Applied 00-fix-vulkan-building.patch Work done by McBane87 here: whyvl#7 (comment) Signed-off-by: Vadim Grinco <[email protected]> * Fixed the "detached head" issues Signed-off-by: Vadim Grinco <[email protected]> * Merged in the right direction Signed-off-by: Vadim Grinco <[email protected]> * Merging the latest stable (#2) * Applied 00-fix-vulkan-building.patch * Implemented vulkan backend based on the work done by whyvl, Dts0, McBane87 and others Tested on AMD Ryzen 7 8845HS w/ Radeon 780M Graphics with ROCm disabled ``` [GIN-debug] POST /v1/chat/completions --> github.com/ollama/ollama/server.(*Server).ChatHandler-fm (6 handlers) [GIN-debug] POST /v1/completions --> github.com/ollama/ollama/server.(*Server).GenerateHandler-fm (6 handlers) [GIN-debug] POST /v1/embeddings --> github.com/ollama/ollama/server.(*Server).EmbedHandler-fm (6 handlers) [GIN-debug] GET /v1/models --> github.com/ollama/ollama/server.(*Server).ListHandler-fm (6 handlers) [GIN-debug] GET /v1/models/:model --> github.com/ollama/ollama/server.(*Server).ShowHandler-fm (6 handlers) time=2025-03-11T13:00:40.793Z level=INFO source=gpu.go:199 msg="vulkan: load libvulkan and libcap ok" time=2025-03-11T13:00:40.877Z level=INFO source=gpu.go:421 msg="error looking up vulkan GPU memory" error="device is a CPU" time=2025-03-11T13:00:40.878Z level=WARN source=amd_linux.go:443 msg="amdgpu detected, but no compatible rocm library found. Either install rocm v6, or follow manual install instructions at https://github.com/ollama/ollama/blob/main/docs/linux.md#manual-install" time=2025-03-11T13:00:40.878Z level=WARN source=amd_linux.go:348 msg="unable to verify rocm library: no suitable rocm found, falling back to CPU" time=2025-03-11T13:00:40.879Z level=INFO source=types.go:137 msg="inference compute" id=0 library=vulkan variant="" compute=1.3 driver=1.3 name="AMD Radeon Graphics (RADV GFX1103_R1)" total="15.6 GiB" available="15.6 GiB" ``` ``` # ollama run phi4:14b >>> /set verbose Set 'verbose' mode. >>> how's it going? Hello! I'm here to help you with any questions or tasks you have. How can I assist you today? 😊 total duration: 3.341959745s load duration: 18.165612ms prompt eval count: 15 token(s) prompt eval duration: 475ms prompt eval rate: 31.58 tokens/s eval count: 26 token(s) eval duration: 2.846s eval rate: 9.14 tokens/s >>> ``` * This is no longer needed Signed-off-by: Vadim Grinco <[email protected]> * Fixes SIGSEGV: segmentation violation running gemma3 models on ollama 0.6.0 ollama#21 Patch provided by McBane87 on whyvl#21 Signed-off-by: Vadim Grinco <[email protected]> * Applied 04-disable-mmap-vulkan.patch From: whyvl#7 (comment) Signed-off-by: Vadim Grinco <[email protected]> * Pulled new upstream code for ggml-bulkan backend Signed-off-by: Vadim Grinco <[email protected]> * Merged latest ollama 0.6.2 and nasrally's Flash Attention patches (#5) * readme: add Ellama to list of community integrations (ollama#9800) * readme: add screenpipe to community integrations (ollama#9786) * Add support for ROCm gfx1151 (ollama#9773) * conditionally enable parallel pipelines * sample: make mutations in transforms explicit (ollama#9743) * updated minP to use early exit making use of sorted tokens * ml/backend/ggml: allocate memory with malloc when loading model (ollama#9822) * runner: remove cache prompt flag from ollama runner (ollama#9826) We do not need to bypass the prompt caching in the ollama runner yet, as only embedding models needed to bypass the prompt caching. When embedding models are implemented they can skip initializing this cache completely. * ollamarunner: Check for minBatch of context space when shifting Models can specify that a group of inputs need to be handled a single batch. However, context shifting didn't respect this and could trigger a break anyways. In this case, we should instead trigger a context shift earlier so that it occurs before the grouped batch. Note that there still some corner cases: - A long prompt that exceeds the context window can get truncated in the middle of an image. With the current models, this will result in the model not recognizing the image at all, which is pretty much the expected result with truncation. - The context window is set less than the minimum batch size. The only solution to this is to refuse to load the model with these settings. However, this can never occur with current models and default settings. Since users are unlikely to run into these scenarios, fixing them is left as a follow up. * Applied latest patches from McBane87 See this for details: whyvl#7 (comment) Signed-off-by: Vadim Grinco <[email protected]> * Add ability to enable flash attention on vulkan (#4) * discover: add flash attention handling for vulkan * envconfig: fix typo in config.go As part of the process some code was refactored and I added a new field FlashAttention to GpuInfo since the previous solution didn't allow for a granular check via vulkan extensions. As a side effect, this now allows for granular per-device FA support checking in other places --------- Signed-off-by: Vadim Grinco <[email protected]> Co-authored-by: zeo <[email protected]> Co-authored-by: Louis Beaumont <[email protected]> Co-authored-by: Daniel Hiltgen <[email protected]> Co-authored-by: Michael Yang <[email protected]> Co-authored-by: Parth Sareen <[email protected]> Co-authored-by: Jeffrey Morgan <[email protected]> Co-authored-by: Bruce MacDonald <[email protected]> Co-authored-by: Jesse Gross <[email protected]> Co-authored-by: Nikita <[email protected]> * Revert Readme changes * Revert * Revert changes in amd_linux.go * Revert changes in amd_linux.go * Remove flashattention setting gpu.go * Revert whitespace changes in gpu.go * Revert changes in transforms_test.go * Revert changes in runner.go * Revert changes in Makefile.sync * Revert some unintented changes in Dockerfile * Revert vulkan copy changes in Dockerfile * Update Vulkan Code to de4c07f93783a1a96456a44dc16b9db538ee1618 * Fixed duplicate sync in ggml.go * Revert changes in ggml.go * Revert chnages in ggml.go * enable falsh attention on vulkan * revert remove parenthesis * fixed flash attention logic enabling * vk_check_flash_attention 0 means supported * Update gpu.go * Add vulkan to Windows Build script * Remove commented out code * Enable Vulkan Flash attention in FlashAttentionSupported * Fix logging * Update Vulkan backend to e54d41befcc1575f4c898c5ff4ef43970cead75f * Removed libcap related code libcap is not directly related to Vulkan and should be added by its own PR. It adds additional library dependencies for building and also requires users to run setcap or run ollama as root, which is not ideal for easy use * Fix Unit Test (Add Vulkan Library) * Add vulkan to TestHomogeneousGPUs Test * vulkan: get GPU ID (ollama v0.11.5) Signed-off-by: Xiaodong Ye <[email protected]> * disable mmap for vulkan * Reduce Changes remove TestHomogeneousGPUs (doesn't exist on master) * Update vulkan version to the version used in llama.cpp * rename gpu patch to correct number * added Vulkan API to get correct Device UUID current UUID from pipelineCacheUUID does not match CUDA * Fix GPU ID Patch * Remove Code not in llama.cpp * modified UUID code inside ggml * Fix Patch * Copied minimal definition from vulkan header * Fix compile error in Mac Metal is preferred so we're disabling Vulkan for now * Removed unused code Fix linter error in CI * Fix patches apply * fixing lint error * Removed unneeded function call Somehow removing this call fixed the crashing when Vulkan header was removed * added missing NL * Fixed missing members in Vulkan header also added zero clear for some structs * Fixed wrong structure ID * Fixed Vulkan header More aligned with official header definition now * buildvulkanAsSeperateFunction * Vulkan on Windows Test * temporarly comment out gate to run windows task * use temporarly windows-latest for build * Commenting out other presets to build vulkan * reenable cpu * commenting out error action stop * temporarly commenting out rocm * set vulkan path * comment out cude for faster turnaround * correct vulkan install * correct vulkan silent install * fixed install command * revert debugging changes (vulkan builds on windows) * revert windows-latest * trying to build vulkan for linux * temporarly disable cuda and rocm * try again linux build * fix version * trying to fix * trying again * trying again * fix version * fixed vulkan-sdk name * try again * trying again * try without version number * try again * add some more extra * trying to use version 1.4.313 * revert debugging changes * Filter out already supported gpus * revert debug code * Use runners for GPU discovery This revamps how we discover GPUs in the system by leveraging the Ollama runner. This should eliminate inconsistency between our GPU discovery and the runners capabilities at runtime, particularly for cases where we try to filter out unsupported GPUs. Now the runner does that implicitly based on the actual device list. In some cases free VRAM reporting can be unreliable which can leaad to scheduling mistakes, so this also includes a patch to leverage more reliable VRAM reporting libraries if available. Automatic workarounds have been removed as only one GPU leveraged this, which is now documented. This GPU will soon fall off the support matrix with the next ROCm bump. Additional cleanup of the scheduler and discovery packages can be done in the future once we have switched on the new memory management code, and removed support for the llama runner. * timing info for runner * WIP - wire up Vulkan with the new engine based discovery Not a complete implementation - free VRAM is better, but not accurate on windows * fix - trust the library paths from discovery when starting runner * fix index bug * fix vulkan ids to be underlying * fix - give bootstrapping more time on slow systems * Test if Vulkan device is supported * vk_check_flash_attention is not needed (coompat2 coopmapt and scalar implementation exist) * Handle GGML_VK_VISIBLE_DEVICES * ask for supported first * win: fix CPU query buffer handling Try in a short loop until we get the size right. * test: harden integration tests for slow start If the server takes a while to start up, block tests from starting until it's online to avoid setting large timeouts in individual test cases. * gofumpt fix * fix build * merge fixes * merge fixes * fixed build * merge fixes * fixing build * fixed build * fixed formatting * fixed build * fix vulkan gpu id patch * sync llama.cpp vulkan code * update build windows script * merge fixes * fix format * fixed vulkan casing * handle igpu as gpu * improve case * print out unknown library * rturn Vulkan for vulkan library * Revert "rturn Vulkan for vulkan library" This reverts commit 690461a. * fixed patch number * return Library Name * remvoe debug code * return integrated in vulkan backend * Return pci Properties * update patch * directly get pci proeprties without parsing * workaround for filtering devices. Correct way is to have a LibraryPosition Parameter in the deviceInfo * Revert "directly get pci proeprties without parsing" This reverts commit 8e06248. * Set FilteredID for Environment Filtering * ROCm Library is named ROCm * revert changes in patch * Create 0028-vulkan-pci-and-memory.patch * vulkan memory patch * casing fix * Add more pci properties * Added better memory management * Added better memory managament * fixed patch * Fixed patch * FilterID creation group by library * filter out vulkan supported by other gpu * fixing deviceid compare * Vulkan Fix FA coopmat1 invalid array indexing * Use everywhere the same Vulkan Version 1.4.321.1 * Remove unneeded patch * vulkan update * sync vulkan glsl files * only use for vulkan the filteredid (numeric device number) * simplify code --------- Signed-off-by: Vadim Grinco <[email protected]> Signed-off-by: Xiaodong Ye <[email protected]> Co-authored-by: pufferffish <[email protected]> Co-authored-by: KOISHI KOMEIJI FROM TOUHOU 11 <fuck> Co-authored-by: DSLstandard <[email protected]> Co-authored-by: pufferffish <[email protected]> Co-authored-by: yeongbba <[email protected]> Co-authored-by: tomaThomas <[email protected]> Co-authored-by: Antoine Viallon <[email protected]> Co-authored-by: Vadim Grinco <[email protected]> Co-authored-by: zeo <[email protected]> Co-authored-by: Louis Beaumont <[email protected]> Co-authored-by: Daniel Hiltgen <[email protected]> Co-authored-by: Michael Yang <[email protected]> Co-authored-by: Parth Sareen <[email protected]> Co-authored-by: Jeffrey Morgan <[email protected]> Co-authored-by: Bruce MacDonald <[email protected]> Co-authored-by: Jesse Gross <[email protected]> Co-authored-by: Nikita <[email protected]> Co-authored-by: Masato Nakasaka <[email protected]> Co-authored-by: Xiaodong Ye <[email protected]> Co-authored-by: Daniel Hiltgen <[email protected]>
1 parent fd8aa94 commit 2aba569

File tree

152 files changed

+29425
-15
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

152 files changed

+29425
-15
lines changed

.github/workflows/test.yaml

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,32 @@ jobs:
5252
container: rocm/dev-ubuntu-22.04:6.1.2
5353
extra-packages: rocm-libs
5454
flags: '-DAMDGPU_TARGETS=gfx1010 -DCMAKE_PREFIX_PATH=/opt/rocm'
55+
- preset: Vulkan
56+
container: ubuntu:22.04
57+
extra-packages: >
58+
mesa-vulkan-drivers vulkan-tools
59+
libvulkan1 libvulkan-dev
60+
vulkan-sdk cmake ccache g++ make
5561
runs-on: linux
5662
container: ${{ matrix.container }}
5763
steps:
5864
- uses: actions/checkout@v4
5965
- run: |
6066
[ -n "${{ matrix.container }}" ] || sudo=sudo
6167
$sudo apt-get update
68+
# Add LunarG Vulkan SDK apt repo for Ubuntu 22.04
69+
if [ "${{ matrix.preset }}" = "Vulkan" ]; then
70+
$sudo apt-get install -y --no-install-recommends wget gnupg ca-certificates software-properties-common
71+
wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | $sudo gpg --dearmor -o /usr/share/keyrings/lunarg-archive-keyring.gpg
72+
# Use signed-by to bind the repo to the installed keyring to avoid NO_PUBKEY
73+
echo "deb [signed-by=/usr/share/keyrings/lunarg-archive-keyring.gpg] https://packages.lunarg.com/vulkan/1.4.313 jammy main" | $sudo tee /etc/apt/sources.list.d/lunarg-vulkan-1.4.313-jammy.list > /dev/null
74+
$sudo apt-get update
75+
fi
6276
$sudo apt-get install -y cmake ccache ${{ matrix.extra-packages }}
77+
# Export VULKAN_SDK if provided by LunarG package (defensive)
78+
if [ -d "/usr/lib/x86_64-linux-gnu/vulkan" ] && [ "${{ matrix.preset }}" = "Vulkan" ]; then
79+
echo "VULKAN_SDK=/usr" >> $GITHUB_ENV
80+
fi
6381
env:
6482
DEBIAN_FRONTEND: noninteractive
6583
- uses: actions/cache@v4
@@ -92,18 +110,21 @@ jobs:
92110
- preset: ROCm
93111
install: https://download.amd.com/developer/eula/rocm-hub/AMD-Software-PRO-Edition-24.Q4-WinSvr2022-For-HIP.exe
94112
flags: '-DAMDGPU_TARGETS=gfx1010 -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_FLAGS="-parallel-jobs=4 -Wno-ignored-attributes -Wno-deprecated-pragma" -DCMAKE_CXX_FLAGS="-parallel-jobs=4 -Wno-ignored-attributes -Wno-deprecated-pragma"'
113+
- preset: Vulkan
114+
install: https://sdk.lunarg.com/sdk/download/1.4.321.1/windows/vulkansdk-windows-X64-1.4.321.1.exe
95115
runs-on: windows
96116
steps:
97117
- run: |
98118
choco install -y --no-progress ccache ninja
99119
ccache -o cache_dir=${{ github.workspace }}\.ccache
100-
- if: matrix.preset == 'CUDA' || matrix.preset == 'ROCm'
120+
- if: matrix.preset == 'CUDA' || matrix.preset == 'ROCm' || matrix.preset == 'Vulkan'
101121
id: cache-install
102122
uses: actions/cache/restore@v4
103123
with:
104124
path: |
105125
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA
106126
C:\Program Files\AMD\ROCm
127+
C:\VulkanSDK
107128
key: ${{ matrix.install }}
108129
- if: matrix.preset == 'CUDA'
109130
name: Install CUDA ${{ matrix.cuda-version }}
@@ -133,6 +154,18 @@ jobs:
133154
echo "HIPCXX=$hipPath\bin\clang++.exe" | Out-File -FilePath $env:GITHUB_ENV -Append
134155
echo "HIP_PLATFORM=amd" | Out-File -FilePath $env:GITHUB_ENV -Append
135156
echo "CMAKE_PREFIX_PATH=$hipPath" | Out-File -FilePath $env:GITHUB_ENV -Append
157+
- if: matrix.preset == 'Vulkan'
158+
name: Install Vulkan ${{ matrix.rocm-version }}
159+
run: |
160+
$ErrorActionPreference = "Stop"
161+
if ("${{ steps.cache-install.outputs.cache-hit }}" -ne 'true') {
162+
Invoke-WebRequest -Uri "${{ matrix.install }}" -OutFile "install.exe"
163+
Start-Process -FilePath .\install.exe -ArgumentList "-c","--am","--al","in" -NoNewWindow -Wait
164+
}
165+
166+
$vulkanPath = (Resolve-Path "C:\VulkanSDK\*").path
167+
echo "$vulkanPath\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
168+
echo "VULKAN_SDK=$vulkanPath" >> $env:GITHUB_ENV
136169
- if: ${{ !cancelled() && steps.cache-install.outputs.cache-hit != 'true' }}
137170
uses: actions/cache/save@v4
138171
with:

CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,15 @@ if(CMAKE_HIP_COMPILER)
139139
endforeach()
140140
endif()
141141
endif()
142+
143+
find_package(Vulkan)
144+
if(Vulkan_FOUND)
145+
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ml/backend/ggml/ggml/src/ggml-vulkan)
146+
install(TARGETS ggml-vulkan
147+
RUNTIME_DEPENDENCIES
148+
PRE_INCLUDE_REGEXES vulkan
149+
PRE_EXCLUDE_REGEXES ".*"
150+
RUNTIME DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT Vulkan
151+
LIBRARY DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT Vulkan
152+
)
153+
endif()

CMakePresets.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@
7070
"CMAKE_HIP_FLAGS": "-parallel-jobs=4",
7171
"AMDGPU_TARGETS": "gfx940;gfx941;gfx942;gfx1010;gfx1012;gfx1030;gfx1100;gfx1101;gfx1102;gfx1151;gfx1200;gfx1201;gfx908:xnack-;gfx90a:xnack+;gfx90a:xnack-"
7272
}
73+
},
74+
{
75+
"name": "Vulkan",
76+
"inherits": [ "Default" ]
7377
}
7478
],
7579
"buildPresets": [
@@ -122,6 +126,11 @@
122126
"name": "ROCm 6",
123127
"inherits": [ "ROCm" ],
124128
"configurePreset": "ROCm 6"
129+
},
130+
{
131+
"name": "Vulkan",
132+
"targets": [ "ggml-vulkan" ],
133+
"configurePreset": "Vulkan"
125134
}
126135
]
127136
}

Dockerfile

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ ARG ROCMVERSION=6.3.3
77
ARG JETPACK5VERSION=r35.4.1
88
ARG JETPACK6VERSION=r36.4.0
99
ARG CMAKEVERSION=3.31.2
10+
ARG VULKANVERSION=1.4.321.1
1011

1112
# We require gcc v10 minimum. v10.3 has regressions, so the rockylinux 8.5 AppStream has the latest compatible version
1213
FROM --platform=linux/amd64 rocm/dev-almalinux-8:${ROCMVERSION}-complete AS base-amd64
@@ -17,6 +18,16 @@ RUN yum install -y yum-utils \
1718
&& dnf install -y ccache \
1819
&& yum-config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/cuda-rhel8.repo
1920
ENV PATH=/opt/rh/gcc-toolset-10/root/usr/bin:$PATH
21+
ARG VULKANVERSION
22+
RUN wget https://sdk.lunarg.com/sdk/download/${VULKANVERSION}/linux/vulkansdk-linux-x86_64-${VULKANVERSION}.tar.xz -O /tmp/vulkansdk-linux-x86_64-${VULKANVERSION}.tar.xz \
23+
&& tar xvf /tmp/vulkansdk-linux-x86_64-${VULKANVERSION}.tar.xz \
24+
&& dnf -y install ninja-build \
25+
&& ln -s /usr/bin/python3 /usr/bin/python \
26+
&& /${VULKANVERSION}/vulkansdk -j 8 vulkan-headers \
27+
&& /${VULKANVERSION}/vulkansdk -j 8 shaderc
28+
RUN cp -r /${VULKANVERSION}/x86_64/include/* /usr/local/include/ \
29+
&& cp -r /${VULKANVERSION}/x86_64/lib/* /usr/local/lib
30+
ENV PATH=/${VULKANVERSION}/x86_64/bin:$PATH
2031

2132
FROM --platform=linux/arm64 almalinux:8 AS base-arm64
2233
# install epel-release for ccache
@@ -106,6 +117,13 @@ RUN --mount=type=cache,target=/root/.ccache \
106117
&& cmake --build --parallel ${PARALLEL} --preset 'JetPack 6' \
107118
&& cmake --install build --component CUDA --strip --parallel ${PARALLEL}
108119

120+
FROM base AS vulkan
121+
RUN --mount=type=cache,target=/root/.ccache \
122+
cmake --preset 'Vulkan' -DOLLAMA_RUNNER_DIR="vulkan" \
123+
&& cmake --build --parallel --preset 'Vulkan' \
124+
&& cmake --install build --component Vulkan --strip --parallel 8
125+
126+
109127
FROM base AS build
110128
WORKDIR /go/src/github.com/ollama/ollama
111129
COPY go.mod go.sum .
@@ -123,7 +141,8 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
123141
FROM --platform=linux/amd64 scratch AS amd64
124142
# COPY --from=cuda-11 dist/lib/ollama/ /lib/ollama/
125143
COPY --from=cuda-12 dist/lib/ollama /lib/ollama/
126-
COPY --from=cuda-13 dist/lib/ollama/ /lib/ollama/
144+
COPY --from=cuda-13 dist/lib/ollama /lib/ollama/
145+
COPY --from=vulkan dist/lib/ollama /lib/ollama/
127146

128147
FROM --platform=linux/arm64 scratch AS arm64
129148
# COPY --from=cuda-11 dist/lib/ollama/ /lib/ollama/
@@ -136,12 +155,13 @@ FROM scratch AS rocm
136155
COPY --from=rocm-6 dist/lib/ollama /lib/ollama
137156

138157
FROM ${FLAVOR} AS archive
158+
ARG VULKANVERSION
139159
COPY --from=cpu dist/lib/ollama /lib/ollama
140160
COPY --from=build /bin/ollama /bin/ollama
141161

142162
FROM ubuntu:24.04
143163
RUN apt-get update \
144-
&& apt-get install -y ca-certificates \
164+
&& apt-get install -y ca-certificates libvulkan1 \
145165
&& apt-get clean \
146166
&& rm -rf /var/lib/apt/lists/*
147167
COPY --from=archive /bin /usr/bin

discover/gpu.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ func devInfoToInfoList(devs []ml.DeviceInfo) GpuInfoList {
7070
if dev.Library == "ROCm" && rocmDir != "" {
7171
info.DependencyPath = append(info.DependencyPath, rocmDir)
7272
}
73+
// TODO any special processing of Vulkan devices?
7374
resp = append(resp, info)
7475
}
7576
if len(resp) == 0 {
@@ -97,7 +98,16 @@ func (l GpuInfoList) GetVisibleDevicesEnv() []string {
9798
if len(l) == 0 {
9899
return nil
99100
}
100-
return []string{rocmGetVisibleDevicesEnv(l)}
101+
res := []string{}
102+
envVar := rocmGetVisibleDevicesEnv(l)
103+
if envVar != "" {
104+
res = append(res, envVar)
105+
}
106+
envVar = vkGetVisibleDevicesEnv(l)
107+
if envVar != "" {
108+
res = append(res, envVar)
109+
}
110+
return res
101111
}
102112

103113
func rocmGetVisibleDevicesEnv(gpuInfo []GpuInfo) string {
@@ -127,6 +137,25 @@ func rocmGetVisibleDevicesEnv(gpuInfo []GpuInfo) string {
127137
return envVar + strings.Join(ids, ",")
128138
}
129139

140+
func vkGetVisibleDevicesEnv(gpuInfo []GpuInfo) string {
141+
ids := []string{}
142+
for _, info := range gpuInfo {
143+
if info.Library != "Vulkan" {
144+
continue
145+
}
146+
if info.filterID != "" {
147+
ids = append(ids, info.filterID)
148+
} else {
149+
ids = append(ids, info.ID)
150+
}
151+
}
152+
if len(ids) == 0 {
153+
return ""
154+
}
155+
envVar := "GGML_VK_VISIBLE_DEVICES="
156+
return envVar + strings.Join(ids, ",")
157+
}
158+
130159
// GetSystemInfo returns the last cached state of the GPUs on the system
131160
func GetSystemInfo() SystemInfo {
132161
deviceMu.Lock()

discover/runner.go

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ func GPUDevices(ctx context.Context, runners []FilteredRunnerDiscovery) []ml.Dev
8686
// are enumerated, but not actually supported.
8787
// We run this in serial to avoid potentially initializing a GPU multiple
8888
// times concurrently leading to memory contention
89+
// TODO refactor so we group the lib dirs and do serial per version, but parallel for different libs
8990
for dir := range libDirs {
9091
var dirs []string
9192
if dir != "" {
@@ -131,19 +132,25 @@ func GPUDevices(ctx context.Context, runners []FilteredRunnerDiscovery) []ml.Dev
131132
go func(i int) {
132133
defer wg.Done()
133134
var envVar string
135+
id := devices[i].ID
134136
if devices[i].Library == "ROCm" {
135137
if runtime.GOOS != "linux" {
136138
envVar = "HIP_VISIBLE_DEVICES"
137139
} else {
138140
envVar = "ROCR_VISIBLE_DEVICES"
139141
}
140-
} else {
142+
} else if devices[i].Library == "CUDA" {
141143
envVar = "CUDA_VISIBLE_DEVICES"
144+
} else if devices[i].Library == "Vulkan" {
145+
id = devices[i].FilteredID
146+
envVar = "GGML_VK_VISIBLE_DEVICES"
147+
} else {
148+
slog.Error("Unknown Library:" + devices[i].Library)
142149
}
143150

144151
extraEnvs := []string{
145-
"GGML_CUDA_INIT=1", // force deep initialization to trigger crash on unsupported GPUs
146-
envVar + "=" + devices[i].ID, // Filter to just this one GPU
152+
"GGML_CUDA_INIT=1", // force deep initialization to trigger crash on unsupported GPUs
153+
envVar + "=" + id, // Filter to just this one GPU
147154
}
148155
if len(bootstrapDevices(ctx2ndPass, devices[i].LibraryPath, extraEnvs)) == 0 {
149156
needsDelete[i] = true
@@ -163,6 +170,8 @@ func GPUDevices(ctx context.Context, runners []FilteredRunnerDiscovery) []ml.Dev
163170
wg.Wait()
164171
logutil.Trace("supported GPU library combinations", "supported", supported)
165172

173+
filterOutVulkanThatAreSupportedByOtherGPU(needsDelete)
174+
166175
// Mark for deletion any overlaps - favoring the library version that can cover all GPUs if possible
167176
filterOverlapByLibrary(supported, needsDelete)
168177

@@ -184,7 +193,7 @@ func GPUDevices(ctx context.Context, runners []FilteredRunnerDiscovery) []ml.Dev
184193
}
185194
}
186195

187-
// Now filter out any overlap with different libraries (favor CUDA/ROCm over others)
196+
// Now filter out any overlap with different libraries (favor CUDA/HIP over others)
188197
for i := 0; i < len(devices); i++ {
189198
for j := i + 1; j < len(devices); j++ {
190199
// For this pass, we only drop exact duplicates
@@ -346,6 +355,37 @@ func GPUDevices(ctx context.Context, runners []FilteredRunnerDiscovery) []ml.Dev
346355
return devices
347356
}
348357

358+
func filterOutVulkanThatAreSupportedByOtherGPU(needsDelete []bool) {
359+
// Filter out Vulkan devices that share a PCI ID with a non-Vulkan device that is not marked for deletion
360+
for i := range devices {
361+
if devices[i].Library != "Vulkan" || needsDelete[i] {
362+
continue
363+
}
364+
if devices[i].PCIID == "" {
365+
continue
366+
}
367+
for j := range devices {
368+
if i == j {
369+
continue
370+
}
371+
if devices[j].PCIID == "" {
372+
continue
373+
}
374+
if devices[j].PCIID == devices[i].PCIID && devices[j].Library != "Vulkan" && !needsDelete[j] {
375+
needsDelete[i] = true
376+
slog.Debug("dropping Vulkan duplicate by PCI ID",
377+
"vulkan_id", devices[i].ID,
378+
"vulkan_libdir", devices[i].LibraryPath[len(devices[i].LibraryPath)-1],
379+
"pci_id", devices[i].PCIID,
380+
"kept_library", devices[j].Library,
381+
"kept_id", devices[j].ID,
382+
)
383+
break
384+
}
385+
}
386+
}
387+
}
388+
349389
func filterOverlapByLibrary(supported map[string]map[string]map[string]int, needsDelete []bool) {
350390
// For multi-GPU systems, use the newest version that supports all the GPUs
351391
for _, byLibDirs := range supported {
@@ -451,6 +491,7 @@ func bootstrapDevices(ctx context.Context, ollamaLibDirs []string, extraEnvs []s
451491
cmd.Stdout = os.Stdout
452492
cmd.Stderr = os.Stderr
453493
}
494+
454495
// cmd.SysProcAttr = llm.LlamaServerSysProcAttr // circular dependency - bring back once refactored
455496
pathEnvVal := strings.Join(libraryPaths, string(filepath.ListSeparator))
456497
pathNeeded := true
@@ -508,6 +549,14 @@ func bootstrapDevices(ctx context.Context, ollamaLibDirs []string, extraEnvs []s
508549
}
509550
}
510551
logutil.Trace("runner enumerated devices", "OLLAMA_LIBRARY_PATH", ollamaLibDirs, "devices", devices)
552+
553+
// Enumerate returned devices starting at 0 per library and assign the per-library index as FilteredID
554+
libCounts := make(map[string]int)
555+
for i := range devices {
556+
lib := devices[i].Library
557+
devices[i].FilteredID = strconv.Itoa(libCounts[lib])
558+
libCounts[lib]++
559+
}
511560
return devices
512561
}
513562

discover/types.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type GpuInfo struct { // TODO better name maybe "InferenceProcessor"?
3737
UnreliableFreeMemory bool
3838

3939
// GPU information
40-
filterID string // AMD Workaround: The numeric ID of the device used to filter out other devices
40+
filterID string // AMD/Vulkan Workaround: The numeric ID of the device used to filter out other devices
4141
Name string `json:"name"` // user friendly name if available
4242
ComputeMajor int `json:"compute_major"` // Compute Capability or gfx
4343
ComputeMinor int `json:"compute_minor"`
@@ -175,7 +175,8 @@ func (l GpuInfoList) FlashAttentionSupported() bool {
175175
supportsFA := gpu.Library == "cpu" ||
176176
gpu.Name == "Metal" || gpu.Library == "Metal" ||
177177
(gpu.Library == "CUDA" && gpu.DriverMajor >= 7 && !(gpu.ComputeMajor == 7 && gpu.ComputeMinor == 2)) || // We don't have kernels for Jetson Xavier
178-
gpu.Library == "ROCm"
178+
gpu.Library == "ROCm" ||
179+
gpu.Library == "Vulkan"
179180

180181
if !supportsFA {
181182
return false

envconfig/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ var (
217217
CudaVisibleDevices = String("CUDA_VISIBLE_DEVICES")
218218
HipVisibleDevices = String("HIP_VISIBLE_DEVICES")
219219
RocrVisibleDevices = String("ROCR_VISIBLE_DEVICES")
220+
VkVisibleDevices = String("GGML_VK_VISIBLE_DEVICES")
220221
GpuDeviceOrdinal = String("GPU_DEVICE_ORDINAL")
221222
HsaOverrideGfxVersion = String("HSA_OVERRIDE_GFX_VERSION")
222223
)
@@ -307,6 +308,7 @@ func AsMap() map[string]EnvVar {
307308
ret["CUDA_VISIBLE_DEVICES"] = EnvVar{"CUDA_VISIBLE_DEVICES", CudaVisibleDevices(), "Set which NVIDIA devices are visible"}
308309
ret["HIP_VISIBLE_DEVICES"] = EnvVar{"HIP_VISIBLE_DEVICES", HipVisibleDevices(), "Set which AMD devices are visible by numeric ID"}
309310
ret["ROCR_VISIBLE_DEVICES"] = EnvVar{"ROCR_VISIBLE_DEVICES", RocrVisibleDevices(), "Set which AMD devices are visible by UUID or numeric ID"}
311+
ret["GGML_VK_VISIBLE_DEVICES"] = EnvVar{"GGML_VK_VISIBLE_DEVICES", VkVisibleDevices(), "Set which Vulkan devices are visible by numeric ID"}
310312
ret["GPU_DEVICE_ORDINAL"] = EnvVar{"GPU_DEVICE_ORDINAL", GpuDeviceOrdinal(), "Set which AMD devices are visible by numeric ID"}
311313
ret["HSA_OVERRIDE_GFX_VERSION"] = EnvVar{"HSA_OVERRIDE_GFX_VERSION", HsaOverrideGfxVersion(), "Override the gfx used for all detected AMD GPUs"}
312314
ret["OLLAMA_INTEL_GPU"] = EnvVar{"OLLAMA_INTEL_GPU", IntelGPU(), "Enable experimental Intel GPU detection"}

llama/llama.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ func EnumerateGPUs() []ml.DeviceID {
6969
for i := range C.ggml_backend_dev_count() {
7070
device := C.ggml_backend_dev_get(i)
7171

72-
if C.ggml_backend_dev_type(device) == C.GGML_BACKEND_DEVICE_TYPE_GPU {
72+
switch C.ggml_backend_dev_type(device) {
73+
case C.GGML_BACKEND_DEVICE_TYPE_GPU,
74+
C.GGML_BACKEND_DEVICE_TYPE_IGPU:
7375
var props C.struct_ggml_backend_dev_props
7476
C.ggml_backend_dev_get_props(device, &props)
7577
ids = append(ids, ml.DeviceID{

0 commit comments

Comments
 (0)