sonar

Scan files at memory bandwidth speed.
Log | Files | Refs

commit 813560cfb6d33ff7d146f356680b6aa589b4a800
parent 7bc10afc050d521c9808f06a2969574929ce5d04
Author: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Date:   Fri, 18 Sep 2026 12:54:20 -0400

scan: publish snapshots so a frame never waits on a build

A UI has to draw on a clock and the work behind it does not run on one, so the
two need somewhere to meet that neither can stall. A snapshot is a fixed
twenty rows and a few counters whatever the volume holds, handed over behind a
sequence number raised before a write and again after. A reader takes a copy
and checks the number is unchanged and even; if a write was in progress it
keeps the answer it already had rather than waiting.

Diffstat:
Ascan/snapshot.odin | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+), 0 deletions(-)

diff --git a/scan/snapshot.odin b/scan/snapshot.odin @@ -0,0 +1,58 @@ +package scan + +import "core:sync" + +TOP_ROWS :: 20 + +Row :: struct { + node: u32, + bytes: u64, +} + +// What a UI draws: a fixed number of rows and a few counters, whatever the size of +// the volume behind it. +Snapshot :: struct { + rows: [TOP_ROWS]Row, + count: int, + nodes: u64, // records folded so far + bytes: u64, + pending: int, // nodes waiting on an ancestor + elapsed: f64, // milliseconds since the scan began + complete: bool, +} + +/* +Hands a snapshot from the thread building it to the thread drawing it. + +A sequence number is raised before a write and again after, so it is odd only while +the data is in flux. A reader takes a copy and checks the number is unchanged and +even; if not it takes another. That is what keeps a frame from ever waiting on a +build step, however long the step takes: the reader either gets the new answer or +keeps the one it already had. +*/ +Publisher :: struct { + seq: u32, + data: Snapshot, +} + +publish :: proc(p: ^Publisher, s: Snapshot) { + sync.atomic_add(&p.seq, 1) + p.data = s + sync.atomic_add(&p.seq, 1) +} + +// The latest complete snapshot. Fails only if the builder wrote several times during +// the attempt, in which case the caller draws what it drew last frame. +current :: proc(p: ^Publisher) -> (s: Snapshot, ok: bool) { + for _ in 0 ..< 16 { + before := sync.atomic_load(&p.seq) + if before & 1 != 0 { + continue // a write is in progress + } + s = p.data + if sync.atomic_load(&p.seq) == before { + return s, true + } + } + return {}, false +}