Repository navigation
Step 31: CUDA backend — native C/CUDA library, cuBLAS GEMM, custom kernels, CudaBackend #70
Copy link
Copy link
Closed
Description
Summary
Implement the CUDA GPU backend for dotLLM — the first GPU acceleration step (Phase 4). This introduces the native C/CUDA shared library (dotllm_native), CUDA kernel implementations for all transformer operations, the CudaBackend implementing IBackend, and P/Invoke interop in DotLLM.Cuda.
Roadmap reference: Phase 4, Step 31
Dependencies: Phase 1–2 (all completed)
Scope
1. Documentation — docs/GPU.md
- Comprehensive GPU backend design document
- Prerequisites (CUDA toolkit, driver versions, supported GPUs)
- Architecture: native library ↔ P/Invoke ↔ C# backend
- Memory management model (device allocator, memory pools, pinned host memory)
- Kernel catalogue and dispatch strategy
- Build system (CMake) and packaging (
runtimes/{rid}/native/) - Integration with existing
IBackend/IKernelRunnerinterfaces - Performance expectations and measurement methodology
2. Native C/CUDA library (native/)
- Build system: CMakeLists.txt with CUDA toolkit detection, compute capability targets (sm_70+)
- Header:
native/include/dotllm_native.h— flat C API, no C++ across boundary - cuBLAS wrappers (
native/src/cublas/):- FP32/FP16 GEMM via cuBLAS
- cuBLAS handle lifecycle (create/destroy per device)
- Custom CUDA kernels (
native/src/cuda/):- Fused RMSNorm + SiLU kernel
- RoPE (rotary position embedding) kernel
- Embedding lookup kernel
- Element-wise add, multiply kernels
- Softmax kernel
- Quantized dequantization kernels (Q8_0, Q4_K_M → FP16)
- Quantized GEMV for decode (Q8_0, Q4_K)
- Flash attention kernel (tiled, fused softmax)
- KV-cache update kernel
- Device management (
native/src/cuda/):- Device query (count, compute capability, memory)
- Memory allocation/free (device + pinned host)
- Stream management (create/destroy/sync)
- Error handling with descriptive messages
3. C# interop layer (DotLLM.Cuda/)
- P/Invoke declarations:
[LibraryImport("dotllm_native")]for all native functions CudaBackend: ImplementsIBackend- Device enumeration and selection
- GPU tensor allocation (
cudaMallocvia native) - Host↔device copies (
cudaMemcpyvia native) - Stream management wrapper
- Deterministic disposal (free device memory, destroy handles)
CudaDevice: Device info (name, compute capability, total/free memory)CudaStream: RAII wrapper around CUDA stream handleCudaTensor: ITensor implementation for GPU-resident data (opaquenintdevice pointer)CudaKernelRunner: ImplementsIKernelRunner— dispatches to native kernels
4. GPU-aware model forward pass
- Adapt
TransformerModelor create GPU variant that dispatches viaIKernelRunner - Weight upload: load from mmap'd GGUF →
cudaMemcpyto device at model load time - GPU KV-cache: allocate and manage on device
- All intermediate tensors on GPU — no device↔host transfers during forward pass
- Logits transfer back to host only for sampling
5. CLI integration
--device gpu/--device cpuflag--gpu-layers Npreparation (for Step 32)- Device info display on startup
Acceptance Criteria
-
docs/GPU.mdcomprehensive design document - Native library builds via CMake on Linux (Windows optional initially)
-
dotllm_native.hdefines complete flat C API - cuBLAS GEMM works for FP32 and FP16
- Custom kernels: RMSNorm, SiLU, RoPE, softmax, add, multiply, embedding
- Flash attention kernel (at minimum, naive GPU attention)
- Q8_0 and Q4_K dequantization on GPU
-
CudaBackendimplementsIBackendwith device memory management -
CudaKernelRunnerimplementsIKernelRunner - End-to-end: load GGUF model → run forward pass on GPU → generate text
- Numerical accuracy within ε of CPU output for same prompt
- GPU decode throughput within 2× of llama.cpp for equivalent model/quantization
- Unit tests for P/Invoke layer and GPU tensor operations
- Integration test: GPU vs CPU output comparison
Key Design Decisions to Make
- FP16 vs FP32 compute: Use FP16 (half) for GPU compute? cuBLAS FP16 GEMM is ~2× faster on Tensor Cores.
- Memory pool: Custom CUDA memory pool vs
cudaMalloc/cudaFreeper tensor? - Stream strategy: Single stream per device vs multi-stream overlap?
- Quantized matmul: Dequantize-then-cuBLAS vs custom quantized GEMV kernels?
- Flash attention: Custom kernel vs cuDNN flash attention?
Reference
- llama.cpp
ggml-cuda/for proven kernel implementations docs/ARCHITECTURE.md— system architecturedocs/MULTI_GPU.md— GPU interop patterns (NCCL API, P/Invoke conventions)docs/QUANTIZATION.md— quantization block layoutsCLAUDE.md— GPU interop rules, native API conventions
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
Step 31: CUDA GPU backend — PTX kernels, Driver API interop, FP16 for…
Add --device both to bench_compare.py and bench_history.py (#70)
Fix BDN crash on machines without CUDA: lazy-load DotLLM.Cuda assembly (
Fix docs/CUDA.md and docs/GPU.md to match actual implementation (#70)
Catch missing CUDA libraries gracefully in BDN GPU path (#70)
Add CUDA 13.x to cuBLAS library resolver (#70)
Update README and ROADMAP for Step 31 CUDA backend (#70)
Fix CUDA tests failing on CI without GPU: probe native library before…
Fix build: Skip.Always → Skip.If(true, ...) (#70)
Retrigger CI (#70)
Fix CI: isolate P/Invoke in NoInlining method, relax float precision (#…
Fix CudaGemvPathComparisonTest: probe native lib before touching CUDA…
Document GPU test filter in README (#70)
Fix CudaGemvPathComparisonTest: move all CUDA code behind NoInlining (#…
Skip GPU tests in CI: add --filter Category!=GPU (#70)
Relax WeightRepacking float tolerance to precision:3 (#70)
Address PR review feedback + Qwen GPU investigation (#70)
Step 31: CUDA GPU backend — PTX kernels, Driver API, FP16 pipeline (#71)