Skip to content

Commit

Permalink
[cc] Simplify and adjust memory limits on Android
Browse files Browse the repository at this point in the history
On Android, compositor memory limits are derived from system memory and
dalvik memory limits. This code was noted as outdated in 2017 (see
linked bug), and as a result didn't work the way it should have.

This is because:
- Reported system RAM on Android is lower than installed RAM because of
  carveouts
- Dalvik memory limits are not really correlated with system RAM

Based on field data, the large majority of devices is running with a
computed limit of 256MiB, with some devices using 96MiB. This CL
simplifies the code to:
- Low-end or <2GiB: 96MiB
- Otherwise, 256MiB

Which mostly matches the current in-the-wild reality. These limits are
likely not optimal, but at least this simplifies the code. Also, lower
the priority cutoff to "NICE_TO_HAVE", which matches desktop, and
reality, since ALLOW_EVERYTHING is lowered to NICE_TO_HAVE elsewhere in
the code (see PriorityCutoffToTileMemoryLimitPolicy() for instance).

This is gated behind a feature flag, to make sure that this is not
breaking things.

(cherry picked from commit 42b97eaa9deace1c188434ccac37ee22223ade4f)

Bug: 380310632
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4860245
  • Loading branch information
Benoit Lize authored and dahlstrom-g committed Jan 3, 2025
1 parent 8e80e03 commit e663c95
Showing 1 changed file with 75 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ BASE_FEATURE(kScaleScrollbarAnimationTiming,
"ScaleScrollbarAnimationTiming",
base::FEATURE_DISABLED_BY_DEFAULT);

#if BUILDFLAG(IS_ANDROID)
// Whether to use a simpler way to compute compositor memory limits on
// Android. Intended to become default, but introduced temporarily to check
// it's not breaking things.
BASE_FEATURE(kSimpleCompositorMemoryLimits,
"SimpleCompositorMemoryLimits",
base::FEATURE_DISABLED_BY_DEFAULT);
#endif

constexpr base::FeatureParam<double> kFadeDelayScalingFactor{
&kScaleScrollbarAnimationTiming, "fade_delay_scaling_factor",
/*default_value=*/1.0};
Expand Down Expand Up @@ -105,65 +114,77 @@ cc::ManagedMemoryPolicy GetGpuMemoryPolicy(
}

#if BUILDFLAG(IS_ANDROID)
// We can't query available GPU memory from the system on Android.
// Physical memory is also mis-reported sometimes (eg. Nexus 10 reports
// 1262MB when it actually has 2GB, while Razr M has 1GB but only reports
// 128MB java heap size). First we estimate physical memory using both.
size_t dalvik_mb = base::SysInfo::DalvikHeapSizeMB();
size_t physical_mb = base::SysInfo::AmountOfPhysicalMemoryMB();
size_t physical_memory_mb = 0;
if (base::SysInfo::IsLowEndDevice()) {
// TODO(crbug.com/742534): The code below appears to no longer work.
// |dalvik_mb| no longer follows the expected heuristic pattern, causing us
// to over-estimate memory on low-end devices. This entire section probably
// needs to be re-written, but for now we can address the low-end Android
// issues by ignoring |dalvik_mb|.
physical_memory_mb = physical_mb;
} else if (dalvik_mb >= 256) {
physical_memory_mb = dalvik_mb * 4;
if (base::FeatureList::IsEnabled(kSimpleCompositorMemoryLimits)) {
if (base::SysInfo::IsLowEndDevice() ||
base::SysInfo::AmountOfPhysicalMemoryMB() < 2000) {
actual.bytes_limit_when_visible = 96 * 1024 * 1024;
} else {
actual.bytes_limit_when_visible = 256 * 1024 * 1024;
}
actual.priority_cutoff_when_visible =
gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
} else {
physical_memory_mb = std::max(dalvik_mb * 4, (physical_mb * 4) / 3);
}

// Now we take a default of 1/8th of memory on high-memory devices,
// and gradually scale that back for low-memory devices (to be nicer
// to other apps so they don't get killed). Examples:
// Nexus 4/10(2GB) 256MB (normally 128MB)
// Droid Razr M(1GB) 114MB (normally 57MB)
// Galaxy Nexus(1GB) 100MB (normally 50MB)
// Xoom(1GB) 100MB (normally 50MB)
// Nexus S(low-end) 8MB (normally 8MB)
// Note that the compositor now uses only some of this memory for
// pre-painting and uses the rest only for 'emergencies'.
if (actual.bytes_limit_when_visible == 0) {
// NOTE: Non-low-end devices use only 50% of these limits,
// except during 'emergencies' where 100% can be used.
if (physical_memory_mb >= 1536) {
actual.bytes_limit_when_visible = physical_memory_mb / 8; // >192MB
} else if (physical_memory_mb >= 1152) {
actual.bytes_limit_when_visible = physical_memory_mb / 8; // >144MB
} else if (physical_memory_mb >= 768) {
actual.bytes_limit_when_visible = physical_memory_mb / 10; // >76MB
} else if (physical_memory_mb >= 513) {
actual.bytes_limit_when_visible = physical_memory_mb / 12; // <64MB
// We can't query available GPU memory from the system on Android.
// Physical memory is also mis-reported sometimes (eg. Nexus 10 reports
// 1262MB when it actually has 2GB, while Razr M has 1GB but only reports
// 128MB java heap size). First we estimate physical memory using both.
size_t dalvik_mb = base::SysInfo::DalvikHeapSizeMB();
size_t physical_mb = base::SysInfo::AmountOfPhysicalMemoryMB();
size_t physical_memory_mb = 0;
if (base::SysInfo::IsLowEndDevice()) {
// TODO(crbug.com/742534): The code below appears to no longer work.
// |dalvik_mb| no longer follows the expected heuristic pattern, causing
// us to over-estimate memory on low-end devices. This entire section
// probably needs to be re-written, but for now we can address the low-end
// Android issues by ignoring |dalvik_mb|.
physical_memory_mb = physical_mb;
} else if (dalvik_mb >= 256) {
physical_memory_mb = dalvik_mb * 4;
} else {
// Devices with this little RAM have very little headroom so we hardcode
// the limit rather than relying on the heuristics above. (They also use
// 4444 textures so we can use a lower limit.)
actual.bytes_limit_when_visible = 8;
physical_memory_mb = std::max(dalvik_mb * 4, (physical_mb * 4) / 3);
}

actual.bytes_limit_when_visible =
actual.bytes_limit_when_visible * 1024 * 1024;
// Clamp the observed value to a specific range on Android.
actual.bytes_limit_when_visible = std::max(
actual.bytes_limit_when_visible, static_cast<size_t>(8 * 1024 * 1024));
actual.bytes_limit_when_visible =
std::min(actual.bytes_limit_when_visible,
static_cast<size_t>(256 * 1024 * 1024));
// Now we take a default of 1/8th of memory on high-memory devices,
// and gradually scale that back for low-memory devices (to be nicer
// to other apps so they don't get killed). Examples:
// Nexus 4/10(2GB) 256MB (normally 128MB)
// Droid Razr M(1GB) 114MB (normally 57MB)
// Galaxy Nexus(1GB) 100MB (normally 50MB)
// Xoom(1GB) 100MB (normally 50MB)
// Nexus S(low-end) 8MB (normally 8MB)
// Note that the compositor now uses only some of this memory for
// pre-painting and uses the rest only for 'emergencies'.
if (actual.bytes_limit_when_visible == 0) {
// NOTE: Non-low-end devices use only 50% of these limits,
// except during 'emergencies' where 100% can be used.
if (physical_memory_mb >= 1536) {
actual.bytes_limit_when_visible = physical_memory_mb / 8; // >192MB
} else if (physical_memory_mb >= 1152) {
actual.bytes_limit_when_visible = physical_memory_mb / 8; // >144MB
} else if (physical_memory_mb >= 768) {
actual.bytes_limit_when_visible = physical_memory_mb / 10; // >76MB
} else if (physical_memory_mb >= 513) {
actual.bytes_limit_when_visible = physical_memory_mb / 12; // <64MB
} else {
// Devices with this little RAM have very little headroom so we hardcode
// the limit rather than relying on the heuristics above. (They also
// use 4444 textures so we can use a lower limit.)
actual.bytes_limit_when_visible = 8;
}

actual.bytes_limit_when_visible =
actual.bytes_limit_when_visible * 1024 * 1024;
// Clamp the observed value to a specific range on Android.
actual.bytes_limit_when_visible =
std::max(actual.bytes_limit_when_visible,
static_cast<size_t>(8 * 1024 * 1024));
actual.bytes_limit_when_visible =
std::min(actual.bytes_limit_when_visible,
static_cast<size_t>(256 * 1024 * 1024));
}
actual.priority_cutoff_when_visible =
gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING;
}
actual.priority_cutoff_when_visible =
gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING;
#else
// Ignore what the system said and give all clients the same maximum
// allocation on desktop platforms.
Expand Down

0 comments on commit e663c95

Please sign in to comment.