fix(ludic.telemetry): nothing made per event - properties and the line written into kept buffers, the queue a ring of bytes made at the start
An event was a tree of values encoded into a new string, a dropped line was never given back, and every batch and save joined the queue into another. Now: telemetry_props / telemetry_str / _int / _bool write the properties as JSON into a buffer the state keeps; the line is written beside it, its time worked out from the clock's seconds (TelemetryWorld.clock_s, was stamp); its bytes go into one ring (ring_bytes, at most queue_max lines), the oldest overwritten past either; a batch and the file are written into a third kept buffer and go as bytes (TelemetryTransport.send takes the bytes and their length; Http.body_bytes, Fs.write_bytes). The facts are pooled. tests/ring_test: ten thousand events past the cap in lines and in bytes, 0 bytes of heap; the line exact JSON, escaped, 2000-02-29 right; the batch puts the id in; the file round-trips. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
fc0f3d3790
commit
d1bea7f10e
14 changed files with 454 additions and 97 deletions
76
packages/ludic.telemetry/ring.ludic
Normal file
76
packages/ludic.telemetry/ring.ludic
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
# ring.ludic - the queued lines in one byte ring made at the start: a line's bytes, its length and where
|
||||
# its player mark is, oldest first. Full (lines or bytes), the oldest are overwritten; nothing is made
|
||||
# per event, per drop or per send
|
||||
|
||||
# the ring for this start, made once at its size and kept across starts of the same size
|
||||
function tr_init(telemetry_st: mut TelemetryState) -> void {
|
||||
let c = telemetry__conf(telemetry_st)
|
||||
if telemetry_st.telemetry__ring == null or len(telemetry_st.telemetry__ring) != c.ring_bytes {
|
||||
telemetry_st.telemetry__ring = buffer(c.ring_bytes)
|
||||
telemetry_st.telemetry__out = sb_new(c.ring_bytes + c.batch * 128 + 1024)
|
||||
}
|
||||
if telemetry_st.telemetry__off == null or len(telemetry_st.telemetry__off) != c.queue_max {
|
||||
telemetry_st.telemetry__off = words(c.queue_max)
|
||||
telemetry_st.telemetry__len = words(c.queue_max)
|
||||
telemetry_st.telemetry__mk = words(c.queue_max)
|
||||
}
|
||||
tr_clear(telemetry_st)
|
||||
}
|
||||
function tr_clear(telemetry_st: mut TelemetryState) -> void {
|
||||
telemetry_st.telemetry__head = 0
|
||||
telemetry_st.telemetry__n = 0
|
||||
telemetry_st.telemetry__wr = 0
|
||||
}
|
||||
function tr_slot(telemetry_st: TelemetryState, i: int) -> int { return (telemetry_st.telemetry__head + i) % len(telemetry_st.telemetry__off) }
|
||||
|
||||
# the oldest k lines gone (sent, or overwritten)
|
||||
function tr_drop(telemetry_st: mut TelemetryState, k: int) -> void {
|
||||
let n = Math.min(k, telemetry_st.telemetry__n)
|
||||
telemetry_st.telemetry__head = tr_slot(telemetry_st, n)
|
||||
telemetry_st.telemetry__n -= n
|
||||
if telemetry_st.telemetry__n == 0 { tr_clear(telemetry_st) }
|
||||
telemetry_st.telemetry__dirty = true
|
||||
}
|
||||
|
||||
# a line (the first `n` bytes of b) put at the ring's end, its mark `mk` bytes in (-1 none)
|
||||
function tr_add(telemetry_st: mut TelemetryState, b: []byte, n: int, mk: int) -> void {
|
||||
let ring = telemetry_st.telemetry__ring
|
||||
if n <= 0 or n > len(ring) { return }
|
||||
if telemetry_st.telemetry__n == len(telemetry_st.telemetry__off) { tr_drop(telemetry_st, 1) }
|
||||
var at = telemetry_st.telemetry__wr
|
||||
if at + n > len(ring) { at = 0 }
|
||||
while telemetry_st.telemetry__n > 0 and tr_over(telemetry_st, at, n) { tr_drop(telemetry_st, 1) }
|
||||
for i in 0 .. n { ring[at + i] = b[i] }
|
||||
let s = tr_slot(telemetry_st, telemetry_st.telemetry__n)
|
||||
telemetry_st.telemetry__off[s] = at
|
||||
telemetry_st.telemetry__len[s] = n
|
||||
telemetry_st.telemetry__mk[s] = mk
|
||||
telemetry_st.telemetry__n += 1
|
||||
telemetry_st.telemetry__wr = at + n
|
||||
telemetry_st.telemetry__dirty = true
|
||||
}
|
||||
# would bytes at .. at + n overwrite the oldest line
|
||||
function tr_over(telemetry_st: TelemetryState, at: int, n: int) -> bool {
|
||||
let s = telemetry_st.telemetry__head
|
||||
let o = telemetry_st.telemetry__off[s]
|
||||
return o < at + n and at < o + telemetry_st.telemetry__len[s]
|
||||
}
|
||||
|
||||
# line i (0 the oldest) onto sb, its mark written as `id` when id is not null
|
||||
function tr_line_to(telemetry_st: TelemetryState, i: int, sb: StrBuf, id: string) -> void {
|
||||
let s = tr_slot(telemetry_st, i)
|
||||
let o = telemetry_st.telemetry__off[s]
|
||||
let n = telemetry_st.telemetry__len[s]
|
||||
let mk = telemetry_st.telemetry__mk[s]
|
||||
let ring = telemetry_st.telemetry__ring
|
||||
var k = 0
|
||||
while k < n {
|
||||
if id != null and k == mk {
|
||||
sb_add(sb, id)
|
||||
k += len(TELEMETRY_MARK)
|
||||
} else {
|
||||
sb_byte(sb, ring[o + k])
|
||||
k += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue