Skip to content

Commit

Permalink
Record TotalPrivateMemoryFootprint(VisibleOrHigherPriorityRenderers) …
Browse files Browse the repository at this point in the history
…for UserLevelMemoryPressureSignal feature.

Add the following 4 metrics:
- Memory.Experimental.UserLevelMemoryPressureSignal.TotalPrivateMemoryFootprintBefore,
- Memory.Experimental.UserLevelMemoryPressureSignal.TotalPrivateMemoryFootprintAfter,
- Memory.Experimental.UserLevelMemoryPressureSignal.TotalPrivateMemoryFootprintVisibleOrHigherPriorityRenderersBefore, and
- Memory.Experimental.UserLevelMemoryPressureSignal.TotalPrivateMemoryFootprintVisibleOrHigherPriorityRenderersAfter.

Bug: 1393283
Change-Id: Ic60709da4a11db79b5c0b42e39fd54137b841e52
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4085201
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Reviewed-by: Benoit Lize <lizeb@chromium.org>
Reviewed-by: Bartek Nowierski <bartekn@chromium.org>
Commit-Queue: Takashi Sakamoto <tasak@google.com>
Cr-Commit-Position: refs/heads/main@{#1107638}
  • Loading branch information
tasak authored and Chromium LUCI CQ committed Feb 21, 2023
1 parent edc91b6 commit 55ccdf3
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include <fcntl.h>
#include <inttypes.h>
#include <unistd.h>
#include <utility>
#include "base/android/child_process_binding_types.h"
#include "base/feature_list.h"
#include "base/files/file.h"
Expand All @@ -18,6 +17,8 @@
#include "base/functional/bind.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/process/process.h"
#include "base/strings/string_number_conversions.h"
Expand All @@ -32,6 +33,10 @@

namespace memory_pressure {

namespace {
constexpr uint64_t k1MB = 1024ull * 1024;
}

#if !defined(ARCH_CPU_64_BITS)

namespace features {
Expand Down Expand Up @@ -79,7 +84,6 @@ base::TimeDelta MinimumIntervalFor6GbDevices() {
return kMinimumInterval.Get();
}

constexpr uint64_t k1MB = 1024ull * 1024;
constexpr size_t kDefaultMemoryThresholdMB = 485;

uint64_t MemoryThresholdParamFor4GbDevices() {
Expand Down Expand Up @@ -159,12 +163,15 @@ void UserLevelMemoryPressureSignalGenerator::Start(
}
void UserLevelMemoryPressureSignalGenerator::OnTimerFired() {
base::TimeDelta interval = measure_interval_;
uint64_t total_private_footprint_bytes =
std::pair<uint64_t, uint64_t> total_pmfs =
GetTotalPrivateFootprintVisibleOrHigherPriorityRenderers();

if (total_private_footprint_bytes > memory_threshold_) {
if (total_pmfs.first > memory_threshold_) {
NotifyMemoryPressure();
interval = minimum_interval_;

ReportBeforeAfterMetrics(total_pmfs.first, total_pmfs.second, "Before");
StartReportingTimer();
}

StartPeriodicTimer(interval);
Expand All @@ -183,19 +190,40 @@ void UserLevelMemoryPressureSignalGenerator::StartPeriodicTimer(
base::Unretained(this)));
}

void UserLevelMemoryPressureSignalGenerator::StartReportingTimer() {
// Don't try to start the timer in tests that don't support it.
if (!base::SequencedTaskRunner::HasCurrentDefault()) {
return;
}
delayed_report_timer_.Start(
FROM_HERE, base::Seconds(10),
base::BindOnce(
&UserLevelMemoryPressureSignalGenerator::OnReportingTimerFired,
base::Unretained(this)));
}

void UserLevelMemoryPressureSignalGenerator::OnReportingTimerFired() {
std::pair<uint64_t, uint64_t> total_pmfs =
GetTotalPrivateFootprintVisibleOrHigherPriorityRenderers();
ReportBeforeAfterMetrics(total_pmfs.first, total_pmfs.second, "After");
}

// static
uint64_t UserLevelMemoryPressureSignalGenerator::
std::pair<uint64_t, uint64_t> UserLevelMemoryPressureSignalGenerator::
GetTotalPrivateFootprintVisibleOrHigherPriorityRenderers() {
uint64_t total_private_footprint_bytes = 0u;
uint64_t total_pmf_visible_or_higher_priority_renderers_bytes = 0u;

auto add_process_private_footprint = [&](const base::Process& process) {
auto add_process_private_footprint = [&](uint64_t& pmf,
const base::Process& process) {
if (process.IsValid()) {
total_private_footprint_bytes += GetPrivateFootprint(process).value_or(0);
pmf += GetPrivateFootprint(process).value_or(0);
}
};

// Measure private memory footprint of browser process
add_process_private_footprint(base::Process::Current());
add_process_private_footprint(
total_pmf_visible_or_higher_priority_renderers_bytes,
base::Process::Current());

// Measure private memory footprints of GPU process and Utility processes.
// Since GPU process uses the same user id as the browser process (android),
Expand All @@ -206,13 +234,16 @@ uint64_t UserLevelMemoryPressureSignalGenerator::
// TODO(crbug.com/1393283): measure the private memory footprints of
// the utility processes correctly.
for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
add_process_private_footprint(iter.GetData().GetProcess());
add_process_private_footprint(
total_pmf_visible_or_higher_priority_renderers_bytes,
iter.GetData().GetProcess());
}

// Measure private memory footprints of renderer processes with visible
// or higher priority. Since the renderer processes with invisible or lower
// priority will be cleaned up by Android OS, this pressure signal feature
// doesn't need to take care of them.
uint64_t lower_priority_renderers_pmf_bytes = 0u;
for (content::RenderProcessHost::iterator iter =
content::RenderProcessHost::AllHostsIterator();
!iter.IsAtEnd(); iter.Advance()) {
Expand All @@ -227,6 +258,8 @@ uint64_t UserLevelMemoryPressureSignalGenerator::
// Ignore renderer processes with invisible or lower priority.
if (host->GetEffectiveChildBindingState() <
base::android::ChildBindingState::VISIBLE) {
lower_priority_renderers_pmf_bytes +=
GetPrivateFootprint(process).value_or(0);
continue;
}

Expand All @@ -235,11 +268,14 @@ uint64_t UserLevelMemoryPressureSignalGenerator::
// status, i.e. no such file or directory. So each renderer process
// provides its private memory footprint for the browser process and
// the browser process gets the (cached) value via RenderProcessHostImpl.
total_private_footprint_bytes +=
total_pmf_visible_or_higher_priority_renderers_bytes +=
static_cast<content::RenderProcessHostImpl*>(host)
->GetPrivateMemoryFootprint();
}
return total_private_footprint_bytes;

return std::make_pair(total_pmf_visible_or_higher_priority_renderers_bytes,
total_pmf_visible_or_higher_priority_renderers_bytes +
lower_priority_renderers_pmf_bytes);
}

// static
Expand Down Expand Up @@ -278,6 +314,27 @@ void UserLevelMemoryPressureSignalGenerator::NotifyMemoryPressure() {
MEMORY_PRESSURE_LEVEL_CRITICAL);
}

// static
void UserLevelMemoryPressureSignalGenerator::ReportBeforeAfterMetrics(
uint64_t total_pmf_visible_or_higher_priority_renderers,
uint64_t total_pmf,
const char* suffix_name) {
std::string metric_name_total_pmf_visible_or_higher_priority_renderers =
base::StringPrintf(
"Memory.Experimental.UserLevelMemoryPressureSignal."
"TotalPrivateMemoryFootprintVisibleOrHigherPriorityRenderers%s",
suffix_name);
base::UmaHistogramMemoryLargeMB(
metric_name_total_pmf_visible_or_higher_priority_renderers,
total_pmf_visible_or_higher_priority_renderers / k1MB);

std::string metric_name_total_pmf = base::StringPrintf(
"Memory.Experimental.UserLevelMemoryPressureSignal."
"TotalPrivateMemoryFootprint%s",
suffix_name);
base::UmaHistogramMemoryLargeMB(metric_name_total_pmf, total_pmf / k1MB);
}

namespace {

// TODO(crbug.com/1393283): if this feature is approved, refactor the duplicate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "build/build_config.h"

#if BUILDFLAG(IS_ANDROID)
#include <utility>
#include "base/no_destructor.h"
#include "base/timer/timer.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
Expand Down Expand Up @@ -38,11 +39,20 @@ class UserLevelMemoryPressureSignalGenerator {
base::TimeDelta measure_interval,
base::TimeDelta minimum_interval);
void OnTimerFired();
void OnReportingTimerFired();

void StartPeriodicTimer(base::TimeDelta interval);
void StartReportingTimer();

static std::pair<uint64_t, uint64_t>
GetTotalPrivateFootprintVisibleOrHigherPriorityRenderers();

static void NotifyMemoryPressure();
static uint64_t GetTotalPrivateFootprintVisibleOrHigherPriorityRenderers();

static void ReportBeforeAfterMetrics(
uint64_t total_pmf_visible_or_higher_priority_renderers,
uint64_t total_pmf,
const char* suffix_name);

static absl::optional<uint64_t> GetPrivateFootprint(
const base::Process& process);
Expand All @@ -51,6 +61,7 @@ class UserLevelMemoryPressureSignalGenerator {
base::TimeDelta measure_interval_;
base::TimeDelta minimum_interval_;
base::OneShotTimer periodic_measuring_timer_;
base::OneShotTimer delayed_report_timer_;
};

} // namespace memory_pressure
Expand Down
60 changes: 60 additions & 0 deletions tools/metrics/histograms/metadata/memory/histograms.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,66 @@ chromium-metrics-reviews@google.com.
</summary>
</histogram>

<histogram
name="Memory.Experimental.UserLevelMemoryPressureSignal.TotalPrivateMemoryFootprintAfter"
units="MB" expires_after="2023-08-01">
<owner>tasak@google.com</owner>
<owner>chrome-memory-tok@google.com</owner>
<summary>
The total private memory footprint 10 seconds after a user-level memory
pressure signal is generated. Recorded on Android.
</summary>
</histogram>

<histogram
name="Memory.Experimental.UserLevelMemoryPressureSignal.TotalPrivateMemoryFootprintBefore"
units="MB" expires_after="2023-08-01">
<owner>tasak@google.com</owner>
<owner>chrome-memory-tok@google.com</owner>
<summary>
The total private memory footprint right before a user-level memory pressure
signal is generated. Recorded on Android.

This memory footprint metric cannot be compared across platforms because
each platform relies on platform-level APIs for accounting. As such, though
this attempts to measure private memory footprint as best as possible, it
does not measure the same thing on each platform. We have not found a good
way to compare any system level memory metric across platforms due to the
different nature of memory management on each platform.
</summary>
</histogram>

<histogram
name="Memory.Experimental.UserLevelMemoryPressureSignal.TotalPrivateMemoryFootprintVisibleOrHigherPriorityRenderersAfter"
units="MB" expires_after="2023-08-01">
<owner>tasak@google.com</owner>
<owner>chrome-memory-tok@google.com</owner>
<summary>
The total private memory footprint excluding lower priority renderers' 10
seconds after a user-level memory pressure signal is generated. Recorded on
Android.
</summary>
</histogram>

<histogram
name="Memory.Experimental.UserLevelMemoryPressureSignal.TotalPrivateMemoryFootprintVisibleOrHigherPriorityRenderersBefore"
units="MB" expires_after="2023-08-01">
<owner>tasak@google.com</owner>
<owner>chrome-memory-tok@google.com</owner>
<summary>
The total private memory footprint excluding lower priority renderers' right
before a user-level memory pressure signal is generated. Recorded on
Android.

This memory footprint metric cannot be compared across platforms because
each platform relies on platform-level APIs for accounting. As such, though
this attempts to measure private memory footprint as best as possible, it
does not measure the same thing on each platform. We have not found a good
way to compare any system level memory metric across platforms due to the
different nature of memory management on each platform.
</summary>
</histogram>

<histogram base="true" name="Memory.Experimental.Utility2" units="MB"
expires_after="2024-01-10">
<!-- Name completed by histogram_suffixes name="ProcessMemoryAllocator2" -->
Expand Down

0 comments on commit 55ccdf3

Please sign in to comment.