diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc new file mode 100644 index 00000000000..ad0fb1866db --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc @@ -0,0 +1,201 @@ +// Copyright 2014 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 "third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h" + +#include <memory> + +#include "base/bind.h" +#include "base/metrics/histogram_macros.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_event_argument.h" +#include "third_party/blink/renderer/platform/histogram.h" +#include "third_party/blink/renderer/platform/scheduler/base/task_queue.h" +#include "third_party/blink/renderer/platform/scheduler/base/task_queue_manager.h" +#include "third_party/blink/renderer/platform/scheduler/child/default_params.h" +#include "third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_helper.h" +#include "third_party/blink/renderer/platform/scheduler/child/worker_scheduler_proxy.h" + +namespace blink { +namespace scheduler { + +namespace { +// Workers could be short-lived, set a shorter interval than +// the renderer thread. +constexpr base::TimeDelta kUnspecifiedWorkerThreadLoadTrackerReportingInterval = + base::TimeDelta::FromSeconds(1); + +void ReportWorkerTaskLoad(base::TimeTicks time, double load) { + int load_percentage = static_cast<int>(load * 100); + DCHECK_LE(load_percentage, 100); + // TODO(kinuko): Maybe we also want to separately log when the associated + // tab is in foreground and when not. + UMA_HISTOGRAM_PERCENTAGE("WorkerScheduler.WorkerThreadLoad", load_percentage); +} + +// TODO(scheduler-dev): Remove conversions when Blink starts using +// base::TimeTicks instead of doubles for time. +base::TimeTicks MonotonicTimeInSecondsToTimeTicks( + double monotonic_time_in_seconds) { + return base::TimeTicks() + + base::TimeDelta::FromSecondsD(monotonic_time_in_seconds); +} + +} // namespace + +WorkerThreadScheduler::WorkerThreadScheduler( + WebThreadType thread_type, + std::unique_ptr<TaskQueueManager> task_queue_manager, + WorkerSchedulerProxy* proxy) + : NonMainThreadScheduler( + std::make_unique<WorkerSchedulerHelper>(std::move(task_queue_manager), + this)), + idle_helper_(helper_.get(), + this, + "WorkerSchedulerIdlePeriod", + base::TimeDelta::FromMilliseconds(300), + helper_->NewTaskQueue(TaskQueue::Spec("worker_idle_tq"))), + idle_canceled_delayed_task_sweeper_(helper_.get(), + idle_helper_.IdleTaskRunner()), + load_tracker_(helper_->NowTicks(), + base::BindRepeating(&ReportWorkerTaskLoad), + kUnspecifiedWorkerThreadLoadTrackerReportingInterval), + throttling_state_(proxy ? proxy->throttling_state() + : FrameScheduler::ThrottlingState::kNotThrottled), + worker_metrics_helper_(thread_type), + weak_factory_(this) { + thread_start_time_ = helper_->NowTicks(); + load_tracker_.Resume(thread_start_time_); + helper_->AddTaskTimeObserver(this); + + if (proxy) { + worker_metrics_helper_.SetParentFrameType(proxy->parent_frame_type()); + proxy->OnWorkerSchedulerCreated(GetWeakPtr()); + } + + TRACE_EVENT_OBJECT_CREATED_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), "WorkerScheduler", this); +} + +WorkerThreadScheduler::~WorkerThreadScheduler() { + TRACE_EVENT_OBJECT_DELETED_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), "WorkerScheduler", this); + + helper_->RemoveTaskTimeObserver(this); +} + +scoped_refptr<base::SingleThreadTaskRunner> +WorkerThreadScheduler::DefaultTaskRunner() { + DCHECK(initialized_); + return helper_->DefaultWorkerTaskQueue(); +} + +scoped_refptr<SingleThreadIdleTaskRunner> +WorkerThreadScheduler::IdleTaskRunner() { + DCHECK(initialized_); + return idle_helper_.IdleTaskRunner(); +} + +scoped_refptr<base::SingleThreadTaskRunner> +WorkerThreadScheduler::IPCTaskRunner() { + return base::ThreadTaskRunnerHandle::Get(); +} + +bool WorkerThreadScheduler::CanExceedIdleDeadlineIfRequired() const { + DCHECK(initialized_); + return idle_helper_.CanExceedIdleDeadlineIfRequired(); +} + +bool WorkerThreadScheduler::ShouldYieldForHighPriorityWork() { + // We don't consider any work as being high priority on workers. + return false; +} + +void WorkerThreadScheduler::AddTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + DCHECK(initialized_); + helper_->AddTaskObserver(task_observer); +} + +void WorkerThreadScheduler::RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + DCHECK(initialized_); + helper_->RemoveTaskObserver(task_observer); +} + +void WorkerThreadScheduler::Shutdown() { + DCHECK(initialized_); + load_tracker_.RecordIdle(helper_->NowTicks()); + base::TimeTicks end_time = helper_->NowTicks(); + base::TimeDelta delta = end_time - thread_start_time_; + + // The lifetime could be radically different for different workers, + // some workers could be short-lived (but last at least 1 sec in + // Service Workers case) or could be around as long as the tab is open. + UMA_HISTOGRAM_CUSTOM_TIMES( + "WorkerThread.Runtime", delta, base::TimeDelta::FromSeconds(1), + base::TimeDelta::FromDays(1), 50 /* bucket count */); + helper_->Shutdown(); +} + +scoped_refptr<WorkerTaskQueue> WorkerThreadScheduler::DefaultTaskQueue() { + DCHECK(initialized_); + return helper_->DefaultWorkerTaskQueue(); +} + +void WorkerThreadScheduler::Init() { + initialized_ = true; + idle_helper_.EnableLongIdlePeriod(); +} + +void WorkerThreadScheduler::OnTaskCompleted( + WorkerTaskQueue* worker_task_queue, + const TaskQueue::Task& task, + base::TimeTicks start, + base::TimeTicks end, + base::Optional<base::TimeDelta> thread_time) { + worker_metrics_helper_.RecordTaskMetrics(worker_task_queue, task, start, end, + thread_time); +} + +SchedulerHelper* WorkerThreadScheduler::GetSchedulerHelperForTesting() { + return helper_.get(); +} + +bool WorkerThreadScheduler::CanEnterLongIdlePeriod(base::TimeTicks, + base::TimeDelta*) { + return true; +} + +base::TimeTicks WorkerThreadScheduler::CurrentIdleTaskDeadlineForTesting() + const { + return idle_helper_.CurrentIdleTaskDeadline(); +} + +void WorkerThreadScheduler::WillProcessTask(double start_time) {} + +void WorkerThreadScheduler::DidProcessTask(double start_time, double end_time) { + base::TimeTicks start_time_ticks = + MonotonicTimeInSecondsToTimeTicks(start_time); + base::TimeTicks end_time_ticks = MonotonicTimeInSecondsToTimeTicks(end_time); + + load_tracker_.RecordTaskTime(start_time_ticks, end_time_ticks); +} + +void WorkerThreadScheduler::OnThrottlingStateChanged( + FrameScheduler::ThrottlingState throttling_state) { + throttling_state_ = throttling_state; +} + +scoped_refptr<WorkerTaskQueue> WorkerThreadScheduler::ControlTaskQueue() { + return helper_->ControlWorkerTaskQueue(); +} + +base::WeakPtr<WorkerThreadScheduler> WorkerThreadScheduler::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + +} // namespace scheduler +} // namespace blink |