Skip to content

Prevent timer wheel from growing unexpectedly#238

Merged
notgull merged 3 commits intoSmithay:masterfrom
cmeissl:perf/timer_wheel
Feb 13, 2026
Merged

Prevent timer wheel from growing unexpectedly#238
notgull merged 3 commits intoSmithay:masterfrom
cmeissl:perf/timer_wheel

Conversation

@cmeissl
Copy link
Contributor

@cmeissl cmeissl commented Feb 10, 2026

A client cancelling and inserting timers at high rates could result in the used heap to grow unexpectedly.
This can for example happen if a compositor tracks inactivity using a timer and receives a lot of pointer events in a single dispatch.

Currently TimerWheel::cancel can result in just marking a timer cancelled without the timer being actually removed
from the heap. So there might be a time-frame where the heap grows quite big holding mostly cancelled timers.
TimerWheel::next_expired is expected to clean-up the cancelled timers, but at this point the heap might have already
grown quite big and BinaryHeap::pop will not implicitly shrink its backing store.
Also I am not completely sure this will catch all usage patterns as TimerWheel::insert could result in re-ordering
of the heap.
(Note: Calling shrink might also bring the memory consumption down, but this might result in constant re-allocation)

Calling TimerWheel::cancel might already result in linear search in the heap to mark a timer cancelled,
so imo using retain does not make this worse but should keep the heap at a reasonable size.
This might also have the side-effect of making some operations like next_expired a bit faster for some use-cases.

fixes #233

@notgull
Copy link
Member

notgull commented Feb 12, 2026

@cmeissl Please rebase on master for CI fixes.

since rust 1.70 BinaryHeap provides a retain
function that can be used to remove our
cancelled timers.
this prevent indefinitely grow of the heap
when timers get cancelled and re-inserted
with high frequency.
now that we always clean-up cancelled timers
right away there is no longer a need to store
the token in an Option.
@codecov
Copy link

codecov bot commented Feb 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.17%. Comparing base (b1dbe00) to head (242cfad).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #238      +/-   ##
==========================================
+ Coverage   85.47%   86.17%   +0.69%     
==========================================
  Files          14       16       +2     
  Lines        1825     1997     +172     
==========================================
+ Hits         1560     1721     +161     
- Misses        265      276      +11     
Flag Coverage Δ
macos-latest 85.48% <100.00%> (?)
ubuntu-latest 85.76% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@cmeissl
Copy link
Contributor Author

cmeissl commented Feb 12, 2026

@cmeissl Please rebase on master for CI fixes.

done, thanks for taking care of the CI issues!

@cmeissl
Copy link
Contributor Author

cmeissl commented Feb 12, 2026

@notgull Do you think it is possible to get a release with the PR applied soon? Looks like quite a lot of people are affected in niri and cosmic-comp by this issue.

cmeissl added a commit to cmeissl/niri that referenced this pull request Feb 13, 2026
this tracks Smithay/calloop#238
which resolves an issue where cancelling
timers can result in performance degradation
over time and memory buildup
cmeissl added a commit to cmeissl/niri that referenced this pull request Feb 13, 2026
this tracks Smithay/calloop#238
which resolves an issue where cancelling
timers can result in performance degradation
over time and memory buildup
@notgull notgull merged commit 327c073 into Smithay:master Feb 13, 2026
12 checks passed
@notgull notgull mentioned this pull request Feb 13, 2026
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.

Timer::unregister() taking longer and longer as session time increases

2 participants