Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Side by Side Diff: base/memory/discardable_memory_emulated.cc

Issue 15650016: [Not for review] Discardable memory emulation (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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.
4
5 #include "base/memory/discardable_memory.h"
6
7 #include "base/containers/hash_tables.h"
8 #include "base/containers/mru_cache.h"
9 #include "base/memory/singleton.h"
10 #include "base/synchronization/lock.h"
11 #include "base/sys_info.h"
12
13 #if defined(COMPILER_GCC)
14 namespace BASE_HASH_NAMESPACE {
15 template <>
16 struct hash<base::DiscardableMemory*> {
17 size_t operator()(base::DiscardableMemory* ptr) const {
18 return hash<size_t>()(reinterpret_cast<size_t>(ptr));
19 }
20 };
21 } // namespace BASE_HASH_NAMESPACE
22 #endif // COMPILER
23
24 namespace base {
25
26 namespace {
27
28 // These are definitely magical. Is there a nice way to set them?
29 static size_t kCacheLimitUpperBound = 32 * 1024 * 1024;
30 static size_t kCacheLimitPurgeBound = 4 * 1024 * 1024;
31 static int64 kSystemMemoryLowerBound = 256 * 1024 * 1024;
32
33 static bool SystemIsUnderMemoryPressure() {
34 return SysInfo::AmountOfAvailablePhysicalMemory() <
35 kSystemMemoryLowerBound;
Avi (use Gerrit) 2013/06/12 14:56:49 Way too magical. Does this function belong in SysI
36 }
37
38 typedef HashingMRUCache<DiscardableMemory*, bool> AllocationMap;
Avi (use Gerrit) 2013/06/12 14:56:49 bool? If that's just a placeholder, say so.
39
40 } // namespace
41
42 // This provider is accessed from multiple threads, so some care needs to be
43 // taken to ensure thread safety. In general, the policy has been that
44 // allocations are initiated by client code (via Lock or InitializeAndLock),
45 // and deallocations are initiated by the provider. Given this policy, the
46 // provider assumes that the lock has already been aquired by the provider
47 // itself in the Purge/Policy/DidDeallocate methods, but does not make this
48 // assumption in the rest of the interface and aquires the lock as appropriate.
49 class DiscardableMemoryProvider {
Avi (use Gerrit) 2013/06/12 14:56:49 Give the member functions explanatory comments. Me
Avi (use Gerrit) 2013/06/12 14:56:49 DiscardableMemoryProvider desperately needs a unit
50 public:
51 DiscardableMemoryProvider()
52 : allocations_(AllocationMap::NO_AUTO_EVICT),
53 bytes_allocated_(0) {
54 }
55
56 virtual ~DiscardableMemoryProvider() {
57 AutoLock lock(lock_);
58 AllocationMap::iterator it = allocations_.begin();
59 for (; it != allocations_.end(); ++it)
60 if (it->first->Memory())
61 it->first->Deallocate();
62 }
63
64 static DiscardableMemoryProvider* GetInstance() {
65 return Singleton<DiscardableMemoryProvider>::get();
66 }
67
68 void Register(DiscardableMemory* discardable) {
69 Unregister(discardable);
Avi (use Gerrit) 2013/06/12 14:56:49 Why the Unregister? Register is only called from D
70 {
71 AutoLock lock(lock_);
72 allocations_.Put(discardable, true);
73 EnforcePolicy();
74 }
75 }
76
77 void Unregister(DiscardableMemory* discardable) {
78 if (discardable->is_locked())
79 discardable->Unlock();
80 {
81 AutoLock lock(lock_);
82 if (discardable->memory_)
83 discardable->Deallocate();
Avi (use Gerrit) 2013/06/12 14:56:49 Eh... Unregister is only called by ~DiscardableMe
84 AllocationMap::iterator it = allocations_.Peek(discardable);
85 if (it != allocations_.end()) {
86 allocations_.Erase(it);
87 EnforcePolicy();
88 }
89 }
90 }
91
92 void DidAllocate(size_t bytes) {
93 AutoLock lock(lock_);
94 bytes_allocated_ += bytes;
95 EnforcePolicy();
96 }
97
98 void DidDeallocate(size_t bytes) {
99 lock_.AssertAcquired();
100 DCHECK(bytes <= bytes_allocated_);
101 bytes_allocated_ -= bytes;
102 EnforcePolicy();
103 }
104
105 void DidAccess(DiscardableMemory* discardable) {
106 AutoLock lock(lock_);
107 allocations_.Get(discardable);
108 }
109
110 void ForcePurge() {
111 AutoLock lock(lock_);
112 PurgeAll();
113 }
114
115 void PurgeAll() {
116 AllocationMap::iterator it = allocations_.begin();
117 for (; it != allocations_.end(); ++it) {
118 if (it->first->memory_ && !it->first->is_locked()) {
119 it->first->Deallocate();
120 DCHECK(!it->first->memory_);
121 }
122 }
123 }
124
125 void PurgeLRU() {
126 AllocationMap::reverse_iterator it = allocations_.rbegin();
127 for(; it != allocations_.rend(); ++it) {
128 if (!it->first->memory_ || !it->first->is_locked())
129 continue;
130 it->first->Deallocate();
131 DCHECK(!it->first->memory_);
132 if (bytes_allocated_ < kCacheLimitPurgeBound)
cpu_(ooo_6.6-7.5) 2013/06/13 20:16:06 I was expecting freeing N megs, not freeing until
133 break;
134 }
135 }
136
137 void EnforcePolicy() {
138 if (SystemIsUnderMemoryPressure())
139 PurgeAll();
cpu_(ooo_6.6-7.5) 2013/06/13 20:16:06 again, surprised on the full purge.
140 else if (bytes_allocated_ > kCacheLimitUpperBound)
141 PurgeLRU();
142 }
143
144 private:
145 AllocationMap allocations_;
146 bool visible_;
147 size_t bytes_allocated_;
148 Lock lock_;
Avi (use Gerrit) 2013/06/12 14:56:49 Member variables need comment love too. In particu
149
150 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryProvider);
151 };
152
153 DiscardableMemory::~DiscardableMemory() {
154 DiscardableMemoryProvider::GetInstance()->Unregister(this);
155 }
156
157 bool DiscardableMemory::InitializeAndLock(size_t size) {
158 DiscardableMemoryProvider::GetInstance()->Register(this);
159 size_ = size;
160 return Lock() != DISCARDABLE_MEMORY_FAILED;
Avi (use Gerrit) 2013/06/12 14:56:49 LockDiscardableMemoryStatus status = Lock(); DCHEC
161 }
162
163 LockDiscardableMemoryStatus DiscardableMemory::Lock() {
164 DCHECK(!is_locked_);
165 DiscardableMemoryProvider::GetInstance()->DidAccess(this);
166 is_locked_ = true;
167
168 if (memory_)
169 return DISCARDABLE_MEMORY_SUCCESS;
170
171 if (Allocate())
172 return DISCARDABLE_MEMORY_PURGED;
173
174 return DISCARDABLE_MEMORY_FAILED;
175 }
176
177 void DiscardableMemory::Unlock() {
178 DCHECK(is_locked_);
179 DiscardableMemoryProvider::GetInstance()->DidAccess(this);
180 is_locked_ = false;
181 }
182
183 bool DiscardableMemory::Allocate() {
184 DCHECK(!memory_);
185 memory_ = malloc(size_ * sizeof(char));
Avi (use Gerrit) 2013/06/12 14:56:49 sizeof(char) is defined by the standard to be 1 (C
186 if (memory_)
187 DiscardableMemoryProvider::GetInstance()->DidAllocate(size_);
188 return memory_;
189 }
190
191 void DiscardableMemory::Deallocate() {
192 DCHECK(memory_);
193 free(memory_);
194 memory_ = NULL;
195 DiscardableMemoryProvider::GetInstance()->DidDeallocate(size_);
196 }
197
198
199 // static
200 bool DiscardableMemory::PurgeForTestingSupported() {
201 return true;
202 }
203
204 // static
205 void DiscardableMemory::PurgeForTesting() {
206 Purge();
207 }
208
209 void DiscardableMemory::Purge() {
210 DiscardableMemoryProvider::GetInstance()->ForcePurge();
211 }
212
213 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698