Skip to content

performance regression in average_frame_rasterizer_time_millis #194807

Closed

Activity

  1. added
    c: performanceRelates to speed or footprint issues (see "perf:" labels)
    P1High-priority issues at the top of the work list
    on Oct 19, 2026
  2. self-assigned this
    on Oct 21, 2026
  3. b-luk commented on Oct 21, 2026

    @b-luk
    Contributor

    I bisected and debugged this with help from AI. Analysis is below. I discussed with @gaaclarke and will close this issue.

    Summary

    This is not a real rasterizer regression. A Dart VM change in the roll reduced how often background garbage collection (GC) runs during this benchmark. Because the CPU is doing less background work overall, the OS scales down the CPU clock frequency, making the short per-frame raster bursts take longer in wall-clock time (while still finishing around ~2 ms, well within the 16 ms frame budget). Because this down-clocking only happens when the overall CPU workload is light, it will not make heavy frames slower and is not expected to increase visible jank in real world apps.

    What caused the shift

    The regression is a ~1.5× jump in average_frame_rasterizer_time_millis when running the complex_layout_scroll_perf_bad benchmark on an iPhone. We were able to reproduce the same regression running locally on macOS. Bisecting the Dart roll range narrows the regression to 3.15.0-26.dev → 3.15.0-27.dev. The only VM change contained within that version bump is dart-lang/sdk@0e87827aa370 ([vm, gc] Increase page size to 2 MB). (cc @rmacnak-google as an FYI)

    That commit quadrupled the Dart heap page size (Page::kPageSize) from 512 KB to 2 MB, which also raised the threshold for triggering an idle old-generation GC between scroll bursts (from +1 MB to +4 MB). As a result, the VM runs significantly less background GC work (~30–45% fewer old-gen GCs) during the benchmark:

    • CI (iPhone 11): old_gen_gc_count dropped from 30 → 22, and overall device average_cpu_usage dropped from ~40% → ~35%.
    • Local (macOS): Old-gen GCs dropped from 36 → 20, and background GC marking time (ConcurrentMark in the timeline trace) dropped from 1.94 s → 1.05 s.

    Why less GC work makes raster times look higher

    The raster thread in this benchmark only runs for ~0.5–1 ms per frame (~5% of the time). When background GC worker threads are running on other cores, they keep the CPU cluster spun up at full clock speed. With fewer background GCs, the CPU spends more time in a down-clocked / low-power state when the raster thread wakes up. Analyzing timeline trace output (from output of flutter drive -t test_driver/scroll_perf_bad.dart -d macos --profile --trace-startup) shows:

    • No specific raster bottleneck: Timeline traces show every single sub-phase of the raster thread (preroll, drawing, glyph atlas, presentation) is uniformly ~1.7× slower.
    • Frames during GC are still fast: Within a single trace, frames that overlap with background GC run at the same fast speed before and after the roll (p90 ≈ 0.8–0.9 ms), whereas the slower frames (p90 ≈ 2.0–2.2 ms) only happen during quiet periods when no background GC is active.

    Proof: Keeping the CPU busy erases the difference

    To confirm this is purely CPU frequency scaling (DVFS), we ran two unrelated background busy-loops (yes > /dev/null) alongside the benchmark to keep the CPU cluster at full clock speed:

    Condition p50 raster (ms) p90 raster (ms)
    Before (3.15.0-26.0.dev), idle 0.57 1.26
    After (3.15.0-27.0.dev), idle 0.73 2.23
    Before (3.15.0-26.0.dev), with CPU load 0.34 0.60
    After (3.15.0-27.0.dev), with CPU load 0.45 0.60

    Keeping the CPU warm makes both versions faster than the idle pre-roll baseline and completely eliminates the 90th-percentile gap (0.60 ms vs. 0.60 ms).

    Conclusion

    The Dart VM change is a net CPU/GC efficiency improvement, and missed_frame_rasterizer_budget_count on CI did not change. The jump on the graph is a power-management (DVFS) side effect on a lightly loaded device.

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

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

Labels

P1High-priority issues at the top of the work listc: performanceRelates to speed or footprint issues (see "perf:" labels)team-engineOwned by Engine team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions