Skip to content

reuse the poll events buffer across dispatches - #257

Open
MSWEBX wants to merge 1 commit into
Smithay:masterfrom
MSWEBX:reuse-poll-events
Open

MSWEBX wants to merge 1 commit into
Smithay:masterfrom
MSWEBX:reuse-poll-events

Conversation

@MSWEBX

@MSWEBX MSWEBX commented Oct 19, 2026

Copy link
Copy Markdown

calloop PR: reuse the poll events buffer across dispatches

Repo: https://github.com/Smithay/calloop (fork it, branch reuse-poll-events)
Base: master at 1e9def9a3f8ce1417e559cc57a549a9516ea5aac
Patch: calloop.patch (next to this file; git apply calloop.patch on that base)
Checked on that base: cargo fmt --check clean, cargo test: 48 + 3 + 1 passed. The new test
fails on the unpatched crate (0.14.5: 1000 allocations in 1000 dispatches).

Our vendored copy (vendor/calloop, 0.14.5) carries the same change.


Title

Reuse the poll events buffer across dispatches

Body

Poll::poll collects each wake's ready events into a new Vec<PollEvent>, so every
EventLoop::dispatch that finds a ready source allocates (48 bytes for one event on x86-64) and
frees it again. A GUI client wakes for its display connection about once a frame, which puts one
allocation into every frame. winit's Wayland backend dispatches through calloop, so every winit
app on Wayland pays this cost. We found it while enforcing a zero-allocation steady-state frame in
a game. heaptrack showed it as the only remaining per-frame allocation besides one in
wayland-backend (Smithay/wayland-rs#TODO).

This change:

  • EventLoop keeps a poll_events: Vec<PollEvent> next to its existing synthetic_events buffer.
  • Poll::poll (crate-private) takes &mut Vec<PollEvent>, clears it and refills it, instead of
    returning a new Vec.
  • dispatch_events iterates and drains that buffer, so its capacity survives to the next dispatch.

The level-triggered re-registration, the timer events and the error paths are unchanged. No
public API changes.

A new integration test, tests/dispatch_allocations.rs, counts allocations through a thread-local
counting global allocator. It warms up once, then dispatches a ready Generic source 1000 times
and asserts zero allocations. Without the change it reports 1000.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NwaQZQwdPnpxWEikdEfVvo

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant