summaryrefslogtreecommitdiffstats
path: root/cc
diff options
context:
space:
mode:
authorreveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-16 05:47:59 +0000
committerreveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-16 05:47:59 +0000
commitd069439a2f947e1af88863ec3d9699c6fbafc261 (patch)
tree334682075751607ab3fa921778242bec87045cbd /cc
parentb168871584f817ee586b5482bec6b4876ea66da7 (diff)
downloadchromium_src-d069439a2f947e1af88863ec3d9699c6fbafc261.zip
chromium_src-d069439a2f947e1af88863ec3d9699c6fbafc261.tar.gz
chromium_src-d069439a2f947e1af88863ec3d9699c6fbafc261.tar.bz2
cc: Prevent the tile manager from allocating more memory than allowed.
This adds a new ReduceMemoryUsage function to the resource pool. By calling this function in TileManager::ScheduleTasks after creating all resources needed to to call RasterWorkerPool::ScheduleTasks we free enough unused resources to ensure that we never go above the limit. This also fixes the use of the num_resources_limit by correctly accounting for all allocated resources. BUG=273140 TEST=cc_unittests --gtest_filter=TileManagerTests/TileManagerTest.RespectMemoryLimit* Review URL: https://chromiumcodereview.appspot.com/23231002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@217951 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r--cc/resources/resource_pool.cc43
-rw-r--r--cc/resources/resource_pool.h19
-rw-r--r--cc/resources/tile_manager.cc13
-rw-r--r--cc/resources/tile_manager_unittest.cc62
-rw-r--r--cc/test/fake_tile_manager.cc23
5 files changed, 126 insertions, 34 deletions
diff --git a/cc/resources/resource_pool.cc b/cc/resources/resource_pool.cc
index 5835db5..06bc1fb 100644
--- a/cc/resources/resource_pool.cc
+++ b/cc/resources/resource_pool.cc
@@ -31,19 +31,20 @@ ResourcePool::ResourcePool(ResourceProvider* resource_provider)
: resource_provider_(resource_provider),
max_memory_usage_bytes_(0),
max_unused_memory_usage_bytes_(0),
+ max_resource_count_(0),
memory_usage_bytes_(0),
unused_memory_usage_bytes_(0),
- num_resources_limit_(0) {
+ resource_count_(0) {
}
ResourcePool::~ResourcePool() {
- SetMemoryUsageLimits(0, 0, 0);
+ SetResourceUsageLimits(0, 0, 0);
}
scoped_ptr<ResourcePool::Resource> ResourcePool::AcquireResource(
gfx::Size size, GLenum format) {
- for (ResourceList::iterator it = resources_.begin();
- it != resources_.end(); ++it) {
+ for (ResourceList::iterator it = unused_resources_.begin();
+ it != unused_resources_.end(); ++it) {
Resource* resource = *it;
// TODO(epenner): It would be nice to DCHECK that this
@@ -57,14 +58,13 @@ scoped_ptr<ResourcePool::Resource> ResourcePool::AcquireResource(
if (resource->format() != format)
continue;
- resources_.erase(it);
+ unused_resources_.erase(it);
unused_memory_usage_bytes_ -= resource->bytes();
return make_scoped_ptr(resource);
}
// Create new resource.
- Resource* resource = new Resource(
- resource_provider_, size, format);
+ Resource* resource = new Resource(resource_provider_, size, format);
// Extend all read locks on all resources until the resource is
// finished being used, such that we know when resources are
@@ -72,44 +72,51 @@ scoped_ptr<ResourcePool::Resource> ResourcePool::AcquireResource(
resource_provider_->EnableReadLockFences(resource->id(), true);
memory_usage_bytes_ += resource->bytes();
+ ++resource_count_;
return make_scoped_ptr(resource);
}
void ResourcePool::ReleaseResource(
scoped_ptr<ResourcePool::Resource> resource) {
- if (MemoryUsageTooHigh()) {
+ if (ResourceUsageTooHigh()) {
memory_usage_bytes_ -= resource->bytes();
+ --resource_count_;
return;
}
unused_memory_usage_bytes_ += resource->bytes();
- resources_.push_back(resource.release());
+ unused_resources_.push_back(resource.release());
}
-void ResourcePool::SetMemoryUsageLimits(
+void ResourcePool::SetResourceUsageLimits(
size_t max_memory_usage_bytes,
size_t max_unused_memory_usage_bytes,
- size_t num_resources_limit) {
+ size_t max_resource_count) {
max_memory_usage_bytes_ = max_memory_usage_bytes;
max_unused_memory_usage_bytes_ = max_unused_memory_usage_bytes;
- num_resources_limit_ = num_resources_limit;
+ max_resource_count_ = max_resource_count;
- while (!resources_.empty()) {
- if (!MemoryUsageTooHigh())
+ ReduceResourceUsage();
+}
+
+void ResourcePool::ReduceResourceUsage() {
+ while (!unused_resources_.empty()) {
+ if (!ResourceUsageTooHigh())
break;
// MRU eviction pattern as least recently used is less likely to
// be blocked by read lock fence.
- Resource* resource = resources_.back();
- resources_.pop_back();
+ Resource* resource = unused_resources_.back();
+ unused_resources_.pop_back();
memory_usage_bytes_ -= resource->bytes();
unused_memory_usage_bytes_ -= resource->bytes();
+ --resource_count_;
delete resource;
}
}
-bool ResourcePool::MemoryUsageTooHigh() {
- if (resources_.size() > num_resources_limit_)
+bool ResourcePool::ResourceUsageTooHigh() {
+ if (resource_count_ > max_resource_count_)
return true;
if (memory_usage_bytes_ > max_memory_usage_bytes_)
return true;
diff --git a/cc/resources/resource_pool.h b/cc/resources/resource_pool.h
index 309bf33..771650e 100644
--- a/cc/resources/resource_pool.h
+++ b/cc/resources/resource_pool.h
@@ -40,9 +40,11 @@ class CC_EXPORT ResourcePool {
GLenum format);
void ReleaseResource(scoped_ptr<ResourcePool::Resource>);
- void SetMemoryUsageLimits(size_t max_memory_usage_bytes,
- size_t max_unused_memory_usage_bytes,
- size_t num_resources_limit);
+ void SetResourceUsageLimits(size_t max_memory_usage_bytes,
+ size_t max_unused_memory_usage_bytes,
+ size_t max_resource_count);
+
+ void ReduceResourceUsage();
size_t total_memory_usage_bytes() const {
return memory_usage_bytes_;
@@ -50,23 +52,26 @@ class CC_EXPORT ResourcePool {
size_t acquired_memory_usage_bytes() const {
return memory_usage_bytes_ - unused_memory_usage_bytes_;
}
- size_t NumResources() const { return resources_.size(); }
+ size_t acquired_resource_count() const {
+ return resource_count_ - unused_resources_.size();
+ }
protected:
explicit ResourcePool(ResourceProvider* resource_provider);
- bool MemoryUsageTooHigh();
+ bool ResourceUsageTooHigh();
private:
ResourceProvider* resource_provider_;
size_t max_memory_usage_bytes_;
size_t max_unused_memory_usage_bytes_;
+ size_t max_resource_count_;
size_t memory_usage_bytes_;
size_t unused_memory_usage_bytes_;
- size_t num_resources_limit_;
+ size_t resource_count_;
typedef std::list<Resource*> ResourceList;
- ResourceList resources_;
+ ResourceList unused_resources_;
DISALLOW_COPY_AND_ASSIGN(ResourcePool);
};
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index 86de610..cff5883 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -180,7 +180,7 @@ TileManager::~TileManager() {
void TileManager::SetGlobalState(
const GlobalStateThatImpactsTilePriority& global_state) {
global_state_ = global_state;
- resource_pool_->SetMemoryUsageLimits(
+ resource_pool_->SetResourceUsageLimits(
global_state_.memory_limit_in_bytes,
global_state_.unused_memory_limit_in_bytes,
global_state_.num_resources_limit);
@@ -499,9 +499,10 @@ void TileManager::AssignGpuMemoryToTiles(
static_cast<int64>(bytes_releasable_) +
static_cast<int64>(global_state_.memory_limit_in_bytes) -
static_cast<int64>(resource_pool_->acquired_memory_usage_bytes());
- int resources_available = resources_releasable_ +
- global_state_.num_resources_limit -
- resource_pool_->NumResources();
+ int resources_available =
+ resources_releasable_ +
+ global_state_.num_resources_limit -
+ resource_pool_->acquired_resource_count();
size_t bytes_allocatable =
std::max(static_cast<int64>(0), bytes_available);
@@ -705,6 +706,10 @@ void TileManager::ScheduleTasks(
tasks.Append(tile_version.raster_task_, tile->required_for_activation());
}
+ // We must reduce the amount of unused resoruces before calling
+ // ScheduleTasks to prevent usage from rising above limits.
+ resource_pool_->ReduceResourceUsage();
+
// Schedule running of |tasks|. This replaces any previously
// scheduled tasks and effectively cancels all tasks not present
// in |tasks|.
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index 5076fb0..d3b9fac 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -44,6 +44,7 @@ class TileManagerTest : public testing::TestWithParam<bool> {
state.memory_limit_in_bytes = 100 * 1000 * 1000;
state.num_resources_limit = max_tiles;
}
+ state.unused_memory_limit_in_bytes = state.memory_limit_in_bytes;
state.memory_limit_policy = memory_limit_policy;
state.tree_priority = tree_priority;
@@ -56,6 +57,7 @@ class TileManagerTest : public testing::TestWithParam<bool> {
gfx::Size tile_size = settings_.default_tile_size;
state.memory_limit_in_bytes =
max_memory_tiles_ * 4 * tile_size.width() * tile_size.height();
+ state.unused_memory_limit_in_bytes = state.memory_limit_in_bytes;
state.memory_limit_policy = memory_limit_policy_;
state.num_resources_limit = 100;
state.tree_priority = tree_priority;
@@ -69,15 +71,16 @@ class TileManagerTest : public testing::TestWithParam<bool> {
testing::Test::TearDown();
}
- TileVector CreateTiles(int count,
- TilePriority active_priority,
- TilePriority pending_priority) {
+ TileVector CreateTilesWithSize(int count,
+ TilePriority active_priority,
+ TilePriority pending_priority,
+ gfx::Size tile_size) {
TileVector tiles;
for (int i = 0; i < count; ++i) {
scoped_refptr<Tile> tile =
make_scoped_refptr(new Tile(tile_manager_.get(),
picture_pile_.get(),
- settings_.default_tile_size,
+ tile_size,
gfx::Rect(),
gfx::Rect(),
1.0,
@@ -91,6 +94,15 @@ class TileManagerTest : public testing::TestWithParam<bool> {
return tiles;
}
+ TileVector CreateTiles(int count,
+ TilePriority active_priority,
+ TilePriority pending_priority) {
+ return CreateTilesWithSize(count,
+ active_priority,
+ pending_priority,
+ settings_.default_tile_size);
+ }
+
FakeTileManager* tile_manager() {
return tile_manager_.get();
}
@@ -465,6 +477,48 @@ TEST_P(TileManagerTest, TextReRasterAsNoLCD) {
EXPECT_EQ(0, TilesWithLCDCount(pending_tree_tiles));
}
+TEST_P(TileManagerTest, RespectMemoryLimit) {
+ Initialize(5, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
+ TileVector large_tiles = CreateTiles(
+ 5, TilePriorityForNowBin(), TilePriority());
+
+ size_t memory_required_bytes;
+ size_t memory_nice_to_have_bytes;
+ size_t memory_allocated_bytes;
+ size_t memory_used_bytes;
+
+ tile_manager()->ManageTiles();
+ tile_manager()->GetMemoryStats(&memory_required_bytes,
+ &memory_nice_to_have_bytes,
+ &memory_allocated_bytes,
+ &memory_used_bytes);
+ // Allocated bytes should never be more than the memory limit.
+ EXPECT_LE(memory_allocated_bytes,
+ tile_manager()->GlobalState().memory_limit_in_bytes);
+
+ // Finish raster of large tiles.
+ tile_manager()->UpdateVisibleTiles();
+
+ // Remove all large tiles. This will leave the memory currently
+ // used by these tiles as unused when ManageTiles() is called.
+ large_tiles.clear();
+
+ // Create a new set of tiles using a different size. These tiles
+ // can use the memory currently assigned to the lerge tiles but
+ // they can't use the same resources as the size doesn't match.
+ TileVector small_tiles = CreateTilesWithSize(
+ 5, TilePriorityForNowBin(), TilePriority(), gfx::Size(128, 128));
+
+ tile_manager()->ManageTiles();
+ tile_manager()->GetMemoryStats(&memory_required_bytes,
+ &memory_nice_to_have_bytes,
+ &memory_allocated_bytes,
+ &memory_used_bytes);
+ // Allocated bytes should never be more than the memory limit.
+ EXPECT_LE(memory_allocated_bytes,
+ tile_manager()->GlobalState().memory_limit_in_bytes);
+}
+
// If true, the max tile limit should be applied as bytes; if false,
// as num_resources_limit.
INSTANTIATE_TEST_CASE_P(TileManagerTests,
diff --git a/cc/test/fake_tile_manager.cc b/cc/test/fake_tile_manager.cc
index c132254..9e9e48a 100644
--- a/cc/test/fake_tile_manager.cc
+++ b/cc/test/fake_tile_manager.cc
@@ -4,6 +4,8 @@
#include "cc/test/fake_tile_manager.h"
+#include <deque>
+
#include "cc/resources/raster_worker_pool.h"
namespace cc {
@@ -14,9 +16,28 @@ class FakeRasterWorkerPool : public RasterWorkerPool {
public:
FakeRasterWorkerPool() : RasterWorkerPool(NULL, 1) {}
- virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE {}
+ virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE {
+ RasterWorkerPool::SetRasterTasks(queue);
+ for (RasterTaskVector::const_iterator it = raster_tasks().begin();
+ it != raster_tasks().end(); ++it) {
+ completed_tasks_.push_back(it->get());
+ }
+ }
+ virtual void CheckForCompletedTasks() OVERRIDE {
+ while (!completed_tasks_.empty()) {
+ internal::RasterWorkerPoolTask* task = completed_tasks_.front().get();
+ task->WillComplete();
+ task->CompleteOnOriginThread();
+ task->DidComplete();
+ completed_tasks_.pop_front();
+ }
+ }
virtual void OnRasterTasksFinished() OVERRIDE {}
virtual void OnRasterTasksRequiredForActivationFinished() OVERRIDE {}
+
+ private:
+ typedef std::deque<scoped_refptr<internal::RasterWorkerPoolTask> > TaskDeque;
+ TaskDeque completed_tasks_;
};
} // namespace