Files
local-transcriber/tests/test_cuda_bootstrap.py
T
ddadminandClaude Opus 4.6 bdb9b06855 feat(cuda): добавлен прозрачный GPU runtime для Linux/WSL2
- Зачем:
  - ctranslate2 требует libcublas.so.12 для CUDA, но не бандлит её в wheel —
    без системного CUDA toolkit GPU не работает из коробки.
- Что:
  - добавлена зависимость nvidia-cublas-cu12 (Linux x86_64).
  - создан _cuda_bootstrap.py: preload libcublas через ctypes.CDLL(RTLD_GLOBAL)
    до импорта ctranslate2 (LD_LIBRARY_PATH не работает — glibc кеширует пути).
  - добавлен strict_device в transcriber: --device cuda/cpu не делает silent fallback.
  - CLI: диагностика requested vs resolved device, Windows CUDA-подсказка.
- Проверка:
  - uv run pytest -v (52 passed, 1 skipped).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 18:37:14 +03:00

108 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import ctypes
import glob
import os
import sys
import types
import pytest
from local_transcriber._cuda_bootstrap import ensure_cublas_loadable, is_cublas_available
def test_ensure_cublas_no_nvidia_package(monkeypatch):
"""Без nvidia-cublas-cu12 -- ничего не падает."""
monkeypatch.setattr(sys, "platform", "linux")
monkeypatch.setitem(sys.modules, "nvidia.cublas", None)
ensure_cublas_loadable() # не должно бросать исключений
def test_ensure_cublas_loads_library(monkeypatch, tmp_path):
"""С nvidia.cublas -- вызывает ctypes.CDLL с полным путём и RTLD_GLOBAL."""
monkeypatch.setattr(sys, "platform", "linux")
# Создаём фейковый nvidia.cublas с lib/libcublas.so.12
lib_dir = tmp_path / "lib"
lib_dir.mkdir()
fake_so = lib_dir / "libcublas.so.12"
fake_so.touch()
# Мокаем родительский пакет nvidia (иначе import nvidia.cublas упадёт)
fake_nvidia = types.ModuleType("nvidia")
fake_nvidia.__path__ = [str(tmp_path)]
fake_cublas = types.ModuleType("nvidia.cublas")
fake_cublas.__path__ = [str(tmp_path)]
fake_nvidia.cublas = fake_cublas
monkeypatch.setitem(sys.modules, "nvidia", fake_nvidia)
monkeypatch.setitem(sys.modules, "nvidia.cublas", fake_cublas)
calls = []
monkeypatch.setattr(ctypes, "CDLL", lambda path, mode=0: calls.append((path, mode)))
ensure_cublas_loadable()
assert len(calls) == 1
assert calls[0][0] == str(fake_so)
assert calls[0][1] == ctypes.RTLD_GLOBAL
def test_ensure_cublas_skips_non_linux(monkeypatch):
"""На не-Linux платформах -- no-op."""
monkeypatch.setattr(sys, "platform", "win32")
ensure_cublas_loadable() # не должно бросать исключений
def _nvidia_cublas_installed() -> bool:
"""Проверяет, что pip-пакет nvidia-cublas-cu12 установлен."""
try:
import nvidia.cublas # type: ignore[import-untyped]
cublas_paths = getattr(nvidia.cublas, "__path__", None)
if not cublas_paths:
return False
lib_dir = os.path.join(cublas_paths[0], "lib")
return any(glob.glob(os.path.join(lib_dir, "libcublas.so.12*")))
except ImportError:
return False
def _system_cublas_available() -> bool:
"""Проверяет, что libcublas.so.12 доступна через системный линкер (без bootstrap)."""
try:
ctypes.CDLL("libcublas.so.12")
return True
except OSError:
return False
@pytest.mark.skipif(
sys.platform != "linux",
reason="CUDA bootstrap только для Linux",
)
@pytest.mark.skipif(
not _nvidia_cublas_installed(),
reason="nvidia-cublas-cu12 не установлен",
)
def test_bootstrap_makes_cublas_resolvable():
"""Bootstrap из pip-пакета делает libcublas.so.12 резолвимой.
Тест проходит ТОЛЬКО если:
1. nvidia-cublas-cu12 установлен (иначе skip)
2. libcublas НЕ доступна через системный линкер до bootstrap
(иначе skip -- тест не может доказать, что сработал именно bootstrap)
3. После ensure_cublas_loadable() -- libcublas доступна
"""
if _system_cublas_available():
pytest.skip(
"libcublas.so.12 уже доступна через системный линкер -- "
"невозможно проверить, что сработал именно bootstrap"
)
ensure_cublas_loadable()
assert is_cublas_available(), (
"nvidia-cublas-cu12 установлен, но после bootstrap "
"libcublas.so.12 всё ещё не резолвится через dlopen"
)