// Copyright 2013 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 "base/time/time.h" #include "cc/resources/tile.h" #include "cc/resources/tile_priority.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" #include "cc/test/fake_picture_pile_impl.h" #include "cc/test/fake_tile_manager.h" #include "cc/test/fake_tile_manager_client.h" #include "cc/test/lap_timer.h" #include "cc/test/test_tile_priorities.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/perf/perf_test.h" namespace cc { namespace { static const int kTimeLimitMillis = 2000; static const int kWarmupRuns = 5; static const int kTimeCheckInterval = 10; class TileManagerPerfTest : public testing::Test { public: typedef std::vector<std::pair<scoped_refptr<Tile>, ManagedTileBin> > TileBinVector; TileManagerPerfTest() : timer_(kWarmupRuns, base::TimeDelta::FromMilliseconds(kTimeLimitMillis), kTimeCheckInterval) {} // Overridden from testing::Test: virtual void SetUp() OVERRIDE { output_surface_ = FakeOutputSurface::Create3d(); CHECK(output_surface_->BindToClient(&output_surface_client_)); resource_provider_ = ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1); size_t raster_task_limit_bytes = 32 * 1024 * 1024; // 16-64MB in practice. tile_manager_ = make_scoped_ptr( new FakeTileManager(&tile_manager_client_, resource_provider_.get(), raster_task_limit_bytes)); picture_pile_ = FakePicturePileImpl::CreatePile(); } GlobalStateThatImpactsTilePriority GlobalStateForTest() { GlobalStateThatImpactsTilePriority state; gfx::Size tile_size = settings_.default_tile_size; state.memory_limit_in_bytes = 10000u * 4u * static_cast<size_t>(tile_size.width() * tile_size.height()); state.num_resources_limit = 10000; state.memory_limit_policy = ALLOW_ANYTHING; state.tree_priority = SMOOTHNESS_TAKES_PRIORITY; return state; } virtual void TearDown() OVERRIDE { tile_manager_.reset(NULL); picture_pile_ = NULL; } TilePriority GetTilePriorityFromBin(ManagedTileBin bin) { switch (bin) { case NOW_AND_READY_TO_DRAW_BIN: case NOW_BIN: return TilePriorityForNowBin(); case SOON_BIN: return TilePriorityForSoonBin(); case EVENTUALLY_AND_ACTIVE_BIN: case EVENTUALLY_BIN: return TilePriorityForEventualBin(); case AT_LAST_BIN: case AT_LAST_AND_ACTIVE_BIN: case NEVER_BIN: return TilePriority(); default: NOTREACHED(); return TilePriority(); } } ManagedTileBin GetNextBin(ManagedTileBin bin) { switch (bin) { case NOW_AND_READY_TO_DRAW_BIN: case NOW_BIN: return SOON_BIN; case SOON_BIN: return EVENTUALLY_BIN; case EVENTUALLY_AND_ACTIVE_BIN: case EVENTUALLY_BIN: return NEVER_BIN; case AT_LAST_BIN: case AT_LAST_AND_ACTIVE_BIN: case NEVER_BIN: return NOW_BIN; default: NOTREACHED(); return NEVER_BIN; } } void CreateBinTiles(int count, ManagedTileBin bin, TileBinVector* tiles) { for (int i = 0; i < count; ++i) { scoped_refptr<Tile> tile = tile_manager_->CreateTile(picture_pile_.get(), settings_.default_tile_size, gfx::Rect(), gfx::Rect(), 1.0, 0, 0, Tile::USE_LCD_TEXT); tile->SetPriority(ACTIVE_TREE, GetTilePriorityFromBin(bin)); tile->SetPriority(PENDING_TREE, GetTilePriorityFromBin(bin)); tiles->push_back(std::make_pair(tile, bin)); } } void CreateTiles(int count, TileBinVector* tiles) { // Roughly an equal amount of all bins. int count_per_bin = count / NUM_BINS; CreateBinTiles(count_per_bin, NOW_BIN, tiles); CreateBinTiles(count_per_bin, SOON_BIN, tiles); CreateBinTiles(count_per_bin, EVENTUALLY_BIN, tiles); CreateBinTiles(count - 3 * count_per_bin, NEVER_BIN, tiles); } void RunManageTilesTest(const std::string& test_name, unsigned tile_count, int priority_change_percent) { DCHECK_GE(tile_count, 100u); DCHECK_GE(priority_change_percent, 0); DCHECK_LE(priority_change_percent, 100); TileBinVector tiles; CreateTiles(tile_count, &tiles); timer_.Reset(); do { if (priority_change_percent > 0) { for (unsigned i = 0; i < tile_count; i += 100 / priority_change_percent) { Tile* tile = tiles[i].first.get(); ManagedTileBin bin = GetNextBin(tiles[i].second); tile->SetPriority(ACTIVE_TREE, GetTilePriorityFromBin(bin)); tile->SetPriority(PENDING_TREE, GetTilePriorityFromBin(bin)); tiles[i].second = bin; } } tile_manager_->ManageTiles(GlobalStateForTest()); tile_manager_->CheckForCompletedTasks(); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); perf_test::PrintResult("manage_tiles", "", test_name, timer_.LapsPerSecond(), "runs/s", true); } private: FakeTileManagerClient tile_manager_client_; LayerTreeSettings settings_; scoped_ptr<FakeTileManager> tile_manager_; scoped_refptr<FakePicturePileImpl> picture_pile_; FakeOutputSurfaceClient output_surface_client_; scoped_ptr<FakeOutputSurface> output_surface_; scoped_ptr<ResourceProvider> resource_provider_; LapTimer timer_; }; TEST_F(TileManagerPerfTest, ManageTiles) { RunManageTilesTest("100_0", 100, 0); RunManageTilesTest("1000_0", 1000, 0); RunManageTilesTest("10000_0", 10000, 0); RunManageTilesTest("100_10", 100, 10); RunManageTilesTest("1000_10", 1000, 10); RunManageTilesTest("10000_10", 10000, 10); RunManageTilesTest("100_100", 100, 100); RunManageTilesTest("1000_100", 1000, 100); RunManageTilesTest("10000_100", 10000, 100); } } // namespace } // namespace cc