跪拜 Guibai
← Back to the summary

Flutter's CPU Affinity Rollercoaster: Raster Thread Fix Rolled Back After 2x Regression, ADPF RFC Puts OS in Charge

Last week we discussed #195071 on CPUs like the Snapdragon 8 Elite that have Little Cores, and it turns out the story keeps evolving. Similar problems aren't limited to one case:

So the common thread is clear:

Flutter's UI/Raster Thread tasks are short, periodic, latency-sensitive, while the CPU scheduler typically has to balance throughput, power, temperature, and overall system load. The so-called optimal choice may not be consistent across platforms.

For example, on Android the two 4.61 GHz Prime Cores might actually be slower than the six 3.63 GHz Performance Cores, because 4.61 GHz is the maximum attainable frequency, but thread wake-up costs are high. Flutter's Raster Thread work is often very short, like a frame that only needs 1–2 ms of rasterization. If the thread wakes up every 16.7 ms and sleeps as soon as it's done, and the Prime Cluster has dropped to its minimum frequency due to idling, then when the thread wakes, the CPU frequency hasn't ramped up yet before the task completes.

But if the Raster Thread runs on other Performance Cores, there may be other tasks keeping that cluster at a higher frequency, giving Flutter better scheduling directly.

The problem appeared after the fix: the official Benchmark regressed by 2x. In #195826, merging #195071 made the official fading_child_animation_perf benchmark's average_frame_rasterizer_time_millis regress by 2x, so the change was rolled back.

So the solution still brings other negative effects.

Looking back, Flutter has repeatedly stepped on this issue. This time it's like a loop of CPU affinity policy adjustments:

Time Problem Approach
2023, #134452 On Pixel 6 Pro, UI/Raster could be scheduled to slow cores, causing jank Use affinity to prefer performance cores
2024, #153690 On Pixel 8, UI, Raster, and some Dart Workers could crowd onto the same fastest core Expand the pool of available cores to avoid over-concentration
2026-10, #195070 Snapdragons without traditional little cores were misclassified, excluding 6 Performance Cores Use cpu_capacity to identify devices without little cores
2026-11, #195826 After expanding the core range, official benchmarks regressed Roll back the change and re-evaluate

Initially cores were restricted because the Android scheduler would put critical render threads on slower cores, affecting frame rate. But after the restriction, on devices like Pixel 8, UI, Raster, and some Workers competed for the same core.

Then, with further fixes, on the Oryon architecture without traditional Little Cores, Flutter still relied on highest-frequency grouping, which ended up excluding the six Performance Cores.

After this release, it did get faster on SM8850, but official tests hit a regression again.

So I think a more reasonable direction is to reconsider the entire core selection and scheduling mechanism. Patching piecemeal is just piling up a trash heap.

So do you think Flutter should choose cores itself, or let the operating system decide?

Currently there is an official ADPF integration RFC #45 proposal, corresponding to #195992. It aims to design support that tells Android the frame deadline and lets the system schedule itself. In other words, Flutter might no longer need to judge which cores are suitable for Raster based on CPU static parameters. Instead, it would tell Android:

This way Android can make decisions combining CPU frequency, scheduling policies, and power budgets.

The RFC author has run multiple Profile Benchmarks on Pixel 8, Pixel 9, and Lenovo Tab, deliberately disabling Fixed Performance Mode in the test environment so devices use normal dynamic frequency scaling. Approximate results:

Benchmark Pre-prototype Raster Avg ADPF prototype Improvement
Pixel 8, complex layout scroll 4.18 ms 2.65 ms 36%
Pixel 8, Tiles scroll 4.62 ms 2.91 ms 37%
Pixel 9, complex layout scroll 4.15 ms 2.59 ms 38%
Pixel 9, Tiles scroll 4.28 ms 2.42 ms 44%

But the prototype also has regressions. For example, some light-load scenarios on Pixel 8 and Lenovo Tab are slower, and Hybrid Composition has special thread-merging issues.

However, I think this approach's direction is more reasonable. At least handing decisions to the system is more stable than maintaining this mess. The rule doesn't support external configuration updates, so it's better to leave it to the system.