stadium: make VM population bound RAM-derived, not a static array of 4
Replaces STADIUM_MAX_VM_COUNT (Kconfig, hardcoded default 4) with a boot-time computation, mirroring the pattern stadium_boot_init() already used for the cell pool. New Kconfig STADIUM_VM_MEMORY_PERCENT (default 50): max_vm_count = (kmalloc_get_stats().free_bytes after the cell array * STADIUM_VM_MEMORY_PERCENT / 100) / VM_MEMORY_SIZE, floored to 1, no ceiling (population is not knowable in advance - could be 4, could be 4000). stadium_quotas and word_slots (plus stat_promotions/stat_evictions) are now kmalloc'd to the computed count instead of declared with a macro. New accessor stadium_max_vm_count() replaces every STADIUM_MAX_VM_COUNT reference, including capsule_birth.c's birth-refusal gate. Two things found and fixed along the way: - The existing cell-pool budget was sourced from pmm_get_stats(), which reflects physical pages PMM hasn't handed to any subsystem yet - but the actual allocation is kmalloc(), which draws from the separate, fixed-size heap kmalloc_init() (M6) already carved out of PMM before stadium_boot_init() ever runs. Budgeting against PMM's leftover and allocating from the kmalloc heap are two different pools. Both the cell budget and the new VM-count budget now source from kmalloc_get_stats() instead. - stadium_owner[] (which VM's quota owns each cell) was uint8_t, capped at 255 slots by a compile-time assert tied to the old macro. Widened to uint16_t (65535 slots of headroom) with a runtime clamp + log if the computed count ever exceeds that, since there's no ceiling anymore. Three-arch QEMU acceptance: all clean to ok>, computed VM count genuinely differs by actual available RAM (amd64/riscv64: 50 slots at -m 1024, aarch64: 101 slots), Stadium conservation invariant identical across all three (resident_sum=43691 reservoir=21845 sum=65536). logs/20260815-080526/amd64, logs/20260815-080826/aarch64, logs/20260815-080952/riscv64. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
154eddeab0
commit
00e657019e
+68
@@ -823,3 +823,71 @@ unreachable NULL-write, `m5_time_trust`/`m5_variance` dead fields.
|
|||||||
closed items, four sequencing-blocked items (no ruling needed, just not startable yet), and
|
closed items, four sequencing-blocked items (no ruling needed, just not startable yet), and
|
||||||
one code question. Nothing in either track's open half is closeable without either Artemis or
|
one code question. Nothing in either track's open half is closeable without either Artemis or
|
||||||
an explicit decision from Captain Bob — which is the state this pass was asked to produce.
|
an explicit decision from Captain Bob — which is the state this pass was asked to produce.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## G. Stadium VM population bound made RAM-derived — 2026-08-15
|
||||||
|
|
||||||
|
Captain Bob flagged, mid-conversation, that `STADIUM_MAX_VM_COUNT` being a hardcoded
|
||||||
|
compile-time `4` was not the design he had in mind: "The stadium has capacity that is
|
||||||
|
determined at boot time with the remaining ram... a static array of four, then we're
|
||||||
|
fucked." Confirmed by grep: `STADIUM_MAX_VM_COUNT` (Kconfig default 4) sized two genuinely
|
||||||
|
static compile-time arrays — `stadium_quotas[STADIUM_MAX_VM_COUNT]` and
|
||||||
|
`word_slots[STADIUM_MAX_VM_COUNT][DICTIONARY_SIZE]` — and gated `capsule_birth.c`'s birth
|
||||||
|
refusal, with zero RAM-based computation anywhere near it. Not an oversight: `FABRIC.md`
|
||||||
|
§20.5 item 1.5 (RESOLVED 2026-08-04) explicitly decided this the other way — "fixed for the
|
||||||
|
machine's lifetime once set at build... the outer total does not itself flex at runtime."
|
||||||
|
Captain Bob overruled that: population is not knowable in advance (could be 4, could be
|
||||||
|
4000), so the bound must be computed at boot, no ceiling.
|
||||||
|
|
||||||
|
**What was already correct, and what wasn't.** The Stadium's *cell pool* (actual patron
|
||||||
|
storage) was already boot-time RAM-derived — `stadium_boot_init()`
|
||||||
|
(`src/starkernel/vm/stadium.c:118`) already computed `ncells` from a percentage of free
|
||||||
|
memory and `kmalloc()`'d it. Only the *VM population ceiling* was static.
|
||||||
|
|
||||||
|
**A second, real bug found while fixing this.** The cell-pool budget was computed from
|
||||||
|
`pmm_get_stats().free_bytes` — physical pages PMM hasn't handed to any subsystem yet — but
|
||||||
|
the actual allocation was `kmalloc()`, which draws from the *separate*, fixed-size heap
|
||||||
|
`kmalloc_init()` (M6) already carved out of PMM before `stadium_boot_init()` ever runs.
|
||||||
|
Budgeting against PMM's leftover and allocating from the kmalloc heap are two different
|
||||||
|
pools; the percentage was being applied to memory nothing here actually draws from. Fixed
|
||||||
|
as part of this change — both the existing cell budget and the new VM-count budget now
|
||||||
|
source from `kmalloc_get_stats()`.
|
||||||
|
|
||||||
|
**Owner-byte width.** `stadium_owner[]` (which VM's quota owns each cell) was `uint8_t`,
|
||||||
|
capped at 255 slots by the old compile-time assert. With no ceiling, this needed widening —
|
||||||
|
done, `uint16_t` (65535 slots of headroom), with a runtime clamp + log if the computed count
|
||||||
|
ever exceeds that.
|
||||||
|
|
||||||
|
**Mechanism (mirrors the existing cell-pool pattern exactly):** new Kconfig
|
||||||
|
`STADIUM_VM_MEMORY_PERCENT` (default 50, untuned placeholder like its `STADIUM_MEMORY_PERCENT`
|
||||||
|
sibling). At boot, after the cell array is allocated: `max_vm_count =
|
||||||
|
(kmalloc_get_stats().free_bytes * STADIUM_VM_MEMORY_PERCENT / 100) / VM_MEMORY_SIZE`
|
||||||
|
(`VM_MEMORY_SIZE` = 5 MiB, the real per-VM footprint — not the small bookkeeping tables),
|
||||||
|
floored to 1 so Hera can always boot, clamped to 65535. `stadium_quotas` and `word_slots`
|
||||||
|
(plus their `stat_promotions`/`stat_evictions` companions) are now `kmalloc()`'d to that
|
||||||
|
count instead of declared with the macro. New accessor `stadium_max_vm_count()` replaces
|
||||||
|
every `STADIUM_MAX_VM_COUNT` reference, including `capsule_birth.c`'s birth-refusal gate.
|
||||||
|
|
||||||
|
**Files touched:** `Kconfig.kernel`, `include/starforth_config.h`,
|
||||||
|
`include/starkernel/vm/stadium.h`, `include/starkernel/vm/stadium_words.h`,
|
||||||
|
`include/starkernel/capsule_run.h` (comment only), `src/starkernel/vm/stadium.c`,
|
||||||
|
`src/starkernel/vm/stadium_words.c`, `src/starkernel/capsule/capsule_birth.c`.
|
||||||
|
|
||||||
|
**Verification, all three architectures clean, computed VM count genuinely differs across
|
||||||
|
runs (proof it's really reading RAM, not a disguised constant):**
|
||||||
|
|
||||||
|
- **amd64:** `Stadium: 83886 cells (5242 KB), 50 VM slots` — `logs/20260815-080526/amd64/`
|
||||||
|
- **aarch64:** `Stadium: 167772 cells (10485 KB), 101 VM slots` — `logs/20260815-080826/aarch64/`
|
||||||
|
- **riscv64:** `Stadium: 83886 cells (5242 KB), 50 VM slots` — `logs/20260815-080952/riscv64/`
|
||||||
|
|
||||||
|
All three reached `ok>` clean with Hermes's self-test, an identical Stadium conservation
|
||||||
|
check (`resident_sum=43691 reservoir=21845 sum=65536`, `Q48_ONE=65536`), and KILL/rest all
|
||||||
|
passing — the RAM-derived count changed, the physics invariant it feeds into didn't, which
|
||||||
|
is exactly what should happen. Up from the old fixed `4` in every case.
|
||||||
|
|
||||||
|
**Related, same conversation:** this surfaced alongside a correction to §12 Q5's
|
||||||
|
`STADIUM_CAPACITY_TICK` framing (F.2 above) — Captain Bob's "the clock is only the
|
||||||
|
heartbeat, period" pushback, confirmed against `FABRIC.md` §16.4/§17.1's decided one-clock
|
||||||
|
rule. Both are Stadium-capacity-adjacent but independent: this item is the VM *population*
|
||||||
|
bound (a count), that one is the fleet-capacity *cadence* (a tick threshold).
|
||||||
|
|||||||
+16
-10
@@ -33,17 +33,23 @@ config SK_PARITY_DEBUG
|
|||||||
treatment as every other previously-unwired constant in this
|
treatment as every other previously-unwired constant in this
|
||||||
migration.
|
migration.
|
||||||
|
|
||||||
config STADIUM_MAX_VM_COUNT
|
config STADIUM_VM_MEMORY_PERCENT
|
||||||
int "Outer Stadium VM population bound (STADIUM_MAX_VM_COUNT)"
|
int "Percent of remaining kmalloc heap the outer Stadium budgets for VM population (STADIUM_VM_MEMORY_PERCENT)"
|
||||||
default 4
|
default 50
|
||||||
help
|
help
|
||||||
Hard bound on live VMs in the outer Stadium (FABRIC.md item 1.5).
|
Replaces the old fixed STADIUM_MAX_VM_COUNT bound (Captain Bob,
|
||||||
Birth is refused once this many VMs are LIVE simultaneously; a
|
2026-08-15: a hardcoded population ceiling cannot be right when the
|
||||||
dead or stillborn VM's registry slot does not count against the
|
actual population is unknowable in advance -- could be 4, could be
|
||||||
bound. Default of 4 matches Tripod's currently-known topology
|
4000). The outer Stadium's VM population bound is now computed at
|
||||||
(Hera + two Hermes instances + Artemis) -- an explicit placeholder
|
boot, the same way the cell array already is (STADIUM_MEMORY_PERCENT
|
||||||
pending a DoE campaign to find an idealized default (item 5.1),
|
below): this percentage of the kmalloc heap's remaining free bytes
|
||||||
not a padded estimate.
|
(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
|
config STADIUM_CONTAINS_DEPTH_MAX
|
||||||
int "Patron containment chain depth cap (STADIUM_CONTAINS_DEPTH_MAX)"
|
int "Patron containment chain depth cap (STADIUM_CONTAINS_DEPTH_MAX)"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Capsule Block Manifest — Auto-generated
|
# Capsule Block Manifest — Auto-generated
|
||||||
<!-- Generated by mkcapsule --manifest 2026-08-15T00:21:57Z -->
|
<!-- Generated by mkcapsule --manifest 2026-08-15T12:09:24Z -->
|
||||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||||
<!-- Hand-written justifications and immutability notes live -->
|
<!-- Hand-written justifications and immutability notes live -->
|
||||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||||
|
|||||||
Binary file not shown.
@@ -20,8 +20,8 @@ tick_number,elapsed_ns,tick_interval_ns,cache_hits_delta,bucket_hits_delta,word_
|
|||||||
19,190000,10000,0,0,154,35,40,731,731,0,0,0,65536,0,0,65536,0,0
|
19,190000,10000,0,0,154,35,40,731,731,0,0,0,65536,0,0,65536,0,0
|
||||||
20,200000,10000,0,0,154,35,38,567,567,0,0,0,65536,0,0,65536,0,0
|
20,200000,10000,0,0,154,35,38,567,567,0,0,0,65536,0,0,65536,0,0
|
||||||
21,210000,10000,0,0,153,38,37,4096,0,0,0,0,65536,0,0,65536,0,0
|
21,210000,10000,0,0,153,38,37,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
22,220000,10000,0,0,167,40,38,582,582,0,0,0,65536,0,0,65536,0,0
|
22,220000,10000,0,0,167,38,38,582,582,0,0,0,65536,0,0,65536,0,0
|
||||||
23,230000,10000,0,0,176,17,38,685,685,0,0,0,65536,0,0,65536,0,0
|
23,230000,10000,0,0,176,11,37,685,685,0,0,0,65536,0,0,65536,0,0
|
||||||
24,240000,10000,0,0,175,10,25,731,731,0,0,0,65536,0,0,65536,0,0
|
24,240000,10000,0,0,175,10,25,731,731,0,0,0,65536,0,0,65536,0,0
|
||||||
25,250000,10000,0,0,196,11,23,731,731,0,0,0,65536,0,0,65536,0,0
|
25,250000,10000,0,0,196,11,23,731,731,0,0,0,65536,0,0,65536,0,0
|
||||||
26,260000,10000,0,0,192,14,24,4096,0,0,0,0,65536,0,0,65536,0,0
|
26,260000,10000,0,0,192,14,24,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
@@ -48,14 +48,14 @@ tick_number,elapsed_ns,tick_interval_ns,cache_hits_delta,bucket_hits_delta,word_
|
|||||||
47,470000,10000,0,0,218,57,18,4096,198,0,0,0,65536,0,0,65536,0,0
|
47,470000,10000,0,0,218,57,18,4096,198,0,0,0,65536,0,0,65536,0,0
|
||||||
48,480000,10000,0,0,221,60,20,4096,350,0,0,0,65536,0,0,65536,0,0
|
48,480000,10000,0,0,221,60,20,4096,350,0,0,0,65536,0,0,65536,0,0
|
||||||
49,490000,10000,0,0,225,66,20,4096,528,0,0,0,65536,0,0,65536,0,0
|
49,490000,10000,0,0,225,66,20,4096,528,0,0,0,65536,0,0,65536,0,0
|
||||||
50,500000,10000,0,0,214,69,21,4096,694,0,0,0,65536,0,0,65536,0,0
|
50,500000,10000,0,0,214,69,22,4096,694,0,0,0,65536,0,0,65536,0,0
|
||||||
51,510000,10000,0,0,227,71,23,4096,883,0,0,0,65536,0,0,65536,0,0
|
51,510000,10000,0,0,227,71,23,4096,883,0,0,0,65536,0,0,65536,0,0
|
||||||
52,520000,10000,0,0,208,71,23,4096,1043,0,0,0,65536,0,0,65536,0,0
|
52,520000,10000,0,0,208,71,24,4096,1043,0,0,0,65536,0,0,65536,0,0
|
||||||
53,530000,10000,0,0,207,71,25,4096,1202,0,0,0,65536,0,0,65536,0,0
|
53,530000,10000,0,0,207,71,25,4096,1202,0,0,0,65536,0,0,65536,0,0
|
||||||
54,540000,10000,0,0,200,71,26,4096,1319,0,0,0,65536,0,0,65536,0,0
|
54,540000,10000,0,0,200,71,26,4096,1319,0,0,0,65536,0,0,65536,0,0
|
||||||
55,550000,10000,0,0,205,72,27,4096,1464,0,0,0,65536,0,0,65536,0,0
|
55,550000,10000,0,0,205,72,27,4096,1464,0,0,0,65536,0,0,65536,0,0
|
||||||
56,560000,10000,0,0,211,73,27,4096,1620,0,0,0,65536,0,0,65536,0,0
|
56,560000,10000,0,0,211,73,27,4096,1620,0,0,0,65536,0,0,65536,0,0
|
||||||
57,570000,10000,0,0,193,80,28,4096,1712,0,0,0,65536,0,0,65536,0,0
|
57,570000,10000,0,0,193,80,29,4096,1712,0,0,0,65536,0,0,65536,0,0
|
||||||
58,580000,10000,0,0,185,4,61,4096,1757,0,0,0,65536,0,0,65536,0,0
|
58,580000,10000,0,0,185,4,61,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
59,590000,10000,0,0,81,7,32,4096,1757,0,0,0,65536,0,0,65536,0,0
|
59,590000,10000,0,0,81,7,32,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
60,600000,10000,0,0,52,10,28,4096,1757,0,0,0,65536,0,0,65536,0,0
|
60,600000,10000,0,0,52,10,28,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
@@ -72,39 +72,39 @@ tick_number,elapsed_ns,tick_interval_ns,cache_hits_delta,bucket_hits_delta,word_
|
|||||||
71,710000,10000,0,0,44,22,39,4096,1757,0,0,0,65536,0,0,65536,0,0
|
71,710000,10000,0,0,44,22,39,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
72,720000,10000,0,0,130,24,27,4096,1757,0,0,0,65536,0,0,65536,0,0
|
72,720000,10000,0,0,130,24,27,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
73,730000,10000,0,0,134,26,21,4096,1757,0,0,0,65536,0,0,65536,0,0
|
73,730000,10000,0,0,134,26,21,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
1,10000,18446744073708831616,0,0,117,4,4,4096,0,0,4895412794951728796,7,65536,0,0,65536,0,0
|
1,10000,18446744073708831616,0,0,117,4,4,4096,0,0,4895412794951728796,8,65536,0,0,65536,0,0
|
||||||
2,20000,10000,0,0,78,10,7,4096,0,0,0,8,65536,0,0,65536,0,0
|
2,20000,10000,0,0,78,10,7,4096,0,0,0,10,65536,0,0,65536,0,0
|
||||||
3,30000,10000,0,0,101,13,7,4096,0,0,0,10,65536,0,0,65536,0,0
|
3,30000,10000,0,0,101,13,7,4096,0,0,0,12,65536,0,0,65536,0,0
|
||||||
4,40000,10000,0,0,63,19,8,4096,0,0,0,11,65536,0,0,65536,0,0
|
4,40000,10000,0,0,63,19,8,4096,0,0,0,13,65536,0,0,65536,0,0
|
||||||
5,50000,10000,0,0,92,25,8,4096,2,0,0,13,65536,0,0,65536,0,0
|
5,50000,10000,0,0,92,25,8,4096,2,0,0,15,65536,0,0,65536,0,0
|
||||||
6,60000,10000,0,0,64,27,8,4096,2,0,0,17,65536,0,0,65536,0,0
|
6,60000,10000,0,0,64,27,8,4096,2,0,0,17,65536,0,0,65536,0,0
|
||||||
7,70000,10000,0,0,228,32,8,4096,210,0,0,22,65536,0,0,65536,0,0
|
7,70000,10000,0,0,228,32,8,4096,210,0,0,21,65536,0,0,65536,0,0
|
||||||
8,80000,10000,0,0,256,34,9,4096,466,0,0,22,65536,0,0,65536,0,0
|
8,80000,10000,0,0,256,34,9,4096,466,0,0,22,65536,0,0,65536,0,0
|
||||||
9,90000,10000,0,0,256,36,10,4096,722,0,0,23,65536,0,0,65536,0,0
|
9,90000,10000,0,0,256,36,10,4096,722,0,0,22,65536,0,0,65536,0,0
|
||||||
10,100000,10000,0,0,256,36,11,4096,978,0,0,23,65536,0,0,65536,0,0
|
10,100000,10000,0,0,256,36,11,4096,978,0,0,23,65536,0,0,65536,0,0
|
||||||
11,110000,10000,0,0,256,36,11,4096,1234,0,0,24,65536,0,0,65536,0,0
|
11,110000,10000,0,0,256,36,11,4096,1234,0,0,23,65536,0,0,65536,0,0
|
||||||
12,120000,10000,0,0,256,36,12,4096,1490,0,0,25,65536,0,0,65536,0,0
|
12,120000,10000,0,0,256,36,12,4096,1490,0,0,24,65536,0,0,65536,0,0
|
||||||
13,130000,10000,0,0,256,37,12,4096,1746,0,0,25,65536,0,0,65536,0,0
|
13,130000,10000,0,0,256,37,12,4096,1746,0,0,24,65536,0,0,65536,0,0
|
||||||
14,140000,10000,0,0,230,39,12,4096,1949,0,0,31,65536,0,0,65536,0,0
|
14,140000,10000,0,0,230,39,12,4096,1949,0,0,26,65536,0,0,65536,0,0
|
||||||
15,150000,10000,0,0,256,39,13,4096,2204,0,0,31,65536,0,0,65536,0,0
|
15,150000,10000,0,0,256,39,13,4096,2204,0,0,27,65536,0,0,65536,0,0
|
||||||
16,160000,10000,0,0,256,39,14,4096,2459,0,0,32,65536,0,0,65536,0,0
|
16,160000,10000,0,0,256,39,14,4096,2459,0,0,27,65536,0,0,65536,0,0
|
||||||
17,170000,10000,0,0,256,39,15,4096,2713,0,0,34,65536,0,0,65536,0,0
|
17,170000,10000,0,0,256,39,15,4096,2713,0,0,29,65536,0,0,65536,0,0
|
||||||
18,180000,10000,0,0,256,39,15,4096,2969,0,0,35,65536,0,0,65536,0,0
|
18,180000,10000,0,0,256,39,15,4096,2969,0,0,29,65536,0,0,65536,0,0
|
||||||
19,190000,10000,0,0,256,39,16,4096,3224,0,0,37,65536,0,1,65536,0,0
|
19,190000,10000,0,0,256,39,16,4096,3224,0,0,31,65536,0,1,65536,0,0
|
||||||
20,200000,10000,0,0,256,41,17,4096,3480,0,0,38,65536,0,1,65536,0,0
|
20,200000,10000,0,0,256,41,17,4096,3480,0,0,31,65536,0,1,65536,0,0
|
||||||
21,210000,10000,0,0,256,41,17,4096,3736,0,0,38,65536,0,1,65536,0,0
|
21,210000,10000,0,0,256,41,17,4096,3736,0,0,32,65536,0,1,65536,0,0
|
||||||
22,220000,10000,0,0,256,41,18,4096,3992,0,0,39,65536,0,1,65536,0,0
|
22,220000,10000,0,0,256,41,18,4096,3992,0,0,32,65536,0,1,65536,0,0
|
||||||
23,230000,10000,0,0,256,41,19,4096,4096,0,0,40,65536,0,1,65536,0,0
|
23,230000,10000,0,0,256,41,19,4096,4096,0,0,34,65536,0,1,65536,0,0
|
||||||
24,240000,10000,0,0,256,41,20,4096,4096,0,0,41,65536,0,1,65536,0,0
|
24,240000,10000,0,0,256,41,20,4096,4096,0,0,34,65536,0,1,65536,0,0
|
||||||
25,250000,10000,0,0,256,43,20,2048,2048,0,0,42,65536,0,1,65536,0,0
|
25,250000,10000,0,0,256,43,20,2048,2048,0,0,35,65536,0,1,65536,0,0
|
||||||
26,260000,10000,0,0,256,45,21,2048,2048,0,0,42,65536,0,1,65536,0,0
|
26,260000,10000,0,0,256,45,21,2048,2048,0,0,36,65536,0,1,65536,0,0
|
||||||
27,270000,10000,0,0,256,45,22,1024,1024,0,0,44,65536,0,1,65536,0,0
|
27,270000,10000,0,0,256,45,22,1024,1024,0,0,36,65536,0,1,65536,0,0
|
||||||
28,280000,10000,0,0,256,45,23,1024,1024,0,0,45,65536,0,1,65536,0,0
|
28,280000,10000,0,0,256,45,23,1024,1024,0,0,37,65536,0,1,65536,0,0
|
||||||
29,290000,10000,0,0,256,45,24,512,512,0,0,46,65536,0,1,65536,0,0
|
29,290000,10000,0,0,256,45,24,512,512,0,0,38,65536,0,1,65536,0,0
|
||||||
30,300000,10000,0,0,256,45,24,512,512,0,0,47,65536,0,1,65536,0,0
|
30,300000,10000,0,0,256,45,24,512,512,0,0,38,65536,0,1,65536,0,0
|
||||||
31,310000,10000,0,0,256,45,25,256,256,0,0,47,65536,0,1,65536,0,0
|
31,310000,10000,0,0,256,45,25,256,256,0,0,39,65536,0,1,65536,0,0
|
||||||
32,320000,10000,0,0,255,45,26,256,256,0,0,50,65536,0,1,65536,0,0
|
32,320000,10000,0,0,255,45,26,256,256,0,0,41,65536,0,1,65536,0,0
|
||||||
33,330000,10000,0,0,256,45,27,256,256,0,0,50,65536,0,1,65536,0,0
|
33,330000,10000,0,0,256,45,27,256,256,0,0,41,65536,0,1,65536,0,0
|
||||||
34,340000,10000,0,0,256,45,27,256,256,0,0,52,65536,0,1,65536,0,0
|
34,340000,10000,0,0,256,45,27,256,256,0,0,43,65536,0,1,65536,0,0
|
||||||
35,350000,10000,0,0,256,45,28,256,256,0,0,53,65536,0,1,65536,0,0
|
35,350000,10000,0,0,256,45,28,256,256,0,0,44,65536,0,1,65536,0,0
|
||||||
36,360000,10000,0,0,256,45,29,256,256,0,0,54,65536,0,1,65536,0,0
|
36,360000,10000,0,0,256,45,29,256,256,0,0,44,65536,0,1,65536,0,0
|
||||||
|
|||||||
|
@@ -0,0 +1,110 @@
|
|||||||
|
tick_number,elapsed_ns,tick_interval_ns,cache_hits_delta,bucket_hits_delta,word_executions_delta,hot_word_count,avg_word_heat_q48,window_width,actual_window_size,predicted_label_hits,jitter_bits,apic_ticks,time_trust_q48,variance_q48,vm_call_depth_max,hera_heat_q48,hermes_heat_q48,artemis_heat_q48
|
||||||
|
1,10000,10000,0,0,183,4,45,731,731,0,0,0,65536,0,0,65536,0,0
|
||||||
|
2,20000,10000,0,0,173,5,44,582,582,0,0,0,65536,0,0,65536,0,0
|
||||||
|
3,30000,10000,0,0,184,6,60,582,582,0,0,0,65536,0,0,65536,0,0
|
||||||
|
4,40000,10000,0,0,174,8,71,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
|
5,50000,10000,0,0,150,9,78,582,582,0,0,0,65536,0,0,65536,0,0
|
||||||
|
6,60000,10000,0,0,159,11,73,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
|
7,70000,10000,0,0,188,15,71,685,685,0,0,0,65536,0,0,65536,0,0
|
||||||
|
8,80000,10000,0,0,214,16,83,685,685,0,0,0,65536,0,0,65536,0,0
|
||||||
|
9,90000,10000,0,0,216,19,82,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
|
10,100000,10000,0,0,222,21,84,567,567,0,0,0,65536,0,0,65536,0,0
|
||||||
|
11,110000,10000,0,0,207,23,86,731,731,0,0,0,65536,0,0,65536,0,0
|
||||||
|
12,120000,10000,0,0,189,26,83,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
|
13,130000,10000,0,0,221,28,80,731,731,0,0,0,65536,0,0,65536,0,0
|
||||||
|
14,140000,10000,0,0,204,29,83,685,685,0,0,0,65536,0,0,65536,0,0
|
||||||
|
15,150000,10000,0,0,203,30,82,731,731,0,0,0,65536,0,0,65536,0,0
|
||||||
|
16,160000,10000,0,0,201,32,83,567,567,0,0,0,65536,0,0,65536,0,0
|
||||||
|
17,170000,10000,0,0,190,34,86,731,731,0,0,0,65536,0,0,65536,0,0
|
||||||
|
18,180000,10000,0,0,170,35,73,582,582,0,0,0,65536,0,0,65536,0,0
|
||||||
|
19,190000,10000,0,0,154,35,40,731,731,0,0,0,65536,0,0,65536,0,0
|
||||||
|
20,200000,10000,0,0,154,35,38,567,567,0,0,0,65536,0,0,65536,0,0
|
||||||
|
21,210000,10000,0,0,153,38,37,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
|
22,220000,10000,0,0,167,38,38,582,582,0,0,0,65536,0,0,65536,0,0
|
||||||
|
23,230000,10000,0,0,176,11,37,685,685,0,0,0,65536,0,0,65536,0,0
|
||||||
|
24,240000,10000,0,0,175,10,25,731,731,0,0,0,65536,0,0,65536,0,0
|
||||||
|
25,250000,10000,0,0,196,11,23,731,731,0,0,0,65536,0,0,65536,0,0
|
||||||
|
26,260000,10000,0,0,192,14,24,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
|
27,270000,10000,0,0,158,16,30,685,685,0,0,0,65536,0,0,65536,0,0
|
||||||
|
28,280000,10000,0,0,158,17,23,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
|
29,290000,10000,0,0,164,17,27,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
|
30,300000,10000,0,0,154,18,26,685,685,0,0,0,65536,0,0,65536,0,0
|
||||||
|
31,310000,10000,0,0,172,6,25,582,582,0,0,0,65536,0,0,65536,0,0
|
||||||
|
32,320000,10000,0,0,180,9,22,567,567,0,0,0,65536,0,0,65536,0,0
|
||||||
|
33,330000,10000,0,0,145,11,29,567,567,0,0,0,65536,0,0,65536,0,0
|
||||||
|
34,340000,10000,0,0,203,14,30,582,582,0,0,0,65536,0,0,65536,0,0
|
||||||
|
35,350000,10000,0,0,154,16,36,731,731,0,0,0,65536,0,0,65536,0,0
|
||||||
|
36,360000,10000,0,0,144,18,32,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
|
37,370000,10000,0,0,144,18,29,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
|
38,380000,10000,0,0,132,18,28,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
|
39,390000,10000,0,0,180,18,24,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
|
40,400000,10000,0,0,220,23,20,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||||
|
41,410000,10000,0,0,215,25,19,4096,24,0,0,0,65536,0,0,65536,0,0
|
||||||
|
42,420000,10000,0,0,208,32,20,4096,24,0,0,0,65536,0,0,65536,0,0
|
||||||
|
43,430000,10000,0,0,177,36,19,4096,24,0,0,0,65536,0,0,65536,0,0
|
||||||
|
44,440000,10000,0,0,199,42,20,4096,24,0,0,0,65536,0,0,65536,0,0
|
||||||
|
45,450000,10000,0,0,223,47,19,4096,30,0,0,0,65536,0,0,65536,0,0
|
||||||
|
46,460000,10000,0,0,202,50,17,4096,67,0,0,0,65536,0,0,65536,0,0
|
||||||
|
47,470000,10000,0,0,218,57,18,4096,198,0,0,0,65536,0,0,65536,0,0
|
||||||
|
48,480000,10000,0,0,221,60,20,4096,350,0,0,0,65536,0,0,65536,0,0
|
||||||
|
49,490000,10000,0,0,225,66,20,4096,528,0,0,0,65536,0,0,65536,0,0
|
||||||
|
50,500000,10000,0,0,214,69,22,4096,694,0,0,0,65536,0,0,65536,0,0
|
||||||
|
51,510000,10000,0,0,227,71,23,4096,883,0,0,0,65536,0,0,65536,0,0
|
||||||
|
52,520000,10000,0,0,208,71,24,4096,1043,0,0,0,65536,0,0,65536,0,0
|
||||||
|
53,530000,10000,0,0,207,71,25,4096,1202,0,0,0,65536,0,0,65536,0,0
|
||||||
|
54,540000,10000,0,0,200,71,26,4096,1319,0,0,0,65536,0,0,65536,0,0
|
||||||
|
55,550000,10000,0,0,205,72,27,4096,1464,0,0,0,65536,0,0,65536,0,0
|
||||||
|
56,560000,10000,0,0,211,73,27,4096,1620,0,0,0,65536,0,0,65536,0,0
|
||||||
|
57,570000,10000,0,0,193,80,29,4096,1712,0,0,0,65536,0,0,65536,0,0
|
||||||
|
58,580000,10000,0,0,185,4,61,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
59,590000,10000,0,0,81,7,32,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
60,600000,10000,0,0,52,10,28,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
61,610000,10000,0,0,63,17,25,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
62,620000,10000,0,0,85,19,24,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
63,630000,10000,0,0,68,20,23,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
64,640000,10000,0,0,39,20,23,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
65,650000,10000,0,0,45,20,25,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
66,660000,10000,0,0,42,20,29,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
67,670000,10000,0,0,47,20,31,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
68,680000,10000,0,0,43,20,34,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
69,690000,10000,0,0,48,20,35,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
70,700000,10000,0,0,48,21,38,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
71,710000,10000,0,0,44,22,39,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
72,720000,10000,0,0,130,24,27,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
73,730000,10000,0,0,134,26,21,4096,1757,0,0,0,65536,0,0,65536,0,0
|
||||||
|
1,10000,18446744073708831616,0,0,117,4,4,4096,0,0,4895412794951728796,8,65536,0,0,65536,0,0
|
||||||
|
2,20000,10000,0,0,78,10,7,4096,0,0,0,10,65536,0,0,65536,0,0
|
||||||
|
3,30000,10000,0,0,101,13,7,4096,0,0,0,12,65536,0,0,65536,0,0
|
||||||
|
4,40000,10000,0,0,63,19,8,4096,0,0,0,13,65536,0,0,65536,0,0
|
||||||
|
5,50000,10000,0,0,92,25,8,4096,2,0,0,15,65536,0,0,65536,0,0
|
||||||
|
6,60000,10000,0,0,64,27,8,4096,2,0,0,17,65536,0,0,65536,0,0
|
||||||
|
7,70000,10000,0,0,228,32,8,4096,210,0,0,21,65536,0,0,65536,0,0
|
||||||
|
8,80000,10000,0,0,256,34,9,4096,466,0,0,22,65536,0,0,65536,0,0
|
||||||
|
9,90000,10000,0,0,256,36,10,4096,722,0,0,22,65536,0,0,65536,0,0
|
||||||
|
10,100000,10000,0,0,256,36,11,4096,978,0,0,23,65536,0,0,65536,0,0
|
||||||
|
11,110000,10000,0,0,256,36,11,4096,1234,0,0,23,65536,0,0,65536,0,0
|
||||||
|
12,120000,10000,0,0,256,36,12,4096,1490,0,0,24,65536,0,0,65536,0,0
|
||||||
|
13,130000,10000,0,0,256,37,12,4096,1746,0,0,24,65536,0,0,65536,0,0
|
||||||
|
14,140000,10000,0,0,230,39,12,4096,1949,0,0,26,65536,0,0,65536,0,0
|
||||||
|
15,150000,10000,0,0,256,39,13,4096,2204,0,0,27,65536,0,0,65536,0,0
|
||||||
|
16,160000,10000,0,0,256,39,14,4096,2459,0,0,27,65536,0,0,65536,0,0
|
||||||
|
17,170000,10000,0,0,256,39,15,4096,2713,0,0,29,65536,0,0,65536,0,0
|
||||||
|
18,180000,10000,0,0,256,39,15,4096,2969,0,0,29,65536,0,0,65536,0,0
|
||||||
|
19,190000,10000,0,0,256,39,16,4096,3224,0,0,31,65536,0,1,65536,0,0
|
||||||
|
20,200000,10000,0,0,256,41,17,4096,3480,0,0,31,65536,0,1,65536,0,0
|
||||||
|
21,210000,10000,0,0,256,41,17,4096,3736,0,0,32,65536,0,1,65536,0,0
|
||||||
|
22,220000,10000,0,0,256,41,18,4096,3992,0,0,32,65536,0,1,65536,0,0
|
||||||
|
23,230000,10000,0,0,256,41,19,4096,4096,0,0,34,65536,0,1,65536,0,0
|
||||||
|
24,240000,10000,0,0,256,41,20,4096,4096,0,0,34,65536,0,1,65536,0,0
|
||||||
|
25,250000,10000,0,0,256,43,20,2048,2048,0,0,35,65536,0,1,65536,0,0
|
||||||
|
26,260000,10000,0,0,256,45,21,2048,2048,0,0,36,65536,0,1,65536,0,0
|
||||||
|
27,270000,10000,0,0,256,45,22,1024,1024,0,0,36,65536,0,1,65536,0,0
|
||||||
|
28,280000,10000,0,0,256,45,23,1024,1024,0,0,37,65536,0,1,65536,0,0
|
||||||
|
29,290000,10000,0,0,256,45,24,512,512,0,0,38,65536,0,1,65536,0,0
|
||||||
|
30,300000,10000,0,0,256,45,24,512,512,0,0,38,65536,0,1,65536,0,0
|
||||||
|
31,310000,10000,0,0,256,45,25,256,256,0,0,39,65536,0,1,65536,0,0
|
||||||
|
32,320000,10000,0,0,255,45,26,256,256,0,0,41,65536,0,1,65536,0,0
|
||||||
|
33,330000,10000,0,0,256,45,27,256,256,0,0,41,65536,0,1,65536,0,0
|
||||||
|
34,340000,10000,0,0,256,45,27,256,256,0,0,43,65536,0,1,65536,0,0
|
||||||
|
35,350000,10000,0,0,256,45,28,256,256,0,0,44,65536,0,1,65536,0,0
|
||||||
|
36,360000,10000,0,0,256,45,29,256,256,0,0,44,65536,0,1,65536,0,0
|
||||||
|
@@ -70,7 +70,7 @@
|
|||||||
#define STARFORTH_CONFIG_HEARTBEAT_THREAD_ENABLED_DEFAULT 1
|
#define STARFORTH_CONFIG_HEARTBEAT_THREAD_ENABLED_DEFAULT 1
|
||||||
#define STARFORTH_CONFIG_HEARTBEAT_TICK_NS_DEFAULT 10000ULL
|
#define STARFORTH_CONFIG_HEARTBEAT_TICK_NS_DEFAULT 10000ULL
|
||||||
#define STARFORTH_CONFIG_HEARTBEAT_INFERENCE_FREQUENCY_DEFAULT 1000
|
#define STARFORTH_CONFIG_HEARTBEAT_INFERENCE_FREQUENCY_DEFAULT 1000
|
||||||
#define STARFORTH_CONFIG_STADIUM_MAX_VM_COUNT_DEFAULT 4
|
#define STARFORTH_CONFIG_STADIUM_VM_MEMORY_PERCENT_DEFAULT 50
|
||||||
#define STARFORTH_CONFIG_STADIUM_CONTAINS_DEPTH_MAX_DEFAULT 5
|
#define STARFORTH_CONFIG_STADIUM_CONTAINS_DEPTH_MAX_DEFAULT 5
|
||||||
#define STARFORTH_CONFIG_STADIUM_CAPACITY_TICK_DEFAULT 1000
|
#define STARFORTH_CONFIG_STADIUM_CAPACITY_TICK_DEFAULT 1000
|
||||||
#define STARFORTH_CONFIG_STADIUM_MEMORY_PERCENT_DEFAULT 1
|
#define STARFORTH_CONFIG_STADIUM_MEMORY_PERCENT_DEFAULT 1
|
||||||
@@ -161,8 +161,8 @@
|
|||||||
#define HEARTBEAT_INFERENCE_FREQUENCY STARFORTH_CONFIG_HEARTBEAT_INFERENCE_FREQUENCY_DEFAULT
|
#define HEARTBEAT_INFERENCE_FREQUENCY STARFORTH_CONFIG_HEARTBEAT_INFERENCE_FREQUENCY_DEFAULT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef STADIUM_MAX_VM_COUNT
|
#ifndef STADIUM_VM_MEMORY_PERCENT
|
||||||
#define STADIUM_MAX_VM_COUNT STARFORTH_CONFIG_STADIUM_MAX_VM_COUNT_DEFAULT
|
#define STADIUM_VM_MEMORY_PERCENT STARFORTH_CONFIG_STADIUM_VM_MEMORY_PERCENT_DEFAULT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef STADIUM_CONTAINS_DEPTH_MAX
|
#ifndef STADIUM_CONTAINS_DEPTH_MAX
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ typedef enum {
|
|||||||
CAPSULE_RUN_ERR_EXEC_FAIL, /* Execution failed */
|
CAPSULE_RUN_ERR_EXEC_FAIL, /* Execution failed */
|
||||||
CAPSULE_RUN_ERR_HASH_MISMATCH, /* Post-run hash mismatch */
|
CAPSULE_RUN_ERR_HASH_MISMATCH, /* Post-run hash mismatch */
|
||||||
CAPSULE_RUN_ERR_STILLBORN, /* VM birth failed */
|
CAPSULE_RUN_ERR_STILLBORN, /* VM birth failed */
|
||||||
CAPSULE_RUN_ERR_FLEET_FULL, /* Outer Stadium at STADIUM_MAX_VM_COUNT (FABRIC.md item 1.5/2.2) */
|
CAPSULE_RUN_ERR_FLEET_FULL, /* Outer Stadium at stadium_max_vm_count() (FABRIC.md item 1.5/2.2) */
|
||||||
} CapsuleRunResult;
|
} CapsuleRunResult;
|
||||||
|
|
||||||
/*===========================================================================
|
/*===========================================================================
|
||||||
|
|||||||
@@ -118,40 +118,53 @@ typedef char stadium_contains_depth_configured_check[(STADIUM_CONTAINS_DEPTH_MAX
|
|||||||
typedef char stadium_capacity_tick_configured_check[(STADIUM_CAPACITY_TICK > 0) ? 1 : -1];
|
typedef char stadium_capacity_tick_configured_check[(STADIUM_CAPACITY_TICK > 0) ? 1 : -1];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Item 3.7: the per-cell owner array stores a quota-slot index in a single
|
* Item 3.7, revised 2026-08-15: the per-cell owner array stores a quota-slot
|
||||||
* uint8_t, so STADIUM_MAX_VM_COUNT must fit in one byte. Default 4, so this
|
* index. The VM population bound is no longer a compile-time constant (see
|
||||||
* holds by a wide margin -- checked because it is depended on, not because
|
* stadium_max_vm_count() below), so this can no longer be a compile-time
|
||||||
* it is expected to fail.
|
* assert -- the owner element type is now uint16_t (65535 slots of
|
||||||
|
* headroom), and stadium_boot_init() itself clamps the computed count to
|
||||||
|
* that range at runtime, logging if it ever has to.
|
||||||
*/
|
*/
|
||||||
typedef char stadium_max_vm_count_fits_owner_byte_check[(STADIUM_MAX_VM_COUNT <= 255) ? 1 : -1];
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* stadium_boot_init - Boot-time allocation (FABRIC.md item 3.2, §17.6 position
|
* stadium_boot_init - Boot-time allocation (FABRIC.md item 3.2, §17.6 position
|
||||||
* (b)). Sizes the global cell array from the memory budget actually observed
|
* (b)). Sizes the global cell array from the memory budget actually observed
|
||||||
* at boot -- STADIUM_MEMORY_PERCENT of pmm_get_stats().free_bytes at the
|
* at boot -- STADIUM_MEMORY_PERCENT of kmalloc_get_stats().free_bytes at the
|
||||||
* point of the call, rounded down to whole STADIUM_CELL_BYTES cells -- rather
|
* point of the call, rounded down to whole STADIUM_CELL_BYTES cells -- rather
|
||||||
* than a hardcoded count. Also allocates the header/continuation discriminator
|
* than a hardcoded count. (Corrected 2026-08-15 from pmm_get_stats(): PMM's
|
||||||
* bitmap item 3.1 declared but did not allocate: one bit per cell, bit set
|
* free-byte figure reflects physical pages not yet handed to any subsystem,
|
||||||
* means the cell at that index is a patron header, clear means continuation
|
* but kmalloc_init() (M6) already carved its own fixed-size heap out of PMM
|
||||||
* or not yet in use. Both are kmalloc'd (freestanding kernel, no separate
|
* before this ever runs, and every allocation in this function actually
|
||||||
* PMM-backed region needed for this) and explicitly zero-filled, since
|
* draws from that kmalloc heap, not raw PMM -- pmm_get_stats() was budgeting
|
||||||
* kmalloc does not zero.
|
* against a pool nothing here actually allocates from.) Also computes the
|
||||||
|
* outer Stadium's VM population bound the same way, from the kmalloc heap's
|
||||||
|
* *remaining* free bytes after the cell array's own allocation: see
|
||||||
|
* stadium_max_vm_count() below. Also allocates the header/continuation
|
||||||
|
* discriminator bitmap item 3.1 declared but did not allocate: one bit per
|
||||||
|
* cell, bit set means the cell at that index is a patron header, clear means
|
||||||
|
* continuation or not yet in use. Both are kmalloc'd (freestanding kernel,
|
||||||
|
* no separate PMM-backed region needed for this) and explicitly zero-filled,
|
||||||
|
* since kmalloc does not zero.
|
||||||
*
|
*
|
||||||
* (Item 3.7) Also allocates a per-cell owner byte array (which VM's quota a
|
* (Item 3.7) Also allocates a per-cell owner array (which VM's quota a cell
|
||||||
* cell belongs to) and chains every cell into a single free list, in
|
* belongs to; uint16_t as of 2026-08-15, see the note above) and chains
|
||||||
* ascending index order, granted in full to vm_id 0 (Hera) -- the only VM
|
* every cell into a single free list, in ascending index order, granted in
|
||||||
* that exists (item 0.1). Ascending order guarantees the first-ever
|
* full to vm_id 0 (Hera) -- the only VM that exists (item 0.1). Ascending
|
||||||
* admission pops cell 0, preserving item 3.6's "Hera is patron zero"
|
* order guarantees the first-ever admission pops cell 0, preserving item
|
||||||
* invariant once real birth-wiring calls stadium_admit() for the first
|
* 3.6's "Hera is patron zero" invariant once real birth-wiring calls
|
||||||
* time. The free-list next-pointer reuses each cell's own `link` field
|
* stadium_admit() for the first time. The free-list next-pointer reuses
|
||||||
* while unresident -- a repurposing of documented-but-unspecified storage,
|
* each cell's own `link` field while unresident -- a repurposing of
|
||||||
* not a header change; see stadium_admit()'s doc for why this doesn't
|
* documented-but-unspecified storage, not a header change; see
|
||||||
* answer the separate, still-open continuation-chain question.
|
* stadium_admit()'s doc for why this doesn't answer the separate,
|
||||||
|
* still-open continuation-chain question.
|
||||||
|
*
|
||||||
|
* Also allocates the VM quota array (stadium_quotas), sized to the
|
||||||
|
* computed stadium_max_vm_count() rather than a compile-time bound.
|
||||||
*
|
*
|
||||||
* Must be called after M6 (kmalloc_init) and before any VM is born (§6). Does
|
* Must be called after M6 (kmalloc_init) and before any VM is born (§6). Does
|
||||||
* not halt boot on failure -- nothing downstream consumes the Stadium yet.
|
* not halt boot on failure -- nothing downstream consumes the Stadium yet.
|
||||||
*
|
*
|
||||||
* @return 0 on success, -1 if kmalloc failed for any of the three allocations.
|
* @return 0 on success, -1 if kmalloc failed for any of the four allocations.
|
||||||
*/
|
*/
|
||||||
int stadium_boot_init(void);
|
int stadium_boot_init(void);
|
||||||
|
|
||||||
@@ -161,6 +174,15 @@ int stadium_is_initialized(void);
|
|||||||
/* stadium_cell_count - Number of cells in the array, 0 if not initialized. */
|
/* stadium_cell_count - Number of cells in the array, 0 if not initialized. */
|
||||||
size_t stadium_cell_count(void);
|
size_t stadium_cell_count(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* stadium_max_vm_count - The outer Stadium's VM population bound, computed
|
||||||
|
* at stadium_boot_init() from the kmalloc heap's remaining free bytes
|
||||||
|
* (replaces the old compile-time STADIUM_MAX_VM_COUNT, 2026-08-15 -- see
|
||||||
|
* stadium_boot_init()'s own doc). 0 if not initialized. capsule_birth.c's
|
||||||
|
* birth gate reads this instead of a macro.
|
||||||
|
*/
|
||||||
|
size_t stadium_max_vm_count(void);
|
||||||
|
|
||||||
/* stadium_cells - Pointer to the cell array, NULL if not initialized. */
|
/* stadium_cells - Pointer to the cell array, NULL if not initialized. */
|
||||||
StadiumCell *stadium_cells(void);
|
StadiumCell *stadium_cells(void);
|
||||||
|
|
||||||
@@ -309,7 +331,7 @@ uint64_t stadium_reservoir_peek(VMUuid vm_id);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* stadium_quota_slot_for_vm - Read-only: vm_id's quota slot index (0 to
|
* stadium_quota_slot_for_vm - Read-only: vm_id's quota slot index (0 to
|
||||||
* STADIUM_MAX_VM_COUNT-1), for callers outside stadium.c that need to key
|
* stadium_max_vm_count()-1), for callers outside stadium.c that need to key
|
||||||
* their own per-VM state the same way stadium.c's internal arrays already
|
* their own per-VM state the same way stadium.c's internal arrays already
|
||||||
* do (FABRIC.md §25.5 item 4.2 -- stadium_words.c's word_id -> cell_index
|
* do (FABRIC.md §25.5 item 4.2 -- stadium_words.c's word_id -> cell_index
|
||||||
* map needs this to stop colliding across VMs; word_id is scoped per-VM,
|
* map needs this to stop colliding across VMs; word_id is scoped per-VM,
|
||||||
@@ -366,10 +388,14 @@ int stadium_evict(size_t cell_index);
|
|||||||
/*
|
/*
|
||||||
* StadiumVMQuota - per-VM ownership of a subset of the global cell array
|
* StadiumVMQuota - per-VM ownership of a subset of the global cell array
|
||||||
* (FABRIC.md §22.3, item 3.7: "each VM holds its own free-list head index
|
* (FABRIC.md §22.3, item 3.7: "each VM holds its own free-list head index
|
||||||
* into the global array"). A small table, linearly searched by vm_id -- a
|
* into the global array"). Linearly searched by vm_id -- a VMUuid (item 3.8)
|
||||||
* VMUuid (item 3.8) can't be used as a direct array index anyway, and
|
* can't be used as a direct array index anyway. Was a small, compile-time-
|
||||||
* STADIUM_MAX_VM_COUNT is small enough (default 4) that a linear scan costs
|
* bounded table (linear scan "costs nothing" at the old default of 4);
|
||||||
* nothing. Not exposed outside stadium.c: nothing outside needs to inspect
|
* since 2026-08-15 the table is sized at boot from stadium_max_vm_count()
|
||||||
|
* and could genuinely be large, so this scan is no longer assumed free --
|
||||||
|
* flagged here rather than silently carried forward as still-obviously-fine,
|
||||||
|
* though no algorithmic change was made in this pass. Not exposed outside
|
||||||
|
* stadium.c: nothing outside needs to inspect
|
||||||
* quota state directly yet. Slot emptiness is tracked by an internal
|
* quota state directly yet. Slot emptiness is tracked by an internal
|
||||||
* `in_use` flag, not a vm_id sentinel value -- there is no unused vm_id bit
|
* `in_use` flag, not a vm_id sentinel value -- there is no unused vm_id bit
|
||||||
* pattern to reserve for it.
|
* pattern to reserve for it.
|
||||||
@@ -449,7 +475,7 @@ size_t stadium_admit(VMUuid vm_id, const StadiumPatronHeader *candidate);
|
|||||||
* REFUSES (returns -1, does not crash) if: the Stadium is not initialized;
|
* REFUSES (returns -1, does not crash) if: the Stadium is not initialized;
|
||||||
* new_vm_id already holds a quota; from_vm_id holds no quota; from_vm_id's
|
* new_vm_id already holds a quota; from_vm_id holds no quota; from_vm_id's
|
||||||
* free list has fewer than 2 cells (nothing to split); or no empty quota
|
* free list has fewer than 2 cells (nothing to split); or no empty quota
|
||||||
* slot remains (STADIUM_MAX_VM_COUNT exhausted).
|
* slot remains (stadium_max_vm_count() exhausted).
|
||||||
*
|
*
|
||||||
* @param new_vm_id The VM receiving a fresh quota. Must not already have one.
|
* @param new_vm_id The VM receiving a fresh quota. Must not already have one.
|
||||||
* @param from_vm_id The VM whose free list is split. Must already hold a quota.
|
* @param from_vm_id The VM whose free list is split. Must already hold a quota.
|
||||||
|
|||||||
@@ -47,11 +47,15 @@
|
|||||||
#include "starkernel/vm_uuid.h"
|
#include "starkernel/vm_uuid.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* stadium_words_init - Zeroes the word_id -> cell_index map (DICTIONARY_SIZE
|
* stadium_words_init - Allocates and zeroes the word_id -> cell_index map
|
||||||
* entries per VM quota slot, STADIUM_MAX_VM_COUNT slots, static -- no
|
* (DICTIONARY_SIZE entries per VM quota slot, stadium_max_vm_count() slots,
|
||||||
* allocation). Must be called after stadium_boot_init() and
|
* kmalloc'd -- was a flat static array before 2026-08-15, when the VM count
|
||||||
* stadium_birth_hera(), before any word ever dispatches. Safe to call again
|
* bound became RAM-derived rather than a compile-time constant). Must be
|
||||||
* (re-zeroes for every slot); nothing does today.
|
* called after stadium_boot_init() and stadium_birth_hera(), before any word
|
||||||
|
* ever dispatches. NOT safe to call twice -- unlike the old zero-only
|
||||||
|
* version, a second call would kmalloc a second set of tables and leak the
|
||||||
|
* first; guarded internally as a no-op if already initialized. Nothing
|
||||||
|
* calls it twice today.
|
||||||
*
|
*
|
||||||
* item 4.2 (FABRIC.md §25.5): the map is keyed by quota slot, not just
|
* item 4.2 (FABRIC.md §25.5): the map is keyed by quota slot, not just
|
||||||
* word_id -- word_id is assigned per-VM (vm->next_word_id), not globally
|
* word_id -- word_id is assigned per-VM (vm->next_word_id), not globally
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -34,7 +34,6 @@
|
|||||||
#include "starkernel/vm/stadium.h" /* item 4.1a -- stadium_grant_quota() */
|
#include "starkernel/vm/stadium.h" /* item 4.1a -- stadium_grant_quota() */
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#include "platform_alloc.h"
|
#include "platform_alloc.h"
|
||||||
#include "starforth_config.h" /* STADIUM_MAX_VM_COUNT */
|
|
||||||
|
|
||||||
/*===========================================================================
|
/*===========================================================================
|
||||||
* VM Execution Hooks
|
* VM Execution Hooks
|
||||||
@@ -451,7 +450,7 @@ CapsuleRunResult capsule_birth_baby(
|
|||||||
CapsuleValidateResult vr = capsule_validate(cap, arena, dir->arena_size, 1);
|
CapsuleValidateResult vr = capsule_validate(cap, arena, dir->arena_size, 1);
|
||||||
if (vr != CAPSULE_VALID) return CAPSULE_RUN_ERR_INVALID;
|
if (vr != CAPSULE_VALID) return CAPSULE_RUN_ERR_INVALID;
|
||||||
|
|
||||||
if (vm_registry_live_count() >= STADIUM_MAX_VM_COUNT) {
|
if (vm_registry_live_count() >= stadium_max_vm_count()) {
|
||||||
capsule_parity_log_birth_failed(vm_uuid_none(), cap->capsule_id,
|
capsule_parity_log_birth_failed(vm_uuid_none(), cap->capsule_id,
|
||||||
CAPSULE_RUN_ERR_FLEET_FULL, 0);
|
CAPSULE_RUN_ERR_FLEET_FULL, 0);
|
||||||
return CAPSULE_RUN_ERR_FLEET_FULL;
|
return CAPSULE_RUN_ERR_FLEET_FULL;
|
||||||
|
|||||||
+81
-32
@@ -39,12 +39,18 @@
|
|||||||
#include "starkernel/console.h"
|
#include "starkernel/console.h"
|
||||||
#include "starkernel/hal/hal.h"
|
#include "starkernel/hal/hal.h"
|
||||||
#include "starkernel/q48_16.h" /* Q48_ONE -- item 4.1's reservoir starts each VM's quota at 1.0 */
|
#include "starkernel/q48_16.h" /* Q48_ONE -- item 4.1's reservoir starts each VM's quota at 1.0 */
|
||||||
|
#include "vm.h" /* VM_MEMORY_SIZE -- the per-VM footprint stadium_max_vm_count() budgets against */
|
||||||
|
|
||||||
static StadiumCell *stadium_cell_array = (StadiumCell *)0;
|
static StadiumCell *stadium_cell_array = (StadiumCell *)0;
|
||||||
static uint8_t *stadium_bitmap = (uint8_t *)0;
|
static uint8_t *stadium_bitmap = (uint8_t *)0;
|
||||||
static uint8_t *stadium_owner = (uint8_t *)0;
|
static uint16_t *stadium_owner = (uint16_t *)0; /* widened from uint8_t
|
||||||
|
2026-08-15: the VM-count bound is no longer capped at
|
||||||
|
255 (see stadium_max_vm_count_val below), so a byte
|
||||||
|
could silently wrap. 65535 is ample headroom. */
|
||||||
static size_t stadium_ncells = 0;
|
static size_t stadium_ncells = 0;
|
||||||
static int stadium_initialized = 0;
|
static int stadium_initialized = 0;
|
||||||
|
static size_t stadium_max_vm_count_val = 0; /* computed at boot, see
|
||||||
|
stadium_boot_init() and stadium_max_vm_count() */
|
||||||
|
|
||||||
/* Sentinel for the header's `link` field while it is reused as a free-list
|
/* Sentinel for the header's `link` field while it is reused as a free-list
|
||||||
* next-pointer (item 3.7): link is uint32_t, but STADIUM_CELL_NONE is
|
* next-pointer (item 3.7): link is uint32_t, but STADIUM_CELL_NONE is
|
||||||
@@ -79,12 +85,15 @@ typedef struct {
|
|||||||
* checks the fleet sum. */
|
* checks the fleet sum. */
|
||||||
} StadiumVMQuota;
|
} StadiumVMQuota;
|
||||||
|
|
||||||
static StadiumVMQuota stadium_quotas[STADIUM_MAX_VM_COUNT];
|
/* kmalloc'd at stadium_boot_init() to stadium_max_vm_count_val entries,
|
||||||
|
* replacing the old static StadiumVMQuota stadium_quotas[STADIUM_MAX_VM_COUNT]
|
||||||
|
* (2026-08-15: the bound is computed from RAM, not a compile-time constant). */
|
||||||
|
static StadiumVMQuota *stadium_quotas = (StadiumVMQuota *)0;
|
||||||
|
|
||||||
/* Returns the quota slot index for vm_id, or -1 if none is granted. */
|
/* Returns the quota slot index for vm_id, or -1 if none is granted. */
|
||||||
static int quota_slot_for_vm(VMUuid vm_id) {
|
static int quota_slot_for_vm(VMUuid vm_id) {
|
||||||
int i;
|
size_t i;
|
||||||
for (i = 0; i < STADIUM_MAX_VM_COUNT; i++) {
|
for (i = 0; i < stadium_max_vm_count_val; i++) {
|
||||||
if (stadium_quotas[i].in_use && vm_uuid_equal(stadium_quotas[i].vm_id, vm_id)) return i;
|
if (stadium_quotas[i].in_use && vm_uuid_equal(stadium_quotas[i].vm_id, vm_id)) return i;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
@@ -107,8 +116,14 @@ static void console_put_u64(uint64_t v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int stadium_boot_init(void) {
|
int stadium_boot_init(void) {
|
||||||
pmm_stats_t pmm = pmm_get_stats();
|
/* Budgeted from kmalloc_get_stats(), not pmm_get_stats() (corrected
|
||||||
uint64_t budget_bytes = (pmm.free_bytes * (uint64_t)STADIUM_MEMORY_PERCENT) / 100u;
|
* 2026-08-15 -- see this function's doc in stadium.h): kmalloc_init()
|
||||||
|
* (M6) already carved its own fixed-size heap out of PMM before this
|
||||||
|
* ever runs, and every allocation below draws from that heap, not raw
|
||||||
|
* PMM, so PMM's own free-byte figure was the wrong pool to budget
|
||||||
|
* against. */
|
||||||
|
kmalloc_stats_t kstats = kmalloc_get_stats();
|
||||||
|
uint64_t budget_bytes = (kstats.free_bytes * (uint64_t)STADIUM_MEMORY_PERCENT) / 100u;
|
||||||
size_t ncells = (size_t)(budget_bytes / STADIUM_CELL_BYTES);
|
size_t ncells = (size_t)(budget_bytes / STADIUM_CELL_BYTES);
|
||||||
size_t bitmap_bytes = (ncells + 7u) / 8u;
|
size_t bitmap_bytes = (ncells + 7u) / 8u;
|
||||||
|
|
||||||
@@ -117,9 +132,9 @@ int stadium_boot_init(void) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
StadiumCell *cells = (StadiumCell *)kmalloc(ncells * STADIUM_CELL_BYTES);
|
StadiumCell *cells = (StadiumCell *)kmalloc(ncells * STADIUM_CELL_BYTES);
|
||||||
uint8_t *bitmap = (uint8_t *)kmalloc(bitmap_bytes);
|
uint8_t *bitmap = (uint8_t *)kmalloc(bitmap_bytes);
|
||||||
uint8_t *owner = (uint8_t *)kmalloc(ncells);
|
uint16_t *owner = (uint16_t *)kmalloc(ncells * sizeof(uint16_t));
|
||||||
if (!cells || !bitmap || !owner) {
|
if (!cells || !bitmap || !owner) {
|
||||||
console_println("Stadium: kmalloc failed for boot-time allocation");
|
console_println("Stadium: kmalloc failed for boot-time allocation");
|
||||||
if (cells) kfree(cells);
|
if (cells) kfree(cells);
|
||||||
@@ -128,6 +143,32 @@ int stadium_boot_init(void) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* VM population bound (2026-08-15, replaces compile-time
|
||||||
|
* STADIUM_MAX_VM_COUNT): STADIUM_VM_MEMORY_PERCENT of whatever's left
|
||||||
|
* in the kmalloc heap AFTER the cell array above, divided by
|
||||||
|
* VM_MEMORY_SIZE (the real per-VM footprint -- 5 MiB, include/vm.h --
|
||||||
|
* not the small quota/word-slot bookkeeping tables). Floored to 1 so
|
||||||
|
* Hera can always boot; no ceiling otherwise (Captain Bob, 2026-08-15:
|
||||||
|
* the population is not knowable in advance). Clamped to what the
|
||||||
|
* uint16_t owner array can index, logged if that ever actually bites. */
|
||||||
|
kmalloc_stats_t kstats_after_cells = kmalloc_get_stats();
|
||||||
|
uint64_t vm_budget_bytes = (kstats_after_cells.free_bytes * (uint64_t)STADIUM_VM_MEMORY_PERCENT) / 100u;
|
||||||
|
size_t max_vm_count = (size_t)(vm_budget_bytes / VM_MEMORY_SIZE);
|
||||||
|
if (max_vm_count < 1u) max_vm_count = 1u;
|
||||||
|
if (max_vm_count > 65535u) {
|
||||||
|
console_println("Stadium: computed VM count exceeds owner-index range, clamped to 65535");
|
||||||
|
max_vm_count = 65535u;
|
||||||
|
}
|
||||||
|
|
||||||
|
StadiumVMQuota *quotas = (StadiumVMQuota *)kmalloc(max_vm_count * sizeof(StadiumVMQuota));
|
||||||
|
if (!quotas) {
|
||||||
|
console_println("Stadium: kmalloc failed for VM quota table");
|
||||||
|
kfree(cells);
|
||||||
|
kfree(bitmap);
|
||||||
|
kfree(owner);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
uint8_t *raw = (uint8_t *)cells;
|
uint8_t *raw = (uint8_t *)cells;
|
||||||
size_t n = ncells * STADIUM_CELL_BYTES;
|
size_t n = ncells * STADIUM_CELL_BYTES;
|
||||||
@@ -153,33 +194,37 @@ int stadium_boot_init(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
for (i = 0; i < STADIUM_MAX_VM_COUNT; i++) {
|
for (i = 0; i < max_vm_count; i++) {
|
||||||
stadium_quotas[i].vm_id = vm_uuid_none();
|
quotas[i].vm_id = vm_uuid_none();
|
||||||
stadium_quotas[i].in_use = 0;
|
quotas[i].in_use = 0;
|
||||||
stadium_quotas[i].free_head = STADIUM_CELL_NONE;
|
quotas[i].free_head = STADIUM_CELL_NONE;
|
||||||
stadium_quotas[i].reservoir = 0;
|
quotas[i].reservoir = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stadium_quotas[0].vm_id = vm_uuid_hera();
|
quotas[0].vm_id = vm_uuid_hera();
|
||||||
stadium_quotas[0].in_use = 1;
|
quotas[0].in_use = 1;
|
||||||
stadium_quotas[0].free_head = 0;
|
quotas[0].free_head = 0;
|
||||||
/* item 4.1, §17.7: at quota-grant time, before any resident patron
|
/* item 4.1, §17.7: at quota-grant time, before any resident patron
|
||||||
* exists, the reservoir holds the VM's entire conserved share -- mirrors
|
* exists, the reservoir holds the VM's entire conserved share -- mirrors
|
||||||
* Hera holding the fleet's whole Q48_ONE before any other VM is born. */
|
* Hera holding the fleet's whole Q48_ONE before any other VM is born. */
|
||||||
stadium_quotas[0].reservoir = Q48_ONE;
|
quotas[0].reservoir = Q48_ONE;
|
||||||
|
|
||||||
stadium_cell_array = cells;
|
stadium_cell_array = cells;
|
||||||
stadium_bitmap = bitmap;
|
stadium_bitmap = bitmap;
|
||||||
stadium_owner = owner;
|
stadium_owner = owner;
|
||||||
stadium_ncells = ncells;
|
stadium_ncells = ncells;
|
||||||
stadium_initialized = 1;
|
stadium_quotas = quotas;
|
||||||
|
stadium_max_vm_count_val = max_vm_count;
|
||||||
|
stadium_initialized = 1;
|
||||||
|
|
||||||
console_puts("Stadium: ");
|
console_puts("Stadium: ");
|
||||||
console_put_u64((uint64_t)ncells);
|
console_put_u64((uint64_t)ncells);
|
||||||
console_puts(" cells (");
|
console_puts(" cells (");
|
||||||
console_put_u64((uint64_t)(ncells * STADIUM_CELL_BYTES) / 1024u);
|
console_put_u64((uint64_t)(ncells * STADIUM_CELL_BYTES) / 1024u);
|
||||||
console_println(" KB)");
|
console_puts(" KB), ");
|
||||||
|
console_put_u64((uint64_t)max_vm_count);
|
||||||
|
console_println(" VM slots");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -192,6 +237,10 @@ size_t stadium_cell_count(void) {
|
|||||||
return stadium_ncells;
|
return stadium_ncells;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t stadium_max_vm_count(void) {
|
||||||
|
return stadium_max_vm_count_val;
|
||||||
|
}
|
||||||
|
|
||||||
StadiumCell *stadium_cells(void) {
|
StadiumCell *stadium_cells(void) {
|
||||||
return stadium_cell_array;
|
return stadium_cell_array;
|
||||||
}
|
}
|
||||||
@@ -276,7 +325,7 @@ static void bitmap_clear(size_t cell_index) {
|
|||||||
*/
|
*/
|
||||||
int stadium_evict(size_t cell_index) {
|
int stadium_evict(size_t cell_index) {
|
||||||
StadiumPatronHeader *header;
|
StadiumPatronHeader *header;
|
||||||
uint8_t slot;
|
uint16_t slot;
|
||||||
|
|
||||||
if (cell_index >= stadium_ncells) return -1;
|
if (cell_index >= stadium_ncells) return -1;
|
||||||
if (!bitmap_get(cell_index)) return -1;
|
if (!bitmap_get(cell_index)) return -1;
|
||||||
@@ -361,7 +410,7 @@ size_t stadium_admit(VMUuid vm_id, const StadiumPatronHeader *candidate) {
|
|||||||
/* Item 4.2 fix (§25.7): record ownership so stadium_evict()'s
|
/* Item 4.2 fix (§25.7): record ownership so stadium_evict()'s
|
||||||
* reservoir credit and free-list return land on the VM that actually
|
* reservoir credit and free-list return land on the VM that actually
|
||||||
* admitted this patron, not whatever owner[idx] held at boot. */
|
* admitted this patron, not whatever owner[idx] held at boot. */
|
||||||
stadium_owner[idx] = (uint8_t)slot;
|
stadium_owner[idx] = (uint16_t)slot;
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,7 +418,7 @@ size_t stadium_admit(VMUuid vm_id, const StadiumPatronHeader *candidate) {
|
|||||||
StadiumPatronHeader *h;
|
StadiumPatronHeader *h;
|
||||||
|
|
||||||
if (!bitmap_get(i)) continue;
|
if (!bitmap_get(i)) continue;
|
||||||
if (stadium_owner[i] != (uint8_t)slot) continue;
|
if (stadium_owner[i] != (uint16_t)slot) continue;
|
||||||
h = &stadium_cell_array[i].header;
|
h = &stadium_cell_array[i].header;
|
||||||
if (h->flags & STADIUM_FLAG_PIN) continue;
|
if (h->flags & STADIUM_FLAG_PIN) continue;
|
||||||
if (h->contains != STADIUM_CONTAINS_NONE) continue;
|
if (h->contains != STADIUM_CONTAINS_NONE) continue;
|
||||||
@@ -403,7 +452,7 @@ size_t stadium_admit(VMUuid vm_id, const StadiumPatronHeader *candidate) {
|
|||||||
* owner[idx] = slot as part of reaping least_dense_index, so this is
|
* owner[idx] = slot as part of reaping least_dense_index, so this is
|
||||||
* currently a no-op in practice, but it must not be assumed to stay a
|
* currently a no-op in practice, but it must not be assumed to stay a
|
||||||
* no-op: this is the correctness statement, not a redundant write. */
|
* no-op: this is the correctness statement, not a redundant write. */
|
||||||
stadium_owner[idx] = (uint8_t)slot;
|
stadium_owner[idx] = (uint16_t)slot;
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,7 +474,7 @@ int stadium_grant_quota(VMUuid new_vm_id, VMUuid from_vm_id) {
|
|||||||
if (from_slot < 0) return -1;
|
if (from_slot < 0) return -1;
|
||||||
|
|
||||||
new_slot = -1;
|
new_slot = -1;
|
||||||
for (i = 0; i < STADIUM_MAX_VM_COUNT; i++) {
|
for (i = 0; i < (int)stadium_max_vm_count_val; i++) {
|
||||||
if (!stadium_quotas[i].in_use) { new_slot = i; break; }
|
if (!stadium_quotas[i].in_use) { new_slot = i; break; }
|
||||||
}
|
}
|
||||||
if (new_slot < 0) return -1;
|
if (new_slot < 0) return -1;
|
||||||
@@ -444,7 +493,7 @@ int stadium_grant_quota(VMUuid new_vm_id, VMUuid from_vm_id) {
|
|||||||
idx = new_head;
|
idx = new_head;
|
||||||
last_new = STADIUM_CELL_NONE;
|
last_new = STADIUM_CELL_NONE;
|
||||||
for (i = 0; i < (int)half; i++) {
|
for (i = 0; i < (int)half; i++) {
|
||||||
stadium_owner[idx] = (uint8_t)new_slot;
|
stadium_owner[idx] = (uint16_t)new_slot;
|
||||||
last_new = idx;
|
last_new = idx;
|
||||||
idx = link_to_size(stadium_cell_array[idx].header.link);
|
idx = link_to_size(stadium_cell_array[idx].header.link);
|
||||||
}
|
}
|
||||||
@@ -469,7 +518,7 @@ static int owned_resident_slot(VMUuid vm_id, size_t cell_index) {
|
|||||||
if (slot < 0) return -1;
|
if (slot < 0) return -1;
|
||||||
if (cell_index >= stadium_ncells) return -1;
|
if (cell_index >= stadium_ncells) return -1;
|
||||||
if (!bitmap_get(cell_index)) return -1;
|
if (!bitmap_get(cell_index)) return -1;
|
||||||
if (stadium_owner[cell_index] != (uint8_t)slot) return -1;
|
if (stadium_owner[cell_index] != (uint16_t)slot) return -1;
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,7 +588,7 @@ uint64_t stadium_resident_sum(VMUuid vm_id) {
|
|||||||
|
|
||||||
for (i = 0; i < stadium_ncells; i++) {
|
for (i = 0; i < stadium_ncells; i++) {
|
||||||
if (!bitmap_get(i)) continue;
|
if (!bitmap_get(i)) continue;
|
||||||
if (stadium_owner[i] != (uint8_t)slot) continue;
|
if (stadium_owner[i] != (uint16_t)slot) continue;
|
||||||
sum += stadium_cell_array[i].header.heat;
|
sum += stadium_cell_array[i].header.heat;
|
||||||
}
|
}
|
||||||
return sum;
|
return sum;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "starkernel/vm/stadium.h"
|
#include "starkernel/vm/stadium.h"
|
||||||
#include "starkernel/console.h"
|
#include "starkernel/console.h"
|
||||||
|
#include "starkernel/kmalloc.h"
|
||||||
#include "starkernel/q48_16.h" /* Q48_ONE -- diagnostic print only */
|
#include "starkernel/q48_16.h" /* Q48_ONE -- diagnostic print only */
|
||||||
#include "vm.h" /* DICTIONARY_SIZE, WORD_ID_INVALID */
|
#include "vm.h" /* DICTIONARY_SIZE, WORD_ID_INVALID */
|
||||||
|
|
||||||
@@ -55,15 +56,61 @@ typedef struct {
|
|||||||
uint64_t last_decay_tick;
|
uint64_t last_decay_tick;
|
||||||
} StadiumWordSlot;
|
} StadiumWordSlot;
|
||||||
|
|
||||||
static StadiumWordSlot word_slots[STADIUM_MAX_VM_COUNT][DICTIONARY_SIZE];
|
/* Row-per-quota-slot, kmalloc'd at stadium_words_init() to stadium_max_vm_
|
||||||
static int words_initialized = 0;
|
* count() rows of DICTIONARY_SIZE entries each -- replaces the old static
|
||||||
static uint64_t stat_promotions[STADIUM_MAX_VM_COUNT];
|
* word_slots[STADIUM_MAX_VM_COUNT][DICTIONARY_SIZE] (2026-08-15: the VM
|
||||||
static uint64_t stat_evictions[STADIUM_MAX_VM_COUNT];
|
* count bound is computed from RAM, not a compile-time constant, so this
|
||||||
|
* can no longer be a flat static array). */
|
||||||
|
static StadiumWordSlot **word_slots = (StadiumWordSlot **)0;
|
||||||
|
static int words_initialized = 0;
|
||||||
|
static uint64_t *stat_promotions = (uint64_t *)0;
|
||||||
|
static uint64_t *stat_evictions = (uint64_t *)0;
|
||||||
|
|
||||||
void stadium_words_init(void) {
|
void stadium_words_init(void) {
|
||||||
int slot;
|
size_t slot;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
for (slot = 0; slot < STADIUM_MAX_VM_COUNT; slot++) {
|
size_t count = stadium_max_vm_count();
|
||||||
|
|
||||||
|
if (words_initialized) return; /* not re-entrant -- see stadium_words.h */
|
||||||
|
|
||||||
|
if (count == 0) {
|
||||||
|
console_println("Stadium words: init skipped (Stadium not initialized)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
word_slots = (StadiumWordSlot **)kmalloc(count * sizeof(StadiumWordSlot *));
|
||||||
|
stat_promotions = (uint64_t *)kmalloc(count * sizeof(uint64_t));
|
||||||
|
stat_evictions = (uint64_t *)kmalloc(count * sizeof(uint64_t));
|
||||||
|
if (!word_slots || !stat_promotions || !stat_evictions) {
|
||||||
|
console_println("Stadium words: kmalloc failed for per-VM tables");
|
||||||
|
if (word_slots) kfree(word_slots);
|
||||||
|
if (stat_promotions) kfree(stat_promotions);
|
||||||
|
if (stat_evictions) kfree(stat_evictions);
|
||||||
|
word_slots = (StadiumWordSlot **)0;
|
||||||
|
stat_promotions = (uint64_t *)0;
|
||||||
|
stat_evictions = (uint64_t *)0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (slot = 0; slot < count; slot++) {
|
||||||
|
word_slots[slot] = (StadiumWordSlot *)kmalloc(DICTIONARY_SIZE * sizeof(StadiumWordSlot));
|
||||||
|
if (!word_slots[slot]) {
|
||||||
|
console_println("Stadium words: kmalloc failed for a word-slot row");
|
||||||
|
/* Free everything allocated so far, including this row's
|
||||||
|
* predecessors, and bail the same all-or-nothing way
|
||||||
|
* stadium_boot_init() does. */
|
||||||
|
{
|
||||||
|
size_t j;
|
||||||
|
for (j = 0; j < slot; j++) kfree(word_slots[j]);
|
||||||
|
}
|
||||||
|
kfree(word_slots);
|
||||||
|
kfree(stat_promotions);
|
||||||
|
kfree(stat_evictions);
|
||||||
|
word_slots = (StadiumWordSlot **)0;
|
||||||
|
stat_promotions = (uint64_t *)0;
|
||||||
|
stat_evictions = (uint64_t *)0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (i = 0; i < DICTIONARY_SIZE; i++) {
|
for (i = 0; i < DICTIONARY_SIZE; i++) {
|
||||||
word_slots[slot][i].cell_index = STADIUM_CELL_NONE;
|
word_slots[slot][i].cell_index = STADIUM_CELL_NONE;
|
||||||
word_slots[slot][i].last_decay_tick = 0;
|
word_slots[slot][i].last_decay_tick = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user