Closed Bug 1850573 Opened 1 years ago Closed 1 year ago

Set CPU affinity for main thread and stylo threads on Android when PerformanceHintManager is not available

Categories

(Core :: Performance Engineering, task)

Unspecified
Android
task

Tracking

()

RESOLVED FIXED
120 Branch
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.

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.

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

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

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

Pushed by jnicol@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/22b6ef4463c6 Create/destroy PerformanceHintSession in ContentChild based on process priority. r=smaug https://hg.mozilla.org/integration/autoland/rev/b45b74317025 Add HeterogeneousCpuInfo to HAL with Android implementation. r=geckoview-reviewers,owlish https://hg.mozilla.org/integration/autoland/rev/3d7ee3118e93 Set stylo threads' affinities to performant cores when content process is foregrounded. r=smaug https://hg.mozilla.org/integration/autoland/rev/80bdce072953 Override number of style threads on systems with heterogeneous CPUs. r=emilio
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: