marcodsn Claude Opus 4.8 commited on
Commit
76e2a61
·
1 Parent(s): 83b2601

Fix ZeroGPU: preload CUDA runtime libs for the llama.cpp wheel

Browse files

The cu124 llama-cpp-python wheel is dynamically linked against
libcudart/libcublas, which are not on the loader path in the HF Spaces
image (OSError: libcudart.so.12). Ship them as nvidia-* pip wheels and
dlopen them with RTLD_GLOBAL (cudart first) before importing llama_cpp
so libllama.so resolves its symbols.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files changed (2) hide show
  1. requirements.txt +3 -0
  2. src/id/llm/local.py +38 -0
requirements.txt CHANGED
@@ -1,6 +1,9 @@
1
  # llama.cpp with CUDA wheels for Hugging Face ZeroGPU (CUDA 12.4).
2
  --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cu124
3
  llama-cpp-python
 
 
 
4
  spaces
5
  huggingface_hub>=0.24
6
 
 
1
  # llama.cpp with CUDA wheels for Hugging Face ZeroGPU (CUDA 12.4).
2
  --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cu124
3
  llama-cpp-python
4
+ # CUDA runtime libs the wheel is linked against (preloaded in id/llm/local.py).
5
+ nvidia-cuda-runtime-cu12>=12.4,<12.5
6
+ nvidia-cublas-cu12>=12.4,<12.5
7
  spaces
8
  huggingface_hub>=0.24
9
 
src/id/llm/local.py CHANGED
@@ -38,12 +38,50 @@ except Exception: # pragma: no cover - exercised only off ZeroGPU
38
  return fn
39
 
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  def _load_model() -> Any:
42
  """Build (once) the llama.cpp model from the cached GGUF."""
43
  global _LLM
44
  if _LLM is None:
45
  with _LOCK:
46
  if _LLM is None:
 
47
  from llama_cpp import Llama
48
 
49
  _LLM = Llama.from_pretrained(
 
38
  return fn
39
 
40
 
41
+ def _preload_cuda() -> None:
42
+ """Make the CUDA runtime resolvable for llama.cpp's CUDA-linked .so.
43
+
44
+ The prebuilt ``cu124`` ``llama-cpp-python`` wheel is dynamically linked
45
+ against ``libcudart``/``libcublas``, which are not on the loader path in the
46
+ HF Spaces image. We ship them as ``nvidia-*`` pip wheels and ``dlopen`` them
47
+ with ``RTLD_GLOBAL`` (cudart first) so ``libllama.so`` finds the symbols.
48
+ """
49
+ if N_GPU_LAYERS == 0:
50
+ return
51
+ import ctypes
52
+ import glob
53
+ import site
54
+
55
+ roots: set[str] = set()
56
+ getsp = getattr(site, "getsitepackages", None)
57
+ if getsp:
58
+ roots.update(getsp())
59
+ import sys
60
+
61
+ roots.update(p for p in sys.path if p.endswith("site-packages"))
62
+ # Load order matters: cudart -> cublasLt -> cublas.
63
+ for pattern in (
64
+ "nvidia/cuda_runtime/lib/libcudart.so*",
65
+ "nvidia/cublas/lib/libcublasLt.so*",
66
+ "nvidia/cublas/lib/libcublas.so*",
67
+ ):
68
+ for root in roots:
69
+ hits = glob.glob(os.path.join(root, pattern))
70
+ if hits:
71
+ try:
72
+ ctypes.CDLL(hits[0], mode=ctypes.RTLD_GLOBAL)
73
+ except OSError:
74
+ pass
75
+ break
76
+
77
+
78
  def _load_model() -> Any:
79
  """Build (once) the llama.cpp model from the cached GGUF."""
80
  global _LLM
81
  if _LLM is None:
82
  with _LOCK:
83
  if _LLM is None:
84
+ _preload_cuda()
85
  from llama_cpp import Llama
86
 
87
  _LLM = Llama.from_pretrained(