starkernel: item 4.1 -- hot words onto the Stadium, density-ranked eviction
Punch list §25 item 4.1 complete. Replaces the round-robin hotwords cache with Stadium density-ranked admission/eviction on the kernel side, via the §17.7 reservoir mechanism and a kernel-side word_id -> cell_index map (no DictEntry change, dict_hash untouched). Adds stadium_birth_hera() to close the cell-0 panic hazard, STADIUM_WORD_HEAT_QUANTUM/STADIUM_WORD_COOL_RATE_Q48 Kconfig knobs (flagged untuned), and a stadium_word_forget() FORGET coherence hook to close a recycled-word_id aliasing gap. Verified: all five hotwords_cache_* call sites in dictionary_management.c bypassed under __STARKERNEL__; word dispatch feeds the Stadium at all three vm_core.c physics_execution_heat_increment() sites; hosted make unaffected; all three architectures booted to ok> with matching dict_hash (0x3d4e1daf289da94f) and matching conservation stats (promotions=354 evictions=0, resident_sum=65536 reservoir=0 sum=65536). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
bd92c57834
commit
3d0b9351bd
@@ -38,6 +38,7 @@
|
||||
#include "starkernel/pmm.h"
|
||||
#include "starkernel/console.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 */
|
||||
|
||||
static StadiumCell *stadium_cell_array = (StadiumCell *)0;
|
||||
static uint8_t *stadium_bitmap = (uint8_t *)0;
|
||||
@@ -71,6 +72,11 @@ typedef struct {
|
||||
VMUuid vm_id;
|
||||
int in_use;
|
||||
size_t free_head;
|
||||
uint64_t reservoir; /* item 4.1, FABRIC.md §17.7 -- Q48.16, heat this VM's
|
||||
* quota holds but no resident patron has claimed.
|
||||
* Invariant: Σ(resident patron heat) + reservoir ==
|
||||
* Q48_ONE, checked the same way vm_physics_conserved()
|
||||
* checks the fleet sum. */
|
||||
} StadiumVMQuota;
|
||||
|
||||
static StadiumVMQuota stadium_quotas[STADIUM_MAX_VM_COUNT];
|
||||
@@ -152,11 +158,16 @@ int stadium_boot_init(void) {
|
||||
stadium_quotas[i].vm_id = vm_uuid_none();
|
||||
stadium_quotas[i].in_use = 0;
|
||||
stadium_quotas[i].free_head = STADIUM_CELL_NONE;
|
||||
stadium_quotas[i].reservoir = 0;
|
||||
}
|
||||
}
|
||||
stadium_quotas[0].vm_id = vm_uuid_hera();
|
||||
stadium_quotas[0].in_use = 1;
|
||||
stadium_quotas[0].free_head = 0;
|
||||
/* item 4.1, §17.7: at quota-grant time, before any resident patron
|
||||
* 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. */
|
||||
stadium_quotas[0].reservoir = Q48_ONE;
|
||||
|
||||
stadium_cell_array = cells;
|
||||
stadium_bitmap = bitmap;
|
||||
@@ -282,6 +293,13 @@ int stadium_evict(size_t cell_index) {
|
||||
bitmap_clear(cell_index);
|
||||
slot = stadium_owner[cell_index];
|
||||
|
||||
/* item 4.1, §17.7: the departing patron's remaining heat must flow back
|
||||
* to its owner's reservoir before the cell returns to the free list, or
|
||||
* every reap leaks heat and Σ(resident) + reservoir drifts below
|
||||
* Q48_ONE. Captured BEFORE the zero-fill below, which would otherwise
|
||||
* destroy it. */
|
||||
stadium_quotas[slot].reservoir += header->heat;
|
||||
|
||||
{
|
||||
uint8_t *raw = (uint8_t *)header;
|
||||
size_t i;
|
||||
@@ -380,4 +398,64 @@ size_t stadium_admit(VMUuid vm_id, const StadiumPatronHeader *candidate) {
|
||||
return idx;
|
||||
}
|
||||
|
||||
uint64_t stadium_reservoir_pull(VMUuid vm_id, uint64_t amount) {
|
||||
int slot = quota_slot_for_vm(vm_id);
|
||||
uint64_t pulled;
|
||||
|
||||
if (slot < 0) return 0;
|
||||
|
||||
pulled = (amount > stadium_quotas[slot].reservoir) ? stadium_quotas[slot].reservoir : amount;
|
||||
stadium_quotas[slot].reservoir -= pulled;
|
||||
return pulled;
|
||||
}
|
||||
|
||||
void stadium_reservoir_push(VMUuid vm_id, uint64_t amount) {
|
||||
int slot = quota_slot_for_vm(vm_id);
|
||||
|
||||
if (slot < 0) return;
|
||||
stadium_quotas[slot].reservoir += amount;
|
||||
}
|
||||
|
||||
uint64_t stadium_reservoir_peek(VMUuid vm_id) {
|
||||
int slot = quota_slot_for_vm(vm_id);
|
||||
|
||||
if (slot < 0) return 0;
|
||||
return stadium_quotas[slot].reservoir;
|
||||
}
|
||||
|
||||
/*
|
||||
* FABRIC.md item 3.6 / item 4.1: see stadium.h's doc. Idempotent via the
|
||||
* item-3.1 discriminator bitmap -- if cell 0 already reads as resident,
|
||||
* something already birthed her (or, if it isn't actually Hera, something
|
||||
* else already claimed cell 0 -- either way this must not clobber it).
|
||||
*/
|
||||
int stadium_birth_hera(void) {
|
||||
StadiumPatronHeader candidate;
|
||||
size_t idx;
|
||||
|
||||
if (!stadium_initialized) return -1;
|
||||
if (stadium_ncells > 0 && bitmap_get(STADIUM_HERA_CELL_INDEX)) return 0;
|
||||
|
||||
{
|
||||
uint8_t *raw = (uint8_t *)&candidate;
|
||||
size_t i;
|
||||
for (i = 0; i < sizeof(candidate); i++) raw[i] = 0;
|
||||
}
|
||||
candidate.identity = 0;
|
||||
candidate.heat = 0;
|
||||
candidate.ttl = 0;
|
||||
candidate.link = STADIUM_LINK_NONE;
|
||||
candidate.contains = STADIUM_CONTAINS_NONE;
|
||||
candidate.mass = 1;
|
||||
candidate.flags = STADIUM_FLAG_PIN;
|
||||
candidate.behaviour = (uint8_t)STADIUM_BEHAVIOUR_COOL;
|
||||
|
||||
idx = stadium_admit(vm_uuid_hera(), &candidate);
|
||||
if (idx == STADIUM_CELL_NONE) return -1; /* refused; should not happen (quota is fresh and empty) */
|
||||
if (idx != STADIUM_HERA_CELL_INDEX) {
|
||||
sk_hal_panic("Stadium: birth_hera did not land on cell 0 -- patron-zero invariant broken");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __STARKERNEL__ */
|
||||
Reference in New Issue
Block a user