text: // 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 <stddef.h>
  #include <stdint.h>
  
  #include "base/test/test_simple_task_runner.h"
  #include "base/time/time.h"
  #include "base/timer/lap_timer.h"
  #include "build/build_config.h"
  #include "cc/raster/bitmap_raster_buffer_provider.h"
  #include "cc/raster/gpu_raster_buffer_provider.h"
  #include "cc/raster/one_copy_raster_buffer_provider.h"
  #include "cc/raster/raster_buffer_provider.h"
  #include "cc/raster/raster_query_queue.h"
  #include "cc/raster/synchronous_task_graph_runner.h"
  #include "cc/raster/zero_copy_raster_buffer_provider.h"
  #include "cc/resources/resource_pool.h"
  #include "cc/test/fake_layer_tree_frame_sink.h"
  #include "cc/tiles/tile_task_manager.h"
  #include "components/viz/client/client_resource_provider.h"
  #include "components/viz/common/gpu/context_cache_controller.h"
  #include "components/viz/common/gpu/context_provider.h"
  #include "components/viz/common/resources/platform_color.h"
  #include "components/viz/test/test_context_provider.h"
  #include "components/viz/test/test_context_support.h"
  #include "components/viz/test/test_gpu_memory_buffer_manager.h"
  #include "gpu/command_buffer/client/raster_implementation_gles.h"
  #include "gpu/command_buffer/common/sync_token.h"
  #include "gpu/config/gpu_feature_info.h"
  #include "testing/gtest/include/gtest/gtest.h"
  #include "testing/perf/perf_result_reporter.h"
  #include "third_party/khronos/GLES2/gl2.h"
  #include "third_party/skia/include/gpu/GrDirectContext.h"
  
  namespace cc {
  namespace {
  
  class PerfGLES2Interface : public gpu::gles2::GLES2InterfaceStub {
    // Overridden from gpu::gles2::GLES2Interface:
    GLuint CreateImageCHROMIUM(ClientBuffer buffer,
                               GLsizei width,
                               GLsizei height,
                               GLenum internalformat) override {
      return 1u;
    }
    void GenBuffers(GLsizei n, GLuint* buffers) override {
      for (GLsizei i = 0; i < n; ++i)
        buffers[i] = 1u;
    }
    void GenTextures(GLsizei n, GLuint* textures) override {
      for (GLsizei i = 0; i < n; ++i)
        textures[i] = 1u;
    }
    void GetIntegerv(GLenum pname, GLint* params) override {
      if (pname == GL_MAX_TEXTURE_SIZE)
        *params = INT_MAX;
    }
    void GenQueriesEXT(GLsizei n, GLuint* queries) override {
      for (GLsizei i = 0; i < n; ++i)
        queries[i] = 1u;
    }
    void GetQueryObjectuivEXT(GLuint query,
                              GLenum pname,
                              GLuint* params) override {
      if (pname == GL_QUERY_RESULT_AVAILABLE_EXT)
        *params = 1;
    }
  
    // Overridden from gpu::InterfaceBase
    void GenUnverifiedSyncTokenCHROMIUM(GLbyte* sync_token) override {
      // Copy the data over after setting the data to ensure alignment.
      gpu::SyncToken sync_token_data(gpu::CommandBufferNamespace::GPU_IO,
                                     gpu::CommandBufferId(), 0);
      memcpy(sync_token, &sync_token_data, sizeof(sync_token_data));
    }
  };
  
  class PerfContextProvider
      : public base::RefCountedThreadSafe<PerfContextProvider>,
        public viz::ContextProvider,
        public viz::RasterContextProvider {
   public:
    PerfContextProvider()
        : context_gl_(new PerfGLES2Interface),
          cache_controller_(&support_, nullptr) {
      capabilities_.sync_query = true;
  
      raster_context_ = std::make_unique<gpu::raster::RasterImplementationGLES>(
          context_gl_.get(), ContextSupport());
    }
  
    // viz::ContextProvider implementation.
    void AddRef() const override {
      base::RefCountedThreadSafe<PerfContextProvider>::AddRef();
    }
    void Release() const override {
      base::RefCountedThreadSafe<PerfContextProvider>::Release();
    }
  
    gpu::ContextResult BindToCurrentThread() override {
      return gpu::ContextResult::kSuccess;
    }
    const gpu::Capabilities& ContextCapabilities() const override {
      return capabilities_;
    }
    const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override {
      return gpu_feature_info_;
    }
    gpu::gles2::GLES2Interface* ContextGL() override { return context_gl_.get(); }
    gpu::raster::RasterInterface* RasterInterface() override {
      return raster_context_.get();
    }
    gpu::ContextSupport* ContextSupport() override { return &support_; }
    class GrDirectContext* GrContext() override {
      if (!test_context_provider_) {
        test_context_provider_ = viz::TestContextProvider::Create();
      }
      return test_context_provider_->GrContext();
    }
    gpu::SharedImageInterface* SharedImageInterface() override {
      if (!test_context_provider_) {
        test_context_provider_ = viz::TestContextProvider::Create();
      }
      return test_context_provider_->SharedImageInterface();
    }
    viz::ContextCacheController* CacheController() override {
      return &cache_controller_;
    }
    base::Lock* GetLock() override { return &context_lock_; }
    void AddObserver(viz::ContextLostObserver* obs) override {}
    void RemoveObserver(viz::ContextLostObserver* obs) override {}
  
   private:
    friend class base::RefCountedThreadSafe<PerfContextProvider>;
  
    ~PerfContextProvider() override = default;
  
    std::unique_ptr<PerfGLES2Interface> context_gl_;
    std::unique_ptr<gpu::raster::RasterInterface> raster_context_;
  
    scoped_refptr<viz::TestContextProvider> test_context_provider_;
    viz::TestContextSupport support_;
    viz::ContextCacheController cache_controller_;
    base::Lock context_lock_;
    gpu::Capabilities capabilities_;
    gpu::GpuFeatureInfo gpu_feature_info_;
  };
  
  enum RasterBufferProviderType {
    RASTER_BUFFER_PROVIDER_TYPE_ZERO_COPY,
    RASTER_BUFFER_PROVIDER_TYPE_ONE_COPY,
    RASTER_BUFFER_PROVIDER_TYPE_GPU,
    RASTER_BUFFER_PROVIDER_TYPE_BITMAP
  };
  
  static const int kTimeLimitMillis = 2000;
  static const int kWarmupRuns = 5;
  static const int kTimeCheckInterval = 10;
  
  class PerfTileTask : public TileTask {
   public:
    explicit PerfTileTask(TileTask::Vector* dependencies = nullptr)
        : TileTask(TileTask::SupportsConcurrentExecution::kYes,
                   TileTask::SupportsBackgroundThreadPriority::kYes,
                   dependencies) {}
  
    void Reset() {
      did_complete_ = false;
      state().Reset();
    }
  
    void Cancel() {
      if (!state().IsCanceled())
        state().DidCancel();
  
      did_complete_ = true;
    }
  
   protected:
    ~PerfTileTask() override = default;
  };
  
  class PerfImageDecodeTaskImpl : public PerfTileTask {
   public:
    PerfImageDecodeTaskImpl() = default;
    PerfImageDecodeTaskImpl(const PerfImageDecodeTaskImpl&) = delete;
  
    PerfImageDecodeTaskImpl& operator=(const PerfImageDecodeTaskImpl&) = delete;
  
    // Overridden from Task:
    void RunOnWorkerThread() override {}
  
    // Overridden from TileTask:
    void OnTaskCompleted() override {}
  
   protected:
    ~PerfImageDecodeTaskImpl() override = default;
  };
  
  class PerfRasterBufferProviderHelper {
   public:
    virtual std::unique_ptr<RasterBuffer> AcquireBufferForRaster(
        const ResourcePool::InUsePoolResource& resource,
        uint64_t resource_content_id,
        uint64_t previous_content_id,
        bool depends_on_at_raster_decodes) = 0;
  };
  
  class PerfRasterTaskImpl : public PerfTileTask {
   public:
    PerfRasterTaskImpl(ResourcePool* pool,
                       ResourcePool::InUsePoolResource in_use_resource,
                       std::unique_ptr<RasterBuffer> raster_buffer,
                       TileTask::Vector* dependencies)
        : PerfTileTask(dependencies),
          pool_(pool),
          resource_(std::move(in_use_resource)),
          raster_buffer_(std::move(raster_buffer)) {}
    PerfRasterTaskImpl(const PerfRasterTaskImpl&) = delete;
    PerfRasterTaskImpl& operator=(const PerfRasterTaskImpl&) = delete;
  
    // Overridden from Task:
    void RunOnWorkerThread() override {}
  
    // Overridden from TileTask:
    void OnTaskCompleted() override {
      // Note: Perf tests will Reset() the PerfTileTask, causing it to be
      // completed multiple times. We can only do the work of completion once
      // though.
      if (raster_buffer_) {
        raster_buffer_ = nullptr;
        pool_->ReleaseResource(std::move(resource_));
      }
    }
  
   protected:
    ~PerfRasterTaskImpl() override = default;
  
   private:
    ResourcePool* const pool_;
    ResourcePool::InUsePoolResource resource_;
    std::unique_ptr<RasterBuffer> raster_buffer_;
  };
  
  class RasterBufferProviderPerfTestBase {
   public:
    typedef std::vector<scoped_refptr<TileTask>> RasterTaskVector;
  
    enum NamedTaskSet { REQUIRED_FOR_ACTIVATION, REQUIRED_FOR_DRAW, ALL };
  
    RasterBufferProviderPerfTestBase()
        : compositor_context_provider_(
              base::MakeRefCounted<PerfContextProvider>()),
          worker_context_provider_(base::MakeRefCounted<PerfContextProvider>()),
          task_runner_(new base::TestSimpleTaskRunner),
          task_graph_runner_(new SynchronousTaskGraphRunner),
          timer_(kWarmupRuns,
                 base::Milliseconds(kTimeLimitMillis),
                 kTimeCheckInterval) {}
  
    void CreateImageDecodeTasks(unsigned num_image_decode_tasks,
                                TileTask::Vector* image_decode_tasks) {
      for (unsigned i = 0; i < num_image_decode_tasks; ++i)
        image_decode_tasks->push_back(new PerfImageDecodeTaskImpl);
    }
  
    void CreateRasterTasks(PerfRasterBufferProviderHelper* helper,
                           unsigned num_raster_tasks,
                           const TileTask::Vector& image_decode_tasks,
                           RasterTaskVector* raster_tasks) {
      const gfx::Size size(1, 1);
  
      for (unsigned i = 0; i < num_raster_tasks; ++i) {
        ResourcePool::InUsePoolResource in_use_resource =
            resource_pool_->AcquireResource(size, viz::RGBA_8888,
                                            gfx::ColorSpace());
  
        // No tile ids are given to support partial updates.
        std::unique_ptr<RasterBuffer> raster_buffer;
        if (helper)
          raster_buffer =
              helper->AcquireBufferForRaster(in_use_resource, 0, 0, false);
        TileTask::Vector dependencies = image_decode_tasks;
        raster_tasks->push_back(new PerfRasterTaskImpl(
            resource_pool_.get(), std::move(in_use_resource),
            std::move(raster_buffer), &dependencies));
      }
    }
  
    void ResetRasterTasks(const RasterTaskVector& raster_tasks) {
      for (auto& raster_task : raster_tasks) {
        for (auto& decode_task : raster_task->dependencies())
          static_cast<PerfTileTask*>(decode_task.get())->Reset();
  
        static_cast<PerfTileTask*>(raster_task.get())->Reset();
      }
    }
  
    void CancelRasterTasks(const RasterTaskVector& raster_tasks) {
      for (auto& raster_task : raster_tasks) {
        for (auto& decode_task : raster_task->dependencies())
          static_cast<PerfTileTask*>(decode_task.get())->Cancel();
  
        static_cast<PerfTileTask*>(raster_task.get())->Cancel();
      }
    }
  
    void BuildTileTaskGraph(TaskGraph* graph,
                            const RasterTaskVector& raster_tasks) {
      uint16_t priority = 0;
  
      for (auto& raster_task : raster_tasks) {
        priority++;
  
        for (auto& decode_task : raster_task->dependencies()) {
          // Add decode task if it doesn't already exist in graph.
          auto decode_it =
              std::find_if(graph->nodes.begin(), graph->nodes.end(),
                           [decode_task](const TaskGraph::Node& node) {
                             return node.task == decode_task;
                           });
  
          if (decode_it == graph->nodes.end()) {
            graph->nodes.push_back(
                TaskGraph::Node(decode_task.get(), 0u /* group */, priority, 0u));
          }
  
          graph->edges.push_back(
              TaskGraph::Edge(decode_task.get(), raster_task.get()));
        }
  
        graph->nodes.push_back(TaskGraph::Node(
            raster_task.get(), 0u /* group */, priority,
            static_cast<uint32_t>(raster_task->dependencies().size())));
      }
    }
  
   protected:
    scoped_refptr<viz::ContextProvider> compositor_context_provider_;
    scoped_refptr<viz::RasterContextProvider> worker_context_provider_;
    std::unique_ptr<FakeLayerTreeFrameSink> layer_tree_frame_sink_;
    std::unique_ptr<viz::ClientResourceProvider> resource_provider_;
    scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
    std::unique_ptr<ResourcePool> resource_pool_;
    std::unique_ptr<SynchronousTaskGraphRunner> task_graph_runner_;
    base::LapTimer timer_;
  };
  
  class RasterBufferProviderPerfTest
      : public RasterBufferProviderPerfTestBase,
        public PerfRasterBufferProviderHelper,
        public testing::TestWithParam<RasterBufferProviderType> {
   public:
    // Overridden from testing::Test:
    void SetUp() override {
      pending_raster_queries_ = std::make_unique<RasterQueryQueue>(
          worker_context_provider_.get(), /*oop_rasterization_enabled=*/false);
  
      switch (GetParam()) {
        case RASTER_BUFFER_PROVIDER_TYPE_ZERO_COPY:
          Create3dResourceProvider();
          raster_buffer_provider_ =
              std::make_unique<ZeroCopyRasterBufferProvider>(
                  &gpu_memory_buffer_manager_, compositor_context_provider_.get(),
                  viz::RGBA_8888);
          break;
        case RASTER_BUFFER_PROVIDER_TYPE_ONE_COPY:
          Create3dResourceProvider();
          raster_buffer_provider_ = std::make_unique<OneCopyRasterBufferProvider>(
              task_runner_.get(), compositor_context_provider_.get(),
              worker_context_provider_.get(), &gpu_memory_buffer_manager_,
              std::numeric_limits<int>::max(), false, false,
              std::numeric_limits<int>::max(), viz::RGBA_8888);
          break;
        case RASTER_BUFFER_PROVIDER_TYPE_GPU:
          Create3dResourceProvider();
          raster_buffer_provider_ = std::make_unique<GpuRasterBufferProvider>(
              compositor_context_provider_.get(), worker_context_provider_.get(),
              false, viz::RGBA_8888, gfx::Size(), true, false,
              pending_raster_queries_.get());
          break;
        case RASTER_BUFFER_PROVIDER_TYPE_BITMAP:
          CreateSoftwareResourceProvider();
          raster_buffer_provider_ = std::make_unique<BitmapRasterBufferProvider>(
              layer_tree_frame_sink_.get());
          break;
      }
      DCHECK(raster_buffer_provider_);
  
      resource_pool_ = std::make_unique<ResourcePool>(
          resource_provider_.get(), compositor_context_provider_.get(),
          task_runner_, ResourcePool::kDefaultExpirationDelay, false);
      tile_task_manager_ = TileTaskManagerImpl::Create(task_graph_runner_.get());
    }
    void TearDown() override {
      tile_task_manager_->Shutdown();
      tile_task_manager_->CheckForCompletedTasks();
  
      raster_buffer_provider_->Shutdown();
      resource_pool_.reset();
    }
  
    // Overridden from PerfRasterBufferProviderHelper:
    std::unique_ptr<RasterBuffer> AcquireBufferForRaster(
        const ResourcePool::InUsePoolResource& resource,
        uint64_t resource_content_id,
        uint64_t previous_content_id,
        bool depends_on_at_raster_decodes) override {
      return raster_buffer_provider_->AcquireBufferForRaster(
          resource, resource_content_id, previous_content_id,
          depends_on_at_raster_decodes,
          false /* depends_on_hardware_accelerated_jpeg_candidates */,
          false /* depends_on_hardware_accelerated_webp_candidates */);
    }
  
    void RunMessageLoopUntilAllTasksHaveCompleted() {
      task_graph_runner_->RunUntilIdle();
      task_runner_->RunUntilIdle();
    }
  
    void RunScheduleTasksTest(const std::string& test_name,
                              unsigned num_raster_tasks,
                              unsigned num_image_decode_tasks) {
      TileTask::Vector image_decode_tasks;
      RasterTaskVector raster_tasks;
      CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks);
      CreateRasterTasks(this, num_raster_tasks, image_decode_tasks,
                        &raster_tasks);
  
      // Avoid unnecessary heap allocations by reusing the same graph.
      TaskGraph graph;
  
      timer_.Reset();
      do {
        graph.Reset();
        ResetRasterTasks(raster_tasks);
        BuildTileTaskGraph(&graph, raster_tasks);
        tile_task_manager_->ScheduleTasks(&graph);
        tile_task_manager_->CheckForCompletedTasks();
        timer_.NextLap();
      } while (!timer_.HasTimeLimitExpired());
  
      TaskGraph empty;
      tile_task_manager_->ScheduleTasks(&empty);
      RunMessageLoopUntilAllTasksHaveCompleted();
      tile_task_manager_->CheckForCompletedTasks();
  
      perf_test::PerfResultReporter reporter = SetUpReporter(test_name);
      reporter.AddResult("_tasks" + TestModifierString(), timer_.LapsPerSecond());
    }
  
    void RunScheduleAlternateTasksTest(const std::string& test_name,
                                       unsigned num_raster_tasks,
                                       unsigned num_image_decode_tasks) {
      const size_t kNumVersions = 2;
      TileTask::Vector image_decode_tasks[kNumVersions];
      RasterTaskVector raster_tasks[kNumVersions];
      for (size_t i = 0; i < kNumVersions; ++i) {
        CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks[i]);
        CreateRasterTasks(this, num_raster_tasks, image_decode_tasks[i],
                          &raster_tasks[i]);
      }
  
      // Avoid unnecessary heap allocations by reusing the same graph.
      TaskGraph graph;
  
      size_t count = 0;
      timer_.Reset();
      do {
        graph.Reset();
        // Reset the tasks as for scheduling new state tasks are needed.
        ResetRasterTasks(raster_tasks[count % kNumVersions]);
        BuildTileTaskGraph(&graph, raster_tasks[count % kNumVersions]);
        tile_task_manager_->ScheduleTasks(&graph);
        tile_task_manager_->CheckForCompletedTasks();
        ++count;
        timer_.NextLap();
      } while (!timer_.HasTimeLimitExpired());
  
      TaskGraph empty;
      tile_task_manager_->ScheduleTasks(&empty);
      RunMessageLoopUntilAllTasksHaveCompleted();
      tile_task_manager_->CheckForCompletedTasks();
  
      perf_test::PerfResultReporter reporter = SetUpReporter(test_name);
      reporter.AddResult("_alternate_tasks" + TestModifierString(),
                         timer_.LapsPerSecond());
    }
  
    void RunScheduleAndExecuteTasksTest(const std::string& test_name,
                                        unsigned num_raster_tasks,
                                        unsigned num_image_decode_tasks) {
      TileTask::Vector image_decode_tasks;
      RasterTaskVector raster_tasks;
      CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks);
      CreateRasterTasks(this, num_raster_tasks, image_decode_tasks,
                        &raster_tasks);
  
      // Avoid unnecessary heap allocations by reusing the same graph.
      TaskGraph graph;
  
      timer_.Reset();
      do {
        graph.Reset();
        BuildTileTaskGraph(&graph, raster_tasks);
        tile_task_manager_->ScheduleTasks(&graph);
        RunMessageLoopUntilAllTasksHaveCompleted();
        timer_.NextLap();
      } while (!timer_.HasTimeLimitExpired());
  
      TaskGraph empty;
      tile_task_manager_->ScheduleTasks(&empty);
      RunMessageLoopUntilAllTasksHaveCompleted();
  
      perf_test::PerfResultReporter reporter = SetUpReporter(test_name);
      reporter.AddResult("_and_execute_tasks" + TestModifierString(),
                         timer_.LapsPerSecond());
    }
  
   protected:
    perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
      perf_test::PerfResultReporter reporter("schedule", story_name);
      reporter.RegisterImportantMetric("_tasks" + TestModifierString(), "runs/s");
      reporter.RegisterImportantMetric("_alternate_tasks" + TestModifierString(),
                                       "runs/s");
      reporter.RegisterImportantMetric(
          "_and_execute_tasks" + TestModifierString(), "runs/s");
      return reporter;
    }
  
   private:
    void Create3dResourceProvider() {
      resource_provider_ = std::make_unique<viz::ClientResourceProvider>();
    }
  
    void CreateSoftwareResourceProvider() {
      layer_tree_frame_sink_ = FakeLayerTreeFrameSink::CreateSoftware();
      resource_provider_ = std::make_unique<viz::ClientResourceProvider>();
    }
  
    std::string TestModifierString() const {
      switch (GetParam()) {
        case RASTER_BUFFER_PROVIDER_TYPE_ZERO_COPY:
          return std::string("_zero_copy_raster_buffer_provider");
        case RASTER_BUFFER_PROVIDER_TYPE_ONE_COPY:
          return std::string("_one_copy_raster_buffer_provider");
        case RASTER_BUFFER_PROVIDER_TYPE_GPU:
          return std::string("_gpu_raster_buffer_provider");
        case RASTER_BUFFER_PROVIDER_TYPE_BITMAP:
          return std::string("_bitmap_raster_buffer_provider");
      }
      NOTREACHED();
      return std::string();
    }
  
    std::unique_ptr<TileTaskManager> tile_task_manager_;
    std::unique_ptr<RasterBufferProvider> raster_buffer_provider_;
    viz::TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
    std::unique_ptr<RasterQueryQueue> pending_raster_queries_;
  };
  
  TEST_P(RasterBufferProviderPerfTest, ScheduleTasks) {
    RunScheduleTasksTest("1_0", 1, 0);
    RunScheduleTasksTest("32_0", 32, 0);
    RunScheduleTasksTest("1_1", 1, 1);
    RunScheduleTasksTest("32_1", 32, 1);
    RunScheduleTasksTest("1_4", 1, 4);
    RunScheduleTasksTest("32_4", 32, 4);
  }
  
  TEST_P(RasterBufferProviderPerfTest, ScheduleAlternateTasks) {
    RunScheduleAlternateTasksTest("1_0", 1, 0);
    RunScheduleAlternateTasksTest("32_0", 32, 0);
    RunScheduleAlternateTasksTest("1_1", 1, 1);
    RunScheduleAlternateTasksTest("32_1", 32, 1);
    RunScheduleAlternateTasksTest("1_4", 1, 4);
    RunScheduleAlternateTasksTest("32_4", 32, 4);
  }
  
  TEST_P(RasterBufferProviderPerfTest, ScheduleAndExecuteTasks) {
    RunScheduleAndExecuteTasksTest("1_0", 1, 0);
    RunScheduleAndExecuteTasksTest("32_0", 32, 0);
    RunScheduleAndExecuteTasksTest("1_1", 1, 1);
    RunScheduleAndExecuteTasksTest("32_1", 32, 1);
    RunScheduleAndExecuteTasksTest("1_4", 1, 4);
    RunScheduleAndExecuteTasksTest("32_4", 32, 4);
  }
  
  INSTANTIATE_TEST_SUITE_P(
      RasterBufferProviderPerfTests,
      RasterBufferProviderPerfTest,
      ::testing::Values(RASTER_BUFFER_PROVIDER_TYPE_ZERO_COPY,
                        RASTER_BUFFER_PROVIDER_TYPE_ONE_COPY,
                        RASTER_BUFFER_PROVIDER_TYPE_GPU,
                        RASTER_BUFFER_PROVIDER_TYPE_BITMAP));
  
  class RasterBufferProviderCommonPerfTest
      : public RasterBufferProviderPerfTestBase,
        public testing::Test {
   public:
    // Overridden from testing::Test:
    void SetUp() override {
      resource_provider_ = std::make_unique<viz::ClientResourceProvider>();
      resource_pool_ = std::make_unique<ResourcePool>(
          resource_provider_.get(), compositor_context_provider_.get(),
          task_runner_, ResourcePool::kDefaultExpirationDelay, false);
    }
  
    void RunBuildTileTaskGraphTest(const std::string& test_name,
                                   unsigned num_raster_tasks,
                                   unsigned num_image_decode_tasks) {
      TileTask::Vector image_decode_tasks;
      RasterTaskVector raster_tasks;
      CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks);
      CreateRasterTasks(nullptr, num_raster_tasks, image_decode_tasks,
                        &raster_tasks);
  
      // Avoid unnecessary heap allocations by reusing the same graph.
      TaskGraph graph;
  
      timer_.Reset();
      do {
        graph.Reset();
        BuildTileTaskGraph(&graph, raster_tasks);
        timer_.NextLap();
      } while (!timer_.HasTimeLimitExpired());
  
      CancelRasterTasks(raster_tasks);
  
      for (auto& task : raster_tasks)
        task->OnTaskCompleted();
  
      perf_test::PerfResultReporter reporter = SetUpReporter(test_name);
      reporter.AddResult("", timer_.LapsPerSecond());
    }
  
   protected:
    perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
      perf_test::PerfResultReporter reporter("build_raster_test_graph",
                                             story_name);
      reporter.RegisterImportantMetric("", "runs/s");
      return reporter;
    }
  };
  
  TEST_F(RasterBufferProviderCommonPerfTest, BuildTileTaskGraph) {
    RunBuildTileTaskGraphTest("1_0", 1, 0);
    RunBuildTileTaskGraphTest("32_0", 32, 0);
    RunBuildTileTaskGraphTest("1_1", 1, 1);
    RunBuildTileTaskGraphTest("32_1", 32, 1);
    RunBuildTileTaskGraphTest("1_4", 1, 4);
    RunBuildTileTaskGraphTest("32_4", 32, 4);
  }
  
  }  // namespace
  }  // namespace cc
  