Upstream version 9.37.195.0
[platform/framework/web/crosswalk.git] / src / base / memory / discardable_memory_manager.cc
index 49ecc48..d976da2 100644 (file)
@@ -17,13 +17,17 @@ namespace internal {
 
 DiscardableMemoryManager::DiscardableMemoryManager(
     size_t memory_limit,
-    size_t bytes_to_keep_under_moderate_pressure)
+    size_t soft_memory_limit,
+    size_t bytes_to_keep_under_moderate_pressure,
+    TimeDelta hard_memory_limit_expiration_time)
     : allocations_(AllocationMap::NO_AUTO_EVICT),
-      bytes_allocated_(0),
+      bytes_allocated_(0u),
       memory_limit_(memory_limit),
+      soft_memory_limit_(soft_memory_limit),
       bytes_to_keep_under_moderate_pressure_(
-          bytes_to_keep_under_moderate_pressure) {
-  BytesAllocatedChanged();
+          bytes_to_keep_under_moderate_pressure),
+      hard_memory_limit_expiration_time_(hard_memory_limit_expiration_time) {
+  BytesAllocatedChanged(bytes_allocated_);
 }
 
 DiscardableMemoryManager::~DiscardableMemoryManager() {
@@ -48,7 +52,13 @@ void DiscardableMemoryManager::UnregisterMemoryPressureListener() {
 void DiscardableMemoryManager::SetMemoryLimit(size_t bytes) {
   AutoLock lock(lock_);
   memory_limit_ = bytes;
-  EnforcePolicyWithLockAcquired();
+  PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
+      Now(), memory_limit_);
+}
+
+void DiscardableMemoryManager::SetSoftMemoryLimit(size_t bytes) {
+  AutoLock lock(lock_);
+  soft_memory_limit_ = bytes;
 }
 
 void DiscardableMemoryManager::SetBytesToKeepUnderModeratePressure(
@@ -57,6 +67,16 @@ void DiscardableMemoryManager::SetBytesToKeepUnderModeratePressure(
   bytes_to_keep_under_moderate_pressure_ = bytes;
 }
 
+void DiscardableMemoryManager::SetHardMemoryLimitExpirationTime(
+    TimeDelta hard_memory_limit_expiration_time) {
+  AutoLock lock(lock_);
+  hard_memory_limit_expiration_time_ = hard_memory_limit_expiration_time;
+}
+
+bool DiscardableMemoryManager::ReduceMemoryUsage() {
+  return PurgeIfNotUsedSinceHardLimitCutoffUntilWithinSoftMemoryLimit();
+}
+
 void DiscardableMemoryManager::Register(Allocation* allocation, size_t bytes) {
   AutoLock lock(lock_);
   // A registered memory listener is currently required. This DCHECK can be
@@ -78,7 +98,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 +115,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 +123,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 +133,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 +149,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(
@@ -159,7 +186,7 @@ void DiscardableMemoryManager::OnMemoryPressure(
     MemoryPressureListener::MemoryPressureLevel pressure_level) {
   switch (pressure_level) {
     case MemoryPressureListener::MEMORY_PRESSURE_MODERATE:
-      Purge();
+      PurgeUntilWithinBytesToKeepUnderModeratePressure();
       return;
     case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL:
       PurgeAll();
@@ -169,21 +196,28 @@ void DiscardableMemoryManager::OnMemoryPressure(
   NOTREACHED();
 }
 
-void DiscardableMemoryManager::Purge() {
+void
+DiscardableMemoryManager::PurgeUntilWithinBytesToKeepUnderModeratePressure() {
   AutoLock lock(lock_);
 
-  PurgeLRUWithLockAcquiredUntilUsageIsWithin(
-      bytes_to_keep_under_moderate_pressure_);
+  PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
+      Now(), bytes_to_keep_under_moderate_pressure_);
 }
 
-void DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin(
-    size_t limit) {
-  TRACE_EVENT1(
-      "base",
-      "DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin",
-      "limit",
-      limit);
+bool DiscardableMemoryManager::
+    PurgeIfNotUsedSinceHardLimitCutoffUntilWithinSoftMemoryLimit() {
+  AutoLock lock(lock_);
+
+  PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
+      Now() - hard_memory_limit_expiration_time_, soft_memory_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 +229,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 +242,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