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

Side by Side Diff: cc/resources/resource_pool.cc

Issue 1420433009: cc: Keep most recently used resources at the front of resource queue. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Changed order of mru <-> lru. Created 5 years, 1 month 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
« no previous file with comments | « cc/resources/resource_pool.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "cc/resources/resource_pool.h" 5 #include "cc/resources/resource_pool.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/format_macros.h" 9 #include "base/format_macros.h"
10 #include "base/strings/stringprintf.h" 10 #include "base/strings/stringprintf.h"
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 this, task_runner_.get()); 72 this, task_runner_.get());
73 } 73 }
74 74
75 ResourcePool::~ResourcePool() { 75 ResourcePool::~ResourcePool() {
76 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( 76 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
77 this); 77 this);
78 78
79 DCHECK_EQ(0u, in_use_resources_.size()); 79 DCHECK_EQ(0u, in_use_resources_.size());
80 80
81 while (!busy_resources_.empty()) { 81 while (!busy_resources_.empty()) {
82 DidFinishUsingResource(busy_resources_.take_front()); 82 DidFinishUsingResource(busy_resources_.take_back());
83 } 83 }
84 84
85 SetResourceUsageLimits(0, 0); 85 SetResourceUsageLimits(0, 0);
86 DCHECK_EQ(0u, unused_resources_.size()); 86 DCHECK_EQ(0u, unused_resources_.size());
87 DCHECK_EQ(0u, in_use_memory_usage_bytes_); 87 DCHECK_EQ(0u, in_use_memory_usage_bytes_);
88 DCHECK_EQ(0u, total_memory_usage_bytes_); 88 DCHECK_EQ(0u, total_memory_usage_bytes_);
89 DCHECK_EQ(0u, total_resource_count_); 89 DCHECK_EQ(0u, total_resource_count_);
90 } 90 }
91 91
92 Resource* ResourcePool::AcquireResource(const gfx::Size& size, 92 Resource* ResourcePool::AcquireResource(const gfx::Size& size,
93 ResourceFormat format) { 93 ResourceFormat format) {
94 // Finding resources in |unused_resources_| from MRU to LRU direction, touches
95 // LRU resources only if needed, which inreases possibility of expiring more
96 // LRU resources within kResourceExpirationDelayMs.
94 for (ResourceDeque::iterator it = unused_resources_.begin(); 97 for (ResourceDeque::iterator it = unused_resources_.begin();
95 it != unused_resources_.end(); ++it) { 98 it != unused_resources_.end(); ++it) {
96 ScopedResource* resource = *it; 99 ScopedResource* resource = *it;
97 DCHECK(resource_provider_->CanLockForWrite(resource->id())); 100 DCHECK(resource_provider_->CanLockForWrite(resource->id()));
98 101
99 if (resource->format() != format) 102 if (resource->format() != format)
100 continue; 103 continue;
101 if (resource->size() != size) 104 if (resource->size() != size)
102 continue; 105 continue;
103 106
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 152
150 void ResourcePool::ReleaseResource(Resource* resource, uint64_t content_id) { 153 void ResourcePool::ReleaseResource(Resource* resource, uint64_t content_id) {
151 auto it = in_use_resources_.find(resource->id()); 154 auto it = in_use_resources_.find(resource->id());
152 DCHECK(it != in_use_resources_.end()); 155 DCHECK(it != in_use_resources_.end());
153 156
154 PoolResource* pool_resource = it->second; 157 PoolResource* pool_resource = it->second;
155 pool_resource->set_content_id(content_id); 158 pool_resource->set_content_id(content_id);
156 pool_resource->set_last_usage(base::TimeTicks::Now()); 159 pool_resource->set_last_usage(base::TimeTicks::Now());
157 160
158 // Transfer resource to |busy_resources_|. 161 // Transfer resource to |busy_resources_|.
159 busy_resources_.push_back(in_use_resources_.take_and_erase(it)); 162 busy_resources_.push_front(in_use_resources_.take_and_erase(it));
160 in_use_memory_usage_bytes_ -= ResourceUtil::UncheckedSizeInBytes<size_t>( 163 in_use_memory_usage_bytes_ -= ResourceUtil::UncheckedSizeInBytes<size_t>(
161 pool_resource->size(), pool_resource->format()); 164 pool_resource->size(), pool_resource->format());
162 165
163 // Now that we have evictable resources, schedule an eviction call for this 166 // Now that we have evictable resources, schedule an eviction call for this
164 // resource if necessary. 167 // resource if necessary.
165 ScheduleEvictExpiredResourcesIn(resource_expiration_delay_); 168 ScheduleEvictExpiredResourcesIn(resource_expiration_delay_);
166 } 169 }
167 170
168 void ResourcePool::SetResourceUsageLimits(size_t max_memory_usage_bytes, 171 void ResourcePool::SetResourceUsageLimits(size_t max_memory_usage_bytes,
169 size_t max_resource_count) { 172 size_t max_resource_count) {
170 max_memory_usage_bytes_ = max_memory_usage_bytes; 173 max_memory_usage_bytes_ = max_memory_usage_bytes;
171 max_resource_count_ = max_resource_count; 174 max_resource_count_ = max_resource_count;
172 175
173 ReduceResourceUsage(); 176 ReduceResourceUsage();
174 } 177 }
175 178
176 void ResourcePool::ReduceResourceUsage() { 179 void ResourcePool::ReduceResourceUsage() {
177 while (!unused_resources_.empty()) { 180 while (!unused_resources_.empty()) {
178 if (!ResourceUsageTooHigh()) 181 if (!ResourceUsageTooHigh())
179 break; 182 break;
180 183
181 // LRU eviction pattern. Most recently used might be blocked by 184 // LRU eviction pattern. Most recently used might be blocked by
182 // a read lock fence but it's still better to evict the least 185 // a read lock fence but it's still better to evict the least
183 // recently used as it prevents a resource that is hard to reuse 186 // recently used as it prevents a resource that is hard to reuse
184 // because of unique size from being kept around. Resources that 187 // because of unique size from being kept around. Resources that
185 // can't be locked for write might also not be truly free-able. 188 // can't be locked for write might also not be truly free-able.
186 // We can free the resource here but it doesn't mean that the 189 // We can free the resource here but it doesn't mean that the
187 // memory is necessarily returned to the OS. 190 // memory is necessarily returned to the OS.
188 DeleteResource(unused_resources_.take_front()); 191 DeleteResource(unused_resources_.take_back());
189 } 192 }
190 } 193 }
191 194
192 bool ResourcePool::ResourceUsageTooHigh() { 195 bool ResourcePool::ResourceUsageTooHigh() {
193 if (total_resource_count_ > max_resource_count_) 196 if (total_resource_count_ > max_resource_count_)
194 return true; 197 return true;
195 if (total_memory_usage_bytes_ > max_memory_usage_bytes_) 198 if (total_memory_usage_bytes_ > max_memory_usage_bytes_)
196 return true; 199 return true;
197 return false; 200 return false;
198 } 201 }
(...skipping 15 matching lines...) Expand all
214 } else if (resource_provider_->IsLost(resource->id())) { 217 } else if (resource_provider_->IsLost(resource->id())) {
215 // Remove lost resources from pool. 218 // Remove lost resources from pool.
216 DeleteResource(busy_resources_.take(it)); 219 DeleteResource(busy_resources_.take(it));
217 } else { 220 } else {
218 ++i; 221 ++i;
219 } 222 }
220 } 223 }
221 } 224 }
222 225
223 void ResourcePool::DidFinishUsingResource(scoped_ptr<PoolResource> resource) { 226 void ResourcePool::DidFinishUsingResource(scoped_ptr<PoolResource> resource) {
224 unused_resources_.push_back(resource.Pass()); 227 unused_resources_.push_front(resource.Pass());
225 } 228 }
226 229
227 void ResourcePool::ScheduleEvictExpiredResourcesIn( 230 void ResourcePool::ScheduleEvictExpiredResourcesIn(
228 base::TimeDelta time_from_now) { 231 base::TimeDelta time_from_now) {
229 if (evict_expired_resources_pending_) 232 if (evict_expired_resources_pending_)
230 return; 233 return;
231 234
232 evict_expired_resources_pending_ = true; 235 evict_expired_resources_pending_ = true;
233 236
234 task_runner_->PostDelayedTask(FROM_HERE, 237 task_runner_->PostDelayedTask(FROM_HERE,
(...skipping 18 matching lines...) Expand all
253 ScheduleEvictExpiredResourcesIn(GetUsageTimeForLRUResource() + 256 ScheduleEvictExpiredResourcesIn(GetUsageTimeForLRUResource() +
254 resource_expiration_delay_ - current_time); 257 resource_expiration_delay_ - current_time);
255 } 258 }
256 259
257 void ResourcePool::EvictResourcesNotUsedSince(base::TimeTicks time_limit) { 260 void ResourcePool::EvictResourcesNotUsedSince(base::TimeTicks time_limit) {
258 while (!unused_resources_.empty()) { 261 while (!unused_resources_.empty()) {
259 // |unused_resources_| is not strictly ordered with regards to last_usage, 262 // |unused_resources_| is not strictly ordered with regards to last_usage,
260 // as this may not exactly line up with the time a resource became non-busy. 263 // as this may not exactly line up with the time a resource became non-busy.
261 // However, this should be roughly ordered, and will only introduce slight 264 // However, this should be roughly ordered, and will only introduce slight
262 // delays in freeing expired resources. 265 // delays in freeing expired resources.
263 if (unused_resources_.front()->last_usage() > time_limit) 266 if (unused_resources_.back()->last_usage() > time_limit)
264 return; 267 return;
265 268
266 DeleteResource(unused_resources_.take_front()); 269 DeleteResource(unused_resources_.take_back());
267 } 270 }
268 271
269 // Also free busy resources older than the delay. With a sufficiently large 272 // Also free busy resources older than the delay. With a sufficiently large
270 // delay, such as the 1 second used here, any "busy" resources which have 273 // delay, such as the 1 second used here, any "busy" resources which have
271 // expired are not likely to be busy. Additionally, freeing a "busy" resource 274 // expired are not likely to be busy. Additionally, freeing a "busy" resource
272 // has no downside other than incorrect accounting. 275 // has no downside other than incorrect accounting.
273 while (!busy_resources_.empty()) { 276 while (!busy_resources_.empty()) {
274 if (busy_resources_.front()->last_usage() > time_limit) 277 if (busy_resources_.back()->last_usage() > time_limit)
275 return; 278 return;
276 279
277 DeleteResource(busy_resources_.take_front()); 280 DeleteResource(busy_resources_.take_back());
278 } 281 }
279 } 282 }
280 283
281 base::TimeTicks ResourcePool::GetUsageTimeForLRUResource() const { 284 base::TimeTicks ResourcePool::GetUsageTimeForLRUResource() const {
282 if (!unused_resources_.empty()) { 285 if (!unused_resources_.empty()) {
283 return unused_resources_.front()->last_usage(); 286 return unused_resources_.back()->last_usage();
284 } 287 }
285 288
286 // This is only called when we have at least one evictable resource. 289 // This is only called when we have at least one evictable resource.
287 DCHECK(!busy_resources_.empty()); 290 DCHECK(!busy_resources_.empty());
288 return busy_resources_.front()->last_usage(); 291 return busy_resources_.back()->last_usage();
289 } 292 }
290 293
291 bool ResourcePool::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, 294 bool ResourcePool::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
292 base::trace_event::ProcessMemoryDump* pmd) { 295 base::trace_event::ProcessMemoryDump* pmd) {
293 for (const auto& resource : unused_resources_) { 296 for (const auto& resource : unused_resources_) {
294 resource->OnMemoryDump(pmd, resource_provider_, true /* is_free */); 297 resource->OnMemoryDump(pmd, resource_provider_, true /* is_free */);
295 } 298 }
296 for (const auto& resource : busy_resources_) { 299 for (const auto& resource : busy_resources_) {
297 resource->OnMemoryDump(pmd, resource_provider_, false /* is_free */); 300 resource->OnMemoryDump(pmd, resource_provider_, false /* is_free */);
298 } 301 }
299 for (const auto& entry : in_use_resources_) { 302 for (const auto& entry : in_use_resources_) {
300 entry.second->OnMemoryDump(pmd, resource_provider_, false /* is_free */); 303 entry.second->OnMemoryDump(pmd, resource_provider_, false /* is_free */);
301 } 304 }
302 return true; 305 return true;
303 } 306 }
304 307
305 } // namespace cc 308 } // namespace cc
OLDNEW
« no previous file with comments | « cc/resources/resource_pool.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698