ELIPS can offload distance and top-k computation to the GPU. The current acceleration surface is deliberately small: discover devices with elips.accelerators(), pick a backend when you open a client with device=, and run exact GPU brute-force search with elips.bf_knn(...). See the C++ GPU Engine internals and the Python SDK Base API for more context.
Backends & Maturity
ELIPS ships distance and top-k kernels for the backends below. There are no other GPU backends.
- Metal — production. Default ON for Apple Silicon; provides the distance and top-k kernels used by GPU search.
- CUDA — experimental. Requires the NVIDIA toolkit.
- HIP / ROCm — experimental. Requires ROCm.
- CPU — always available fallback.
GPU kernels cover distance computation and top-k selection only. The rest of the index pipeline runs on the CPU.
Installation & Builds
- Metal: Apple Silicon only. Gated by
-DELIPS_GPU_METAL=ON(defaults to ON for Apple platforms). Do not force this on Linux. - CUDA: requires the NVIDIA toolkit.
- HIP: requires ROCm.
Detecting GPU Support
elips.has_gpu is a boolean that is True when the current build was compiled with at least one GPU backend and a device is present.
import elips
if elips.has_gpu:
print("GPU acceleration available")
else:
print("CPU-only build or no device")Device Discovery
elips.accelerators() -> list[AcceleratorSpec]— every GPU detected across the compiled backends.elips.accelerator() -> AcceleratorSpec | None— the device ELIPS would pick by default, orNoneon a CPU-only machine.
import elips
for spec in elips.accelerators():
print(spec.backend, spec.index, spec.name, spec.memory_bytes)
best = elips.accelerator()
if best is None:
print("no GPU available")
else:
print(f"default device: {best.name} ({best.backend})")AcceleratorSpec
A discovery record describing one GPU. Fields:
name(str) — human-readable device name.backend(str) — one of"metal","cuda","hip".index(int) — the device ordinal within its backend (theNin"cuda:N").memory_bytes(int) — total device memory.free_memory_bytes(int) — currently free device memory.unified_memory(bool) — whether the device shares memory with the host (true on Apple Silicon).supports_fp16(bool) — half-precision support.raw— the backend-specific raw descriptor.
Selecting a Device
Choose a backend when you open a client with the device= keyword. Valid values are "cpu", "auto", "metal", "cuda:N", and "hip:N". There is no gpu=True keyword.
import elips
# Let ELIPS choose the best available device
client = elips.Client(dimension=128, device="auto")
# Pin a specific backend/device
client = elips.Client(dimension=128, device="metal")
client = elips.Client(dimension=128, device="cuda:0")Requesting a named backend that is absent raises BackendUnavailableError — unless you pass fallback=True, in which case ELIPS silently falls back to the CPU.
try:
client = elips.Client(dimension=128, device="cuda:0")
except elips.BackendUnavailableError:
client = elips.Client(dimension=128, device="cpu")
# Or ask for fallback up front
client = elips.Client(dimension=128, device="cuda:0", fallback=True)Advanced device policy can also be supplied as a gpu=GpuConfig(...) object, but the device= string is the recommended selector for almost all use cases.
Native Device Info
The high-level client does not expose gpu_info() directly. Reach the detailed device report through the native handle:
client = elips.Client(dimension=128, device="auto")
info = client.native.gpu_info()
print(info)GPU Brute-Force kNN
elips.bf_knn(xq, xb, k, metric="l2", device="auto") runs an exact brute-force k-nearest-neighbour search with no index build. It returns a tuple (D, I) of float32 distances and int64 labels. device="metal" is the Apple-GPU path; metric strings are FAISS-style ("l2" for euclidean). This is available in GPU-enabled builds only.
import numpy as np, elips
xb = np.random.rand(100000, 128).astype("float32") # corpus
xq = np.random.rand(1000, 128).astype("float32") # queries
# Exact GPU brute-force, no index build
D, I = elips.bf_knn(xq, xb, 10, metric="l2", device="metal")
print(D.shape, I.shape) # (1000, 10) (1000, 10)On an Apple M4 (dim=128, 100k corpus, 1k queries, k=10, L2), batched bf_knn on Metal reaches recall 1.000 at roughly 914 QPS; single-query latency is far lower (~24 QPS), so batch your queries to amortize kernel launch and transfer overhead.
C++ GPU Types
If you drop into the C++ layer, the GPU abstractions were renamed: GpuBackend (was GpuPort), BackendSelector (was GpuSelector), and QueryBatcher (was DynamicBatcher). See the GPU Engine internals.
Common Pitfalls
- No
gpu=True: select hardware withdevice="metal"|"cuda:N"|"hip:N"|"auto"|"cpu", not a boolean flag. - Absent backends raise: a named backend that is not present raises
BackendUnavailableErrorunlessfallback=Trueis set. - Batch your queries: single-query GPU calls are dominated by launch and transfer overhead; batch for throughput.
- Metal is Apple-only: the Metal backend defaults OFF on non-Apple systems — do not force it on Linux builds.
- Check for None:
elips.accelerator()returnsNoneon CPU-only machines.