Module Sarek_cuda.Cuda_api

Constants

val max_device_name_length : int

Maximum device name length in characters

val max_ptx_header_preview : int

Maximum PTX header preview length for error messages

Exceptions

exception Cuda_error of Cuda_types.cu_result * string

Deprecated: no longer raised. check below now raises the canonical Cuda_error.Cuda_error (a Backend_error alias) via the shared Sarek_backend_error.Backend_error.Make.check funnel, so every handler in the codebase can catch one exception shape across backends. This declaration is kept only so that out-of-tree code matching on Cuda_api.Cuda_error (code, ctx) still compiles (this library is opam-published).

  • deprecated no longer raised; Cuda_api.check now raises Cuda_error.Cuda_error (Backend_error) - catch that instead
val check : string -> Cuda_types.cu_result -> unit

Check CUDA result and raise a canonical Backend_error on failure.

val pending_kernargs : (int * nativeint * Stdlib.Obj.t) list Stdlib.ref

Host-side kernel-argument buffers (the CArray of argument pointers plus the per-argument value cells) for launches that may still be in flight, keyed by device id.

cuLaunchKernel is asynchronous. The NVIDIA driver snapshots the kernel parameters synchronously before returning, so a caller may free them right after the call — but the ZLUDA/HIP stack reads them later, at dispatch time. Freeing them when Kernel.launch returns is therefore a use-after-free once the OCaml GC reclaims the cells: the GPU then reads recycled host memory as the kernel's arguments (observed as an intermittent GPU page fault at a host-range address on ZLUDA).

We retain the buffers here until the stream that ran the launch is drained. Each entry is keyed by (device_id, stream_key) where stream_key is the raw address of the stream handle (0 for the default/null stream, which is what SPOC uses). Values are kept as Obj.t purely for liveness and are never inspected. A mutex guards the list so launches/retires from different OCaml domains cannot lose an entry (drop = use-after-free) or a removal.

val pending_lock : Stdlib.Mutex.t
val retain_kernargs : int -> nativeint -> Stdlib.Obj.t -> unit
val retire_stream : int -> nativeint -> unit

Release buffers for one stream — use after draining exactly that stream (its synchronize, or a blocking op known to run on it).

val retire_device : int -> unit

Release all buffers for a device — use only after a full-context synchronize (drains every stream) or context destruction.

val stream_key_of_ptr : 'a Ctypes.ptr -> nativeint

Raw address of a stream handle; the default (null) stream is 0.

val default_stream_key : nativeint

Key of the default/null stream (what SPOC's blocking memcpys run on).

Device Management

module Device : sig ... end

Memory Management

module Memory : sig ... end

Stream Management

module Stream : sig ... end

Event Management

module Event : sig ... end

Kernel Management

module Kernel : sig ... end

Utility Functions

val driver_version : unit -> int * int
val is_driver_available : unit -> bool

Driver-only availability: libcuda is loadable and reports at least one device. Sufficient for the PTX backend, which never calls NVRTC — this is what makes SPOC work on non-NVIDIA CUDA implementations such as ZLUDA, which ship the driver API without libnvrtc.

val is_available : unit -> bool
val memory_info : Device.t -> int64 * int64