Ir.Alloc_censusA process-global census of the allocation classes whose accumulation across a schedule search exhausted a 12 GB card (gh-ocannl-550).
The question the census exists to answer is which class grows with candidates processed, so the classes are separated rather than summed: the device buffers behind the backends' pool tables (working, i.e. context-owned, vs. constant, i.e. per-device and deduped), the backend contexts, and the loaded code modules. Bytes are tracked only for pools; a module's device footprint is not a number any backend API reports.
Counting sites, and therefore the exact coverage:
Backends.allocate_delta (a compile's in-context delta) and the allocate used when a from_host or copy destination is not in the context yet — against the context finalize that frees either. A device's reserved merge-buffer pool is NOT counted: it is one entry per device that grows in place, so it cannot be a growth class at all, and its allocation site is inside each backend rather than at the shared seam. Read the device's merge_buffer_capacity for that one.Backend_impl.Device.make_context / make_child, shared by every backend, against the context finalize.cc and cuda (the backends the gh-ocannl-550 measurements and its regression test use); hip and metal leave the counters at zero rather than reporting a wrong number.Consequently live_* is exact for what it covers and is not a device-memory total: use Context.get_used_memory for the backend's own view. Note also which counters are live and which are not: pools and modules are (a pool is in the table or it is not; a module's unload is counted by the finalizer that performs it), whereas contexts are only ever decremented by an explicit release — see unreleased_contexts.
Records a pool as live. Replacing an existing (device_id, pool_id) entry replaces its size (a pool grown in place is still one live pool).
Drops a pool from the live set, counting a free. Idempotent: a second call for a pool already forgotten does nothing, so a backend whose free_pool runs twice cannot double-count.
type t = {live_working_pools : int;live_working_bytes : int;live_constant_pools : int;live_constant_bytes : int;working_pools_allocated : int;constant_pools_allocated : int;pools_freed : int;contexts_created : int;contexts_released : int;modules_loaded : int;modules_unloaded : int;}A point-in-time reading. The live_* fields come from the live table, the rest are cumulative since process start.
val sexp_of_t : t -> Sexplib0.Sexp.tinclude Ppx_compare_lib.Equal.S with type t := tval equal : t Base__Ppx_compare_lib.equalval snapshot : unit -> tval live_pools : t -> intval live_pool_bytes : t -> intval unreleased_contexts : t -> intcontexts_created - contexts_released. NOT a live count, and the difference matters: unlike a pool, a context is not rooted by any table, so an unreleased one may well have been collected already — nothing on the device depends on the record's liveness. What the number tracks is contexts whose pools were never explicitly freed, which is the useful signal precisely because those pools ARE rooted. Compare live_pools, live_modules: those two are genuinely live, the former because the table is the authority and the latter because unloads are counted from the GC finalizer that performs them.
val live_modules : t -> intval to_string : t -> string