atagen

monolith

public
Star0
Watch0

Commit c251154e674e

tarball

atagen <boss@atagen.co>2026-10-19 10:44 UTC

1 file changed+7-1
drm: bound the per-frame cpu samples

Surface::frame_cpu_ns was only drained by the once-a-second stats line in on_vblank, so frames that rendered without vblanks, like empty-frame loops and failing retries, grew it without limit.
Modified file: crates/monolith/src/drm.rs+7 additions−1 deletions
@@ -57,6 +57,10 @@ const CURSOR_FRAME_NS: u64 = 16_666_667;
5757 /// clients that were mid-bind are not killed by the removal.
5858 const GLOBAL_REMOVAL_DELAY: Duration = Duration::from_secs(5);
5959
60+/// Frames render without vblanks while retrying or looping on empty frames,
61+/// and only a vblank drains the samples.
62+const MAX_CPU_SAMPLES: usize = 1024;
63+
6064 type Allocator = GbmAllocator<DrmDeviceFd>;
6165 type Exporter = GbmFramebufferExporter<DrmDeviceFd>;
6266 type Manager = DrmOutputManager<Allocator, Exporter, OutputPresentationFeedback, DrmDeviceFd>;
@@ -1119,7 +1123,9 @@ fn render_surface(state: &mut State, crtc: crtc::Handle, target: u64) -> bool {
11191123 let render_ns = render_began.elapsed().as_nanos() as u64 - queue_ns;
11201124 let took = began.elapsed().as_nanos() as u64;
11211125 surface.budget.record(took);
1122- surface.frame_cpu_ns.push(thread_cpu_ns() - frame_cpu_began);
1126+ if surface.frame_cpu_ns.len() < MAX_CPU_SAMPLES {
1127+ surface.frame_cpu_ns.push(thread_cpu_ns() - frame_cpu_began);
1128+ }
11231129 if took > surface.refresh_ns / 2 {
11241130 tracing::debug!(
11251131 output = surface.output.name(),