Commit be247ab1 authored by reveman@chromium.org's avatar reveman@chromium.org

base: Fix registering of memory pressure listeners used when emulating discardable memory.

Memory pressure listeners need to be created on a thread with a message
loop current. Discardable memory is often used on worker threads that
don't have a message loop and with the current system where listeners
are registered on first use, the result is that we're most likely never
notified of memory pressure.

This adds a function to the discardable memory interface that allows us
to register memory pressure listeners on a thread, and at a time, when
we know a message loop is current.

BUG=332570
TBR=jamesr@chromium.org

Review URL: https://codereview.chromium.org/129963002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@244229 0039d316-1c4b-4281-b951-d872f2087c98
parent d3ed588c
...@@ -63,6 +63,14 @@ class BASE_EXPORT DiscardableMemory { ...@@ -63,6 +63,14 @@ class BASE_EXPORT DiscardableMemory {
public: public:
virtual ~DiscardableMemory() {} virtual ~DiscardableMemory() {}
// Call this on a thread with a MessageLoop current to allow discardable
// memory implementations to respond to memory pressure signals.
static void RegisterMemoryPressureListeners();
// Call this to prevent discardable memory implementations from responding
// to memory pressure signals.
static void UnregisterMemoryPressureListeners();
// Gets the discardable memory type with a given name. // Gets the discardable memory type with a given name.
static DiscardableMemoryType GetNamedType(const std::string& name); static DiscardableMemoryType GetNamedType(const std::string& name);
......
...@@ -121,6 +121,16 @@ bool UnlockAshmemRegion(int fd, size_t off, size_t size, const void* address) { ...@@ -121,6 +121,16 @@ bool UnlockAshmemRegion(int fd, size_t off, size_t size, const void* address) {
} // namespace internal } // namespace internal
// static
void DiscardableMemory::RegisterMemoryPressureListeners() {
internal::DiscardableMemoryEmulated::RegisterMemoryPressureListeners();
}
// static
void DiscardableMemory::UnregisterMemoryPressureListeners() {
internal::DiscardableMemoryEmulated::UnregisterMemoryPressureListeners();
}
// static // static
void DiscardableMemory::GetSupportedTypes( void DiscardableMemory::GetSupportedTypes(
std::vector<DiscardableMemoryType>* types) { std::vector<DiscardableMemoryType>* types) {
......
...@@ -29,6 +29,21 @@ DiscardableMemoryEmulated::~DiscardableMemoryEmulated() { ...@@ -29,6 +29,21 @@ DiscardableMemoryEmulated::~DiscardableMemoryEmulated() {
g_provider.Pointer()->Unregister(this); g_provider.Pointer()->Unregister(this);
} }
// static
void DiscardableMemoryEmulated::RegisterMemoryPressureListeners() {
g_provider.Pointer()->RegisterMemoryPressureListener();
}
// static
void DiscardableMemoryEmulated::UnregisterMemoryPressureListeners() {
g_provider.Pointer()->UnregisterMemoryPressureListener();
}
// static
void DiscardableMemoryEmulated::PurgeForTesting() {
g_provider.Pointer()->PurgeAll();
}
bool DiscardableMemoryEmulated::Initialize() { bool DiscardableMemoryEmulated::Initialize() {
return Lock() == DISCARDABLE_MEMORY_LOCK_STATUS_PURGED; return Lock() == DISCARDABLE_MEMORY_LOCK_STATUS_PURGED;
} }
...@@ -57,10 +72,5 @@ void* DiscardableMemoryEmulated::Memory() const { ...@@ -57,10 +72,5 @@ void* DiscardableMemoryEmulated::Memory() const {
return memory_.get(); return memory_.get();
} }
// static
void DiscardableMemoryEmulated::PurgeForTesting() {
g_provider.Pointer()->PurgeAll();
}
} // namespace internal } // namespace internal
} // namespace base } // namespace base
...@@ -15,6 +15,9 @@ class DiscardableMemoryEmulated : public DiscardableMemory { ...@@ -15,6 +15,9 @@ class DiscardableMemoryEmulated : public DiscardableMemory {
explicit DiscardableMemoryEmulated(size_t size); explicit DiscardableMemoryEmulated(size_t size);
virtual ~DiscardableMemoryEmulated(); virtual ~DiscardableMemoryEmulated();
static void RegisterMemoryPressureListeners();
static void UnregisterMemoryPressureListeners();
static void PurgeForTesting(); static void PurgeForTesting();
bool Initialize(); bool Initialize();
......
...@@ -9,6 +9,16 @@ ...@@ -9,6 +9,16 @@
namespace base { namespace base {
// static
void DiscardableMemory::RegisterMemoryPressureListeners() {
internal::DiscardableMemoryEmulated::RegisterMemoryPressureListeners();
}
// static
void DiscardableMemory::UnregisterMemoryPressureListeners() {
internal::DiscardableMemoryEmulated::UnregisterMemoryPressureListeners();
}
// static // static
void DiscardableMemory::GetSupportedTypes( void DiscardableMemory::GetSupportedTypes(
std::vector<DiscardableMemoryType>* types) { std::vector<DiscardableMemoryType>* types) {
......
...@@ -88,6 +88,16 @@ class DiscardableMemoryMac : public DiscardableMemory { ...@@ -88,6 +88,16 @@ class DiscardableMemoryMac : public DiscardableMemory {
} // namespace } // namespace
// static
void DiscardableMemory::RegisterMemoryPressureListeners() {
internal::DiscardableMemoryEmulated::RegisterMemoryPressureListeners();
}
// static
void DiscardableMemory::UnregisterMemoryPressureListeners() {
internal::DiscardableMemoryEmulated::UnregisterMemoryPressureListeners();
}
// static // static
void DiscardableMemory::GetSupportedTypes( void DiscardableMemory::GetSupportedTypes(
std::vector<DiscardableMemoryType>* types) { std::vector<DiscardableMemoryType>* types) {
......
...@@ -29,10 +29,7 @@ DiscardableMemoryProvider::DiscardableMemoryProvider() ...@@ -29,10 +29,7 @@ DiscardableMemoryProvider::DiscardableMemoryProvider()
bytes_allocated_(0), bytes_allocated_(0),
discardable_memory_limit_(kDefaultDiscardableMemoryLimit), discardable_memory_limit_(kDefaultDiscardableMemoryLimit),
bytes_to_reclaim_under_moderate_pressure_( bytes_to_reclaim_under_moderate_pressure_(
kDefaultBytesToReclaimUnderModeratePressure), kDefaultBytesToReclaimUnderModeratePressure) {
memory_pressure_listener_(
base::Bind(&DiscardableMemoryProvider::NotifyMemoryPressure,
Unretained(this))) {
} }
DiscardableMemoryProvider::~DiscardableMemoryProvider() { DiscardableMemoryProvider::~DiscardableMemoryProvider() {
...@@ -40,18 +37,20 @@ DiscardableMemoryProvider::~DiscardableMemoryProvider() { ...@@ -40,18 +37,20 @@ DiscardableMemoryProvider::~DiscardableMemoryProvider() {
DCHECK_EQ(0u, bytes_allocated_); DCHECK_EQ(0u, bytes_allocated_);
} }
void DiscardableMemoryProvider::NotifyMemoryPressure( void DiscardableMemoryProvider::RegisterMemoryPressureListener() {
MemoryPressureListener::MemoryPressureLevel pressure_level) { AutoLock lock(lock_);
switch (pressure_level) { DCHECK(base::MessageLoop::current());
case MemoryPressureListener::MEMORY_PRESSURE_MODERATE: DCHECK(!memory_pressure_listener_);
Purge(); memory_pressure_listener_.reset(
return; new MemoryPressureListener(
case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL: base::Bind(&DiscardableMemoryProvider::OnMemoryPressure,
PurgeAll(); Unretained(this))));
return; }
}
NOTREACHED(); void DiscardableMemoryProvider::UnregisterMemoryPressureListener() {
AutoLock lock(lock_);
DCHECK(memory_pressure_listener_);
memory_pressure_listener_.reset();
} }
void DiscardableMemoryProvider::SetDiscardableMemoryLimit(size_t bytes) { void DiscardableMemoryProvider::SetDiscardableMemoryLimit(size_t bytes) {
...@@ -69,6 +68,9 @@ void DiscardableMemoryProvider::SetBytesToReclaimUnderModeratePressure( ...@@ -69,6 +68,9 @@ void DiscardableMemoryProvider::SetBytesToReclaimUnderModeratePressure(
void DiscardableMemoryProvider::Register( void DiscardableMemoryProvider::Register(
const DiscardableMemory* discardable, size_t bytes) { const DiscardableMemory* discardable, size_t bytes) {
AutoLock lock(lock_); AutoLock lock(lock_);
// A registered memory listener is currently required. This DCHECK can be
// moved or removed if we decide that it's useful to relax this condition.
DCHECK(memory_pressure_listener_);
DCHECK(allocations_.Peek(discardable) == allocations_.end()); DCHECK(allocations_.Peek(discardable) == allocations_.end());
allocations_.Put(discardable, Allocation(bytes)); allocations_.Put(discardable, Allocation(bytes));
} }
...@@ -169,6 +171,20 @@ size_t DiscardableMemoryProvider::GetBytesAllocatedForTest() const { ...@@ -169,6 +171,20 @@ size_t DiscardableMemoryProvider::GetBytesAllocatedForTest() const {
return bytes_allocated_; return bytes_allocated_;
} }
void DiscardableMemoryProvider::OnMemoryPressure(
MemoryPressureListener::MemoryPressureLevel pressure_level) {
switch (pressure_level) {
case MemoryPressureListener::MEMORY_PRESSURE_MODERATE:
Purge();
return;
case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL:
PurgeAll();
return;
}
NOTREACHED();
}
void DiscardableMemoryProvider::Purge() { void DiscardableMemoryProvider::Purge() {
AutoLock lock(lock_); AutoLock lock(lock_);
......
...@@ -46,6 +46,13 @@ class BASE_EXPORT_PRIVATE DiscardableMemoryProvider { ...@@ -46,6 +46,13 @@ class BASE_EXPORT_PRIVATE DiscardableMemoryProvider {
DiscardableMemoryProvider(); DiscardableMemoryProvider();
~DiscardableMemoryProvider(); ~DiscardableMemoryProvider();
// Call this to register memory pressure listener. Must be called on a
// thread with a MessageLoop current.
void RegisterMemoryPressureListener();
// Call this to unregister memory pressure listener.
void UnregisterMemoryPressureListener();
// The maximum number of bytes of discardable memory that may be allocated // The maximum number of bytes of discardable memory that may be allocated
// before we force a purge. If this amount is zero, it is interpreted as // before we force a purge. If this amount is zero, it is interpreted as
// having no limit at all. // having no limit at all.
...@@ -99,7 +106,7 @@ class BASE_EXPORT_PRIVATE DiscardableMemoryProvider { ...@@ -99,7 +106,7 @@ class BASE_EXPORT_PRIVATE DiscardableMemoryProvider {
typedef HashingMRUCache<const DiscardableMemory*, Allocation> AllocationMap; typedef HashingMRUCache<const DiscardableMemory*, Allocation> AllocationMap;
// This can be called as a hint that the system is under memory pressure. // This can be called as a hint that the system is under memory pressure.
void NotifyMemoryPressure( void OnMemoryPressure(
MemoryPressureListener::MemoryPressureLevel pressure_level); MemoryPressureListener::MemoryPressureLevel pressure_level);
// Purges |bytes_to_reclaim_under_moderate_pressure_| bytes of // Purges |bytes_to_reclaim_under_moderate_pressure_| bytes of
...@@ -132,7 +139,7 @@ class BASE_EXPORT_PRIVATE DiscardableMemoryProvider { ...@@ -132,7 +139,7 @@ class BASE_EXPORT_PRIVATE DiscardableMemoryProvider {
// Allows us to be respond when the system reports that it is under memory // Allows us to be respond when the system reports that it is under memory
// pressure. // pressure.
MemoryPressureListener memory_pressure_listener_; scoped_ptr<MemoryPressureListener> memory_pressure_listener_;
DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryProvider); DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryProvider);
}; };
......
...@@ -64,6 +64,7 @@ class DiscardableMemoryProviderTestBase { ...@@ -64,6 +64,7 @@ class DiscardableMemoryProviderTestBase {
DiscardableMemoryProviderTestBase() DiscardableMemoryProviderTestBase()
: message_loop_(MessageLoop::TYPE_IO), : message_loop_(MessageLoop::TYPE_IO),
provider_(new internal::DiscardableMemoryProvider) { provider_(new internal::DiscardableMemoryProvider) {
provider_->RegisterMemoryPressureListener();
} }
protected: protected:
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <algorithm> #include <algorithm>
#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
...@@ -17,11 +18,23 @@ namespace { ...@@ -17,11 +18,23 @@ namespace {
class DiscardableMemoryTest class DiscardableMemoryTest
: public testing::TestWithParam<DiscardableMemoryType> { : public testing::TestWithParam<DiscardableMemoryType> {
public:
DiscardableMemoryTest() : message_loop_(MessageLoop::TYPE_IO) {
// Register memory pressure listeners now that we have a message loop.
DiscardableMemory::RegisterMemoryPressureListeners();
}
virtual ~DiscardableMemoryTest() {
DiscardableMemory::UnregisterMemoryPressureListeners();
}
protected: protected:
scoped_ptr<DiscardableMemory> CreateLockedMemory(size_t size) { scoped_ptr<DiscardableMemory> CreateLockedMemory(size_t size) {
return DiscardableMemory::CreateLockedMemoryWithType( return DiscardableMemory::CreateLockedMemoryWithType(
GetParam(), size).Pass(); GetParam(), size).Pass();
} }
private:
MessageLoop message_loop_;
}; };
const size_t kSize = 1024; const size_t kSize = 1024;
......
...@@ -9,6 +9,16 @@ ...@@ -9,6 +9,16 @@
namespace base { namespace base {
// static
void DiscardableMemory::RegisterMemoryPressureListeners() {
internal::DiscardableMemoryEmulated::RegisterMemoryPressureListeners();
}
// static
void DiscardableMemory::UnregisterMemoryPressureListeners() {
internal::DiscardableMemoryEmulated::UnregisterMemoryPressureListeners();
}
// static // static
void DiscardableMemory::GetSupportedTypes( void DiscardableMemory::GetSupportedTypes(
std::vector<DiscardableMemoryType>* types) { std::vector<DiscardableMemoryType>* types) {
......
...@@ -430,6 +430,10 @@ void RenderThreadImpl::Init() { ...@@ -430,6 +430,10 @@ void RenderThreadImpl::Init() {
base::DiscardableMemory::SetPreferredType(type); base::DiscardableMemory::SetPreferredType(type);
// Allow discardable memory implementations to register memory pressure
// listeners.
base::DiscardableMemory::RegisterMemoryPressureListeners();
// AllocateGpuMemoryBuffer must be used exclusively on one thread but // AllocateGpuMemoryBuffer must be used exclusively on one thread but
// it doesn't have to be the same thread RenderThreadImpl is created on. // it doesn't have to be the same thread RenderThreadImpl is created on.
allocate_gpu_memory_buffer_thread_checker_.DetachFromThread(); allocate_gpu_memory_buffer_thread_checker_.DetachFromThread();
......
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