Skip to content

Commit f455558

Browse files
committed
Revert RAG auto Vulkan guard, guard multi-backend Vulkan detection, and preserve forced Vulkan across updates
1 parent 5432a0c commit f455558

7 files changed

Lines changed: 88 additions & 61 deletions

File tree

studio/backend/core/inference/llama_cpp.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2316,17 +2316,27 @@ def _get_gguf_size_bytes(model_path: str) -> int:
23162316

23172317
@staticmethod
23182318
def _is_vulkan_backend(binary: Optional[str] = None) -> bool:
2319-
"""True if the installed llama.cpp build is the Vulkan one.
2320-
2321-
Builds are single-backend, so the presence of the Vulkan ggml
2322-
backend library next to llama-server is sufficient. Used to keep
2323-
the free-memory probe and the GPU pin in the same device-index
2324-
space (ggml's Vulkan ordinals, not nvidia-smi order).
2319+
"""True if the installed llama.cpp build is Vulkan-only.
2320+
2321+
The official prebuilts are single-backend, so the Vulkan ggml backend
2322+
library next to llama-server identifies a Vulkan build. Used to keep the
2323+
free-memory probe and the GPU pin in ggml's Vulkan device-index space.
2324+
Guard the assumption for a custom multi-backend build: if a CUDA or HIP
2325+
ggml library sits alongside Vulkan, defer to that (the nvidia-smi/torch
2326+
probes and the CUDA/HIP pin), since those backends are torch-usable and
2327+
the memory probe/pin are better understood there than on Vulkan.
23252328
"""
23262329
binary = binary or LlamaCppBackend._find_llama_server_binary()
23272330
if not binary:
23282331
return False
2329-
return (_llama_lib_dir(binary) / _vulkan_lib_filename()).is_file()
2332+
lib_dir = _llama_lib_dir(binary)
2333+
if not (lib_dir / _vulkan_lib_filename()).is_file():
2334+
return False
2335+
for _backend in ("cuda", "hip"):
2336+
sibling = f"ggml-{_backend}.dll" if sys.platform == "win32" else f"libggml-{_backend}.so"
2337+
if (lib_dir / sibling).is_file():
2338+
return False
2339+
return True
23302340

23312341
@staticmethod
23322342
def _resolve_visible_physical_ids() -> Optional[list[int]]:

studio/backend/core/rag/embeddings.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -278,15 +278,9 @@ def _resolve_auto() -> str:
278278
-- or ST if its binary is missing. GPU check is torch-free (nvidia-smi)."""
279279
from core.inference.llama_cpp import LlamaCppBackend
280280

281-
binary = LlamaCppBackend._find_llama_server_binary()
282-
# A Vulkan build's GPU is not torch-usable (torch has no Vulkan backend), so
283-
# its free-memory report must not steer auto to sentence-transformers, which
284-
# would then run on CPU/XPU; the llama-server Vulkan build is the fast path.
285-
if not LlamaCppBackend._is_vulkan_backend(binary) and LlamaCppBackend._get_gpu_free_memory(
286-
binary
287-
):
281+
if LlamaCppBackend._get_gpu_free_memory():
288282
return "sentence-transformers"
289-
if binary:
283+
if LlamaCppBackend._find_llama_server_binary():
290284
return "llama-server"
291285
return "sentence-transformers"
292286

studio/backend/tests/test_llama_cpp_update.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,48 @@ def _on_start(cmd):
448448
assert popen_kwargs["env"]["UNSLOTH_PROGRESS_PERCENT_STEP"] == "5"
449449

450450

451+
def test_start_update_preserves_vulkan_via_env(monkeypatch, tmp_path):
452+
# A Vulkan install (marker asset carries 'vulkan') must re-assert
453+
# UNSLOTH_FORCE_VULKAN on update, or detect_host on a GPU box re-routes to
454+
# CUDA/ROCm and silently replaces the Vulkan build.
455+
install_dir = tmp_path / "llama.cpp"
456+
binary = _write_install(
457+
install_dir,
458+
"b9493",
459+
repo = "ggml-org/llama.cpp",
460+
asset = "llama-b9493-bin-ubuntu-vulkan-x64.tar.gz",
461+
)
462+
monkeypatch.setattr(upd, "_find_binary", lambda: binary)
463+
monkeypatch.setattr(upd, "_installer_script", lambda: tmp_path / "install_llama_prebuilt.py")
464+
monkeypatch.setattr(freshness, "_fetch_latest_release_tag", lambda repo, timeout = 5.0: "b9518")
465+
466+
def _on_start(cmd):
467+
_write_install(
468+
install_dir,
469+
"b9518",
470+
repo = "ggml-org/llama.cpp",
471+
asset = "llama-b9518-bin-ubuntu-vulkan-x64.tar.gz",
472+
)
473+
474+
popen_kwargs: dict = {}
475+
_patch_installer_popen(
476+
monkeypatch,
477+
lines = ["installed\n"],
478+
on_start = _on_start,
479+
captured_kwargs = popen_kwargs,
480+
)
481+
482+
assert upd.start_update()["started"] is True
483+
deadline = time.time() + 10
484+
while time.time() < deadline:
485+
job = upd.get_update_status()["job"]
486+
if job["state"] in ("success", "error"):
487+
break
488+
time.sleep(0.05)
489+
assert job["state"] == "success", job
490+
assert popen_kwargs["env"]["UNSLOTH_FORCE_VULKAN"] == "1"
491+
492+
451493
def test_start_update_reports_full_release_tag(monkeypatch, tmp_path):
452494
install_dir = tmp_path / "llama.cpp"
453495
binary = _write_install(install_dir, "b9595")

studio/backend/tests/test_llama_cpp_vulkan_probe.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ def _build_loggers_stub():
5353
_maybe_stub("structlog", lambda: _types.ModuleType("structlog"))
5454

5555
from core.inference import llama_cpp as _llama_mod # noqa: E402
56-
from core.inference.llama_cpp import LlamaCppBackend, _vulkan_lib_filename # noqa: E402
56+
from core.inference.llama_cpp import ( # noqa: E402
57+
LlamaCppBackend,
58+
_llama_lib_dir,
59+
_vulkan_lib_filename,
60+
)
5761

5862
MIB = 1024 * 1024
5963
GIB = 1024 * MIB
@@ -152,5 +156,20 @@ def test_vulkan_pin_args_uses_device_names_not_env_mask():
152156
assert LlamaCppBackend._vulkan_pin_args([]) == []
153157

154158

159+
def test_vulkan_only_build_is_detected(tmp_path):
160+
binary = _make_vulkan_install(tmp_path)
161+
assert LlamaCppBackend._is_vulkan_backend(binary) is True
162+
163+
164+
def test_multi_backend_build_is_not_vulkan_only(tmp_path):
165+
# A custom build that ships CUDA (or HIP) alongside Vulkan must NOT be
166+
# treated as Vulkan-only, or its CUDA GPU would be probed/pinned as a Vulkan
167+
# device; defer to the CUDA/HIP path instead.
168+
binary = _make_vulkan_install(tmp_path)
169+
cuda = "ggml-cuda.dll" if sys.platform == "win32" else "libggml-cuda.so"
170+
(_llama_lib_dir(binary) / cuda).write_bytes(b"stub")
171+
assert LlamaCppBackend._is_vulkan_backend(binary) is False
172+
173+
155174
if __name__ == "__main__":
156175
raise SystemExit(pytest.main([__file__, "-v"]))

studio/backend/tests/test_rag_embed_llama_server.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,8 @@ def _mock_auto(monkeypatch, *, gpus, binary):
5252
from core.inference.llama_cpp import LlamaCppBackend
5353

5454
monkeypatch.setattr(config, "EMBED_BACKEND", "auto")
55-
# _resolve_auto passes the resolved binary to _get_gpu_free_memory and probes
56-
# _is_vulkan_backend (a Vulkan GPU is not torch-usable); accept the arg and
57-
# keep these non-Vulkan so the CUDA/no-CUDA selection is what's exercised.
58-
monkeypatch.setattr(LlamaCppBackend, "_get_gpu_free_memory", staticmethod(lambda *a: gpus))
55+
monkeypatch.setattr(LlamaCppBackend, "_get_gpu_free_memory", staticmethod(lambda: gpus))
5956
monkeypatch.setattr(LlamaCppBackend, "_find_llama_server_binary", staticmethod(lambda: binary))
60-
monkeypatch.setattr(LlamaCppBackend, "_is_vulkan_backend", staticmethod(lambda *a: False))
6157

6258

6359
def _stub_st_load(monkeypatch):

studio/backend/tests/test_rag_embeddings.py

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -220,43 +220,3 @@ def test_st_encode_failure_without_llama_binary_reraises(monkeypatch):
220220
embeddings._reset_backend()
221221
with pytest.raises(RuntimeError, match = "CUDA error during encode"):
222222
embeddings.encode(["alpha", "beta"])
223-
224-
225-
def _patch_auto_backend(monkeypatch, *, binary, is_vulkan, gpu_free):
226-
"""Stub the hardware probes _resolve_auto reads."""
227-
from core.inference.llama_cpp import LlamaCppBackend
228-
229-
monkeypatch.setattr(LlamaCppBackend, "_find_llama_server_binary", staticmethod(lambda: binary))
230-
monkeypatch.setattr(
231-
LlamaCppBackend, "_is_vulkan_backend", staticmethod(lambda b = None: is_vulkan)
232-
)
233-
monkeypatch.setattr(
234-
LlamaCppBackend, "_get_gpu_free_memory", staticmethod(lambda b = None: gpu_free)
235-
)
236-
237-
238-
def test_resolve_auto_cuda_gpu_picks_sentence_transformers(monkeypatch):
239-
# A torch-usable (CUDA/ROCm) GPU -> ST wins bulk indexing.
240-
_patch_auto_backend(
241-
monkeypatch, binary = "/fake/llama-server", is_vulkan = False, gpu_free = [(0, 24000)]
242-
)
243-
assert embeddings._resolve_auto() == "sentence-transformers"
244-
245-
246-
def test_resolve_auto_vulkan_gpu_picks_llama_server(monkeypatch):
247-
# A Vulkan build's GPU is not torch-usable, so its free-memory report must
248-
# NOT steer auto to ST (which would run on CPU/XPU); llama-server can use it.
249-
_patch_auto_backend(
250-
monkeypatch, binary = "/fake/llama-server", is_vulkan = True, gpu_free = [(0, 8000)]
251-
)
252-
assert embeddings._resolve_auto() == "llama-server"
253-
254-
255-
def test_resolve_auto_cpu_host_with_binary_picks_llama_server(monkeypatch):
256-
_patch_auto_backend(monkeypatch, binary = "/fake/llama-server", is_vulkan = False, gpu_free = [])
257-
assert embeddings._resolve_auto() == "llama-server"
258-
259-
260-
def test_resolve_auto_cpu_host_without_binary_picks_sentence_transformers(monkeypatch):
261-
_patch_auto_backend(monkeypatch, binary = None, is_vulkan = False, gpu_free = [])
262-
assert embeddings._resolve_auto() == "sentence-transformers"

studio/backend/utils/llama_cpp_update.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,12 @@ def _run_update(install_dir: Path, repo: str, asset: Optional[str], script: Path
514514
logger.info("llama update: installing", cmd = " ".join(cmd))
515515
# Stream progress lines into job["progress"].
516516
env = dict(os.environ, UNSLOTH_PROGRESS_PERCENT_STEP = "5")
517+
# Preserve a Vulkan install across updates. The marker asset records the
518+
# backend, but detect_host on a CUDA/ROCm box would re-route to that
519+
# backend and silently replace the Vulkan build; re-assert the Vulkan
520+
# choice via the same env flag setup uses (mirrors _rocm_install_args).
521+
if asset and "vulkan" in asset.lower():
522+
env["UNSLOTH_FORCE_VULKAN"] = "1"
517523
proc = subprocess.Popen(
518524
cmd,
519525
stdout = subprocess.PIPE,

0 commit comments

Comments
 (0)