pub const fn arena_size_for(cbs: usize) -> usizeExpand description
phase-271 — default arena bytes for a per-entry executor holding cbs
callback slots. Scales the build-time ARENA_SIZE (which is sized for the
default MAX_CBS) linearly by cbs, so a per-entry ExecutorSizing with
a caller-chosen cbs gets the same per-slot arena budget the global default
used — a fat entry (more callbacks) gets a larger arena, a lean one a smaller
one — without a workspace-global NROS_EXECUTOR_ARENA_SIZE. Floored at the
full default so no per-entry executor is ever smaller than a single-slot
build would have been (the arena is a worst-case upper bound; over-provision
is safe, under-provision fails entity creation).
§The ratio is for an UNDECLARED image only (issue 1290)
The scaling above reads ARENA_SIZE as a budget for MAX_CBS slots, so
ARENA_SIZE / MAX_CBS is one slot’s worth and cbs of them is cbs slots’
worth. That is exactly what ARENA_SIZE is while nothing declared: the
derivation budgets max_cbs worst-case entries plus a base overhead.
It stopped being that in phase-403 step 3 for an image that DECLARES its
entities. There nros-node/build.rs sums the model per KIND — subscriptions
at their own depth and type, timers at 64 bytes, services, action clients —
and MAX_CBS is a separate knob that takes no part. Dividing by it then
divides by a number with no relationship to the sum, and multiplying by
cbs scales a total that was never per-slot. Measured on
packages/testing/nros-bench/large-msg-baremetal with one declared
subscription: the model is 14,424 bytes and arena_size_for(2) returned
7,212. Half.
So when the image declares, this asks the model: ARENA_SIZE IS the model
(floored, and executor::arena_oracle refuses at compile time to let a
stated knob sit below it), and every per-entry executor gets all of it.
That over-provisions a TIERED boot, where one tier holds a subset of the
image and now carries the whole model. Deliberate, and the direction is the
safe one: the alternative needs the ENTRY’s own per-kind counts where the
macro emits the sizing, and those do not reach it today (issue 1290 records
the choice). An entry that wants less states its own
ExecutorSizing and holds it to what it registers with
ExecutorSizing::assert_covers_model, which is a compile-time check the
ratio never had.