Skip to content

[Linux] Fallback vsync timer quantizes deadlines to milliseconds, causing occasional skipped frames #190620

Closed

Description

@zhn1100

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!

Activity

  1. added
    engineflutter/engine related. See also e: labels.
    c: performanceRelates to speed or footprint issues (see "perf:" labels)
    platform-linuxBuilding on or for Linux specifically
    c: proposalA detailed proposal for a change to Flutter
    team-linuxOwned by the Linux platform team
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    and removed
    c: proposalA detailed proposal for a change to Flutter
    team-linuxOwned by the Linux platform team
    on Aug 5, 2026
  2. mbcorona commented on Aug 5, 2026

    @mbcorona
    Member

    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.

  3. zhn1100 commented on Aug 6, 2026

    @zhn1100
    Author

    Thank you for the guidance.

    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:

    1. Extract the attached sample.
    2. Run flutter pub get.
    3. Run flutter run --profile -d linux.
    4. Open DevTools Performance and record the Timeline.
    5. 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.

    Stable:

    • Flutter: 3.44.8
    • Framework revision: 058e0af
    • Engine revision: 0cd6107

    Master:

    • Flutter: 3.47.0-0.4.pre (channel master)
    • Framework revision: e26b384
    • Engine revision: e26b384

    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.

    Tested environment and limitations

    Tested:

    • Linux: CachyOS 7.1.5 (Arch-based), kernel 7.1.5-1-cachyos
    • Display environment: Wayland, niri 26.04
    • GPU: NVIDIA GeForce RTX 4050 (proprietary driver)
    • GLib: 2.88.3
    • GTK: 3.24.52
    • Refresh rate: 60.061 Hz (eDP-1, preferred mode)

    Not yet fully verified:

    • a native Xorg session;
    • AMD and Intel GPUs;
    • other GLib versions and Linux distributions;
    • long-term power and wakeup behavior;
    • whether the remaining late intervals have the same cause.

    Attachments

    All attachments are hosted at:
    https://github.com/zhn1100/flutter-issue-190620

    Would 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.

  4. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Aug 6, 2026
  5. suryaKommana2662 commented on Aug 7, 2026

    @suryaKommana2662
    Contributor

    @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.

    Image
  6. added
    team-linuxOwned by the Linux platform team
    and removed
    in triagePresently being triaged by the triage team
    on Aug 7, 2026
  7. added
    P2Important issues not at the top of the work list
    triaged-linuxTriaged by the Linux platform team
    on Aug 19, 2026
  8. github-actions commented on Nov 4, 2026

    @github-actions

    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.

  9. locked as resolved and limited conversation to collaborators on Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listc: performanceRelates to speed or footprint issues (see "perf:" labels)engineflutter/engine related. See also e: labels.found in release: 3.44Found to occur in 3.44platform-linuxBuilding on or for Linux specificallyteam-linuxOwned by the Linux platform teamtriaged-linuxTriaged by the Linux platform team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions