root/cc/resources/raster_worker_pool.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GetPictureCloneIndexForCurrentThread
  2. Run
  3. on_raster_finished_callback_
  4. RunOnWorkerThread
  5. ScheduleOnOriginThread
  6. RunOnOriginThread
  7. CompleteOnOriginThread
  8. RunReplyOnOriginThread
  9. RasterFinished
  10. OnRasterFinishedOnOriginThread
  11. tasks_required_for_activation_count_
  12. RunOnWorkerThread
  13. RunOnOriginThread
  14. RunRasterFinished
  15. did_complete_
  16. WillSchedule
  17. DidSchedule
  18. HasBeenScheduled
  19. WillComplete
  20. DidComplete
  21. HasCompleted
  22. required_for_activation
  23. Swap
  24. Reset
  25. weak_ptr_factory_
  26. SetNumRasterThreads
  27. GetNumRasterThreads
  28. GetTaskGraphRunner
  29. GetPictureCloneIndexForCurrentThread
  30. SetClient
  31. Shutdown
  32. SetTaskGraph
  33. CollectCompletedWorkerPoolTasks
  34. CreateRasterFinishedTask
  35. CreateRasterRequiredForActivationFinishedTask
  36. RunTaskOnOriginThread
  37. OnRasterFinished
  38. OnRasterRequiredForActivationFinished
  39. InsertNodeForTask
  40. InsertNodeForRasterTask

// 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 "cc/resources/raster_worker_pool.h"

#include <algorithm>

#include "base/atomic_sequence_num.h"
#include "base/debug/trace_event_synthetic_delay.h"
#include "base/lazy_instance.h"
#include "base/strings/stringprintf.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread_local.h"
#include "cc/base/scoped_ptr_deque.h"

namespace cc {
namespace {

// Synthetic delay for raster tasks that are required for activation. Global to
// avoid static initializer on critical path.
struct RasterRequiredForActivationSyntheticDelayInitializer {
  RasterRequiredForActivationSyntheticDelayInitializer()
      : delay(base::debug::TraceEventSyntheticDelay::Lookup(
            "cc.RasterRequiredForActivation")) {}
  base::debug::TraceEventSyntheticDelay* delay;
};
static base::LazyInstance<RasterRequiredForActivationSyntheticDelayInitializer>
    g_raster_required_for_activation_delay = LAZY_INSTANCE_INITIALIZER;

class RasterTaskGraphRunner : public internal::TaskGraphRunner,
                              public base::DelegateSimpleThread::Delegate {
 public:
  RasterTaskGraphRunner() {
    size_t num_threads = RasterWorkerPool::GetNumRasterThreads();
    while (workers_.size() < num_threads) {
      scoped_ptr<base::DelegateSimpleThread> worker =
          make_scoped_ptr(new base::DelegateSimpleThread(
              this,
              base::StringPrintf("CompositorRasterWorker%u",
                                 static_cast<unsigned>(workers_.size() + 1))
                  .c_str()));
      worker->Start();
#if defined(OS_ANDROID) || defined(OS_LINUX)
      worker->SetThreadPriority(base::kThreadPriority_Background);
#endif
      workers_.push_back(worker.Pass());
    }
  }

  virtual ~RasterTaskGraphRunner() { NOTREACHED(); }

  size_t GetPictureCloneIndexForCurrentThread() {
    return current_tls_.Get()->picture_clone_index;
  }

 private:
  struct ThreadLocalState {
    explicit ThreadLocalState(size_t picture_clone_index)
        : picture_clone_index(picture_clone_index) {}

    size_t picture_clone_index;
  };

  // Overridden from base::DelegateSimpleThread::Delegate:
  virtual void Run() OVERRIDE {
    // Use picture clone index 0..num_threads.
    int picture_clone_index = picture_clone_index_sequence_.GetNext();
    DCHECK_LE(0, picture_clone_index);
    DCHECK_GT(RasterWorkerPool::GetNumRasterThreads(), picture_clone_index);
    current_tls_.Set(new ThreadLocalState(picture_clone_index));

    internal::TaskGraphRunner::Run();
  }

  ScopedPtrDeque<base::DelegateSimpleThread> workers_;
  base::AtomicSequenceNumber picture_clone_index_sequence_;
  base::ThreadLocalPointer<ThreadLocalState> current_tls_;
};

base::LazyInstance<RasterTaskGraphRunner>::Leaky g_task_graph_runner =
    LAZY_INSTANCE_INITIALIZER;

const int kDefaultNumRasterThreads = 1;

int g_num_raster_threads = 0;

class RasterFinishedWorkerPoolTaskImpl : public internal::WorkerPoolTask {
 public:
  typedef base::Callback<void(const internal::WorkerPoolTask* source)> Callback;

  explicit RasterFinishedWorkerPoolTaskImpl(
      base::SequencedTaskRunner* task_runner,
      const Callback& on_raster_finished_callback)
      : task_runner_(task_runner),
        on_raster_finished_callback_(on_raster_finished_callback) {}

  // Overridden from internal::Task:
  virtual void RunOnWorkerThread() OVERRIDE {
    TRACE_EVENT0("cc", "RasterFinishedWorkerPoolTaskImpl::RunOnWorkerThread");
    RasterFinished();
  }

  // Overridden from internal::WorkerPoolTask:
  virtual void ScheduleOnOriginThread(internal::WorkerPoolTaskClient* client)
      OVERRIDE {}
  virtual void RunOnOriginThread() OVERRIDE {
    TRACE_EVENT0("cc", "RasterFinishedWorkerPoolTaskImpl::RunOnOriginThread");
    RasterFinished();
  }
  virtual void CompleteOnOriginThread(internal::WorkerPoolTaskClient* client)
      OVERRIDE {}
  virtual void RunReplyOnOriginThread() OVERRIDE {}

 protected:
  virtual ~RasterFinishedWorkerPoolTaskImpl() {}

  void RasterFinished() {
    task_runner_->PostTask(
        FROM_HERE,
        base::Bind(
            &RasterFinishedWorkerPoolTaskImpl::OnRasterFinishedOnOriginThread,
            this));
  }

 private:
  void OnRasterFinishedOnOriginThread() const {
    on_raster_finished_callback_.Run(this);
  }

  scoped_refptr<base::SequencedTaskRunner> task_runner_;
  const Callback on_raster_finished_callback_;

  DISALLOW_COPY_AND_ASSIGN(RasterFinishedWorkerPoolTaskImpl);
};

class RasterRequiredForActivationFinishedWorkerPoolTaskImpl
    : public RasterFinishedWorkerPoolTaskImpl {
 public:
  RasterRequiredForActivationFinishedWorkerPoolTaskImpl(
      base::SequencedTaskRunner* task_runner,
      const Callback& on_raster_finished_callback,
      size_t tasks_required_for_activation_count)
      : RasterFinishedWorkerPoolTaskImpl(task_runner,
                                         on_raster_finished_callback),
        tasks_required_for_activation_count_(
            tasks_required_for_activation_count) {
    if (tasks_required_for_activation_count_) {
      g_raster_required_for_activation_delay.Get().delay->BeginParallel(
          &activation_delay_end_time_);
    }
  }

  // Overridden from internal::Task:
  virtual void RunOnWorkerThread() OVERRIDE {
    TRACE_EVENT0("cc",
                 "RasterRequiredForActivationFinishedWorkerPoolTaskImpl::"
                 "RunOnWorkerThread");
    RunRasterFinished();
  }

  // Overridden from internal::WorkerPoolTask:
  virtual void RunOnOriginThread() OVERRIDE {
    TRACE_EVENT0("cc",
                 "RasterRequiredForActivationFinishedWorkerPoolTaskImpl::"
                 "RunOnOriginThread");
    RunRasterFinished();
  }

 private:
  virtual ~RasterRequiredForActivationFinishedWorkerPoolTaskImpl() {}

  void RunRasterFinished() {
    if (tasks_required_for_activation_count_) {
      g_raster_required_for_activation_delay.Get().delay->EndParallel(
          activation_delay_end_time_);
    }
    RasterFinished();
  }

  base::TimeTicks activation_delay_end_time_;
  const size_t tasks_required_for_activation_count_;

  DISALLOW_COPY_AND_ASSIGN(
      RasterRequiredForActivationFinishedWorkerPoolTaskImpl);
};

}  // namespace

namespace internal {

WorkerPoolTask::WorkerPoolTask() : did_schedule_(false), did_complete_(false) {}

WorkerPoolTask::~WorkerPoolTask() {
  DCHECK(!did_schedule_);
  DCHECK(!did_run_ || did_complete_);
}

void WorkerPoolTask::WillSchedule() { DCHECK(!did_schedule_); }

void WorkerPoolTask::DidSchedule() {
  did_schedule_ = true;
  did_complete_ = false;
}

bool WorkerPoolTask::HasBeenScheduled() const { return did_schedule_; }

void WorkerPoolTask::WillComplete() { DCHECK(!did_complete_); }

void WorkerPoolTask::DidComplete() {
  DCHECK(did_schedule_);
  DCHECK(!did_complete_);
  did_schedule_ = false;
  did_complete_ = true;
}

bool WorkerPoolTask::HasCompleted() const { return did_complete_; }

RasterWorkerPoolTask::RasterWorkerPoolTask(
    const Resource* resource,
    internal::WorkerPoolTask::Vector* dependencies)
    : resource_(resource) {
  dependencies_.swap(*dependencies);
}

RasterWorkerPoolTask::~RasterWorkerPoolTask() {}

}  // namespace internal

RasterTaskQueue::Item::Item(internal::RasterWorkerPoolTask* task,
                            bool required_for_activation)
    : task(task), required_for_activation(required_for_activation) {}

RasterTaskQueue::Item::~Item() {}

RasterTaskQueue::RasterTaskQueue() : required_for_activation_count(0u) {}

RasterTaskQueue::~RasterTaskQueue() {}

void RasterTaskQueue::Swap(RasterTaskQueue* other) {
  items.swap(other->items);
  std::swap(required_for_activation_count,
            other->required_for_activation_count);
}

void RasterTaskQueue::Reset() {
  required_for_activation_count = 0u;
  items.clear();
}

// This allows an external rasterize on-demand system to run raster tasks
// with highest priority using the same task graph runner instance.
unsigned RasterWorkerPool::kOnDemandRasterTaskPriority = 0u;
// This allows a micro benchmark system to run tasks with highest priority,
// since it should finish as quickly as possible.
unsigned RasterWorkerPool::kBenchmarkRasterTaskPriority = 0u;
// Task priorities that make sure raster finished tasks run before any
// remaining raster tasks.
unsigned RasterWorkerPool::kRasterFinishedTaskPriority = 2u;
unsigned RasterWorkerPool::kRasterRequiredForActivationFinishedTaskPriority =
    1u;
unsigned RasterWorkerPool::kRasterTaskPriorityBase = 3u;

RasterWorkerPool::RasterWorkerPool(base::SequencedTaskRunner* task_runner,
                                   internal::TaskGraphRunner* task_graph_runner,
                                   ResourceProvider* resource_provider)
    : task_runner_(task_runner),
      task_graph_runner_(task_graph_runner),
      client_(NULL),
      resource_provider_(resource_provider),
      weak_ptr_factory_(this) {
  if (task_graph_runner_)
    namespace_token_ = task_graph_runner_->GetNamespaceToken();
}

RasterWorkerPool::~RasterWorkerPool() {}

// static
void RasterWorkerPool::SetNumRasterThreads(int num_threads) {
  DCHECK_LT(0, num_threads);
  DCHECK_EQ(0, g_num_raster_threads);

  g_num_raster_threads = num_threads;
}

// static
int RasterWorkerPool::GetNumRasterThreads() {
  if (!g_num_raster_threads)
    g_num_raster_threads = kDefaultNumRasterThreads;

  return g_num_raster_threads;
}

// static
internal::TaskGraphRunner* RasterWorkerPool::GetTaskGraphRunner() {
  return g_task_graph_runner.Pointer();
}

// static
size_t RasterWorkerPool::GetPictureCloneIndexForCurrentThread() {
  return g_task_graph_runner.Pointer()->GetPictureCloneIndexForCurrentThread();
}

void RasterWorkerPool::SetClient(RasterWorkerPoolClient* client) {
  client_ = client;
}

void RasterWorkerPool::Shutdown() {
  TRACE_EVENT0("cc", "RasterWorkerPool::Shutdown");

  if (task_graph_runner_) {
    internal::TaskGraph empty;
    task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
    task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
  }

  weak_ptr_factory_.InvalidateWeakPtrs();
}

void RasterWorkerPool::SetTaskGraph(internal::TaskGraph* graph) {
  TRACE_EVENT0("cc", "RasterWorkerPool::SetTaskGraph");

  DCHECK(task_graph_runner_);
  for (internal::TaskGraph::Node::Vector::iterator it = graph->nodes.begin();
       it != graph->nodes.end();
       ++it) {
    internal::TaskGraph::Node& node = *it;
    internal::WorkerPoolTask* task =
        static_cast<internal::WorkerPoolTask*>(node.task);

    if (!task->HasBeenScheduled()) {
      task->WillSchedule();
      task->ScheduleOnOriginThread(this);
      task->DidSchedule();
    }
  }

  task_graph_runner_->ScheduleTasks(namespace_token_, graph);
}

void RasterWorkerPool::CollectCompletedWorkerPoolTasks(
    internal::Task::Vector* completed_tasks) {
  DCHECK(task_graph_runner_);
  task_graph_runner_->CollectCompletedTasks(namespace_token_, completed_tasks);
}

scoped_refptr<internal::WorkerPoolTask>
RasterWorkerPool::CreateRasterFinishedTask() {
  return make_scoped_refptr(new RasterFinishedWorkerPoolTaskImpl(
      task_runner_,
      base::Bind(&RasterWorkerPool::OnRasterFinished,
                 weak_ptr_factory_.GetWeakPtr())));
}

scoped_refptr<internal::WorkerPoolTask>
RasterWorkerPool::CreateRasterRequiredForActivationFinishedTask(
    size_t tasks_required_for_activation_count) {
  return make_scoped_refptr(
      new RasterRequiredForActivationFinishedWorkerPoolTaskImpl(
          task_runner_,
          base::Bind(&RasterWorkerPool::OnRasterRequiredForActivationFinished,
                     weak_ptr_factory_.GetWeakPtr()),
          tasks_required_for_activation_count));
}

void RasterWorkerPool::RunTaskOnOriginThread(internal::WorkerPoolTask* task) {
  task->WillSchedule();
  task->ScheduleOnOriginThread(this);
  task->DidSchedule();

  task->WillRun();
  task->RunOnOriginThread();
  task->DidRun();

  task->WillComplete();
  task->CompleteOnOriginThread(this);
  task->DidComplete();
}

void RasterWorkerPool::OnRasterFinished(
    const internal::WorkerPoolTask* source) {
  TRACE_EVENT0("cc", "RasterWorkerPool::OnRasterFinished");

  // Early out if current |raster_finished_task_| is not the source.
  if (source != raster_finished_task_.get())
    return;

  OnRasterTasksFinished();
}

void RasterWorkerPool::OnRasterRequiredForActivationFinished(
    const internal::WorkerPoolTask* source) {
  TRACE_EVENT0("cc", "RasterWorkerPool::OnRasterRequiredForActivationFinished");

  // Early out if current |raster_required_for_activation_finished_task_|
  // is not the source.
  if (source != raster_required_for_activation_finished_task_.get())
    return;

  OnRasterTasksRequiredForActivationFinished();
}

// static
void RasterWorkerPool::InsertNodeForTask(internal::TaskGraph* graph,
                                         internal::WorkerPoolTask* task,
                                         unsigned priority,
                                         size_t dependencies) {
  DCHECK(std::find_if(graph->nodes.begin(),
                      graph->nodes.end(),
                      internal::TaskGraph::Node::TaskComparator(task)) ==
         graph->nodes.end());
  graph->nodes.push_back(
      internal::TaskGraph::Node(task, priority, dependencies));
}

// static
void RasterWorkerPool::InsertNodeForRasterTask(
    internal::TaskGraph* graph,
    internal::WorkerPoolTask* raster_task,
    const internal::WorkerPoolTask::Vector& decode_tasks,
    unsigned priority) {
  size_t dependencies = 0u;

  // Insert image decode tasks.
  for (internal::WorkerPoolTask::Vector::const_iterator it =
           decode_tasks.begin();
       it != decode_tasks.end();
       ++it) {
    internal::WorkerPoolTask* decode_task = it->get();

    // Skip if already decoded.
    if (decode_task->HasCompleted())
      continue;

    dependencies++;

    // Add decode task if it doesn't already exists in graph.
    internal::TaskGraph::Node::Vector::iterator decode_it =
        std::find_if(graph->nodes.begin(),
                     graph->nodes.end(),
                     internal::TaskGraph::Node::TaskComparator(decode_task));
    if (decode_it == graph->nodes.end())
      InsertNodeForTask(graph, decode_task, priority, 0u);

    graph->edges.push_back(internal::TaskGraph::Edge(decode_task, raster_task));
  }

  InsertNodeForTask(graph, raster_task, priority, dependencies);
}

}  // namespace cc

/* [<][>][^][v][top][bottom][index][help] */