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
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "starkernel/vm/stadium.h"
|
||||
#include "starkernel/console.h"
|
||||
#include "starkernel/kmalloc.h"
|
||||
#include "starkernel/q48_16.h" /* Q48_ONE -- diagnostic print only */
|
||||
#include "vm.h" /* DICTIONARY_SIZE, WORD_ID_INVALID */
|
||||
|
||||
@@ -55,15 +56,61 @@ typedef struct {
|
||||
uint64_t last_decay_tick;
|
||||
} StadiumWordSlot;
|
||||
|
||||
static StadiumWordSlot word_slots[STADIUM_MAX_VM_COUNT][DICTIONARY_SIZE];
|
||||
static int words_initialized = 0;
|
||||
static uint64_t stat_promotions[STADIUM_MAX_VM_COUNT];
|
||||
static uint64_t stat_evictions[STADIUM_MAX_VM_COUNT];
|
||||
/* Row-per-quota-slot, kmalloc'd at stadium_words_init() to stadium_max_vm_
|
||||
* count() rows of DICTIONARY_SIZE entries each -- replaces the old static
|
||||
* word_slots[STADIUM_MAX_VM_COUNT][DICTIONARY_SIZE] (2026-08-15: the VM
|
||||
* 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) {
|
||||
int slot;
|
||||
size_t slot;
|
||||
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++) {
|
||||
word_slots[slot][i].cell_index = STADIUM_CELL_NONE;
|
||||
word_slots[slot][i].last_decay_tick = 0;
|
||||
|
||||
Reference in New Issue
Block a user