| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |