Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / base / memory / discardable_memory_manager.cc
blob3647b7b2f91a682d2805c2752a981ad771f99e40
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/memory/discardable_memory_manager.h"
7 #include "base/bind.h"
8 #include "base/containers/hash_tables.h"
9 #include "base/containers/mru_cache.h"
10 #include "base/debug/crash_logging.h"
11 #include "base/debug/trace_event.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/synchronization/lock.h"
15 namespace base {
16 namespace internal {
18 DiscardableMemoryManager::DiscardableMemoryManager(
19 size_t memory_limit,
20 size_t soft_memory_limit,
21 TimeDelta hard_memory_limit_expiration_time)
22 : allocations_(AllocationMap::NO_AUTO_EVICT),
23 bytes_allocated_(0u),
24 memory_limit_(memory_limit),
25 soft_memory_limit_(soft_memory_limit),
26 hard_memory_limit_expiration_time_(hard_memory_limit_expiration_time) {
27 BytesAllocatedChanged(bytes_allocated_);
30 DiscardableMemoryManager::~DiscardableMemoryManager() {
31 DCHECK(allocations_.empty());
32 DCHECK_EQ(0u, bytes_allocated_);
35 void DiscardableMemoryManager::SetMemoryLimit(size_t bytes) {
36 AutoLock lock(lock_);
37 memory_limit_ = bytes;
38 PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
39 Now(), memory_limit_);
42 void DiscardableMemoryManager::SetSoftMemoryLimit(size_t bytes) {
43 AutoLock lock(lock_);
44 soft_memory_limit_ = bytes;
47 void DiscardableMemoryManager::SetHardMemoryLimitExpirationTime(
48 TimeDelta hard_memory_limit_expiration_time) {
49 AutoLock lock(lock_);
50 hard_memory_limit_expiration_time_ = hard_memory_limit_expiration_time;
53 bool DiscardableMemoryManager::ReduceMemoryUsage() {
54 return PurgeIfNotUsedSinceHardLimitCutoffUntilWithinSoftMemoryLimit();
57 void DiscardableMemoryManager::ReduceMemoryUsageUntilWithinLimit(size_t bytes) {
58 AutoLock lock(lock_);
59 PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(Now(),
60 bytes);
63 void DiscardableMemoryManager::Register(Allocation* allocation, size_t bytes) {
64 AutoLock lock(lock_);
65 DCHECK(allocations_.Peek(allocation) == allocations_.end());
66 allocations_.Put(allocation, AllocationInfo(bytes));
69 void DiscardableMemoryManager::Unregister(Allocation* allocation) {
70 AutoLock lock(lock_);
71 AllocationMap::iterator it = allocations_.Peek(allocation);
72 DCHECK(it != allocations_.end());
73 const AllocationInfo& info = it->second;
75 if (info.purgable) {
76 size_t bytes_purgable = info.bytes;
77 DCHECK_LE(bytes_purgable, bytes_allocated_);
78 bytes_allocated_ -= bytes_purgable;
79 BytesAllocatedChanged(bytes_allocated_);
81 allocations_.Erase(it);
84 bool DiscardableMemoryManager::AcquireLock(Allocation* allocation,
85 bool* purged) {
86 AutoLock lock(lock_);
87 // Note: |allocations_| is an MRU cache, and use of |Get| here updates that
88 // cache.
89 AllocationMap::iterator it = allocations_.Get(allocation);
90 DCHECK(it != allocations_.end());
91 AllocationInfo* info = &it->second;
93 if (!info->bytes)
94 return false;
96 TimeTicks now = Now();
97 size_t bytes_required = info->purgable ? 0u : info->bytes;
99 if (memory_limit_) {
100 size_t limit = 0;
101 if (bytes_required < memory_limit_)
102 limit = memory_limit_ - bytes_required;
104 PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(now,
105 limit);
108 // Check for overflow.
109 if (std::numeric_limits<size_t>::max() - bytes_required < bytes_allocated_)
110 return false;
112 *purged = !allocation->AllocateAndAcquireLock();
113 info->purgable = false;
114 info->last_usage = now;
115 if (bytes_required) {
116 bytes_allocated_ += bytes_required;
117 BytesAllocatedChanged(bytes_allocated_);
119 return true;
122 void DiscardableMemoryManager::ReleaseLock(Allocation* allocation) {
123 AutoLock lock(lock_);
124 // Note: |allocations_| is an MRU cache, and use of |Get| here updates that
125 // cache.
126 AllocationMap::iterator it = allocations_.Get(allocation);
127 DCHECK(it != allocations_.end());
128 AllocationInfo* info = &it->second;
130 TimeTicks now = Now();
131 allocation->ReleaseLock();
132 info->purgable = true;
133 info->last_usage = now;
135 PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
136 now, memory_limit_);
139 void DiscardableMemoryManager::PurgeAll() {
140 AutoLock lock(lock_);
141 PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(Now(), 0);
144 bool DiscardableMemoryManager::IsRegisteredForTest(
145 Allocation* allocation) const {
146 AutoLock lock(lock_);
147 AllocationMap::const_iterator it = allocations_.Peek(allocation);
148 return it != allocations_.end();
151 bool DiscardableMemoryManager::CanBePurgedForTest(
152 Allocation* allocation) const {
153 AutoLock lock(lock_);
154 AllocationMap::const_iterator it = allocations_.Peek(allocation);
155 return it != allocations_.end() && it->second.purgable;
158 size_t DiscardableMemoryManager::GetBytesAllocatedForTest() const {
159 AutoLock lock(lock_);
160 return bytes_allocated_;
163 bool DiscardableMemoryManager::
164 PurgeIfNotUsedSinceHardLimitCutoffUntilWithinSoftMemoryLimit() {
165 AutoLock lock(lock_);
167 PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
168 Now() - hard_memory_limit_expiration_time_, soft_memory_limit_);
170 return bytes_allocated_ <= soft_memory_limit_;
173 void DiscardableMemoryManager::
174 PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
175 TimeTicks timestamp,
176 size_t limit) {
177 lock_.AssertAcquired();
179 size_t bytes_allocated_before_purging = bytes_allocated_;
180 for (AllocationMap::reverse_iterator it = allocations_.rbegin();
181 it != allocations_.rend();
182 ++it) {
183 Allocation* allocation = it->first;
184 AllocationInfo* info = &it->second;
186 if (bytes_allocated_ <= limit)
187 break;
189 bool purgable = info->purgable && info->last_usage <= timestamp;
190 if (!purgable)
191 continue;
193 size_t bytes_purgable = info->bytes;
194 DCHECK_LE(bytes_purgable, bytes_allocated_);
195 bytes_allocated_ -= bytes_purgable;
196 info->purgable = false;
197 allocation->Purge();
200 if (bytes_allocated_ != bytes_allocated_before_purging)
201 BytesAllocatedChanged(bytes_allocated_);
204 void DiscardableMemoryManager::BytesAllocatedChanged(
205 size_t new_bytes_allocated) const {
206 TRACE_COUNTER_ID1(
207 "base", "DiscardableMemoryUsage", this, new_bytes_allocated);
209 static const char kDiscardableMemoryUsageKey[] = "dm-usage";
210 base::debug::SetCrashKeyValue(kDiscardableMemoryUsageKey,
211 Uint64ToString(new_bytes_allocated));
214 TimeTicks DiscardableMemoryManager::Now() const {
215 return TimeTicks::Now();
218 } // namespace internal
219 } // namespace base