Module Spoc_core.Runtime

type dims = Spoc_framework.Framework_sig.dims = {
  1. x : int;
  2. y : int;
  3. z : int;
}

Re-export framework dims helpers to avoid duplicate types

val dims2d : int -> int -> Spoc_framework.Framework_sig.dims
val dims3d : int -> int -> int -> Spoc_framework.Framework_sig.dims
val to_framework_dims : dims -> dims
val init_device : ?framework:string -> unit -> Device.t

Initialize the runtime and get the best available device

val all_devices : ?framework:string -> unit -> Device.t array

Get all available devices

val kernel_cache : (string, Kernel.t) Spoc_framework.Guarded_cache.t

Outer kernel memo, keyed by Spoc_framework.Compile_cache.make_key so this layer uses the same key shape as the per-backend caches underneath it — not the same key. Their device component is the backend-local device index; this layer spans backends, so its device component must be globally unique and is built from the global Device.t.id (see compile_kernel). That difference is why Device.reset, which retires the global id space without perturbing any backend-local one, has to drop this layer and only this one. Guarded against concurrent multi-domain access by Spoc_framework.Guarded_cache (this is the cross-backend entry point most multi-domain code hits).

The key MUST include device identity. Device.t.framework is the backend name, shared by every device of that backend, so keying on it alone aliases all of them — and Kernel.compile_cached closes the specific backend kernel into the Kernel.t it returns, so a hit would hand device B a kernel built for device A and silently produce wrong results.

destroy is a no-op because the backend handles are owned by the per-backend caches reached through Kernel.compile_cached — this layer holds only memoization and must never release anything. That does NOT make this layer safe to leave alone during teardown: those backend caches release the handles these Kernel.t closures capture, so the layer has to be dropped whenever they are (see the Cache_hooks registrations below).

For the same reason the cache is created ~invalidated_by_clear:true: its values BORROW the backend caches' handles, so a build still in flight when a clear runs closes over a handle the clear releases, and installing it afterwards would poison the memo for the rest of the process.

val clear_cache : unit -> unit

Clear the kernel cache

val device_is_of_backend : backend:Stdlib.String.t -> Device.t -> bool

Does global device d belong to the backend family backend? Backends register either under the family name ("HIP") or as a "<family>/<variant>" refinement of it ("CUDA/PTX", "CUDA/C"), and a single backend API module can back several of those, so both spellings must match. Mirrors Device.resolve_framework.

val compile_kernel : Device.t -> name:string -> source:string -> Kernel.t

Compile a kernel from source, with caching.

type arg =
  1. | ArgBuffer : _ Memory.buffer -> arg
  2. | ArgInt32 : int32 -> arg
  3. | ArgInt64 : int64 -> arg
  4. | ArgFloat32 : float -> arg
  5. | ArgFloat64 : float -> arg

Argument builder - collects kernel arguments

val set_args : Device.t -> arg list -> Kernel.args

Create arguments from a list

val run_kernel : Kernel.t -> args:Kernel.args -> grid:dims -> block:dims -> ?shared_mem:int -> unit -> unit

Run a kernel with the given arguments

val run : Device.t -> name:string -> source:string -> args:arg list -> grid:dims -> block:dims -> ?shared_mem:int -> unit -> unit

High-level run function: compile (if needed) and execute.

val alloc_float32 : Device.t -> int -> float Memory.buffer

Memory allocation shortcuts

val alloc_float64 : Device.t -> int -> float Memory.buffer
val alloc_int32 : Device.t -> int -> int32 Memory.buffer
val alloc_int64 : Device.t -> int -> int64 Memory.buffer
val alloc_custom : Device.t -> size:int -> elem_size:int -> 'a Memory.buffer

Allocate a buffer for custom types with explicit element size

val to_device : src:('a, 'b, Stdlib.Bigarray.c_layout) Stdlib.Bigarray.Array1.t -> dst:'a Memory.buffer -> unit

Host-to-device transfer

val from_device : src:'a Memory.buffer -> dst:('a, 'b, Stdlib.Bigarray.c_layout) Stdlib.Bigarray.Array1.t -> unit

Device-to-host transfer

val to_device_ptr : src_ptr:unit Ctypes.ptr -> dst:'a Memory.buffer -> unit

Host-to-device transfer for custom types (raw pointer)

val from_device_ptr : src:'a Memory.buffer -> dst_ptr:unit Ctypes.ptr -> unit

Device-to-host transfer for custom types (raw pointer)

val free : 'a Memory.buffer -> unit

Free a buffer