Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / base / memory / discardable_memory_manager.cc
index 5ff7e3a..468690b 100644 (file)
@@ -9,16 +9,14 @@
 #include "base/containers/mru_cache.h"
 #include "base/debug/trace_event.h"
 #include "base/synchronization/lock.h"
-#include "base/sys_info.h"
 
 namespace base {
 namespace internal {
-
 namespace {
 
 // This is admittedly pretty magical. It's approximately enough memory for eight
 // 2560x1600 images.
-static const size_t kDefaultDiscardableMemoryLimit = 128 * 1024 * 1024;
+static const size_t kDefaultMemoryLimit = 128 * 1024 * 1024;
 static const size_t kDefaultBytesToKeepUnderModeratePressure = 12 * 1024 * 1024;
 
 }  // namespace
@@ -26,9 +24,10 @@ static const size_t kDefaultBytesToKeepUnderModeratePressure = 12 * 1024 * 1024;
 DiscardableMemoryManager::DiscardableMemoryManager()
     : allocations_(AllocationMap::NO_AUTO_EVICT),
       bytes_allocated_(0),
-      discardable_memory_limit_(kDefaultDiscardableMemoryLimit),
+      memory_limit_(kDefaultMemoryLimit),
       bytes_to_keep_under_moderate_pressure_(
           kDefaultBytesToKeepUnderModeratePressure) {
+  BytesAllocatedChanged();
 }
 
 DiscardableMemoryManager::~DiscardableMemoryManager() {
@@ -40,10 +39,8 @@ void DiscardableMemoryManager::RegisterMemoryPressureListener() {
   AutoLock lock(lock_);
   DCHECK(base::MessageLoop::current());
   DCHECK(!memory_pressure_listener_);
-  memory_pressure_listener_.reset(
-      new MemoryPressureListener(
-          base::Bind(&DiscardableMemoryManager::OnMemoryPressure,
-                     Unretained(this))));
+  memory_pressure_listener_.reset(new MemoryPressureListener(base::Bind(
+      &DiscardableMemoryManager::OnMemoryPressure, Unretained(this))));
 }
 
 void DiscardableMemoryManager::UnregisterMemoryPressureListener() {
@@ -52,9 +49,9 @@ void DiscardableMemoryManager::UnregisterMemoryPressureListener() {
   memory_pressure_listener_.reset();
 }
 
-void DiscardableMemoryManager::SetDiscardableMemoryLimit(size_t bytes) {
+void DiscardableMemoryManager::SetMemoryLimit(size_t bytes) {
   AutoLock lock(lock_);
-  discardable_memory_limit_ = bytes;
+  memory_limit_ = bytes;
   EnforcePolicyWithLockAcquired();
 }
 
@@ -64,87 +61,77 @@ void DiscardableMemoryManager::SetBytesToKeepUnderModeratePressure(
   bytes_to_keep_under_moderate_pressure_ = bytes;
 }
 
-void DiscardableMemoryManager::Register(
-    const DiscardableMemory* discardable, size_t bytes) {
+void DiscardableMemoryManager::Register(Allocation* allocation, size_t bytes) {
   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.
   // TODO(reveman): Enable this DCHECK when skia and blink are able to
   // register memory pressure listeners. crbug.com/333907
   // DCHECK(memory_pressure_listener_);
-  DCHECK(allocations_.Peek(discardable) == allocations_.end());
-  allocations_.Put(discardable, Allocation(bytes));
+  DCHECK(allocations_.Peek(allocation) == allocations_.end());
+  allocations_.Put(allocation, AllocationInfo(bytes));
 }
 
-void DiscardableMemoryManager::Unregister(
-    const DiscardableMemory* discardable) {
+void DiscardableMemoryManager::Unregister(Allocation* allocation) {
   AutoLock lock(lock_);
-  AllocationMap::iterator it = allocations_.Peek(discardable);
-  if (it == allocations_.end())
-    return;
-
-  if (it->second.memory) {
-    size_t bytes = it->second.bytes;
-    DCHECK_LE(bytes, bytes_allocated_);
-    bytes_allocated_ -= bytes;
-    free(it->second.memory);
+  AllocationMap::iterator it = allocations_.Peek(allocation);
+  DCHECK(it != allocations_.end());
+  const AllocationInfo& info = it->second;
+
+  if (info.purgable) {
+    size_t bytes_purgable = info.bytes;
+    DCHECK_LE(bytes_purgable, bytes_allocated_);
+    bytes_allocated_ -= bytes_purgable;
+    BytesAllocatedChanged();
   }
   allocations_.Erase(it);
 }
 
-scoped_ptr<uint8, FreeDeleter> DiscardableMemoryManager::Acquire(
-    const DiscardableMemory* discardable,
-    bool* purged) {
+bool DiscardableMemoryManager::AcquireLock(Allocation* allocation,
+                                           bool* purged) {
   AutoLock lock(lock_);
-  // NB: |allocations_| is an MRU cache, and use of |Get| here updates that
+  // Note: |allocations_| is an MRU cache, and use of |Get| here updates that
   // cache.
-  AllocationMap::iterator it = allocations_.Get(discardable);
-  CHECK(it != allocations_.end());
-
-  if (it->second.memory) {
-    scoped_ptr<uint8, FreeDeleter> memory(it->second.memory);
-    it->second.memory = NULL;
-    *purged = false;
-    return memory.Pass();
-  }
+  AllocationMap::iterator it = allocations_.Get(allocation);
+  DCHECK(it != allocations_.end());
+  AllocationInfo* info = &it->second;
+
+  if (!info->bytes)
+    return false;
 
-  size_t bytes = it->second.bytes;
-  if (!bytes)
-    return scoped_ptr<uint8, FreeDeleter>();
+  size_t bytes_required = info->purgable ? 0u : info->bytes;
 
-  if (discardable_memory_limit_) {
+  if (memory_limit_) {
     size_t limit = 0;
-    if (bytes < discardable_memory_limit_)
-      limit = discardable_memory_limit_ - bytes;
+    if (bytes_required < memory_limit_)
+      limit = memory_limit_ - bytes_required;
 
     PurgeLRUWithLockAcquiredUntilUsageIsWithin(limit);
   }
 
   // Check for overflow.
-  if (std::numeric_limits<size_t>::max() - bytes < bytes_allocated_)
-    return scoped_ptr<uint8, FreeDeleter>();
-
-  scoped_ptr<uint8, FreeDeleter> memory(static_cast<uint8*>(malloc(bytes)));
-  if (!memory)
-    return scoped_ptr<uint8, FreeDeleter>();
-
-  bytes_allocated_ += bytes;
-  *purged = true;
-  return memory.Pass();
+  if (std::numeric_limits<size_t>::max() - bytes_required < bytes_allocated_)
+    return false;
+
+  *purged = !allocation->AllocateAndAcquireLock();
+  info->purgable = false;
+  if (bytes_required) {
+    bytes_allocated_ += bytes_required;
+    BytesAllocatedChanged();
+  }
+  return true;
 }
 
-void DiscardableMemoryManager::Release(
-    const DiscardableMemory* discardable,
-    scoped_ptr<uint8, FreeDeleter> memory) {
+void DiscardableMemoryManager::ReleaseLock(Allocation* allocation) {
   AutoLock lock(lock_);
-  // NB: |allocations_| is an MRU cache, and use of |Get| here updates that
+  // Note: |allocations_| is an MRU cache, and use of |Get| here updates that
   // cache.
-  AllocationMap::iterator it = allocations_.Get(discardable);
-  CHECK(it != allocations_.end());
-
-  DCHECK(!it->second.memory);
-  it->second.memory = memory.release();
+  AllocationMap::iterator it = allocations_.Get(allocation);
+  DCHECK(it != allocations_.end());
+  AllocationInfo* info = &it->second;
 
+  allocation->ReleaseLock();
+  info->purgable = true;
   EnforcePolicyWithLockAcquired();
 }
 
@@ -154,17 +141,17 @@ void DiscardableMemoryManager::PurgeAll() {
 }
 
 bool DiscardableMemoryManager::IsRegisteredForTest(
-    const DiscardableMemory* discardable) const {
+    Allocation* allocation) const {
   AutoLock lock(lock_);
-  AllocationMap::const_iterator it = allocations_.Peek(discardable);
+  AllocationMap::const_iterator it = allocations_.Peek(allocation);
   return it != allocations_.end();
 }
 
 bool DiscardableMemoryManager::CanBePurgedForTest(
-    const DiscardableMemory* discardable) const {
+    Allocation* allocation) const {
   AutoLock lock(lock_);
-  AllocationMap::const_iterator it = allocations_.Peek(discardable);
-  return it != allocations_.end() && it->second.memory;
+  AllocationMap::const_iterator it = allocations_.Peek(allocation);
+  return it != allocations_.end() && it->second.purgable;
 }
 
 size_t DiscardableMemoryManager::GetBytesAllocatedForTest() const {
@@ -198,28 +185,40 @@ void DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin(
   TRACE_EVENT1(
       "base",
       "DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin",
-      "limit", limit);
+      "limit",
+      limit);
 
   lock_.AssertAcquired();
 
+  size_t bytes_allocated_before_purging = bytes_allocated_;
   for (AllocationMap::reverse_iterator it = allocations_.rbegin();
        it != allocations_.rend();
        ++it) {
+    Allocation* allocation = it->first;
+    AllocationInfo* info = &it->second;
+
     if (bytes_allocated_ <= limit)
       break;
-    if (!it->second.memory)
+    if (!info->purgable)
       continue;
 
-    size_t bytes = it->second.bytes;
-    DCHECK_LE(bytes, bytes_allocated_);
-    bytes_allocated_ -= bytes;
-    free(it->second.memory);
-    it->second.memory = NULL;
+    size_t bytes_purgable = info->bytes;
+    DCHECK_LE(bytes_purgable, bytes_allocated_);
+    bytes_allocated_ -= bytes_purgable;
+    info->purgable = false;
+    allocation->Purge();
   }
+
+  if (bytes_allocated_ != bytes_allocated_before_purging)
+    BytesAllocatedChanged();
 }
 
 void DiscardableMemoryManager::EnforcePolicyWithLockAcquired() {
-  PurgeLRUWithLockAcquiredUntilUsageIsWithin(discardable_memory_limit_);
+  PurgeLRUWithLockAcquiredUntilUsageIsWithin(memory_limit_);
+}
+
+void DiscardableMemoryManager::BytesAllocatedChanged() const {
+  TRACE_COUNTER_ID1("base", "DiscardableMemoryUsage", this, bytes_allocated_);
 }
 
 }  // namespace internal