Commit af79a3bb authored by Thiabaud Engelbrecht's avatar Thiabaud Engelbrecht Committed by Commit Bot

[discardable] Fix setting task runner for Periodic Purge.

The task runner used to run the periodic periodic was not set properly,
causing DCHECKs to fail. This CL fixes this issue.

Periodic Purging continues to be disabled by default, so this CL causes
no change in functionality.

Bug: 1131857
Change-Id: If3bd626e9f5ac3c52b7d9e181605882c134d115e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2519032
Commit-Queue: Thiabaud Engelbrecht <thiabaud@google.com>
Reviewed-by: default avatarPeng Huang <penghuang@chromium.org>
Reviewed-by: default avatarBenoit L <lizeb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#825203}
parent f3c5839b
...@@ -223,6 +223,11 @@ ClientDiscardableSharedMemoryManager::~ClientDiscardableSharedMemoryManager() { ...@@ -223,6 +223,11 @@ ClientDiscardableSharedMemoryManager::~ClientDiscardableSharedMemoryManager() {
// which needs |manager_mojo_|. // which needs |manager_mojo_|.
heap_.reset(); heap_.reset();
if (base::FeatureList::IsEnabled(kSchedulePeriodicPurge) &&
periodic_purge_task_runner_) {
DCHECK(periodic_purge_task_runner_->RunsTasksInCurrentSequence());
}
// Delete the |manager_mojo_| on IO thread, so any pending tasks on IO thread // Delete the |manager_mojo_| on IO thread, so any pending tasks on IO thread
// will be executed before the |manager_mojo_| is deleted. // will be executed before the |manager_mojo_| is deleted.
bool posted = io_task_runner_->DeleteSoon(FROM_HERE, manager_mojo_.release()); bool posted = io_task_runner_->DeleteSoon(FROM_HERE, manager_mojo_.release());
...@@ -243,8 +248,19 @@ ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory( ...@@ -243,8 +248,19 @@ ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(
size_t size) { size_t size) {
base::AutoLock lock(lock_); base::AutoLock lock(lock_);
if (timer_ == nullptr && periodic_purge_task_runner_) if (base::FeatureList::IsEnabled(kSchedulePeriodicPurge)) {
StartScheduledPurging(periodic_purge_task_runner_); if (timer_ == nullptr && periodic_purge_task_runner_) {
// A Timer can only be started from its sequence, but this does not
// necessarily execute on the right thread. Post a task to make sure
// we're starting the timer correctly.
timer_ = std::make_unique<base::RepeatingTimer>();
periodic_purge_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&ClientDiscardableSharedMemoryManager::StartScheduledPurging,
weak_factory_.GetWeakPtr()));
}
}
DCHECK_NE(size, 0u); DCHECK_NE(size, 0u);
...@@ -375,24 +391,23 @@ ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory( ...@@ -375,24 +391,23 @@ ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(
return std::move(discardable_memory); return std::move(discardable_memory);
} }
void ClientDiscardableSharedMemoryManager::StartScheduledPurging( void ClientDiscardableSharedMemoryManager::StartScheduledPurging() {
scoped_refptr<base::SequencedTaskRunner> task_runner) { // The expected cost of purging should be very small (< 1ms), so it can be
DCHECK(task_runner); // scheduled frequently. However, we don't purge memory that has been
if (base::FeatureList::IsEnabled(kSchedulePeriodicPurge)) { // touched recently (see: |BackgroundPurge| and |kMinAgeForScheduledPurge|),
// The expected cost of purging should be very small (< 1ms), so it can be // so there is no benefit to running this more than once per minute.
// scheduled frequently. However, we don't purge memory that has been constexpr base::TimeDelta kInterval = base::TimeDelta::FromMinutes(1);
// touched recently (see: |BackgroundPurge| and |kMinAgeForScheduledPurge|),
// so there is no benefit to running this more than once per minute. base::AutoLock lock(lock_);
constexpr base::TimeDelta kInterval = base::TimeDelta::FromMinutes(1); timer_->Start(
FROM_HERE, kInterval,
timer_ = std::make_unique<base::RepeatingTimer>(); base::BindRepeating(&ClientDiscardableSharedMemoryManager::ScheduledPurge,
timer_->SetTaskRunner(task_runner); weak_factory_.GetWeakPtr()));
}
timer_->Start(FROM_HERE, kInterval,
base::BindRepeating( void ClientDiscardableSharedMemoryManager::StopScheduledPurging() {
&ClientDiscardableSharedMemoryManager::ScheduledPurge, base::AutoLock lock(lock_);
base::Unretained(this))); timer_ = nullptr;
}
} }
bool ClientDiscardableSharedMemoryManager::OnMemoryDump( bool ClientDiscardableSharedMemoryManager::OnMemoryDump(
...@@ -470,8 +485,15 @@ void ClientDiscardableSharedMemoryManager::ReleaseFreeMemory() { ...@@ -470,8 +485,15 @@ void ClientDiscardableSharedMemoryManager::ReleaseFreeMemory() {
ReleaseFreeMemoryImpl(); ReleaseFreeMemoryImpl();
} }
if (GetBytesAllocated() == 0) if (base::FeatureList::IsEnabled(kSchedulePeriodicPurge)) {
timer_ = nullptr; if (GetBytesAllocated() == 0 && periodic_purge_task_runner_) {
periodic_purge_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&ClientDiscardableSharedMemoryManager::StopScheduledPurging,
weak_factory_.GetWeakPtr()));
}
}
} }
void ClientDiscardableSharedMemoryManager::ReleaseFreeMemoryImpl() { void ClientDiscardableSharedMemoryManager::ReleaseFreeMemoryImpl() {
......
...@@ -76,8 +76,8 @@ class DISCARDABLE_MEMORY_EXPORT ClientDiscardableSharedMemoryManager ...@@ -76,8 +76,8 @@ class DISCARDABLE_MEMORY_EXPORT ClientDiscardableSharedMemoryManager
const char* name, const char* name,
base::trace_event::ProcessMemoryDump* pmd) const; base::trace_event::ProcessMemoryDump* pmd) const;
void StartScheduledPurging( void StartScheduledPurging();
scoped_refptr<base::SequencedTaskRunner> task_runner); void StopScheduledPurging();
struct Statistics { struct Statistics {
size_t total_size; size_t total_size;
...@@ -101,7 +101,7 @@ class DISCARDABLE_MEMORY_EXPORT ClientDiscardableSharedMemoryManager ...@@ -101,7 +101,7 @@ class DISCARDABLE_MEMORY_EXPORT ClientDiscardableSharedMemoryManager
scoped_refptr<base::SingleThreadTaskRunner> periodic_purge_task_runner); scoped_refptr<base::SingleThreadTaskRunner> periodic_purge_task_runner);
std::unique_ptr<DiscardableSharedMemoryHeap> heap_ GUARDED_BY(lock_); std::unique_ptr<DiscardableSharedMemoryHeap> heap_ GUARDED_BY(lock_);
mutable base::Lock lock_; mutable base::Lock lock_;
std::unique_ptr<base::RepeatingTimer> timer_; std::unique_ptr<base::RepeatingTimer> timer_ GUARDED_BY(lock_);
scoped_refptr<base::SingleThreadTaskRunner> periodic_purge_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> periodic_purge_task_runner_;
private: private:
...@@ -187,6 +187,9 @@ class DISCARDABLE_MEMORY_EXPORT ClientDiscardableSharedMemoryManager ...@@ -187,6 +187,9 @@ class DISCARDABLE_MEMORY_EXPORT ClientDiscardableSharedMemoryManager
// RenderThreadImpl. // RenderThreadImpl.
bool foregrounded_ = false; bool foregrounded_ = false;
base::WeakPtrFactory<ClientDiscardableSharedMemoryManager> weak_factory_{
this};
DISALLOW_COPY_AND_ASSIGN(ClientDiscardableSharedMemoryManager); DISALLOW_COPY_AND_ASSIGN(ClientDiscardableSharedMemoryManager);
}; };
......
...@@ -69,7 +69,10 @@ class TestClientDiscardableSharedMemoryManager ...@@ -69,7 +69,10 @@ class TestClientDiscardableSharedMemoryManager
return heap_->GetSizeOfFreeLists(); return heap_->GetSizeOfFreeLists();
} }
base::RepeatingTimer* timer() const { return timer_.get(); } bool TimerIsNull() const {
base::AutoLock lock(lock_);
return timer_ == nullptr;
}
}; };
class ClientDiscardableSharedMemoryManagerTest : public testing::Test { class ClientDiscardableSharedMemoryManagerTest : public testing::Test {
...@@ -395,27 +398,31 @@ TEST_F(ClientDiscardableSharedMemoryManagerPeriodicPurgingTest, ...@@ -395,27 +398,31 @@ TEST_F(ClientDiscardableSharedMemoryManagerPeriodicPurgingTest,
SchedulingProactivePurging) { SchedulingProactivePurging) {
base::test::ScopedFeatureList fl; base::test::ScopedFeatureList fl;
fl.InitAndEnableFeature(discardable_memory::kSchedulePeriodicPurge); fl.InitAndEnableFeature(discardable_memory::kSchedulePeriodicPurge);
ASSERT_EQ(client_->timer(), nullptr); ASSERT_TRUE(client_->TimerIsNull());
// the amount of memory allocated here is arbitrary, we're only trying to get // the amount of memory allocated here is arbitrary, we're only trying to get
// the timer started. // the timer started.
auto mem = client_->AllocateLockedDiscardableMemory(200); auto mem = client_->AllocateLockedDiscardableMemory(200);
EXPECT_NE(client_->timer(), nullptr); task_env_.FastForwardBy(TimeDelta::FromSeconds(0));
EXPECT_FALSE(client_->TimerIsNull());
// This does not destroy the timer because there is still memory allocated. // This does not destroy the timer because there is still memory allocated.
client_->ReleaseFreeMemory(); client_->ReleaseFreeMemory();
EXPECT_NE(client_->timer(), nullptr); task_env_.FastForwardBy(TimeDelta::FromSeconds(0));
EXPECT_FALSE(client_->TimerIsNull());
mem = nullptr; mem = nullptr;
EXPECT_NE(client_->timer(), nullptr); task_env_.FastForwardBy(TimeDelta::FromSeconds(0));
EXPECT_FALSE(client_->TimerIsNull());
// Now that all memory is freed, destroy the timer. // Now that all memory is freed, destroy the timer.
client_->ReleaseFreeMemory(); client_->ReleaseFreeMemory();
EXPECT_EQ(client_->timer(), nullptr); task_env_.FastForwardBy(TimeDelta::FromSeconds(0));
EXPECT_TRUE(client_->TimerIsNull());
} }
// This test is similar to the one above, but tests that creating and deleting // This test is similar to the one above, but tests that creating and deleting
...@@ -424,34 +431,40 @@ TEST_F(ClientDiscardableSharedMemoryManagerPeriodicPurgingTest, ...@@ -424,34 +431,40 @@ TEST_F(ClientDiscardableSharedMemoryManagerPeriodicPurgingTest,
SchedulingProactivePurgingMultipleAllocations) { SchedulingProactivePurgingMultipleAllocations) {
base::test::ScopedFeatureList fl; base::test::ScopedFeatureList fl;
fl.InitAndEnableFeature(discardable_memory::kSchedulePeriodicPurge); fl.InitAndEnableFeature(discardable_memory::kSchedulePeriodicPurge);
ASSERT_EQ(client_->timer(), nullptr); ASSERT_TRUE(client_->TimerIsNull());
// the amount of memory allocated here is arbitrary, we're only trying to get // the amount of memory allocated here is arbitrary, we're only trying to get
// the timer started. // the timer started.
auto mem = client_->AllocateLockedDiscardableMemory(200); auto mem = client_->AllocateLockedDiscardableMemory(200);
auto mem2 = client_->AllocateLockedDiscardableMemory(100); auto mem2 = client_->AllocateLockedDiscardableMemory(100);
EXPECT_NE(client_->timer(), nullptr); task_env_.FastForwardBy(TimeDelta::FromSeconds(0));
EXPECT_FALSE(client_->TimerIsNull());
client_->ReleaseFreeMemory(); client_->ReleaseFreeMemory();
EXPECT_NE(client_->timer(), nullptr); task_env_.FastForwardBy(TimeDelta::FromSeconds(0));
EXPECT_FALSE(client_->TimerIsNull());
mem = nullptr; mem = nullptr;
EXPECT_NE(client_->timer(), nullptr); task_env_.FastForwardBy(TimeDelta::FromSeconds(0));
EXPECT_FALSE(client_->TimerIsNull());
client_->ReleaseFreeMemory(); client_->ReleaseFreeMemory();
EXPECT_NE(client_->timer(), nullptr); task_env_.FastForwardBy(TimeDelta::FromSeconds(0));
EXPECT_FALSE(client_->TimerIsNull());
mem2 = nullptr; mem2 = nullptr;
EXPECT_NE(client_->timer(), nullptr); task_env_.FastForwardBy(TimeDelta::FromSeconds(0));
EXPECT_FALSE(client_->TimerIsNull());
client_->ReleaseFreeMemory(); client_->ReleaseFreeMemory();
EXPECT_EQ(client_->timer(), nullptr); task_env_.FastForwardBy(TimeDelta::FromSeconds(0));
EXPECT_TRUE(client_->TimerIsNull());
} }
} // namespace } // namespace
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment