feat(kernel): v4 boots in the kernel's boot -- the Stadium, its checks, the opcode patrons
#189, ENGINE step 4, Phase 1 (plan 2026-11-13-engine-step4-phase1), Tasks 1-4. Captain Bob, 2026-11-13: Q1 "A new node key", Q2 "Per heartbeat tick", Q3 "All of v3's", Q4 "In Phase 1" / "Full births now", who runs next "Hera by compudynamics now" (Task 5, to come). - stadium.c/.h: stadium_node_key(node) ("NODE" | number), stadium_boot_init_for(first), stadium_birth_node(key, name); stadium_boot_init() and stadium_birth_hera() are them for Hera's key, so v3's path is as it was (only an impossible panic's words changed). - kernel_main.c: the system is chosen and said first, then the Stadium, sessions, switch-signal and kernel-Hermes tables for both systems in v3's order; v4: Hera, node 10, patron zero under her node key, the word, block and opcode layers. The quota self-test and the heartbeat's line are functions now, called by both systems. - sk_v4.c/.h: sk_v4_run() goes -- sk_v4_boot() returns, the kernel's checks after POST (opcodes, words, conservation, quota, heartbeat), then sk_v4_prompt(). sk_v4_charge_opcodes() at the heartbeat's service points (the key wait, after each line) and once after POST. - stadium_ops.c/.h: a node's 32 opcodes as Stadium patrons (HEAT-OP's feed, "Both"): retirements charged as the word layer's dispatches, a quantum each, the reservoir's floor kept, shared by retirements when short; cooling per tick as words. ~0.5 us a charge on the host: kept. - qemu_session.py: a v4 acceptance boot fails without "Stadium: N cells", "Stadium conservation: CONSERVED" and the heartbeat's ticks (#189). Tests first (logs/20261113-122142): the physics check failed on the v4 boot; test_stadium_node, test_stadium_ops (and its share case, after a real boot showed ";" taking all the heat) failed before. Now: kernel host tests all pass; amd64 v4 boot passes, POST 539/539, dict_hash unchanged, "Stadium opcodes: 30 resident, hottest opcode 8", CONSERVED; a system=v3 boot prints its Stadium lines as on 2026-11-06. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
This commit is contained in:
@@ -0,0 +1,170 @@
|
|||||||
|
# ENGINE Step 4, Phase 1: v4 in the kernel's boot -- Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** steps use checkbox (`- [ ]`) syntax. One QEMU at a time, in the foreground
|
||||||
|
> (`.claude/CLAUDE.md`); every log and CSV is committed.
|
||||||
|
|
||||||
|
**Goal (#189):** on bare metal, v4 boots *in* the kernel's boot, not before it: the kernel's own order,
|
||||||
|
as v3's -- hardware, the heartbeat, **the Stadium**, then the v4 system on the first node (Hera) with
|
||||||
|
POST, then the devices, then the prompt -- and the Stadium holds Hera from the start, so that Phase 2
|
||||||
|
can feed it every word Hera calls. `sk_v4_run()`, which today takes the boot before the Stadium is
|
||||||
|
made and never returns (`kernel_main.c:647`), goes.
|
||||||
|
|
||||||
|
**Parent plan:** `2026-10-20-engine-step4-node-in-the-vms-place.md`, Phase 1 (rows 1, 2, 5, 6 and 9 of
|
||||||
|
`V3-PARITY.md` section 1). Order ruled 2026-11-12 (Captain Bob, #189): Part A (done), Phase 1, Phase 2,
|
||||||
|
then Phase 7. HEAT-OP's Stadium feed was ruled into this phase ("Both": the registers now -- built
|
||||||
|
2026-11-12 -- and the Stadium feed in Phase 1, measured, kept or reverted on the numbers).
|
||||||
|
|
||||||
|
## What a v4 boot does today, and what v3's does
|
||||||
|
|
||||||
|
| | v3 (`system=v3`) | v4 today |
|
||||||
|
|---|---|---|
|
||||||
|
| Heartbeat | started (`kernel_main_deep`) | started -- the same code, before the choice |
|
||||||
|
| The Stadium | `stadium_boot_init`, `session_boot_init`, `stadium_birth_hera`, `stadium_words_init`, `stadium_blocks_init` -- "Stadium: 83886 cells (5242 KB), 50 VM slots" | **never made**: `sk_v4_run()` is called before it and does not return |
|
||||||
|
| The system | the v3 VM, POST | one node, POST (`v4_boot_run`) |
|
||||||
|
| The checks after POST | "Stadium words: promotions=...", "Stadium conservation: ... CONSERVED", "Stadium quota grant self-test: OK", "Heartbeat: N ticks" | none |
|
||||||
|
| Devices | PCI, the disk | the block chain, after POST (`sk_v4_block_chain`) |
|
||||||
|
| The prompt | `sk_repl()` | `sk_v4_run()`'s own loop |
|
||||||
|
|
||||||
|
## Rulings (Captain Bob, 2026-11-13)
|
||||||
|
|
||||||
|
- **Q1: "A new node key."** The Stadium is keyed by v4 node number now, ahead of the fleet -- not by
|
||||||
|
`vm_uuid_hera()`. A node's key is made from its number (`stadium_node_key(node)`, a `VMUuid` that
|
||||||
|
no v3 VM can have); the node the kernel brings up first, Hera -- node 10, as the hosted mesh numbers
|
||||||
|
her (`test_host_unit.c`: "it is told it is 10") -- is patron zero under her key. v3's path keeps
|
||||||
|
`vm_uuid_hera()` and `stadium_birth_hera()` unchanged (`MACHINE.md` 7 item 3); the v4 path gets
|
||||||
|
`stadium_birth_node(key)`, the same birth for a key it is given.
|
||||||
|
- **Q2: per heartbeat tick**, as recommended.
|
||||||
|
- **Q3: "All of v3's."** A v4 boot runs every boot check v3's does that is not v3's VM itself: the
|
||||||
|
Stadium, the session table, the switch-signal table, kernel-Hermes' channels and queues, Hera's
|
||||||
|
birth, the word and block layers; and after POST the conservation check, the quota grant self-test
|
||||||
|
and the heartbeat's tick line.
|
||||||
|
- **Q4: "In Phase 1."** The registry (`v4/src/manage.c`) comes into the kernel build in this phase:
|
||||||
|
Task 5 is in. Asked how much -- it needs a fabric of nodes, births that make them, and who runs
|
||||||
|
next (`ENGINE.md` 6, open) -- **"Full births now."**
|
||||||
|
- **Who runs next (`ENGINE.md` 6): "Hera by compudynamics now."** As v3's turn-attractor, agreed
|
||||||
|
with Captain Bob (`FABRIC-3.md`, the turn-attractor: "the next turn to whichever live identity VM
|
||||||
|
currently has the lowest `execution_heat_q48` ... No priority levels, no time slices, no
|
||||||
|
preemption -- the same density comparison Stadium already uses"): the next instruction word goes
|
||||||
|
to the **coolest awake node** that can run, by its resident heat in the Stadium -- its opcode
|
||||||
|
patrons (Task 3) until Phase 2 adds its words. Switching only between instruction words
|
||||||
|
(`ENGINE.md` 3a). A node asleep at its wires, or blocked, is not a candidate.
|
||||||
|
|
||||||
|
## Questions (as they were put)
|
||||||
|
|
||||||
|
**Q1. Hera's place in the Stadium.** *Recommend:* the v4 node is Hera, patron zero, under
|
||||||
|
`vm_uuid_hera()`: `stadium_birth_hera()` as v3 has it, and its session. The Stadium's own code is the
|
||||||
|
kernel's and unchanged (Q3 of 2026-10-20: "keyed by node number where they are keyed by VM today" --
|
||||||
|
with one node, Hera's UUID is that key until the fleet, Phase 5 onward).
|
||||||
|
|
||||||
|
**Q2. The opcode patrons: how a count becomes heat.** The Stadium's heat is a conserved share of 1.0,
|
||||||
|
not a count. *Recommend:* 32 opcode patrons for the node, one per opcode, admitted at boot as the word
|
||||||
|
layer admits words (`stadium_words.c`), behaviour `COOL`; **at each heartbeat tick, not at each
|
||||||
|
instruction**, each opcode's retirements since the last tick (`v4_heat.op[k]`'s delta) are charged as
|
||||||
|
that many of the word layer's dispatches -- the same pull from the node's reservoir, the same cooling
|
||||||
|
per tick -- in one step. Per instruction it would be a kernel call per instruction (the "huge
|
||||||
|
performance hit" the ruling allows to be reverted); per tick it is 32 sums a tick. Measured either way
|
||||||
|
(Task 3). *If not:* charged per instruction, at the hook in `v4/src/exec.c` -- then measured, and
|
||||||
|
reverted if it is the hit.
|
||||||
|
|
||||||
|
**Q3. Which of v3's boot checks a v4 boot runs.** *Recommend:* those of the Stadium and the heartbeat,
|
||||||
|
which are the kernel's: the Stadium's allocation, Hera's birth, the word and block layers, and after
|
||||||
|
POST the conservation check (`stadium_words_print_boot_diagnostics`), the quota grant self-test and the
|
||||||
|
heartbeat's tick line. Not v3's switch-signal table, kernel-Hermes' channels and queues, or the v3 VM's
|
||||||
|
own Stadium step lines: they are a v3 VM's (Q1 of 2026-10-20: Hermes is v4's wires, not
|
||||||
|
`kernel_hermes.c`).
|
||||||
|
|
||||||
|
**Q4. The registry (`v4/src/manage.c`, MESH step 9) in this phase or after alpha.5.** The parent plan
|
||||||
|
puts it in Phase 1; the physics does not need it -- one node, Hera, is enough for Phases 2 and 7.
|
||||||
|
*Recommend:* after alpha.5, with the fleet (Phase 5 onward), to keep #189's path short. *If not:* Task 5
|
||||||
|
below.
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
|
||||||
|
### Task 1: The Stadium before the system
|
||||||
|
|
||||||
|
**Files:** `kernel/src/kernel_main.c`. Test: the amd64 boot (an acceptance check, Task 4).
|
||||||
|
|
||||||
|
- [ ] **Step 1: Seen to fail first:** the acceptance check of Task 4, on today's build: a v4 boot has no
|
||||||
|
"Stadium: ... cells" line.
|
||||||
|
- [ ] **Step 2:** `stadium_boot_init`, `session_boot_init`, `sk_vm_switch_signal_boot_init`,
|
||||||
|
`sk_hermes_channels_boot_init`, `sk_hermes_queues_boot_init` move above the choice of system -- the
|
||||||
|
kernel's, for both systems, in v3's order (Q3). Then on v3's path `stadium_birth_hera()` as today; on
|
||||||
|
v4's, `stadium_birth_node(stadium_node_key(10))` (Q1, a failing host test first:
|
||||||
|
`kernel/tests/test_stadium_node.c` -- the key is no v3 VM's, the node lands on cell 0, its session is
|
||||||
|
registered and pinned). Then `stadium_words_init` and `stadium_blocks_init`. v3's path is otherwise
|
||||||
|
unchanged (`MACHINE.md` 7 item 3): the same calls, in the same order, before its VM.
|
||||||
|
- [ ] **Step 3:** the three boots and the stick, v4: "Stadium: N cells (... KB), 50 VM slots" before
|
||||||
|
the system starts; POST and `dict_hash` unchanged (the node is not touched). One `system=v3` boot,
|
||||||
|
for v3's path: the same lines it printed before.
|
||||||
|
|
||||||
|
### Task 2: `sk_v4_run()` goes
|
||||||
|
|
||||||
|
**Files:** `kernel/src/v4/sk_v4.c`, `kernel/include/starkernel/v4/sk_v4.h`, `kernel/src/kernel_main.c`.
|
||||||
|
|
||||||
|
- [ ] **Step 1:** `sk_v4_run()` becomes two: `sk_v4_boot()` -- the node, POST, the blocks, the
|
||||||
|
identity; it returns -- and `sk_v4_prompt()`, the prompt loop, which does not. The kernel calls them
|
||||||
|
in its own order: the Stadium (Task 1), `sk_v4_boot()`, the checks after POST (Q3), then
|
||||||
|
`sk_v4_prompt()`.
|
||||||
|
- [ ] **Step 2:** the checks after POST on v4, under Hera's node key: "Stadium words: ...", "Stadium
|
||||||
|
conservation: ... CONSERVED", "Stadium quota grant self-test: OK", the heartbeat's tick line (Q3).
|
||||||
|
- [ ] **Step 3:** the three boots and the stick: those lines, then `[zuse@Hera] ok> `; POST and
|
||||||
|
`dict_hash` unchanged.
|
||||||
|
|
||||||
|
### Task 3: The opcode patrons (HEAT-OP into the Stadium), measured
|
||||||
|
|
||||||
|
**Files:** `kernel/src/vm/stadium_ops.c` (new), its header, `kernel/src/v4/sk_v4.c` (the tick).
|
||||||
|
Test: `kernel/tests/test_stadium_ops.c` (the host harness, `make -C kernel/tests`), with the Stadium's
|
||||||
|
own sources.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Failing test:** 32 patrons admitted for a node; N retirements of an opcode between two
|
||||||
|
ticks heat its patron as N of the word layer's dispatches would; the sum of the node's resident heat
|
||||||
|
and its reservoir stays 1.0 (`stadium_conserved`); no retirements, no heat; cooling per tick as words.
|
||||||
|
- [ ] **Step 2:** `stadium_ops.c`, as ruled in Q2; the heartbeat's tick charges the deltas.
|
||||||
|
- [ ] **Step 3:** a line after POST, "Stadium opcodes: ..." (the hottest opcodes), and conservation
|
||||||
|
still CONSERVED with them in.
|
||||||
|
- [ ] **Step 4: Measured:** the amd64 boot's time and POST's instruction count, with and without the
|
||||||
|
feed, five boots each -- recorded in the commit. Kept, or reverted on the numbers (Captain Bob,
|
||||||
|
2026-11-12).
|
||||||
|
|
||||||
|
### Task 4: Acceptance asserts it
|
||||||
|
|
||||||
|
**Files:** `scripts/qemu_session.py` (the v4 boot's checks), `scripts/nightly.sh` (the stages read them).
|
||||||
|
|
||||||
|
- [ ] **Step 1:** a v4 acceptance boot must show "Stadium: ... cells", "Stadium conservation: ...
|
||||||
|
CONSERVED" and the heartbeat's line before its prompt; one without them fails (#189 Done when, third
|
||||||
|
item: "a boot without the physics fails"). Seen to fail on today's build (Task 1 Step 1).
|
||||||
|
- [ ] **Step 2:** the protocol, all eight stages; then the push, on Captain Bob's word.
|
||||||
|
|
||||||
|
### Task 5: the registry and births (Q4: "Full births now")
|
||||||
|
|
||||||
|
Each its own increment, each test first, each a boot:
|
||||||
|
|
||||||
|
- [ ] **5a. A fabric in the kernel, Hera in it.** `v4/src/fabric.c` and `manage.c` into the kernel
|
||||||
|
build; Hera, node 10, at a place of a kernel fabric, entered in the registry; the prompt's lines go
|
||||||
|
to her through it. `centre.4th` and `hera.4th` loaded on her: `NODE-ME` answers her place (word
|
||||||
|
count and `dict_hash` change).
|
||||||
|
- [ ] **5b. Births.** `NODE-BORN`: room for a node from the kernel's heap, a place in the fabric, a
|
||||||
|
Stadium quota granted from Hera's under the new node's key (`stadium_node_key(number)`), its
|
||||||
|
opcode patrons; `NODE-KILL` gives the room and the quota back. The capsule words
|
||||||
|
(`CAPSULE-OPEN/-CELL/-LINE`) from the kernel's capsule directory.
|
||||||
|
- [ ] **5c. Who runs next.** The turn-attractor: each step, the coolest awake node that can run
|
||||||
|
executes an instruction word; the opcode charge for every node at the heartbeat's service points.
|
||||||
|
A test that two busy nodes take turns as their heat says, and a sleeping node is never chosen.
|
||||||
|
- [ ] **5d. Acceptance.** A boot births a node from Hera, it answers a line, Hera kills it, and the
|
||||||
|
Stadium is CONSERVED after.
|
||||||
|
|
||||||
|
## What this phase does not do
|
||||||
|
|
||||||
|
Phase 2 (the word accounts at `call`: the kernel's record per word, `execution_heat`,
|
||||||
|
`stadium_word_dispatch`, the ACL's countdown) and Phase 7 (decay, the rolling window, pipelining,
|
||||||
|
inference, L8 on those records). After Phase 1 the Stadium holds Hera and her 32 opcode patrons, and
|
||||||
|
nothing yet of her words.
|
||||||
|
|
||||||
|
## Review focus
|
||||||
|
|
||||||
|
1. **v3's path:** a `system=v3` boot prints what it printed before, in the same order.
|
||||||
|
2. **The 32-bit build and the stick:** the Stadium's allocation fits the stick loaded high as it does
|
||||||
|
at 2 GiB.
|
||||||
|
3. **Conservation with the opcodes in:** K = 1.0 after POST, before the prompt.
|
||||||
|
4. **The tick's cost:** with the feed, the heartbeat still keeps its rate (its tick line's count against
|
||||||
|
the boot's time).
|
||||||
@@ -693,6 +693,7 @@ LOADER_EXTRA_SRCS := \
|
|||||||
$(KERNEL_SRC)/vm/q48_stubs.c \
|
$(KERNEL_SRC)/vm/q48_stubs.c \
|
||||||
$(KERNEL_SRC)/vm/stadium.c \
|
$(KERNEL_SRC)/vm/stadium.c \
|
||||||
$(KERNEL_SRC)/vm/stadium_words.c \
|
$(KERNEL_SRC)/vm/stadium_words.c \
|
||||||
|
$(KERNEL_SRC)/vm/stadium_ops.c \
|
||||||
$(KERNEL_SRC)/vm/stadium_blocks.c \
|
$(KERNEL_SRC)/vm/stadium_blocks.c \
|
||||||
$(KERNEL_SRC)/vm/session.c \
|
$(KERNEL_SRC)/vm/session.c \
|
||||||
$(KERNEL_SRC)/vm/kernel_hermes.c \
|
$(KERNEL_SRC)/vm/kernel_hermes.c \
|
||||||
|
|||||||
@@ -10,13 +10,27 @@
|
|||||||
|
|
||||||
#include "uefi.h" /* BootDisk */
|
#include "uefi.h" /* BootDisk */
|
||||||
|
|
||||||
/* Start one StarForth v4 host node from the capsule image linked into the
|
/* Hera's node number: the first node the kernel brings up, as the hosted mesh numbers her
|
||||||
* kernel, with its console on the kernel's console, and run it. Does not
|
* (v4/tests/test_host_unit.c: "it is told it is 10"). The Stadium is keyed by it (#189). */
|
||||||
* return. */
|
#define SK_V4_HERA_NODE 10u
|
||||||
/* `chain` sets the kernel's block chain up. It is called when the node has
|
|
||||||
* booted and passed POST, before the prompt: as on the v3 path, POST runs
|
/* Bring one StarForth v4 host node up from the capsule image linked into the
|
||||||
* against block RAM of its own and the chain comes after it. `boot_disk` is
|
* kernel, with its console on the kernel's console: the node, POST, the
|
||||||
* the loader's: which disk it booted from (sk_v4_identity_boot()). */
|
* blocks, the identity. It returns; a node that does not start stops the
|
||||||
void sk_v4_run(void (*chain)(void), const BootDisk *boot_disk);
|
* machine. `chain` sets the kernel's block chain up: it is called when the
|
||||||
|
* node has booted and passed POST, before the prompt -- as on the v3 path,
|
||||||
|
* POST runs against block RAM of its own and the chain comes after it.
|
||||||
|
* `boot_disk` is the loader's: which disk it booted from
|
||||||
|
* (sk_v4_identity_boot()). */
|
||||||
|
void sk_v4_boot(void (*chain)(void), const BootDisk *boot_disk);
|
||||||
|
|
||||||
|
/* The prompt: read a line, hand it to the node, say how it ended. Does not
|
||||||
|
* return. The kernel calls it after sk_v4_boot() and its own checks (#189,
|
||||||
|
* ENGINE.md step 4, Phase 1: sk_v4_run() went). */
|
||||||
|
void sk_v4_prompt(void);
|
||||||
|
|
||||||
|
/* Charge the node's opcode counts to its opcode patrons in the Stadium (#189; stadium_ops.h). The
|
||||||
|
* prompt does it as it waits and after each line; the kernel once after sk_v4_boot(). */
|
||||||
|
void sk_v4_charge_opcodes(void);
|
||||||
|
|
||||||
#endif /* STARKERNEL_V4_SK_V4_H */
|
#endif /* STARKERNEL_V4_SK_V4_H */
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* SPDX-License-Identifier: LicenseRef-Starship-1.0
|
/* SPDX-License-Identifier: LicenseRef-Starship-1.0
|
||||||
* Copyright (c) 2023-2026 Robert A. James
|
* Copyright (c) 2023-2026 Robert A. James
|
||||||
*/
|
*/
|
||||||
/* sk_v4_stop.h -- the v4 kernel's fatal stop (#177): what sk_v4_run does when the system cannot
|
/* sk_v4_stop.h -- the v4 kernel's fatal stop (#177): what sk_v4_boot and sk_v4_prompt do when the system cannot
|
||||||
* go on ("not started", "did not let go of POST's blocks", "stopped on a fault"). Never returns.
|
* go on ("not started", "did not let go of POST's blocks", "stopped on a fault"). Never returns.
|
||||||
*/
|
*/
|
||||||
#ifndef STARKERNEL_V4_SK_V4_STOP_H
|
#ifndef STARKERNEL_V4_SK_V4_STOP_H
|
||||||
|
|||||||
@@ -180,6 +180,21 @@ typedef char stadium_capacity_tick_configured_check[(STADIUM_CAPACITY_TICK > 0)
|
|||||||
*/
|
*/
|
||||||
int stadium_boot_init(void);
|
int stadium_boot_init(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Stadium keyed by a v4 node's number (#189; Captain Bob, 2026-11-13: "A new node key").
|
||||||
|
* stadium_node_key(node) -- a node's key: "NODE" in the high word, the node's number in the low; never
|
||||||
|
* Hera's all-zero key or none's all-ones, and the same each time.
|
||||||
|
* stadium_boot_init_for(first) -- stadium_boot_init(), with `first`'s key in the first quota where
|
||||||
|
* stadium_boot_init() puts Hera's (it is stadium_boot_init_for(vm_uuid_hera())).
|
||||||
|
* stadium_birth_node(key, name) -- stadium_birth_hera() for any key: the node is patron zero, on cell
|
||||||
|
* 0, its session registered under `name` and pinned. 0, or -1 as stadium_birth_hera().
|
||||||
|
* v3's path keeps vm_uuid_hera() and stadium_birth_hera() (docs/v4.0.0/MACHINE.md 7, item 3).
|
||||||
|
*/
|
||||||
|
#define STADIUM_NODE_KEY_HI 0x4E4F444500000000ULL /* "NODE" */
|
||||||
|
VMUuid stadium_node_key(uint32_t node);
|
||||||
|
int stadium_boot_init_for(VMUuid first);
|
||||||
|
int stadium_birth_node(VMUuid key, const char *name);
|
||||||
|
|
||||||
/* stadium_is_initialized - Whether stadium_boot_init() has succeeded. */
|
/* stadium_is_initialized - Whether stadium_boot_init() has succeeded. */
|
||||||
int stadium_is_initialized(void);
|
int stadium_is_initialized(void);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/* SPDX-License-Identifier: LicenseRef-Starship-1.0
|
||||||
|
* Copyright (c) 2023-2026 Robert A. James
|
||||||
|
*/
|
||||||
|
/* stadium_ops.h -- a v4 node's opcodes as Stadium patrons (#189; plan
|
||||||
|
* 2026-11-13-engine-step4-phase1, Task 3).
|
||||||
|
*
|
||||||
|
* Captain Bob, 2026-11-12: "Add HEAT-OP. If it's a huge performance hit, we'll revert it" -- "Both":
|
||||||
|
* the registers (v4/include/v4/node.h) and the Stadium feed; 2026-11-13: "Per heartbeat tick".
|
||||||
|
* docs/v4.0.0/V3-PARITY.md 1c's reading -- "a VM's word patrons become its 32 opcode patrons" -- held
|
||||||
|
* since 1h left the opcodes unwired "for now"; this wires them, beside the word patrons, not instead.
|
||||||
|
*
|
||||||
|
* A node's 32 opcodes are patrons of its quota, behaviour COOL, each made resident on its first
|
||||||
|
* retirement as a word is on its first dispatch (stadium_words.c). At a charge, an opcode's
|
||||||
|
* retirements since the last charge are charged as that many of the word layer's dispatches -- the
|
||||||
|
* same quantum (STADIUM_WORD_HEAT_QUANTUM), the same floor left in the reservoir (a third); when
|
||||||
|
* they want more than there is, what there is is shared in proportion to the retirements, not taken
|
||||||
|
* by whichever opcode is charged first -- and a resident one first cools by the ticks since, as a
|
||||||
|
* word does
|
||||||
|
* (STADIUM_WORD_COOL_RATE_Q48). The kernel charges at its heartbeat's service points (sk_v4.c):
|
||||||
|
* where the node's host waits, and after each line. Conservation is the Stadium's: what is pulled is
|
||||||
|
* the node's own share.
|
||||||
|
*/
|
||||||
|
#ifndef STARKERNEL_VM_STADIUM_OPS_H
|
||||||
|
#define STARKERNEL_VM_STADIUM_OPS_H
|
||||||
|
|
||||||
|
#ifdef __STARKERNEL__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "starkernel/vm_uuid.h"
|
||||||
|
|
||||||
|
#define STADIUM_OPS_COUNT 32u /* the F18 opcodes, 0 .. 31 */
|
||||||
|
#define STADIUM_OPS_IDENTITY 0x4F50000000000000ULL /* "OP" in a patron's identity, | the opcode */
|
||||||
|
|
||||||
|
/* The per-quota tables; after stadium_boot_init_for(). Not re-entrant. */
|
||||||
|
void stadium_ops_init(void);
|
||||||
|
|
||||||
|
/* Charge the node `vm_id`'s opcodes: `counts` are its 32 running retirement counts (v4_heat.op),
|
||||||
|
* `tick` the heartbeat's count now. Nothing for a key with no quota. */
|
||||||
|
void stadium_ops_charge(VMUuid vm_id, const uint64_t counts[STADIUM_OPS_COUNT], uint64_t tick);
|
||||||
|
|
||||||
|
/* An opcode patron's heat now (Q48.16), or 0: not resident, or no quota. */
|
||||||
|
uint64_t stadium_ops_heat(VMUuid vm_id, unsigned op);
|
||||||
|
|
||||||
|
/* "Stadium opcodes: N resident, hottest opcode K" -- one line, at most 63 characters. */
|
||||||
|
void stadium_ops_print_boot_diagnostics(VMUuid vm_id);
|
||||||
|
|
||||||
|
#endif /* __STARKERNEL__ */
|
||||||
|
#endif
|
||||||
+117
-63
@@ -16,7 +16,7 @@
|
|||||||
* M0-M6: Complete (build, boot, PMM, VMM, interrupts, timer, kmalloc) -- v1.5.1-FINAL
|
* M0-M6: Complete (build, boot, PMM, VMM, interrupts, timer, kmalloc) -- v1.5.1-FINAL
|
||||||
* M7: Complete (the StarForth VM integrated, parity validated)
|
* M7: Complete (the StarForth VM integrated, parity validated)
|
||||||
* M7.1: In progress (capsule birth, the Mama vocabulary, the Tripod fleet, the word ACL)
|
* M7.1: In progress (capsule birth, the Mama vocabulary, the Tripod fleet, the word ACL)
|
||||||
* The system booted by default is v4, StarForth's F18 engine (sk_v4_run); system=v3 boots v3
|
* The system booted by default is v4, StarForth's F18 engine (sk_v4_boot, sk_v4_prompt); system=v3 boots v3
|
||||||
* (docs/fabric/FABRIC-3.md XLIII).
|
* (docs/fabric/FABRIC-3.md XLIII).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -59,6 +59,7 @@ EFI_RUNTIME_SERVICES *g_sk_runtime_services = NULL;
|
|||||||
#include "starkernel/vm/bootstrap/sk_vm_bootstrap.h"
|
#include "starkernel/vm/bootstrap/sk_vm_bootstrap.h"
|
||||||
#include "starkernel/vm/parity.h"
|
#include "starkernel/vm/parity.h"
|
||||||
#include "starkernel/vm/stadium.h"
|
#include "starkernel/vm/stadium.h"
|
||||||
|
#include "starkernel/vm/stadium_ops.h"
|
||||||
#include "starkernel/vm/stadium_words.h"
|
#include "starkernel/vm/stadium_words.h"
|
||||||
#include "starkernel/vm/stadium_blocks.h"
|
#include "starkernel/vm/stadium_blocks.h"
|
||||||
#include "starkernel/vm/kernel_hermes.h"
|
#include "starkernel/vm/kernel_hermes.h"
|
||||||
@@ -88,6 +89,9 @@ EFI_RUNTIME_SERVICES *g_sk_runtime_services = NULL;
|
|||||||
#include "starkernel/v4/sk_v4.h"
|
#include "starkernel/v4/sk_v4.h"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef SK_V4_HERA_NODE
|
||||||
|
#define SK_V4_HERA_NODE 10u /* a kernel without v4 never keys the Stadium by node (#189) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Forward declaration — kernel_main_deep contains everything from heartbeat
|
/* Forward declaration — kernel_main_deep contains everything from heartbeat
|
||||||
* init onward. The 2 MB BSS stack is set up by kernel_entry.S before
|
* init onward. The 2 MB BSS stack is set up by kernel_entry.S before
|
||||||
@@ -606,6 +610,71 @@ static void sk_v4_block_chain(void)
|
|||||||
*
|
*
|
||||||
* @param boot_info The @c BootInfo passed from @c kernel_main_impl().
|
* @param boot_info The @c BootInfo passed from @c kernel_main_impl().
|
||||||
*/
|
*/
|
||||||
|
/* The boot's checks after the system is up, the same on both systems (#189, plan
|
||||||
|
* 2026-11-13-engine-step4-phase1, Task 2; Q3: "All of v3's"). They were inline in
|
||||||
|
* kernel_main_deep, v3's path; v4's calls them too, under Hera's node key. */
|
||||||
|
|
||||||
|
/* item 4.1a self-test: stadium_grant_quota() with a synthetic identity, from `parent`'s quota. */
|
||||||
|
#ifdef STARFORTH_ENABLE_VM
|
||||||
|
static void sk_boot_quota_selftest(VMUuid parent, const char *name) {
|
||||||
|
{
|
||||||
|
VMUuid test_id;
|
||||||
|
test_id.hi = 0;
|
||||||
|
test_id.lo = 1; /* distinct from vm_uuid_hera() (all-zero) and
|
||||||
|
* vm_uuid_none() (all-ones) */
|
||||||
|
int grant_rc = stadium_grant_quota(test_id, parent);
|
||||||
|
console_puts("Stadium quota grant self-test: ");
|
||||||
|
console_println(grant_rc == 0 ? "OK" : "REFUSED");
|
||||||
|
if (grant_rc == 0) {
|
||||||
|
console_puts(" "); console_puts(name); print_uint(" reservoir=", stadium_reservoir_peek(parent));
|
||||||
|
print_uint(" test-vm reservoir=", stadium_reservoir_peek(test_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Phase 0 acceptance (section 25.1 item 0.10): a few real ticks, then the heartbeat's line. */
|
||||||
|
static void sk_boot_heartbeat_line(void) {
|
||||||
|
{
|
||||||
|
uint64_t wait_start = heartbeat_ticks();
|
||||||
|
uint64_t spins = 0;
|
||||||
|
while (heartbeat_ticks() - wait_start < 3 && spins < 100000000ULL) {
|
||||||
|
arch_relax();
|
||||||
|
spins++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console_puts("Heartbeat: ");
|
||||||
|
{
|
||||||
|
char buf[24]; uint64_t v = heartbeat_ticks(); int i = 0, j = 0; char t[24];
|
||||||
|
if (v == 0) buf[i++] = '0';
|
||||||
|
else { while (v > 0) { t[j++] = (char)('0' + (v % 10)); v /= 10; } while (j > 0) buf[i++] = t[--j]; }
|
||||||
|
buf[i] = '\0';
|
||||||
|
console_puts(buf);
|
||||||
|
}
|
||||||
|
console_puts(" ticks, trust=0x");
|
||||||
|
{
|
||||||
|
char buf[9]; uint32_t v = (uint32_t)heartbeat_trust();
|
||||||
|
for (int k = 7; k >= 0; k--) {
|
||||||
|
int nib = (int)((v >> (k * 4)) & 0xF);
|
||||||
|
buf[7 - k] = (char)(nib < 10 ? '0' + nib : 'a' + nib - 10);
|
||||||
|
}
|
||||||
|
buf[8] = '\0';
|
||||||
|
console_puts(buf);
|
||||||
|
}
|
||||||
|
console_puts(", variance=0x");
|
||||||
|
{
|
||||||
|
char buf[9]; uint32_t v = (uint32_t)heartbeat_state()->variance;
|
||||||
|
for (int k = 7; k >= 0; k--) {
|
||||||
|
int nib = (int)((v >> (k * 4)) & 0xF);
|
||||||
|
buf[7 - k] = (char)(nib < 10 ? '0' + nib : 'a' + nib - 10);
|
||||||
|
}
|
||||||
|
buf[8] = '\0';
|
||||||
|
console_puts(buf);
|
||||||
|
}
|
||||||
|
console_println("");
|
||||||
|
}
|
||||||
|
|
||||||
static void kernel_main_deep(BootInfo *boot_info) {
|
static void kernel_main_deep(BootInfo *boot_info) {
|
||||||
/* M5: Initialize heartbeat subsystem */
|
/* M5: Initialize heartbeat subsystem */
|
||||||
console_println("Heartbeat: init...");
|
console_println("Heartbeat: init...");
|
||||||
@@ -631,25 +700,25 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
|||||||
* Task 3). An ISO, CD or ESP-image boot is not a stick. */
|
* Task 3). An ISO, CD or ESP-image boot is not a stick. */
|
||||||
console_println(boot_info->boot_disk.is_stick ? "Boot disk: a StarshipOS stick"
|
console_println(boot_info->boot_disk.is_stick ? "Boot disk: a StarshipOS stick"
|
||||||
: "Boot disk: not a StarshipOS stick");
|
: "Boot disk: not a StarshipOS stick");
|
||||||
|
/* Which system runs, worked out before the Stadium is made: its first quota is keyed by it --
|
||||||
|
* Hera's all-zero key for v3, the first node's for v4 (#189, plan 2026-11-13-engine-step4-phase1,
|
||||||
|
* Q1: "A new node key"). Said first, as before. */
|
||||||
|
int sk_use_v4 = 0;
|
||||||
#ifdef STARFORTH_V4
|
#ifdef STARFORTH_V4
|
||||||
{
|
{
|
||||||
const int v3_refused = boot_info->boot_disk.is_stick && boot_info->args.system == KARGS_SYSTEM_V3;
|
const int v3_refused = boot_info->boot_disk.is_stick && boot_info->args.system == KARGS_SYSTEM_V3;
|
||||||
if (boot_info->args.system == KARGS_SYSTEM_V4 || v3_refused ||
|
sk_use_v4 = boot_info->args.system == KARGS_SYSTEM_V4 || v3_refused ||
|
||||||
(boot_info->args.system == KARGS_SYSTEM_DEFAULT && SK_V4_DEFAULT)) {
|
(boot_info->args.system == KARGS_SYSTEM_DEFAULT && SK_V4_DEFAULT);
|
||||||
|
if (sk_use_v4)
|
||||||
console_println(v3_refused ? "System: v3 is not on this stick -- StarForth v4"
|
console_println(v3_refused ? "System: v3 is not on this stick -- StarForth v4"
|
||||||
: boot_info->args.system == KARGS_SYSTEM_V4
|
: boot_info->args.system == KARGS_SYSTEM_V4
|
||||||
? "System: StarForth v4 (system=v4)"
|
? "System: StarForth v4 (system=v4)"
|
||||||
: "System: StarForth v4 (this build's default)");
|
: "System: StarForth v4 (this build's default)");
|
||||||
/* StarForth v4 at a single prompt: one host node of the F18-derived
|
else
|
||||||
* engine, in place of the v3 VM and everything below. It does not
|
console_println(boot_info->args.system == KARGS_SYSTEM_V3
|
||||||
* return. */
|
? "System: StarForth v3 (system=v3)"
|
||||||
sk_v4_boot_info = boot_info;
|
: "System: StarForth v3 (this build's default; system=v4 for v4)");
|
||||||
sk_v4_run(sk_v4_block_chain, &boot_info->boot_disk);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
console_println(boot_info->args.system == KARGS_SYSTEM_V3
|
|
||||||
? "System: StarForth v3 (system=v3)"
|
|
||||||
: "System: StarForth v3 (this build's default; system=v4 for v4)");
|
|
||||||
#else
|
#else
|
||||||
console_println(boot_info->args.system == KARGS_SYSTEM_V4
|
console_println(boot_info->args.system == KARGS_SYSTEM_V4
|
||||||
? "System: StarForth v3 -- system=v4 asked for, and this kernel has no v4"
|
? "System: StarForth v3 -- system=v4 asked for, and this kernel has no v4"
|
||||||
@@ -657,10 +726,13 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef STARFORTH_ENABLE_VM
|
#ifdef STARFORTH_ENABLE_VM
|
||||||
|
/* The Stadium and the kernel's tables are the kernel's, for both systems, in v3's order (#189,
|
||||||
|
* Phase 1 Task 1; Q3: "All of v3's"). */
|
||||||
/* Stadium: boot-time allocation (FABRIC-0.md item 3.2), before any VM
|
/* Stadium: boot-time allocation (FABRIC-0.md item 3.2), before any VM
|
||||||
* exists (§6). Soft failure -- nothing downstream consumes the Stadium
|
* exists (§6). Soft failure -- nothing downstream consumes the Stadium
|
||||||
* yet, so a failed allocation logs and boot continues. */
|
* yet, so a failed allocation logs and boot continues. */
|
||||||
(void)stadium_boot_init();
|
(void)(sk_use_v4 ? stadium_boot_init_for(stadium_node_key(SK_V4_HERA_NODE)) /* #189: keyed by node */
|
||||||
|
: stadium_boot_init());
|
||||||
|
|
||||||
/* Session: boot-time allocation (FABRIC-2.md §H.12 step 4), sized from
|
/* Session: boot-time allocation (FABRIC-2.md §H.12 step 4), sized from
|
||||||
* stadium_max_vm_count() so it must run after stadium_boot_init() above
|
* stadium_max_vm_count() so it must run after stadium_boot_init() above
|
||||||
@@ -693,6 +765,36 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
|||||||
* table just above. Publish (task 3.3) enqueues here; nothing drains
|
* table just above. Publish (task 3.3) enqueues here; nothing drains
|
||||||
* it yet (task 3.4). */
|
* it yet (task 3.4). */
|
||||||
(void)sk_hermes_queues_boot_init();
|
(void)sk_hermes_queues_boot_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef STARFORTH_V4
|
||||||
|
if (sk_use_v4) {
|
||||||
|
#ifdef STARFORTH_ENABLE_VM
|
||||||
|
/* Hera, the first node, is patron zero under her node key; then the word and block layers,
|
||||||
|
* as on v3's path below (#189). */
|
||||||
|
(void)stadium_birth_node(stadium_node_key(SK_V4_HERA_NODE), "Hera");
|
||||||
|
stadium_words_init();
|
||||||
|
stadium_blocks_init();
|
||||||
|
stadium_ops_init(); /* the node's 32 opcode patrons (#189) */
|
||||||
|
#endif
|
||||||
|
/* StarForth v4: one host node of the F18-derived engine, in place of
|
||||||
|
* the v3 VM, brought up in the kernel's boot (#189, Phase 1): the
|
||||||
|
* node and POST, then the kernel's checks as v3's, then the prompt,
|
||||||
|
* which does not return. */
|
||||||
|
sk_v4_boot_info = boot_info;
|
||||||
|
sk_v4_boot(sk_v4_block_chain, &boot_info->boot_disk);
|
||||||
|
#ifdef STARFORTH_ENABLE_VM
|
||||||
|
sk_v4_charge_opcodes(); /* what POST retired */
|
||||||
|
stadium_ops_print_boot_diagnostics(stadium_node_key(SK_V4_HERA_NODE));
|
||||||
|
stadium_words_print_boot_diagnostics(stadium_node_key(SK_V4_HERA_NODE));
|
||||||
|
sk_boot_quota_selftest(stadium_node_key(SK_V4_HERA_NODE), "Hera");
|
||||||
|
#endif
|
||||||
|
sk_boot_heartbeat_line();
|
||||||
|
sk_v4_prompt();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef STARFORTH_ENABLE_VM
|
||||||
|
|
||||||
/* item 4.1, FABRIC-0.md item 3.6/§17.7: actually enforce "Hera is patron
|
/* item 4.1, FABRIC-0.md item 3.6/§17.7: actually enforce "Hera is patron
|
||||||
* zero" before anything else can land on cell 0 via the free list, then
|
* zero" before anything else can land on cell 0 via the free list, then
|
||||||
@@ -986,19 +1088,7 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
|||||||
* capsule birth (item 0.1 pruned automatic Hermes birth from init.4th;
|
* capsule birth (item 0.1 pruned automatic Hermes birth from init.4th;
|
||||||
* restoring it is item 4.2's job, not this one's). Diagnostic only --
|
* restoring it is item 4.2's job, not this one's). Diagnostic only --
|
||||||
* the synthetic VM is never used for anything else. */
|
* the synthetic VM is never used for anything else. */
|
||||||
{
|
sk_boot_quota_selftest(vm_uuid_hera(), "Hera");
|
||||||
VMUuid test_id;
|
|
||||||
test_id.hi = 0;
|
|
||||||
test_id.lo = 1; /* distinct from vm_uuid_hera() (all-zero) and
|
|
||||||
* vm_uuid_none() (all-ones) */
|
|
||||||
int grant_rc = stadium_grant_quota(test_id, vm_uuid_hera());
|
|
||||||
console_puts("Stadium quota grant self-test: ");
|
|
||||||
console_println(grant_rc == 0 ? "OK" : "REFUSED");
|
|
||||||
if (grant_rc == 0) {
|
|
||||||
print_uint(" Hera reservoir=", stadium_reservoir_peek(vm_uuid_hera()));
|
|
||||||
print_uint(" test-vm reservoir=", stadium_reservoir_peek(test_id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FABRIC-3.6.md task 2.2 (item 28) self-test: sk_hermes_alloc()'s
|
/* FABRIC-3.6.md task 2.2 (item 28) self-test: sk_hermes_alloc()'s
|
||||||
* heat-coupled allocate, against its own synthetic VM (lo=3, distinct
|
* heat-coupled allocate, against its own synthetic VM (lo=3, distinct
|
||||||
@@ -1347,43 +1437,7 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
|||||||
* (not a virtual-tick construct; §16.4/§18.5 govern patron state, not
|
* (not a virtual-tick construct; §16.4/§18.5 govern patron state, not
|
||||||
* this one-time boot diagnostic) rather than reporting whatever count
|
* this one-time boot diagnostic) rather than reporting whatever count
|
||||||
* happened to land. */
|
* happened to land. */
|
||||||
{
|
sk_boot_heartbeat_line();
|
||||||
uint64_t wait_start = heartbeat_ticks();
|
|
||||||
uint64_t spins = 0;
|
|
||||||
while (heartbeat_ticks() - wait_start < 3 && spins < 100000000ULL) {
|
|
||||||
arch_relax();
|
|
||||||
spins++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console_puts("Heartbeat: ");
|
|
||||||
{
|
|
||||||
char buf[24]; uint64_t v = heartbeat_ticks(); int i = 0, j = 0; char t[24];
|
|
||||||
if (v == 0) buf[i++] = '0';
|
|
||||||
else { while (v > 0) { t[j++] = (char)('0' + (v % 10)); v /= 10; } while (j > 0) buf[i++] = t[--j]; }
|
|
||||||
buf[i] = '\0';
|
|
||||||
console_puts(buf);
|
|
||||||
}
|
|
||||||
console_puts(" ticks, trust=0x");
|
|
||||||
{
|
|
||||||
char buf[9]; uint32_t v = (uint32_t)heartbeat_trust();
|
|
||||||
for (int k = 7; k >= 0; k--) {
|
|
||||||
int nib = (int)((v >> (k * 4)) & 0xF);
|
|
||||||
buf[7 - k] = (char)(nib < 10 ? '0' + nib : 'a' + nib - 10);
|
|
||||||
}
|
|
||||||
buf[8] = '\0';
|
|
||||||
console_puts(buf);
|
|
||||||
}
|
|
||||||
console_puts(", variance=0x");
|
|
||||||
{
|
|
||||||
char buf[9]; uint32_t v = (uint32_t)heartbeat_state()->variance;
|
|
||||||
for (int k = 7; k >= 0; k--) {
|
|
||||||
int nib = (int)((v >> (k * 4)) & 0xF);
|
|
||||||
buf[7 - k] = (char)(nib < 10 ? '0' + nib : 'a' + nib - 10);
|
|
||||||
}
|
|
||||||
buf[8] = '\0';
|
|
||||||
console_puts(buf);
|
|
||||||
}
|
|
||||||
console_println("");
|
|
||||||
|
|
||||||
/* FABRIC-3.md §XXVIII, Stage 3 (2026-09-13): register the Tripod fleet
|
/* FABRIC-3.md §XXVIII, Stage 3 (2026-09-13): register the Tripod fleet
|
||||||
* as preemptive-switch-signal participants now, only after all three
|
* as preemptive-switch-signal participants now, only after all three
|
||||||
|
|||||||
+26
-5
@@ -18,8 +18,8 @@
|
|||||||
* and a console exists only while Zuse's drive is attached and checked
|
* and a console exists only while Zuse's drive is attached and checked
|
||||||
* (sk_v4_identity.c; ENGINE.md 2, ruled 2026-10-20).
|
* (sk_v4_identity.c; ENGINE.md 2, ruled 2026-10-20).
|
||||||
*
|
*
|
||||||
* This is the lone node, started before the kernel's fleet and beside it.
|
* The kernel brings it up in its own boot, after the Stadium (#189, ENGINE.md step 4,
|
||||||
* It goes when the node is brought up in the VM's place (ENGINE.md step 4).
|
* Phase 1): sk_v4_boot(), the kernel's checks after POST, then sk_v4_prompt().
|
||||||
*
|
*
|
||||||
* Nothing of the v3 VM is started. docs/v4.0.0/DECOMPOSITION.md.
|
* Nothing of the v3 VM is started. docs/v4.0.0/DECOMPOSITION.md.
|
||||||
*/
|
*/
|
||||||
@@ -33,6 +33,10 @@
|
|||||||
#include "starkernel/timer.h"
|
#include "starkernel/timer.h"
|
||||||
#include "v4/boot.h"
|
#include "v4/boot.h"
|
||||||
#include "block_subsystem.h"
|
#include "block_subsystem.h"
|
||||||
|
#ifdef STARFORTH_ENABLE_VM
|
||||||
|
#include "starkernel/vm/stadium.h"
|
||||||
|
#include "starkernel/vm/stadium_ops.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SK_V4_LINE 1024u /* what the line editor here takes: a line, as the boot takes one (v4/system/boot.c) */
|
#define SK_V4_LINE 1024u /* what the line editor here takes: a line, as the boot takes one (v4/system/boot.c) */
|
||||||
|
|
||||||
@@ -52,6 +56,16 @@ static char sk_v4_text[SK_V4_LINE + 1u];
|
|||||||
* above them, and the kernel's real chain is set up afterwards. */
|
* above them, and the kernel's real chain is set up afterwards. */
|
||||||
static uint8_t sk_v4_post_blk_ram[BLK_RAM_BLOCKS * BLK_FORTH_SIZE];
|
static uint8_t sk_v4_post_blk_ram[BLK_RAM_BLOCKS * BLK_FORTH_SIZE];
|
||||||
|
|
||||||
|
/* HEAT-OP into the Stadium (#189; Captain Bob: "Per heartbeat tick"): the node's opcode counts are
|
||||||
|
* charged to its opcode patrons at the heartbeat's service points -- where its host waits for a key,
|
||||||
|
* a tick at a time, and after each line. */
|
||||||
|
void sk_v4_charge_opcodes(void)
|
||||||
|
{
|
||||||
|
#ifdef STARFORTH_ENABLE_VM
|
||||||
|
stadium_ops_charge(stadium_node_key(SK_V4_HERA_NODE), sk_v4_heat.op, heartbeat_ticks());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void sk_v4_out(const char *text, unsigned len)
|
static void sk_v4_out(const char *text, unsigned len)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
@@ -123,6 +137,7 @@ static int sk_v4_readline(void)
|
|||||||
} else {
|
} else {
|
||||||
heartbeat_service();
|
heartbeat_service();
|
||||||
}
|
}
|
||||||
|
sk_v4_charge_opcodes();
|
||||||
/* Nothing typed: wait for the next interrupt, not in a spin (#151 -- the spin kept a
|
/* Nothing typed: wait for the next interrupt, not in a spin (#151 -- the spin kept a
|
||||||
* CPU core 100% busy at the prompt, and the demo's host with it). The heartbeat's
|
* CPU core 100% busy at the prompt, and the demo's host with it). The heartbeat's
|
||||||
* timer wakes it at 100 Hz, so a key is seen within a tick, as the blink and the
|
* timer wakes it at 100 Hz, so a key is seen within a tick, as the blink and the
|
||||||
@@ -148,10 +163,11 @@ static int sk_v4_readline(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sk_v4_run(void (*chain)(void), const BootDisk *boot_disk)
|
/* The node's boot record: sk_v4_boot() fills it, sk_v4_prompt() hands it lines. */
|
||||||
{
|
static v4_boot boot;
|
||||||
v4_boot boot;
|
|
||||||
|
|
||||||
|
void sk_v4_boot(void (*chain)(void), const BootDisk *boot_disk)
|
||||||
|
{
|
||||||
console_println("StarForth v4: one host node, the F18-derived engine");
|
console_println("StarForth v4: one host node, the F18-derived engine");
|
||||||
sk_v4_image = v4_map_image;
|
sk_v4_image = v4_map_image;
|
||||||
boot.n = &sk_v4_node; boot.es = &sk_v4_es; boot.h = &sk_v4_heat; boot.im = &sk_v4_image;
|
boot.n = &sk_v4_node; boot.es = &sk_v4_es; boot.h = &sk_v4_heat; boot.im = &sk_v4_image;
|
||||||
@@ -177,7 +193,10 @@ void sk_v4_run(void (*chain)(void), const BootDisk *boot_disk)
|
|||||||
console_fb_mirror(1);
|
console_fb_mirror(1);
|
||||||
console_fb_enable_ttf();
|
console_fb_enable_ttf();
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void sk_v4_prompt(void)
|
||||||
|
{
|
||||||
/* The prompt is the host's: read a line, hand it to the node, say how it
|
/* The prompt is the host's: read a line, hand it to the node, say how it
|
||||||
* ended. */
|
* ended. */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -185,6 +204,8 @@ void sk_v4_run(void (*chain)(void), const BootDisk *boot_disk)
|
|||||||
int how;
|
int how;
|
||||||
int logged_out = 0;
|
int logged_out = 0;
|
||||||
|
|
||||||
|
sk_v4_charge_opcodes(); /* what the last line retired (#189) */
|
||||||
|
|
||||||
#if !EMERGENCY_CONSOLE_ENABLED
|
#if !EMERGENCY_CONSOLE_ENABLED
|
||||||
/* no identity, no console: headless until Zuse's drive is checked.
|
/* no identity, no console: headless until Zuse's drive is checked.
|
||||||
* The drives are looked at first, now: one pulled while the last
|
* The drives are looked at first, now: one pulled while the last
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "starkernel/arch.h"
|
#include "starkernel/arch.h"
|
||||||
|
|
||||||
/* Interrupts off, then halt for ever: the core sleeps instead of spinning at 100% (#177), and no
|
/* Interrupts off, then halt for ever: the core sleeps instead of spinning at 100% (#177), and no
|
||||||
* timer or device wakes it to do anything. sk_v4_run's three stops each said why first. */
|
* timer or device wakes it to do anything. sk_v4_boot's and sk_v4_prompt's stops (sk_v4_run's, until #189's Phase 1) each say why first. */
|
||||||
void sk_v4_stop(void)
|
void sk_v4_stop(void)
|
||||||
{
|
{
|
||||||
arch_disable_interrupts();
|
arch_disable_interrupts();
|
||||||
|
|||||||
+21
-6
@@ -183,7 +183,18 @@ static void console_put_u64(uint64_t v) {
|
|||||||
console_puts(&buf[i]);
|
console_puts(&buf[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VMUuid stadium_node_key(uint32_t node) {
|
||||||
|
VMUuid k;
|
||||||
|
k.hi = STADIUM_NODE_KEY_HI;
|
||||||
|
k.lo = (uint64_t)node;
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
int stadium_boot_init(void) {
|
int stadium_boot_init(void) {
|
||||||
|
return stadium_boot_init_for(vm_uuid_hera());
|
||||||
|
}
|
||||||
|
|
||||||
|
int stadium_boot_init_for(VMUuid first) {
|
||||||
/* Budgeted from kmalloc_get_stats(), not pmm_get_stats() (corrected
|
/* Budgeted from kmalloc_get_stats(), not pmm_get_stats() (corrected
|
||||||
* 2026-08-15 -- see this function's doc in stadium.h): kmalloc_init()
|
* 2026-08-15 -- see this function's doc in stadium.h): kmalloc_init()
|
||||||
* (M6) already carved its own fixed-size heap out of PMM before this
|
* (M6) already carved its own fixed-size heap out of PMM before this
|
||||||
@@ -283,7 +294,7 @@ int stadium_boot_init(void) {
|
|||||||
quotas[i].consumed = 0;
|
quotas[i].consumed = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
quotas[0].vm_id = vm_uuid_hera();
|
quotas[0].vm_id = first; /* Hera on v3's path, the first node on v4's (#189) */
|
||||||
quotas[0].in_use = 1;
|
quotas[0].in_use = 1;
|
||||||
quotas[0].free_head = 0;
|
quotas[0].free_head = 0;
|
||||||
quotas[0].free_count = ncells;
|
quotas[0].free_count = ncells;
|
||||||
@@ -811,6 +822,10 @@ int stadium_conserved(VMUuid vm_id) {
|
|||||||
* must not break that.
|
* must not break that.
|
||||||
*/
|
*/
|
||||||
int stadium_birth_hera(void) {
|
int stadium_birth_hera(void) {
|
||||||
|
return stadium_birth_node(vm_uuid_hera(), "Hera");
|
||||||
|
}
|
||||||
|
|
||||||
|
int stadium_birth_node(VMUuid key, const char *name) {
|
||||||
StadiumPatronHeader candidate;
|
StadiumPatronHeader candidate;
|
||||||
size_t idx;
|
size_t idx;
|
||||||
|
|
||||||
@@ -831,19 +846,19 @@ int stadium_birth_hera(void) {
|
|||||||
candidate.flags = 0;
|
candidate.flags = 0;
|
||||||
candidate.behaviour = (uint8_t)STADIUM_BEHAVIOUR_COOL;
|
candidate.behaviour = (uint8_t)STADIUM_BEHAVIOUR_COOL;
|
||||||
|
|
||||||
idx = stadium_admit(vm_uuid_hera(), &candidate);
|
idx = stadium_admit(key, &candidate);
|
||||||
if (idx == STADIUM_CELL_NONE) return -1; /* refused; should not happen (quota is fresh and empty) */
|
if (idx == STADIUM_CELL_NONE) return -1; /* refused; should not happen (quota is fresh and empty) */
|
||||||
if (idx != STADIUM_HERA_CELL_INDEX) {
|
if (idx != STADIUM_HERA_CELL_INDEX) {
|
||||||
sk_hal_panic("Stadium: birth_hera did not land on cell 0 -- patron-zero invariant broken");
|
sk_hal_panic("Stadium: the first patron did not land on cell 0 -- patron-zero invariant broken");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Session *s = session_register(vm_uuid_hera(), vm_uuid_hera(), "Hera");
|
Session *s = session_register(key, key, name);
|
||||||
if (s) {
|
if (s) {
|
||||||
s->stadium_cell = idx;
|
s->stadium_cell = idx;
|
||||||
session_set_pinned(vm_uuid_hera(), 1);
|
session_set_pinned(key, 1);
|
||||||
} else {
|
} else {
|
||||||
console_println("Stadium: session_register failed for Hera (session.c not yet initialized?)");
|
console_println("Stadium: session_register failed for the first patron (session.c not yet initialized?)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
/* SPDX-License-Identifier: LicenseRef-Starship-1.0
|
||||||
|
* Copyright (c) 2023-2026 Robert A. James
|
||||||
|
*/
|
||||||
|
/* stadium_ops.c -- a v4 node's opcodes as Stadium patrons. See stadium_ops.h (#189). */
|
||||||
|
#include "starkernel/vm/stadium_ops.h"
|
||||||
|
|
||||||
|
#ifdef __STARKERNEL__
|
||||||
|
|
||||||
|
#include "starkernel/vm/stadium.h"
|
||||||
|
#include "starkernel/console.h"
|
||||||
|
#include "starkernel/kmalloc.h"
|
||||||
|
#include "starkernel/q48_16.h"
|
||||||
|
#include "starforth_config.h" /* STADIUM_WORD_HEAT_QUANTUM, STADIUM_WORD_COOL_RATE_Q48 */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t cell_index; /* STADIUM_CELL_NONE: not resident */
|
||||||
|
uint64_t last_tick; /* when it was last cooled */
|
||||||
|
uint64_t last_count; /* the opcode's retirements at the last charge */
|
||||||
|
} StadiumOpSlot;
|
||||||
|
|
||||||
|
static StadiumOpSlot **op_slots = (StadiumOpSlot **)0; /* [quota slot][opcode] */
|
||||||
|
static int ops_initialized = 0;
|
||||||
|
|
||||||
|
void stadium_ops_init(void)
|
||||||
|
{
|
||||||
|
size_t count = stadium_max_vm_count(), slot;
|
||||||
|
unsigned k;
|
||||||
|
|
||||||
|
if (ops_initialized) return;
|
||||||
|
if (count == 0) { console_println("Stadium opcodes: init skipped (no Stadium)"); return; }
|
||||||
|
op_slots = (StadiumOpSlot **)kmalloc(count * sizeof(StadiumOpSlot *));
|
||||||
|
if (!op_slots) { console_println("Stadium opcodes: kmalloc failed"); return; }
|
||||||
|
for (slot = 0; slot < count; slot++) {
|
||||||
|
op_slots[slot] = (StadiumOpSlot *)kmalloc(STADIUM_OPS_COUNT * sizeof(StadiumOpSlot));
|
||||||
|
if (!op_slots[slot]) {
|
||||||
|
size_t j;
|
||||||
|
console_println("Stadium opcodes: kmalloc failed");
|
||||||
|
for (j = 0; j < slot; j++) kfree(op_slots[j]);
|
||||||
|
kfree(op_slots);
|
||||||
|
op_slots = (StadiumOpSlot **)0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (k = 0; k < STADIUM_OPS_COUNT; k++) {
|
||||||
|
op_slots[slot][k].cell_index = STADIUM_CELL_NONE;
|
||||||
|
op_slots[slot][k].last_tick = 0;
|
||||||
|
op_slots[slot][k].last_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ops_initialized = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The opcode's cell, if it is still its own (the word layer's self-healing lookup). */
|
||||||
|
static size_t op_cell(int slot, unsigned k)
|
||||||
|
{
|
||||||
|
size_t cell = op_slots[slot][k].cell_index;
|
||||||
|
const uint8_t *bm = stadium_header_bitmap();
|
||||||
|
|
||||||
|
if (cell == STADIUM_CELL_NONE) return STADIUM_CELL_NONE;
|
||||||
|
if (cell >= stadium_cell_count() || !bm || !((bm[cell / 8u] >> (cell % 8u)) & 1u)
|
||||||
|
|| stadium_cells()[cell].header.identity != (STADIUM_OPS_IDENTITY | k)) {
|
||||||
|
op_slots[slot][k].cell_index = STADIUM_CELL_NONE;
|
||||||
|
return STADIUM_CELL_NONE;
|
||||||
|
}
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stadium_ops_charge(VMUuid vm_id, const uint64_t counts[STADIUM_OPS_COUNT], uint64_t tick)
|
||||||
|
{
|
||||||
|
int slot;
|
||||||
|
unsigned k;
|
||||||
|
uint64_t retired[STADIUM_OPS_COUNT], total = 0, want, pullable, floor = Q48_ONE / 3, avail;
|
||||||
|
const uint64_t q = (uint64_t)STADIUM_WORD_HEAT_QUANTUM;
|
||||||
|
|
||||||
|
if (!ops_initialized) return;
|
||||||
|
slot = stadium_quota_slot_for_vm(vm_id);
|
||||||
|
if (slot < 0) return;
|
||||||
|
|
||||||
|
/* First: every resident opcode cools by the ticks since, as a word does (a fraction of its own
|
||||||
|
* heat a tick, back to the reservoir); and each opcode's retirements since the last charge. */
|
||||||
|
for (k = 0; k < STADIUM_OPS_COUNT; k++) {
|
||||||
|
StadiumOpSlot *o = &op_slots[slot][k];
|
||||||
|
size_t cell = op_cell(slot, k);
|
||||||
|
retired[k] = counts[k] - o->last_count;
|
||||||
|
o->last_count = counts[k];
|
||||||
|
total = (total + retired[k] < total) ? UINT64_MAX : total + retired[k];
|
||||||
|
if (cell != STADIUM_CELL_NONE) {
|
||||||
|
StadiumPatronHeader *h = &stadium_cells()[cell].header;
|
||||||
|
uint64_t elapsed = tick - o->last_tick;
|
||||||
|
if (elapsed > 0) {
|
||||||
|
uint64_t cooled = ((h->heat * (uint64_t)STADIUM_WORD_COOL_RATE_Q48) >> 16) * elapsed;
|
||||||
|
if (cooled > h->heat) cooled = h->heat;
|
||||||
|
if (cooled > 0) { h->heat -= cooled; stadium_reservoir_push(vm_id, cooled); }
|
||||||
|
}
|
||||||
|
o->last_tick = tick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (total == 0) return;
|
||||||
|
|
||||||
|
/* Then: the retirements are that many of the word layer's dispatches -- a quantum each, never
|
||||||
|
* leaving the reservoir below a third. When they want more than there is, what there is is
|
||||||
|
* shared by retirements, not by the order the opcodes are taken in (#189). */
|
||||||
|
avail = stadium_reservoir_peek(vm_id);
|
||||||
|
pullable = avail > floor ? avail - floor : 0;
|
||||||
|
want = total > UINT64_MAX / q ? UINT64_MAX : total * q;
|
||||||
|
{
|
||||||
|
unsigned shift = 0;
|
||||||
|
while ((total >> shift) >= ((uint64_t)1 << 32)) shift++; /* pullable * share fits 64 bits */
|
||||||
|
for (k = 0; k < STADIUM_OPS_COUNT; k++) {
|
||||||
|
StadiumOpSlot *o = &op_slots[slot][k];
|
||||||
|
uint64_t give;
|
||||||
|
size_t cell;
|
||||||
|
if (retired[k] == 0) continue;
|
||||||
|
give = want <= pullable ? retired[k] * q
|
||||||
|
: (total >> shift) ? pullable * (retired[k] >> shift) / (total >> shift) : 0;
|
||||||
|
give = stadium_reservoir_pull(vm_id, give);
|
||||||
|
cell = op_cell(slot, k);
|
||||||
|
if (cell != STADIUM_CELL_NONE) { stadium_cells()[cell].header.heat += give; continue; }
|
||||||
|
/* not resident: admitted on its first retirements, with what they pull */
|
||||||
|
{
|
||||||
|
StadiumPatronHeader c;
|
||||||
|
uint8_t *raw = (uint8_t *)&c;
|
||||||
|
size_t i, idx;
|
||||||
|
for (i = 0; i < sizeof c; i++) raw[i] = 0;
|
||||||
|
c.identity = STADIUM_OPS_IDENTITY | k;
|
||||||
|
c.heat = give;
|
||||||
|
c.link = 0;
|
||||||
|
c.contains = STADIUM_CONTAINS_NONE;
|
||||||
|
c.mass = 1;
|
||||||
|
c.behaviour = (uint8_t)STADIUM_BEHAVIOUR_COOL;
|
||||||
|
idx = stadium_admit(vm_id, &c);
|
||||||
|
if (idx == STADIUM_CELL_NONE) { stadium_reservoir_push(vm_id, give); continue; }
|
||||||
|
o->cell_index = idx;
|
||||||
|
o->last_tick = tick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t stadium_ops_heat(VMUuid vm_id, unsigned op)
|
||||||
|
{
|
||||||
|
int slot;
|
||||||
|
size_t cell;
|
||||||
|
|
||||||
|
if (!ops_initialized || op >= STADIUM_OPS_COUNT) return 0;
|
||||||
|
slot = stadium_quota_slot_for_vm(vm_id);
|
||||||
|
if (slot < 0) return 0;
|
||||||
|
cell = op_cell(slot, op);
|
||||||
|
return cell == STADIUM_CELL_NONE ? 0 : stadium_cells()[cell].header.heat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stadium_ops_print_boot_diagnostics(VMUuid vm_id)
|
||||||
|
{
|
||||||
|
unsigned k, resident = 0, hottest = 0;
|
||||||
|
uint64_t best = 0;
|
||||||
|
char line[64];
|
||||||
|
unsigned at = 0;
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
for (k = 0; k < STADIUM_OPS_COUNT; k++) {
|
||||||
|
uint64_t h = stadium_ops_heat(vm_id, k);
|
||||||
|
if (h > 0) resident++;
|
||||||
|
if (h > best) { best = h; hottest = k; }
|
||||||
|
}
|
||||||
|
for (p = "Stadium opcodes: "; *p; p++) line[at++] = *p;
|
||||||
|
if (resident >= 10) line[at++] = (char)('0' + resident / 10);
|
||||||
|
line[at++] = (char)('0' + resident % 10);
|
||||||
|
for (p = " resident, hottest opcode "; *p; p++) line[at++] = *p;
|
||||||
|
if (hottest >= 10) line[at++] = (char)('0' + hottest / 10);
|
||||||
|
line[at++] = (char)('0' + hottest % 10);
|
||||||
|
line[at] = 0;
|
||||||
|
console_println(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __STARKERNEL__ */
|
||||||
@@ -19,7 +19,11 @@ CC ?= cc
|
|||||||
CFLAGS := -std=c99 -Wall -Wextra -Werror -O2 -g -I$(HERE) -I$(ROOT)/kernel/include \
|
CFLAGS := -std=c99 -Wall -Wextra -Werror -O2 -g -I$(HERE) -I$(ROOT)/kernel/include \
|
||||||
-I$(ROOT)/kernel/include/starkernel -I$(ROOT)/v3/include
|
-I$(ROOT)/kernel/include/starkernel -I$(ROOT)/v3/include
|
||||||
|
|
||||||
TESTS := test_gpt test_usb_config test_sk_v4_stop test_sk_v4_slots test_sk_v4_mint test_sk_v4_identity test_heartbeat_export test_ssm_jacquard test_physics_l2
|
TESTS := test_gpt test_usb_config test_sk_v4_stop test_sk_v4_slots test_sk_v4_mint test_sk_v4_identity test_heartbeat_export test_ssm_jacquard test_physics_l2 test_stadium_node test_stadium_ops
|
||||||
|
SRC_test_stadium_ops := $(ROOT)/kernel/src/vm/stadium_ops.c $(ROOT)/kernel/src/vm/stadium.c $(ROOT)/kernel/src/vm/session.c $(ROOT)/kernel/src/capsule/vm_uuid.c
|
||||||
|
EXTRA_test_stadium_ops := -D__STARKERNEL__
|
||||||
|
SRC_test_stadium_node := $(ROOT)/kernel/src/vm/stadium.c $(ROOT)/kernel/src/vm/session.c $(ROOT)/kernel/src/capsule/vm_uuid.c
|
||||||
|
EXTRA_test_stadium_node := -D__STARKERNEL__
|
||||||
SRC_test_physics_l2 := $(ROOT)/v3/src/physics_execution_hooks.c
|
SRC_test_physics_l2 := $(ROOT)/v3/src/physics_execution_hooks.c
|
||||||
SRC_test_ssm_jacquard := $(ROOT)/v3/src/ssm_jacquard.c $(ROOT)/v3/src/compudynamics.c
|
SRC_test_ssm_jacquard := $(ROOT)/v3/src/ssm_jacquard.c $(ROOT)/v3/src/compudynamics.c
|
||||||
SRC_test_heartbeat_export := $(ROOT)/v3/src/heartbeat_export.c
|
SRC_test_heartbeat_export := $(ROOT)/v3/src/heartbeat_export.c
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/* SPDX-License-Identifier: LicenseRef-Starship-1.0
|
||||||
|
* Copyright (c) 2023-2026 Robert A. James
|
||||||
|
*/
|
||||||
|
/* test_stadium_node.c -- kernel/src/vm/stadium.c and session.c on the host (#189, plan
|
||||||
|
* 2026-11-13-engine-step4-phase1, Task 1): the Stadium keyed by a v4 node's number (Captain Bob,
|
||||||
|
* 2026-11-13: "A new node key"). A node's key is none of v3's (not Hera's all-zero, not "none"); the
|
||||||
|
* Stadium can be made with that key in its first quota; the node is born on cell 0, its session
|
||||||
|
* registered and pinned, its whole share in its reservoir -- as Hera is on v3's path, which keeps
|
||||||
|
* vm_uuid_hera() and stadium_birth_hera().
|
||||||
|
*
|
||||||
|
* What the sources call outside themselves is defined here.
|
||||||
|
*/
|
||||||
|
#include "harness.h"
|
||||||
|
#include "starkernel/vm/stadium.h"
|
||||||
|
#include "starkernel/session.h"
|
||||||
|
#include "starkernel/vm_uuid.h"
|
||||||
|
#include "starkernel/kmalloc.h"
|
||||||
|
#include "starkernel/q48_16.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void *kmalloc(size_t size) { return calloc(1, size); }
|
||||||
|
void kfree(void *ptr) { free(ptr); }
|
||||||
|
kmalloc_stats_t kmalloc_get_stats(void)
|
||||||
|
{
|
||||||
|
kmalloc_stats_t s;
|
||||||
|
memset(&s, 0, sizeof s);
|
||||||
|
s.free_bytes = 16u * 1024u * 1024u; /* a small heap: the Stadium takes its percentage of it */
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
void log_message(int level, const char *fmt, ...) { (void)level; (void)fmt; }
|
||||||
|
void sk_hal_panic(const char *message) { printf("PANIC: %s\n", message); exit(2); }
|
||||||
|
int blk_flush(uint32_t block_num) { (void)block_num; return 0; }
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
VMUuid key = stadium_node_key(10), other = stadium_node_key(11);
|
||||||
|
Session *s;
|
||||||
|
|
||||||
|
CHECK(!vm_uuid_is_hera(key) && !vm_uuid_is_none(key), "a node's key is neither Hera's (all-zero) nor none");
|
||||||
|
CHECK(!vm_uuid_equal(key, other), "two nodes, two keys");
|
||||||
|
CHECK(vm_uuid_equal(key, stadium_node_key(10)), "a node's key is the same each time");
|
||||||
|
|
||||||
|
CHECK(stadium_boot_init_for(key) == 0 && stadium_is_initialized(), "the Stadium is made with the node's key first");
|
||||||
|
CHECK(session_boot_init() == 0, "the sessions");
|
||||||
|
CHECK(stadium_quota_slot_for_vm(key) == 0, "the node holds the first quota");
|
||||||
|
CHECK(stadium_quota_slot_for_vm(vm_uuid_hera()) < 0, "and Hera's all-zero key none");
|
||||||
|
CHECK(stadium_reservoir_peek(key) == Q48_ONE, "its reservoir holds the whole share, 1.0");
|
||||||
|
|
||||||
|
CHECK(stadium_birth_node(key, "Hera") == 0, "the node is born");
|
||||||
|
s = session_find(key);
|
||||||
|
CHECK(s != 0 && s->stadium_cell == 0, "on cell 0, patron zero, its session registered");
|
||||||
|
CHECK(session_is_pinned(key), "and pinned");
|
||||||
|
CHECK(stadium_conserved(key), "conservation holds: resident heat and reservoir sum to 1.0");
|
||||||
|
CHECK(stadium_birth_node(key, "Hera") == 0 && session_find(key) == s, "born twice is born once");
|
||||||
|
return DONE();
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/* SPDX-License-Identifier: LicenseRef-Starship-1.0
|
||||||
|
* Copyright (c) 2023-2026 Robert A. James
|
||||||
|
*/
|
||||||
|
/* test_stadium_ops.c -- kernel/src/vm/stadium_ops.c on the host (#189, plan
|
||||||
|
* 2026-11-13-engine-step4-phase1, Task 3): HEAT-OP into the Stadium (Captain Bob, 2026-11-12: "Add
|
||||||
|
* HEAT-OP ... Both"; 2026-11-13: "Per heartbeat tick"). A node's 32 opcodes are patrons; at a charge,
|
||||||
|
* each opcode's retirements since the last are charged as that many of the word layer's dispatches --
|
||||||
|
* the same quantum, the same floor on the reservoir -- and a resident one cools by the ticks since,
|
||||||
|
* as a word does. Conservation holds throughout.
|
||||||
|
*/
|
||||||
|
#include "harness.h"
|
||||||
|
#include "starkernel/vm/stadium.h"
|
||||||
|
#include "starkernel/vm/stadium_ops.h"
|
||||||
|
#include "starkernel/session.h"
|
||||||
|
#include "starkernel/vm_uuid.h"
|
||||||
|
#include "starkernel/kmalloc.h"
|
||||||
|
#include "starkernel/q48_16.h"
|
||||||
|
#include "starforth_config.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void *kmalloc(size_t size) { return calloc(1, size); }
|
||||||
|
void kfree(void *ptr) { free(ptr); }
|
||||||
|
kmalloc_stats_t kmalloc_get_stats(void)
|
||||||
|
{
|
||||||
|
kmalloc_stats_t s;
|
||||||
|
memset(&s, 0, sizeof s);
|
||||||
|
s.free_bytes = 512u * 1024u * 1024u; /* room for more than one quota, as on the boot (50 VM slots) */
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
void log_message(int level, const char *fmt, ...) { (void)level; (void)fmt; }
|
||||||
|
void sk_hal_panic(const char *message) { printf("PANIC: %s\n", message); exit(2); }
|
||||||
|
int blk_flush(uint32_t block_num) { (void)block_num; return 0; }
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
VMUuid key = stadium_node_key(10);
|
||||||
|
uint64_t counts[32], before, h20, r, q = (uint64_t)STADIUM_WORD_HEAT_QUANTUM;
|
||||||
|
unsigned k, hot = 0;
|
||||||
|
|
||||||
|
CHECK(stadium_boot_init_for(key) == 0 && session_boot_init() == 0 && stadium_birth_node(key, "Hera") == 0,
|
||||||
|
"a Stadium with the node born in it");
|
||||||
|
stadium_ops_init();
|
||||||
|
memset(counts, 0, sizeof counts);
|
||||||
|
|
||||||
|
stadium_ops_charge(key, counts, 1);
|
||||||
|
for (k = 0; k < 32; k++) if (stadium_ops_heat(key, k) != 0) hot++;
|
||||||
|
CHECK(hot == 0 && stadium_reservoir_peek(key) == Q48_ONE, "no retirements, no heat: the reservoir holds 1.0");
|
||||||
|
|
||||||
|
counts[20] = 5; /* + retired five times */
|
||||||
|
before = stadium_reservoir_peek(key);
|
||||||
|
stadium_ops_charge(key, counts, 2);
|
||||||
|
h20 = stadium_ops_heat(key, 20);
|
||||||
|
CHECK(h20 == 5u * q && stadium_reservoir_peek(key) == before - 5u * q,
|
||||||
|
"five retirements of + are five dispatches' heat, pulled from the reservoir (%llu)", (unsigned long long)h20);
|
||||||
|
CHECK(stadium_ops_heat(key, 21) == 0, "and no other opcode is heated");
|
||||||
|
CHECK(stadium_conserved(key), "conservation holds");
|
||||||
|
|
||||||
|
stadium_ops_charge(key, counts, 12); /* ten ticks later, nothing retired */
|
||||||
|
CHECK(stadium_ops_heat(key, 20) < h20 && stadium_reservoir_peek(key) > before - 5u * q,
|
||||||
|
"with nothing retired, + cools over ten ticks, back to the reservoir");
|
||||||
|
CHECK(stadium_conserved(key), "conservation holds");
|
||||||
|
|
||||||
|
counts[24] = (uint64_t)1 << 40; /* dup, very many times */
|
||||||
|
stadium_ops_charge(key, counts, 13);
|
||||||
|
r = stadium_reservoir_peek(key);
|
||||||
|
CHECK(r >= Q48_ONE / 3, "a flood of retirements leaves the reservoir its floor, a third (%llu)", (unsigned long long)r);
|
||||||
|
CHECK(stadium_ops_heat(key, 24) > 0 && stadium_conserved(key), "dup is heated, and conservation holds");
|
||||||
|
|
||||||
|
CHECK(stadium_ops_heat(vm_uuid_hera(), 20) == 0, "a key with no quota has no opcode heat");
|
||||||
|
|
||||||
|
/* more wanted than the reservoir has: shared by retirements, not by the order the opcodes are
|
||||||
|
* charged in -- a low-numbered opcode retired a little does not take it all */
|
||||||
|
{
|
||||||
|
VMUuid k2 = stadium_node_key(12);
|
||||||
|
uint64_t c2[32], h0, h5;
|
||||||
|
CHECK(stadium_grant_quota(k2, key) == 0, "a second node, its own quota");
|
||||||
|
memset(c2, 0, sizeof c2);
|
||||||
|
c2[0] = 1000000; /* ; retired a million times */
|
||||||
|
c2[5] = 3000000; /* next three million */
|
||||||
|
stadium_ops_charge(k2, c2, 20);
|
||||||
|
h0 = stadium_ops_heat(k2, 0); h5 = stadium_ops_heat(k2, 5);
|
||||||
|
CHECK(h0 > 0 && h5 > 0, "both opcodes are heated (; %llu, next %llu)", (unsigned long long)h0, (unsigned long long)h5);
|
||||||
|
CHECK(h5 > 2u * h0 && h5 < 4u * h0, "in proportion to their retirements, about 3 to 1");
|
||||||
|
CHECK(stadium_reservoir_peek(k2) >= Q48_ONE / 3 && stadium_conserved(k2), "the floor kept, conservation held");
|
||||||
|
}
|
||||||
|
return DONE();
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Phase 1 (#189), Task 1 Step 1 / Task 4 Step 1: the physics check (scripts/qemu_session.py physics())
|
||||||
|
# on today's v4 boot, before the Stadium is made on it: the three physics lines FAIL; POST and the prompt pass.
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
LOG: logs/20261113-122142/amd64/qemu-amd64-20261113-122142.log
|
||||||
|
PASS: POST: PASSED
|
||||||
|
PASS: Boot disk: not a StarshipOS stick (an ISO or ESP boot)
|
||||||
|
PASS: Zuse: genesis minted onto attached thumbdrive (a fresh data stick)
|
||||||
|
FAIL: the Stadium: its cells allocated
|
||||||
|
--- serial log, the log's last 40 lines (logs/20261113-122142/amd64/qemu-amd64-20261113-122142.log):
|
||||||
|
125 | V4: capsule v4:sys:forth.f18 signature: missing (unsigned)
|
||||||
|
126 | PARITY:V4_F18 name=v4:sys:forth.f18 capsule_hash=0x16cab4a1268b85da
|
||||||
|
127 | V4: capsule v4:sys:numout.f18 signature: missing (unsigned)
|
||||||
|
128 | PARITY:V4_F18 name=v4:sys:numout.f18 capsule_hash=0x85a240ad3fb2b299
|
||||||
|
129 | V4: capsule v4:sys:words.f18 signature: missing (unsigned)
|
||||||
|
130 | PARITY:V4_F18 name=v4:sys:words.f18 capsule_hash=0xb1d381f927d9f14e
|
||||||
|
131 | V4: capsule v4:sys:system.f18 signature: missing (unsigned)
|
||||||
|
132 | PARITY:V4_F18 name=v4:sys:system.f18 capsule_hash=0x61c6532daa58b47d
|
||||||
|
133 | V4: capsule v4:sys:qmath.f18 signature: missing (unsigned)
|
||||||
|
134 | PARITY:V4_F18 name=v4:sys:qmath.f18 capsule_hash=0xdb4140713dd857f3
|
||||||
|
135 | V4: capsule v4:sys:blocks.f18 signature: missing (unsigned)
|
||||||
|
136 | PARITY:V4_F18 name=v4:sys:blocks.f18 capsule_hash=0x76307ef48678dc2a
|
||||||
|
137 | V4: capsule v4:sys:log.f18 signature: missing (unsigned)
|
||||||
|
138 | PARITY:V4_F18 name=v4:sys:log.f18 capsule_hash=0xfc6540e6b824a52b
|
||||||
|
139 | V4: capsule v4:sys:acl.f18 signature: missing (unsigned)
|
||||||
|
140 | PARITY:V4_F18 name=v4:sys:acl.f18 capsule_hash=0x6845aa048db7eb22
|
||||||
|
141 | V4: capsule v4:sys:end.f18 signature: missing (unsigned)
|
||||||
|
142 | PARITY:V4_F18 name=v4:sys:end.f18 capsule_hash=0x5ef01312c07b79cc
|
||||||
|
143 | PARITY:V4_ROM words=2372 rom_hash=0x87b23d3ae2643c8d instructions=59537530
|
||||||
|
144 | V4: capsule v4:forth79.4th signature: missing (unsigned)
|
||||||
|
145 | PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x7d5965f7983485b9
|
||||||
|
146 | PARITY:V4_POST tests=539 pass=539 fail=0
|
||||||
|
147 | PARITY:V4_SYSTEM word_count=320 dict_hash=0x47570d4ced6ce255
|
||||||
|
148 | PARITY:OK
|
||||||
|
149 | POST: PASSED
|
||||||
|
150 | PCI: init...
|
||||||
|
151 | PCI: ECAM mapped (amd64)
|
||||||
|
152 | virtio-rng: no device on PCI bus 0
|
||||||
|
153 | rng: backend = rdrand
|
||||||
|
154 | entropy: ready
|
||||||
|
155 | virtio-input: no device on PCI bus 0
|
||||||
|
156 | Starting heartbeat...
|
||||||
|
157 | APIC Timer: started (LVT=0x00020020 ICR=9924004)
|
||||||
|
158 |
|
||||||
|
159 | I/O APIC: keyboard IRQ1 unmasked
|
||||||
|
160 | Heartbeat running.
|
||||||
|
161 | blkio_usb: MSC device ready
|
||||||
|
162 | Artemis: the stick's partition attached
|
||||||
|
163 | \x1b[38;2;255;165;0m[Hera]\x1b[39m Zuse: genesis minted onto attached thumbdrive
|
||||||
|
164 | \x1b[38;2;255;165;0m[zuse@Hera]\x1b[39m \x1b[38;2;85;255;255mok> \x1b[39m
|
||||||
|
---
|
||||||
|
FAIL: the Stadium: conservation CONSERVED
|
||||||
|
--- serial log, the log's last 40 lines (logs/20261113-122142/amd64/qemu-amd64-20261113-122142.log):
|
||||||
|
125 | V4: capsule v4:sys:forth.f18 signature: missing (unsigned)
|
||||||
|
126 | PARITY:V4_F18 name=v4:sys:forth.f18 capsule_hash=0x16cab4a1268b85da
|
||||||
|
127 | V4: capsule v4:sys:numout.f18 signature: missing (unsigned)
|
||||||
|
128 | PARITY:V4_F18 name=v4:sys:numout.f18 capsule_hash=0x85a240ad3fb2b299
|
||||||
|
129 | V4: capsule v4:sys:words.f18 signature: missing (unsigned)
|
||||||
|
130 | PARITY:V4_F18 name=v4:sys:words.f18 capsule_hash=0xb1d381f927d9f14e
|
||||||
|
131 | V4: capsule v4:sys:system.f18 signature: missing (unsigned)
|
||||||
|
132 | PARITY:V4_F18 name=v4:sys:system.f18 capsule_hash=0x61c6532daa58b47d
|
||||||
|
133 | V4: capsule v4:sys:qmath.f18 signature: missing (unsigned)
|
||||||
|
134 | PARITY:V4_F18 name=v4:sys:qmath.f18 capsule_hash=0xdb4140713dd857f3
|
||||||
|
135 | V4: capsule v4:sys:blocks.f18 signature: missing (unsigned)
|
||||||
|
136 | PARITY:V4_F18 name=v4:sys:blocks.f18 capsule_hash=0x76307ef48678dc2a
|
||||||
|
137 | V4: capsule v4:sys:log.f18 signature: missing (unsigned)
|
||||||
|
138 | PARITY:V4_F18 name=v4:sys:log.f18 capsule_hash=0xfc6540e6b824a52b
|
||||||
|
139 | V4: capsule v4:sys:acl.f18 signature: missing (unsigned)
|
||||||
|
140 | PARITY:V4_F18 name=v4:sys:acl.f18 capsule_hash=0x6845aa048db7eb22
|
||||||
|
141 | V4: capsule v4:sys:end.f18 signature: missing (unsigned)
|
||||||
|
142 | PARITY:V4_F18 name=v4:sys:end.f18 capsule_hash=0x5ef01312c07b79cc
|
||||||
|
143 | PARITY:V4_ROM words=2372 rom_hash=0x87b23d3ae2643c8d instructions=59537530
|
||||||
|
144 | V4: capsule v4:forth79.4th signature: missing (unsigned)
|
||||||
|
145 | PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x7d5965f7983485b9
|
||||||
|
146 | PARITY:V4_POST tests=539 pass=539 fail=0
|
||||||
|
147 | PARITY:V4_SYSTEM word_count=320 dict_hash=0x47570d4ced6ce255
|
||||||
|
148 | PARITY:OK
|
||||||
|
149 | POST: PASSED
|
||||||
|
150 | PCI: init...
|
||||||
|
151 | PCI: ECAM mapped (amd64)
|
||||||
|
152 | virtio-rng: no device on PCI bus 0
|
||||||
|
153 | rng: backend = rdrand
|
||||||
|
154 | entropy: ready
|
||||||
|
155 | virtio-input: no device on PCI bus 0
|
||||||
|
156 | Starting heartbeat...
|
||||||
|
157 | APIC Timer: started (LVT=0x00020020 ICR=9924004)
|
||||||
|
158 |
|
||||||
|
159 | I/O APIC: keyboard IRQ1 unmasked
|
||||||
|
160 | Heartbeat running.
|
||||||
|
161 | blkio_usb: MSC device ready
|
||||||
|
162 | Artemis: the stick's partition attached
|
||||||
|
163 | \x1b[38;2;255;165;0m[Hera]\x1b[39m Zuse: genesis minted onto attached thumbdrive
|
||||||
|
164 | \x1b[38;2;255;165;0m[zuse@Hera]\x1b[39m \x1b[38;2;85;255;255mok> \x1b[39m
|
||||||
|
---
|
||||||
|
FAIL: the heartbeat: ticking
|
||||||
|
--- serial log, the log's last 40 lines (logs/20261113-122142/amd64/qemu-amd64-20261113-122142.log):
|
||||||
|
125 | V4: capsule v4:sys:forth.f18 signature: missing (unsigned)
|
||||||
|
126 | PARITY:V4_F18 name=v4:sys:forth.f18 capsule_hash=0x16cab4a1268b85da
|
||||||
|
127 | V4: capsule v4:sys:numout.f18 signature: missing (unsigned)
|
||||||
|
128 | PARITY:V4_F18 name=v4:sys:numout.f18 capsule_hash=0x85a240ad3fb2b299
|
||||||
|
129 | V4: capsule v4:sys:words.f18 signature: missing (unsigned)
|
||||||
|
130 | PARITY:V4_F18 name=v4:sys:words.f18 capsule_hash=0xb1d381f927d9f14e
|
||||||
|
131 | V4: capsule v4:sys:system.f18 signature: missing (unsigned)
|
||||||
|
132 | PARITY:V4_F18 name=v4:sys:system.f18 capsule_hash=0x61c6532daa58b47d
|
||||||
|
133 | V4: capsule v4:sys:qmath.f18 signature: missing (unsigned)
|
||||||
|
134 | PARITY:V4_F18 name=v4:sys:qmath.f18 capsule_hash=0xdb4140713dd857f3
|
||||||
|
135 | V4: capsule v4:sys:blocks.f18 signature: missing (unsigned)
|
||||||
|
136 | PARITY:V4_F18 name=v4:sys:blocks.f18 capsule_hash=0x76307ef48678dc2a
|
||||||
|
137 | V4: capsule v4:sys:log.f18 signature: missing (unsigned)
|
||||||
|
138 | PARITY:V4_F18 name=v4:sys:log.f18 capsule_hash=0xfc6540e6b824a52b
|
||||||
|
139 | V4: capsule v4:sys:acl.f18 signature: missing (unsigned)
|
||||||
|
140 | PARITY:V4_F18 name=v4:sys:acl.f18 capsule_hash=0x6845aa048db7eb22
|
||||||
|
141 | V4: capsule v4:sys:end.f18 signature: missing (unsigned)
|
||||||
|
142 | PARITY:V4_F18 name=v4:sys:end.f18 capsule_hash=0x5ef01312c07b79cc
|
||||||
|
143 | PARITY:V4_ROM words=2372 rom_hash=0x87b23d3ae2643c8d instructions=59537530
|
||||||
|
144 | V4: capsule v4:forth79.4th signature: missing (unsigned)
|
||||||
|
145 | PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x7d5965f7983485b9
|
||||||
|
146 | PARITY:V4_POST tests=539 pass=539 fail=0
|
||||||
|
147 | PARITY:V4_SYSTEM word_count=320 dict_hash=0x47570d4ced6ce255
|
||||||
|
148 | PARITY:OK
|
||||||
|
149 | POST: PASSED
|
||||||
|
150 | PCI: init...
|
||||||
|
151 | PCI: ECAM mapped (amd64)
|
||||||
|
152 | virtio-rng: no device on PCI bus 0
|
||||||
|
153 | rng: backend = rdrand
|
||||||
|
154 | entropy: ready
|
||||||
|
155 | virtio-input: no device on PCI bus 0
|
||||||
|
156 | Starting heartbeat...
|
||||||
|
157 | APIC Timer: started (LVT=0x00020020 ICR=9924004)
|
||||||
|
158 |
|
||||||
|
159 | I/O APIC: keyboard IRQ1 unmasked
|
||||||
|
160 | Heartbeat running.
|
||||||
|
161 | blkio_usb: MSC device ready
|
||||||
|
162 | Artemis: the stick's partition attached
|
||||||
|
163 | \x1b[38;2;255;165;0m[Hera]\x1b[39m Zuse: genesis minted onto attached thumbdrive
|
||||||
|
164 | \x1b[38;2;255;165;0m[zuse@Hera]\x1b[39m \x1b[38;2;85;255;255mok> \x1b[39m
|
||||||
|
---
|
||||||
|
PASS: [zuse@Hera] ok>
|
||||||
|
PASS: 7 ok, and a prompt
|
||||||
|
RESULT: FAIL
|
||||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
# #189 Phase 1 (plan 2026-11-13-engine-step4-phase1), Tasks 1-4, 2026-11-13
|
||||||
|
../amd64/physics-check-before.txt: the acceptance physics check (qemu_session.py physics()) on the v4 boot before: the three lines FAIL.
|
||||||
|
test_stadium_node-before.log: the node-key test before stadium_node_key/_boot_init_for/_birth_node existed: does not compile.
|
||||||
|
test_stadium_ops-before.log: the opcode-patron test before stadium_ops.c: no source to build.
|
||||||
|
test_stadium_ops-share-before.log: the share test against the first stadium_ops.c, which charged opcodes in order: ; took all 43691, the next 0 -- seen on a real boot as '1 resident, hottest opcode 0'.
|
||||||
|
bench_ops.txt (bench_ops.c): the charge on the host, every opcode retiring: about 0.5 us a charge; conservation held. Not the 'huge performance hit': it stands (Captain Bob, 2026-11-12).
|
||||||
|
The v3 path: logs/20261113-124843 (system=v3, v3_keys) prints its Stadium lines in the order of logs/20261106-192739.
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#include "starkernel/vm/stadium.h"
|
||||||
|
#include "starkernel/vm/stadium_ops.h"
|
||||||
|
#include "starkernel/session.h"
|
||||||
|
#include "starkernel/kmalloc.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
void *kmalloc(size_t size) { return calloc(1, size); }
|
||||||
|
void kfree(void *ptr) { free(ptr); }
|
||||||
|
kmalloc_stats_t kmalloc_get_stats(void) { kmalloc_stats_t s; memset(&s, 0, sizeof s); s.free_bytes = 512u*1024u*1024u; return s; }
|
||||||
|
void log_message(int level, const char *fmt, ...) { (void)level; (void)fmt; }
|
||||||
|
void sk_hal_panic(const char *m) { printf("PANIC %s\n", m); exit(2); }
|
||||||
|
int blk_flush(uint32_t b) { (void)b; return 0; }
|
||||||
|
int main(void) {
|
||||||
|
VMUuid key = stadium_node_key(10); uint64_t c[32]; unsigned k; long i, n = 1000000;
|
||||||
|
struct timespec a, b;
|
||||||
|
stadium_boot_init_for(key); session_boot_init(); stadium_birth_node(key, "Hera"); stadium_ops_init();
|
||||||
|
memset(c, 0, sizeof c);
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &a);
|
||||||
|
for (i = 1; i <= n; i++) { for (k = 0; k < 32; k++) c[k] += 1000 + k; stadium_ops_charge(key, c, (uint64_t)i); }
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &b);
|
||||||
|
printf("%ld charges, every opcode retiring: %.1f ns a charge; conserved=%d\n", n,
|
||||||
|
((b.tv_sec - a.tv_sec) * 1e9 + (b.tv_nsec - a.tv_nsec)) / n, stadium_conserved(key));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
1000000 charges, every opcode retiring: 553.5 ns a charge; conserved=1
|
||||||
|
1000000 charges, every opcode retiring: 465.8 ns a charge; conserved=1
|
||||||
|
1000000 charges, every opcode retiring: 526.8 ns a charge; conserved=1
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user