You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi, thanks for maintaining Flutter! I noticed a possible precision issue in the
Linux task runner's timer scheduling.
Where:shell/platform/linux/fl_task_runner.cc — this runner serves the GTK
embedder's engine task scheduling (it is registered as the custom UI task
runner, so the fallback vsync tick goes through it). When rescheduling, the
next timer is armed with g_timeout_add(remaining / 1000 + 1): every deadline
is rounded to a whole millisecond and shifted up to 1 ms late.
Why it matters: The GTK embedder has no real vsync, so the fallback tick's
timing is the frame cadence. Rounding deadlines to milliseconds fires the tick
at a coarse, always-late position; inside the shared main loop this can
periodically collide with other sources and the tick lands one full interval
late — a skipped frame. I observed exactly this on Linux (Wayland): periodic
skipped frames with no load correlation. GLib itself wakes with microsecond
precision (ppoll), so the rounding is introduced here, not in GLib.
Proposed fix: arm the timer with g_timeout_source_new(0) + g_source_set_ready_time (absolute monotonic microseconds) instead of g_timeout_add; set the ready time before attaching; keep the default
priority. Additionally, the ns→µs conversion in fl_task_runner_post_flutter_task currently truncates and should round up to
preserve the never-early property.
Happy to open a PR if this looks reasonable. Thanks for your time!
Thanks, the diagnosis.
To treat this as a confirmed frame-scheduling bug and validate a fix, could you attach a minimal runnable sample, flutter doctor -v, and a flutter run --profile timeline trace (saved from DevTools) that shows a tick landing a full interval late?
With those we can route to the Linux team.
I have prepared a standalone Flutter Linux reproduction with no third-party
packages, together with flutter doctor -v output and a profile-mode
DevTools Performance trace.
Minimal reproduction
The sample contains only a Flutter Ticker driving a lightweight moving
rectangle. Each callback records the elapsed interval, and callbacks with an
interval of at least 25 ms emit a late_ticker_callback Timeline event.
Reproduction steps:
Extract the attached sample.
Run flutter pub get.
Run flutter run --profile -d linux.
Open DevTools Performance and record the Timeline.
Search for late_ticker_callback.
On the tested 60 Hz setup, callbacks would normally be expected at
approximately 16.67 ms intervals.
In the attached trace, some callbacks occur at approximately 33.33 ms. The
attached screenshot shows one selected event with:
delta_us: 33334
expected_us: 16667
Occasional longer intervals were also observed. The sample performs very
little Dart build or paint work.
Version coverage
I reproduced the behavior on the tested official stable revision and on the
tested master revision.
The complete flutter doctor -v output is attached.
DevTools trace
The baseline attachment is a DevTools Performance snapshot captured from a flutter run --profile session. It can be imported into DevTools and contains late_ticker_callback events at approximately 33.33 ms.
I have also attached a screenshot with one event selected and its arguments
expanded.
Timeline recording appears to affect the observed event rate, so the trace is
used primarily to demonstrate the event and its context. The quantitative A/B
comparison below is based on the sample's lightweight in-app counters under
matched test conditions.
Experimental scheduling change
The current Linux task runner converts the remaining delay from microseconds
to an integer-millisecond GLib timeout.
I tested an experimental change which instead creates a one-shot GLib source
and assigns the task's absolute monotonic deadline using g_source_set_ready_time().
In the matched profile A/B runs (self-built baseline and patched engines from
the same checkout, same GN configuration; only this change differs):
baseline: 172 / 10622 callbacks (1.62%)
patched: 23 / 10777 callbacks (0.21%)
relative reduction: 86.82%
The p99 interval changed from approximately 33333 us to 16667 us.
This suggests that the existing millisecond timeout scheduling is a
significant contributor in this environment. I have not established that it
is the only contributor, since a small number of late intervals remain after
the experimental change.
Initial safety checks
In the limited probes performed for the experimental implementation:
no early dispatch was observed in 45 tested deadline-boundary samples;
the source remained one-shot and did not busy-loop;
cancellation, rescheduling, equal-deadline tasks, and posting a task from a
callback behaved as expected in the performed probes;
no obvious idle-source starvation was observed;
short CPU and context-switch observations did not show an obvious increase.
These checks are limited to the tested environment and are not intended as a
claim of general correctness or zero power impact.
The existing nanosecond-to-microsecond conversion uses integer division.
Relative to the stored microsecond deadline, no early dispatch was observed.
Relative to the original nanosecond value, there may still be a
sub-microsecond truncation. I have not included a change to that conversion in
the candidate patch.
@zhn1100 Thanks for providing the detailed report, reproduction details and performance traces. I was able to reproduce the reported behavior on my local Linux setup using the provided minimal reproduction in profile mode (flutter run --profile -d linux). After recording a Performance trace in DevTools, I observed late_ticker_callback timeline events with values consistent with the report, including:
delta_us ≈ 33334
expected_us ≈ 16667
These observations are consistent with the occasional skipped-frame behavior described in the issue. Routing to the team-linux for the further investigation.
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.
Activity
mbcorona commentedon Aug 5, 2026
Thanks, the diagnosis.
To treat this as a confirmed frame-scheduling bug and validate a fix, could you attach a minimal runnable sample, flutter doctor -v, and a flutter run --profile timeline trace (saved from DevTools) that shows a tick landing a full interval late?
With those we can route to the Linux team.
Evidence attachments for flutter/flutter#190620
zhn1100 commentedon Aug 6, 2026
Thank you for the guidance.
I have prepared a standalone Flutter Linux reproduction with no third-party
packages, together with
flutter doctor -voutput and a profile-modeDevTools Performance trace.
Minimal reproduction
The sample contains only a Flutter
Tickerdriving a lightweight movingrectangle. Each callback records the elapsed interval, and callbacks with an
interval of at least 25 ms emit a
late_ticker_callbackTimeline event.Reproduction steps:
flutter pub get.flutter run --profile -d linux.late_ticker_callback.On the tested 60 Hz setup, callbacks would normally be expected at
approximately 16.67 ms intervals.
In the attached trace, some callbacks occur at approximately 33.33 ms. The
attached screenshot shows one selected event with:
delta_us: 33334expected_us: 16667Occasional longer intervals were also observed. The sample performs very
little Dart build or paint work.
Version coverage
I reproduced the behavior on the tested official stable revision and on the
tested master revision.
Stable:
Master:
The complete
flutter doctor -voutput is attached.DevTools trace
The baseline attachment is a DevTools Performance snapshot captured from a
flutter run --profilesession. It can be imported into DevTools and containslate_ticker_callbackevents at approximately 33.33 ms.I have also attached a screenshot with one event selected and its arguments
expanded.
Timeline recording appears to affect the observed event rate, so the trace is
used primarily to demonstrate the event and its context. The quantitative A/B
comparison below is based on the sample's lightweight in-app counters under
matched test conditions.
Experimental scheduling change
The current Linux task runner converts the remaining delay from microseconds
to an integer-millisecond GLib timeout.
I tested an experimental change which instead creates a one-shot GLib source
and assigns the task's absolute monotonic deadline using
g_source_set_ready_time().In the matched profile A/B runs (self-built baseline and patched engines from
the same checkout, same GN configuration; only this change differs):
The p99 interval changed from approximately 33333 us to 16667 us.
This suggests that the existing millisecond timeout scheduling is a
significant contributor in this environment. I have not established that it
is the only contributor, since a small number of late intervals remain after
the experimental change.
Initial safety checks
In the limited probes performed for the experimental implementation:
callback behaved as expected in the performed probes;
These checks are limited to the tested environment and are not intended as a
claim of general correctness or zero power impact.
The existing nanosecond-to-microsecond conversion uses integer division.
Relative to the stored microsecond deadline, no early dispatch was observed.
Relative to the original nanosecond value, there may still be a
sub-microsecond truncation. I have not included a change to that conversion in
the candidate patch.
Tested environment and limitations
Tested:
Not yet fully verified:
Attachments
All attachments are hosted at:
https://github.com/zhn1100/flutter-issue-190620
flutter doctor -vflutter --versionWould these materials be sufficient to route the issue to the Linux team?
Please let me know if a different trace format or a smaller attachment set
would be more useful. Thank you for taking a look.
suryaKommana2662 commentedon Aug 7, 2026
@zhn1100 Thanks for providing the detailed report, reproduction details and performance traces. I was able to reproduce the reported behavior on my local Linux setup using the provided minimal reproduction in profile mode (
flutter run --profile -d linux). After recording a Performance trace in DevTools, I observed late_ticker_callback timeline events with values consistent with the report, including:These observations are consistent with the occasional skipped-frame behavior described in the issue. Routing to the
team-linuxfor the further investigation.Fix use-after-free of FlTaskRunner timeout on shutdown (flutter#194525)
Fix use-after-free of FlTaskRunner timeout on shutdown (flutter#194525)
Fix use-after-free of FlTaskRunner timeout on shutdown (flutter#194525)
github-actions commentedon Nov 4, 2026
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.