Set CPU affinity for main thread and stylo threads on Android when PerformanceHintManager is not available
Categories
(Core :: Performance Engineering, task)
Tracking
()
Tracking | Status | |
---|---|---|
firefox120 | --- | fixed |
People
(Reporter: jnicol, Assigned: jnicol)
References
(Blocks 1 open bug)
Details
(Whiteboard: [sp3])
Attachments
(4 files)
In bug 1848766 we made use of the PerformanceHintManager API to ensure the content process main thread and stylo threadpool threads get scheduled on powerful cores. Unfortunately this API is currently unavailable on most devices. In such cases we should manually set the CPU affinity of these threads instead.
From testing on a variety of devices it appears that when there are 2 or more big cores setting the affinity to the big cores only gives maximum performance. When there are less than 2 big cores, setting the affinity to the big and medium cores performs better.
We can determine which cores are big, little, and medium by parsing /sys/devices/system/cpu/cpu/<n>/cpufreq/cpuinfo_max_freq
for n in 0..num_cores. In theory the max frequency might not correspond to the power of the core, but in all the devices I've looked at this is fine. Also working on the assumption that there are at most 3 sizes of CPU. We can always extend this later if SOCs with 4 sizes of CPU start to exist. Note that this file is not available in some old devices, so we must gracefully do nothing in that case. But surprisingly this file seems readable in isolated content processes which is nice.
I think we should only set the affinity if PerformanceHintManager is unavailable: otherwise PerformanceHintManager should be able to make a more informed decision than we are, and we might end up keeping work on big cores that doesn't need to be there.
We should probably be a good citizen and "reset" the affinity to all cores when we no longer require the extra performance. Note that when a process is backgrounded Android will automatically stop it from running on certain cores, so we don't have to worry about setting the affinity to little cores when in the background to save power etc.
Updated•1 years ago
|
Assignee | ||
Comment 1•1 year ago
|
||
We use a PerformanceHintSession where supported to ensure the content
process main thread and stylo threads are scheduled at a high
priority. Previously we created the session when the
VsyncRefreshDriverTimer is started, and destroyed the session when it
is stopped (after a timeout).
This patch instead moves the creation and destruction to ContentChild
based on the process priority. This more accurately reflects the
conditions under which we want the session to be active.
Assignee | ||
Comment 2•1 year ago
|
||
This adds a function GetHeterogeneousCpuInfo() to HAL, which
classifies the processor cores in to "big", "medium", and
"little". This is currently only implemented on Android, where it
works by parsing the maximum CPU frequency from sysfs.
When all CPUs have the same frequency they are all classified as
"big", and when there are only 2 different frequencies they are
classified as "big" and "little". All CPUs with a frequency in-between
the lowest and highest are classified as "medium".
This information can be used to count the number of each cores in each
category, eg for determining appropriate thread pool sizes. Or to
determine the indices of cores in a certain category, eg for setting
CPU affinity for certain threads.
Depends on D188477
Assignee | ||
Comment 3•1 year ago
|
||
On Android we use the PerformanceHintManager API to ensure that the
content process' main thread and stylo worker threads get scheduled as
required on the device's more performant cores. Unfortunately,
however, this API is only available on a handful of devices. This
patch therefore adds a fallback path, setting the affinity of the
stylo threads to the performant CPUs when the content process is in
the foreground.
The Android OS automatically resets each thread's affinity to all CPUs
when the process is foregrounded, meaning we must override it each
time the process is foregrounded rather than only doing so once during
init. Android additionally takes care of setting each thread's
affinity to a low-power subset of CPUs when the process is
backgrounded, meaning we do not have to do that ourselves.
Testing on a variety of devices has shown that setting the affinity to
only the big cores works best if there are 2 or more big cores. When
there are fewer than 2 big cores setting the affinity to big and
medium cores performs better.
Testing also showed no benefit to setting the main thread's affinity
in addition to that of the stylo threads. Presumably the main thread
is busy enough that it already gets frequently scheduled on the
powerful cores. Additionally, setting the main thread affinity could
have unintended consequences as each newly spawned thread inherits the
affinity mask from its parent. Therefore we only do so for the stylo
threads.
Depends on D188478
Assignee | ||
Comment 4•1 year ago
|
||
If there are 2 or more "big" CPUs then use the number of big CPUs as
the number of threads. If there are fewer than 2 then use the number
of big plus the number of "medium".
Currently this only affects android, as hal::GetHeterogeneousCpuInfo
is not implemented on other platforms.
Depends on D188479
Assignee | ||
Comment 5•1 year ago
|
||
Try run (with --extra-args disable-perf-tuning
): https://treeherder.mozilla.org/perfherder/comparesubtest?originalProject=try&newProject=try&newRevision=9ec01e045e2e5fdd12d0ff48f36268821e1d67fe&originalSignature=4590278&newSignature=4590278&framework=13&application=geckoview&originalRevision=5007e38bbfebe0adc912871919cb1a0bda516f86&page=1
Low confidence due to a couple outliers but if you look at the graph or subtests it's a pretty clear win
Comment 7•1 year ago
|
||
bugherder |
https://hg.mozilla.org/mozilla-central/rev/22b6ef4463c6
https://hg.mozilla.org/mozilla-central/rev/b45b74317025
https://hg.mozilla.org/mozilla-central/rev/3d7ee3118e93
https://hg.mozilla.org/mozilla-central/rev/80bdce072953
Description
•