daemon: felis paints about 15 frames per second under a sustained flood #378
Labels
No labels
priority/P0
priority/P1
priority/P2
release/v0.1.0
status/blocked
status/planned
type/bug
type/design
type/test-gap
type/tracker
No milestone
No project
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
natsukium/felis#378
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-up to #375. With the
ParseCorelock handed off (parking_lot::Mutex), felis no longer freezes under a flood, but it still paints far below the display rate while the flood runs.Observed
Linux cross-terminal run of 2026-09-24 (i5-12400F, RTX 3080, niri, 60 Hz), DOOM-fire at a 141x61 grid:
NextGridFramepulls per second, about 15 on average. Each pull is one painted frame.The two numbers are linked: the fewer grid frames the daemon snapshots, the more of the lock the parse thread keeps, so felis's DOOM-fire figure counts parse work the other terminals spent partly on frames. The published figure carries this caveat until the paint rate is fixed.
Why
parking_lot's eventual fairness hands the lock to a waiter only about every 0.5 ms. Each pull needs a drain, a fan-out and a ship under that lock, and the parse thread wins every other contention, so a cycle waits several fairness slices.Done when
catof the 150 MB payloads shows no regression.docs/reference/benchmarks.mdis removed or restated.Candidates, not decided: bound the parse thread's hold per swap buffer, give the pull path an explicit hand-off (a fair unlock when a pull is pending), or snapshot outside the lock.
Traced the drain path in
crates/felis-daemon/src/serve/session_task.rs:drain_and_fantakes and releases theParseCorelock 5-6 separate times per drain cycle rather than once:drain_effects(session_task.rs:1589, plus one more insidestreaming::drain_effects)fan_out_grid_state(session_task.rs:1665and:1684, two acquisitions)fan_out_notificationsinsideafter_drive(session_task.rs:1631)broadcast_facets(session_task.rs:1701)ship_sub_at, once per subscriber (session_task.rs:1788)parking_lot's eventual fairness hands the lock to a waiter only about once per 0.5 ms, while the parse thread relocks back-to-back between chunks. Completing one pull needs every one of these 5-6 acquisitions to independently win that fairness lottery before the parse thread reclaims the lock, which matches the observed 4-34 fps spread under a sustained flood.Candidate fix: acquire the lock once per drain cycle and hold it across drain, fan-out and ship, instead of the current lock/unlock sequence. That cuts the number of required fairness wins from 5-6 to 1 per pull.