| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/common/gpu/gpu_memory_manager.h" |
| #include "content/common/gpu/gpu_memory_manager_client.h" |
| #include "content/common/gpu/gpu_memory_tracking.h" |
| #include "gpu/command_buffer/common/gpu_memory_allocation.h" |
| #include "ui/gfx/size_conversions.h" |
| |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using gpu::MemoryAllocation; |
| using gpu::ManagedMemoryStats; |
| |
| #if defined(COMPILER_GCC) |
| namespace BASE_HASH_NAMESPACE { |
| template<> |
| struct hash<content::GpuMemoryManagerClient*> { |
| uint64 operator()(content::GpuMemoryManagerClient* ptr) const { |
| return hash<uint64>()(reinterpret_cast<uint64>(ptr)); |
| } |
| }; |
| } // namespace BASE_HASH_NAMESPACE |
| #endif // COMPILER |
| |
| class FakeMemoryTracker : public gpu::gles2::MemoryTracker { |
| public: |
| virtual void TrackMemoryAllocatedChange( |
| size_t /* old_size */, |
| size_t /* new_size */, |
| gpu::gles2::MemoryTracker::Pool /* pool */) OVERRIDE { |
| } |
| virtual bool EnsureGPUMemoryAvailable(size_t /* size_needed */) OVERRIDE { |
| return true; |
| } |
| private: |
| virtual ~FakeMemoryTracker() { |
| } |
| }; |
| |
| namespace content { |
| |
| // This class is used to collect all stub assignments during a |
| // Manage() call. |
| class ClientAssignmentCollector { |
| public: |
| struct ClientMemoryStat { |
| MemoryAllocation allocation; |
| }; |
| typedef base::hash_map<GpuMemoryManagerClient*, ClientMemoryStat> |
| ClientMemoryStatMap; |
| |
| static const ClientMemoryStatMap& GetClientStatsForLastManage() { |
| return client_memory_stats_for_last_manage_; |
| } |
| static void ClearAllStats() { |
| client_memory_stats_for_last_manage_.clear(); |
| } |
| static void AddClientStat(GpuMemoryManagerClient* client, |
| const MemoryAllocation& allocation) { |
| DCHECK(!client_memory_stats_for_last_manage_.count(client)); |
| client_memory_stats_for_last_manage_[client].allocation = allocation; |
| } |
| |
| private: |
| static ClientMemoryStatMap client_memory_stats_for_last_manage_; |
| }; |
| |
| ClientAssignmentCollector::ClientMemoryStatMap |
| ClientAssignmentCollector::client_memory_stats_for_last_manage_; |
| |
| class FakeClient : public GpuMemoryManagerClient { |
| public: |
| GpuMemoryManager* memmgr_; |
| bool suggest_have_frontbuffer_; |
| MemoryAllocation allocation_; |
| uint64 total_gpu_memory_; |
| gfx::Size surface_size_; |
| GpuMemoryManagerClient* share_group_; |
| scoped_refptr<gpu::gles2::MemoryTracker> memory_tracker_; |
| scoped_ptr<GpuMemoryTrackingGroup> tracking_group_; |
| scoped_ptr<GpuMemoryManagerClientState> client_state_; |
| |
| // This will create a client with no surface |
| FakeClient(GpuMemoryManager* memmgr, GpuMemoryManagerClient* share_group) |
| : memmgr_(memmgr), |
| suggest_have_frontbuffer_(false), |
| total_gpu_memory_(0), |
| share_group_(share_group), |
| memory_tracker_(NULL) { |
| if (!share_group_) { |
| memory_tracker_ = new FakeMemoryTracker(); |
| tracking_group_.reset( |
| memmgr_->CreateTrackingGroup(0, memory_tracker_.get())); |
| } |
| client_state_.reset(memmgr_->CreateClientState(this, false, true)); |
| } |
| |
| // This will create a client with a surface |
| FakeClient(GpuMemoryManager* memmgr, int32 surface_id, bool visible) |
| : memmgr_(memmgr), |
| suggest_have_frontbuffer_(false), |
| total_gpu_memory_(0), |
| share_group_(NULL), |
| memory_tracker_(NULL) { |
| memory_tracker_ = new FakeMemoryTracker(); |
| tracking_group_.reset( |
| memmgr_->CreateTrackingGroup(0, memory_tracker_.get())); |
| client_state_.reset( |
| memmgr_->CreateClientState(this, surface_id != 0, visible)); |
| } |
| |
| virtual ~FakeClient() { |
| client_state_.reset(); |
| tracking_group_.reset(); |
| memory_tracker_ = NULL; |
| } |
| |
| virtual void SetMemoryAllocation(const MemoryAllocation& alloc) OVERRIDE { |
| allocation_ = alloc; |
| ClientAssignmentCollector::AddClientStat(this, alloc); |
| } |
| |
| virtual void SuggestHaveFrontBuffer(bool suggest_have_frontbuffer) OVERRIDE { |
| suggest_have_frontbuffer_ = suggest_have_frontbuffer; |
| } |
| |
| virtual bool GetTotalGpuMemory(uint64* bytes) OVERRIDE { |
| if (total_gpu_memory_) { |
| *bytes = total_gpu_memory_; |
| return true; |
| } |
| return false; |
| } |
| void SetTotalGpuMemory(uint64 bytes) { total_gpu_memory_ = bytes; } |
| |
| virtual gpu::gles2::MemoryTracker* GetMemoryTracker() const OVERRIDE { |
| if (share_group_) |
| return share_group_->GetMemoryTracker(); |
| return memory_tracker_.get(); |
| } |
| |
| virtual gfx::Size GetSurfaceSize() const OVERRIDE { |
| return surface_size_; |
| } |
| void SetSurfaceSize(gfx::Size size) { surface_size_ = size; } |
| |
| void SetVisible(bool visible) { |
| client_state_->SetVisible(visible); |
| } |
| |
| void SetManagedMemoryStats(const ManagedMemoryStats& stats) { |
| client_state_->SetManagedMemoryStats(stats); |
| } |
| |
| uint64 BytesWhenVisible() const { |
| return allocation_.bytes_limit_when_visible; |
| } |
| |
| uint64 BytesWhenNotVisible() const { |
| return allocation_.bytes_limit_when_not_visible; |
| } |
| }; |
| |
| class GpuMemoryManagerTest : public testing::Test { |
| protected: |
| static const uint64 kFrontbufferLimitForTest = 3; |
| |
| GpuMemoryManagerTest() |
| : memmgr_(0, kFrontbufferLimitForTest) { |
| memmgr_.TestingDisableScheduleManage(); |
| memmgr_.allow_nonvisible_memory_ = true; |
| } |
| |
| virtual void SetUp() { |
| } |
| |
| static int32 GenerateUniqueSurfaceId() { |
| static int32 surface_id_ = 1; |
| return surface_id_++; |
| } |
| |
| bool IsAllocationForegroundForSurfaceYes( |
| const MemoryAllocation& alloc) { |
| return !alloc.have_backbuffer_when_not_visible; |
| } |
| bool IsAllocationBackgroundForSurfaceYes( |
| const MemoryAllocation& alloc) { |
| return !alloc.have_backbuffer_when_not_visible; |
| } |
| bool IsAllocationHibernatedForSurfaceYes( |
| const MemoryAllocation& alloc) { |
| return !alloc.have_backbuffer_when_not_visible; |
| } |
| bool IsAllocationForegroundForSurfaceNo( |
| const MemoryAllocation& alloc) { |
| return !alloc.have_backbuffer_when_not_visible && |
| alloc.bytes_limit_when_visible == |
| GetMinimumClientAllocation(); |
| } |
| bool IsAllocationBackgroundForSurfaceNo( |
| const MemoryAllocation& alloc) { |
| return !alloc.have_backbuffer_when_not_visible && |
| alloc.bytes_limit_when_visible == |
| GetMinimumClientAllocation(); |
| } |
| bool IsAllocationHibernatedForSurfaceNo( |
| const MemoryAllocation& alloc) { |
| return !alloc.have_backbuffer_when_not_visible && |
| alloc.bytes_limit_when_visible == 0; |
| } |
| |
| void Manage() { |
| ClientAssignmentCollector::ClearAllStats(); |
| memmgr_.Manage(); |
| } |
| |
| uint64 CalcAvailableFromGpuTotal(uint64 bytes) { |
| return GpuMemoryManager::CalcAvailableFromGpuTotal(bytes); |
| } |
| |
| uint64 CalcAvailableClamped(uint64 bytes) { |
| bytes = std::max(bytes, memmgr_.GetDefaultAvailableGpuMemory()); |
| bytes = std::min(bytes, memmgr_.GetMaximumTotalGpuMemory()); |
| return bytes; |
| } |
| |
| uint64 GetAvailableGpuMemory() { |
| return memmgr_.GetAvailableGpuMemory(); |
| } |
| |
| uint64 GetMaximumClientAllocation() { |
| return memmgr_.GetMaximumClientAllocation(); |
| } |
| |
| uint64 GetMinimumClientAllocation() { |
| return memmgr_.GetMinimumClientAllocation(); |
| } |
| |
| void SetClientStats( |
| FakeClient* client, |
| uint64 required, |
| uint64 nicetohave) { |
| client->SetManagedMemoryStats( |
| ManagedMemoryStats(required, nicetohave, 0, false)); |
| } |
| |
| GpuMemoryManager memmgr_; |
| }; |
| |
| // Test GpuMemoryManager::Manage basic functionality. |
| // Expect memory allocation to set suggest_have_frontbuffer/backbuffer |
| // according to visibility and last used time for stubs with surface. |
| // Expect memory allocation to be shared according to share groups for stubs |
| // without a surface. |
| TEST_F(GpuMemoryManagerTest, TestManageBasicFunctionality) { |
| // Test stubs with surface. |
| FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub2(&memmgr_, GenerateUniqueSurfaceId(), false); |
| |
| Manage(); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); |
| |
| // Test stubs without surface, with share group of 1 stub. |
| FakeClient stub3(&memmgr_, &stub1), stub4(&memmgr_, &stub2); |
| |
| Manage(); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub3.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4.allocation_)); |
| |
| // Test stub without surface, with share group of multiple stubs. |
| FakeClient stub5(&memmgr_ , &stub2); |
| |
| Manage(); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4.allocation_)); |
| } |
| |
| // Test GpuMemoryManager::Manage functionality: changing visibility. |
| // Expect memory allocation to set suggest_have_frontbuffer/backbuffer |
| // according to visibility and last used time for stubs with surface. |
| // Expect memory allocation to be shared according to share groups for stubs |
| // without a surface. |
| TEST_F(GpuMemoryManagerTest, TestManageChangingVisibility) { |
| FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub2(&memmgr_, GenerateUniqueSurfaceId(), false); |
| |
| FakeClient stub3(&memmgr_, &stub1), stub4(&memmgr_, &stub2); |
| FakeClient stub5(&memmgr_ , &stub2); |
| |
| Manage(); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub3.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub5.allocation_)); |
| |
| stub1.SetVisible(false); |
| stub2.SetVisible(true); |
| |
| Manage(); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub5.allocation_)); |
| } |
| |
| // Test GpuMemoryManager::Manage functionality: Test more than threshold number |
| // of visible stubs. |
| // Expect all allocations to continue to have frontbuffer. |
| TEST_F(GpuMemoryManagerTest, TestManageManyVisibleStubs) { |
| FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub2(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub3(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub4(&memmgr_, GenerateUniqueSurfaceId(), true); |
| |
| FakeClient stub5(&memmgr_ , &stub1), stub6(&memmgr_ , &stub2); |
| FakeClient stub7(&memmgr_ , &stub2); |
| |
| Manage(); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub3.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub4.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub5.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub6.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub7.allocation_)); |
| } |
| |
| // Test GpuMemoryManager::Manage functionality: Test more than threshold number |
| // of not visible stubs. |
| // Expect the stubs surpassing the threshold to not have a backbuffer. |
| TEST_F(GpuMemoryManagerTest, TestManageManyNotVisibleStubs) { |
| FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub2(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub3(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub4(&memmgr_, GenerateUniqueSurfaceId(), true); |
| stub4.SetVisible(false); |
| stub3.SetVisible(false); |
| stub2.SetVisible(false); |
| stub1.SetVisible(false); |
| |
| FakeClient stub5(&memmgr_ , &stub1), stub6(&memmgr_ , &stub4); |
| FakeClient stub7(&memmgr_ , &stub1); |
| |
| Manage(); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub3.allocation_)); |
| EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub4.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub5.allocation_)); |
| EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub6.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub7.allocation_)); |
| } |
| |
| // Test GpuMemoryManager::Manage functionality: Test changing the last used |
| // time of stubs when doing so causes change in which stubs surpass threshold. |
| // Expect frontbuffer to be dropped for the older stub. |
| TEST_F(GpuMemoryManagerTest, TestManageChangingLastUsedTime) { |
| FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub2(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub3(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub4(&memmgr_, GenerateUniqueSurfaceId(), true); |
| |
| FakeClient stub5(&memmgr_ , &stub3), stub6(&memmgr_ , &stub4); |
| FakeClient stub7(&memmgr_ , &stub3); |
| |
| // Make stub4 be the least-recently-used client |
| stub4.SetVisible(false); |
| stub3.SetVisible(false); |
| stub2.SetVisible(false); |
| stub1.SetVisible(false); |
| |
| Manage(); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub3.allocation_)); |
| EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub4.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub5.allocation_)); |
| EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub6.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub7.allocation_)); |
| |
| // Make stub3 become the least-recently-used client. |
| stub2.SetVisible(true); |
| stub2.SetVisible(false); |
| stub4.SetVisible(true); |
| stub4.SetVisible(false); |
| |
| Manage(); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); |
| EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub3.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub4.allocation_)); |
| EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub5.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub6.allocation_)); |
| EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub7.allocation_)); |
| } |
| |
| // Test GpuMemoryManager::Manage functionality: Test changing importance of |
| // enough stubs so that every stub in share group crosses threshold. |
| // Expect memory allocation of the stubs without surface to share memory |
| // allocation with the most visible stub in share group. |
| TEST_F(GpuMemoryManagerTest, TestManageChangingImportanceShareGroup) { |
| FakeClient stub_ignore_a(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub_ignore_b(&memmgr_, GenerateUniqueSurfaceId(), false), |
| stub_ignore_c(&memmgr_, GenerateUniqueSurfaceId(), false); |
| FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), false), |
| stub2(&memmgr_, GenerateUniqueSurfaceId(), false); |
| |
| FakeClient stub3(&memmgr_, &stub2), stub4(&memmgr_, &stub2); |
| |
| // stub1 and stub2 keep their non-hibernated state because they're |
| // either visible or the 2 most recently used clients (through the |
| // first three checks). |
| stub1.SetVisible(true); |
| stub2.SetVisible(true); |
| Manage(); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub3.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4.allocation_)); |
| |
| stub1.SetVisible(false); |
| Manage(); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3.allocation_)); |
| EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4.allocation_)); |
| |
| stub2.SetVisible(false); |
| Manage(); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4.allocation_)); |
| |
| // stub_ignore_b will cause stub1 to become hibernated (because |
| // stub_ignore_a, stub_ignore_b, and stub2 are all non-hibernated and more |
| // important). |
| stub_ignore_b.SetVisible(true); |
| stub_ignore_b.SetVisible(false); |
| Manage(); |
| EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub1.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3.allocation_)); |
| EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4.allocation_)); |
| |
| // stub_ignore_c will cause stub2 to become hibernated (because |
| // stub_ignore_a, stub_ignore_b, and stub_ignore_c are all non-hibernated |
| // and more important). |
| stub_ignore_c.SetVisible(true); |
| stub_ignore_c.SetVisible(false); |
| Manage(); |
| EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub1.allocation_)); |
| EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub2.allocation_)); |
| EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub3.allocation_)); |
| EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub4.allocation_)); |
| } |
| |
| // Test GpuMemoryManager::UpdateAvailableGpuMemory functionality |
| TEST_F(GpuMemoryManagerTest, TestUpdateAvailableGpuMemory) { |
| FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub2(&memmgr_, GenerateUniqueSurfaceId(), false), |
| stub3(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub4(&memmgr_, GenerateUniqueSurfaceId(), false); |
| // We take the lowest GPU's total memory as the limit |
| uint64 expected = 400 * 1024 * 1024; |
| stub1.SetTotalGpuMemory(expected); // GPU Memory |
| stub2.SetTotalGpuMemory(expected - 1024 * 1024); // Smaller but not visible. |
| stub3.SetTotalGpuMemory(expected + 1024 * 1024); // Visible but larger. |
| stub4.SetTotalGpuMemory(expected + 1024 * 1024); // Not visible and larger. |
| Manage(); |
| uint64 bytes_expected = CalcAvailableFromGpuTotal(expected); |
| EXPECT_EQ(GetAvailableGpuMemory(), CalcAvailableClamped(bytes_expected)); |
| } |
| |
| // Test GpuMemoryManager Stub Memory Stats functionality: |
| // Creates various surface/non-surface stubs and switches stub visibility and |
| // tests to see that stats data structure values are correct. |
| TEST_F(GpuMemoryManagerTest, StubMemoryStatsForLastManageTests) { |
| ClientAssignmentCollector::ClientMemoryStatMap stats; |
| |
| Manage(); |
| stats = ClientAssignmentCollector::GetClientStatsForLastManage(); |
| EXPECT_EQ(stats.size(), 0ul); |
| |
| FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true); |
| Manage(); |
| stats = ClientAssignmentCollector::GetClientStatsForLastManage(); |
| uint64 stub1allocation1 = |
| stats[&stub1].allocation.bytes_limit_when_visible; |
| |
| EXPECT_EQ(stats.size(), 1ul); |
| EXPECT_GT(stub1allocation1, 0ul); |
| |
| FakeClient stub2(&memmgr_, &stub1); |
| Manage(); |
| stats = ClientAssignmentCollector::GetClientStatsForLastManage(); |
| EXPECT_EQ(stats.count(&stub1), 1ul); |
| uint64 stub1allocation2 = |
| stats[&stub1].allocation.bytes_limit_when_visible; |
| EXPECT_EQ(stats.count(&stub2), 1ul); |
| uint64 stub2allocation2 = |
| stats[&stub2].allocation.bytes_limit_when_visible; |
| |
| EXPECT_EQ(stats.size(), 2ul); |
| EXPECT_GT(stub1allocation2, 0ul); |
| EXPECT_GT(stub2allocation2, 0ul); |
| if (stub1allocation2 != GetMaximumClientAllocation()) |
| EXPECT_LT(stub1allocation2, stub1allocation1); |
| |
| FakeClient stub3(&memmgr_, GenerateUniqueSurfaceId(), true); |
| Manage(); |
| stats = ClientAssignmentCollector::GetClientStatsForLastManage(); |
| uint64 stub1allocation3 = |
| stats[&stub1].allocation.bytes_limit_when_visible; |
| uint64 stub2allocation3 = |
| stats[&stub2].allocation.bytes_limit_when_visible; |
| uint64 stub3allocation3 = |
| stats[&stub3].allocation.bytes_limit_when_visible; |
| |
| EXPECT_EQ(stats.size(), 3ul); |
| EXPECT_GT(stub1allocation3, 0ul); |
| EXPECT_GT(stub2allocation3, 0ul); |
| EXPECT_GT(stub3allocation3, 0ul); |
| if (stub1allocation3 != GetMaximumClientAllocation()) |
| EXPECT_LT(stub1allocation3, stub1allocation2); |
| |
| stub1.SetVisible(false); |
| |
| Manage(); |
| stats = ClientAssignmentCollector::GetClientStatsForLastManage(); |
| uint64 stub1allocation4 = |
| stats[&stub1].allocation.bytes_limit_when_visible; |
| uint64 stub2allocation4 = |
| stats[&stub2].allocation.bytes_limit_when_visible; |
| uint64 stub3allocation4 = |
| stats[&stub3].allocation.bytes_limit_when_visible; |
| |
| EXPECT_EQ(stats.size(), 3ul); |
| EXPECT_GT(stub1allocation4, 0ul); |
| EXPECT_GE(stub2allocation4, 0ul); |
| EXPECT_GT(stub3allocation4, 0ul); |
| if (stub3allocation3 != GetMaximumClientAllocation()) |
| EXPECT_GT(stub3allocation4, stub3allocation3); |
| } |
| |
| // Test GpuMemoryManager's managed memory tracking |
| TEST_F(GpuMemoryManagerTest, TestManagedUsageTracking) { |
| FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub2(&memmgr_, GenerateUniqueSurfaceId(), false); |
| EXPECT_EQ(0ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(0ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| |
| // Set memory allocations and verify the results are reflected. |
| stub1.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 5, false)); |
| stub2.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 7, false)); |
| EXPECT_EQ(5ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(7ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| |
| // Remove a visible client |
| stub1.client_state_.reset(); |
| EXPECT_EQ(0ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(7ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| EXPECT_EQ(0ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(7ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| stub1.client_state_.reset(memmgr_.CreateClientState(&stub1, true, true)); |
| EXPECT_EQ(0ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(7ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| stub1.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 5, false)); |
| EXPECT_EQ(5ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(7ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| |
| // Remove a nonvisible client |
| stub2.client_state_.reset(); |
| EXPECT_EQ(5ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(0ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| EXPECT_EQ(5ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(0ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| stub2.client_state_.reset(memmgr_.CreateClientState(&stub2, true, false)); |
| EXPECT_EQ(5ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(0ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| stub2.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 7, false)); |
| EXPECT_EQ(5ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(7ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| |
| // Create and then destroy some stubs, and verify their allocations go away. |
| { |
| FakeClient stub3(&memmgr_, GenerateUniqueSurfaceId(), true), |
| stub4(&memmgr_, GenerateUniqueSurfaceId(), false); |
| stub3.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 1, false)); |
| stub4.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 2, false)); |
| EXPECT_EQ(6ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(9ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| } |
| EXPECT_EQ(5ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(7ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| |
| // Do no-op changes to stubs' visibility and make sure nothing chnages. |
| stub1.SetVisible(true); |
| stub2.SetVisible(false); |
| EXPECT_EQ(5ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(7ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| |
| // Change visbility state. |
| stub1.SetVisible(false); |
| stub2.SetVisible(true); |
| EXPECT_EQ(7ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(5ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| |
| // Increase allocation amounts. |
| stub1.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 6, false)); |
| stub2.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 8, false)); |
| EXPECT_EQ(8ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(6ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| |
| // Decrease allocation amounts. |
| stub1.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 4, false)); |
| stub2.SetManagedMemoryStats(ManagedMemoryStats(0, 0, 6, false)); |
| EXPECT_EQ(6ul, memmgr_.bytes_allocated_managed_visible_); |
| EXPECT_EQ(4ul, memmgr_.bytes_allocated_managed_nonvisible_); |
| } |
| |
| // Test nonvisible MRU behavior (the most recently used nonvisible clients |
| // keep their contents). |
| TEST_F(GpuMemoryManagerTest, BackgroundMru) { |
| // Set memory manager constants for this test. Note that the budget |
| // for backgrounded content will be 64/4 = 16. |
| memmgr_.TestingSetAvailableGpuMemory(64); |
| memmgr_.TestingSetMinimumClientAllocation(8); |
| |
| uint64 bytes_when_not_visible_expected = 6u; |
| |
| FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true); |
| FakeClient stub2(&memmgr_, GenerateUniqueSurfaceId(), true); |
| FakeClient stub3(&memmgr_, GenerateUniqueSurfaceId(), true); |
| |
| // When all are visible, they should all be allowed to have memory |
| // should they become nonvisible. |
| SetClientStats(&stub1, 6, 23); |
| SetClientStats(&stub2, 6, 23); |
| SetClientStats(&stub3, 6, 23); |
| Manage(); |
| EXPECT_GE(stub1.BytesWhenVisible(), 20u); |
| EXPECT_GE(stub2.BytesWhenVisible(), 20u); |
| EXPECT_GE(stub3.BytesWhenVisible(), 20u); |
| EXPECT_LT(stub1.BytesWhenVisible(), 22u); |
| EXPECT_LT(stub2.BytesWhenVisible(), 22u); |
| EXPECT_LT(stub3.BytesWhenVisible(), 22u); |
| EXPECT_GE(stub1.BytesWhenNotVisible(), bytes_when_not_visible_expected); |
| EXPECT_GE(stub2.BytesWhenNotVisible(), bytes_when_not_visible_expected); |
| EXPECT_GE(stub3.BytesWhenNotVisible(), bytes_when_not_visible_expected); |
| |
| // Background stubs 1 and 2, and they should fit. All stubs should |
| // have their full nicetohave budget should they become visible. |
| stub2.SetVisible(false); |
| stub1.SetVisible(false); |
| Manage(); |
| EXPECT_GE(stub1.BytesWhenVisible(), 23u); |
| EXPECT_GE(stub2.BytesWhenVisible(), 23u); |
| EXPECT_GE(stub3.BytesWhenVisible(), 23u); |
| EXPECT_LT(stub1.BytesWhenVisible(), 32u); |
| EXPECT_LT(stub2.BytesWhenVisible(), 32u); |
| EXPECT_GE(stub1.BytesWhenNotVisible(), bytes_when_not_visible_expected); |
| EXPECT_GE(stub2.BytesWhenNotVisible(), bytes_when_not_visible_expected); |
| EXPECT_GE(stub3.BytesWhenNotVisible(), bytes_when_not_visible_expected); |
| |
| // Now background stub 3, and it should cause stub 2 to be |
| // evicted because it was set non-visible first |
| stub3.SetVisible(false); |
| Manage(); |
| EXPECT_GE(stub1.BytesWhenNotVisible(), bytes_when_not_visible_expected); |
| EXPECT_EQ(stub2.BytesWhenNotVisible(), 0u); |
| EXPECT_GE(stub3.BytesWhenNotVisible(), bytes_when_not_visible_expected); |
| } |
| |
| TEST_F(GpuMemoryManagerTest, AllowNonvisibleMemory) { |
| memmgr_.TestingSetAvailableGpuMemory(512); |
| memmgr_.TestingSetMinimumClientAllocation(16); |
| |
| FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true); |
| FakeClient stub2(&memmgr_, GenerateUniqueSurfaceId(), true); |
| FakeClient stub3(&memmgr_, GenerateUniqueSurfaceId(), true); |
| |
| memmgr_.allow_nonvisible_memory_ = true; |
| stub1.SetVisible(true); |
| SetClientStats(&stub1, 20, 80); |
| SetClientStats(&stub2, 20, 80); |
| SetClientStats(&stub3, 20, 80); |
| Manage(); |
| EXPECT_GT(stub1.BytesWhenNotVisible(), 0u); |
| EXPECT_GT(stub2.BytesWhenNotVisible(), 0u); |
| EXPECT_GT(stub3.BytesWhenNotVisible(), 0u); |
| |
| memmgr_.allow_nonvisible_memory_ = false; |
| Manage(); |
| EXPECT_EQ(stub1.BytesWhenNotVisible(), 0u); |
| EXPECT_EQ(stub2.BytesWhenNotVisible(), 0u); |
| EXPECT_EQ(stub3.BytesWhenNotVisible(), 0u); |
| } |
| |
| // Test that once a backgrounded client has dropped its resources, it |
| // doesn't get them back until it becomes visible again. |
| TEST_F(GpuMemoryManagerTest, BackgroundDiscardPersistent) { |
| // Set memory manager constants for this test. Note that the budget |
| // for backgrounded content will be 64/4 = 16. |
| memmgr_.TestingSetAvailableGpuMemory(64); |
| memmgr_.TestingSetMinimumClientAllocation(8); |
| |
| uint64 bytes_when_not_visible_expected = 10ul; |
| if (!memmgr_.allow_nonvisible_memory_) |
| bytes_when_not_visible_expected = 0; |
| |
| FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true); |
| FakeClient stub2(&memmgr_, GenerateUniqueSurfaceId(), true); |
| |
| // Both clients should be able to keep their contents should one of |
| // them become nonvisible. |
| SetClientStats(&stub1, 10, 20); |
| SetClientStats(&stub2, 10, 20); |
| Manage(); |
| EXPECT_GE(stub1.BytesWhenNotVisible(), bytes_when_not_visible_expected); |
| EXPECT_GE(stub2.BytesWhenNotVisible(), bytes_when_not_visible_expected); |
| |
| // If they both go nonvisible, then only the most recently used client |
| // should keep its contents. |
| stub1.SetVisible(false); |
| stub2.SetVisible(false); |
| Manage(); |
| EXPECT_EQ(stub1.BytesWhenNotVisible(), 0u); |
| EXPECT_GE(stub2.BytesWhenNotVisible(), bytes_when_not_visible_expected); |
| |
| // When becoming visible, stub 2 should get its contents back, and |
| // retain them next time it is made nonvisible. |
| stub2.SetVisible(true); |
| Manage(); |
| EXPECT_GE(stub2.BytesWhenNotVisible(), bytes_when_not_visible_expected); |
| stub2.SetVisible(false); |
| Manage(); |
| EXPECT_GE(stub2.BytesWhenNotVisible(), bytes_when_not_visible_expected); |
| } |
| |
| // Test tracking of unmanaged (e.g, WebGL) memory. |
| TEST_F(GpuMemoryManagerTest, UnmanagedTracking) { |
| // Set memory manager constants for this test |
| memmgr_.TestingSetAvailableGpuMemory(64); |
| memmgr_.TestingSetMinimumClientAllocation(8); |
| memmgr_.TestingSetUnmanagedLimitStep(16); |
| |
| FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true); |
| |
| // Expect that the one stub get its nicetohave level. |
| SetClientStats(&stub1, 16, 32); |
| Manage(); |
| EXPECT_GE(stub1.BytesWhenVisible(), 32u); |
| |
| // Now allocate some unmanaged memory and make sure the amount |
| // goes down. |
| memmgr_.TrackMemoryAllocatedChange( |
| stub1.tracking_group_.get(), |
| 0, |
| 48, |
| gpu::gles2::MemoryTracker::kUnmanaged); |
| Manage(); |
| EXPECT_LT(stub1.BytesWhenVisible(), 24u); |
| |
| // Now allocate the entire FB worth of unmanaged memory, and |
| // make sure that we stay stuck at the minimum tab allocation. |
| memmgr_.TrackMemoryAllocatedChange( |
| stub1.tracking_group_.get(), |
| 48, |
| 64, |
| gpu::gles2::MemoryTracker::kUnmanaged); |
| Manage(); |
| EXPECT_EQ(stub1.BytesWhenVisible(), 8u); |
| |
| // Far-oversubscribe the entire FB, and make sure we stay at |
| // the minimum allocation, and don't blow up. |
| memmgr_.TrackMemoryAllocatedChange( |
| stub1.tracking_group_.get(), |
| 64, |
| 999, |
| gpu::gles2::MemoryTracker::kUnmanaged); |
| Manage(); |
| EXPECT_EQ(stub1.BytesWhenVisible(), 8u); |
| |
| // Delete all tracked memory so we don't hit leak checks. |
| memmgr_.TrackMemoryAllocatedChange( |
| stub1.tracking_group_.get(), |
| 999, |
| 0, |
| gpu::gles2::MemoryTracker::kUnmanaged); |
| } |
| |
| // Test the default allocation levels are used. |
| TEST_F(GpuMemoryManagerTest, DefaultAllocation) { |
| // Set memory manager constants for this test |
| memmgr_.TestingSetAvailableGpuMemory(64); |
| memmgr_.TestingSetMinimumClientAllocation(8); |
| memmgr_.TestingSetDefaultClientAllocation(16); |
| |
| FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true); |
| |
| // Expect that a client which has not sent stats receive at |
| // least the default allocation. |
| Manage(); |
| EXPECT_GE(stub1.BytesWhenVisible(), |
| memmgr_.GetDefaultClientAllocation()); |
| EXPECT_EQ(stub1.BytesWhenNotVisible(), 0u); |
| } |
| |
| } // namespace content |