Module Spoc_core.Transfer

Auto-Transfer Mode

val auto_mode : bool Stdlib.ref
val enable_auto : unit -> unit
val disable_auto : unit -> unit
val is_auto : unit -> bool
val set_auto : bool -> unit

Device Buffer Allocation

val alloc_scalar_buffer : Device.t -> int -> ('a, 'b) Vector.scalar_kind -> Vector.device_buffer

Allocate a device buffer for a scalar vector, returning a DEVICE_BUFFER module. The buffer is packaged with its backend for type-safe operations.

For CPU devices (OpenCL CPU, Native), uses zero-copy allocation when possible to avoid memory transfers entirely.

val alloc_scalar_buffer_zero_copy : Device.t -> ('a, 'b, Stdlib.Bigarray.c_layout) Stdlib.Bigarray.Array1.t -> ('a, 'b) Vector.scalar_kind -> Vector.device_buffer option

Allocate a device buffer using zero-copy (host memory sharing) if supported. Returns None if the backend doesn't support zero-copy for this device.

val alloc_custom_buffer : Device.t -> int -> int -> Vector.device_buffer

Allocate a device buffer for a custom vector

Buffer Management for Vectors

val ensure_buffer : ('a, 'b) Vector.t -> Device.t -> Vector.device_buffer

Ensure vector has a device buffer, allocating if needed. For backends that support zero-copy (typically CPU backends), automatically uses zero-copy to avoid memory transfer overhead. The backend decides via alloc_zero_copy.

Transfer Operations

module Read_back : sig ... end

Everything that reads device memory back into host storage, and NOTHING else. The module exists for its signature: copy_device_to_host is defined inside and deliberately absent from it, so the only code that can call the packed-buffer read directly is Read_back.read_back_to_host below.

val has_device_data : ('a, 'b) Vector.t -> Device.t -> bool
val read_back_to_host : ('a, 'b) Vector.t -> Device.t -> unit
val to_device : ('a, 'b) Vector.t -> Device.t -> unit

Transfer vector data to a device

val to_cpu : ?force:bool -> ('a, 'b) Vector.t -> unit

Transfer vector data from device to CPU.

  • parameter force

    If true, always transfer even if location is Both (useful after kernel writes)

val sync : ('a, 'b) Vector.t -> unit

Ensure vector is fully synchronized

Buffer Cleanup

val free_buffer : ('a, 'b) Vector.t -> Device.t -> unit

Release the device memory vec holds on dev, draining it to host storage first.

FOUR steps, and not one of them may sit inside get_buffer's Some arm. Under the SoA ABI the leaves are the only device memory the vector has and the packed buffer is never allocated, so on a transparent vector get_buffer returns None ALWAYS — an early return there does not skip a corner case, it skips the whole function.

The previous version of this comment already said "under the SoA ABI they are the only device memory this vector has" while the bookkeeping below it still lived in the Some buf arm and assumed a packed buffer existed. That mismatch was the bug, not a wording slip: the location reset is the only code here that assigns CPU, so a transparent SoA vector came out of this function with its leaves freed and location still naming dev. Two measured consequences, both on a vector whose data was intact in host storage:

  • to_cpu ~force:true raised Failure "to_cpu: no device buffer to transfer from"Both dev plus force means "read the device back", and there is nothing there to read;
  • to_device on the same device took the "skip (Both)" short-circuit and allocated nothing, reinstating the exact short-circuit the Stale_CPU work earlier in this branch exists to eliminate.

free_all_buffers was never exposed to this because it assigns CPU unconditionally at the end. This function now does the same, scoped to dev.

val free_all_buffers : ('a, 'b) Vector.t -> unit

Free all device buffers for a vector

Device Synchronization

val flush : Device.t -> unit

Synchronize all pending operations on a device

Stream Operations

module type STREAM = sig ... end

Stream handle - packages backend stream with its operations

type stream = (module STREAM)
val create_stream : Device.t -> stream

Create a new stream on a device

val default_stream : Device.t -> stream

Get default stream for a device

val synchronize_stream : stream -> unit
val destroy_stream : stream -> unit

Batch Operations

val to_device_all : ('a, 'b) Vector.t list -> Device.t -> unit
val to_cpu_all : ('a, 'b) Vector.t list -> unit
val sync_all : ('a, 'b) Vector.t list -> unit

Auto-sync Callback Registration