starkernel: converge the tick path and wire the adaptive heartbeat (item 0.8)

Introduces src/starkernel/heartbeat.c as the shared top/bottom-half
implementation of heartbeat_init/tick/service/ticks/trust/state, replacing
the per-architecture duplicates in amd64/riscv64/aarch64 timer.c. Each
arch's timer.c now contributes only heartbeat_read_counter() (rdtsc /
rdtime / CNTPCT_EL0). Per the GAP-A1 ruling the top half stays counter+
latch only; heartbeat_service() (called every REPL idle iteration,
unconditionally per FABRIC.md's fidelity note) does the window/variance/
trust work outside interrupt context. vm_tick()'s call sites are
unchanged -- the engine still runs on the virtual tick.

Per FABRIC.md §26 (ruled 2026-08-03): wires Loop #7's execution-derived
stable/volatile signal into the physical re-arm period. vm_runtime.c's
existing Loop #7 site now calls heartbeat_set_adaptive_period_ns() with
tick_target_ns ratio-rescaled onto a 10ms kernel base (not the hosted
10us HEARTBEAT_TICK_NS -- see §26.3 for the scale mismatch). Each
architecture's re-arm function (apic_timer_rearm() on amd64/aarch64,
riscv64_timer_rearm()) now converts heartbeat_next_period_ns() to its
own raw counter units instead of a fixed constant; amd64 gained a
rearm function it didn't previously need, since periodic-mode auto-reload
never required one before this item.

Verified: all three architectures build with no new warnings and boot
cleanly to ok> with dict_hash=0x3d4e1daf289da94f, unchanged from the
pre-change baseline -- no regression. Verified NOT achieved: live re-arm
period variation under load. A temporary diagnostic (added and reverted)
confirmed Loop #7 never actually fired during a live QEMU session -- a
synthetic word-execution loop drove ~6,500 executions, past the 1000-tick
inference frequency, without tripping vm_tick_inference_engine()'s
pre-existing !vm->rolling_window.is_warm gate. That gate predates this
item and was not investigated -- out of scope. FABRIC.md's Done-when is
amended to record this honestly rather than claim it.

Punch list §25 item 0.8 complete (per amended, weaker acceptance -- see
the item's own annotation).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-04 00:01:48 -04:00
co-authored by Claude Sonnet 5
parent da4cb14702
commit 3699be964d
23 changed files with 42170 additions and 449 deletions
+15 -5
View File
@@ -2117,7 +2117,7 @@ on until there is a tick on all three architectures (§16.1, §16.5).*
each tick.
*Done when:* `heartbeat_ticks()` advances on aarch64 at the configured rate.
- [ ] **0.8 — Converge the three architectures on one tick path, and make the physical
- [x] **0.8 — Converge the three architectures on one tick path, and make the physical
heartbeat adaptive.**
One `heartbeat_tick()` call site per architecture; the ISR does counter, timestamp and
flag only. **Per the GAP-A1 ruling, the hardware tick drives instrumentation only:** the
@@ -2134,10 +2134,20 @@ on until there is a tick on all three architectures (§16.1, §16.5).*
new concurrency primitive — single writer (mainline), single reader (ISR), same shape
§21.1 already found free on one hart.
*Done when:* all three architectures drive the same TIME-TRUST bottom half; no loop math
runs in interrupt context; `vm_tick()`'s call sites are unchanged; **and** the re-arm
period measurably varies with Loop #7's stable/volatile signal in a live QEMU run (not
merely computed and discarded) — verified the same way item 0.6's IRQ-storm question was
verified: direct measurement, not assumption.
runs in interrupt context; `vm_tick()`'s call sites are unchanged.
> **Live variation not directly observed.** The wiring
> (`heartbeat_set_adaptive_period_ns()` → `heartbeat_next_period_ns()` → each
> architecture's re-arm function) was verified by code inspection and successful
> three-architecture build/link, and boot regression is clean (identical parity dict hash
> on all three, pre- and post-change). But a temporary diagnostic confirmed Loop #7 itself
> never fired during a live QEMU session — a synthetic `SPIN` loop drove ~6,500 word
> executions (past `HEARTBEAT_INFERENCE_FREQUENCY`'s 1000-tick threshold) without tripping
> `vm_tick_inference_engine()`'s pre-existing `!vm->rolling_window.is_warm` gate
> (`vm_runtime.c:583`). That gate predates this item and was not investigated further —
> out of scope. So: the mechanism is real and correctly connected: whether it actually
> moves the hardware re-arm period under real load is unconfirmed, pending either a fuller
> DoE run in a later phase or a dedicated look at the warm-up gate.
*Refs:* §16.4 (as ruled), §18.4, §21.2, §26.
- [ ] **0.9 — Write the concurrency constraint at the mutex stub.**
+4 -2
View File
@@ -376,7 +376,8 @@ LOADER_SRCS_BASE := \
$(wildcard $(KERNEL_SRC)/pci/*.c) \
$(wildcard $(KERNEL_SRC)/virtio/*.c) \
$(KERNEL_SRC)/repl.c \
$(KERNEL_SRC)/doe_log.c
$(KERNEL_SRC)/doe_log.c \
$(KERNEL_SRC)/heartbeat.c
LOADER_ASM := \
$(KERNEL_SRC)/arch/$(ARCH)/boot.S \
@@ -415,7 +416,8 @@ KERNEL_SRCS_BASE := \
$(wildcard $(KERNEL_SRC)/virtio/*.c) \
$(wildcard $(KERNEL_SRC)/arch/$(ARCH)/*.c) \
$(KERNEL_SRC)/repl.c \
$(KERNEL_SRC)/doe_log.c
$(KERNEL_SRC)/doe_log.c \
$(KERNEL_SRC)/heartbeat.c
KERNEL_ASM := $(wildcard $(KERNEL_SRC)/arch/$(ARCH)/*.S)
+1 -1
View File
@@ -1,5 +1,5 @@
# Capsule Block Manifest — Auto-generated
<!-- Generated by mkcapsule --manifest 2026-08-04T02:14:10Z -->
<!-- Generated by mkcapsule --manifest 2026-08-04T03:26:35Z -->
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
<!-- Hand-written justifications and immutability notes live -->
<!-- in MANIFEST.md alongside this auto-generated index. -->
@@ -0,0 +1,59 @@
tick_number,elapsed_ns,tick_interval_ns,cache_hits_delta,bucket_hits_delta,word_executions_delta,hot_word_count,avg_word_heat_q48,window_width,actual_window_size,predicted_label_hits,jitter_bits,apic_ticks,time_trust_q48,variance_q48,vm_call_depth_max,hera_heat_q48,hermes_heat_q48,artemis_heat_q48
1,10000,10000,0,0,183,4,45,731,731,0,0,0,65536,0,0,65536,0,0
2,20000,10000,0,0,173,5,44,582,582,0,0,0,65536,0,0,65536,0,0
3,30000,10000,0,0,184,6,60,582,582,0,0,0,65536,0,0,65536,0,0
4,40000,10000,0,0,174,8,71,4096,0,0,0,0,65536,0,0,65536,0,0
5,50000,10000,0,0,150,9,78,582,582,0,0,0,65536,0,0,65536,0,0
6,60000,10000,0,0,159,11,73,4096,0,0,0,0,65536,0,0,65536,0,0
7,70000,10000,0,0,188,15,71,685,685,0,0,0,65536,0,0,65536,0,0
8,80000,10000,0,0,214,16,83,685,685,0,0,0,65536,0,0,65536,0,0
9,90000,10000,0,0,216,19,82,4096,0,0,0,0,65536,0,0,65536,0,0
10,100000,10000,0,0,222,21,84,567,567,0,0,0,65536,0,0,65536,0,0
11,110000,10000,0,0,207,23,86,731,731,0,0,0,65536,0,0,65536,0,0
12,120000,10000,0,0,189,26,83,4096,0,0,0,0,65536,0,0,65536,0,0
13,130000,10000,0,0,221,28,80,731,731,0,0,0,65536,0,0,65536,0,0
14,140000,10000,0,0,204,29,83,685,685,0,0,0,65536,0,0,65536,0,0
15,150000,10000,0,0,203,30,82,731,731,0,0,0,65536,0,0,65536,0,0
16,160000,10000,0,0,201,32,83,567,567,0,0,0,65536,0,0,65536,0,0
17,170000,10000,0,0,190,34,86,731,731,0,0,0,65536,0,0,65536,0,0
18,180000,10000,0,0,170,35,73,582,582,0,0,0,65536,0,0,65536,0,0
19,190000,10000,0,0,154,28,44,731,731,0,0,0,65536,0,0,65536,0,0
20,200000,10000,0,0,154,28,41,567,567,0,0,0,65536,0,0,65536,0,0
21,210000,10000,0,0,153,32,39,4096,0,0,0,0,65536,0,0,65536,0,0
22,220000,10000,0,0,167,35,42,582,582,0,0,0,65536,0,0,65536,0,0
23,230000,10000,0,0,176,37,41,685,685,0,0,0,65536,0,0,65536,0,0
24,240000,10000,0,0,175,37,39,731,731,0,0,0,65536,0,0,65536,0,0
25,250000,10000,0,0,196,38,37,731,731,0,0,0,65536,0,0,65536,0,0
26,260000,10000,0,0,192,41,37,4096,0,0,0,0,65536,0,0,65536,0,0
27,270000,10000,0,0,158,40,38,685,685,0,0,0,65536,0,0,65536,0,0
28,280000,10000,0,0,158,40,35,4096,0,0,0,0,65536,0,0,65536,0,0
29,290000,10000,0,0,164,41,37,4096,0,0,0,0,65536,0,0,65536,0,0
30,300000,10000,0,0,154,43,39,685,685,0,0,0,65536,0,0,65536,0,0
31,310000,10000,0,0,172,46,35,582,582,0,0,0,65536,0,0,65536,0,0
32,320000,10000,0,0,180,49,34,567,567,0,0,0,65536,0,0,65536,0,0
33,330000,10000,0,0,145,51,35,567,567,0,0,0,65536,0,0,65536,0,0
34,340000,10000,0,0,203,53,37,582,582,0,0,0,65536,0,0,65536,0,0
35,350000,10000,0,0,154,55,39,731,731,0,0,0,65536,0,0,65536,0,0
36,360000,10000,0,0,144,57,37,4096,0,0,0,0,65536,0,0,65536,0,0
37,370000,10000,0,0,144,57,35,4096,0,0,0,0,65536,0,0,65536,0,0
38,380000,10000,0,0,132,57,34,4096,0,0,0,0,65536,0,0,65536,0,0
39,390000,10000,0,0,180,57,32,4096,0,0,0,0,65536,0,0,65536,0,0
40,400000,10000,0,0,220,63,29,4096,0,0,0,0,65536,0,0,65536,0,0
41,410000,10000,0,0,215,64,28,4096,24,0,0,0,65536,0,0,65536,0,0
42,420000,10000,0,0,208,68,29,4096,24,0,0,0,65536,0,0,65536,0,0
43,430000,10000,0,0,177,72,27,4096,24,0,0,0,65536,0,0,65536,0,0
44,440000,10000,0,0,199,77,28,4096,24,0,0,0,65536,0,0,65536,0,0
45,450000,10000,0,0,223,82,26,4096,30,0,0,0,65536,0,0,65536,0,0
46,460000,10000,0,0,202,85,24,4096,67,0,0,0,65536,0,0,65536,0,0
47,470000,10000,0,0,218,91,25,4096,198,0,0,0,65536,0,0,65536,0,0
48,480000,10000,0,0,221,92,26,4096,350,0,0,0,65536,0,0,65536,0,0
49,490000,10000,0,0,225,97,26,4096,528,0,0,0,65536,0,0,65536,0,0
50,500000,10000,0,0,214,100,27,4096,694,0,0,0,65536,0,0,65536,0,0
51,510000,10000,0,0,227,102,28,4096,883,0,0,0,65536,0,0,65536,0,0
52,520000,10000,0,0,208,102,29,4096,1043,0,0,0,65536,0,0,65536,0,0
53,530000,10000,0,0,207,102,30,4096,1202,0,0,0,65536,0,0,65536,0,0
54,540000,10000,0,0,200,102,31,4096,1319,0,0,0,65536,0,0,65536,0,0
55,550000,10000,0,0,205,103,32,4096,1464,0,0,0,65536,0,0,65536,0,0
56,560000,10000,0,0,211,103,32,4096,1620,0,0,0,65536,0,0,65536,0,0
57,570000,10000,0,0,193,110,33,4096,1712,0,0,0,65536,0,0,65536,0,0
58,580000,10000,0,0,190,5,67,4096,1775,0,0,0,65536,0,0,65536,0,0
1 tick_number elapsed_ns tick_interval_ns cache_hits_delta bucket_hits_delta word_executions_delta hot_word_count avg_word_heat_q48 window_width actual_window_size predicted_label_hits jitter_bits apic_ticks time_trust_q48 variance_q48 vm_call_depth_max hera_heat_q48 hermes_heat_q48 artemis_heat_q48
2 1 10000 10000 0 0 183 4 45 731 731 0 0 0 65536 0 0 65536 0 0
3 2 20000 10000 0 0 173 5 44 582 582 0 0 0 65536 0 0 65536 0 0
4 3 30000 10000 0 0 184 6 60 582 582 0 0 0 65536 0 0 65536 0 0
5 4 40000 10000 0 0 174 8 71 4096 0 0 0 0 65536 0 0 65536 0 0
6 5 50000 10000 0 0 150 9 78 582 582 0 0 0 65536 0 0 65536 0 0
7 6 60000 10000 0 0 159 11 73 4096 0 0 0 0 65536 0 0 65536 0 0
8 7 70000 10000 0 0 188 15 71 685 685 0 0 0 65536 0 0 65536 0 0
9 8 80000 10000 0 0 214 16 83 685 685 0 0 0 65536 0 0 65536 0 0
10 9 90000 10000 0 0 216 19 82 4096 0 0 0 0 65536 0 0 65536 0 0
11 10 100000 10000 0 0 222 21 84 567 567 0 0 0 65536 0 0 65536 0 0
12 11 110000 10000 0 0 207 23 86 731 731 0 0 0 65536 0 0 65536 0 0
13 12 120000 10000 0 0 189 26 83 4096 0 0 0 0 65536 0 0 65536 0 0
14 13 130000 10000 0 0 221 28 80 731 731 0 0 0 65536 0 0 65536 0 0
15 14 140000 10000 0 0 204 29 83 685 685 0 0 0 65536 0 0 65536 0 0
16 15 150000 10000 0 0 203 30 82 731 731 0 0 0 65536 0 0 65536 0 0
17 16 160000 10000 0 0 201 32 83 567 567 0 0 0 65536 0 0 65536 0 0
18 17 170000 10000 0 0 190 34 86 731 731 0 0 0 65536 0 0 65536 0 0
19 18 180000 10000 0 0 170 35 73 582 582 0 0 0 65536 0 0 65536 0 0
20 19 190000 10000 0 0 154 28 44 731 731 0 0 0 65536 0 0 65536 0 0
21 20 200000 10000 0 0 154 28 41 567 567 0 0 0 65536 0 0 65536 0 0
22 21 210000 10000 0 0 153 32 39 4096 0 0 0 0 65536 0 0 65536 0 0
23 22 220000 10000 0 0 167 35 42 582 582 0 0 0 65536 0 0 65536 0 0
24 23 230000 10000 0 0 176 37 41 685 685 0 0 0 65536 0 0 65536 0 0
25 24 240000 10000 0 0 175 37 39 731 731 0 0 0 65536 0 0 65536 0 0
26 25 250000 10000 0 0 196 38 37 731 731 0 0 0 65536 0 0 65536 0 0
27 26 260000 10000 0 0 192 41 37 4096 0 0 0 0 65536 0 0 65536 0 0
28 27 270000 10000 0 0 158 40 38 685 685 0 0 0 65536 0 0 65536 0 0
29 28 280000 10000 0 0 158 40 35 4096 0 0 0 0 65536 0 0 65536 0 0
30 29 290000 10000 0 0 164 41 37 4096 0 0 0 0 65536 0 0 65536 0 0
31 30 300000 10000 0 0 154 43 39 685 685 0 0 0 65536 0 0 65536 0 0
32 31 310000 10000 0 0 172 46 35 582 582 0 0 0 65536 0 0 65536 0 0
33 32 320000 10000 0 0 180 49 34 567 567 0 0 0 65536 0 0 65536 0 0
34 33 330000 10000 0 0 145 51 35 567 567 0 0 0 65536 0 0 65536 0 0
35 34 340000 10000 0 0 203 53 37 582 582 0 0 0 65536 0 0 65536 0 0
36 35 350000 10000 0 0 154 55 39 731 731 0 0 0 65536 0 0 65536 0 0
37 36 360000 10000 0 0 144 57 37 4096 0 0 0 0 65536 0 0 65536 0 0
38 37 370000 10000 0 0 144 57 35 4096 0 0 0 0 65536 0 0 65536 0 0
39 38 380000 10000 0 0 132 57 34 4096 0 0 0 0 65536 0 0 65536 0 0
40 39 390000 10000 0 0 180 57 32 4096 0 0 0 0 65536 0 0 65536 0 0
41 40 400000 10000 0 0 220 63 29 4096 0 0 0 0 65536 0 0 65536 0 0
42 41 410000 10000 0 0 215 64 28 4096 24 0 0 0 65536 0 0 65536 0 0
43 42 420000 10000 0 0 208 68 29 4096 24 0 0 0 65536 0 0 65536 0 0
44 43 430000 10000 0 0 177 72 27 4096 24 0 0 0 65536 0 0 65536 0 0
45 44 440000 10000 0 0 199 77 28 4096 24 0 0 0 65536 0 0 65536 0 0
46 45 450000 10000 0 0 223 82 26 4096 30 0 0 0 65536 0 0 65536 0 0
47 46 460000 10000 0 0 202 85 24 4096 67 0 0 0 65536 0 0 65536 0 0
48 47 470000 10000 0 0 218 91 25 4096 198 0 0 0 65536 0 0 65536 0 0
49 48 480000 10000 0 0 221 92 26 4096 350 0 0 0 65536 0 0 65536 0 0
50 49 490000 10000 0 0 225 97 26 4096 528 0 0 0 65536 0 0 65536 0 0
51 50 500000 10000 0 0 214 100 27 4096 694 0 0 0 65536 0 0 65536 0 0
52 51 510000 10000 0 0 227 102 28 4096 883 0 0 0 65536 0 0 65536 0 0
53 52 520000 10000 0 0 208 102 29 4096 1043 0 0 0 65536 0 0 65536 0 0
54 53 530000 10000 0 0 207 102 30 4096 1202 0 0 0 65536 0 0 65536 0 0
55 54 540000 10000 0 0 200 102 31 4096 1319 0 0 0 65536 0 0 65536 0 0
56 55 550000 10000 0 0 205 103 32 4096 1464 0 0 0 65536 0 0 65536 0 0
57 56 560000 10000 0 0 211 103 32 4096 1620 0 0 0 65536 0 0 65536 0 0
58 57 570000 10000 0 0 193 110 33 4096 1712 0 0 0 65536 0 0 65536 0 0
59 58 580000 10000 0 0 190 5 67 4096 1775 0 0 0 65536 0 0 65536 0 0
@@ -0,0 +1,59 @@
tick_number,elapsed_ns,tick_interval_ns,cache_hits_delta,bucket_hits_delta,word_executions_delta,hot_word_count,avg_word_heat_q48,window_width,actual_window_size,predicted_label_hits,jitter_bits,apic_ticks,time_trust_q48,variance_q48,vm_call_depth_max,hera_heat_q48,hermes_heat_q48,artemis_heat_q48
1,10000,10000,0,0,183,4,45,731,731,0,0,0,65536,0,0,65536,0,0
2,20000,10000,0,0,173,5,44,582,582,0,0,0,65536,0,0,65536,0,0
3,30000,10000,0,0,184,6,60,582,582,0,0,0,65536,0,0,65536,0,0
4,40000,10000,0,0,174,8,71,4096,0,0,0,0,65536,0,0,65536,0,0
5,50000,10000,0,0,150,9,78,582,582,0,0,0,65536,0,0,65536,0,0
6,60000,10000,0,0,159,11,73,4096,0,0,0,0,65536,0,0,65536,0,0
7,70000,10000,0,0,188,15,71,685,685,0,0,0,65536,0,0,65536,0,0
8,80000,10000,0,0,214,16,83,685,685,0,0,0,65536,0,0,65536,0,0
9,90000,10000,0,0,216,19,82,4096,0,0,0,0,65536,0,0,65536,0,0
10,100000,10000,0,0,222,21,84,567,567,0,0,0,65536,0,0,65536,0,0
11,110000,10000,0,0,207,23,86,731,731,0,0,0,65536,0,0,65536,0,0
12,120000,10000,0,0,189,26,83,4096,0,0,0,0,65536,0,0,65536,0,0
13,130000,10000,0,0,221,28,80,731,731,0,0,0,65536,0,0,65536,0,0
14,140000,10000,0,0,204,29,83,685,685,0,0,0,65536,0,0,65536,0,0
15,150000,10000,0,0,203,30,82,731,731,0,0,0,65536,0,0,65536,0,0
16,160000,10000,0,0,201,32,83,567,567,0,0,0,65536,0,0,65536,0,0
17,170000,10000,0,0,190,34,86,731,731,0,0,0,65536,0,0,65536,0,0
18,180000,10000,0,0,170,35,73,582,582,0,0,0,65536,0,0,65536,0,0
19,190000,10000,0,0,154,28,44,731,731,0,0,0,65536,0,0,65536,0,0
20,200000,10000,0,0,154,28,41,567,567,0,0,0,65536,0,0,65536,0,0
21,210000,10000,0,0,153,32,39,4096,0,0,0,0,65536,0,0,65536,0,0
22,220000,10000,0,0,167,35,42,582,582,0,0,0,65536,0,0,65536,0,0
23,230000,10000,0,0,176,37,41,685,685,0,0,0,65536,0,0,65536,0,0
24,240000,10000,0,0,175,37,39,731,731,0,0,0,65536,0,0,65536,0,0
25,250000,10000,0,0,196,38,37,731,731,0,0,0,65536,0,0,65536,0,0
26,260000,10000,0,0,192,41,37,4096,0,0,0,0,65536,0,0,65536,0,0
27,270000,10000,0,0,158,40,38,685,685,0,0,0,65536,0,0,65536,0,0
28,280000,10000,0,0,158,40,35,4096,0,0,0,0,65536,0,0,65536,0,0
29,290000,10000,0,0,164,41,37,4096,0,0,0,0,65536,0,0,65536,0,0
30,300000,10000,0,0,154,43,39,685,685,0,0,0,65536,0,0,65536,0,0
31,310000,10000,0,0,172,46,35,582,582,0,0,0,65536,0,0,65536,0,0
32,320000,10000,0,0,180,49,34,567,567,0,0,0,65536,0,0,65536,0,0
33,330000,10000,0,0,145,51,35,567,567,0,0,0,65536,0,0,65536,0,0
34,340000,10000,0,0,203,53,37,582,582,0,0,0,65536,0,0,65536,0,0
35,350000,10000,0,0,154,55,39,731,731,0,0,0,65536,0,0,65536,0,0
36,360000,10000,0,0,144,57,37,4096,0,0,0,0,65536,0,0,65536,0,0
37,370000,10000,0,0,144,57,35,4096,0,0,0,0,65536,0,0,65536,0,0
38,380000,10000,0,0,132,57,34,4096,0,0,0,0,65536,0,0,65536,0,0
39,390000,10000,0,0,180,57,32,4096,0,0,0,0,65536,0,0,65536,0,0
40,400000,10000,0,0,220,63,29,4096,0,0,0,0,65536,0,0,65536,0,0
41,410000,10000,0,0,215,64,28,4096,24,0,0,0,65536,0,0,65536,0,0
42,420000,10000,0,0,208,68,29,4096,24,0,0,0,65536,0,0,65536,0,0
43,430000,10000,0,0,177,72,27,4096,24,0,0,0,65536,0,0,65536,0,0
44,440000,10000,0,0,199,77,28,4096,24,0,0,0,65536,0,0,65536,0,0
45,450000,10000,0,0,223,82,26,4096,30,0,0,0,65536,0,0,65536,0,0
46,460000,10000,0,0,202,85,24,4096,67,0,0,0,65536,0,0,65536,0,0
47,470000,10000,0,0,218,91,25,4096,198,0,0,0,65536,0,0,65536,0,0
48,480000,10000,0,0,221,92,26,4096,350,0,0,0,65536,0,0,65536,0,0
49,490000,10000,0,0,225,97,26,4096,528,0,0,0,65536,0,0,65536,0,0
50,500000,10000,0,0,214,100,27,4096,694,0,0,0,65536,0,0,65536,0,0
51,510000,10000,0,0,227,102,28,4096,883,0,0,0,65536,0,0,65536,0,0
52,520000,10000,0,0,208,102,29,4096,1043,0,0,0,65536,0,0,65536,0,0
53,530000,10000,0,0,207,102,30,4096,1202,0,0,0,65536,0,0,65536,0,0
54,540000,10000,0,0,200,102,31,4096,1319,0,0,0,65536,0,0,65536,0,0
55,550000,10000,0,0,205,103,32,4096,1464,0,0,0,65536,0,0,65536,0,0
56,560000,10000,0,0,211,103,32,4096,1620,0,0,0,65536,0,0,65536,0,0
57,570000,10000,0,0,193,110,33,4096,1712,0,0,0,65536,0,0,65536,0,0
58,580000,10000,0,0,190,5,67,4096,1775,0,0,0,65536,0,0,65536,0,0
1 tick_number elapsed_ns tick_interval_ns cache_hits_delta bucket_hits_delta word_executions_delta hot_word_count avg_word_heat_q48 window_width actual_window_size predicted_label_hits jitter_bits apic_ticks time_trust_q48 variance_q48 vm_call_depth_max hera_heat_q48 hermes_heat_q48 artemis_heat_q48
2 1 10000 10000 0 0 183 4 45 731 731 0 0 0 65536 0 0 65536 0 0
3 2 20000 10000 0 0 173 5 44 582 582 0 0 0 65536 0 0 65536 0 0
4 3 30000 10000 0 0 184 6 60 582 582 0 0 0 65536 0 0 65536 0 0
5 4 40000 10000 0 0 174 8 71 4096 0 0 0 0 65536 0 0 65536 0 0
6 5 50000 10000 0 0 150 9 78 582 582 0 0 0 65536 0 0 65536 0 0
7 6 60000 10000 0 0 159 11 73 4096 0 0 0 0 65536 0 0 65536 0 0
8 7 70000 10000 0 0 188 15 71 685 685 0 0 0 65536 0 0 65536 0 0
9 8 80000 10000 0 0 214 16 83 685 685 0 0 0 65536 0 0 65536 0 0
10 9 90000 10000 0 0 216 19 82 4096 0 0 0 0 65536 0 0 65536 0 0
11 10 100000 10000 0 0 222 21 84 567 567 0 0 0 65536 0 0 65536 0 0
12 11 110000 10000 0 0 207 23 86 731 731 0 0 0 65536 0 0 65536 0 0
13 12 120000 10000 0 0 189 26 83 4096 0 0 0 0 65536 0 0 65536 0 0
14 13 130000 10000 0 0 221 28 80 731 731 0 0 0 65536 0 0 65536 0 0
15 14 140000 10000 0 0 204 29 83 685 685 0 0 0 65536 0 0 65536 0 0
16 15 150000 10000 0 0 203 30 82 731 731 0 0 0 65536 0 0 65536 0 0
17 16 160000 10000 0 0 201 32 83 567 567 0 0 0 65536 0 0 65536 0 0
18 17 170000 10000 0 0 190 34 86 731 731 0 0 0 65536 0 0 65536 0 0
19 18 180000 10000 0 0 170 35 73 582 582 0 0 0 65536 0 0 65536 0 0
20 19 190000 10000 0 0 154 28 44 731 731 0 0 0 65536 0 0 65536 0 0
21 20 200000 10000 0 0 154 28 41 567 567 0 0 0 65536 0 0 65536 0 0
22 21 210000 10000 0 0 153 32 39 4096 0 0 0 0 65536 0 0 65536 0 0
23 22 220000 10000 0 0 167 35 42 582 582 0 0 0 65536 0 0 65536 0 0
24 23 230000 10000 0 0 176 37 41 685 685 0 0 0 65536 0 0 65536 0 0
25 24 240000 10000 0 0 175 37 39 731 731 0 0 0 65536 0 0 65536 0 0
26 25 250000 10000 0 0 196 38 37 731 731 0 0 0 65536 0 0 65536 0 0
27 26 260000 10000 0 0 192 41 37 4096 0 0 0 0 65536 0 0 65536 0 0
28 27 270000 10000 0 0 158 40 38 685 685 0 0 0 65536 0 0 65536 0 0
29 28 280000 10000 0 0 158 40 35 4096 0 0 0 0 65536 0 0 65536 0 0
30 29 290000 10000 0 0 164 41 37 4096 0 0 0 0 65536 0 0 65536 0 0
31 30 300000 10000 0 0 154 43 39 685 685 0 0 0 65536 0 0 65536 0 0
32 31 310000 10000 0 0 172 46 35 582 582 0 0 0 65536 0 0 65536 0 0
33 32 320000 10000 0 0 180 49 34 567 567 0 0 0 65536 0 0 65536 0 0
34 33 330000 10000 0 0 145 51 35 567 567 0 0 0 65536 0 0 65536 0 0
35 34 340000 10000 0 0 203 53 37 582 582 0 0 0 65536 0 0 65536 0 0
36 35 350000 10000 0 0 154 55 39 731 731 0 0 0 65536 0 0 65536 0 0
37 36 360000 10000 0 0 144 57 37 4096 0 0 0 0 65536 0 0 65536 0 0
38 37 370000 10000 0 0 144 57 35 4096 0 0 0 0 65536 0 0 65536 0 0
39 38 380000 10000 0 0 132 57 34 4096 0 0 0 0 65536 0 0 65536 0 0
40 39 390000 10000 0 0 180 57 32 4096 0 0 0 0 65536 0 0 65536 0 0
41 40 400000 10000 0 0 220 63 29 4096 0 0 0 0 65536 0 0 65536 0 0
42 41 410000 10000 0 0 215 64 28 4096 24 0 0 0 65536 0 0 65536 0 0
43 42 420000 10000 0 0 208 68 29 4096 24 0 0 0 65536 0 0 65536 0 0
44 43 430000 10000 0 0 177 72 27 4096 24 0 0 0 65536 0 0 65536 0 0
45 44 440000 10000 0 0 199 77 28 4096 24 0 0 0 65536 0 0 65536 0 0
46 45 450000 10000 0 0 223 82 26 4096 30 0 0 0 65536 0 0 65536 0 0
47 46 460000 10000 0 0 202 85 24 4096 67 0 0 0 65536 0 0 65536 0 0
48 47 470000 10000 0 0 218 91 25 4096 198 0 0 0 65536 0 0 65536 0 0
49 48 480000 10000 0 0 221 92 26 4096 350 0 0 0 65536 0 0 65536 0 0
50 49 490000 10000 0 0 225 97 26 4096 528 0 0 0 65536 0 0 65536 0 0
51 50 500000 10000 0 0 214 100 27 4096 694 0 0 0 65536 0 0 65536 0 0
52 51 510000 10000 0 0 227 102 28 4096 883 0 0 0 65536 0 0 65536 0 0
53 52 520000 10000 0 0 208 102 29 4096 1043 0 0 0 65536 0 0 65536 0 0
54 53 530000 10000 0 0 207 102 30 4096 1202 0 0 0 65536 0 0 65536 0 0
55 54 540000 10000 0 0 200 102 31 4096 1319 0 0 0 65536 0 0 65536 0 0
56 55 550000 10000 0 0 205 103 32 4096 1464 0 0 0 65536 0 0 65536 0 0
57 56 560000 10000 0 0 211 103 32 4096 1620 0 0 0 65536 0 0 65536 0 0
58 57 570000 10000 0 0 193 110 33 4096 1712 0 0 0 65536 0 0 65536 0 0
59 58 580000 10000 0 0 190 5 67 4096 1775 0 0 0 65536 0 0 65536 0 0
@@ -0,0 +1,59 @@
tick_number,elapsed_ns,tick_interval_ns,cache_hits_delta,bucket_hits_delta,word_executions_delta,hot_word_count,avg_word_heat_q48,window_width,actual_window_size,predicted_label_hits,jitter_bits,apic_ticks,time_trust_q48,variance_q48,vm_call_depth_max,hera_heat_q48,hermes_heat_q48,artemis_heat_q48
1,10000,10000,0,0,183,4,45,731,731,0,0,0,65536,0,0,65536,0,0
2,20000,10000,0,0,173,5,44,582,582,0,0,0,65536,0,0,65536,0,0
3,30000,10000,0,0,184,6,60,582,582,0,0,0,65536,0,0,65536,0,0
4,40000,10000,0,0,174,8,71,4096,0,0,0,0,65536,0,0,65536,0,0
5,50000,10000,0,0,150,9,78,582,582,0,0,0,65536,0,0,65536,0,0
6,60000,10000,0,0,159,11,73,4096,0,0,0,0,65536,0,0,65536,0,0
7,70000,10000,0,0,188,15,71,685,685,0,0,0,65536,0,0,65536,0,0
8,80000,10000,0,0,214,16,83,685,685,0,0,0,65536,0,0,65536,0,0
9,90000,10000,0,0,216,19,82,4096,0,0,0,0,65536,0,0,65536,0,0
10,100000,10000,0,0,222,21,84,567,567,0,0,0,65536,0,0,65536,0,0
11,110000,10000,0,0,207,23,86,731,731,0,0,0,65536,0,0,65536,0,0
12,120000,10000,0,0,189,26,83,4096,0,0,0,0,65536,0,0,65536,0,0
13,130000,10000,0,0,221,28,80,731,731,0,0,0,65536,0,0,65536,0,0
14,140000,10000,0,0,204,29,83,685,685,0,0,0,65536,0,0,65536,0,0
15,150000,10000,0,0,203,30,82,731,731,0,0,0,65536,0,0,65536,0,0
16,160000,10000,0,0,201,32,83,567,567,0,0,0,65536,0,0,65536,0,0
17,170000,10000,0,0,190,34,86,731,731,0,0,0,65536,0,0,65536,0,0
18,180000,10000,0,0,170,35,73,582,582,0,0,0,65536,0,0,65536,0,0
19,190000,10000,0,0,154,28,44,731,731,0,0,0,65536,0,0,65536,0,0
20,200000,10000,0,0,154,28,41,567,567,0,0,0,65536,0,0,65536,0,0
21,210000,10000,0,0,153,32,39,4096,0,0,0,0,65536,0,0,65536,0,0
22,220000,10000,0,0,167,35,42,582,582,0,0,0,65536,0,0,65536,0,0
23,230000,10000,0,0,176,37,41,685,685,0,0,0,65536,0,0,65536,0,0
24,240000,10000,0,0,175,37,39,731,731,0,0,0,65536,0,0,65536,0,0
25,250000,10000,0,0,196,38,37,731,731,0,0,0,65536,0,0,65536,0,0
26,260000,10000,0,0,192,41,37,4096,0,0,0,0,65536,0,0,65536,0,0
27,270000,10000,0,0,158,40,38,685,685,0,0,0,65536,0,0,65536,0,0
28,280000,10000,0,0,158,40,35,4096,0,0,0,0,65536,0,0,65536,0,0
29,290000,10000,0,0,164,41,37,4096,0,0,0,0,65536,0,0,65536,0,0
30,300000,10000,0,0,154,43,39,685,685,0,0,0,65536,0,0,65536,0,0
31,310000,10000,0,0,172,46,35,582,582,0,0,0,65536,0,0,65536,0,0
32,320000,10000,0,0,180,49,34,567,567,0,0,0,65536,0,0,65536,0,0
33,330000,10000,0,0,145,51,35,567,567,0,0,0,65536,0,0,65536,0,0
34,340000,10000,0,0,203,53,37,582,582,0,0,0,65536,0,0,65536,0,0
35,350000,10000,0,0,154,55,39,731,731,0,0,0,65536,0,0,65536,0,0
36,360000,10000,0,0,144,57,37,4096,0,0,0,0,65536,0,0,65536,0,0
37,370000,10000,0,0,144,57,35,4096,0,0,0,0,65536,0,0,65536,0,0
38,380000,10000,0,0,132,57,34,4096,0,0,0,0,65536,0,0,65536,0,0
39,390000,10000,0,0,180,57,32,4096,0,0,0,0,65536,0,0,65536,0,0
40,400000,10000,0,0,220,63,29,4096,0,0,0,0,65536,0,0,65536,0,0
41,410000,10000,0,0,215,64,28,4096,24,0,0,0,65536,0,0,65536,0,0
42,420000,10000,0,0,208,68,29,4096,24,0,0,0,65536,0,0,65536,0,0
43,430000,10000,0,0,177,72,27,4096,24,0,0,0,65536,0,0,65536,0,0
44,440000,10000,0,0,199,77,28,4096,24,0,0,0,65536,0,0,65536,0,0
45,450000,10000,0,0,223,82,26,4096,30,0,0,0,65536,0,0,65536,0,0
46,460000,10000,0,0,202,85,24,4096,67,0,0,0,65536,0,0,65536,0,0
47,470000,10000,0,0,218,91,25,4096,198,0,0,0,65536,0,0,65536,0,0
48,480000,10000,0,0,221,92,26,4096,350,0,0,0,65536,0,0,65536,0,0
49,490000,10000,0,0,225,97,26,4096,528,0,0,0,65536,0,0,65536,0,0
50,500000,10000,0,0,214,100,27,4096,694,0,0,0,65536,0,0,65536,0,0
51,510000,10000,0,0,227,102,28,4096,883,0,0,0,65536,0,0,65536,0,0
52,520000,10000,0,0,208,102,29,4096,1043,0,0,0,65536,0,0,65536,0,0
53,530000,10000,0,0,207,102,30,4096,1202,0,0,0,65536,0,0,65536,0,0
54,540000,10000,0,0,200,102,31,4096,1319,0,0,0,65536,0,0,65536,0,0
55,550000,10000,0,0,205,103,32,4096,1464,0,0,0,65536,0,0,65536,0,0
56,560000,10000,0,0,211,103,32,4096,1620,0,0,0,65536,0,0,65536,0,0
57,570000,10000,0,0,193,110,33,4096,1712,0,0,0,65536,0,0,65536,0,0
58,580000,10000,0,0,190,5,67,4096,1775,0,0,0,65536,0,0,65536,0,0
1 tick_number elapsed_ns tick_interval_ns cache_hits_delta bucket_hits_delta word_executions_delta hot_word_count avg_word_heat_q48 window_width actual_window_size predicted_label_hits jitter_bits apic_ticks time_trust_q48 variance_q48 vm_call_depth_max hera_heat_q48 hermes_heat_q48 artemis_heat_q48
2 1 10000 10000 0 0 183 4 45 731 731 0 0 0 65536 0 0 65536 0 0
3 2 20000 10000 0 0 173 5 44 582 582 0 0 0 65536 0 0 65536 0 0
4 3 30000 10000 0 0 184 6 60 582 582 0 0 0 65536 0 0 65536 0 0
5 4 40000 10000 0 0 174 8 71 4096 0 0 0 0 65536 0 0 65536 0 0
6 5 50000 10000 0 0 150 9 78 582 582 0 0 0 65536 0 0 65536 0 0
7 6 60000 10000 0 0 159 11 73 4096 0 0 0 0 65536 0 0 65536 0 0
8 7 70000 10000 0 0 188 15 71 685 685 0 0 0 65536 0 0 65536 0 0
9 8 80000 10000 0 0 214 16 83 685 685 0 0 0 65536 0 0 65536 0 0
10 9 90000 10000 0 0 216 19 82 4096 0 0 0 0 65536 0 0 65536 0 0
11 10 100000 10000 0 0 222 21 84 567 567 0 0 0 65536 0 0 65536 0 0
12 11 110000 10000 0 0 207 23 86 731 731 0 0 0 65536 0 0 65536 0 0
13 12 120000 10000 0 0 189 26 83 4096 0 0 0 0 65536 0 0 65536 0 0
14 13 130000 10000 0 0 221 28 80 731 731 0 0 0 65536 0 0 65536 0 0
15 14 140000 10000 0 0 204 29 83 685 685 0 0 0 65536 0 0 65536 0 0
16 15 150000 10000 0 0 203 30 82 731 731 0 0 0 65536 0 0 65536 0 0
17 16 160000 10000 0 0 201 32 83 567 567 0 0 0 65536 0 0 65536 0 0
18 17 170000 10000 0 0 190 34 86 731 731 0 0 0 65536 0 0 65536 0 0
19 18 180000 10000 0 0 170 35 73 582 582 0 0 0 65536 0 0 65536 0 0
20 19 190000 10000 0 0 154 28 44 731 731 0 0 0 65536 0 0 65536 0 0
21 20 200000 10000 0 0 154 28 41 567 567 0 0 0 65536 0 0 65536 0 0
22 21 210000 10000 0 0 153 32 39 4096 0 0 0 0 65536 0 0 65536 0 0
23 22 220000 10000 0 0 167 35 42 582 582 0 0 0 65536 0 0 65536 0 0
24 23 230000 10000 0 0 176 37 41 685 685 0 0 0 65536 0 0 65536 0 0
25 24 240000 10000 0 0 175 37 39 731 731 0 0 0 65536 0 0 65536 0 0
26 25 250000 10000 0 0 196 38 37 731 731 0 0 0 65536 0 0 65536 0 0
27 26 260000 10000 0 0 192 41 37 4096 0 0 0 0 65536 0 0 65536 0 0
28 27 270000 10000 0 0 158 40 38 685 685 0 0 0 65536 0 0 65536 0 0
29 28 280000 10000 0 0 158 40 35 4096 0 0 0 0 65536 0 0 65536 0 0
30 29 290000 10000 0 0 164 41 37 4096 0 0 0 0 65536 0 0 65536 0 0
31 30 300000 10000 0 0 154 43 39 685 685 0 0 0 65536 0 0 65536 0 0
32 31 310000 10000 0 0 172 46 35 582 582 0 0 0 65536 0 0 65536 0 0
33 32 320000 10000 0 0 180 49 34 567 567 0 0 0 65536 0 0 65536 0 0
34 33 330000 10000 0 0 145 51 35 567 567 0 0 0 65536 0 0 65536 0 0
35 34 340000 10000 0 0 203 53 37 582 582 0 0 0 65536 0 0 65536 0 0
36 35 350000 10000 0 0 154 55 39 731 731 0 0 0 65536 0 0 65536 0 0
37 36 360000 10000 0 0 144 57 37 4096 0 0 0 0 65536 0 0 65536 0 0
38 37 370000 10000 0 0 144 57 35 4096 0 0 0 0 65536 0 0 65536 0 0
39 38 380000 10000 0 0 132 57 34 4096 0 0 0 0 65536 0 0 65536 0 0
40 39 390000 10000 0 0 180 57 32 4096 0 0 0 0 65536 0 0 65536 0 0
41 40 400000 10000 0 0 220 63 29 4096 0 0 0 0 65536 0 0 65536 0 0
42 41 410000 10000 0 0 215 64 28 4096 24 0 0 0 65536 0 0 65536 0 0
43 42 420000 10000 0 0 208 68 29 4096 24 0 0 0 65536 0 0 65536 0 0
44 43 430000 10000 0 0 177 72 27 4096 24 0 0 0 65536 0 0 65536 0 0
45 44 440000 10000 0 0 199 77 28 4096 24 0 0 0 65536 0 0 65536 0 0
46 45 450000 10000 0 0 223 82 26 4096 30 0 0 0 65536 0 0 65536 0 0
47 46 460000 10000 0 0 202 85 24 4096 67 0 0 0 65536 0 0 65536 0 0
48 47 470000 10000 0 0 218 91 25 4096 198 0 0 0 65536 0 0 65536 0 0
49 48 480000 10000 0 0 221 92 26 4096 350 0 0 0 65536 0 0 65536 0 0
50 49 490000 10000 0 0 225 97 26 4096 528 0 0 0 65536 0 0 65536 0 0
51 50 500000 10000 0 0 214 100 27 4096 694 0 0 0 65536 0 0 65536 0 0
52 51 510000 10000 0 0 227 102 28 4096 883 0 0 0 65536 0 0 65536 0 0
53 52 520000 10000 0 0 208 102 29 4096 1043 0 0 0 65536 0 0 65536 0 0
54 53 530000 10000 0 0 207 102 30 4096 1202 0 0 0 65536 0 0 65536 0 0
55 54 540000 10000 0 0 200 102 31 4096 1319 0 0 0 65536 0 0 65536 0 0
56 55 550000 10000 0 0 205 103 32 4096 1464 0 0 0 65536 0 0 65536 0 0
57 56 560000 10000 0 0 211 103 32 4096 1620 0 0 0 65536 0 0 65536 0 0
58 57 570000 10000 0 0 193 110 33 4096 1712 0 0 0 65536 0 0 65536 0 0
59 58 580000 10000 0 0 190 5 67 4096 1775 0 0 0 65536 0 0 65536 0 0
@@ -0,0 +1,59 @@
tick_number,elapsed_ns,tick_interval_ns,cache_hits_delta,bucket_hits_delta,word_executions_delta,hot_word_count,avg_word_heat_q48,window_width,actual_window_size,predicted_label_hits,jitter_bits,apic_ticks,time_trust_q48,variance_q48,vm_call_depth_max,hera_heat_q48,hermes_heat_q48,artemis_heat_q48
1,10000,10000,0,0,183,4,45,731,731,0,0,0,65536,0,0,65536,0,0
2,20000,10000,0,0,173,5,44,582,582,0,0,0,65536,0,0,65536,0,0
3,30000,10000,0,0,184,6,60,582,582,0,0,0,65536,0,0,65536,0,0
4,40000,10000,0,0,174,8,71,4096,0,0,0,0,65536,0,0,65536,0,0
5,50000,10000,0,0,150,9,78,582,582,0,0,0,65536,0,0,65536,0,0
6,60000,10000,0,0,159,11,73,4096,0,0,0,0,65536,0,0,65536,0,0
7,70000,10000,0,0,188,15,71,685,685,0,0,0,65536,0,0,65536,0,0
8,80000,10000,0,0,214,16,83,685,685,0,0,0,65536,0,0,65536,0,0
9,90000,10000,0,0,216,19,82,4096,0,0,0,0,65536,0,0,65536,0,0
10,100000,10000,0,0,222,21,84,567,567,0,0,0,65536,0,0,65536,0,0
11,110000,10000,0,0,207,23,86,731,731,0,0,0,65536,0,0,65536,0,0
12,120000,10000,0,0,189,26,83,4096,0,0,0,0,65536,0,0,65536,0,0
13,130000,10000,0,0,221,28,80,731,731,0,0,0,65536,0,0,65536,0,0
14,140000,10000,0,0,204,29,83,685,685,0,0,0,65536,0,0,65536,0,0
15,150000,10000,0,0,203,30,82,731,731,0,0,0,65536,0,0,65536,0,0
16,160000,10000,0,0,201,32,83,567,567,0,0,0,65536,0,0,65536,0,0
17,170000,10000,0,0,190,34,86,731,731,0,0,0,65536,0,0,65536,0,0
18,180000,10000,0,0,170,35,73,582,582,0,0,0,65536,0,0,65536,0,0
19,190000,10000,0,0,154,28,44,731,731,0,0,0,65536,0,0,65536,0,0
20,200000,10000,0,0,154,28,41,567,567,0,0,0,65536,0,0,65536,0,0
21,210000,10000,0,0,153,32,39,4096,0,0,0,0,65536,0,0,65536,0,0
22,220000,10000,0,0,167,35,42,582,582,0,0,0,65536,0,0,65536,0,0
23,230000,10000,0,0,176,37,41,685,685,0,0,0,65536,0,0,65536,0,0
24,240000,10000,0,0,175,37,39,731,731,0,0,0,65536,0,0,65536,0,0
25,250000,10000,0,0,196,38,37,731,731,0,0,0,65536,0,0,65536,0,0
26,260000,10000,0,0,192,41,37,4096,0,0,0,0,65536,0,0,65536,0,0
27,270000,10000,0,0,158,40,38,685,685,0,0,0,65536,0,0,65536,0,0
28,280000,10000,0,0,158,40,35,4096,0,0,0,0,65536,0,0,65536,0,0
29,290000,10000,0,0,164,41,37,4096,0,0,0,0,65536,0,0,65536,0,0
30,300000,10000,0,0,154,43,39,685,685,0,0,0,65536,0,0,65536,0,0
31,310000,10000,0,0,172,46,35,582,582,0,0,0,65536,0,0,65536,0,0
32,320000,10000,0,0,180,49,34,567,567,0,0,0,65536,0,0,65536,0,0
33,330000,10000,0,0,145,51,35,567,567,0,0,0,65536,0,0,65536,0,0
34,340000,10000,0,0,203,53,37,582,582,0,0,0,65536,0,0,65536,0,0
35,350000,10000,0,0,154,55,39,731,731,0,0,0,65536,0,0,65536,0,0
36,360000,10000,0,0,144,57,37,4096,0,0,0,0,65536,0,0,65536,0,0
37,370000,10000,0,0,144,57,35,4096,0,0,0,0,65536,0,0,65536,0,0
38,380000,10000,0,0,132,57,34,4096,0,0,0,0,65536,0,0,65536,0,0
39,390000,10000,0,0,180,57,32,4096,0,0,0,0,65536,0,0,65536,0,0
40,400000,10000,0,0,220,63,29,4096,0,0,0,0,65536,0,0,65536,0,0
41,410000,10000,0,0,215,64,28,4096,24,0,0,0,65536,0,0,65536,0,0
42,420000,10000,0,0,208,68,29,4096,24,0,0,0,65536,0,0,65536,0,0
43,430000,10000,0,0,177,72,27,4096,24,0,0,0,65536,0,0,65536,0,0
44,440000,10000,0,0,199,77,28,4096,24,0,0,0,65536,0,0,65536,0,0
45,450000,10000,0,0,223,82,26,4096,30,0,0,0,65536,0,0,65536,0,0
46,460000,10000,0,0,202,85,24,4096,67,0,0,0,65536,0,0,65536,0,0
47,470000,10000,0,0,218,91,25,4096,198,0,0,0,65536,0,0,65536,0,0
48,480000,10000,0,0,221,92,26,4096,350,0,0,0,65536,0,0,65536,0,0
49,490000,10000,0,0,225,97,26,4096,528,0,0,0,65536,0,0,65536,0,0
50,500000,10000,0,0,214,100,27,4096,694,0,0,0,65536,0,0,65536,0,0
51,510000,10000,0,0,227,102,28,4096,883,0,0,0,65536,0,0,65536,0,0
52,520000,10000,0,0,208,102,29,4096,1043,0,0,0,65536,0,0,65536,0,0
53,530000,10000,0,0,207,102,30,4096,1202,0,0,0,65536,0,0,65536,0,0
54,540000,10000,0,0,200,102,31,4096,1319,0,0,0,65536,0,0,65536,0,0
55,550000,10000,0,0,205,103,32,4096,1464,0,0,0,65536,0,0,65536,0,0
56,560000,10000,0,0,211,103,32,4096,1620,0,0,0,65536,0,0,65536,0,0
57,570000,10000,0,0,193,110,33,4096,1712,0,0,0,65536,0,0,65536,0,0
58,580000,10000,0,0,190,5,67,4096,1775,0,0,0,65536,0,0,65536,0,0
1 tick_number elapsed_ns tick_interval_ns cache_hits_delta bucket_hits_delta word_executions_delta hot_word_count avg_word_heat_q48 window_width actual_window_size predicted_label_hits jitter_bits apic_ticks time_trust_q48 variance_q48 vm_call_depth_max hera_heat_q48 hermes_heat_q48 artemis_heat_q48
2 1 10000 10000 0 0 183 4 45 731 731 0 0 0 65536 0 0 65536 0 0
3 2 20000 10000 0 0 173 5 44 582 582 0 0 0 65536 0 0 65536 0 0
4 3 30000 10000 0 0 184 6 60 582 582 0 0 0 65536 0 0 65536 0 0
5 4 40000 10000 0 0 174 8 71 4096 0 0 0 0 65536 0 0 65536 0 0
6 5 50000 10000 0 0 150 9 78 582 582 0 0 0 65536 0 0 65536 0 0
7 6 60000 10000 0 0 159 11 73 4096 0 0 0 0 65536 0 0 65536 0 0
8 7 70000 10000 0 0 188 15 71 685 685 0 0 0 65536 0 0 65536 0 0
9 8 80000 10000 0 0 214 16 83 685 685 0 0 0 65536 0 0 65536 0 0
10 9 90000 10000 0 0 216 19 82 4096 0 0 0 0 65536 0 0 65536 0 0
11 10 100000 10000 0 0 222 21 84 567 567 0 0 0 65536 0 0 65536 0 0
12 11 110000 10000 0 0 207 23 86 731 731 0 0 0 65536 0 0 65536 0 0
13 12 120000 10000 0 0 189 26 83 4096 0 0 0 0 65536 0 0 65536 0 0
14 13 130000 10000 0 0 221 28 80 731 731 0 0 0 65536 0 0 65536 0 0
15 14 140000 10000 0 0 204 29 83 685 685 0 0 0 65536 0 0 65536 0 0
16 15 150000 10000 0 0 203 30 82 731 731 0 0 0 65536 0 0 65536 0 0
17 16 160000 10000 0 0 201 32 83 567 567 0 0 0 65536 0 0 65536 0 0
18 17 170000 10000 0 0 190 34 86 731 731 0 0 0 65536 0 0 65536 0 0
19 18 180000 10000 0 0 170 35 73 582 582 0 0 0 65536 0 0 65536 0 0
20 19 190000 10000 0 0 154 28 44 731 731 0 0 0 65536 0 0 65536 0 0
21 20 200000 10000 0 0 154 28 41 567 567 0 0 0 65536 0 0 65536 0 0
22 21 210000 10000 0 0 153 32 39 4096 0 0 0 0 65536 0 0 65536 0 0
23 22 220000 10000 0 0 167 35 42 582 582 0 0 0 65536 0 0 65536 0 0
24 23 230000 10000 0 0 176 37 41 685 685 0 0 0 65536 0 0 65536 0 0
25 24 240000 10000 0 0 175 37 39 731 731 0 0 0 65536 0 0 65536 0 0
26 25 250000 10000 0 0 196 38 37 731 731 0 0 0 65536 0 0 65536 0 0
27 26 260000 10000 0 0 192 41 37 4096 0 0 0 0 65536 0 0 65536 0 0
28 27 270000 10000 0 0 158 40 38 685 685 0 0 0 65536 0 0 65536 0 0
29 28 280000 10000 0 0 158 40 35 4096 0 0 0 0 65536 0 0 65536 0 0
30 29 290000 10000 0 0 164 41 37 4096 0 0 0 0 65536 0 0 65536 0 0
31 30 300000 10000 0 0 154 43 39 685 685 0 0 0 65536 0 0 65536 0 0
32 31 310000 10000 0 0 172 46 35 582 582 0 0 0 65536 0 0 65536 0 0
33 32 320000 10000 0 0 180 49 34 567 567 0 0 0 65536 0 0 65536 0 0
34 33 330000 10000 0 0 145 51 35 567 567 0 0 0 65536 0 0 65536 0 0
35 34 340000 10000 0 0 203 53 37 582 582 0 0 0 65536 0 0 65536 0 0
36 35 350000 10000 0 0 154 55 39 731 731 0 0 0 65536 0 0 65536 0 0
37 36 360000 10000 0 0 144 57 37 4096 0 0 0 0 65536 0 0 65536 0 0
38 37 370000 10000 0 0 144 57 35 4096 0 0 0 0 65536 0 0 65536 0 0
39 38 380000 10000 0 0 132 57 34 4096 0 0 0 0 65536 0 0 65536 0 0
40 39 390000 10000 0 0 180 57 32 4096 0 0 0 0 65536 0 0 65536 0 0
41 40 400000 10000 0 0 220 63 29 4096 0 0 0 0 65536 0 0 65536 0 0
42 41 410000 10000 0 0 215 64 28 4096 24 0 0 0 65536 0 0 65536 0 0
43 42 420000 10000 0 0 208 68 29 4096 24 0 0 0 65536 0 0 65536 0 0
44 43 430000 10000 0 0 177 72 27 4096 24 0 0 0 65536 0 0 65536 0 0
45 44 440000 10000 0 0 199 77 28 4096 24 0 0 0 65536 0 0 65536 0 0
46 45 450000 10000 0 0 223 82 26 4096 30 0 0 0 65536 0 0 65536 0 0
47 46 460000 10000 0 0 202 85 24 4096 67 0 0 0 65536 0 0 65536 0 0
48 47 470000 10000 0 0 218 91 25 4096 198 0 0 0 65536 0 0 65536 0 0
49 48 480000 10000 0 0 221 92 26 4096 350 0 0 0 65536 0 0 65536 0 0
50 49 490000 10000 0 0 225 97 26 4096 528 0 0 0 65536 0 0 65536 0 0
51 50 500000 10000 0 0 214 100 27 4096 694 0 0 0 65536 0 0 65536 0 0
52 51 510000 10000 0 0 227 102 28 4096 883 0 0 0 65536 0 0 65536 0 0
53 52 520000 10000 0 0 208 102 29 4096 1043 0 0 0 65536 0 0 65536 0 0
54 53 530000 10000 0 0 207 102 30 4096 1202 0 0 0 65536 0 0 65536 0 0
55 54 540000 10000 0 0 200 102 31 4096 1319 0 0 0 65536 0 0 65536 0 0
56 55 550000 10000 0 0 205 103 32 4096 1464 0 0 0 65536 0 0 65536 0 0
57 56 560000 10000 0 0 211 103 32 4096 1620 0 0 0 65536 0 0 65536 0 0
58 57 570000 10000 0 0 193 110 33 4096 1712 0 0 0 65536 0 0 65536 0 0
59 58 580000 10000 0 0 190 5 67 4096 1775 0 0 0 65536 0 0 65536 0 0
+9
View File
@@ -78,6 +78,15 @@ void apic_timer_start(void);
*/
void apic_timer_stop(void);
/**
* Re-arm the APIC timer at the current adaptive period (item 0.8, §26).
* Recomputes the initial count from heartbeat_next_period_ns() and writes
* it to the ICR; a periodic-mode ICR write restarts the countdown
* immediately at the new value. Called once per tick from the ISR, before
* heartbeat_tick().
*/
void apic_timer_rearm(void);
/**
* Get the configured timer period in TSC ticks.
*/
+44 -2
View File
@@ -154,11 +154,37 @@ const timer_calibration_record_t *timer_calibration_record(void);
void heartbeat_init(uint64_t tsc_hz, uint64_t tick_hz);
/**
* Called by heartbeat ISR on each tick.
* Updates TIME-TICKS, samples TSC, updates rolling window and TIME-TRUST.
* Top half. Called directly from each architecture's ISR (punch-list item
* 0.8) -- one call site per architecture, unchanged from before this item.
* Does exactly three things: reads the raw counter via
* @c heartbeat_read_counter(), increments TIME-TICKS, and latches the
* sample for @c heartbeat_service() to pick up. No window math, no
* variance, no loops -- this must stay cheap enough for interrupt context.
*/
void heartbeat_tick(void);
/**
* Bottom half (punch-list item 0.8). Services one pending sample if
* @c heartbeat_tick() has latched one since the last call: computes the
* inter-tick deviation, updates the rolling window, and (architecture
* permitting -- see @c heartbeat.c) recomputes variance and TIME-TRUST.
* Never runs in interrupt context. Call from the mainline, as frequently
* as convenient -- a stale/skipped service call degrades the window's
* fidelity but affects nothing else, since TIME-TRUST is diagnostic only
* and never gates execution.
*/
void heartbeat_service(void);
/**
* Read the raw hardware counter this architecture's heartbeat is paced
* against -- the same clock @c timer_now_ns() and calibration already use
* internally (rdtsc on amd64, the `time` CSR on riscv64, CNTPCT_EL0 on
* aarch64), not a separate/different source. Implemented once per
* architecture in that architecture's timer.c; consumed only by
* @c heartbeat_tick() in the shared heartbeat.c.
*/
uint64_t heartbeat_read_counter(void);
/**
* Get current TIME-TICKS (monotonic heartbeat count).
*/
@@ -174,4 +200,20 @@ time_trust_t heartbeat_trust(void);
*/
const TimeTrustState *heartbeat_state(void);
/**
* Set the adaptive re-arm period, in nanoseconds (punch-list item 0.8,
* FABRIC.md §26). Called from the mainline execution path only (Loop #7's
* site in vm_runtime.c) -- never from interrupt context. Clamped to
* [1/4x, 4x] of the kernel's base period internally; a caller need not
* pre-clamp.
*/
void heartbeat_set_adaptive_period_ns(uint64_t ns);
/**
* Read the period the next hardware re-arm should use. Called from
* interrupt context by each architecture's re-arm function in place of a
* fixed constant.
*/
uint64_t heartbeat_next_period_ns(void);
#endif /* STARKERNEL_TIMER_H */
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
+16 -1
View File
@@ -32,6 +32,7 @@
#include "apic.h"
#include "uefi.h"
#include "console.h"
#include "timer.h"
#include <stdint.h>
/* Defined in arch.c (item 0.4). Same extern-in-place convention as
@@ -92,6 +93,7 @@ static inline uint32_t mmio_read32(uintptr_t base, uint32_t offset)
static uint32_t s_timer_ppi = TIMER_PPI_EL1;
static uint64_t s_timer_period_tsc = 0;
static uint64_t s_counter_hz_apic = 0; /* CNTFRQ_EL0 (item 0.8/§26) */
/**
* @brief Initialise the GICv2 distributor and CPU interface (M4 milestone).
@@ -227,6 +229,7 @@ int apic_timer_init(uint64_t tsc_hz, uint32_t tick_hz)
} else {
s_timer_period_tsc = 10000000;
}
s_counter_hz_apic = tsc_hz;
return 0;
}
@@ -305,11 +308,23 @@ void apic_timer_start(void)
* @c heartbeat_tick() — same ordering discipline as
* @c riscv64_timer_rearm() (item 0.3): re-arm first, so a fault in the
* rest of the handler cannot also cost the next tick.
*
* The step written is @c heartbeat_next_period_ns() (item 0.8, §26)
* converted to @c CNTPCT_EL0 ticks via @c s_counter_hz_apic, not the fixed
* @c s_timer_period_tsc @c apic_timer_start() used for the very first arm
* -- that value remains @c apic_timer_period_tsc()'s return for
* @c heartbeat_init()'s initial @c expected_delta, unchanged.
*/
void apic_timer_rearm(void)
{
uint64_t period_ticks = (s_counter_hz_apic > 0)
? (heartbeat_next_period_ns() * s_counter_hz_apic) / 1000000000ULL
: s_timer_period_tsc;
if (period_ticks == 0) {
period_ticks = 1;
}
/* uint64_t, zero-extended -- see apic_timer_start() for why. */
uint64_t tval = (uint64_t)(uint32_t)s_timer_period_tsc;
uint64_t tval = (uint64_t)(uint32_t)period_ticks;
if (aarch64_current_el() == 2) {
__asm__ volatile ("msr cnthp_tval_el2, %0" :: "r"(tval));
+10 -123
View File
@@ -75,10 +75,6 @@ static uint64_t s_base_ns = 0; /* ns offset at timer_init() */
static timer_calibration_record_t s_cal;
/* ─── Heartbeat state ────────────────────────────────────────────────── */
static TimeTrustState g_heartbeat;
/* ─── timer_init ─────────────────────────────────────────────────────── */
/*
@@ -229,128 +225,19 @@ const timer_calibration_record_t *timer_calibration_record(void)
/* ─── Heartbeat ──────────────────────────────────────────────────────── */
/*
* @brief Initialise the heartbeat rolling-window state.
*
* Zeroes the @c TimeTrustState @c g_heartbeat and sets up the expected
* inter-tick interval as @c tsc_hz / @c tick_hz system-counter ticks. On
* AArch64 "TSC" refers to @c CNTPCT_EL0; the variable name is preserved
* for cross-ISA consistency.
*
* If either @p tsc_hz or @p tick_hz is zero, @c expected_delta falls back
* to 10,000,000 ticks (≈ 160 ms at 62.5 MHz) which is a safe non-zero
* sentinel preventing division-by-zero in the rolling window.
*
* Initial @c trust is set to @c Q48_ONE (full trust) because the ARM
* Generic Timer is invariant by architecture and requires no initial
* warm-up period unlike the x86 TSC.
*
* @param tsc_hz System counter frequency (Hz); from @c timer_tsc_hz().
* @param tick_hz Heartbeat interrupt rate (Hz); from @c apic_timer_init().
*/
void heartbeat_init(uint64_t tsc_hz, uint64_t tick_hz)
{
g_heartbeat.ticks = 0;
g_heartbeat.last_tsc = 0;
g_heartbeat.total_samples = 0;
g_heartbeat.variance = 0;
g_heartbeat.trust = Q48_ONE;
g_heartbeat.window.pos = 0;
g_heartbeat.window.count = 0;
for (int i = 0; i < TIME_WINDOW_SIZE; i++) {
g_heartbeat.window.deltas[i] = 0;
}
g_heartbeat.expected_delta = (tick_hz > 0 && tsc_hz > 0)
? (tsc_hz / tick_hz)
: 10000000ULL;
}
/**
* @brief Record one heartbeat tick and update the inter-tick deviation window.
* @brief Read the raw counter the aarch64 heartbeat is paced against.
*
* Called from the timer ISR (or its AArch64 stub equivalent) at each
* periodic heartbeat. Reads @c CNTPCT_EL0 and, if @c last_tsc is
* non-zero, computes the signed deviation:
* Item 0.8 (FABRIC.md §25.1): the shared heartbeat.c now owns
* heartbeat_init()/heartbeat_tick()/heartbeat_service()/heartbeat_ticks()/
* heartbeat_trust()/heartbeat_state() and the per-arch @c g_heartbeat
* state that used to live in this file. This is the one piece that stays
* per-architecture -- the same @c CNTPCT_EL0 the rest of this file's
* calibration already reads via @c cntpct_read().
*
* @code
* delta = (now - last_tsc) - expected_delta
* @endcode
*
* Stores @p delta into the circular @c window.deltas[] buffer at position
* @c (window.pos % TIME_WINDOW_SIZE) and advances the pointer. On AArch64,
* @c trust is unconditionally set to @c Q48_ONE (full confidence) because
* the Generic Timer is invariant and needs no statistical quality estimate.
* The x86-64 path uses @c variance_to_trust() instead.
*
* Increments both @c total_samples (lifetime count) and @c ticks (monotonic
* heartbeat counter used by @c heartbeat_ticks()).
* @return Current @c CNTPCT_EL0 value.
*/
void heartbeat_tick(void)
uint64_t heartbeat_read_counter(void)
{
uint64_t now = cntpct_read();
if (g_heartbeat.last_tsc != 0) {
int64_t delta = (int64_t)(now - g_heartbeat.last_tsc)
- (int64_t)g_heartbeat.expected_delta;
uint32_t pos = g_heartbeat.window.pos % TIME_WINDOW_SIZE;
g_heartbeat.window.deltas[pos] = delta;
g_heartbeat.window.pos++;
if (g_heartbeat.window.count < TIME_WINDOW_SIZE) {
g_heartbeat.window.count++;
}
g_heartbeat.total_samples++;
}
g_heartbeat.last_tsc = now;
g_heartbeat.ticks++;
g_heartbeat.trust = Q48_ONE; /* Simplified: full trust on ARM */
}
/**
* @brief Return the total number of heartbeat ticks since @c heartbeat_init().
*
* @c ticks is incremented unconditionally on every @c heartbeat_tick() call,
* including the first tick where no delta is recorded (because @c last_tsc
* is still zero). It therefore counts timer interrupts from boot, not valid
* delta samples.
*
* @return Monotonic tick counter; starts at 0, incremented at each heartbeat.
*/
uint64_t heartbeat_ticks(void)
{
return g_heartbeat.ticks;
}
/**
* @brief Return the current TIME-TRUST quality metric in Q48.16 format.
*
* On AArch64 this always returns @c Q48_ONE (the value 1.0 in Q48.16,
* i.e., @c 0x0000000000010000) because the ARM Generic Timer is invariant
* by architecture and no statistical quality degradation is expected.
*
* The x86-64 implementation derives trust from the rolling-window variance
* of inter-tick TSC deviations using @c variance_to_trust().
*
* @return TIME-TRUST as Q48.16; always @c Q48_ONE on AArch64.
*/
time_trust_t heartbeat_trust(void)
{
return g_heartbeat.trust;
}
/**
* @brief Return a pointer to the heartbeat @c TimeTrustState.
*
* Provides read access to the full @c g_heartbeat structure for callers
* that need to inspect the rolling window contents, variance estimate, or
* expected delta — for example, the VM bootstrap parity collector
* (@c sk_parity_collect()) and the @c sk_hal_time_trust() HAL accessor.
*
* The pointer is valid for the lifetime of the kernel (module-static storage).
*
* @return Pointer to @c g_heartbeat; never NULL.
*/
const TimeTrustState *heartbeat_state(void)
{
return &g_heartbeat;
return cntpct_read();
}
+32
View File
@@ -53,6 +53,7 @@
#include "console.h"
#include "vmm.h"
#include "arch.h"
#include "starkernel/timer.h"
/* ============================================================================
* APIC Register Offsets
@@ -102,6 +103,7 @@ static uint64_t lapic_phys_base = LAPIC_DEFAULT_PHYS;
static uint32_t timer_initial_count = 0;
static uint64_t timer_period_tsc_ticks = 0;
static uint32_t timer_tick_hz = 0;
static uint32_t s_apic_hz = 0; /* Calibrated APIC timer frequency (item 0.8/§26) */
/* ============================================================================
* MSR access (freestanding — no libgcc, no libc)
@@ -422,6 +424,7 @@ int apic_timer_init(uint64_t tsc_hz, uint32_t tick_hz) {
/* Compute initial count for desired tick rate */
timer_initial_count = apic_hz / tick_hz;
timer_tick_hz = tick_hz;
s_apic_hz = apic_hz;
/* Compute expected TSC ticks per heartbeat (for TIME-TRUST variance) */
if (tsc_hz > 0) {
@@ -563,6 +566,35 @@ void apic_timer_stop(void) {
lapic_write(APIC_REG_LVT_TIMER, lvt);
}
/**
* @brief Re-arm the APIC timer at the current adaptive period (item 0.8, §26).
*
* amd64's APIC timer runs in periodic mode: hardware auto-reloads
* @c APIC_REG_TIMER_ICR on every expiry with no software intervention, unlike
* riscv64's one-shot SBI deadline or aarch64's one-shot @c CNTP_TVAL_EL0 --
* neither of which needed a rearm function before this item for the same
* reason this one now exists. To make the period adaptive, this function
* recomputes @c timer_initial_count from @c heartbeat_next_period_ns() (§26)
* and @c s_apic_hz, then writes it to @c APIC_REG_TIMER_ICR. A periodic-mode
* ICR write takes effect immediately and restarts the countdown at the new
* value -- the same mechanism @c apic_timer_start() already relies on to
* force QEMU TCG's emulated APIC to begin counting.
*
* Called from @c isr_common_handler() on every @c APIC_TIMER_VECTOR
* interrupt, before @c heartbeat_tick() -- same ordering discipline as
* riscv64/aarch64's rearm-before-heartbeat_tick(), so a fault in
* @c heartbeat_tick() cannot also cost the next tick.
*/
void apic_timer_rearm(void) {
uint64_t period_ns = heartbeat_next_period_ns();
uint64_t new_count = ((uint64_t)s_apic_hz * period_ns) / 1000000000ULL;
if (new_count == 0) {
new_count = 1;
}
timer_initial_count = (uint32_t)new_count;
lapic_write(APIC_REG_TIMER_ICR, timer_initial_count);
}
/**
* @brief Return the expected TSC-tick count per APIC heartbeat period.
*
+1
View File
@@ -334,6 +334,7 @@ void isr_common_handler(uint64_t vector,
{
/* Handle APIC timer interrupt (heartbeat) */
if (vector == APIC_TIMER_VECTOR) {
apic_timer_rearm();
heartbeat_tick();
/* Acknowledge interrupt and return (don't halt!) */
+10 -216
View File
@@ -1336,225 +1336,19 @@ const timer_calibration_record_t *timer_calibration_record(void)
* 5. Derive TIME-TRUST from variance
*/
static TimeTrustState g_heartbeat;
/**
* @brief Push a signed delta value into the heartbeat rolling window.
* @brief Read the raw counter the amd64 heartbeat is paced against.
*
* Overwrites the oldest entry at @c w->pos (circular), then advances @c pos
* modulo @c TIME_WINDOW_SIZE and increments @c count up to the window
* capacity. Called on every heartbeat tick to record the deviation of the
* actual inter-tick TSC delta from @c expected_delta.
* Item 0.8 (FABRIC.md §25.1): the shared heartbeat.c owns
* heartbeat_init()/heartbeat_tick()/heartbeat_service()/heartbeat_ticks()/
* heartbeat_trust()/heartbeat_state() and the variance/trust math that used
* to live in this file. This is the one piece that stays per-architecture
* -- the same @c rdtsc() the rest of this file's TSC calibration already
* uses, not a separate/different source.
*
* @param w Heartbeat window to update.
* @param delta Signed deviation (actual_delta - expected_delta) in TSC ticks.
* @return Current TSC value.
*/
static void window_push(TimeWindow *w, int64_t delta)
uint64_t heartbeat_read_counter(void)
{
w->deltas[w->pos] = delta;
w->pos = (w->pos + 1) % TIME_WINDOW_SIZE;
if (w->count < TIME_WINDOW_SIZE) {
w->count++;
}
}
/**
* @brief Compute the relative variance of heartbeat deltas as a Q48.16 value.
*
* Computes the population variance of the signed deviation samples in @p w,
* then normalises by @c expected_delta² to produce a dimensionless relative
* variance. The result is represented in Q48.16 fixed-point (value 65536 =
* 1.0 = 100% relative variance). Returns 0 if fewer than 2 samples are
* present or @p expected_delta is 0.
*
* Overflow guards: large deviations are clamped to ±0x7FFFFFFF ticks before
* squaring; @c var_tsc is shifted right if it exceeds @c 0x0000FFFFFFFFFFFF.
*
* @param w Rolling window of inter-tick TSC deviations.
* @param expected_delta Nominal inter-tick TSC delta (tsc_hz / tick_hz).
* @return Relative variance as Q48.16, or 0 if insufficient data.
*/
static q48_16_t window_variance_q48(const TimeWindow *w, uint64_t expected_delta)
{
if (w->count < 2 || expected_delta == 0) {
return 0;
}
/* Compute mean */
int64_t sum = 0;
for (uint32_t i = 0; i < w->count; i++) {
sum += w->deltas[i];
}
int64_t mean = sum / (int64_t)w->count;
/* Compute variance = sum((delta - mean)^2) / count */
uint64_t sum_sq = 0;
for (uint32_t i = 0; i < w->count; i++) {
int64_t diff = w->deltas[i] - mean;
/* Clamp to prevent overflow */
if (diff > 0x7FFFFFFF) diff = 0x7FFFFFFF;
if (diff < -0x7FFFFFFF) diff = -0x7FFFFFFF;
sum_sq += (uint64_t)(diff * diff);
}
uint64_t var_tsc = sum_sq / w->count;
/* Normalize by expected_delta^2 to get relative variance */
uint64_t exp_sq = expected_delta;
if (exp_sq > 0xFFFFFFFF) {
var_tsc >>= 16;
exp_sq >>= 8;
}
exp_sq = exp_sq * exp_sq;
if (exp_sq == 0) return 0;
/* Clamp to avoid overflow when shifting */
if (var_tsc > 0x0000FFFFFFFFFFFFULL) {
var_tsc = 0x0000FFFFFFFFFFFFULL;
}
return (var_tsc << 16) / exp_sq;
}
/**
* @brief Derive TIME-TRUST from a Q48.16 relative variance value.
*
* Applies the formula @c trust = 1 / (1 + variance) in Q48.16 arithmetic:
* @c denom = Q48_ONE + variance, then @c trust = Q48_ONE / denom. Returns
* @c Q48_ONE (maximum trust = 1.0) if @p denom would be zero (defensive).
*
* As variance → 0, trust → 1.0 (perfect timing). As variance → ∞, trust
* → 0.0 (unusable). The Q48.16 output is stored in @c TimeTrustState.trust
* and exported to the VM via @c heartbeat_trust().
*
* @param variance Q48.16 relative variance from @c window_variance_q48().
* @return Q48.16 time-trust value in range (0, 1].
*/
static q48_16_t variance_to_trust(q48_16_t variance)
{
q48_16_t denom = q48_add(Q48_ONE, variance);
if (denom == 0) {
return Q48_ONE;
}
return q48_div(Q48_ONE, denom);
}
/**
* @brief Initialise the M5 heartbeat / TIME-TRUST subsystem.
*
* Zeros the @c g_heartbeat state: tick count, TSC anchor, sample counter,
* variance, and rolling window. Sets the initial trust to @c Q48_ONE (1.0,
* maximum trust) so the VM starts with a confident time signal.
*
* Computes @c expected_delta = @p tsc_hz / @p tick_hz to calibrate the
* deviation window. Falls back to 10 ms at 1 GHz if either argument is zero.
*
* Called from @c kernel_main() after @c timer_init() establishes
* @c tsc_hz_locked.
*
* @param tsc_hz Locked TSC frequency in Hz (from @c timer_tsc_hz()).
* @param tick_hz Target heartbeat rate in Hz (typically 100).
*/
void heartbeat_init(uint64_t tsc_hz, uint64_t tick_hz)
{
g_heartbeat.ticks = 0;
g_heartbeat.last_tsc = 0;
g_heartbeat.total_samples = 0;
g_heartbeat.variance = 0;
g_heartbeat.trust = Q48_ONE;
g_heartbeat.window.pos = 0;
g_heartbeat.window.count = 0;
for (int i = 0; i < TIME_WINDOW_SIZE; i++) {
g_heartbeat.window.deltas[i] = 0;
}
if (tick_hz > 0 && tsc_hz > 0) {
g_heartbeat.expected_delta = tsc_hz / tick_hz;
} else {
g_heartbeat.expected_delta = 10000000; /* 10ms at 1GHz */
}
}
/**
* @brief Process one heartbeat tick — update tick count, variance, and TIME-TRUST.
*
* Called by the APIC timer ISR at @c tick_hz (100 Hz by default). On each call:
* 1. Reads the current TSC via @c rdtsc().
* 2. Increments @c ticks and @c total_samples.
* 3. On the first sample, records @c last_tsc and returns (no delta yet).
* 4. Computes the signed deviation of the actual inter-tick TSC delta from
* @c expected_delta and pushes it into the rolling window.
* 5. Recomputes @c variance and @c trust from the updated window.
*
* Must only be called from interrupt context. Does not take a lock; the
* single-threaded kernel guarantees no concurrent access.
*/
void heartbeat_tick(void)
{
uint64_t now = rdtsc();
TimeTrustState *s = &g_heartbeat;
s->ticks++;
s->total_samples++;
/* First tick: just record TSC */
if (s->total_samples == 1) {
s->last_tsc = now;
return;
}
/* Compute delta from last tick */
uint64_t actual_delta = now - s->last_tsc;
s->last_tsc = now;
/* Compute deviation from expected (signed) */
int64_t deviation = (int64_t)actual_delta - (int64_t)s->expected_delta;
/* Add to rolling window */
window_push(&s->window, deviation);
/* Recompute variance and trust */
s->variance = window_variance_q48(&s->window, s->expected_delta);
s->trust = variance_to_trust(s->variance);
}
/**
* @brief Return the total number of heartbeat ticks since @c heartbeat_init().
*
* The tick count monotonically increases with each @c heartbeat_tick() call.
* Used by the HAL shim (@c sk_hal_heartbeat_ticks()) and the VM's @c M5
* time-trust bridge.
*
* @return Number of heartbeat ticks elapsed.
*/
uint64_t heartbeat_ticks(void)
{
return g_heartbeat.ticks;
}
/**
* @brief Return the current TIME-TRUST value as Q48.16 fixed-point.
*
* Returns @c g_heartbeat.trust, updated on every tick by @c variance_to_trust().
* Value is in range (0, 1]: @c Q48_ONE (65536) = perfect trust, values near
* zero indicate high inter-tick jitter.
*
* @return Current time-trust as a @c time_trust_t (Q48.16 alias).
*/
time_trust_t heartbeat_trust(void)
{
return g_heartbeat.trust;
}
/**
* @brief Return a pointer to the full heartbeat / TIME-TRUST state.
*
* Provides read-only access to @c g_heartbeat for diagnostic output or
* parity logging. The caller must not write through the returned pointer.
*
* @return Pointer to the static @c TimeTrustState (never NULL).
*/
const TimeTrustState *heartbeat_state(void)
{
return &g_heartbeat;
return rdtsc();
}
+18 -2
View File
@@ -17,6 +17,7 @@
#include <stdint.h>
static uint64_t s_timer_period_tsc = 0;
static uint64_t s_time_hz = 0; /* `time` CSR frequency (item 0.8/§26) */
/* ---------------------------------------------------------------------------
* SBI (Supervisor Binary Interface)
@@ -110,16 +111,30 @@ static int sbi_set_timer(uint64_t deadline)
* no error anywhere — the single most likely silent failure of this driver.
* Every path out of a timer interrupt must reach this function.
*
* The step is @c heartbeat_next_period_ns() (item 0.8, §26) converted to
* `time`-counter ticks via @c s_time_hz, not the fixed @c s_timer_period_tsc
* used to seed the very first deadline in @c apic_timer_start() -- the
* latter remains @c apic_timer_period_tsc()'s return value for
* @c heartbeat_init()'s initial @c expected_delta, unchanged.
*
* Called from @c riscv64_interrupt_handler() in @c interrupts.c on
* @c scause cause 5.
*/
void riscv64_timer_rearm(void)
{
uint64_t now;
uint64_t step;
if (!s_sbi_time_ok) return;
s_next_deadline += s_timer_period_tsc;
step = (s_time_hz > 0)
? (heartbeat_next_period_ns() * s_time_hz) / 1000000000ULL
: s_timer_period_tsc;
if (step == 0) {
step = 1;
}
s_next_deadline += step;
/* If servicing ran long enough that the next deadline is already behind
* us, resynchronise rather than burn through a backlog of instant
@@ -127,7 +142,7 @@ void riscv64_timer_rearm(void)
now = rdtime();
if (s_next_deadline <= now)
{
s_next_deadline = now + s_timer_period_tsc;
s_next_deadline = now + step;
}
sbi_set_timer(s_next_deadline);
@@ -183,6 +198,7 @@ int apic_timer_init(uint64_t tsc_hz, uint32_t tick_hz)
s_timer_period_tsc = tsc_hz / tick_hz;
else
s_timer_period_tsc = 10000000;
s_time_hz = tsc_hz;
return 0;
}
+14 -92
View File
@@ -96,7 +96,6 @@ static uint64_t s_base_count = 0;
static uint64_t s_base_ns = 0;
static timer_calibration_record_t s_cal;
static TimeTrustState g_heartbeat;
/*
* @brief Initialise the RISC-V timer subsystem (M5 milestone).
@@ -232,99 +231,22 @@ const timer_calibration_record_t *timer_calibration_record(void)
return &s_cal;
}
/*
* @brief Initialise the heartbeat rolling-window state.
/**
* @brief Read the raw counter the riscv64 heartbeat is paced against.
*
* Zeroes @c g_heartbeat and sets the expected inter-tick interval as
* @c tsc_hz / @c tick_hz `time`-counter ticks. Falls back to 10,000,000
* ticks if either argument is zero. Initial @c trust is @c Q48_ONE
* (full confidence) — the RISC-V @c time counter is architecturally
* invariant regardless of which frequency source populated @c tsc_hz.
* Item 0.8 (FABRIC.md §25.1): the shared heartbeat.c now owns
* heartbeat_init()/heartbeat_tick()/heartbeat_service()/heartbeat_ticks()/
* heartbeat_trust()/heartbeat_state(). This is the one piece that stays
* per-architecture -- the same @c rdtime() the timer deadline is armed
* against, not @c rdcycle() or any other source. Must read the same
* counter the deadline was programmed against: @c expected_delta is
* derived from timebase-frequency and is therefore in @c time units;
* measuring the interval with @c cycle instead would difference two
* unrelated clocks.
*
* @param tsc_hz `time` counter frequency (Hz); from @c timer_tsc_hz().
* @param tick_hz Heartbeat rate (Hz); from @c apic_timer_init().
* @return Current `time` CSR value.
*/
void heartbeat_init(uint64_t tsc_hz, uint64_t tick_hz)
uint64_t heartbeat_read_counter(void)
{
g_heartbeat.ticks = 0;
g_heartbeat.last_tsc = 0;
g_heartbeat.total_samples = 0;
g_heartbeat.variance = 0;
g_heartbeat.trust = Q48_ONE;
g_heartbeat.window.pos = 0;
g_heartbeat.window.count = 0;
for (int i = 0; i < TIME_WINDOW_SIZE; i++)
g_heartbeat.window.deltas[i] = 0;
g_heartbeat.expected_delta = (tick_hz > 0 && tsc_hz > 0)
? (tsc_hz / tick_hz) : 10000000ULL;
return rdtime();
}
/**
* @brief Record one heartbeat tick and update the inter-tick deviation window.
*
* Reads @c rdtime() and, if @c last_tsc is non-zero, records the signed
* deviation @c ((now - last_tsc) - expected_delta) into the circular
* @c window.deltas[] buffer. Increments @c ticks and @c total_samples.
* Sets @c trust = @c Q48_ONE unconditionally — the RISC-V @c time counter
* is invariant and needs no statistical quality estimate.
*
* Must read the same counter the deadline was programmed against.
* @c expected_delta is derived from @c timebase-frequency and is therefore in
* @c time units; measuring the interval with @c cycle instead would difference
* two unrelated clocks and produce exactly the wrong-expected-interval defect
* that switching off @c rdcycle was meant to remove.
*
* Called from @c riscv64_interrupt_handler() on @c scause cause 5, after the
* timer has been re-armed.
*/
void heartbeat_tick(void)
{
uint64_t now = rdtime();
if (g_heartbeat.last_tsc != 0) {
int64_t delta = (int64_t)(now - g_heartbeat.last_tsc)
- (int64_t)g_heartbeat.expected_delta;
uint32_t pos = g_heartbeat.window.pos % TIME_WINDOW_SIZE;
g_heartbeat.window.deltas[pos] = delta;
g_heartbeat.window.pos++;
if (g_heartbeat.window.count < TIME_WINDOW_SIZE)
g_heartbeat.window.count++;
g_heartbeat.total_samples++;
}
g_heartbeat.last_tsc = now;
g_heartbeat.ticks++;
g_heartbeat.trust = Q48_ONE;
}
/**
* @brief Return the total number of heartbeat ticks since @c heartbeat_init().
*
* @return Monotonic tick counter; incremented once per @c heartbeat_tick() call.
*/
uint64_t heartbeat_ticks(void) { return g_heartbeat.ticks; }
/**
* @brief Return the current TIME-TRUST quality metric in Q48.16 format.
*
* Always returns @c Q48_ONE on RISC-V because the @c time counter's *rate
* stability* is invariant by specification — this tracks jitter in the
* tick-to-tick interval, and is orthogonal to whether the frequency value
* itself was discovered or is the fallback (see @c timer_calibration_record()
* for that distinction). The x86-64 implementation derives this from
* rolling-window variance.
*
* @return TIME-TRUST as Q48.16; always @c Q48_ONE on RISC-V.
*/
time_trust_t heartbeat_trust(void) { return g_heartbeat.trust; }
/**
* @brief Return a pointer to the heartbeat @c TimeTrustState.
*
* Provides read access to the full @c g_heartbeat structure for
* @c sk_parity_collect(), @c sk_hal_time_trust(), and other consumers.
* The pointer is valid for the lifetime of the kernel.
*
* @return Pointer to @c g_heartbeat; never NULL.
*/
const TimeTrustState *heartbeat_state(void) { return &g_heartbeat; }
+247
View File
@@ -0,0 +1,247 @@
/*
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 20232025 Robert A. James
All rights reserved.
Licensed under the StarForth License, Version 1.0
*/
/**
* heartbeat.c - Shared M5 heartbeat / TIME-TRUST engine (punch-list item 0.8)
*
* One implementation of heartbeat_init()/heartbeat_ticks()/heartbeat_trust()/
* heartbeat_state(), shared by all three architectures. Each architecture's
* timer.c contributes only heartbeat_read_counter() — the one thing that is
* genuinely per-ISA (rdtsc / rdtime / CNTPCT_EL0).
*
* Top half / bottom half split (FABRIC.md §25.1 item 0.8, per the GAP-A1
* ruling in §16.4/§18.4): heartbeat_tick() is called from interrupt context
* and does nothing but read the counter, bump TIME-TICKS, and latch a
* pending sample. heartbeat_service() runs on the mainline (the REPL idle
* loop) and does the window/variance/trust work. Neither one feeds patron
* state — the engine stays on the virtual tick per §18.4, unchanged by this
* file.
*
* Adaptive re-arm period (FABRIC.md §26, ruled 2026-08-03): Loop #7
* (vm_runtime.c) computes an execution-derived stable/volatile signal and
* calls heartbeat_set_adaptive_period_ns() with it, rescaled to this file's
* kernel-appropriate base (10 ms, matching the 100 Hz rate item 0.1-0.7
* configured) rather than the hosted 10 µs HEARTBEAT_TICK_NS base. Each
* architecture's re-arm function reads heartbeat_next_period_ns() and
* converts it to raw counter units instead of using a fixed constant.
* Single writer (mainline, via vm_tick()'s Loop #7 site), single reader
* (the ISR's re-arm call) — no lock needed, per §21.1's finding that
* nothing here is actually concurrent on one hart.
*/
#include "starkernel/timer.h"
#if defined(ARCH_AMD64)
#define HEARTBEAT_HAS_VARIANCE 1
#else
#define HEARTBEAT_HAS_VARIANCE 0
#endif
/* Kernel-side adaptive-period base: 10 ms, matching the 100 Hz hardware
* rate established throughout items 0.1-0.7. Deliberately NOT
* HEARTBEAT_TICK_NS (include/starforth_config.h) -- that constant is the
* hosted pthread-worker's 10 µs base and is three orders of magnitude too
* fast for a bare-metal ISR period (FABRIC.md §26.3). Loop #7's decision
* logic is reused unmodified; only the base it scales differs. */
#define HEARTBEAT_BASE_PERIOD_NS 10000000ULL
static TimeTrustState g_heartbeat;
/* Top/bottom half handoff. */
static volatile uint64_t g_pending_counter;
static volatile int g_pending_valid;
/* Adaptive re-arm period, clamped to the same [1/4x, 4x] band Loop #7
* itself enforces on tick_target_ns, so a caller cannot runaway the ISR
* rate even if it forwarded an unclamped value. */
static volatile uint64_t g_adaptive_period_ns = HEARTBEAT_BASE_PERIOD_NS;
#if HEARTBEAT_HAS_VARIANCE
/**
* @brief Push a signed delta value into the heartbeat rolling window.
*/
static void window_push(TimeWindow *w, int64_t delta)
{
w->deltas[w->pos] = delta;
w->pos = (w->pos + 1) % TIME_WINDOW_SIZE;
if (w->count < TIME_WINDOW_SIZE) {
w->count++;
}
}
/**
* @brief Compute the relative variance of heartbeat deltas as a Q48.16 value.
*/
static q48_16_t window_variance_q48(const TimeWindow *w, uint64_t expected_delta)
{
if (w->count < 2 || expected_delta == 0) {
return 0;
}
int64_t sum = 0;
for (uint32_t i = 0; i < w->count; i++) {
sum += w->deltas[i];
}
int64_t mean = sum / (int64_t)w->count;
uint64_t sum_sq = 0;
for (uint32_t i = 0; i < w->count; i++) {
int64_t diff = w->deltas[i] - mean;
if (diff > 0x7FFFFFFF) diff = 0x7FFFFFFF;
if (diff < -0x7FFFFFFF) diff = -0x7FFFFFFF;
sum_sq += (uint64_t)(diff * diff);
}
uint64_t var_tsc = sum_sq / w->count;
uint64_t exp_sq = expected_delta;
if (exp_sq > 0xFFFFFFFF) {
var_tsc >>= 16;
exp_sq >>= 8;
}
exp_sq = exp_sq * exp_sq;
if (exp_sq == 0) return 0;
if (var_tsc > 0x0000FFFFFFFFFFFFULL) {
var_tsc = 0x0000FFFFFFFFFFFFULL;
}
return (var_tsc << 16) / exp_sq;
}
/**
* @brief Derive TIME-TRUST from a Q48.16 relative variance value.
*/
static q48_16_t variance_to_trust(q48_16_t variance)
{
q48_16_t denom = q48_add(Q48_ONE, variance);
if (denom == 0) {
return Q48_ONE;
}
return q48_div(Q48_ONE, denom);
}
#endif /* HEARTBEAT_HAS_VARIANCE */
/**
* @brief Initialise the M5 heartbeat / TIME-TRUST subsystem.
*
* Shared across all three architectures -- the fallback and calibration
* formula never differed between them, only what heartbeat_service() does
* with the resulting window did.
*/
void heartbeat_init(uint64_t tsc_hz, uint64_t tick_hz)
{
g_heartbeat.ticks = 0;
g_heartbeat.last_tsc = 0;
g_heartbeat.total_samples = 0;
g_heartbeat.variance = 0;
g_heartbeat.trust = Q48_ONE;
g_heartbeat.window.pos = 0;
g_heartbeat.window.count = 0;
for (int i = 0; i < TIME_WINDOW_SIZE; i++) {
g_heartbeat.window.deltas[i] = 0;
}
g_heartbeat.expected_delta = (tick_hz > 0 && tsc_hz > 0)
? (tsc_hz / tick_hz) : 10000000ULL;
g_pending_valid = 0;
g_adaptive_period_ns = HEARTBEAT_BASE_PERIOD_NS;
}
void heartbeat_tick(void)
{
g_pending_counter = heartbeat_read_counter();
g_heartbeat.ticks++;
g_pending_valid = 1;
}
void heartbeat_service(void)
{
if (!g_pending_valid) {
return;
}
uint64_t now = g_pending_counter;
g_pending_valid = 0;
TimeTrustState *s = &g_heartbeat;
s->total_samples++;
if (s->total_samples == 1) {
s->last_tsc = now;
return;
}
uint64_t actual_delta = now - s->last_tsc;
s->last_tsc = now;
int64_t deviation = (int64_t)actual_delta - (int64_t)s->expected_delta;
#if HEARTBEAT_HAS_VARIANCE
window_push(&s->window, deviation);
s->variance = window_variance_q48(&s->window, s->expected_delta);
s->trust = variance_to_trust(s->variance);
#else
/* RISC-V `time` / AArch64 CNTPCT_EL0 are architecturally invariant
* counters -- no statistical quality estimate needed (matches the
* per-arch rationale this file replaces). */
(void)deviation;
s->trust = Q48_ONE;
#endif
}
uint64_t heartbeat_ticks(void)
{
return g_heartbeat.ticks;
}
time_trust_t heartbeat_trust(void)
{
return g_heartbeat.trust;
}
const TimeTrustState *heartbeat_state(void)
{
return &g_heartbeat;
}
/**
* @brief Set the adaptive re-arm period (FABRIC.md §26).
*
* Called from vm_runtime.c's Loop #7 site on the mainline execution path
* (never interrupt context) with a value already rescaled to this file's
* HEARTBEAT_BASE_PERIOD_NS. Clamped defensively to the same [1/4x, 4x]
* band Loop #7 itself enforces around its own base, so a caller forwarding
* an unclamped or wrongly-scaled value cannot run the ISR away.
*
* @param ns Desired period in nanoseconds for the next re-arm.
*/
void heartbeat_set_adaptive_period_ns(uint64_t ns)
{
uint64_t lo = HEARTBEAT_BASE_PERIOD_NS / 4;
uint64_t hi = HEARTBEAT_BASE_PERIOD_NS * 4;
if (ns < lo) ns = lo;
if (ns > hi) ns = hi;
g_adaptive_period_ns = ns;
}
/**
* @brief Read the period the next hardware re-arm should use.
*
* Called from interrupt context by each architecture's re-arm function
* (apic_timer_rearm(), riscv64_timer_rearm(), the AArch64 equivalent) in
* place of the fixed constant those functions used before item 0.8.
*
* @return Current adaptive period in nanoseconds.
*/
uint64_t heartbeat_next_period_ns(void)
{
return g_adaptive_period_ns;
}
+16 -5
View File
@@ -16,10 +16,13 @@
* - Output: console_puts() / console_putc()
*
* Idle spin: polls console_getc() and services the adaptive heartbeat.
* The APIC timer ISR increments heartbeat_ticks() at 100 Hz;
* the idle spin calls sk_repl_idle() once per SK_IDLE_BEAT_INTERVAL
* ticks. On QEMU TCG the ISR must fire for ticks to advance —
* check "Heartbeat: N ticks" in the serial log to confirm.
* The timer ISR's top half (heartbeat_tick()) latches one
* sample per interrupt; the idle spin drains it every
* iteration via heartbeat_service() (item 0.8, FABRIC.md §26)
* and calls sk_repl_idle() once per SK_IDLE_BEAT_INTERVAL ticks
* for coarser subsystem dispatch. On QEMU TCG the ISR must fire
* for ticks to advance — check "Heartbeat: N ticks" in the
* serial log to confirm.
*
* Runs with interrupts enabled so the APIC heartbeat fires normally.
* Designed as the last thing kernel_main does before the idle loop.
@@ -85,7 +88,15 @@ static int sk_readline(char *buf, int size)
int c = console_getc(); /* non-blocking poll */
if (c < 0) {
/* Idle — service the adaptive heartbeat if a beat has elapsed */
/* Service the heartbeat bottom half every idle iteration, not
* gated by SK_IDLE_BEAT_INTERVAL (item 0.8, FABRIC.md §26):
* heartbeat_service() drains at most one latched sample per
* call, so a coarse gate here would silently lose or merge
* samples between ISR-latched ticks. sk_repl_idle() below is
* a separate, deliberately coarser cadence for higher-level
* subsystem dispatch, unrelated to sample fidelity. */
heartbeat_service();
uint64_t now = heartbeat_ticks();
if (now - g_last_beat_tick >= SK_IDLE_BEAT_INTERVAL) {
g_last_beat_tick = now;
+13
View File
@@ -748,5 +748,18 @@ void vm_tick_inference_engine(VM* vm)
(unsigned long)new_tick_ns);
}
}
/* Punch-list item 0.8 / FABRIC.md §26: drive the physical re-arm
* period from this same execution-derived signal, ratio-preserving
* rescale onto the kernel's 10 ms base rather than the hosted
* HEARTBEAT_TICK_NS (10 µs) base -- see §26.3 for why the literal
* value cannot be used on bare-metal hardware. heartbeat.c clamps
* defensively on the way in, so no clamping is duplicated here. */
{
const uint64_t kernel_base_ns = 10000000ULL; /* 10 ms, matches heartbeat.c's HEARTBEAT_BASE_PERIOD_NS */
uint64_t kernel_period_ns =
(vm->heartbeat.tick_target_ns * kernel_base_ns) / HEARTBEAT_TICK_NS;
heartbeat_set_adaptive_period_ns(kernel_period_ns);
}
}
/* End always-on loop */}