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:
co-authored by
Claude Opus 5.5
parent
33f4090d6d
commit
355909d46f
@@ -262,3 +262,60 @@ Every lock balances individually on every ISA, at both readings. 0 recursions me
|
||||
- The G string is byte-identical to MC-0b and MC-0a on all three ISAs.
|
||||
- The `dict_hash` set and the ledger line are unchanged.
|
||||
- No stop condition was hit. **MC-0b2 done.**
|
||||
|
||||
### 3.4 MC-0c — shared VM code made per-VM or atomic (2026-09-25)
|
||||
|
||||
Scope: §1's second table, plus five further items found by a sweep of every file-scope and function-local mutable variable in the vendored VM sources the kernel compiles. Captain Bob ruled all of it into this stage (2026-09-25).
|
||||
|
||||
**§1's table:**
|
||||
|
||||
| Item | Finding | Change |
|
||||
|---|---|---|
|
||||
| dictionary lookup index (`sf_fc_list/count/cap`, `sf_cached_latest`) | One index for the whole system, holding whichever VM's dictionary was searched last: every switch between VMs that look words up rebuilt it. `dict_reorganize_buckets_by_heat()` reordered that shared index, which could be another VM's. | Per VM: `struct SfFcIndex` (`dictionary_heat_optimization.h`), `vm->fc_index`, allocated on first lookup and freed by both `vm_cleanup()`s. An allocation failure is counted and logged, and the lookup walks the dictionary newest-first instead (still correct). The heat-aware lookup and the heat reorganization use the VM's own index. The index's unused global reset is gone, as are the benchmark word's stale externs. The 256 buckets are one per possible first byte (the whole domain, not a capacity). |
|
||||
| `g_prng_state` (`starforth_words.c`) | One stream for all VMs, as accepted at Stage H; plain read-modify-write. | Still one stream. The step is a compare-and-swap loop, and SEED is a single atomic store. |
|
||||
| `g_runtime` (`physics_runtime.c`) | The kernel build (`STARFORTH_MINIMAL`) compiles stubs; `g_runtime` exists only hosted. | None. |
|
||||
| `state_variable` (`dictionary_manipulation_words.c`) | Written by INTERPRET, never read. STATE is `vm->mode`, already per VM. | Removed (dead). |
|
||||
| `g_hotwords_cache` (`physics_hotwords_cache.c`) | Defined, never referenced; the live cache is per VM (`vm->hotwords_cache`). | None. |
|
||||
| `ttf_words.c` font and raster cache | Hestia's framebuffer. | None; core 0 only, per plan. |
|
||||
|
||||
**Found by the sweep:**
|
||||
|
||||
| Item | Finding | Change |
|
||||
|---|---|---|
|
||||
| `heartbeat_export.c`, three function-local statics | `heartbeat_capture_tick_snapshot()` (every beat, `vm_runtime.c`) took each VM's deltas (beats, words executed, ANOVA early exits) against whichever VM was sampled last. Wrong across VMs on one core today. The snapshot feeds `doe_log_tick_row()` only, not any decision. | The previous values move into the VM's `HeartbeatState` (`export_last_*`). |
|
||||
| TOP-WORDS (`starforth_words.c`) | A static `DictEntry *[1000]`: shared by every VM, and silently cut at 1000 words. | Sized to the heated words and allocated per call. A refusal sets `vm->error` and is logged. |
|
||||
| `inference_outputs_to_string()` | Returned a static 256-byte buffer. No callers. | Takes a caller's buffer. |
|
||||
| Failure counters: word-id refusals, transition-grow failures, WORD too long | Plain `++`. | Atomic increments and loads. |
|
||||
| `block_subsystem.c` crc64 table | Lazy init with no publish ordering; `compute_crc64()` also runs outside the block lock. | Published with release/acquire. |
|
||||
|
||||
Left as system-wide by design: `system_running` and `forth_79_standard` (`system_words.c`, system flags). `profiler_state` and `vm_debug`'s `g_vm` are hosted/diagnostic; `vm_debug` is stubbed in the kernel.
|
||||
|
||||
The vendored hosted `make` builds clean.
|
||||
|
||||
**Probe** (temporary, removed before commit). An `MC0C-PROBE` word in Hera's and every child's vocabulary:
|
||||
- listed every VM's index, and how many times it has ever been rebuilt;
|
||||
- then looked up DUP, SWAP, EMIT, BLOCK and USE in two VMs alternately, 1,000 rounds each (5,000 lookups per VM);
|
||||
- checked that every result belongs to the dictionary of the VM that was searched.
|
||||
|
||||
It ran at Hera's prompt after O-A, and again on rajames after the standard sequence. The results are identical on all three ISAs:
|
||||
|
||||
| ISA | log | every VM has its own index | Hera rebuilds (her own defines/forgets) | every other VM's rebuilds | alternating 2×5000: rebuilds / found / wrong-VM | alloc failures |
|
||||
|---|---|---|---|---|---|---|
|
||||
| amd64 | `logs/20260925-194705` | yes (7 VMs) | 85 | 2 | 0+0 / 10000 / 0 | 0 |
|
||||
| aarch64 | `logs/20260925-200019` | yes (7 VMs) | 85 | 2 | 0+0 / 10000 / 0 | 0 |
|
||||
| riscv64 | `logs/20260925-201350` | yes (7 VMs) | 85 | 2 | 0+0 / 10000 / 0 | 0 |
|
||||
|
||||
These runs' `dict_hash` values differ from the table below only because the probe adds a word.
|
||||
|
||||
**Standard sequence** (clean build, with the probe reverted; the tree is byte-identical to the saved stage diff).
|
||||
|
||||
| ISA | log | O-A (G, PREC, LOAD) | M7.1a hash | MINT / WIREBIND / USE / `1 2 + .` | idle growth | UNKNOWN / faults |
|
||||
|---|---|---|---|---|---|---|
|
||||
| amd64 | `logs/20260925-202657` | A=40 B=40, HHH, ok | `0x99b01134c3d3049c` | all ok, `3` | 0 B / 20 s | 0 / 0 |
|
||||
| aarch64 | `logs/20260925-203935` | A=40 B=40, HHH, ok | `0x99b01134c3d3049c` | all ok, `3` | 0 B / 20 s | 0 / 0 |
|
||||
| riscv64 | `logs/20260925-205238` | A=40 B=40, HHH, ok | `0x99b01134c3d3049c` | all ok, `3` | 0 B / 20 s | 0 / 0 |
|
||||
|
||||
- **The `dict_hash` set is unchanged**, as the plan's evidence requires (the index is not hashed): Hera `0x00340a8b2c842eb7`, Hestia `0x78bf28439e4a643f`, Artemis `0x66886d174d5f3b5a`.
|
||||
- The G string is byte-identical to MC-0b2, MC-0b and MC-0a on all three ISAs.
|
||||
- The ledger line is unchanged.
|
||||
- No stop condition was hit. **MC-0c done.**
|
||||
|
||||
Reference in New Issue
Block a user