Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / base / memory / discardable_memory_manager.cc
index 49ecc48..3647b7b 100644 (file)
@@ -17,13 +17,14 @@ namespace internal {
 
 DiscardableMemoryManager::DiscardableMemoryManager(
     size_t memory_limit,
-    size_t bytes_to_keep_under_moderate_pressure)
+    size_t soft_memory_limit,
+    TimeDelta hard_memory_limit_expiration_time)
     : allocations_(AllocationMap::NO_AUTO_EVICT),
-      bytes_allocated_(0),
+      bytes_allocated_(0u),
       memory_limit_(memory_limit),
-      bytes_to_keep_under_moderate_pressure_(
-          bytes_to_keep_under_moderate_pressure) {
-  BytesAllocatedChanged();
+      soft_memory_limit_(soft_memory_limit),
+      hard_memory_limit_expiration_time_(hard_memory_limit_expiration_time) {
+  BytesAllocatedChanged(bytes_allocated_);
 }
 
 DiscardableMemoryManager::~DiscardableMemoryManager() {
@@ -31,39 +32,36 @@ DiscardableMemoryManager::~DiscardableMemoryManager() {
   DCHECK_EQ(0u, bytes_allocated_);
 }
 
-void DiscardableMemoryManager::RegisterMemoryPressureListener() {
+void DiscardableMemoryManager::SetMemoryLimit(size_t bytes) {
   AutoLock lock(lock_);
-  DCHECK(base::MessageLoop::current());
-  DCHECK(!memory_pressure_listener_);
-  memory_pressure_listener_.reset(new MemoryPressureListener(base::Bind(
-      &DiscardableMemoryManager::OnMemoryPressure, Unretained(this))));
+  memory_limit_ = bytes;
+  PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
+      Now(), memory_limit_);
 }
 
-void DiscardableMemoryManager::UnregisterMemoryPressureListener() {
+void DiscardableMemoryManager::SetSoftMemoryLimit(size_t bytes) {
   AutoLock lock(lock_);
-  DCHECK(memory_pressure_listener_);
-  memory_pressure_listener_.reset();
+  soft_memory_limit_ = bytes;
 }
 
-void DiscardableMemoryManager::SetMemoryLimit(size_t bytes) {
+void DiscardableMemoryManager::SetHardMemoryLimitExpirationTime(
+    TimeDelta hard_memory_limit_expiration_time) {
   AutoLock lock(lock_);
-  memory_limit_ = bytes;
-  EnforcePolicyWithLockAcquired();
+  hard_memory_limit_expiration_time_ = hard_memory_limit_expiration_time;
 }
 
-void DiscardableMemoryManager::SetBytesToKeepUnderModeratePressure(
-    size_t bytes) {
+bool DiscardableMemoryManager::ReduceMemoryUsage() {
+  return PurgeIfNotUsedSinceHardLimitCutoffUntilWithinSoftMemoryLimit();
+}
+
+void DiscardableMemoryManager::ReduceMemoryUsageUntilWithinLimit(size_t bytes) {
   AutoLock lock(lock_);
-  bytes_to_keep_under_moderate_pressure_ = bytes;
+  PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(Now(),
+                                                                      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(allocation) == allocations_.end());
   allocations_.Put(allocation, AllocationInfo(bytes));
 }
@@ -78,7 +76,7 @@ void DiscardableMemoryManager::Unregister(Allocation* allocation) {
     size_t bytes_purgable = info.bytes;
     DCHECK_LE(bytes_purgable, bytes_allocated_);
     bytes_allocated_ -= bytes_purgable;
-    BytesAllocatedChanged();
+    BytesAllocatedChanged(bytes_allocated_);
   }
   allocations_.Erase(it);
 }
@@ -95,6 +93,7 @@ bool DiscardableMemoryManager::AcquireLock(Allocation* allocation,
   if (!info->bytes)
     return false;
 
+  TimeTicks now = Now();
   size_t bytes_required = info->purgable ? 0u : info->bytes;
 
   if (memory_limit_) {
@@ -102,7 +101,8 @@ bool DiscardableMemoryManager::AcquireLock(Allocation* allocation,
     if (bytes_required < memory_limit_)
       limit = memory_limit_ - bytes_required;
 
-    PurgeLRUWithLockAcquiredUntilUsageIsWithin(limit);
+    PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(now,
+                                                                        limit);
   }
 
   // Check for overflow.
@@ -111,9 +111,10 @@ bool DiscardableMemoryManager::AcquireLock(Allocation* allocation,
 
   *purged = !allocation->AllocateAndAcquireLock();
   info->purgable = false;
+  info->last_usage = now;
   if (bytes_required) {
     bytes_allocated_ += bytes_required;
-    BytesAllocatedChanged();
+    BytesAllocatedChanged(bytes_allocated_);
   }
   return true;
 }
@@ -126,14 +127,18 @@ void DiscardableMemoryManager::ReleaseLock(Allocation* allocation) {
   DCHECK(it != allocations_.end());
   AllocationInfo* info = &it->second;
 
+  TimeTicks now = Now();
   allocation->ReleaseLock();
   info->purgable = true;
-  EnforcePolicyWithLockAcquired();
+  info->last_usage = now;
+
+  PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
+      now, memory_limit_);
 }
 
 void DiscardableMemoryManager::PurgeAll() {
   AutoLock lock(lock_);
-  PurgeLRUWithLockAcquiredUntilUsageIsWithin(0);
+  PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(Now(), 0);
 }
 
 bool DiscardableMemoryManager::IsRegisteredForTest(
@@ -155,35 +160,20 @@ size_t DiscardableMemoryManager::GetBytesAllocatedForTest() const {
   return bytes_allocated_;
 }
 
-void DiscardableMemoryManager::OnMemoryPressure(
-    MemoryPressureListener::MemoryPressureLevel pressure_level) {
-  switch (pressure_level) {
-    case MemoryPressureListener::MEMORY_PRESSURE_MODERATE:
-      Purge();
-      return;
-    case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL:
-      PurgeAll();
-      return;
-  }
-
-  NOTREACHED();
-}
-
-void DiscardableMemoryManager::Purge() {
+bool DiscardableMemoryManager::
+    PurgeIfNotUsedSinceHardLimitCutoffUntilWithinSoftMemoryLimit() {
   AutoLock lock(lock_);
 
-  PurgeLRUWithLockAcquiredUntilUsageIsWithin(
-      bytes_to_keep_under_moderate_pressure_);
-}
+  PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
+      Now() - hard_memory_limit_expiration_time_, soft_memory_limit_);
 
-void DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin(
-    size_t limit) {
-  TRACE_EVENT1(
-      "base",
-      "DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin",
-      "limit",
-      limit);
+  return bytes_allocated_ <= soft_memory_limit_;
+}
 
+void DiscardableMemoryManager::
+    PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
+        TimeTicks timestamp,
+        size_t limit) {
   lock_.AssertAcquired();
 
   size_t bytes_allocated_before_purging = bytes_allocated_;
@@ -195,7 +185,9 @@ void DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin(
 
     if (bytes_allocated_ <= limit)
       break;
-    if (!info->purgable)
+
+    bool purgable = info->purgable && info->last_usage <= timestamp;
+    if (!purgable)
       continue;
 
     size_t bytes_purgable = info->bytes;
@@ -206,19 +198,21 @@ void DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin(
   }
 
   if (bytes_allocated_ != bytes_allocated_before_purging)
-    BytesAllocatedChanged();
+    BytesAllocatedChanged(bytes_allocated_);
 }
 
-void DiscardableMemoryManager::EnforcePolicyWithLockAcquired() {
-  PurgeLRUWithLockAcquiredUntilUsageIsWithin(memory_limit_);
-}
-
-void DiscardableMemoryManager::BytesAllocatedChanged() const {
-  TRACE_COUNTER_ID1("base", "DiscardableMemoryUsage", this, bytes_allocated_);
+void DiscardableMemoryManager::BytesAllocatedChanged(
+    size_t new_bytes_allocated) const {
+  TRACE_COUNTER_ID1(
+      "base", "DiscardableMemoryUsage", this, new_bytes_allocated);
 
   static const char kDiscardableMemoryUsageKey[] = "dm-usage";
   base::debug::SetCrashKeyValue(kDiscardableMemoryUsageKey,
-                                Uint64ToString(bytes_allocated_));
+                                Uint64ToString(new_bytes_allocated));
+}
+
+TimeTicks DiscardableMemoryManager::Now() const {
+  return TimeTicks::Now();
 }
 
 }  // namespace internal