Module Sarek_interp.Cpu_pool_lifecycle

Sizing and lifetime of the process-wide CPU worker pools (the interpreter and Native block pool, the Native thread and parallel pools, the fission queue dispatchers).

Every live domain takes part in every minor collection, so an idle worker still slows all host allocation in the process. Pools are therefore created on their first launch only, never by device enumeration, and retired once no launch has used them for the idle timeout: their workers exit and are joined. The next launch creates them again. A pool is never retired while a launch holds it. Retirement is done by one reaper domain that exists only while some pool is live.

Configuration, read when a pool is created:

Configuration

val set_max_domains : int -> unit

set_max_domains n caps every pool created from now on at n workers. Raises Invalid_argument if n < 1.

val set_idle_timeout : float -> unit

set_idle_timeout s retires pools idle for s seconds. Raises Invalid_argument unless s > 0..

val capped : int -> int

capped n is n bounded by the configured maximum, and at least 1.

val domain_count : ?spare:int -> default:int -> unit -> int

Worker count for a new pool: SAREK_DOMAIN_COUNT if set to a positive integer, else Domain.recommended_domain_count () (else default) minus spare (default 0), then capped.

val spawn_workers : int -> (int -> unit) -> abort:(unit -> unit) -> unit Stdlib.Domain.t array

spawn_workers n worker ~abort spawns n domains running worker 0 .. worker (n - 1). If a spawn fails (OCaml's domain limit), abort () must make the workers already started exit; they are joined and the failure is re-raised, so a failed pool creation leaves no domain behind.

Pool slots

type 'p slot

A process-wide pool created on demand and retired when idle.

val slot : create:(unit -> 'p) -> retire:('p -> unit) -> 'p slot

slot ~create ~retire registers a slot with the reaper. create () makes the pool (sizing it with domain_count); retire p makes its workers exit and joins them, and is called only when no launch holds p.

val with_pool : 'p slot -> ('p -> 'a) -> 'a

with_pool s f runs f on the pool of s, creating it if needed. The pool is not retired before f returns or raises.

Other idle resources

val register_reapable : (now:float -> idle_after:float -> bool) -> unit

register_reapable f adds a resource the reaper polls: f ~now ~idle_after retires it if it has been unused since now -. idle_after and nothing is in flight, and returns true iff the resource is still live afterwards.

val note_live : unit -> unit

Starts the reaper if it is not running. Called by a resource registered with register_reapable when it becomes live.

Explicit retirement

val retire_idle_now : unit -> unit

Retire every pool and dispatcher that no launch holds now, whatever its idle time. Pools in use are left to the reaper. Also run at_exit.

val any_live : unit -> bool

true iff a pool, a dispatcher or the reaper is live.