Files
LithosAnanake/Kconfig.kernel
T
Robert Allan JamesandClaude Sonnet 5 89d8c08582 stadium: wire STADIUM_CAPACITY_TICK in as a flat threshold, not a scheduler
Closes FABRIC-2.md's last open §12 Q5 question. fleet_heartbeat_tick_count
is fed by every live VM's own vm_tick(), not one VM's, so it was reaching
HEARTBEAT_INFERENCE_FREQUENCY (shared/borrowed from the per-VM inference
gate) several times faster than intended with more than one VM live -
backwards from FABRIC.md §22.4's required ~1000:1 separation.

What's actually gated turned out to be low-stakes: vm_physics_tick()
(capsule_vm_physics.c:397) is a passive statistics refit - re-sorts a
window of past heat-transfer samples and recomputes a median rate
estimate. It doesn't move heat or arbitrate capacity. Firing too often
just meant a noisier statistic recomputed more frequently than planned,
not incorrect behavior.

Considered and explicitly rejected: scaling the threshold by live VM
count at the check site. That's the first brick of a scheduler - reading
fleet state to adjust a rate dynamically - which this project has
deliberately avoided building. Implemented instead: STADIUM_CAPACITY_TICK
(existing Kconfig symbol, defined but never read by any code path) now
gates vm_physics_heartbeat_tick()'s call directly, replacing the borrowed
HEARTBEAT_INFERENCE_FREQUENCY. Default bumped 1000 -> 4000, a flat
constant picked once for Tripod's known 4-VM topology, same kind of
placeholder as every other frequency knob in Kconfig.kernel - not
computed from anything at runtime. Renamed fleet_last_inference_tick ->
fleet_last_capacity_tick to match. Still one clock, one counter
(fleet_heartbeat_tick_count) - just a bigger flat divisor on it.

Three-arch QEMU acceptance: all clean to ok>, identical Stadium
conservation invariant on all three (resident_sum=43691 reservoir=21845
sum=65536). logs/20260815-093425/amd64, logs/20260815-093521/aarch64,
logs/20260815-093641/riscv64.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 09:37:58 -04:00

134 lines
6.5 KiB
Plaintext

menu "Kernel-only options"
if STARFORTH_VARIANT_KERNEL
config STARFORTH_ENABLE_VM
bool "Enable StarForth VM integration, M7 milestone (STARFORTH_ENABLE_VM)"
default y
help
Compiles the full StarForth VM source tree into the kernel image
and enables capsule birth/execution. Disabling this builds a
kernel that only reaches the M0-M6 hardware milestones (console,
PMM, VMM, interrupts, timers, kmalloc) with no FORTH interpreter,
no capsules, no "ok" REPL. Gates a large source-file selection
block in Makefile.starkernel, not just a handful of -D flags.
config PARITY_MODE
bool "Deterministic parity harness mode (PARITY_MODE)"
default n
help
Enables the parity/determinism verification harness used to
compare dict_hash and capsule state across independent runs.
Off by default (normal boot); on for parity-campaign builds.
config SK_PARITY_DEBUG
bool "Verbose parity/vocabulary debug logging (SK_PARITY_DEBUG)"
default n
help
Extra diagnostic logging in vocabulary_words.c and
vm_bootstrap.c's parity paths (src/starkernel/vm/vm_internal.h
guards these with #if defined(__STARKERNEL__) && SK_PARITY_DEBUG).
Previously opt-in-only via VM_FEATURE_FLAG_VARS with no Kconfig
presence at all; promoted here for discoverability, same
treatment as every other previously-unwired constant in this
migration.
config STADIUM_VM_MEMORY_PERCENT
int "Percent of remaining kmalloc heap the outer Stadium budgets for VM population (STADIUM_VM_MEMORY_PERCENT)"
default 50
help
Replaces the old fixed STADIUM_MAX_VM_COUNT bound (Captain Bob,
2026-08-15: a hardcoded population ceiling cannot be right when the
actual population is unknowable in advance -- could be 4, could be
4000). The outer Stadium's VM population bound is now computed at
boot, the same way the cell array already is (STADIUM_MEMORY_PERCENT
below): this percentage of the kmalloc heap's remaining free bytes
(kmalloc_get_stats(), taken AFTER the cell array's own allocation),
divided by VM_MEMORY_SIZE (5 MiB, include/vm.h), floored to 1 so Hera
can always boot. No upper ceiling -- birth is refused once the
computed bound is reached (FABRIC.md item 1.5's refusal behaviour is
unchanged), it just isn't a compile-time guess anymore. Default of
50% is an untuned placeholder, not a derived optimum, same DoE-later
treatment as STADIUM_MEMORY_PERCENT.
config STADIUM_CONTAINS_DEPTH_MAX
int "Patron containment chain depth cap (STADIUM_CONTAINS_DEPTH_MAX)"
default 5
help
Hard bound on how many patrons deep a `contains` chain (FABRIC.md
item 1.1, the ninth cell wire) may nest. A patron with a non-none
`contains` link cannot be reaped -- reap-gating enforcement of
this bound is item 3.5's scope, not yet implemented. Distinct
from the already-implemented VM-Stadium nesting depth (item 1.7,
default 2): that bounds VMs nested inside VMs, this bounds
patrons held inside patrons within one Stadium.
config STADIUM_CAPACITY_TICK
int "Fleet transfer-slope re-estimation cadence, in virtual ticks (STADIUM_CAPACITY_TICK)"
default 4000
help
How often vm_physics_heartbeat_tick() re-fits the fleet's
transfer-slope estimate (vm_physics_tick() -- a passive median
recompute over recent touch samples, not a capacity/transfer
decision itself), expressed in virtual ticks -- never wall-clock.
Wired in 2026-08-15 (FABRIC-2.md F.2/§12 Q5): this counter is fed
by EVERY live VM's own vm_tick(), not one VM's, so it previously
shared HEARTBEAT_INFERENCE_FREQUENCY (1000) and fired roughly
(live VM count) times faster than a single VM's own heat-inference
gate -- backwards from the "order of magnitude apart" minimum
(FABRIC.md §22.4). Default of 4000 is a flat, untuned placeholder
picked to roughly restore that separation at Tripod's known
4-VM topology (Hera + two Hermes + Artemis) -- not computed from
live VM count at runtime, deliberately: a fixed constant, same
as every other frequency knob here, not adaptive logic. Real
tuning is DoE work (item 5.1), same treatment as the other
placeholder constants in this file.
config STADIUM_MEMORY_PERCENT
int "Percent of free physical memory the Stadium claims at boot (STADIUM_MEMORY_PERCENT)"
default 1
help
The Stadium's global cell array is sized at boot from
pmm_get_stats().free_bytes, taken at the point of allocation
(FABRIC.md item 3.2, §17.6 position (b): "sized at boot from the
memory budget", not a hardcoded cell count). This is the fraction
of that free-byte figure the array claims, rounded down to whole
64-byte cells. Default of 1% is conservative -- comfortably clears
the ~4096-cells-per-VM illustrative figure in FABRIC.md §23.3
against a QEMU -m 1024 test config while leaving the kernel heap
and everything else nearly all of physical memory.
config STADIUM_WORD_HEAT_QUANTUM
int "Q48.16 heat quantum moved per word touch/starter-grant (STADIUM_WORD_HEAT_QUANTUM)"
default 2048
help
FABRIC.md §17.7 (item 4.1): the fixed Q48.16 amount transferred between
a VM's Stadium reservoir and a word patron's cell on every touch
(already-resident) or starter-grant admission attempt (non-resident,
Option B). Q48_ONE is 65536; the default of 2048 is Q48_ONE divided by
HOTWORDS_CACHE_SIZE (32) -- the population of the cache mechanism this
item retires under __STARKERNEL__ -- so roughly 32 words could hold a
"fully loaded" starter share at once, matching the old cache's slot
count. An untuned placeholder, not a derived optimum: real tuning is
DoE work (item 5.1), same treatment as STADIUM_MEMORY_PERCENT above.
config STADIUM_WORD_COOL_RATE_Q48
int "Q48.16 fraction of resident heat removed per tick (STADIUM_WORD_COOL_RATE_Q48)"
default 21845
help
FABRIC.md §17.7 (item 4.1): redirects Loop #3's decay shape onto
Stadium word-patron heat instead of discarding it -- cooled heat
returns to the VM's reservoir rather than vanishing, so this must be a
fraction of the patron's OWN current heat removed per elapsed tick
(unit-safe for a conserved share of 1.0), not a flat per-tick amount
the way execution_heat's own decay works. Default reuses
INITIAL_DECAY_SLOPE_Q48's numeric value (21845, ~1/3) reinterpreted as
this fraction -- the existing inference engine converged on that
magnitude for the analogous cooling purpose on execution_heat, so it
is a reasonable starting point, not the same quantity. Untuned
placeholder: real tuning is DoE work (item 5.1).
endif # STARFORTH_VARIANT_KERNEL
endmenu