Repository navigation
[Android] Let the raster thread use every core of a chip without little cores - #195071
Conversation
…le cores CPUSpeedTracker counts the CPUs with the lowest top frequency as efficiency cores, and the raster thread is set to the others. On the Snapdragon 8 Elite and 8 Elite Gen 5 (two prime and six performance cores) that leaves the raster thread the two prime cores, which idle at their lowest frequency. Also read each CPU's cpu_capacity. When every CPU has one and none is below half of the fastest, the chip has no little cores, and kNotEfficiency is every core. Fixes flutter#195070
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
There was a problem hiding this comment.
Code Review
This pull request introduces CPU capacity detection to identify devices without little cores, reading the cpu_capacity file on Android and updating CPUSpeedTracker to treat all cores as non-efficiency cores when no little cores are present. Feedback suggests simplifying the HasNoLittleCores helper function by using std::min and std::max with std::numeric_limits to avoid verbose optional state management.
| bool HasNoLittleCores(const std::vector<CpuIndexAndSpeed>& cpus) { | ||
| std::optional<int64_t> min_capacity = std::nullopt; | ||
| std::optional<int64_t> max_capacity = std::nullopt; | ||
| for (const auto& cpu : cpus) { | ||
| if (!cpu.capacity.has_value()) { | ||
| return false; | ||
| } | ||
| const int64_t capacity = cpu.capacity.value(); | ||
| if (!min_capacity.has_value() || capacity < min_capacity.value()) { | ||
| min_capacity = capacity; | ||
| } | ||
| if (!max_capacity.has_value() || capacity > max_capacity.value()) { | ||
| max_capacity = capacity; | ||
| } | ||
| } | ||
| return min_capacity.has_value() && min_capacity != max_capacity && | ||
| min_capacity.value() * 2 >= max_capacity.value(); | ||
| } |
There was a problem hiding this comment.
The logic in HasNoLittleCores can be simplified and made more idiomatic by checking if the input vector is empty first, and then using standard std::min and std::max with std::numeric_limits to track the minimum and maximum capacities. This avoids the verbosity of managing multiple std::optional states and calling .value() repeatedly.
bool HasNoLittleCores(const std::vector<CpuIndexAndSpeed>& cpus) {
if (cpus.empty()) {
return false;
}
int64_t min_capacity = std::numeric_limits<int64_t>::max();
int64_t max_capacity = std::numeric_limits<int64_t>::min();
for (const auto& cpu : cpus) {
if (!cpu.capacity.has_value()) {
return false;
}
const int64_t capacity = *cpu.capacity;
min_capacity = std::min(min_capacity, capacity);
max_capacity = std::max(max_capacity, capacity);
}
return min_capacity != max_capacity && min_capacity * 2 >= max_capacity;
}
gaaclarke
left a comment
There was a problem hiding this comment.
Okay, let's just clean up the tests. I think the premise for this change is fine. I think it's unfortunate and maybe there is another way we can do this better. This is acceptable for now.
| ASSERT_EQ(tracker.GetIndices(CpuAffinity::kNotEfficiency)[0], 1u); | ||
| ASSERT_EQ(tracker.GetIndices(CpuAffinity::kNotEfficiency)[1], 2u); |
There was a problem hiding this comment.
Any assertion that won't lead to a crash should be EXPECT_EQ
|
Thanks for the review. I switched the assertions that don't need to abort to EXPECT_*, and kept ASSERT_EQ only on the size checks that guard the indexing right after them. Pushed in 48b667c. You mentioned there may be a better way. I hit this as an app developer, so I'd like to know which direction the team has in mind so I can follow along or help where useful. Is it something like ADPF hint sessions (#114835; I saw #192582 for API 35+), or leaning more on the scheduler and not pinning threads at all? If this is meant as a stopgap, that's fine — we're carrying an app-side workaround for now. |
gaaclarke
left a comment
There was a problem hiding this comment.
I think this is a fine change for now until we come up with a more comprehensive solution to the general problem.
|
@b-luk can you please be a second reviewer for this, you were looking at a similar class of problems the other day. I don't think this is ideal but should do some good without causing any harm with the current approach. |
b-luk
left a comment
There was a problem hiding this comment.
I think both the existing cpu affinity code and the changes from this PR make a lot of assumptions about the categorization and behavior of CPU cores which are somewhat mismatched with categorizations and behavior in the real world. So overall I'm not a fan of this entire existing approach. I think we should be handling CPU core selection and scheduling in a different way than trying to do our own manual categorization of cores and affinity selection. But coming up with an entirely different approach is outside the scope of this PR.
This PR improves your demonstrated use case, so I'm okay with it despite my caveats above.
… covers On a chip without little cores, kNotEfficiency includes the efficiency cores, so it no longer meant "every core except the efficiency cores". Each CpuAffinity value now says which cores it covers, and the enum notes that performance and efficiency here are speed groups, not the industry's core types. The example moves out of CPUSpeedTracker's doc, and kPerformance no longer claims that the UI and raster threads use it.
|
Thanks. Both loops now reserve their vector before filling it, pushed in 1b794a0. With the engine's .clang-tidy, clang-tidy 21 reports the same two errors on the old file locally and none on the new one. |
|
autosubmit label was removed for flutter/flutter/195071, because This PR has not met approval requirements for merging. The PR author is not a member of flutter-hackers and needs 1 more review(s) in order to merge this PR.
|
|
autosubmit label was removed for flutter/flutter/195071, because - The status or check suite Google testing has failed. Please fix the issues identified (or deflake) before re-applying this label. |
flutter/flutter@5e805bf...ee8b482 2026-10-31 [email protected] Roll Skia from 9bab765df357 to 607de4b035dc (1 revision) (flutter/flutter#195728) 2026-10-31 [email protected] Roll Skia from 284054bec98a to 9bab765df357 (2 revisions) (flutter/flutter#195726) 2026-10-31 [email protected] Roll Skia from 3a3f56f7ddd4 to 284054bec98a (1 revision) (flutter/flutter#195724) 2026-10-31 [email protected] Roll Skia from 466994d27b1e to 3a3f56f7ddd4 (1 revision) (flutter/flutter#195719) 2026-10-30 [email protected] Fix XcodeProjectInterpreter dependency cycle in flutter_tools (flutter/flutter#195694) 2026-10-30 [email protected] Document that Positioned also works inside an Overlay (flutter/flutter#190607) 2026-10-30 [email protected] Roll Skia from ce0b85b46db6 to 466994d27b1e (3 revisions) (flutter/flutter#195711) 2026-10-30 [email protected] Adds Vulkan sync validation test run (flutter/flutter#195596) 2026-10-30 [email protected] [Android] Let the raster thread use every core of a chip without little cores (flutter/flutter#195071) 2026-10-30 [email protected] Roll Skia from 121d04c01e2d to ce0b85b46db6 (6 revisions) (flutter/flutter#195699) 2026-10-30 [email protected] [web] Anchor platform view slots to top-left to fix RTL document layout (flutter/flutter#194601) 2026-10-30 [email protected] Update golden file testing docs (flutter/flutter#195449) 2026-10-30 [email protected] [tool] Migrate Cache.flutterRoot static state to instance configuration (flutter/flutter#190795) 2026-10-30 [email protected] Apply view metrics overrides below the framework (flutter/flutter#194311) 2026-10-30 [email protected] Roll Skia from c0c46ee9f938 to 121d04c01e2d (9 revisions) (flutter/flutter#195687) 2026-10-30 [email protected] Use uniforms in the Porter Duff blend shader instead of specialization constants (flutter/flutter#195458) 2026-10-30 [email protected] [flutter_tools] Inject dependencies into iOS, macOS, and Windows application packages (flutter/flutter#194047) If this roll has caused a breakage, revert this CL and set the roller to dry run mode using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
|
This has regressed the average rasterizer time for this test. This is a 2x regression: |
|
reason for revert: This has caused a regression in one of our benchmarks ( #195071 (comment) ). It is possible that the drop in the benchmark is desirable, for example it uses less energy and gives the same apparent output. We track energy usage but it didn't show a positive change for this PR. I'm not sure how it's measured and if it's trustworthy on android. So, our only option is run the benchmarks on the most capable cores. In order to reland this we need to rework it so that either:
|
|
Successfully created revert PR: #195838 |
…out little cores (flutter#195838) Reverts: [[Android] Let the raster thread use every core of a chip without little cores](flutter#195071) Initiated by: @gaaclarke Reason for reverting: 1) we address the problem where the energy measurement shows the tradeoff Original PR Author: @Lopution Reviewed By: @gaaclarke The original PR description is provided below: `CPUSpeedTracker` counts the CPUs with the lowest `cpuinfo_max_freq` as efficiency cores, and the raster thread is set to the other cores (`kNotEfficiency`, renamed `kNotLittle` in this PR). On a chip without little cores, those are full-size cores. On the Snapdragon 8 Elite and 8 Elite Gen 5 (two prime and six performance Oryon cores) the raster thread only gets the two prime cores. They are mostly idle, so raster frames start at the cluster's lowest frequency. See flutter#195070 for measurements. This change also reads `/sys/devices/system/cpu/cpuN/cpu_capacity`, the kernel's rating of each CPU, scaled so that the fastest is 1024. When every CPU has a capacity and none is below half of the fastest, the chip has no little cores, and `kNotLittle` is every core. - Why half: little cores rate well below it. Upstream SM8650 device trees put the Cortex-A520 at about 37% of the X4 at their top frequencies. The SM8850's performance cores are at 762 of 1024. - Equal capacities, or a CPU without one, change nothing. A kernel without capacity data reports 1024 for every CPU. - Other affinities do not change. `kEfficiency` is still the slowest group, so background threads stay off the prime cores. - `kNotEfficiency` is renamed `kNotLittle`, since on these chips it includes the efficiency cores. Each `CpuAffinity` value's doc says which cores it covers, and that performance and efficiency there are speed groups, not the industry's core types. - Chips with little cores (Snapdragon 8 Gen 1–3, Tensor, Exynos 2400) should keep the current set. I have only read the capacities of the SM8850. - Other chips without little cores also get every core. Examples: Dimensity 9300/9400 (the slowest group is four Cortex-A720), Snapdragon 8s Gen 4, and Snapdragon 8 Elite Gen 6. On the 8 Elite Gen 6 the six performance cores report two top frequencies (4.03 and 3.74 GHz), so today three of them count as efficiency cores. I have not measured these chips. - On the Dimensity 9600 Pro (2 × C2-Ultra at 4.55 GHz, 3 × C2-Pro at 4.35 GHz, 3 × C2-Pro at 3.1 GHz), the 3.1 GHz cores should rate near half, so it may go either way. Either way the raster thread keeps at least the five cores it gets today. This keeps the current design and only widens it where the capacities are clear. A chip whose performance cores rate below half of its prime cores would still leave the raster thread on the prime cores. The more general fix would be to stop pinning the raster thread, as Android does not pin a native app's RenderThread. That needs measurements on the devices that flutter-team-archive/engine#45673 and flutter#153690 were about, so this change leaves it out. Tests: three new `CpuAffinity` tests in `fml_unittests`. `NoLittleCores` fails without this change. I ran the `CpuAffinity` tests against the changed files in a standalone build with clang++ and g++, not in a full engine build. On an SM8850 phone, setting the raster threads to every core from the app (the same result as this change) gave the numbers in flutter#195070. I have not tested a custom engine build on the device. Fixes flutter#195070 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant in-code documentation (doc comments with `///`). - [x] If this PR introduces a new feature or capability, I created and linked a website documentation issue or PR in [flutter/website] (or verified none is needed). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/CONTRIBUTING.ai.md [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [flutter/website]: https://github.com/flutter/website [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
…le cores (flutter#195071) `CPUSpeedTracker` counts the CPUs with the lowest `cpuinfo_max_freq` as efficiency cores, and the raster thread is set to the other cores (`kNotEfficiency`, renamed `kNotLittle` in this PR). On a chip without little cores, those are full-size cores. On the Snapdragon 8 Elite and 8 Elite Gen 5 (two prime and six performance Oryon cores) the raster thread only gets the two prime cores. They are mostly idle, so raster frames start at the cluster's lowest frequency. See flutter#195070 for measurements. This change also reads `/sys/devices/system/cpu/cpuN/cpu_capacity`, the kernel's rating of each CPU, scaled so that the fastest is 1024. When every CPU has a capacity and none is below half of the fastest, the chip has no little cores, and `kNotLittle` is every core. - Why half: little cores rate well below it. Upstream SM8650 device trees put the Cortex-A520 at about 37% of the X4 at their top frequencies. The SM8850's performance cores are at 762 of 1024. - Equal capacities, or a CPU without one, change nothing. A kernel without capacity data reports 1024 for every CPU. - Other affinities do not change. `kEfficiency` is still the slowest group, so background threads stay off the prime cores. - `kNotEfficiency` is renamed `kNotLittle`, since on these chips it includes the efficiency cores. Each `CpuAffinity` value's doc says which cores it covers, and that performance and efficiency there are speed groups, not the industry's core types. - Chips with little cores (Snapdragon 8 Gen 1–3, Tensor, Exynos 2400) should keep the current set. I have only read the capacities of the SM8850. - Other chips without little cores also get every core. Examples: Dimensity 9300/9400 (the slowest group is four Cortex-A720), Snapdragon 8s Gen 4, and Snapdragon 8 Elite Gen 6. On the 8 Elite Gen 6 the six performance cores report two top frequencies (4.03 and 3.74 GHz), so today three of them count as efficiency cores. I have not measured these chips. - On the Dimensity 9600 Pro (2 × C2-Ultra at 4.55 GHz, 3 × C2-Pro at 4.35 GHz, 3 × C2-Pro at 3.1 GHz), the 3.1 GHz cores should rate near half, so it may go either way. Either way the raster thread keeps at least the five cores it gets today. This keeps the current design and only widens it where the capacities are clear. A chip whose performance cores rate below half of its prime cores would still leave the raster thread on the prime cores. The more general fix would be to stop pinning the raster thread, as Android does not pin a native app's RenderThread. That needs measurements on the devices that flutter-team-archive/engine#45673 and flutter#153690 were about, so this change leaves it out. Tests: three new `CpuAffinity` tests in `fml_unittests`. `NoLittleCores` fails without this change. I ran the `CpuAffinity` tests against the changed files in a standalone build with clang++ and g++, not in a full engine build. On an SM8850 phone, setting the raster threads to every core from the app (the same result as this change) gave the numbers in flutter#195070. I have not tested a custom engine build on the device. Fixes flutter#195070 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant in-code documentation (doc comments with `///`). - [x] If this PR introduces a new feature or capability, I created and linked a website documentation issue or PR in [flutter/website] (or verified none is needed). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/CONTRIBUTING.ai.md [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [flutter/website]: https://github.com/flutter/website [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
…out little cores (flutter#195838) Reverts: [[Android] Let the raster thread use every core of a chip without little cores](flutter#195071) Initiated by: @gaaclarke Reason for reverting: 1) we address the problem where the energy measurement shows the tradeoff Original PR Author: @Lopution Reviewed By: @gaaclarke The original PR description is provided below: `CPUSpeedTracker` counts the CPUs with the lowest `cpuinfo_max_freq` as efficiency cores, and the raster thread is set to the other cores (`kNotEfficiency`, renamed `kNotLittle` in this PR). On a chip without little cores, those are full-size cores. On the Snapdragon 8 Elite and 8 Elite Gen 5 (two prime and six performance Oryon cores) the raster thread only gets the two prime cores. They are mostly idle, so raster frames start at the cluster's lowest frequency. See flutter#195070 for measurements. This change also reads `/sys/devices/system/cpu/cpuN/cpu_capacity`, the kernel's rating of each CPU, scaled so that the fastest is 1024. When every CPU has a capacity and none is below half of the fastest, the chip has no little cores, and `kNotLittle` is every core. - Why half: little cores rate well below it. Upstream SM8650 device trees put the Cortex-A520 at about 37% of the X4 at their top frequencies. The SM8850's performance cores are at 762 of 1024. - Equal capacities, or a CPU without one, change nothing. A kernel without capacity data reports 1024 for every CPU. - Other affinities do not change. `kEfficiency` is still the slowest group, so background threads stay off the prime cores. - `kNotEfficiency` is renamed `kNotLittle`, since on these chips it includes the efficiency cores. Each `CpuAffinity` value's doc says which cores it covers, and that performance and efficiency there are speed groups, not the industry's core types. - Chips with little cores (Snapdragon 8 Gen 1–3, Tensor, Exynos 2400) should keep the current set. I have only read the capacities of the SM8850. - Other chips without little cores also get every core. Examples: Dimensity 9300/9400 (the slowest group is four Cortex-A720), Snapdragon 8s Gen 4, and Snapdragon 8 Elite Gen 6. On the 8 Elite Gen 6 the six performance cores report two top frequencies (4.03 and 3.74 GHz), so today three of them count as efficiency cores. I have not measured these chips. - On the Dimensity 9600 Pro (2 × C2-Ultra at 4.55 GHz, 3 × C2-Pro at 4.35 GHz, 3 × C2-Pro at 3.1 GHz), the 3.1 GHz cores should rate near half, so it may go either way. Either way the raster thread keeps at least the five cores it gets today. This keeps the current design and only widens it where the capacities are clear. A chip whose performance cores rate below half of its prime cores would still leave the raster thread on the prime cores. The more general fix would be to stop pinning the raster thread, as Android does not pin a native app's RenderThread. That needs measurements on the devices that flutter-team-archive/engine#45673 and flutter#153690 were about, so this change leaves it out. Tests: three new `CpuAffinity` tests in `fml_unittests`. `NoLittleCores` fails without this change. I ran the `CpuAffinity` tests against the changed files in a standalone build with clang++ and g++, not in a full engine build. On an SM8850 phone, setting the raster threads to every core from the app (the same result as this change) gave the numbers in flutter#195070. I have not tested a custom engine build on the device. Fixes flutter#195070 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant in-code documentation (doc comments with `///`). - [x] If this PR introduces a new feature or capability, I created and linked a website documentation issue or PR in [flutter/website] (or verified none is needed). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/CONTRIBUTING.ai.md [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [flutter/website]: https://github.com/flutter/website [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
CPUSpeedTrackercounts the CPUs with the lowestcpuinfo_max_freqas efficiency cores, and the raster thread is set to the other cores (kNotEfficiency, renamedkNotLittlein this PR). On a chip without little cores, those are full-size cores. On the Snapdragon 8 Elite and 8 Elite Gen 5 (two prime and six performance Oryon cores) the raster thread only gets the two prime cores. They are mostly idle, so raster frames start at the cluster's lowest frequency. See #195070 for measurements.This change also reads
/sys/devices/system/cpu/cpuN/cpu_capacity, the kernel's rating of each CPU, scaled so that the fastest is 1024. When every CPU has a capacity and none is below half of the fastest, the chip has no little cores, andkNotLittleis every core.kEfficiencyis still the slowest group, so background threads stay off the prime cores.kNotEfficiencyis renamedkNotLittle, since on these chips it includes the efficiency cores. EachCpuAffinityvalue's doc says which cores it covers, and that performance and efficiency there are speed groups, not the industry's core types.This keeps the current design and only widens it where the capacities are clear. A chip whose performance cores rate below half of its prime cores would still leave the raster thread on the prime cores. The more general fix would be to stop pinning the raster thread, as Android does not pin a native app's RenderThread. That needs measurements on the devices that flutter-team-archive/engine#45673 and #153690 were about, so this change leaves it out.
Tests: three new
CpuAffinitytests infml_unittests.NoLittleCoresfails without this change. I ran theCpuAffinitytests against the changed files in a standalone build with clang++ and g++, not in a full engine build. On an SM8850 phone, setting the raster threads to every core from the app (the same result as this change) gave the numbers in #195070. I have not tested a custom engine build on the device.Fixes #195070
Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.