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

Side by Side Diff: base/task_scheduler/scheduler_worker_pool_impl.cc

Issue 2430633003: TaskScheduler: Record TaskScheduler.NumTasksBeforeDetach.* from OnDetach(). (Closed)
Patch Set: CR gab #3 rebase Created 4 years, 2 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 unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/task_scheduler/scheduler_worker_pool_impl.h" 5 #include "base/task_scheduler/scheduler_worker_pool_impl.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <utility> 10 #include <utility>
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 const ReEnqueueSequenceCallback& re_enqueue_sequence_callback, 230 const ReEnqueueSequenceCallback& re_enqueue_sequence_callback,
231 const PriorityQueue* shared_priority_queue, 231 const PriorityQueue* shared_priority_queue,
232 int index); 232 int index);
233 ~SchedulerWorkerDelegateImpl() override; 233 ~SchedulerWorkerDelegateImpl() override;
234 234
235 PriorityQueue* single_threaded_priority_queue() { 235 PriorityQueue* single_threaded_priority_queue() {
236 return &single_threaded_priority_queue_; 236 return &single_threaded_priority_queue_;
237 } 237 }
238 238
239 // SchedulerWorker::Delegate: 239 // SchedulerWorker::Delegate:
240 void OnMainEntry(SchedulerWorker* worker, 240 void OnMainEntry(SchedulerWorker* worker) override;
241 const TimeDelta& detach_duration) override;
242 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override; 241 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override;
243 void DidRunTaskWithPriority(TaskPriority task_priority, 242 void DidRunTaskWithPriority(TaskPriority task_priority,
244 const TimeDelta& task_latency) override; 243 const TimeDelta& task_latency) override;
245 void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override; 244 void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override;
246 TimeDelta GetSleepTimeout() override; 245 TimeDelta GetSleepTimeout() override;
247 bool CanDetach(SchedulerWorker* worker) override; 246 bool CanDetach(SchedulerWorker* worker) override;
247 void OnDetach() override;
248 248
249 void RegisterSingleThreadTaskRunner() { 249 void RegisterSingleThreadTaskRunner() {
250 // No barrier as barriers only affect sequential consistency which is 250 // No barrier as barriers only affect sequential consistency which is
251 // irrelevant in a single variable use case (they don't force an immediate 251 // irrelevant in a single variable use case (they don't force an immediate
252 // flush anymore than atomics do by default). 252 // flush anymore than atomics do by default).
253 subtle::NoBarrier_AtomicIncrement(&num_single_threaded_runners_, 1); 253 subtle::NoBarrier_AtomicIncrement(&num_single_threaded_runners_, 1);
254 } 254 }
255 255
256 void UnregisterSingleThreadTaskRunner() { 256 void UnregisterSingleThreadTaskRunner() {
257 subtle::NoBarrier_AtomicIncrement(&num_single_threaded_runners_, -1); 257 subtle::NoBarrier_AtomicIncrement(&num_single_threaded_runners_, -1);
258 } 258 }
259 259
260 private: 260 private:
261 SchedulerWorkerPoolImpl* outer_; 261 SchedulerWorkerPoolImpl* outer_;
262 const ReEnqueueSequenceCallback re_enqueue_sequence_callback_; 262 const ReEnqueueSequenceCallback re_enqueue_sequence_callback_;
263 263
264 // Single-threaded PriorityQueue for the worker. 264 // Single-threaded PriorityQueue for the worker.
265 PriorityQueue single_threaded_priority_queue_; 265 PriorityQueue single_threaded_priority_queue_;
266 266
267 // True if the last Sequence returned by GetWork() was extracted from 267 // True if the last Sequence returned by GetWork() was extracted from
268 // |single_threaded_priority_queue_|. 268 // |single_threaded_priority_queue_|.
269 bool last_sequence_is_single_threaded_ = false; 269 bool last_sequence_is_single_threaded_ = false;
270 270
271 // Time of the last detach.
272 TimeTicks last_detach_time_;
273
271 // Time when GetWork() first returned nullptr. 274 // Time when GetWork() first returned nullptr.
272 TimeTicks idle_start_time_; 275 TimeTicks idle_start_time_;
273 276
274 // Indicates whether the last call to GetWork() returned nullptr. 277 // Indicates whether the last call to GetWork() returned nullptr.
275 bool last_get_work_returned_nullptr_ = false; 278 bool last_get_work_returned_nullptr_ = false;
276 279
277 // Indicates whether the SchedulerWorker was detached since the last call to 280 // Indicates whether the SchedulerWorker was detached since the last call to
278 // GetWork(). 281 // GetWork().
279 bool did_detach_since_last_get_work_ = false; 282 bool did_detach_since_last_get_work_ = false;
280 283
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 int index) 477 int index)
475 : outer_(outer), 478 : outer_(outer),
476 re_enqueue_sequence_callback_(re_enqueue_sequence_callback), 479 re_enqueue_sequence_callback_(re_enqueue_sequence_callback),
477 single_threaded_priority_queue_(shared_priority_queue), 480 single_threaded_priority_queue_(shared_priority_queue),
478 index_(index) {} 481 index_(index) {}
479 482
480 SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl:: 483 SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::
481 ~SchedulerWorkerDelegateImpl() = default; 484 ~SchedulerWorkerDelegateImpl() = default;
482 485
483 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::OnMainEntry( 486 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::OnMainEntry(
484 SchedulerWorker* worker, 487 SchedulerWorker* worker) {
485 const TimeDelta& detach_duration) {
486 #if DCHECK_IS_ON() 488 #if DCHECK_IS_ON()
487 // Wait for |outer_->workers_created_| to avoid traversing 489 // Wait for |outer_->workers_created_| to avoid traversing
488 // |outer_->workers_| while it is being filled by Initialize(). 490 // |outer_->workers_| while it is being filled by Initialize().
489 outer_->workers_created_.Wait(); 491 outer_->workers_created_.Wait();
490 DCHECK(ContainsWorker(outer_->workers_, worker)); 492 DCHECK(ContainsWorker(outer_->workers_, worker));
491 #endif 493 #endif
492 494
493 DCHECK_EQ(num_tasks_since_last_wait_, 0U); 495 DCHECK_EQ(num_tasks_since_last_wait_, 0U);
494 496
495 // Record histograms if the worker detached in the past. 497 if (!last_detach_time_.is_null()) {
496 if (!detach_duration.is_max()) { 498 outer_->detach_duration_histogram_->AddTime(TimeTicks::Now() -
497 outer_->detach_duration_histogram_->AddTime(detach_duration); 499 last_detach_time_);
498 outer_->num_tasks_before_detach_histogram_->Add(
499 num_tasks_since_last_detach_);
500 num_tasks_since_last_detach_ = 0;
501 did_detach_since_last_get_work_ = true;
502 } 500 }
503 501
504 PlatformThread::SetName( 502 PlatformThread::SetName(
505 StringPrintf("TaskScheduler%sWorker%d", outer_->name_.c_str(), index_)); 503 StringPrintf("TaskScheduler%sWorker%d", outer_->name_.c_str(), index_));
506 504
507 DCHECK(!tls_current_worker.Get().Get()); 505 DCHECK(!tls_current_worker.Get().Get());
508 DCHECK(!tls_current_worker_pool.Get().Get()); 506 DCHECK(!tls_current_worker_pool.Get().Get());
509 tls_current_worker.Get().Set(worker); 507 tls_current_worker.Get().Set(worker);
510 tls_current_worker_pool.Get().Set(outer_); 508 tls_current_worker_pool.Get().Set(outer_);
511 509
512 // New threads haven't run GetWork() yet, so reset the |idle_start_time_|. 510 // New threads haven't run GetWork() yet, so reset the |idle_start_time_|.
513 idle_start_time_ = TimeTicks(); 511 idle_start_time_ = TimeTicks();
514 512
515 ThreadRestrictions::SetIOAllowed( 513 ThreadRestrictions::SetIOAllowed(
516 outer_->io_restriction_ == 514 outer_->io_restriction_ ==
517 SchedulerWorkerPoolParams::IORestriction::ALLOWED); 515 SchedulerWorkerPoolParams::IORestriction::ALLOWED);
518 } 516 }
519 517
520 scoped_refptr<Sequence> 518 scoped_refptr<Sequence>
521 SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::GetWork( 519 SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::GetWork(
522 SchedulerWorker* worker) { 520 SchedulerWorker* worker) {
523 DCHECK(ContainsWorker(outer_->workers_, worker)); 521 DCHECK(ContainsWorker(outer_->workers_, worker));
524 522
525 // Record the TaskScheduler.NumTasksBetweenWaits histogram if the 523 // Record the TaskScheduler.NumTasksBetweenWaits histogram if the
526 // SchedulerWorker waited on its WaitableEvent since the last GetWork(). 524 // SchedulerWorker waited on its WaitableEvent since the last GetWork().
527 // 525 //
528 // Note: When GetWork() returns nullptr for the first time after returning a 526 // Note: When GetWork() starts returning nullptr, the SchedulerWorker waits on
529 // Sequence, SchedulerWorker waits on its WaitableEvent. When the wait stops 527 // its WaitableEvent. When it wakes up (either because WakeUp() was called or
530 // (either because WakeUp() was called or because the sleep timeout expired), 528 // because the sleep timeout expired), it calls GetWork() again. The code
531 // GetWork() is called and the histogram is recorded. If GetWork() returns 529 // below records the histogram and, if GetWork() returns nullptr again, the
532 // nullptr again, the SchedulerWorker may detach. 530 // SchedulerWorker may detach. If that happens,
533 // |did_detach_since_last_get_work_| is set to true from OnMainEntry() if the 531 // |did_detach_since_last_get_work_| is set to true and the next call to
534 // SchedulerWorker detaches and wakes up again. The next call to GetWork() 532 // GetWork() won't record the histogram (which is correct since the
535 // won't record the histogram (which is correct since the SchedulerWorker 533 // SchedulerWorker didn't wait on its WaitableEvent since the last time the
536 // didn't wait on its WaitableEvent since the last time the histogram was 534 // histogram was recorded).
537 // recorded).
538 if (last_get_work_returned_nullptr_ && !did_detach_since_last_get_work_) { 535 if (last_get_work_returned_nullptr_ && !did_detach_since_last_get_work_) {
539 outer_->num_tasks_between_waits_histogram_->Add(num_tasks_since_last_wait_); 536 outer_->num_tasks_between_waits_histogram_->Add(num_tasks_since_last_wait_);
540 num_tasks_since_last_wait_ = 0; 537 num_tasks_since_last_wait_ = 0;
541 } 538 }
542 539
543 scoped_refptr<Sequence> sequence; 540 scoped_refptr<Sequence> sequence;
544 { 541 {
545 std::unique_ptr<PriorityQueue::Transaction> shared_transaction( 542 std::unique_ptr<PriorityQueue::Transaction> shared_transaction(
546 outer_->shared_priority_queue_.BeginTransaction()); 543 outer_->shared_priority_queue_.BeginTransaction());
547 std::unique_ptr<PriorityQueue::Transaction> single_threaded_transaction( 544 std::unique_ptr<PriorityQueue::Transaction> single_threaded_transaction(
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
652 // created by the worker. 649 // created by the worker.
653 const bool can_detach = 650 const bool can_detach =
654 !idle_start_time_.is_null() && 651 !idle_start_time_.is_null() &&
655 (TimeTicks::Now() - idle_start_time_) > outer_->suggested_reclaim_time_ && 652 (TimeTicks::Now() - idle_start_time_) > outer_->suggested_reclaim_time_ &&
656 worker != outer_->PeekAtIdleWorkersStack() && 653 worker != outer_->PeekAtIdleWorkersStack() &&
657 !subtle::NoBarrier_Load(&num_single_threaded_runners_) && 654 !subtle::NoBarrier_Load(&num_single_threaded_runners_) &&
658 outer_->CanWorkerDetachForTesting(); 655 outer_->CanWorkerDetachForTesting();
659 return can_detach; 656 return can_detach;
660 } 657 }
661 658
659 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::OnDetach() {
660 DCHECK(!did_detach_since_last_get_work_);
661 outer_->num_tasks_before_detach_histogram_->Add(num_tasks_since_last_detach_);
662 num_tasks_since_last_detach_ = 0;
663 did_detach_since_last_get_work_ = true;
664 last_detach_time_ = TimeTicks::Now();
665 }
666
662 SchedulerWorkerPoolImpl::SchedulerWorkerPoolImpl( 667 SchedulerWorkerPoolImpl::SchedulerWorkerPoolImpl(
663 StringPiece name, 668 StringPiece name,
664 SchedulerWorkerPoolParams::IORestriction io_restriction, 669 SchedulerWorkerPoolParams::IORestriction io_restriction,
665 const TimeDelta& suggested_reclaim_time, 670 const TimeDelta& suggested_reclaim_time,
666 TaskTracker* task_tracker, 671 TaskTracker* task_tracker,
667 DelayedTaskManager* delayed_task_manager) 672 DelayedTaskManager* delayed_task_manager)
668 : name_(name.as_string()), 673 : name_(name.as_string()),
669 io_restriction_(io_restriction), 674 io_restriction_(io_restriction),
670 suggested_reclaim_time_(suggested_reclaim_time), 675 suggested_reclaim_time_(suggested_reclaim_time),
671 idle_workers_stack_lock_(shared_priority_queue_.container_lock()), 676 idle_workers_stack_lock_(shared_priority_queue_.container_lock()),
672 idle_workers_stack_cv_for_testing_( 677 idle_workers_stack_cv_for_testing_(
673 idle_workers_stack_lock_.CreateConditionVariable()), 678 idle_workers_stack_lock_.CreateConditionVariable()),
674 join_for_testing_returned_(WaitableEvent::ResetPolicy::MANUAL, 679 join_for_testing_returned_(WaitableEvent::ResetPolicy::MANUAL,
675 WaitableEvent::InitialState::NOT_SIGNALED), 680 WaitableEvent::InitialState::NOT_SIGNALED),
676 #if DCHECK_IS_ON() 681 #if DCHECK_IS_ON()
677 workers_created_(WaitableEvent::ResetPolicy::MANUAL, 682 workers_created_(WaitableEvent::ResetPolicy::MANUAL,
678 WaitableEvent::InitialState::NOT_SIGNALED), 683 WaitableEvent::InitialState::NOT_SIGNALED),
679 #endif 684 #endif
680 // Mimics the UMA_HISTOGRAM_LONG_TIMES macro. 685 // Mimics the UMA_HISTOGRAM_LONG_TIMES macro.
681 detach_duration_histogram_(Histogram::FactoryTimeGet( 686 detach_duration_histogram_(Histogram::FactoryTimeGet(
682 kDetachDurationHistogramPrefix + name_ + kPoolNameSuffix, 687 kDetachDurationHistogramPrefix + name_ + kPoolNameSuffix,
683 TimeDelta::FromMilliseconds(1), 688 TimeDelta::FromMilliseconds(1),
684 TimeDelta::FromHours(1), 689 TimeDelta::FromHours(1),
685 50, 690 50,
686 HistogramBase::kUmaTargetedHistogramFlag)), 691 HistogramBase::kUmaTargetedHistogramFlag)),
687 // Mimics the UMA_HISTOGRAM_COUNTS_1000 macro. A SchedulerWorker is 692 // Mimics the UMA_HISTOGRAM_COUNTS_1000 macro. When a worker runs more
688 // expected to run between zero and a few hundreds of tasks before 693 // than 1000 tasks before detaching, there is no need to know the exact
689 // detaching. When it runs more than 1000 tasks, there is no need to know 694 // number of tasks that ran.
690 // the exact number of tasks that ran.
691 num_tasks_before_detach_histogram_(Histogram::FactoryGet( 695 num_tasks_before_detach_histogram_(Histogram::FactoryGet(
692 kNumTasksBeforeDetachHistogramPrefix + name_ + kPoolNameSuffix, 696 kNumTasksBeforeDetachHistogramPrefix + name_ + kPoolNameSuffix,
693 1, 697 1,
694 1000, 698 1000,
695 50, 699 50,
696 HistogramBase::kUmaTargetedHistogramFlag)), 700 HistogramBase::kUmaTargetedHistogramFlag)),
697 // Mimics the UMA_HISTOGRAM_COUNTS_100 macro. A SchedulerWorker is 701 // Mimics the UMA_HISTOGRAM_COUNTS_100 macro. A SchedulerWorker is
698 // expected to run between zero and a few tens of tasks between waits. 702 // expected to run between zero and a few tens of tasks between waits.
699 // When it runs more than 100 tasks, there is no need to know the exact 703 // When it runs more than 100 tasks, there is no need to know the exact
700 // number of tasks that ran. 704 // number of tasks that ran.
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
786 AutoSchedulerLock auto_lock(idle_workers_stack_lock_); 790 AutoSchedulerLock auto_lock(idle_workers_stack_lock_);
787 idle_workers_stack_.Remove(worker); 791 idle_workers_stack_.Remove(worker);
788 } 792 }
789 793
790 bool SchedulerWorkerPoolImpl::CanWorkerDetachForTesting() { 794 bool SchedulerWorkerPoolImpl::CanWorkerDetachForTesting() {
791 return !worker_detachment_disallowed_.IsSet(); 795 return !worker_detachment_disallowed_.IsSet();
792 } 796 }
793 797
794 } // namespace internal 798 } // namespace internal
795 } // namespace base 799 } // namespace base
OLDNEW
« no previous file with comments | « base/task_scheduler/scheduler_worker.cc ('k') | base/task_scheduler/scheduler_worker_pool_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698