# silvic-gpu
The Metal and CUDA backends of silvic. The kernels are written once (`kernels/kernels.kern`, `kernels/common.h`)
against a small macro vocabulary that `kernels/prelude_metal.h` and `kernels/prelude_cuda.h` define for Metal Shading
Language and CUDA C++, and are compiled at run time: Metal `newLibraryWithSource` with fast math off, NVRTC with
`--fmad=false`. `GpuBackend` implements `silvic_core::Backend` once over the few `GpuDevice` primitives (allocate,
upload, download, compile, launch, sync), so the two backends differ only in their device layer.
| `metal` (macOS) | `metal::MetalDevice`: objc2-metal, shared-storage buffers, one command buffer per sync | `metal::backend(index)` |
| `cuda` | `cuda::CudaDevice`: cudarc, the driver and NVRTC loaded at run time, one stream | `cuda::backend(ordinal)` |
`metal::is_available()` and `cuda::is_available()` probe without panicking, so a process on a machine without the
device (or with a mismatched CUDA driver) gets an error, not an abort.
What runs on the device: gradients (L2, binary, lambdarank with one threadgroup per query; queries over 1024 rows go
to the host's `objective::lambdarank_query`), quantization, bagging, stable partition fused with the child's
histogram (one sync per split), quantized histograms in packed 32-bit threadgroup atomics, float histograms,
fixed-point leaf sums and score updates. Split search stays on the host.
```rust
let mut backend = silvic_gpu::metal::backend(None)?;