Status bar clock: stop allocating kilobytes per second - #244
Merged
ThomasFarstrike merged 1 commit intoAug 10, 2026
Merged
Conversation
The top-bar clock is the single largest steady allocator in the OS: - update_time called mpos.time.localtime() THREE times per firing (once each for hours, minutes, seconds), and the timer fires every second. - Every localtime() call ran the full POSIX-TZ pipeline in localPTZtime: string splits, filter lists, two transition parses Together that is ~4,5 KB of garbage per second on an ESP32, causing excessive garbage collection pauses. Three changes: - topmenu.update_time calls localtime() once and indexes the tuple. - localPTZtime grows a public tzoffset(timestamp, ptz) that returns (utcoffset, isdst, valid_from, valid_until). The offset a POSIX-TZ rule yields is piecewise constant in the timestamp: it changes only at the two DST transitions and at new year, and those instants fall directly out of the parse it already does. _timecalc delegates to it, so the branch logic exists once. - mpos.time.localtime() caches (ptz, offset, isdst, valid_from, valid_until) and reuses it while valid_from <= now < valid_until. The cached path is one time.gmtime() plus one tuple, ~224 B. The full computation now runs about three times a year (two DST transitions and new year), plus on boot and on timezone change. The validity interval is exact, not a TTL heuristic: the clock is correct to the second through DST transitions, and a backward clock jump (NTP correction) simply misses the cache and recomputes. Verified against uncached tztime(): 409,690 comparisons across five zones (northern/southern DST, GMT0, angle-bracket half-hour offset, Julian-day rule) with second-by-second sweeps around every transition and year boundary 2025-2027, plus 1.64M randomized interval cross-checks 2020-2035: zero mismatches.
Contributor
|
Oh waw, great find! These types of improvements are very much needed and appreciated! |
Contributor
|
@fdb FYI, @jnuyens flagged a few more of these which I didn't get to yet:
|
Contributor
Author
|
Made PRs for the first two:
Will see if I can do the other ones. Maybe better to put these as GH issues? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The top-bar clock is the single largest steady allocator in the OS:
Together that is ~4,5 KB of allocations per second on an ESP32, causing excessive garbage collection pauses.
Three changes:
The cached path is one time.gmtime() plus one tuple, ~224 B. The full computation now runs about three times a year (two DST transitions and new year), plus on boot and on timezone change. We've done some extra work to make sure the validity interval is exact: the clock is correct to the second through DST transitions, and a backward clock jump (NTP correction) simply misses the cache and recomputes.
Verified against uncached tztime(): 409,690 comparisons across five zones (northern/southern DST, GMT0, angle-bracket half-hour offset, Julian-day rule) with second-by-second sweeps around every transition and year boundary 2025-2027, plus 1.64M randomized interval cross-checks 2020-2035: zero mismatches.