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
@@ -55,6 +55,10 @@
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#ifdef __STARKERNEL__
|
||||
#include "starkernel/vm/stadium_words.h" /* item 4.1: FORGET coherence hook */
|
||||
#include "starkernel/vm_uuid.h" /* vm_uuid_hera() */
|
||||
#endif
|
||||
/* LIKELY/UNLIKELY macros are defined in vm.h */
|
||||
|
||||
#ifndef SF_FC_BUCKETS
|
||||
@@ -112,14 +116,28 @@ void vm_dictionary_untrack_entry(VM *vm, DictEntry *entry) {
|
||||
|
||||
/* Cache coherence: the entry is about to be removed (FORGET frees it) —
|
||||
* a stale pointer left in the hot-words ring would be a use-after-free,
|
||||
* and an older same-named word may become visible again. */
|
||||
* and an older same-named word may become visible again.
|
||||
* §17.3 (item 4.1): retired under __STARKERNEL__ -- the kernel word
|
||||
* layer stays inert to this mechanism entirely, so there is nothing to
|
||||
* keep coherent here on the kernel side. Hosted is unaffected. */
|
||||
#ifndef __STARKERNEL__
|
||||
hotwords_cache_evict_entry(vm->hotwords_cache, entry);
|
||||
#endif
|
||||
|
||||
uint32_t word_id = entry->word_id;
|
||||
if (word_id == WORD_ID_INVALID || word_id >= DICTIONARY_SIZE) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef __STARKERNEL__
|
||||
/* item 4.1 coherence hook: if this word_id is resident on the Stadium,
|
||||
* reclaim its cell (crediting heat back to the reservoir) BEFORE the id
|
||||
* is recycled below -- otherwise the next word assigned this same id
|
||||
* would alias onto the forgotten word's stale cell (same failure class
|
||||
* as the 2026-08-02 block_words.c aliasing bug). */
|
||||
stadium_word_forget(word_id);
|
||||
#endif
|
||||
|
||||
if (vm->word_id_map[word_id] == entry) {
|
||||
vm->word_id_map[word_id] = NULL;
|
||||
}
|
||||
@@ -316,12 +334,18 @@ DictEntry *vm_find_word(VM *vm, const char *name, size_t len) {
|
||||
|
||||
/* Use hot-words cache for physics-driven frequency-based acceleration.
|
||||
* The cache's bucket fallback resolves via vm_dict_resolve_in_bucket(),
|
||||
* so a non-NULL result already honors newest-first shadowing. */
|
||||
* so a non-NULL result already honors newest-first shadowing.
|
||||
* §17.3 (item 4.1): bypassed under __STARKERNEL__ -- the kernel side
|
||||
* feeds the Stadium instead (vm_core.c's dispatch sites), and this
|
||||
* lookup fast path is retired in favor of the ordinary bucket scan
|
||||
* below. Hosted is unaffected. */
|
||||
#ifndef __STARKERNEL__
|
||||
DictEntry *found = hotwords_cache_lookup(vm, vm->hotwords_cache, bucket, n, name, len);
|
||||
if (found) {
|
||||
sf_mutex_unlock(&vm->dict_lock);
|
||||
return found;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Phase 2: Choose lookup strategy based on pattern diversity */
|
||||
if (vm->lookup_strategy == 1) {
|
||||
@@ -431,8 +455,12 @@ DictEntry *vm_create_word(VM *vm, const char *name, size_t len, word_func_t func
|
||||
|
||||
/* Cache coherence: this definition may shadow an older word of the same
|
||||
* name that the hot-words cache is still serving. Evict the name so the
|
||||
* next lookup re-resolves through the arbitrated bucket scan. */
|
||||
* next lookup re-resolves through the arbitrated bucket scan.
|
||||
* §17.3 (item 4.1): retired under __STARKERNEL__, same as the other
|
||||
* hotwords_cache_* call sites in this file. */
|
||||
#ifndef __STARKERNEL__
|
||||
hotwords_cache_evict_name(vm->hotwords_cache, name, len);
|
||||
#endif
|
||||
|
||||
log_message(LOG_DEBUG, "vm_create_word: '%.*s' len=%zu total=%zu @%p",
|
||||
(int) len, name, len, total, (void *) entry);
|
||||
@@ -492,9 +520,12 @@ void vm_hide_word(VM *vm) {
|
||||
if (vm && vm->latest) {
|
||||
vm->latest->flags |= WORD_HIDDEN;
|
||||
physics_metadata_refresh_state(vm->latest);
|
||||
/* Visibility changed: this name may now resolve to an older entry */
|
||||
/* Visibility changed: this name may now resolve to an older entry.
|
||||
* §17.3 (item 4.1): retired under __STARKERNEL__. */
|
||||
#ifndef __STARKERNEL__
|
||||
hotwords_cache_evict_name(vm->hotwords_cache,
|
||||
vm->latest->name, vm->latest->name_len);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,9 +539,12 @@ void vm_smudge_word(VM *vm) {
|
||||
}
|
||||
vm->latest->flags ^= WORD_SMUDGED;
|
||||
physics_metadata_refresh_state(vm->latest);
|
||||
/* Visibility changed in either direction: force re-resolution */
|
||||
/* Visibility changed in either direction: force re-resolution.
|
||||
* §17.3 (item 4.1): retired under __STARKERNEL__. */
|
||||
#ifndef __STARKERNEL__
|
||||
hotwords_cache_evict_name(vm->hotwords_cache,
|
||||
vm->latest->name, vm->latest->name_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
void vm_pin_execution_heat(VM *vm) {
|
||||
|
||||
@@ -53,6 +53,7 @@ EFI_RUNTIME_SERVICES *g_sk_runtime_services = NULL;
|
||||
#include "starkernel/vm/bootstrap/sk_vm_bootstrap.h"
|
||||
#include "starkernel/vm/parity.h"
|
||||
#include "starkernel/vm/stadium.h"
|
||||
#include "starkernel/vm/stadium_words.h"
|
||||
#include "starkernel/capsule_generated.h"
|
||||
#include "starkernel/capsule_loader.h"
|
||||
#include "starkernel/capsule_birth.h" /* capsule_birth_mama, capsule_find_mama_init */
|
||||
@@ -484,6 +485,14 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
||||
* yet, so a failed allocation logs and boot continues. */
|
||||
(void)stadium_boot_init();
|
||||
|
||||
/* item 4.1, FABRIC.md item 3.6/§17.7: actually enforce "Hera is patron
|
||||
* zero" before anything else can land on cell 0 via the free list, then
|
||||
* bring up the word layer's map. Both must happen before the first word
|
||||
* ever dispatches -- capsule birth below runs init.4th, which dispatches
|
||||
* words. */
|
||||
(void)stadium_birth_hera();
|
||||
stadium_words_init();
|
||||
|
||||
/* M7: VM Bootstrap and Parity Validation */
|
||||
console_println("VM: bootstrap parity...");
|
||||
ParityPacket parity_pkt;
|
||||
@@ -614,6 +623,11 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
||||
#ifdef STARFORTH_ENABLE_VM
|
||||
VM *mama = (VM *)sk_get_mama_vm();
|
||||
|
||||
/* item 4.1 diagnostic (§25.5 acceptance: "observable via a diagnostic
|
||||
* word or boot console output"): word patrons already dispatched during
|
||||
* capsule birth above, so this is non-vacuous by this point. */
|
||||
stadium_words_print_boot_diagnostics(vm_uuid_hera());
|
||||
|
||||
/*
|
||||
* Runtime --doe flag: inject "EXEC-DOE BYE" if requested via boot args.
|
||||
* Checked before SK_STARTUP_FORTH so a runtime --doe takes precedence.
|
||||
|
||||
@@ -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__ */
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
StarForth — Steady-State Virtual Machine Runtime
|
||||
|
||||
Copyright (c) 2023–2025 Robert A. James
|
||||
All rights reserved.
|
||||
|
||||
This file is part of the StarForth project.
|
||||
|
||||
Licensed under the StarForth License, Version 1.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at:
|
||||
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
|
||||
|
||||
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
express or implied, including but not limited to the warranties of
|
||||
merchantability, fitness for a particular purpose, and noninfringement.
|
||||
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* stadium_words.c - Word patrons on the Stadium (FABRIC.md §17.3/§17.7,
|
||||
* punch list item 4.1). See stadium_words.h for the design rationale.
|
||||
*/
|
||||
|
||||
#include "starkernel/vm/stadium_words.h"
|
||||
|
||||
#ifdef __STARKERNEL__
|
||||
|
||||
#include "starkernel/vm/stadium.h"
|
||||
#include "starkernel/console.h"
|
||||
#include "starkernel/q48_16.h" /* Q48_ONE -- diagnostic print only */
|
||||
#include "vm.h" /* DICTIONARY_SIZE, WORD_ID_INVALID */
|
||||
|
||||
/*
|
||||
* StadiumWordSlot - the kernel-side word_id -> cell_index map (decided
|
||||
* 2026-08-05: no DictEntry field). `last_decay_tick` is this layer's own
|
||||
* bookkeeping, separate from DictEntry.physics.last_decay_tick -- that field
|
||||
* belongs to execution_heat's decay, which item 4.1 does not touch.
|
||||
*/
|
||||
typedef struct {
|
||||
size_t cell_index; /* STADIUM_CELL_NONE if not resident */
|
||||
uint64_t last_decay_tick;
|
||||
} StadiumWordSlot;
|
||||
|
||||
static StadiumWordSlot word_slots[DICTIONARY_SIZE];
|
||||
static int words_initialized = 0;
|
||||
static uint64_t stat_promotions = 0;
|
||||
static uint64_t stat_evictions = 0;
|
||||
|
||||
void stadium_words_init(void) {
|
||||
uint32_t i;
|
||||
for (i = 0; i < DICTIONARY_SIZE; i++) {
|
||||
word_slots[i].cell_index = STADIUM_CELL_NONE;
|
||||
word_slots[i].last_decay_tick = 0;
|
||||
}
|
||||
stat_promotions = 0;
|
||||
stat_evictions = 0;
|
||||
words_initialized = 1;
|
||||
}
|
||||
|
||||
static int cell_is_resident(size_t idx) {
|
||||
const uint8_t *bm = stadium_header_bitmap();
|
||||
if (!bm) return 0;
|
||||
return (bm[idx / 8u] >> (idx % 8u)) & 1u;
|
||||
}
|
||||
|
||||
/*
|
||||
* resolve_resident_cell - Self-healing lookup (advisor-flagged reverse
|
||||
* coherence gap): the map may claim word_id is resident at a cell that was
|
||||
* actually reclaimed by someone else's stadium_admit() eviction fallback
|
||||
* since the map was last written. Detected here, lazily, against ground
|
||||
* truth already public via stadium_cells()/stadium_header_bitmap() --
|
||||
* no new coupling from stadium.c into this file. A stale mapping is cleared
|
||||
* and counted as an eviction on discovery.
|
||||
*/
|
||||
static size_t resolve_resident_cell(uint32_t word_id) {
|
||||
size_t cell = word_slots[word_id].cell_index;
|
||||
StadiumCell *cells;
|
||||
|
||||
if (cell == STADIUM_CELL_NONE) return STADIUM_CELL_NONE;
|
||||
if (cell >= stadium_cell_count() || !cell_is_resident(cell)) {
|
||||
word_slots[word_id].cell_index = STADIUM_CELL_NONE;
|
||||
stat_evictions++;
|
||||
return STADIUM_CELL_NONE;
|
||||
}
|
||||
cells = stadium_cells();
|
||||
if (cells[cell].header.identity != (uint64_t)word_id) {
|
||||
word_slots[word_id].cell_index = STADIUM_CELL_NONE;
|
||||
stat_evictions++;
|
||||
return STADIUM_CELL_NONE;
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
void stadium_word_dispatch(VMUuid vm_id, uint32_t word_id, uint64_t heartbeat_ticks) {
|
||||
size_t cell;
|
||||
|
||||
if (!words_initialized) return;
|
||||
if (word_id == WORD_ID_INVALID || word_id >= DICTIONARY_SIZE) return;
|
||||
|
||||
cell = resolve_resident_cell(word_id);
|
||||
|
||||
if (cell != STADIUM_CELL_NONE) {
|
||||
StadiumPatronHeader *h = &stadium_cells()[cell].header;
|
||||
uint64_t elapsed = heartbeat_ticks - word_slots[word_id].last_decay_tick;
|
||||
|
||||
if (elapsed > 0) {
|
||||
/* Redirected Loop #3 (§17.7): a FRACTION of the cell's own
|
||||
* current heat per elapsed tick -- unit-safe for a conserved
|
||||
* share of 1.0, unlike execution_heat's flat per-tick amount.
|
||||
* STADIUM_WORD_COOL_RATE_Q48 / 65536 is that fraction. */
|
||||
uint64_t per_tick = (h->heat * (uint64_t)STADIUM_WORD_COOL_RATE_Q48) >> 16;
|
||||
uint64_t cooled = per_tick * elapsed;
|
||||
if (cooled > h->heat) cooled = h->heat;
|
||||
if (cooled > 0) {
|
||||
h->heat -= cooled;
|
||||
stadium_reservoir_push(vm_id, cooled);
|
||||
}
|
||||
word_slots[word_id].last_decay_tick = heartbeat_ticks;
|
||||
}
|
||||
|
||||
h->heat += stadium_reservoir_pull(vm_id, (uint64_t)STADIUM_WORD_HEAT_QUANTUM);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Not resident: Option B starter-grant admission (§17.7). execution_heat
|
||||
* plays no role -- density is decided entirely by the pulled quantum. */
|
||||
{
|
||||
uint64_t pulled = stadium_reservoir_pull(vm_id, (uint64_t)STADIUM_WORD_HEAT_QUANTUM);
|
||||
StadiumPatronHeader candidate;
|
||||
uint8_t *raw = (uint8_t *)&candidate;
|
||||
size_t i;
|
||||
size_t idx;
|
||||
|
||||
for (i = 0; i < sizeof(candidate); i++) raw[i] = 0;
|
||||
candidate.identity = (uint64_t)word_id;
|
||||
candidate.heat = pulled;
|
||||
candidate.ttl = 0;
|
||||
candidate.link = 0; /* unused for word patrons; no continuation/consumer yet */
|
||||
candidate.contains = STADIUM_CONTAINS_NONE;
|
||||
candidate.mass = 1;
|
||||
candidate.flags = 0; /* unpinned -- words carry no pin exception (§17.3) */
|
||||
candidate.behaviour = (uint8_t)STADIUM_BEHAVIOUR_COOL;
|
||||
|
||||
idx = stadium_admit(vm_id, &candidate);
|
||||
if (idx == STADIUM_CELL_NONE) {
|
||||
stadium_reservoir_push(vm_id, pulled); /* rollback: preserve conservation */
|
||||
return;
|
||||
}
|
||||
|
||||
word_slots[word_id].cell_index = idx;
|
||||
word_slots[word_id].last_decay_tick = heartbeat_ticks;
|
||||
stat_promotions++;
|
||||
}
|
||||
}
|
||||
|
||||
void stadium_word_forget(uint32_t word_id) {
|
||||
size_t cell;
|
||||
|
||||
if (!words_initialized) return;
|
||||
if (word_id == WORD_ID_INVALID || word_id >= DICTIONARY_SIZE) return;
|
||||
|
||||
cell = resolve_resident_cell(word_id);
|
||||
if (cell == STADIUM_CELL_NONE) return;
|
||||
|
||||
if (stadium_evict(cell) == 0) {
|
||||
word_slots[word_id].cell_index = STADIUM_CELL_NONE;
|
||||
stat_evictions++;
|
||||
}
|
||||
}
|
||||
|
||||
void stadium_words_stats(uint64_t *promotions, uint64_t *evictions) {
|
||||
if (promotions) *promotions = stat_promotions;
|
||||
if (evictions) *evictions = stat_evictions;
|
||||
}
|
||||
|
||||
/* Freestanding: no libc printf. Prints an unsigned decimal, no leading
|
||||
* zeros -- same small utility stadium.c already duplicates locally. */
|
||||
static void console_put_u64(uint64_t v) {
|
||||
char buf[21];
|
||||
int i = 20;
|
||||
buf[20] = '\0';
|
||||
if (v == 0) {
|
||||
console_puts("0");
|
||||
return;
|
||||
}
|
||||
while (v > 0 && i > 0) {
|
||||
buf[--i] = (char)('0' + (v % 10));
|
||||
v /= 10;
|
||||
}
|
||||
console_puts(&buf[i]);
|
||||
}
|
||||
|
||||
void stadium_words_print_boot_diagnostics(VMUuid vm_id) {
|
||||
uint64_t promotions = 0, evictions = 0;
|
||||
uint64_t resident_sum = 0;
|
||||
uint64_t reservoir;
|
||||
size_t ncells = stadium_cell_count();
|
||||
size_t i;
|
||||
|
||||
stadium_words_stats(&promotions, &evictions);
|
||||
|
||||
for (i = 0; i < ncells; i++) {
|
||||
if (cell_is_resident(i)) {
|
||||
resident_sum += stadium_cells()[i].header.heat;
|
||||
}
|
||||
}
|
||||
reservoir = stadium_reservoir_peek(vm_id);
|
||||
|
||||
console_puts("Stadium words: promotions=");
|
||||
console_put_u64(promotions);
|
||||
console_puts(" evictions=");
|
||||
console_put_u64(evictions);
|
||||
console_println("");
|
||||
|
||||
console_puts("Stadium conservation: resident_sum=");
|
||||
console_put_u64(resident_sum);
|
||||
console_puts(" reservoir=");
|
||||
console_put_u64(reservoir);
|
||||
console_puts(" sum=");
|
||||
console_put_u64(resident_sum + reservoir);
|
||||
console_puts(" (Q48_ONE=");
|
||||
console_put_u64((uint64_t)Q48_ONE);
|
||||
console_println(")");
|
||||
}
|
||||
|
||||
#endif /* __STARKERNEL__ */
|
||||
@@ -58,6 +58,7 @@
|
||||
#include "starkernel/vm/arena.h"
|
||||
#include "starkernel/console.h" /* g_sk_fault_word */
|
||||
#include "platform_alloc.h" /* sf_free for call_stack */
|
||||
#include "starkernel/vm/stadium_words.h" /* item 4.1: word patrons on the Stadium */
|
||||
#endif
|
||||
#include "word_source/include/vocabulary_words.h"
|
||||
#include "vm_internal.h"
|
||||
@@ -681,6 +682,12 @@ void execute_colon_word(VM* vm)
|
||||
|
||||
physics_execution_heat_increment(w);
|
||||
|
||||
/* item 4.1, FABRIC.md §17.7: feed the Stadium's independent
|
||||
* conserved heat wire. execution_heat above is untouched by
|
||||
* this call. vm_uuid_hera() is hardcoded here -- Tripod is
|
||||
* pruned to Hera alone (item 0.1); revisit at item 4.2. */
|
||||
stadium_word_dispatch(vm_uuid_hera(), w->word_id, vm->heartbeat.tick_count);
|
||||
|
||||
uint32_t word_id = w->word_id;
|
||||
if (word_id < DICTIONARY_SIZE)
|
||||
{
|
||||
@@ -874,6 +881,7 @@ void vm_interpret_word(VM* vm, const char* word_str, size_t len)
|
||||
entry->physics.last_decay_ns = lookup_ns;
|
||||
|
||||
physics_execution_heat_increment(entry);
|
||||
stadium_word_dispatch(vm_uuid_hera(), entry->word_id, vm->heartbeat.tick_count);
|
||||
if (canon && canon != entry)
|
||||
{
|
||||
/* Apply decay to canonical entry as well */
|
||||
@@ -884,6 +892,7 @@ void vm_interpret_word(VM* vm, const char* word_str, size_t len)
|
||||
canon->physics.last_decay_ns = lookup_ns;
|
||||
|
||||
physics_execution_heat_increment(canon);
|
||||
stadium_word_dispatch(vm_uuid_hera(), canon->word_id, vm->heartbeat.tick_count);
|
||||
physics_metadata_touch(canon, canon->execution_heat, lookup_ns);
|
||||
}
|
||||
sf_mutex_unlock(&vm->dict_lock);
|
||||
|
||||
Reference in New Issue
Block a user