doe_log.c: add vm_name/vm_id_hex identity columns; new calibration workload
Adds the identity columns HB-ON's existing per-tick CSV logger (doe_log_tick_row(), doe_log.c) was missing. Previously every column described *a* VM's state each row, but nothing said which VM emitted it -- concurrent VMs' rows were indistinguishable by source. Two new first columns, vm_name and vm_id_hex, resolved via a reverse lookup on vm->stadium_vm_id (capsule_vm_registry_get()). Real bug found and fixed while building this: the freestanding snprintf here silently prints the literal format string instead of substituting for %016llx (width+ll+hex unsupported) -- caught by reading the actual emitted row, not assumed to work. Replaced with a hand-rolled hex nibble-table loop, the same idiom vm_uuid_format()/ MINT-SCRATCH-EMIT already use. Corrects FABRIC-3.md's own prior "still not started: CSV driver" framing: no bespoke CSV emitter is needed for the multiuser DoE at all -- this per-tick logger already exists, fires automatically inside every VM's own execution loop, and just needed HB-ON plus these identity columns to be usable for concurrent workers. Also corrects doe_log.h's own stale doc comment claiming g_doe_log_enabled defaults to 1 -- doe_log.c's own source is authoritative: 0, off by default, matching the HB-ON/HB-OFF naming. One real, honest limitation recorded rather than smoothed over: vm_name reads blank for any tick captured during a WORKER-BIRTH'd capsule's own self-execution at birth time, since capsule_birth_baby() runs that work (and its heartbeat ticks) before the registry name can be set. vm_id_hex is unaffected (reads directly from vm->stadium_vm_id) and still uniquely disambiguates every row -- confirmed live: a blank-name row's own vm_id_hex matched its later PARITY:KILL line's vm_id exactly. New workload-calib1.4th: Bob confirmed the existing 10 workload-N.4th files aren't fixed. Sized to cross HEARTBEAT_CHECK_FREQUENCY (256 word-executions/tick) many times over while staying far lighter than RUN-FIB/RUN-CHAOS5, both too slow under TCG for a bounded verification run. A real, reusable addition, not a throwaway. Verified live on amd64 via a self-contained one-shot EXEC'd test (HB-ON, WORKER-BIRTH two calibration workers, HB-OFF, VM-ERROR? on both, KILL both, completion banner) rather than interactive polling, which breaks once HB-ON makes the log grow continuously via Hera/ Hermes/Artemis's own background ticks. Clean 3-arch qemu boot on the real committed change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BWpNjdwPtFLuVLaAq44L9K
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
e33eb36361
commit
41918a28a4
+53
@@ -4991,3 +4991,56 @@ no separate "load then call" step is needed for that first run, only for subsequ
|
|||||||
**Still not started:** the run-matrix/shuffle/CSV driver itself, the WIREBIND-automation path
|
**Still not started:** the run-matrix/shuffle/CSV driver itself, the WIREBIND-automation path
|
||||||
for the fixed arm, and the per-VM iteration/touch-count budget's exact value.
|
for the fixed arm, and the per-VM iteration/touch-count budget's exact value.
|
||||||
|
|
||||||
|
### XXXIII.5 -- CSV already exists: HB-ON/doe_log.c, plus identity columns (2026-09-16)
|
||||||
|
|
||||||
|
**Correction to XXXIII.4's own "still not started" list:** no bespoke CSV emitter is needed at
|
||||||
|
all. `doe_log.c`'s `doe_log_tick_row()` already streams a 26-column CSV row to the serial log
|
||||||
|
on every heartbeat tick, for every live VM (fires automatically inside every VM's own
|
||||||
|
execution loop, `vm_core.c:908`, no thread or opt-in required) -- entirely independent of
|
||||||
|
`doe.4th`'s own separate single-VM campaign mechanism. Gated by `g_doe_log_enabled`, toggled by
|
||||||
|
the existing `HB-ON`/`HB-OFF` FORTH words. **`doe_log.h`'s own doc comment claiming this
|
||||||
|
defaults to 1 is stale** -- `doe_log.c:97` is authoritative: `g_doe_log_enabled = 0`, off by
|
||||||
|
default, exactly matching the `HB-ON`/`HB-OFF` naming. (This also resolves the open question
|
||||||
|
from §XXXIII.1: the mystery per-boot `doe-<arch>-*.csv` this whole session was *not* this
|
||||||
|
per-tick logger -- confirmed off by default -- so it must be `doe.4th`'s own separate
|
||||||
|
mechanism, still unexplained but now correctly ruled out as unrelated.)
|
||||||
|
|
||||||
|
**Gap found and fixed before this was usable for concurrent VMs:** the existing 26-column
|
||||||
|
schema had no column identifying *which* VM emitted a row -- columns for Hera/Hermes/Artemis's
|
||||||
|
own heat are hardcoded by name, but nothing said whose tick this was. Added two columns,
|
||||||
|
`vm_name` and `vm_id_hex` (both prepended, first two columns), resolved via a reverse lookup
|
||||||
|
on `vm->stadium_vm_id` (`capsule_vm_registry_get()`). `vm_id_hex` is formatted by hand
|
||||||
|
(nibble-table loop, same idiom `vm_uuid_format()`/`MINT-SCRATCH-EMIT` already use) after
|
||||||
|
finding live that this freestanding `snprintf` silently prints the literal format string
|
||||||
|
instead of substituting for `%016llx` (width+`ll`+hex unsupported) -- caught by reading the
|
||||||
|
actual emitted row, not assumed to work from the header comment's own claim.
|
||||||
|
|
||||||
|
**One real, honest limitation found live, not silently smoothed over:** `vm_name` reads blank
|
||||||
|
for any tick captured *during* a workload capsule's own self-execution at birth time --
|
||||||
|
`WORKER-BIRTH` calls `capsule_birth_baby()` (which runs the capsule's self-executing workload,
|
||||||
|
and thus its heartbeat ticks, synchronously and internally) *before* `capsule_vm_registry_set_
|
||||||
|
name()` can run, so the name genuinely doesn't exist yet at the moment those early rows are
|
||||||
|
captured. `vm_id_hex` is unaffected (read directly from `vm->stadium_vm_id`, no registry
|
||||||
|
lookup needed) and correctly disambiguates every row regardless -- confirmed live: a blank-name
|
||||||
|
row's own `vm_id_hex` matched its later `PARITY:KILL` line's `vm_id` exactly. Rows remain fully
|
||||||
|
attributable to a specific worker by ID even when the name column is momentarily empty; a
|
||||||
|
post-processing script correlating by `vm_id_hex` (not `vm_name`) is the correct approach, not
|
||||||
|
a workaround for a broken mechanism.
|
||||||
|
|
||||||
|
**New workload added, not a throwaway:** `workload-calib1.4th` -- Captain Bob confirmed the
|
||||||
|
existing 10 `workload-N.4th` files aren't fixed, extend as needed. Sized specifically to cross
|
||||||
|
`HEARTBEAT_CHECK_FREQUENCY` (256 word-executions/tick) many times over while staying far
|
||||||
|
lighter than `RUN-FIB` (100,000 iters) or `RUN-CHAOS5` (1,000,000 iters), both of which proved
|
||||||
|
too slow under TCG for a bounded interactive verification run. A real, reusable addition to the
|
||||||
|
workload set, not reverted.
|
||||||
|
|
||||||
|
**Verified live on amd64, self-contained (not interactive polling):** wrote a one-shot test
|
||||||
|
capsule (`RUN-IDENTITY-TEST`: `HB-ON`, `WORKER-BIRTH` two calibration workers, `HB-OFF`,
|
||||||
|
`VM-ERROR?` on both, `KILL` both, print a completion banner) and ran it as a single `EXEC`
|
||||||
|
call, waiting for its own "IDENTITY-TEST: complete" banner rather than polling per-command --
|
||||||
|
the same self-contained-driver pattern `doe.4th`'s own `DOE` word already uses, avoiding the
|
||||||
|
interactive `wait_for_prompt`-by-log-stability heuristic that breaks once `HB-ON` makes the log
|
||||||
|
grow continuously via Hera/Hermes/Artemis's own background ticks. Confirmed: banner printed,
|
||||||
|
both workers reported no error, both killed cleanly, Hera stayed healthy throughout
|
||||||
|
(`5 6 + .` -> `11`). Test capsule reverted after capture; `workload-calib1.4th` kept.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Capsule Block Manifest — Auto-generated
|
# Capsule Block Manifest — Auto-generated
|
||||||
<!-- Generated by mkcapsule --manifest 2026-09-16T12:48:45Z -->
|
<!-- Generated by mkcapsule --manifest 2026-09-16T13:47:26Z -->
|
||||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||||
<!-- Hand-written justifications and immutability notes live -->
|
<!-- Hand-written justifications and immutability notes live -->
|
||||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
| `workload-7.4th` | 2150 | `0x02862291387eb7ac` | yes |
|
| `workload-7.4th` | 2150 | `0x02862291387eb7ac` | yes |
|
||||||
| `workload-8.4th` | 2160 | `0x56b7f2f0efa000df` | yes |
|
| `workload-8.4th` | 2160 | `0x56b7f2f0efa000df` | yes |
|
||||||
| `workload-9.4th` | 4706, 4715, 4725, 4735, 4745 | `0x3f2bec73142aa424` | yes |
|
| `workload-9.4th` | 4706, 4715, 4725, 4735, 4745 | `0x3f2bec73142aa424` | yes |
|
||||||
|
| `workload-calib1.4th` | 5043 | `0x3b9f2d17b554fabc` | yes |
|
||||||
| `zuse-eligibility.4th` | 4021, 4022 | `0x8b49c1bc1e01dc58` | yes |
|
| `zuse-eligibility.4th` | 4021, 4022 | `0x8b49c1bc1e01dc58` | yes |
|
||||||
| `zuse.4th` | 4016, 4017, 4018 | `0x490ded9be257a90b` | yes |
|
| `zuse.4th` | 4016, 4017, 4018 | `0x490ded9be257a90b` | yes |
|
||||||
|
|
||||||
@@ -371,6 +372,7 @@
|
|||||||
| 5040 | `common:messaging.4th` | `0x201cfd6d39fcb22d` | ok |
|
| 5040 | `common:messaging.4th` | `0x201cfd6d39fcb22d` | ok |
|
||||||
| 5041 | `common:messaging.4th` | `0x201cfd6d39fcb22d` | ok |
|
| 5041 | `common:messaging.4th` | `0x201cfd6d39fcb22d` | ok |
|
||||||
| 5042 | `common:messaging.4th` | `0x201cfd6d39fcb22d` | ok |
|
| 5042 | `common:messaging.4th` | `0x201cfd6d39fcb22d` | ok |
|
||||||
|
| 5043 | `workload-calib1.4th` | `0x3b9f2d17b554fabc` | ok |
|
||||||
| 5100 | `turtle.4th` | `0x4d470418ca543365` | ok |
|
| 5100 | `turtle.4th` | `0x4d470418ca543365` | ok |
|
||||||
| 5101 | `turtle.4th` | `0x4d470418ca543365` | ok |
|
| 5101 | `turtle.4th` | `0x4d470418ca543365` | ok |
|
||||||
| 5102 | `turtle.4th` | `0x4d470418ca543365` | ok |
|
| 5102 | `turtle.4th` | `0x4d470418ca543365` | ok |
|
||||||
@@ -394,4 +396,4 @@
|
|||||||
None.
|
None.
|
||||||
|
|
||||||
---
|
---
|
||||||
*35 capsule(s) scanned. Re-run `mkcapsule --manifest <dir>` to refresh.*
|
*36 capsule(s) scanned. Re-run `mkcapsule --manifest <dir>` to refresh.*
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
Block 5043
|
||||||
|
( workload-calib1.4th -- DoE calibration workload, SXXXIII. )
|
||||||
|
( Crosses HEARTBEAT_CHECK_FREQUENCY (256) many times over, )
|
||||||
|
( but far lighter than RUN-FIB/RUN-CHAOS5 -- fast under TCG. )
|
||||||
|
: CALIB-CHUNK
|
||||||
|
8 0 DO
|
||||||
|
I 1+ DROP
|
||||||
|
LOOP
|
||||||
|
;
|
||||||
|
: RUN-CALIB1
|
||||||
|
2000 0 DO
|
||||||
|
CALIB-CHUNK
|
||||||
|
LOOP
|
||||||
|
;
|
||||||
|
RUN-CALIB1
|
||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -10,13 +10,29 @@
|
|||||||
/**
|
/**
|
||||||
* doe_log.c — DoE CSV logger for the LithosAnanke kernel
|
* doe_log.c — DoE CSV logger for the LithosAnanke kernel
|
||||||
*
|
*
|
||||||
* Emits 20-column CSV rows to the serial log once per heartbeat tick.
|
* Emits CSV rows to the serial log once per heartbeat tick. Each row is
|
||||||
* Each row is prefixed with a cyan [HADES][DOE ] tag so it can be
|
* prefixed with a cyan [HADES][DOE ] tag so it can be extracted cleanly:
|
||||||
* extracted cleanly:
|
|
||||||
*
|
*
|
||||||
* grep -aP '\[HADES\]\[DOE \]' qemu-amd64-*.log
|
* grep -aP '\[HADES\]\[DOE \]' qemu-amd64-*.log
|
||||||
*
|
*
|
||||||
* Columns (in order):
|
* Columns (in order):
|
||||||
|
* 0a. vm_name string — the emitting VM's own registry name
|
||||||
|
* (reverse lookup on vm->stadium_vm_id,
|
||||||
|
* "?" if unregistered at this tick).
|
||||||
|
* Added 2026-09-16 for the multiuser/
|
||||||
|
* multitasking DoE (FABRIC-3.md
|
||||||
|
* §XXXIII): every prior column already
|
||||||
|
* described *a* VM's state each row,
|
||||||
|
* but nothing said *which* VM emitted
|
||||||
|
* it, making concurrent-VM rows
|
||||||
|
* indistinguishable by source.
|
||||||
|
* 0b. vm_id_hex string — the emitting VM's own stadium_vm_id
|
||||||
|
* as "hi-lo" hex, same format
|
||||||
|
* PARITY:BIRTH/PARITY:KILL already
|
||||||
|
* print. Names get reused across a
|
||||||
|
* trial's own KILL+rebirth cycles;
|
||||||
|
* this is the one column unique to a
|
||||||
|
* single birth instance.
|
||||||
* 1. tick_number uint32 — monotonic heartbeat counter
|
* 1. tick_number uint32 — monotonic heartbeat counter
|
||||||
* 2. elapsed_ns uint64 — ns since run start
|
* 2. elapsed_ns uint64 — ns since run start
|
||||||
* 3. tick_interval_ns uint64 — actual interval from prior tick
|
* 3. tick_interval_ns uint64 — actual interval from prior tick
|
||||||
@@ -101,6 +117,7 @@ int g_doe_log_enabled = 0; /* off by default -- HB-ON to enable, per instruction
|
|||||||
|
|
||||||
static const char *doe_header =
|
static const char *doe_header =
|
||||||
DOE_PREFIX
|
DOE_PREFIX
|
||||||
|
"vm_name,vm_id_hex,"
|
||||||
"tick_number,elapsed_ns,tick_interval_ns,"
|
"tick_number,elapsed_ns,tick_interval_ns,"
|
||||||
"cache_hits_delta,bucket_hits_delta,word_executions_delta,"
|
"cache_hits_delta,bucket_hits_delta,word_executions_delta,"
|
||||||
"hot_word_count,avg_word_heat_q48,"
|
"hot_word_count,avg_word_heat_q48,"
|
||||||
@@ -154,6 +171,38 @@ void doe_log_tick_row(VM *vm, const HeartbeatTickSnapshot *snap)
|
|||||||
* for values > 2^32 on aarch64 due to mixed-width varargs ABI behaviour. */
|
* for values > 2^32 on aarch64 due to mixed-width varargs ABI behaviour. */
|
||||||
unsigned vm_call_depth_max = (vm && vm->call_stack_max > 0) ? (unsigned)vm->call_stack_max : 0;
|
unsigned vm_call_depth_max = (vm && vm->call_stack_max > 0) ? (unsigned)vm->call_stack_max : 0;
|
||||||
|
|
||||||
|
/* Identity columns (2026-09-16, FABRIC-3.md §XXXIII): reverse-lookup
|
||||||
|
* this row's own emitting VM by its stadium_vm_id -- name can be
|
||||||
|
* reused across a KILL+rebirth cycle, so vm_id_hex is what actually
|
||||||
|
* disambiguates one birth instance from the next. "?" name / all-zero
|
||||||
|
* id if vm is NULL or not (yet) registered, never a crash. */
|
||||||
|
const char *vm_name = "?";
|
||||||
|
char vm_id_hex[34] = "0000000000000000-0000000000000000";
|
||||||
|
if (vm) {
|
||||||
|
VMRegistryEntry self_entry;
|
||||||
|
if (capsule_vm_registry_get(vm->stadium_vm_id, &self_entry) == 0) {
|
||||||
|
vm_name = self_entry.name;
|
||||||
|
}
|
||||||
|
/* Hand-rolled hex, not snprintf("%016llx", ...) -- found live
|
||||||
|
* (2026-09-16) that this freestanding snprintf doesn't support
|
||||||
|
* width+ll+x and silently prints the literal format string
|
||||||
|
* instead of substituting. Same nibble-table idiom vm_uuid.c's
|
||||||
|
* own vm_uuid_format() and MINT-SCRATCH-EMIT already use. */
|
||||||
|
{
|
||||||
|
static const char hexd[] = "0123456789abcdef";
|
||||||
|
uint64_t halves[2] = { vm->stadium_vm_id.hi, vm->stadium_vm_id.lo };
|
||||||
|
int pos = 0, h;
|
||||||
|
for (h = 0; h < 2; h++) {
|
||||||
|
int i;
|
||||||
|
for (i = 15; i >= 0; i--) {
|
||||||
|
vm_id_hex[pos++] = hexd[(halves[h] >> (i * 4)) & 0xF];
|
||||||
|
}
|
||||||
|
if (h == 0) vm_id_hex[pos++] = '-';
|
||||||
|
}
|
||||||
|
vm_id_hex[pos] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t hera_heat_q48 = doe_log_heat_by_name("Hera");
|
uint64_t hera_heat_q48 = doe_log_heat_by_name("Hera");
|
||||||
uint64_t hermes_heat_q48 = doe_log_heat_by_name("Hermes");
|
uint64_t hermes_heat_q48 = doe_log_heat_by_name("Hermes");
|
||||||
uint64_t artemis_heat_q48 = doe_log_heat_by_name("Artemis");
|
uint64_t artemis_heat_q48 = doe_log_heat_by_name("Artemis");
|
||||||
@@ -180,8 +229,11 @@ void doe_log_tick_row(VM *vm, const HeartbeatTickSnapshot *snap)
|
|||||||
|
|
||||||
char buf[DOE_BUF_SIZE];
|
char buf[DOE_BUF_SIZE];
|
||||||
snprintf(buf, sizeof(buf),
|
snprintf(buf, sizeof(buf),
|
||||||
|
"%s,%s,"
|
||||||
"%u,%llu,%llu,%u,%u,%u,%llu,%llu,%u,%u,%u,%llu,%llu,%llu,%llu,%u,%llu,%llu,%llu,%llu,%u,"
|
"%u,%llu,%llu,%u,%u,%u,%llu,%llu,%u,%u,%u,%llu,%llu,%llu,%llu,%u,%llu,%llu,%llu,%llu,%u,"
|
||||||
"%llu,%u,%u,%u,%u,%u",
|
"%llu,%u,%u,%u,%u,%u",
|
||||||
|
vm_name,
|
||||||
|
vm_id_hex,
|
||||||
snap->tick_number,
|
snap->tick_number,
|
||||||
(unsigned long long)snap->elapsed_ns,
|
(unsigned long long)snap->elapsed_ns,
|
||||||
(unsigned long long)snap->tick_interval_ns,
|
(unsigned long long)snap->tick_interval_ns,
|
||||||
|
|||||||
Reference in New Issue
Block a user