Stage MC-0c: shared VM code made per-VM or atomic (FABRIC-3.10.8 §3.4)

- Dictionary lookup index is per VM (vm->fc_index, struct SfFcIndex):
  was one global index rebuilt whenever a different VM was searched, and
  heat reorganization could reorder another VM's buckets. Allocated on
  first lookup, freed by vm_cleanup(); allocation failure counted/logged,
  lookup falls back to a newest-first dictionary walk.
- PRNG: still one stream, stepped by compare-and-swap; SEED one store.
- state_variable removed (write-only; STATE is vm->mode).
- Sweep additions (Captain Bob's ruling): heartbeat_export.c delta
  last-values moved into each VM's HeartbeatState (were statics shared by
  every VM -- wrong across VMs today); TOP-WORDS list heap-sized per call
  (was static [1000]); inference_outputs_to_string() takes a caller
  buffer; three failure counters atomic; crc64 table published with
  release/acquire.
- Confirmed, unchanged: g_runtime compiled out of the kernel,
  g_hotwords_cache unreferenced, ttf cache core-0-only.
- Probe (removed): every VM has its own index; two VMs searched
  alternately 2x5000 lookups: 0 rebuilds, 0 wrong-VM results, all three
  ISAs.
- Standard sequence on amd64/aarch64/riscv64: dict_hash set unchanged,
  G byte-identical, MINT/WIREBIND/USE ok, conservation true, 0 idle growth.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-09-25 21:05:20 -04:00
co-authored by Claude Opus 5.5
parent 33f4090d6d
commit 355909d46f
28 changed files with 55241 additions and 125 deletions
+12 -13
View File
@@ -70,13 +70,14 @@ void heartbeat_capture_tick_snapshot(VM* vm, HeartbeatTickSnapshot* snapshot)
* raw counter on riscv64). Use nominal tick period instead. */
snapshot->elapsed_ns = hb->tick_count * (uint64_t)HEARTBEAT_TICK_NS;
static uint64_t last_tick_count = 0;
uint64_t delta_ticks = hb->tick_count - last_tick_count;
uint64_t delta_ticks = hb->tick_count - hb->export_last_tick_count;
snapshot->tick_interval_ns = delta_ticks * (uint64_t)HEARTBEAT_TICK_NS;
last_tick_count = hb->tick_count;
hb->export_last_tick_count = hb->tick_count;
/* Delta metrics — computed from per-VM counters using static last-value tracking.
* On VM reset (current < last), treat current value as the full delta. */
/* Delta metrics — computed from per-VM counters against this VM's own
* previous values (hb->export_last_*; FABRIC-3.10.8 MC-0c -- were statics
* shared by every VM). On VM reset (current < last), treat current value
* as the full delta. */
/* Cache metrics from hotwords cache */
snapshot->cache_hits_delta = 0; /* TODO: wire hotwords cache hit counter */
@@ -85,12 +86,11 @@ void heartbeat_capture_tick_snapshot(VM* vm, HeartbeatTickSnapshot* snapshot)
/* Word execution delta — words executed since the previous heartbeat tick.
* vm->heartbeat.words_executed is incremented by vm_core.c on every dispatch. */
{
static uint64_t last_words_executed = 0;
uint64_t cur = hb->words_executed;
snapshot->word_executions_delta = (uint32_t)(cur >= last_words_executed
? cur - last_words_executed
snapshot->word_executions_delta = (uint32_t)(cur >= hb->export_last_words_executed
? cur - hb->export_last_words_executed
: cur);
last_words_executed = cur;
hb->export_last_words_executed = cur;
}
/* Hot word count - walk dictionary and count words above threshold */
@@ -141,12 +141,11 @@ void heartbeat_capture_tick_snapshot(VM* vm, HeartbeatTickSnapshot* snapshot)
* High rate = selector chose well and the system settled.
* Low rate = selector is still searching. */
{
static uint64_t last_early_exit_count = 0;
uint64_t cur = hb->early_exit_count;
snapshot->predicted_label_hits = (uint32_t)(cur >= last_early_exit_count
? cur - last_early_exit_count
snapshot->predicted_label_hits = (uint32_t)(cur >= hb->export_last_early_exit_count
? cur - hb->export_last_early_exit_count
: cur);
last_early_exit_count = cur;
hb->export_last_early_exit_count = cur;
}
/* Jitter: tick-based timing has no wall-clock deviation to measure.