Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(773)

Unified Diff: cc/resources/pixel_buffer_raster_worker_pool.cc

Issue 17351017: Re-land: cc: Add raster finished signals to RasterWorkerPool. (Closed) Base URL: http://git.chromium.org/chromium/src.git@new-graph-build
Patch Set: fix flaky unit tests Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « cc/resources/pixel_buffer_raster_worker_pool.h ('k') | cc/resources/raster_worker_pool.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/resources/pixel_buffer_raster_worker_pool.cc
diff --git a/cc/resources/pixel_buffer_raster_worker_pool.cc b/cc/resources/pixel_buffer_raster_worker_pool.cc
index bbdb5321f80ebbaafd4622944329b106699e406f..3d8741109c1c58148b661971f7feee359279fd8d 100644
--- a/cc/resources/pixel_buffer_raster_worker_pool.cc
+++ b/cc/resources/pixel_buffer_raster_worker_pool.cc
@@ -4,7 +4,10 @@
#include "cc/resources/pixel_buffer_raster_worker_pool.h"
+#include "base/containers/stack_container.h"
#include "base/debug/trace_event.h"
+#include "base/values.h"
+#include "cc/debug/traced_value.h"
#include "cc/resources/resource.h"
#include "third_party/skia/include/core/SkDevice.h"
@@ -77,18 +80,37 @@ const size_t kMaxPendingUploadBytes = 16 * 2 * kMaxBytesUploadedPerMs;
const int kCheckForCompletedRasterTasksDelayMs = 6;
-const size_t kMaxPendingRasterBytes =
- kMaxBytesUploadedPerMs * kCheckForCompletedRasterTasksDelayMs;
+const size_t kMaxScheduledRasterTasks = 48;
+
+typedef base::StackVector<internal::GraphNode*,
+ kMaxScheduledRasterTasks> NodeVector;
+
+void AddDependenciesToGraphNode(
+ internal::GraphNode* node,
+ const NodeVector::ContainerType& dependencies) {
+ for (NodeVector::ContainerType::const_iterator it = dependencies.begin();
+ it != dependencies.end(); ++it) {
+ internal::GraphNode* dependency = *it;
+
+ node->add_dependency();
+ dependency->add_dependent(node);
+ }
+}
} // namespace
PixelBufferRasterWorkerPool::PixelBufferRasterWorkerPool(
ResourceProvider* resource_provider,
- size_t num_threads) : RasterWorkerPool(resource_provider, num_threads),
- shutdown_(false),
- bytes_pending_upload_(0),
- has_performed_uploads_since_last_flush_(false),
- check_for_completed_raster_tasks_pending_(false) {
+ size_t num_threads)
+ : RasterWorkerPool(resource_provider, num_threads),
+ shutdown_(false),
+ scheduled_raster_task_count_(0),
+ bytes_pending_upload_(0),
+ has_performed_uploads_since_last_flush_(false),
+ check_for_completed_raster_tasks_pending_(false),
+ should_notify_client_if_no_tasks_are_pending_(false),
+ should_notify_client_if_no_tasks_required_for_activation_are_pending_(
+ false) {
}
PixelBufferRasterWorkerPool::~PixelBufferRasterWorkerPool() {
@@ -102,7 +124,10 @@ PixelBufferRasterWorkerPool::~PixelBufferRasterWorkerPool() {
void PixelBufferRasterWorkerPool::Shutdown() {
shutdown_ = true;
RasterWorkerPool::Shutdown();
- CheckForCompletedRasterTasks();
+ RasterWorkerPool::CheckForCompletedTasks();
+ CheckForCompletedUploads();
+ check_for_completed_raster_tasks_callback_.Cancel();
+ check_for_completed_raster_tasks_pending_ = false;
for (TaskMap::iterator it = pixel_buffer_tasks_.begin();
it != pixel_buffer_tasks_.end(); ++it) {
internal::RasterWorkerPoolTask* task = it->first;
@@ -114,6 +139,7 @@ void PixelBufferRasterWorkerPool::Shutdown() {
completed_tasks_.push_back(task);
}
}
+ DCHECK_EQ(completed_tasks_.size(), pixel_buffer_tasks_.size());
}
void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) {
@@ -121,6 +147,12 @@ void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) {
RasterWorkerPool::SetRasterTasks(queue);
+ if (!should_notify_client_if_no_tasks_are_pending_)
+ TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this);
+
+ should_notify_client_if_no_tasks_are_pending_ = true;
+ should_notify_client_if_no_tasks_required_for_activation_are_pending_ = true;
+
// Build new pixel buffer task set.
TaskMap new_pixel_buffer_tasks;
for (RasterTaskVector::const_iterator it = raster_tasks().begin();
@@ -160,13 +192,35 @@ void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) {
}
}
+ tasks_required_for_activation_.clear();
+ for (TaskMap::iterator it = new_pixel_buffer_tasks.begin();
+ it != new_pixel_buffer_tasks.end(); ++it) {
+ internal::RasterWorkerPoolTask* task = it->first;
+ if (IsRasterTaskRequiredForActivation(task))
+ tasks_required_for_activation_.insert(task);
+ }
+
pixel_buffer_tasks_.swap(new_pixel_buffer_tasks);
- // This will schedule more tasks after checking for completed raster
- // tasks. It's worth checking for completed tasks when ScheduleTasks()
- // is called as priorities might have changed and this allows us to
- // schedule as many new top priority tasks as possible.
- CheckForCompletedRasterTasks();
+ // Check for completed tasks when ScheduleTasks() is called as
+ // priorities might have changed and this maximizes the number
+ // of top priority tasks that are scheduled.
+ RasterWorkerPool::CheckForCompletedTasks();
+ CheckForCompletedUploads();
+ FlushUploads();
+
+ // Schedule new tasks.
+ ScheduleMoreTasks();
+
+ // Cancel any pending check for completed raster tasks and schedule
+ // another check.
+ check_for_completed_raster_tasks_callback_.Cancel();
+ check_for_completed_raster_tasks_pending_ = false;
+ ScheduleCheckForCompletedRasterTasks();
+
+ TRACE_EVENT_ASYNC_STEP1(
+ "cc", "ScheduledTasks", this, StateName(),
+ "state", TracedValue::FromValue(StateAsValue().release()));
}
void PixelBufferRasterWorkerPool::CheckForCompletedTasks() {
@@ -176,8 +230,11 @@ void PixelBufferRasterWorkerPool::CheckForCompletedTasks() {
CheckForCompletedUploads();
FlushUploads();
- while (!completed_tasks_.empty()) {
- internal::RasterWorkerPoolTask* task = completed_tasks_.front().get();
+ TaskDeque completed_tasks;
+ completed_tasks_.swap(completed_tasks);
+
+ while (!completed_tasks.empty()) {
+ internal::RasterWorkerPoolTask* task = completed_tasks.front().get();
DCHECK(pixel_buffer_tasks_.find(task) != pixel_buffer_tasks_.end());
pixel_buffer_tasks_.erase(task);
@@ -186,14 +243,33 @@ void PixelBufferRasterWorkerPool::CheckForCompletedTasks() {
task->CompleteOnOriginThread();
task->DidComplete();
- completed_tasks_.pop_front();
+ completed_tasks.pop_front();
}
}
void PixelBufferRasterWorkerPool::OnRasterTasksFinished() {
- // Call CheckForCompletedTasks() when we've finished running all raster
- // tasks needed since last time ScheduleMoreTasks() was called. This
- // reduces latency when processing only a small number of raster tasks.
+ // |should_notify_client_if_no_tasks_are_pending_| can be set to false as
+ // a result of a scheduled CheckForCompletedRasterTasks() call. No need to
+ // perform another check in that case as we've already notified the client.
+ if (!should_notify_client_if_no_tasks_are_pending_)
+ return;
+
+ // Call CheckForCompletedRasterTasks() when we've finished running all
+ // raster tasks needed since last time ScheduleTasks() was called.
+ // This reduces latency between the time when all tasks have finished
+ // running and the time when the client is notified.
+ CheckForCompletedRasterTasks();
+}
+
+void PixelBufferRasterWorkerPool::OnRasterTasksRequiredForActivationFinished() {
+ // Analogous to OnRasterTasksFinished(), there's no need to call
+ // CheckForCompletedRasterTasks() if the client has already been notified.
+ if (!should_notify_client_if_no_tasks_required_for_activation_are_pending_)
+ return;
+
+ // This reduces latency between the time when all tasks required for
+ // activation have finished running and the time when the client is
+ // notified.
CheckForCompletedRasterTasks();
}
@@ -272,6 +348,8 @@ void PixelBufferRasterWorkerPool::CheckForCompletedUploads() {
task) == completed_tasks_.end());
completed_tasks_.push_back(task);
+ tasks_required_for_activation_.erase(task);
+
tasks_with_completed_uploads.pop_front();
}
}
@@ -294,6 +372,8 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks() {
TRACE_EVENT0(
"cc", "PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks");
+ DCHECK(should_notify_client_if_no_tasks_are_pending_);
+
check_for_completed_raster_tasks_callback_.Cancel();
check_for_completed_raster_tasks_pending_ = false;
@@ -301,21 +381,55 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks() {
CheckForCompletedUploads();
FlushUploads();
- ScheduleMoreTasks();
-
- // Make sure another check for completed uploads is scheduled
- // while there is still pending uploads left.
- if (!tasks_with_pending_upload_.empty())
+ // Determine what client notifications to generate.
+ bool will_notify_client_that_no_tasks_required_for_activation_are_pending =
+ (should_notify_client_if_no_tasks_required_for_activation_are_pending_ &&
+ !HasPendingTasksRequiredForActivation());
+ bool will_notify_client_that_no_tasks_are_pending =
+ (should_notify_client_if_no_tasks_are_pending_ &&
+ !HasPendingTasks());
+
+ // Adjust the need to generate notifications before scheduling more tasks.
+ should_notify_client_if_no_tasks_required_for_activation_are_pending_ &=
+ !will_notify_client_that_no_tasks_required_for_activation_are_pending;
+ should_notify_client_if_no_tasks_are_pending_ &=
+ !will_notify_client_that_no_tasks_are_pending;
+
+ if (PendingRasterTaskCount())
+ ScheduleMoreTasks();
+
+ TRACE_EVENT_ASYNC_STEP1(
+ "cc", "ScheduledTasks", this, StateName(),
+ "state", TracedValue::FromValue(StateAsValue().release()));
+
+ // Schedule another check for completed raster tasks while there are
+ // pending raster tasks or pending uploads.
+ if (HasPendingTasks())
ScheduleCheckForCompletedRasterTasks();
+
+ // Generate client notifications.
+ if (will_notify_client_that_no_tasks_required_for_activation_are_pending)
+ client()->DidFinishedRunningTasksRequiredForActivation();
+ if (will_notify_client_that_no_tasks_are_pending) {
+ TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this);
+ client()->DidFinishedRunningTasks();
+ }
}
void PixelBufferRasterWorkerPool::ScheduleMoreTasks() {
TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::ScheduleMoreTasks");
+ enum RasterTaskType {
+ PREPAINT_TYPE = 0,
+ REQUIRED_FOR_ACTIVATION_TYPE = 1,
+ NUM_TYPES = 2
+ };
+ NodeVector tasks[NUM_TYPES];
+ unsigned priority = 2u; // 0-1 reserved for RasterFinished tasks.
+ TaskGraph graph;
+
size_t bytes_pending_upload = bytes_pending_upload_;
- size_t bytes_pending_raster = 0;
- RasterTaskGraph graph;
for (RasterTaskVector::const_iterator it = raster_tasks().begin();
it != raster_tasks().end(); ++it) {
internal::RasterWorkerPoolTask* task = it->get();
@@ -347,21 +461,28 @@ void PixelBufferRasterWorkerPool::ScheduleMoreTasks() {
continue;
}
- // Throttle raster tasks based on bytes pending if raster has not
- // finished.
- size_t new_bytes_pending_raster = bytes_pending_raster;
- new_bytes_pending_raster += task->resource()->bytes();
- if (new_bytes_pending_raster > kMaxPendingRasterBytes)
+ // Throttle raster tasks based on kMaxScheduledRasterTasks.
+ size_t scheduled_raster_task_count =
+ tasks[PREPAINT_TYPE].container().size() +
+ tasks[REQUIRED_FOR_ACTIVATION_TYPE].container().size();
+ if (scheduled_raster_task_count >= kMaxScheduledRasterTasks)
break;
- // Update both |bytes_pending_raster| and |bytes_pending_upload|
- // now that task has cleared all throttling limits.
- bytes_pending_raster = new_bytes_pending_raster;
+ // Update |bytes_pending_upload| now that task has cleared all
+ // throttling limits.
bytes_pending_upload = new_bytes_pending_upload;
+ RasterTaskType type = IsRasterTaskRequiredForActivation(task) ?
+ REQUIRED_FOR_ACTIVATION_TYPE :
+ PREPAINT_TYPE;
+
// Use existing pixel buffer task if available.
if (pixel_buffer_task) {
- graph.InsertRasterTask(pixel_buffer_task, task->dependencies());
+ tasks[type].container().push_back(
+ CreateGraphNodeForRasterTask(pixel_buffer_task,
+ task->dependencies(),
+ priority++,
+ &graph));
continue;
}
@@ -382,16 +503,67 @@ void PixelBufferRasterWorkerPool::ScheduleMoreTasks() {
base::Unretained(this),
make_scoped_refptr(task))));
pixel_buffer_tasks_[task] = new_pixel_buffer_task;
- graph.InsertRasterTask(new_pixel_buffer_task.get(), task->dependencies());
+ tasks[type].container().push_back(
+ CreateGraphNodeForRasterTask(new_pixel_buffer_task.get(),
+ task->dependencies(),
+ priority++,
+ &graph));
}
- SetRasterTaskGraph(&graph);
+ scoped_refptr<internal::WorkerPoolTask>
+ new_raster_required_for_activation_finished_task;
+
+ size_t scheduled_raster_task_required_for_activation_count =
+ tasks[REQUIRED_FOR_ACTIVATION_TYPE].container().size();
+ DCHECK_LE(scheduled_raster_task_required_for_activation_count,
+ tasks_required_for_activation_.size());
+ // Schedule OnRasterTasksRequiredForActivationFinished call only when
+ // notification is pending and throttling is not preventing all pending
+ // tasks required for activation from being scheduled.
+ if (scheduled_raster_task_required_for_activation_count ==
+ tasks_required_for_activation_.size() &&
+ should_notify_client_if_no_tasks_required_for_activation_are_pending_) {
+ new_raster_required_for_activation_finished_task =
+ CreateRasterRequiredForActivationFinishedTask();
+ internal::GraphNode* raster_required_for_activation_finished_node =
+ CreateGraphNodeForTask(
+ new_raster_required_for_activation_finished_task.get(),
+ 0u, // Priority 0
+ &graph);
+ AddDependenciesToGraphNode(
+ raster_required_for_activation_finished_node,
+ tasks[REQUIRED_FOR_ACTIVATION_TYPE].container());
+ }
- // At least one task that could need an upload is now pending, schedule
- // a check for completed raster tasks to ensure this upload is dispatched
- // without too much latency.
- if (bytes_pending_raster)
- ScheduleCheckForCompletedRasterTasks();
+ scoped_refptr<internal::WorkerPoolTask> new_raster_finished_task;
+
+ size_t scheduled_raster_task_count =
+ tasks[PREPAINT_TYPE].container().size() +
+ tasks[REQUIRED_FOR_ACTIVATION_TYPE].container().size();
+ DCHECK_LE(scheduled_raster_task_count, PendingRasterTaskCount());
+ // Schedule OnRasterTasksFinished call only when notification is pending
+ // and throttling is not preventing all pending tasks from being scheduled.
+ if (scheduled_raster_task_count == PendingRasterTaskCount() &&
+ should_notify_client_if_no_tasks_are_pending_) {
+ new_raster_finished_task = CreateRasterFinishedTask();
+ internal::GraphNode* raster_finished_node =
+ CreateGraphNodeForTask(new_raster_finished_task.get(),
+ 1u, // Priority 1
+ &graph);
+ for (unsigned type = 0; type < NUM_TYPES; ++type) {
+ AddDependenciesToGraphNode(
+ raster_finished_node,
+ tasks[type].container());
+ }
+ }
+
+ SetTaskGraph(&graph);
+
+ scheduled_raster_task_count_ = scheduled_raster_task_count;
+
+ set_raster_finished_task(new_raster_finished_task);
+ set_raster_required_for_activation_finished_task(
+ new_raster_required_for_activation_finished_task);
}
void PixelBufferRasterWorkerPool::OnRasterTaskCompleted(
@@ -414,6 +586,7 @@ void PixelBufferRasterWorkerPool::OnRasterTaskCompleted(
completed_tasks_.end(),
task) == completed_tasks_.end());
completed_tasks_.push_back(task);
+ tasks_required_for_activation_.erase(task);
return;
}
@@ -424,4 +597,55 @@ void PixelBufferRasterWorkerPool::OnRasterTaskCompleted(
tasks_with_pending_upload_.push_back(task);
}
+unsigned PixelBufferRasterWorkerPool::PendingRasterTaskCount() const {
+ unsigned num_completed_raster_tasks =
+ tasks_with_pending_upload_.size() + completed_tasks_.size();
+ DCHECK_GE(pixel_buffer_tasks_.size(), num_completed_raster_tasks);
+ return pixel_buffer_tasks_.size() - num_completed_raster_tasks;
+}
+
+bool PixelBufferRasterWorkerPool::HasPendingTasks() const {
+ return PendingRasterTaskCount() || !tasks_with_pending_upload_.empty();
+}
+
+bool PixelBufferRasterWorkerPool::HasPendingTasksRequiredForActivation() const {
+ return !tasks_required_for_activation_.empty();
+}
+
+const char* PixelBufferRasterWorkerPool::StateName() const {
+ if (scheduled_raster_task_count_)
+ return "rasterizing";
+ if (PendingRasterTaskCount())
+ return "throttled";
+ if (!tasks_with_pending_upload_.empty())
+ return "waiting_for_uploads";
+
+ return "finishing";
+}
+
+scoped_ptr<base::Value> PixelBufferRasterWorkerPool::StateAsValue() const {
+ scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
+
+ state->SetInteger("completed_count", completed_tasks_.size());
+ state->SetInteger("pending_count", pixel_buffer_tasks_.size());
+ state->SetInteger("pending_upload_count", tasks_with_pending_upload_.size());
+ state->SetInteger("required_for_activation_count",
+ tasks_required_for_activation_.size());
+ state->Set("scheduled_state", ScheduledStateAsValue().release());
+ state->Set("throttle_state", ThrottleStateAsValue().release());
+ return state.PassAs<base::Value>();
+}
+
+scoped_ptr<base::Value> PixelBufferRasterWorkerPool::ThrottleStateAsValue()
+ const {
+ scoped_ptr<base::DictionaryValue> throttle_state(new base::DictionaryValue);
+
+ throttle_state->SetInteger("bytes_available_for_upload",
+ kMaxPendingUploadBytes - bytes_pending_upload_);
+ throttle_state->SetInteger("bytes_pending_upload", bytes_pending_upload_);
+ throttle_state->SetInteger("scheduled_raster_task_count",
+ scheduled_raster_task_count_);
+ return throttle_state.PassAs<base::Value>();
+}
+
} // namespace cc
« no previous file with comments | « cc/resources/pixel_buffer_raster_worker_pool.h ('k') | cc/resources/raster_worker_pool.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698