Add VM-HEAT primitive: groundwork for a compudynamic turn-attractor (FABRIC-3.md §XIX)
Prompted by reading the std79-doe K report: checked whether the campaign's
"real cross-VM dispatch load" was actually concurrent or strictly
serialized. It's serialized at two levels -- VM-EXEC's vm_interpret(target,
...) is a direct synchronous C call (Hera fully blocked until it returns),
and even the background physics tick (vm_tick(), vm_runtime.c) is driven
by each VM's own execution loop, so idle identities accrue zero ticks
between their own turns. K's perfect conservation (FABRIC-3.md §XVIII)
verifies sequential per-VM accounting correctness, not concurrent-access
safety, since there was never concurrent access to test.
Agreed direction: fix this without a scheduler, by reusing the same
least-dense-candidate judgment stadium_admit() already trusts for
eviction, applied to "whose turn is next" instead of "who gets evicted" --
a fleet-level turn-attractor giving the next turn to whichever live
identity currently has the lowest execution_heat_q48, no fixed round-robin,
no priorities, no preemption. Lives beside Stadium in
capsule_vm_physics.c (already the fleet-level consumer of Stadium
primitives, e.g. the K mechanism itself), not inside stadium.c ("the
floor" -- residency/eviction, a different concern from turn order) and
not a new subsystem.
This pass lands only the primitive the mechanism needs: VM-HEAT
( c-addr u -- heat-q48 ), pushing a named VM's current
execution_heat_q48 via vm_physics_heat_of() -- previously C-internal
only (doe_log_heat_by_name(), doe_log.c), never exposed to FORTH. Silent
0 on an unknown/dead name (no print/error), since a turn-attractor
scanning many candidates every turn shouldn't have to filter console
noise for names that simply aren't live. Registered everywhere
VM-EXEC/VM-CALL already are. Builds clean on all three architectures;
live-tested on amd64: Hera -> 65452, Hermes -> 43, unknown name -> 0, no
faults.
The turn-attractor loop itself (std79-doe.fth's trial ordering) is not
yet built -- next step, not done here.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXieurDfDSsDFdnSyusuWo
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
238ca95b3c
commit
5a9425b91b
@@ -865,6 +865,53 @@ static void mama_word_vm_call(VM *vm)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief VM-HEAT ( c-addr u -- heat-q48 )
|
||||
* Push the named VM's current execution_heat_q48 (Q48.16, 0 if the VM is
|
||||
* unknown/dead), via vm_physics_heat_of() -- previously C-internal only
|
||||
* (doe_log_heat_by_name(), doe_log.c), never exposed to FORTH. Added
|
||||
* 2026-09-12 for a compudynamic turn-attractor (FABRIC-3.md §XIX): "whose
|
||||
* turn is next" decided by comparing live candidates' own current heat via
|
||||
* this word, the same density-comparison judgment stadium_admit() already
|
||||
* makes for eviction, rather than a fixed round-robin order. Silent on an
|
||||
* unknown name (returns 0, does not print/error) -- callers scanning many
|
||||
* VM names each turn to find the coolest one should not have to filter
|
||||
* console noise for names that are simply not currently live.
|
||||
*/
|
||||
static void mama_word_vm_heat(VM *vm)
|
||||
{
|
||||
char vm_name[VM_NAME_MAX];
|
||||
uint32_t i;
|
||||
cell_t vm_u, vm_caddr;
|
||||
const char *src;
|
||||
VMRegistryEntry entry;
|
||||
|
||||
if (vm->dsp < 1) { vm->error = 1; return; }
|
||||
|
||||
vm_u = vm_pop(vm);
|
||||
vm_caddr = vm_pop(vm);
|
||||
|
||||
if (vm_u <= 0 || (uint32_t)vm_u >= VM_NAME_MAX) {
|
||||
vm_push(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
const uint8_t *p = vm_ptr(vm, (vaddr_t)vm_caddr);
|
||||
if (!p) { vm->error = 1; return; }
|
||||
src = (const char *)p;
|
||||
}
|
||||
for (i = 0; i < (uint32_t)vm_u; i++) vm_name[i] = src[i];
|
||||
vm_name[vm_u] = '\0';
|
||||
|
||||
if (capsule_vm_find_by_name_nocase(vm_name, &entry) != 0) {
|
||||
vm_push(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
vm_push(vm, (cell_t)vm_physics_heat_of(entry.vm_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MINT ( -- ok? )
|
||||
* Mint a fresh identity onto the currently attached USB drive
|
||||
@@ -1586,6 +1633,7 @@ void register_mama_forth_words(VM *vm)
|
||||
register_word(vm, "VM-STEP", mama_word_vm_step);
|
||||
register_word(vm, "VM-EXEC", mama_word_vm_exec);
|
||||
register_word(vm, "VM-CALL", mama_word_vm_call);
|
||||
register_word(vm, "VM-HEAT", mama_word_vm_heat);
|
||||
register_word(vm, "CAPSULE-TEST", mama_word_capsule_test);
|
||||
|
||||
/* Create and switch to MAMA vocabulary */
|
||||
@@ -1623,6 +1671,7 @@ void register_mama_forth_words(VM *vm)
|
||||
register_word(vm, "VM-STEP", mama_word_vm_step);
|
||||
register_word(vm, "VM-EXEC", mama_word_vm_exec);
|
||||
register_word(vm, "VM-CALL", mama_word_vm_call);
|
||||
register_word(vm, "VM-HEAT", mama_word_vm_heat);
|
||||
register_word(vm, "CAPSULE-TEST", mama_word_capsule_test);
|
||||
register_word(vm, "EXEC", mama_word_exec);
|
||||
|
||||
@@ -1837,6 +1886,7 @@ void register_child_vm_words(VM *vm)
|
||||
register_word(vm, "EXEC", mama_word_exec);
|
||||
register_word(vm, "VM-EXEC", mama_word_vm_exec);
|
||||
register_word(vm, "VM-CALL", mama_word_vm_call);
|
||||
register_word(vm, "VM-HEAT", mama_word_vm_heat);
|
||||
/* USE (FABRIC-2.md §F.24): not console-specific -- any VM can
|
||||
* redirect the physical REPL to any other VM it has ACL access to
|
||||
* (BINDSTEP re-verifies on every call, §F.9), including a console
|
||||
|
||||
Reference in New Issue
Block a user