Workload capsules the DoE births are definitions only; each defines WL-RUN (its old birth-time work plus its entry word twice) and WL-DONE-ARGS. The driver births N workers, SENDs each 'WL-RUN WL-DONE-ARGS SEND', waits in an ordinary loop for N MU-DONE messages, KILLs them (parked idle), and emits the marker. The serialized VM-EXEC round-robin is gone. Kernel: no switch checkpoint after a payload's last word; work heat is the assessed per-beat charge, and a VM gaining work is raised to the busy set's floor (Captain Bob's ruling) -- fixes a live stall where a busy-waiting Hera never yielded, without serializing batch starts. Evidence: cfg-4 rows spread evenly over Hera and all 8 worker slots (44k switches); full cfg-4 trials on amd64/aarch64/riscv64 end fail=0 with 8/8 KILL dead; Stage G interleave byte-identical on all three. Acceptance: dict_hash unchanged, relay 3, idle growth 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
220 lines
8.6 KiB
C
220 lines
8.6 KiB
C
/*
|
||
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.
|
||
*/
|
||
|
||
/**
|
||
* capsule_vm_physics.h - Dynamic VM Fleet Physics
|
||
*
|
||
* Structural parallel to the word-level physics engine (execution heat,
|
||
* decay, rolling-window history, regression-inferred slope) applied to
|
||
* VMs instead of dictionary words. Kernel-only: no hosted-build
|
||
* equivalent, since the hosted build has no multi-VM fleet.
|
||
*
|
||
* sum(execution_heat_q48 for all LIVE VMs) == Q.1 is a conservation
|
||
* invariant, held by construction: every state change is a balanced
|
||
* transfer (see design doc VM-PHYSICS-DYNAMIC-FLEET-DESIGN-20260705.md).
|
||
*
|
||
* This is a passive observer of VM activity, never a driver of it —
|
||
* there is no scheduler here. Recording happens only at existing
|
||
* dispatch points (BIRTH, KILL, VM-EXEC, VM-CALL, VM-STEP).
|
||
*/
|
||
|
||
#ifndef STARKERNEL_CAPSULE_VM_PHYSICS_H
|
||
#define STARKERNEL_CAPSULE_VM_PHYSICS_H
|
||
|
||
#include <stdint.h>
|
||
#include "starkernel/vm_uuid.h" /* VMUuid -- FABRIC-0.md item 3.8 */
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
/**
|
||
* vm_physics_init - Register a newly-born VM at zero heat
|
||
*
|
||
* Called from mama_word_birth once a VM reaches VM_STATE_LIVE. Starts
|
||
* at execution_heat_q48 = 0, so conservation holds trivially — no
|
||
* fan-out from existing VMs is needed.
|
||
*
|
||
* @param vm_id Registry VM ID assigned at birth
|
||
*/
|
||
void vm_physics_init(VMUuid vm_id);
|
||
|
||
/**
|
||
* vm_physics_retire - Remove a killed VM, returning its heat to Hera
|
||
*
|
||
* Called from mama_word_kill before the registry entry is torn down.
|
||
* The dying VM's entire remaining heat is transferred up its
|
||
* parent_vm_id chain (VMRegistryEntry, capsule_run.h) to the fleet's
|
||
* single structural root, Hera -- no division, no per-survivor
|
||
* weighting. The chain walk tolerates already-dead intermediate
|
||
* parents (a parent's own parent_vm_id was set once at its birth and
|
||
* never rewritten, so the walk continues through it).
|
||
*
|
||
* @param vm_id Registry VM ID of the VM being killed
|
||
*/
|
||
void vm_physics_retire(VMUuid vm_id);
|
||
|
||
/**
|
||
* vm_physics_touch - Record real dispatch activity against a VM
|
||
*
|
||
* Called from the three existing dispatch primitives (VM-EXEC, VM-CALL,
|
||
* VM-STEP) at the point they've already confirmed the target VM is
|
||
* live. Pulls heat from the rest of the fleet toward the touched VM
|
||
* (amount = elapsed_ticks * fleet_transfer_slope_q48 >> 16) and appends
|
||
* vm_id to the fleet's rolling touch-history window.
|
||
*
|
||
* Restated on the virtual tick (FABRIC-0.md item 2.1, 2026-08-04): no
|
||
* longer takes a wall-clock timestamp. Reads fleet_heartbeat_tick_count
|
||
* internally, which is execution-paced (advanced once per vm_tick()
|
||
* call, see vm_physics_heartbeat_tick), so the transfer this produces is
|
||
* a deterministic function of the execution stream, not of wall time.
|
||
*
|
||
* @param vm_id Registry VM ID being dispatched to
|
||
*/
|
||
void vm_physics_touch(VMUuid vm_id);
|
||
|
||
/**
|
||
* vm_physics_charge - Charge the running VM for one beat of its own work
|
||
*
|
||
* FABRIC-3.8.md §3.13.2 (Stage C-a, 2026-09-23). The work law, beside
|
||
* vm_physics_touch()'s dispatch law: called once per beat a VM produces
|
||
* while it is the switch-current VM (vm_tick()), so a VM running its own
|
||
* kernel-Hermes mail on its own stack heats up as it works -- before this,
|
||
* nothing did (G9). Adds one beat's slope to a per-VM carry, and pulls the
|
||
* carry's whole units from the rest of the live fleet in proportion to
|
||
* each VM's heat, through the same conservative transfer as touch. The
|
||
* fraction below one unit, and any whole units lost to the proportional
|
||
* split's own rounding, stay in the carry instead of being discarded.
|
||
* Records NO fleet_window sample, so the slope estimator and the existing
|
||
* DoE heat columns keep their meaning (§3.13.2 "Frozen slope").
|
||
*
|
||
* @param vm_id Registry VM ID of the running VM
|
||
*/
|
||
void vm_physics_charge(VMUuid vm_id);
|
||
|
||
/**
|
||
* vm_physics_work_heat_of - Cumulative heat a VM has pulled in by working
|
||
*
|
||
* FABRIC-3.8.md §3.13.7, ruling C-4 (β), Captain Bob 2026-09-23: heat
|
||
* earned by the VM's own work -- the charge vm_physics_charge() assessed at
|
||
* each of its beats (beats x slope, in the charge carry's sub-unit scale),
|
||
* whether or not the rest of the fleet held heat to move -- independent of
|
||
* any structural endowment (Hera's initial Q48_ONE). This is the quantity
|
||
* the switch decision compares ("coolest VM with work" = least work heat).
|
||
* Never decreases, except that it may be raised by
|
||
* vm_physics_work_heat_floor(). 0 for an unknown or dead VM.
|
||
*/
|
||
uint64_t vm_physics_work_heat_of(VMUuid vm_id);
|
||
|
||
/**
|
||
* vm_physics_work_heat_floor - "Floor on contact" (Captain Bob, Stage H)
|
||
*
|
||
* Raise vm_id's work heat to floor_q48 if it is below it; never lowers it.
|
||
* Called when a VM that had no work gains some (sk_vm_switch_signal_note_
|
||
* work_gained()), with the lowest work heat among the VMs that currently
|
||
* have work -- so a newly-busy VM joins the running set level with its
|
||
* floor instead of at whatever it last had (0 for a new VM), which would
|
||
* otherwise let it run alone until it "caught up."
|
||
*/
|
||
void vm_physics_work_heat_floor(VMUuid vm_id, uint64_t floor_q48);
|
||
|
||
/**
|
||
* vm_physics_tick - Heartbeat-gated inference pass
|
||
*
|
||
* Mirrors vm_tick_inference_engine: when the fleet touch-history window
|
||
* is warm, replays it to re-fit fleet_transfer_slope_q48 via the same
|
||
* closed-form log-linear OLS regression used for word-level decay.
|
||
* Skips the update (does not substitute a default) when unwarmed or
|
||
* when fit quality is not usable.
|
||
*
|
||
* @param now_ns Current monotonic time in nanoseconds
|
||
*/
|
||
void vm_physics_tick(uint64_t now_ns);
|
||
|
||
/**
|
||
* vm_physics_heartbeat_tick - Fleet-wide heartbeat, gates vm_physics_tick()
|
||
*
|
||
* Call from every VM's own vm_tick(), not just Hera's. Increments a
|
||
* single fleet-wide tick counter (distinct from any VM's own per-VM
|
||
* HeartbeatState.tick_count) and calls vm_physics_tick() once that
|
||
* shared counter has advanced by HEARTBEAT_INFERENCE_FREQUENCY since
|
||
* the last fit.
|
||
*
|
||
* Fixes a real defect (VM-FLEET-ATTRACTOR-DESIGN-20260705.md rev k):
|
||
* gating this on Hera's own tick_count meant the inference pass almost
|
||
* never fired, because Hera-as-orchestrator mostly blocks on VM-EXEC/
|
||
* VM-CALL dispatch -- work that accrues to the *target* VM's own tick
|
||
* count, not hers. VM-PHYSICS-DYNAMIC-FLEET-DESIGN-20260705.md already
|
||
* specified the fix's direction: fleet_transfer_slope_q48 must be
|
||
* inferred "from aggregate fleet statistics... not one per VM" -- the
|
||
* same principle applies to the readiness signal that gates computing
|
||
* it, not just the regression's own input trajectory.
|
||
*
|
||
* @param now_ns Current monotonic time in nanoseconds (of whichever
|
||
* VM is calling; unused by vm_physics_tick() today)
|
||
*/
|
||
void vm_physics_heartbeat_tick(uint64_t now_ns);
|
||
|
||
/**
|
||
* vm_physics_fleet_heat_sum - Sum of execution_heat_q48 over all LIVE VMs
|
||
*
|
||
* Diagnostic / verification primitive. Should always read Q.1 (65536)
|
||
* if the conservation invariant holds.
|
||
*/
|
||
uint64_t vm_physics_fleet_heat_sum(void);
|
||
|
||
/**
|
||
* vm_physics_heat_of - Current execution_heat_q48 for one VM
|
||
*
|
||
* Transparency primitive (VM-FLEET-ATTRACTOR-DESIGN-20260705.md): the
|
||
* fleet-wide conservation invariant always reads Q.1 by construction, so
|
||
* it carries no information about how heat is actually distributed among
|
||
* live VMs. This is the per-VM fact that sum alone can't provide.
|
||
*
|
||
* @param vm_id Registry VM ID
|
||
* @return execution_heat_q48, or 0 if vm_id is unknown or not live
|
||
*/
|
||
uint64_t vm_physics_heat_of(VMUuid vm_id);
|
||
|
||
/**
|
||
* vm_physics_conserved - Conservation check
|
||
*
|
||
* @return 1 if |vm_physics_fleet_heat_sum() - Q.1| < epsilon, else 0
|
||
*/
|
||
int vm_physics_conserved(void);
|
||
|
||
/**
|
||
* vm_physics_status - Print a diagnostic status report
|
||
*
|
||
* Replaces K-STATUS/VM-STATUS. Reports fleet heat sum, conservation
|
||
* verdict, and the current fleet-wide inferred slope / fit quality /
|
||
* warm-up state -- the fleet-level analog of K-STATUS's per-VM report,
|
||
* adapted to a mechanism with no fixed VM count to enumerate.
|
||
*/
|
||
void vm_physics_status(void);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* STARKERNEL_CAPSULE_VM_PHYSICS_H */
|