0

bfcache: Introduce detailed memory pressure handling to BFCachePolicy

BFCachePolicy is introduced to purge bfcached page based on memory
pressure. But the current implementation was too harsh to enable
BFCachePolicy by default.

This CL introduces the following 4 feature params to evict bfcached
pages depending on the pressure level and tab status
(foregrounded/backgrounded).

 - foreground_cache_size_on_moderate_pressure
 - background_cache_size_on_moderate_pressure
 - foreground_cache_size_on_critical_pressure
 - background_cache_size_on_critical_pressure

When the cache size is set to be negative, which means that there is
no cache limit for such a situation. For example, if
foreground_cache_size_on_moderate_pressure is -1, BFCachePolicy
doesn’t evict bfcached pages for the foregrounded tabs when moderate
memory pressure is triggered.

BFCache also has the following feature params. These params are still
available as a hard limit of the cache size.

 - cache_size
 - foreground_cache_size

Bug: 1291435
Change-Id: I30bd5e9b4f080cab431b6f0fd4931c385c3b55fd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3420805
Reviewed-by: Francois Pierre Doray <fdoray@chromium.org>
Reviewed-by: Rakina Zata Amni <rakina@chromium.org>
Reviewed-by: Alexander Timin <altimin@chromium.org>
Commit-Queue: Minoru Chikamune <chikamune@chromium.org>
Cr-Commit-Position: refs/heads/main@{#969749}
This commit is contained in:
Minoru Chikamune
2022-02-11 00:43:09 +00:00
committed by Chromium LUCI CQ
parent 996f457ea2
commit 53530571d3
7 changed files with 215 additions and 120 deletions
chrome/browser/performance_manager/policies
components/performance_manager/graph/policies
content

@ -36,23 +36,67 @@ namespace performance_manager::policies {
namespace { namespace {
struct PolicyTestParams { using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
const std::string scenario;
bool enable_policy = false; struct PolicyTestParam {
bool flush_on_moderate_pressure = false; const MemoryPressureLevel memory_pressure_level =
MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE;
bool tab_backgrounded = false;
bool enable_policy = true;
int foreground_cache_size_on_moderate_pressure = 3;
int background_cache_size_on_moderate_pressure = 2;
int foreground_cache_size_on_critical_pressure = 1;
int background_cache_size_on_critical_pressure = 0;
int expected_cached_pages = 4;
}; };
const PolicyTestParam kPolicyTestParams[] = {
// When BFCachePolicy is disabled, the bfcached pages are kept as it is.
{.enable_policy = false},
// Tab foregrounded, moderate memory pressure.
{.expected_cached_pages = 3},
// Tab backgrounded, moderate memory pressure.
{.tab_backgrounded = true, .expected_cached_pages = 2},
// Tab foregrounded, critical memory pressure.
{.memory_pressure_level =
MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL,
.expected_cached_pages = 1},
// Tab backgrounded, critical memory pressure.
{.memory_pressure_level =
MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL,
.tab_backgrounded = true,
.expected_cached_pages = 0},
// Tab foregrounded, moderate memory pressure, cache limit is -1 (no limit).
{.foreground_cache_size_on_moderate_pressure = -1},
// Tab backgrounded, moderate memory pressure, cache limit is -1 (no limit).
{.tab_backgrounded = true,
.background_cache_size_on_moderate_pressure = -1},
// Tab foregrounded, critical memory pressure, cache limit is -1 (no limit).
{.memory_pressure_level =
MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL,
.foreground_cache_size_on_critical_pressure = -1},
// Tab backgrounded, critical memory pressure, cache limit is -1 (no limit).
{.memory_pressure_level =
MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL,
.tab_backgrounded = true,
.background_cache_size_on_critical_pressure = -1}};
class BFCachePolicyBrowserTest class BFCachePolicyBrowserTest
: public InProcessBrowserTest, : public InProcessBrowserTest,
public ::testing::WithParamInterface<PolicyTestParams> { public ::testing::WithParamInterface<PolicyTestParam> {
public: public:
~BFCachePolicyBrowserTest() override = default; ~BFCachePolicyBrowserTest() override = default;
void SetUpCommandLine(base::CommandLine* command_line) override { void SetUpCommandLine(base::CommandLine* command_line) override {
EnableFeature(::features::kBackForwardCache, EnableFeature(::features::kBackForwardCache,
{{"TimeToLiveInBackForwardCacheInSeconds", "3600"}, {{"foreground_cache_size", "10"},
{"cache_size", "10"},
{"TimeToLiveInBackForwardCacheInSeconds", "3600"},
{"ignore_outstanding_network_request_for_testing", "true"}}); {"ignore_outstanding_network_request_for_testing", "true"}});
DisableFeature(::features::kBackForwardCacheMemoryControls); DisableFeature(::features::kBackForwardCacheMemoryControls);
// Disable discarding of pages directly from PerformanceManager for test.
DisableFeature(::performance_manager::features::
kUrgentDiscardingFromPerformanceManager);
// Occlusion can cause the web_contents to be marked visible between the // Occlusion can cause the web_contents to be marked visible between the
// time the test calls WasHidden and BFCachePolicy::MaybeFlushBFCache is // time the test calls WasHidden and BFCachePolicy::MaybeFlushBFCache is
// called, which kills the timer set by BFCachePolicy::OnIsVisibleChanged. // called, which kills the timer set by BFCachePolicy::OnIsVisibleChanged.
@ -62,8 +106,18 @@ class BFCachePolicyBrowserTest
if (GetParam().enable_policy) { if (GetParam().enable_policy) {
EnableFeature( EnableFeature(
performance_manager::features::kBFCachePerformanceManagerPolicy, performance_manager::features::kBFCachePerformanceManagerPolicy,
{{"flush_on_moderate_pressure", {{"foreground_cache_size_on_moderate_pressure",
GetParam().flush_on_moderate_pressure ? "true" : "false"}}); base::NumberToString(
GetParam().foreground_cache_size_on_moderate_pressure)},
{"background_cache_size_on_moderate_pressure",
base::NumberToString(
GetParam().background_cache_size_on_moderate_pressure)},
{"foreground_cache_size_on_critical_pressure",
base::NumberToString(
GetParam().foreground_cache_size_on_critical_pressure)},
{"background_cache_size_on_critical_pressure",
base::NumberToString(
GetParam().background_cache_size_on_critical_pressure)}});
} else { } else {
DisableFeature( DisableFeature(
performance_manager::features::kBFCachePerformanceManagerPolicy); performance_manager::features::kBFCachePerformanceManagerPolicy);
@ -97,23 +151,23 @@ class BFCachePolicyBrowserTest
return web_contents()->GetMainFrame(); return web_contents()->GetMainFrame();
} }
void VerifyEvictionExpectation(bool should_be_evicted, void VerifyEvictionExpectation(
content::RenderFrameHostWrapper& rfh) { std::vector<content::RenderFrameHostWrapper>& render_frame_hosts) {
if (should_be_evicted) { // Wait for memory pressure signal processed and handled by BFCachePolicy.
// When the page is evicted the RenderFrame will be deleted. content::RunAllTasksUntilIdle();
ASSERT_TRUE(rfh.WaitUntilRenderFrameDeleted());
} else { size_t expected_deleted_pages =
// BFCachePolicy runs asynchronously. So we need to wait for the result render_frame_hosts.size() - GetParam().expected_cached_pages;
// before checking.
base::RunLoop run_loop; for (size_t i = 0; i < render_frame_hosts.size(); i++) {
base::SequencedTaskRunnerHandle::Get()->PostTask( content::RenderFrameHostWrapper& rfh = render_frame_hosts[i];
FROM_HERE, base::BindLambdaForTesting([&]() { if (i < expected_deleted_pages) {
EXPECT_EQ( ASSERT_TRUE(rfh.IsRenderFrameDeleted());
rfh->GetLifecycleState(), } else {
content::RenderFrameHost::LifecycleState::kInBackForwardCache); EXPECT_EQ(
run_loop.Quit(); rfh->GetLifecycleState(),
})); content::RenderFrameHost::LifecycleState::kInBackForwardCache);
run_loop.Run(); }
} }
} }
@ -128,60 +182,44 @@ class BFCachePolicyBrowserTest
IN_PROC_BROWSER_TEST_P(BFCachePolicyBrowserTest, CacheFlushed) { IN_PROC_BROWSER_TEST_P(BFCachePolicyBrowserTest, CacheFlushed) {
memory_pressure::test::FakeMemoryPressureMonitor fake_memory_pressure_monitor; memory_pressure::test::FakeMemoryPressureMonitor fake_memory_pressure_monitor;
const GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); const std::vector<std::string> hostnames{"a.com", "b.com", "c.com", "d.com"};
const GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); std::vector<content::RenderFrameHostWrapper> render_frame_hosts;
render_frame_hosts.reserve(hostnames.size());
for (std::string hostname : hostnames) {
const GURL url(embedded_test_server()->GetURL(hostname, "/title1.html"));
EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
render_frame_hosts.emplace_back(
content::RenderFrameHostWrapper(top_frame_host()));
}
const GURL url(embedded_test_server()->GetURL("last.com", "/title1.html"));
EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
content::RenderFrameHostWrapper last_rfh =
content::RenderFrameHostWrapper(top_frame_host());
EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE); EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
if (GetParam().tab_backgrounded) {
// Navigate to A. web_contents()->WasHidden();
EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url_a)); EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::HIDDEN);
content::RenderFrameHostWrapper rfh_a(top_frame_host());
// Navigate to B.
EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url_b));
content::RenderFrameHostWrapper rfh_b(top_frame_host());
// Ensure A is cached.
EXPECT_EQ(rfh_a->GetLifecycleState(),
content::RenderFrameHost::LifecycleState::kInBackForwardCache);
if (GetParam().scenario == "FlushOnModerateMemoryPressure") {
// A moderate memory pressure signal will evict the page from BFCache.
fake_memory_pressure_monitor.SetAndNotifyMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel::
MEMORY_PRESSURE_LEVEL_MODERATE);
VerifyEvictionExpectation(
/* should_be_evicted = */
(GetParam().enable_policy && GetParam().flush_on_moderate_pressure),
rfh_a);
} else if (GetParam().scenario == "FlushOnCriticalMemoryPressure") {
// A critical memory pressure signal will evict the page from BFCache.
fake_memory_pressure_monitor.SetAndNotifyMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel::
MEMORY_PRESSURE_LEVEL_CRITICAL);
VerifyEvictionExpectation(
/* should_be_evicted = */ GetParam().enable_policy, rfh_a);
} else {
NOTREACHED();
} }
}
std::vector<PolicyTestParams> BFCachePolicyBrowserTestValues() { // Ensure pages are cached.
std::vector<PolicyTestParams> test_cases; for (const auto& render_frame_host : render_frame_hosts) {
EXPECT_EQ(render_frame_host->GetLifecycleState(),
for (const std::string scenario : content::RenderFrameHost::LifecycleState::kInBackForwardCache);
{"FlushOnModerateMemoryPressure", "FlushOnCriticalMemoryPressure"}) {
test_cases.push_back({.scenario = scenario});
test_cases.push_back({.scenario = scenario, .enable_policy = true});
test_cases.push_back({.scenario = scenario,
.enable_policy = true,
.flush_on_moderate_pressure = true});
} }
return test_cases; // Ensure the last page is not cached.
EXPECT_EQ(last_rfh->GetLifecycleState(),
content::RenderFrameHost::LifecycleState::kActive);
fake_memory_pressure_monitor.SetAndNotifyMemoryPressure(
GetParam().memory_pressure_level);
VerifyEvictionExpectation(render_frame_hosts);
} }
INSTANTIATE_TEST_SUITE_P(All, INSTANTIATE_TEST_SUITE_P(All,
BFCachePolicyBrowserTest, BFCachePolicyBrowserTest,
testing::ValuesIn(BFCachePolicyBrowserTestValues())); testing::ValuesIn(kPolicyTestParams));
} // namespace performance_manager::policies } // namespace performance_manager::policies

@ -6,6 +6,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/memory/memory_pressure_listener.h" #include "base/memory/memory_pressure_listener.h"
#include "base/notreached.h"
#include "base/task/task_traits.h" #include "base/task/task_traits.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
@ -22,15 +23,44 @@ namespace performance_manager::policies {
namespace { namespace {
// Whether or not the BFCache of all pages should be flushed when the system // The foregrounded tab's cache limit on moderate memory pressure. The negative
// is under *moderate* memory pressure. The policy always flushes the bfcache // value means no limit.
// under critical pressure. int ForegroundCacheSizeOnModeratePressure() {
bool IsFlushOnModeratePressureEnabled() { static constexpr base::FeatureParam<int>
static constexpr base::FeatureParam<bool> flush_on_moderate_pressure{ foreground_cache_size_on_moderate_pressure{
&features::kBFCachePerformanceManagerPolicy, "flush_on_moderate_pressure", &features::kBFCachePerformanceManagerPolicy,
false}; "foreground_cache_size_on_moderate_pressure", 3};
return foreground_cache_size_on_moderate_pressure.Get();
}
return flush_on_moderate_pressure.Get(); // The backgrounded tab's cache limit on moderate memory pressure. The negative
// value means no limit.
int BackgroundCacheSizeOnModeratePressure() {
static constexpr base::FeatureParam<int>
background_cache_size_on_moderate_pressure{
&features::kBFCachePerformanceManagerPolicy,
"background_cache_size_on_moderate_pressure", 1};
return background_cache_size_on_moderate_pressure.Get();
}
// The foregrounded tab's cache limit on critical memory pressure. The negative
// value means no limit.
int ForegroundCacheSizeOnCriticalPressure() {
static constexpr base::FeatureParam<int>
foreground_cache_size_on_critical_pressure{
&features::kBFCachePerformanceManagerPolicy,
"foreground_cache_size_on_critical_pressure", 0};
return foreground_cache_size_on_critical_pressure.Get();
}
// The backgrounded tab's cache limit on critical memory pressure. The negative
// value means no limit.
int BackgroundCacheSizeOnCriticalPressure() {
static constexpr base::FeatureParam<int>
background_cache_size_on_critical_pressure{
&features::kBFCachePerformanceManagerPolicy,
"background_cache_size_on_critical_pressure", 0};
return background_cache_size_on_critical_pressure.Get();
} }
bool PageMightHaveFramesInBFCache(const PageNode* page_node) { bool PageMightHaveFramesInBFCache(const PageNode* page_node) {
@ -45,32 +75,52 @@ bool PageMightHaveFramesInBFCache(const PageNode* page_node) {
return false; return false;
} }
void MaybeFlushBFCacheOnUIThread(const WebContentsProxy& contents_proxy) { using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
void MaybeFlushBFCacheOnUIThread(const WebContentsProxy& contents_proxy,
MemoryPressureLevel memory_pressure_level) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::WebContents* const content = contents_proxy.Get(); content::WebContents* const content = contents_proxy.Get();
if (!content) if (!content)
return; return;
int cache_size = -1;
bool foregrounded =
(content->GetVisibility() == content::Visibility::VISIBLE);
switch (memory_pressure_level) {
case MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE:
cache_size = foregrounded ? ForegroundCacheSizeOnModeratePressure()
: BackgroundCacheSizeOnModeratePressure();
break;
case MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL:
cache_size = foregrounded ? ForegroundCacheSizeOnCriticalPressure()
: BackgroundCacheSizeOnCriticalPressure();
break;
default:
NOTREACHED();
}
// Do not flush BFCache if cache_size is negative (such as -1).
if (cache_size < 0)
return;
// Do not flush the BFCache if there's a pending navigation as this could stop // Do not flush the BFCache if there's a pending navigation as this could stop
// it. // it.
// TODO(sebmarchand): Check if this is really needed. // TODO(sebmarchand): Check if this is really needed.
auto& navigation_controller = content->GetController(); auto& navigation_controller = content->GetController();
if (!navigation_controller.GetPendingEntry()) if (!navigation_controller.GetPendingEntry())
navigation_controller.GetBackForwardCache().Flush(); navigation_controller.GetBackForwardCache().Prune(cache_size);
} }
} // namespace } // namespace
BFCachePolicy::BFCachePolicy() void BFCachePolicy::MaybeFlushBFCache(
: flush_on_moderate_pressure_{IsFlushOnModeratePressureEnabled()} {} const PageNode* page_node,
MemoryPressureLevel memory_pressure_level) {
BFCachePolicy::~BFCachePolicy() = default;
void BFCachePolicy::MaybeFlushBFCache(const PageNode* page_node) {
DCHECK(page_node); DCHECK(page_node);
content::GetUIThreadTaskRunner({})->PostTask( content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&MaybeFlushBFCacheOnUIThread, FROM_HERE,
page_node->GetContentsProxy())); base::BindOnce(&MaybeFlushBFCacheOnUIThread,
page_node->GetContentsProxy(), memory_pressure_level));
} }
void BFCachePolicy::OnPassedToGraph(Graph* graph) { void BFCachePolicy::OnPassedToGraph(Graph* graph) {
@ -84,25 +134,17 @@ void BFCachePolicy::OnTakenFromGraph(Graph* graph) {
graph_ = nullptr; graph_ = nullptr;
} }
void BFCachePolicy::OnMemoryPressure( void BFCachePolicy::OnMemoryPressure(MemoryPressureLevel new_level) {
base::MemoryPressureListener::MemoryPressureLevel new_level) {
// This shouldn't happen but add the check anyway in case the API changes. // This shouldn't happen but add the check anyway in case the API changes.
if (new_level == base::MemoryPressureListener::MemoryPressureLevel:: if (new_level == MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_NONE) {
MEMORY_PRESSURE_LEVEL_NONE) {
return; return;
} }
if (new_level == base::MemoryPressureListener::MemoryPressureLevel:: // Apply the cache limit to all pages.
MEMORY_PRESSURE_LEVEL_MODERATE &&
!flush_on_moderate_pressure_) {
return;
}
// Flush the cache of all pages.
for (auto* page_node : graph_->GetAllPageNodes()) { for (auto* page_node : graph_->GetAllPageNodes()) {
if (page_node->GetPageState() == PageNode::PageState::kActive && if (page_node->GetPageState() == PageNode::PageState::kActive &&
PageMightHaveFramesInBFCache(page_node)) { PageMightHaveFramesInBFCache(page_node)) {
MaybeFlushBFCache(page_node); MaybeFlushBFCache(page_node, new_level);
} }
} }
} }

@ -18,19 +18,20 @@ namespace performance_manager::policies {
class BFCachePolicy : public GraphOwned, class BFCachePolicy : public GraphOwned,
public SystemNode::ObserverDefaultImpl { public SystemNode::ObserverDefaultImpl {
public: public:
BFCachePolicy(); BFCachePolicy() = default;
BFCachePolicy(const BFCachePolicy&) = delete; BFCachePolicy(const BFCachePolicy&) = delete;
BFCachePolicy(BFCachePolicy&&) = delete; BFCachePolicy(BFCachePolicy&&) = delete;
BFCachePolicy& operator=(const BFCachePolicy&) = delete; BFCachePolicy& operator=(const BFCachePolicy&) = delete;
BFCachePolicy& operator=(BFCachePolicy&&) = delete; BFCachePolicy& operator=(BFCachePolicy&&) = delete;
~BFCachePolicy() override; ~BFCachePolicy() override = default;
protected: protected:
using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
// Try to flush the BFCache associated with |page_node|. This will be a no-op // Try to flush the BFCache associated with |page_node|. This will be a no-op
// if there's a pending navigation. // if there's a pending navigation.
virtual void MaybeFlushBFCache(const PageNode* page_node); virtual void MaybeFlushBFCache(const PageNode* page_node,
MemoryPressureLevel memory_pressure_level);
bool flush_on_moderate_pressure_;
private: private:
// GraphOwned implementation: // GraphOwned implementation:
@ -38,8 +39,7 @@ class BFCachePolicy : public GraphOwned,
void OnTakenFromGraph(Graph* graph) override; void OnTakenFromGraph(Graph* graph) override;
// SystemNodeObserver: // SystemNodeObserver:
void OnMemoryPressure( void OnMemoryPressure(MemoryPressureLevel new_level) override;
base::MemoryPressureListener::MemoryPressureLevel new_level) override;
raw_ptr<Graph> graph_; raw_ptr<Graph> graph_;
}; };

@ -13,20 +13,22 @@
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace performance_manager { namespace performance_manager::policies {
namespace policies {
namespace { namespace {
// Mock version of a performance_manager::BFCachePolicy. // Mock version of a performance_manager::BFCachePolicy.
class LenientMockBFCachePolicy : public BFCachePolicy { class LenientMockBFCachePolicy : public BFCachePolicy {
public: public:
LenientMockBFCachePolicy() { flush_on_moderate_pressure_ = true; } LenientMockBFCachePolicy() = default;
~LenientMockBFCachePolicy() override = default; ~LenientMockBFCachePolicy() override = default;
LenientMockBFCachePolicy(const LenientMockBFCachePolicy& other) = delete; LenientMockBFCachePolicy(const LenientMockBFCachePolicy& other) = delete;
LenientMockBFCachePolicy& operator=(const LenientMockBFCachePolicy&) = delete; LenientMockBFCachePolicy& operator=(const LenientMockBFCachePolicy&) = delete;
MOCK_METHOD1(MaybeFlushBFCache, void(const PageNode* page_node)); MOCK_METHOD2(MaybeFlushBFCache,
void(const PageNode* page_node,
MemoryPressureLevel memory_pressure_level));
}; };
using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
using MockBFCachePolicy = ::testing::StrictMock<LenientMockBFCachePolicy>; using MockBFCachePolicy = ::testing::StrictMock<LenientMockBFCachePolicy>;
} // namespace } // namespace
@ -74,18 +76,21 @@ TEST_F(BFCachePolicyTest, BFCacheFlushedOnMemoryPressure) {
page_node_->SetLoadingState(PageNode::LoadingState::kLoadedBusy); page_node_->SetLoadingState(PageNode::LoadingState::kLoadedBusy);
::testing::Mock::VerifyAndClearExpectations(policy_); ::testing::Mock::VerifyAndClearExpectations(policy_);
EXPECT_CALL(*policy_, MaybeFlushBFCache(page_node_.get())); EXPECT_CALL(
*policy_,
MaybeFlushBFCache(page_node_.get(),
MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE));
GetSystemNode()->OnMemoryPressureForTesting( GetSystemNode()->OnMemoryPressureForTesting(
base::MemoryPressureListener::MemoryPressureLevel:: MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE);
MEMORY_PRESSURE_LEVEL_MODERATE);
::testing::Mock::VerifyAndClearExpectations(policy_); ::testing::Mock::VerifyAndClearExpectations(policy_);
EXPECT_CALL(*policy_, MaybeFlushBFCache(page_node_.get())); EXPECT_CALL(
*policy_,
MaybeFlushBFCache(page_node_.get(),
MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL));
GetSystemNode()->OnMemoryPressureForTesting( GetSystemNode()->OnMemoryPressureForTesting(
base::MemoryPressureListener::MemoryPressureLevel:: MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL);
MEMORY_PRESSURE_LEVEL_CRITICAL);
::testing::Mock::VerifyAndClearExpectations(policy_); ::testing::Mock::VerifyAndClearExpectations(policy_);
} }
} // namespace policies } // namespace performance_manager::policies
} // namespace performance_manager

@ -1054,6 +1054,11 @@ void BackForwardCacheImpl::EnforceCacheSizeLimit() {
/*foregrounded_only=*/false); /*foregrounded_only=*/false);
} }
void BackForwardCacheImpl::Prune(size_t limit) {
EnforceCacheSizeLimitInternal(limit,
/*foregrounded_only=*/false);
}
size_t BackForwardCacheImpl::EnforceCacheSizeLimitInternal( size_t BackForwardCacheImpl::EnforceCacheSizeLimitInternal(
size_t limit, size_t limit,
bool foregrounded_only) { bool foregrounded_only) {

@ -310,6 +310,7 @@ class CONTENT_EXPORT BackForwardCacheImpl
// BackForwardCache overrides: // BackForwardCache overrides:
void Flush() override; void Flush() override;
void Prune(size_t limit) override;
void DisableForTesting(DisableForTestingReason reason) override; void DisableForTesting(DisableForTestingReason reason) override;
// RenderProcessHostInternalObserver methods // RenderProcessHostInternalObserver methods

@ -143,6 +143,10 @@ class CONTENT_EXPORT BackForwardCache {
// Evict all entries from the BackForwardCache. // Evict all entries from the BackForwardCache.
virtual void Flush() = 0; virtual void Flush() = 0;
// Evict back/forward cache entries from the least recently used ones until
// the cache is within the given size limit.
virtual void Prune(size_t limit) = 0;
// Disables the BackForwardCache so that no documents will be stored/served. // Disables the BackForwardCache so that no documents will be stored/served.
// This allows tests to "force" not using the BackForwardCache, this can be // This allows tests to "force" not using the BackForwardCache, this can be
// useful when: // useful when: