Module Spoc_core.Vector

include module type of struct include Vector_types end
include sig ... end
type (!'a, !'b) scalar_kind =
  1. | Float16 : (float, Stdlib.Bigarray.float16_elt) scalar_kind
  2. | Float32 : (float, Stdlib.Bigarray.float32_elt) scalar_kind
  3. | Float64 : (float, Stdlib.Bigarray.float64_elt) scalar_kind
  4. | Int32 : (int32, Stdlib.Bigarray.int32_elt) scalar_kind
  5. | Int64 : (int64, Stdlib.Bigarray.int64_elt) scalar_kind
  6. | Char : (char, Stdlib.Bigarray.int8_unsigned_elt) scalar_kind
  7. | Complex32 : (Stdlib.Complex.t, Stdlib.Bigarray.complex32_elt) scalar_kind
type !'a custom_type = 'a Spoc_core_base.Make(Ctypes_ops).custom_type = {
  1. elem_size : int;
  2. type_id : 'a Sarek_ir_types.Type_id.t;
  3. vector_type_id : ('a, unit) t Sarek_ir_types.Type_id.t;
  4. get : Ctypes_ops.handle -> int -> 'a;
  5. set : Ctypes_ops.handle -> int -> 'a -> unit;
  6. name : string;
  7. ir_fields : (string * Sarek_ir_types.elttype) list option;
}
and (!'c, !'d) kind = ('c, 'd) Spoc_core_base.Make(Ctypes_ops).kind =
  1. | Scalar : ('a, 'b) scalar_kind -> ('a, 'b) kind
  2. | Custom : 'a0 custom_type -> ('a0, unit) kind
and (!'c, !'d) host_storage = ('c, 'd) Spoc_core_base.Make(Ctypes_ops).host_storage =
  1. | Bigarray_storage : ('a, 'b, Stdlib.Bigarray.c_layout) Stdlib.Bigarray.Array1.t -> ('a, 'b) host_storage
  2. | Custom_storage : {
    1. ptr : Ctypes_ops.handle;
    2. custom : 'a0 custom_type;
    3. length : int;
    } -> ('a0, unit) host_storage
and soa_binding = Spoc_core_base.Make(Ctypes_ops).soa_binding = {
  1. soa_num_leaves : int;
  2. soa_aos_stride : int;
  3. soa_scatter : unit -> unit;
  4. soa_gather : unit -> unit;
  5. soa_to_device : Ctypes_ops.device_t -> unit;
  6. soa_leaf_bufs : Ctypes_ops.device_t -> Ctypes_ops.device_buf list;
  7. soa_from_device : Ctypes_ops.device_t -> unit;
  8. soa_free_leaves : Ctypes_ops.device_t option -> unit;
  9. soa_leaves_live : bool Stdlib.ref;
}
and (!'a, !'b) t = ('a, 'b) Spoc_core_base.Make(Ctypes_ops).t = {
  1. host : ('a, 'b) host_storage;
  2. device_buffers : (int, Ctypes_ops.device_buf) Stdlib.Hashtbl.t;
  3. length : int;
  4. kind : ('a, 'b) kind;
  5. mutable location : location;
  6. mutable auto_sync : bool;
  7. id : int;
  8. mutable soa : soa_binding option;
}
val to_bigarray_kind : ('a, 'b) scalar_kind -> ('a, 'b) Stdlib.Bigarray.kind
val bigarray_elem_size : ('a, 'b) Stdlib.Bigarray.kind -> int
val scalar_elem_size : ('a, 'b) scalar_kind -> int
val elem_size : ('a, 'b) kind -> int
val scalar_kind_name : ('a, 'b) scalar_kind -> string
val kind_name : ('a, 'b) kind -> string
val float16_type_id : float Sarek_ir_types.Type_id.t
val float32_type_id : float Sarek_ir_types.Type_id.t
val float64_type_id : float Sarek_ir_types.Type_id.t
val int32_type_id : int32 Sarek_ir_types.Type_id.t
val int64_type_id : int64 Sarek_ir_types.Type_id.t
val char_type_id : char Sarek_ir_types.Type_id.t
val complex32_type_id : Stdlib.Complex.t Sarek_ir_types.Type_id.t
val scalar_type_id : ('a, 'b) scalar_kind -> 'a Sarek_ir_types.Type_id.t
val type_id : ('a, 'b) kind -> 'a Sarek_ir_types.Type_id.t
val float16_vector_type_id : (float, Stdlib.Bigarray.float16_elt) t Sarek_ir_types.Type_id.t
val float32_vector_type_id : (float, Stdlib.Bigarray.float32_elt) t Sarek_ir_types.Type_id.t
val float64_vector_type_id : (float, Stdlib.Bigarray.float64_elt) t Sarek_ir_types.Type_id.t
val int32_vector_type_id : (int32, Stdlib.Bigarray.int32_elt) t Sarek_ir_types.Type_id.t
val int64_vector_type_id : (int64, Stdlib.Bigarray.int64_elt) t Sarek_ir_types.Type_id.t
val char_vector_type_id : (char, Stdlib.Bigarray.int8_unsigned_elt) t Sarek_ir_types.Type_id.t
val complex32_vector_type_id : (Stdlib.Complex.t, Stdlib.Bigarray.complex32_elt) t Sarek_ir_types.Type_id.t
val vector_type_id : ('a, 'b) kind -> ('a, 'b) t Sarek_ir_types.Type_id.t
val create_scalar : ('a, 'b) scalar_kind -> ?dev:Ctypes_ops.device_t -> int -> ('a, 'b) t
val create : ('a, 'b) kind -> ?dev:Ctypes_ops.device_t -> int -> ('a, 'b) t
val create_custom : 'a custom_type -> ?dev:Ctypes_ops.device_t -> int -> ('a, unit) t
val of_bigarray : ('a, 'b) scalar_kind -> ('a, 'b, Stdlib.Bigarray.c_layout) Stdlib.Bigarray.Array1.t -> ('a, 'b) t
val of_raw_handle : 'a custom_type -> nativeint -> int -> ('a, unit) t
val has_buffer : ('a, 'b) t -> Ctypes_ops.device_t -> bool
val get_buffer : ('a, 'b) t -> Ctypes_ops.device_t -> Ctypes_ops.device_buf option
val custom_to_bytes : 'a custom_type -> 'a -> bytes
val custom_of_bytes : 'a custom_type -> bytes -> 'a
type sub_meta = Spoc_core_base.Make(Ctypes_ops).sub_meta = {
  1. parent_id : int;
  2. start : int;
  3. ok_range : int;
  4. ko_range : int;
  5. depth : int;
}
val is_sub : ('a, 'b) t -> bool
val get_sub_meta : ('a, 'b) t -> sub_meta option
val depth : ('a, 'b) t -> int
val parent_id : ('a, 'b) t -> int option
val sub_start : ('a, 'b) t -> int option
val sub_ok_range : ('a, 'b) t -> int option
val sub_ko_range : ('a, 'b) t -> int option
val copy_host_only : ('a, 'b) t -> ('a, 'b) t
val sub_vector_host : ('a, 'b) t -> start:int -> len:int -> ('a, 'b) t
val partition_host : ('a, 'b) t -> Ctypes_ops.device_t array -> ('a, 'b) t array
val of_list : ('a, 'b) kind -> 'a list -> ('a, 'b) t
val of_array : ('a, 'b) kind -> 'a array -> ('a, 'b) t
val host_handle : ('a, 'b) t -> Ctypes_ops.handle
val host_raw : ('a, 'b) t -> nativeint
module type DEVICE_BUFFER = Vector_types.DEVICE_BUFFER

Re-export DEVICE_BUFFER module type for backward compatibility

type device_buffer = (module DEVICE_BUFFER)

Device buffer type alias

module Custom_helpers = Vector_types.Custom_helpers

Helper functions for custom type implementations. These wrap Ctypes operations to provide simpler APIs for PPX-generated code.

val of_ctypes_ptr : 'a custom_type -> unit Ctypes.ptr -> int -> ('a, unit) t

Wrap an existing ctypes pointer as a custom-storage vector (shares memory).

Accessors

val length : ('a, 'b) t -> int
val kind : ('a, 'b) t -> ('a, 'b) kind
val location : ('a, 'b) t -> location
val id : ('a, 'b) t -> int
val device : ('a, 'b) t -> Device.t option

Get device if vector has GPU data

Raw Data Access

val to_bigarray : 'a 'b. ('a, 'b) t -> ('a, 'b, Stdlib.Bigarray.c_layout) Stdlib.Bigarray.Array1.t

Get underlying Bigarray (only for scalar vectors)

Sync and host pointer helpers (delegated)

type sync_callback = Vector_transfer.sync_callback = {
  1. sync : 'a 'b. ('a, 'b) t -> bool;
}
val to_ctypes_ptr : ('a, 'b) Vector_types.t -> unit Ctypes.ptr
val host_ptr : ('a, 'b) Vector_types.t -> nativeint
val register_sync_callback : Vector_transfer.sync_callback -> unit
val ensure_cpu_sync : ('a, 'b) Vector_types.t -> unit

Element Access

val get : 'a 'b. ('a, 'b) t -> int -> 'a

Get element (works for both storage types). Auto-syncs from GPU if location is Stale_CPU and auto_sync is enabled.

val set : 'a 'b. ('a, 'b) t -> int -> 'a -> unit

Set element (works for both storage types)

val (.%[]) : ('a, 'b) t -> int -> 'a

Indexing operators

val (.%[]<-) : ('a, 'b) t -> int -> 'a -> unit

Unsafe Access (no bounds check)

val unsafe_get : 'a 'b. ('a, 'b) t -> int -> 'a
val unsafe_set : 'a 'b. ('a, 'b) t -> int -> 'a -> unit
val kernel_set : 'a 'b. ('a, 'b) t -> int -> 'a -> unit

Kernel-safe set: no bounds check, no location update, AND no staleness sync. After backlog-190 this is the only host writer exempt from the staleness handling set/unsafe_set/fill all now perform, so the exemption is stated rather than left as a difference a reader has to notice. It is deliberate: a per-element location update would race across the threads this function exists to serve, and the kernel already owns the buffer for the duration of the launch.

Use this in parallel kernel execution where:

  • Bounds are guaranteed by kernel logic
  • Location tracking is not needed (data stays on same device)
  • Multiple threads may write to different indices concurrently

Auto-sync Control

val set_auto_sync : ('a, 'b) t -> bool -> unit

Turn the implicit device->host read-back on vec on or off.

WHAT TURNING IT OFF MEANS, written here because this is where a caller turning it off will look, and because until now it was written nowhere: Vector_transfer.ensure_cpu_sync returns immediately when this is false, so every operation that relies on it stops pulling the device copy down. The caller takes over that duty; the operations do not fail, they read whatever host storage holds.

Three consequences that are not obvious from the flag's name:

  • get returns the HOST buffer on a Stale_CPU vector, i.e. the values from before the launch, with no error;
  • set/unsafe_set no longer read-modify-write against a current buffer, so the element they write sits beside length - 1 stale ones and the location arm below correctly leaves the DEVICE copy authoritative;
  • for a transparent SoA vector, Soa_vector.scatter transposes out of that same host storage, so a launch result still sitting in the leaves is overwritten by pre-launch bytes rather than gathered first. Raised in review of PR #375; NOT changed there, because making the SoA path transfer anyway would be this flag not meaning what it says. Drain explicitly (Transfer.to_cpu ~force:true) before reusing such a vector.

true is the default and the state every test in this repository runs in except where a case disables it deliberately to observe a specific transfer.

val auto_sync : ('a, 'b) t -> bool

Location Queries

val is_on_cpu : ('a, 'b) t -> bool
val is_on_gpu : ('a, 'b) t -> bool
val is_synced : ('a, 'b) t -> bool
val needs_gpu_update : ('a, 'b) t -> bool
val needs_cpu_update : ('a, 'b) t -> bool

Device Buffer Management

has_buffer and get_buffer are provided by Vector_types via the functor.

Pretty Printing

val location_to_string : location -> string
val to_string : ('a, 'b) t -> string

Convenience Constructors for Scalar Types

val float16 : (float, Stdlib.Bigarray.float16_elt) kind
val float32 : (float, Stdlib.Bigarray.float32_elt) kind
val float64 : (float, Stdlib.Bigarray.float64_elt) kind
val int32 : (int32, Stdlib.Bigarray.int32_elt) kind
val int64 : (int64, Stdlib.Bigarray.int64_elt) kind
val char : (char, Stdlib.Bigarray.int8_unsigned_elt) kind
val complex32 : (Stdlib.Complex.t, Stdlib.Bigarray.complex32_elt) kind
val create_float16 : ?dev:Ctypes_ops.device_t -> int -> (float, Stdlib.Bigarray.float16_elt) t

Create an f16 vector. Elements are ordinary OCaml floats; every set rounds to IEEE binary16 (so 3.14159 reads back as 3.14062).

val create_float32 : ?dev:Ctypes_ops.device_t -> int -> (float, Stdlib.Bigarray.float32_elt) t
val create_float64 : ?dev:Ctypes_ops.device_t -> int -> (float, Stdlib.Bigarray.float64_elt) t
val create_int32 : ?dev:Ctypes_ops.device_t -> int -> (int32, Stdlib.Bigarray.int32_elt) t
val create_int64 : ?dev:Ctypes_ops.device_t -> int -> (int64, Stdlib.Bigarray.int64_elt) t

Initialization Helpers

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

Fill vector with a value

val init : 'a 'b. ('a, 'b) kind -> int -> (int -> 'a) -> ('a, 'b) t

Initialize with a function

val copy : 'a 'b. ('a, 'b) t -> ('a, 'b) t

Copy vector (CPU data only, auto-syncs source if needed)

Subvector Support

val sub_vector : ('a, 'b) t -> start:int -> len:int -> ?ok_range:int -> ?ko_range:int -> unit -> ('a, 'b) t

Create a subvector that shares CPU memory with parent.

  • parameter vec

    Parent vector

  • parameter start

    Starting index in parent

  • parameter len

    Length of subvector

  • parameter ok_range

    Elements safe to read (default: len)

  • parameter ko_range

    Elements to avoid writing (default: 0)

Multi-GPU Helpers

val partition : ('a, 'b) t -> Device.t array -> ('a, 'b) t array

Partition a vector across multiple devices. Creates subvectors, one per device, that together cover the full vector.

val gather : ('a, 'b) t array -> unit

Gather subvectors back to parent (sync all to CPU). Assumes subvectors were created by partition and don't overlap.

Phase 6: Vector Utilities

Iteration

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

Iterate over all elements (CPU-side, auto-syncs if needed)

val iteri : 'a 'b. (int -> 'a -> unit) -> ('a, 'b) t -> unit

Iterate with index

Mapping

val map : 'a 'b 'c 'd. ('a -> 'c) -> ('c, 'd) kind -> ('a, 'b) t -> ('c, 'd) t

Map function over vector, creating new vector with given kind

val mapi : 'a 'b 'c 'd. (int -> 'a -> 'c) -> ('c, 'd) kind -> ('a, 'b) t -> ('c, 'd) t

Map with index

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

In-place map (same type)

Folding

val fold_left : 'a 'b 'acc. ('acc -> 'a -> 'acc) -> 'acc -> ('a, 'b) t -> 'acc

Fold left

val fold_right : 'a 'b 'acc. ('a -> 'acc -> 'acc) -> ('a, 'b) t -> 'acc -> 'acc

Fold right

Predicates

val for_all : 'a 'b. ('a -> bool) -> ('a, 'b) t -> bool

Check if all elements satisfy predicate

val exists : 'a 'b. ('a -> bool) -> ('a, 'b) t -> bool

Check if any element satisfies predicate

val find : 'a 'b. ('a -> bool) -> ('a, 'b) t -> 'a option

Find first element satisfying predicate

val find_index : 'a 'b. ('a -> bool) -> ('a, 'b) t -> int option

Find index of first element satisfying predicate

Aggregation

val sum : zero:'a -> add:('a -> 'a -> 'a) -> ('a, 'b) t -> 'a

Sum elements (requires + operation via fold)

val min_elt : compare:('a -> 'a -> int) -> ('a, 'b) t -> 'a option

Find minimum element

val max_elt : compare:('a -> 'a -> int) -> ('a, 'b) t -> 'a option

Find maximum element

Conversion

val to_list : 'a 'b. ('a, 'b) t -> 'a list

Convert to OCaml list

val to_array : 'a 'b. ('a, 'b) t -> 'a array

Convert to OCaml array

Blitting

val blit : 'a 'b. src:('a, 'b) t -> src_off:int -> dst:('a, 'b) t -> dst_off:int -> len:int -> unit

Copy elements from one vector to another