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

Side by Side Diff: test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc

Issue 2615603002: Implement async AbortAll for the compiler dispatcher (Closed)
Patch Set: updates Created 3 years, 11 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
« no previous file with comments | « test/unittests/cancelable-tasks-unittest.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 the V8 project 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 "src/compiler-dispatcher/compiler-dispatcher.h" 5 #include "src/compiler-dispatcher/compiler-dispatcher.h"
6 6
7 #include "include/v8-platform.h" 7 #include "include/v8-platform.h"
8 #include "src/base/platform/semaphore.h" 8 #include "src/base/platform/semaphore.h"
9 #include "src/compiler-dispatcher/compiler-dispatcher-job.h" 9 #include "src/compiler-dispatcher/compiler-dispatcher-job.h"
10 #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" 10 #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h"
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 static bool old_flag_; 63 static bool old_flag_;
64 DISALLOW_COPY_AND_ASSIGN(IgnitionCompilerDispatcherTest); 64 DISALLOW_COPY_AND_ASSIGN(IgnitionCompilerDispatcherTest);
65 }; 65 };
66 66
67 bool IgnitionCompilerDispatcherTest::old_flag_; 67 bool IgnitionCompilerDispatcherTest::old_flag_;
68 68
69 namespace { 69 namespace {
70 70
71 class MockPlatform : public v8::Platform { 71 class MockPlatform : public v8::Platform {
72 public: 72 public:
73 MockPlatform() : idle_task_(nullptr), time_(0.0), time_step_(0.0), sem_(0) {} 73 MockPlatform() : time_(0.0), time_step_(0.0), idle_task_(nullptr), sem_(0) {}
74 ~MockPlatform() override { 74 ~MockPlatform() override {
75 EXPECT_TRUE(tasks_.empty()); 75 base::LockGuard<base::Mutex> lock(&mutex_);
76 EXPECT_TRUE(foreground_tasks_.empty());
77 EXPECT_TRUE(background_tasks_.empty());
76 EXPECT_TRUE(idle_task_ == nullptr); 78 EXPECT_TRUE(idle_task_ == nullptr);
77 } 79 }
78 80
79 size_t NumberOfAvailableBackgroundThreads() override { return 1; } 81 size_t NumberOfAvailableBackgroundThreads() override { return 1; }
80 82
81 void CallOnBackgroundThread(Task* task, 83 void CallOnBackgroundThread(Task* task,
82 ExpectedRuntime expected_runtime) override { 84 ExpectedRuntime expected_runtime) override {
83 tasks_.push_back(task); 85 base::LockGuard<base::Mutex> lock(&mutex_);
86 background_tasks_.push_back(task);
84 } 87 }
85 88
86 void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override { 89 void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
87 UNREACHABLE(); 90 base::LockGuard<base::Mutex> lock(&mutex_);
91 foreground_tasks_.push_back(task);
88 } 92 }
89 93
90 void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task, 94 void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
91 double delay_in_seconds) override { 95 double delay_in_seconds) override {
92 UNREACHABLE(); 96 UNREACHABLE();
93 } 97 }
94 98
95 void CallIdleOnForegroundThread(v8::Isolate* isolate, 99 void CallIdleOnForegroundThread(v8::Isolate* isolate,
96 IdleTask* task) override { 100 IdleTask* task) override {
101 base::LockGuard<base::Mutex> lock(&mutex_);
97 ASSERT_TRUE(idle_task_ == nullptr); 102 ASSERT_TRUE(idle_task_ == nullptr);
98 idle_task_ = task; 103 idle_task_ = task;
99 } 104 }
100 105
101 bool IdleTasksEnabled(v8::Isolate* isolate) override { return true; } 106 bool IdleTasksEnabled(v8::Isolate* isolate) override { return true; }
102 107
103 double MonotonicallyIncreasingTime() override { 108 double MonotonicallyIncreasingTime() override {
104 time_ += time_step_; 109 time_ += time_step_;
105 return time_; 110 return time_;
106 } 111 }
107 112
108 void RunIdleTask(double deadline_in_seconds, double time_step) { 113 void RunIdleTask(double deadline_in_seconds, double time_step) {
109 ASSERT_TRUE(idle_task_ != nullptr);
110 time_step_ = time_step; 114 time_step_ = time_step;
111 IdleTask* task = idle_task_; 115 IdleTask* task;
112 idle_task_ = nullptr; 116 {
117 base::LockGuard<base::Mutex> lock(&mutex_);
118 task = idle_task_;
119 ASSERT_TRUE(idle_task_ != nullptr);
120 idle_task_ = nullptr;
121 }
113 task->Run(deadline_in_seconds); 122 task->Run(deadline_in_seconds);
114 delete task; 123 delete task;
115 } 124 }
116 125
117 bool IdleTaskPending() const { return idle_task_; } 126 bool IdleTaskPending() {
127 base::LockGuard<base::Mutex> lock(&mutex_);
128 return idle_task_;
129 }
118 130
119 bool BackgroundTasksPending() const { return !tasks_.empty(); } 131 bool BackgroundTasksPending() {
132 base::LockGuard<base::Mutex> lock(&mutex_);
133 return !background_tasks_.empty();
134 }
135
136 bool ForegroundTasksPending() {
137 base::LockGuard<base::Mutex> lock(&mutex_);
138 return !foreground_tasks_.empty();
139 }
120 140
121 void RunBackgroundTasksAndBlock(Platform* platform) { 141 void RunBackgroundTasksAndBlock(Platform* platform) {
122 std::vector<Task*> tasks; 142 std::vector<Task*> tasks;
123 tasks.swap(tasks_); 143 {
144 base::LockGuard<base::Mutex> lock(&mutex_);
145 tasks.swap(background_tasks_);
146 }
124 platform->CallOnBackgroundThread(new TaskWrapper(this, tasks, true), 147 platform->CallOnBackgroundThread(new TaskWrapper(this, tasks, true),
125 kShortRunningTask); 148 kShortRunningTask);
126 sem_.Wait(); 149 sem_.Wait();
127 } 150 }
128 151
129 void RunBackgroundTasks(Platform* platform) { 152 void RunBackgroundTasks(Platform* platform) {
130 std::vector<Task*> tasks; 153 std::vector<Task*> tasks;
131 tasks.swap(tasks_); 154 {
155 base::LockGuard<base::Mutex> lock(&mutex_);
156 tasks.swap(background_tasks_);
157 }
132 platform->CallOnBackgroundThread(new TaskWrapper(this, tasks, false), 158 platform->CallOnBackgroundThread(new TaskWrapper(this, tasks, false),
133 kShortRunningTask); 159 kShortRunningTask);
134 } 160 }
135 161
162 void RunForegroundTasks() {
163 std::vector<Task*> tasks;
164 {
165 base::LockGuard<base::Mutex> lock(&mutex_);
166 tasks.swap(foreground_tasks_);
167 }
168 for (auto& task : tasks) {
169 task->Run();
170 delete task;
171 }
172 }
173
136 void ClearBackgroundTasks() { 174 void ClearBackgroundTasks() {
137 std::vector<Task*> tasks; 175 std::vector<Task*> tasks;
138 tasks.swap(tasks_); 176 {
177 base::LockGuard<base::Mutex> lock(&mutex_);
178 tasks.swap(background_tasks_);
179 }
180 for (auto& task : tasks) {
181 delete task;
182 }
183 }
184
185 void ClearForegroundTasks() {
186 std::vector<Task*> tasks;
187 {
188 base::LockGuard<base::Mutex> lock(&mutex_);
189 tasks.swap(foreground_tasks_);
190 }
139 for (auto& task : tasks) { 191 for (auto& task : tasks) {
140 delete task; 192 delete task;
141 } 193 }
142 } 194 }
143 195
144 void ClearIdleTask() { 196 void ClearIdleTask() {
197 base::LockGuard<base::Mutex> lock(&mutex_);
145 ASSERT_TRUE(idle_task_ != nullptr); 198 ASSERT_TRUE(idle_task_ != nullptr);
146 delete idle_task_; 199 delete idle_task_;
147 idle_task_ = nullptr; 200 idle_task_ = nullptr;
148 } 201 }
149 202
150 private: 203 private:
151 class TaskWrapper : public Task { 204 class TaskWrapper : public Task {
152 public: 205 public:
153 TaskWrapper(MockPlatform* platform, const std::vector<Task*>& tasks, 206 TaskWrapper(MockPlatform* platform, const std::vector<Task*>& tasks,
154 bool signal) 207 bool signal)
155 : platform_(platform), tasks_(tasks), signal_(signal) {} 208 : platform_(platform), tasks_(tasks), signal_(signal) {}
156 ~TaskWrapper() = default; 209 ~TaskWrapper() = default;
157 210
158 void Run() override { 211 void Run() override {
159 for (auto& task : tasks_) { 212 for (auto& task : tasks_) {
160 task->Run(); 213 task->Run();
161 delete task; 214 delete task;
162 } 215 }
163 if (signal_) platform_->sem_.Signal(); 216 if (signal_) platform_->sem_.Signal();
164 } 217 }
165 218
166 private: 219 private:
167 MockPlatform* platform_; 220 MockPlatform* platform_;
168 std::vector<Task*> tasks_; 221 std::vector<Task*> tasks_;
169 bool signal_; 222 bool signal_;
170 223
171 DISALLOW_COPY_AND_ASSIGN(TaskWrapper); 224 DISALLOW_COPY_AND_ASSIGN(TaskWrapper);
172 }; 225 };
173 226
174 IdleTask* idle_task_;
175 double time_; 227 double time_;
176 double time_step_; 228 double time_step_;
177 229
178 std::vector<Task*> tasks_; 230 // Protects all *_tasks_.
231 base::Mutex mutex_;
232
233 IdleTask* idle_task_;
234 std::vector<Task*> background_tasks_;
235 std::vector<Task*> foreground_tasks_;
236
179 base::Semaphore sem_; 237 base::Semaphore sem_;
180 238
181 DISALLOW_COPY_AND_ASSIGN(MockPlatform); 239 DISALLOW_COPY_AND_ASSIGN(MockPlatform);
182 }; 240 };
183 241
184 } // namespace 242 } // namespace
185 243
186 TEST_F(CompilerDispatcherTest, Construct) { 244 TEST_F(CompilerDispatcherTest, Construct) {
187 MockPlatform platform; 245 MockPlatform platform;
188 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); 246 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
452 ASSERT_FALSE(dispatcher.FinishNow(shared)); 510 ASSERT_FALSE(dispatcher.FinishNow(shared));
453 511
454 ASSERT_FALSE(dispatcher.IsEnqueued(shared)); 512 ASSERT_FALSE(dispatcher.IsEnqueued(shared));
455 ASSERT_FALSE(shared->is_compiled()); 513 ASSERT_FALSE(shared->is_compiled());
456 ASSERT_TRUE(i_isolate()->has_pending_exception()); 514 ASSERT_TRUE(i_isolate()->has_pending_exception());
457 515
458 i_isolate()->clear_pending_exception(); 516 i_isolate()->clear_pending_exception();
459 platform.ClearIdleTask(); 517 platform.ClearIdleTask();
460 } 518 }
461 519
520 TEST_F(IgnitionCompilerDispatcherTest, AsyncAbortAllPendingBackgroundTask) {
521 MockPlatform platform;
522 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
523
524 const char script[] =
525 "function g() { var y = 1; function f11(x) { return x * y }; return f11; "
526 "} g();";
527 Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
528 Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
529
530 ASSERT_FALSE(platform.IdleTaskPending());
531 ASSERT_TRUE(dispatcher.Enqueue(shared));
532 ASSERT_TRUE(platform.IdleTaskPending());
533
534 ASSERT_EQ(dispatcher.jobs_.size(), 1u);
535 ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
536 CompileJobStatus::kInitial);
537
538 // Make compiling super expensive, and advance job as much as possible on the
539 // foreground thread.
540 dispatcher.tracer_->RecordCompile(50000.0, 1);
541 platform.RunIdleTask(10.0, 0.0);
542 ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
543 CompileJobStatus::kReadyToCompile);
544
545 ASSERT_TRUE(dispatcher.IsEnqueued(shared));
546 ASSERT_FALSE(shared->is_compiled());
547 ASSERT_FALSE(platform.IdleTaskPending());
548 ASSERT_TRUE(platform.BackgroundTasksPending());
549
550 // The background task hasn't yet started, so we can just cancel it.
551 dispatcher.AbortAll(CompilerDispatcher::BlockingBehavior::kDontBlock);
552 ASSERT_FALSE(platform.ForegroundTasksPending());
553
554 ASSERT_FALSE(dispatcher.IsEnqueued(shared));
555 ASSERT_FALSE(shared->is_compiled());
556
557 platform.RunBackgroundTasksAndBlock(V8::GetCurrentPlatform());
558
559 if (platform.IdleTaskPending()) platform.ClearIdleTask();
560 ASSERT_FALSE(platform.BackgroundTasksPending());
561 ASSERT_FALSE(platform.ForegroundTasksPending());
562 }
563
564 TEST_F(IgnitionCompilerDispatcherTest, AsyncAbortAllRunningBackgroundTask) {
565 MockPlatform platform;
566 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
567
568 const char script1[] =
569 "function g() { var y = 1; function f11(x) { return x * y }; return f11; "
570 "} g();";
571 Handle<JSFunction> f1 = Handle<JSFunction>::cast(RunJS(isolate(), script1));
572 Handle<SharedFunctionInfo> shared1(f1->shared(), i_isolate());
573
574 const char script2[] =
575 "function g() { var y = 1; function f12(x) { return x * y }; return f12; "
576 "} g();";
577 Handle<JSFunction> f2 = Handle<JSFunction>::cast(RunJS(isolate(), script2));
578 Handle<SharedFunctionInfo> shared2(f2->shared(), i_isolate());
579
580 ASSERT_FALSE(platform.IdleTaskPending());
581 ASSERT_TRUE(dispatcher.Enqueue(shared1));
582 ASSERT_TRUE(platform.IdleTaskPending());
583
584 ASSERT_EQ(dispatcher.jobs_.size(), 1u);
585 ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
586 CompileJobStatus::kInitial);
587
588 // Make compiling super expensive, and advance job as much as possible on the
589 // foreground thread.
590 dispatcher.tracer_->RecordCompile(50000.0, 1);
591 platform.RunIdleTask(10.0, 0.0);
592 ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
593 CompileJobStatus::kReadyToCompile);
594
595 ASSERT_TRUE(dispatcher.IsEnqueued(shared1));
596 ASSERT_FALSE(shared1->is_compiled());
597 ASSERT_FALSE(platform.IdleTaskPending());
598 ASSERT_TRUE(platform.BackgroundTasksPending());
599
600 // Kick off background tasks and freeze them.
601 dispatcher.block_for_testing_.SetValue(true);
602 platform.RunBackgroundTasks(V8::GetCurrentPlatform());
603
604 // Busy loop until the background task started running.
605 while (dispatcher.block_for_testing_.Value()) {
606 }
607 dispatcher.AbortAll(CompilerDispatcher::BlockingBehavior::kDontBlock);
608 ASSERT_TRUE(platform.ForegroundTasksPending());
609
610 // We can't schedule new tasks while we're aborting.
611 ASSERT_FALSE(dispatcher.Enqueue(shared2));
612
613 // Run the first AbortTask. Since the background job is still pending, it
614 // can't do anything.
615 platform.RunForegroundTasks();
616 {
617 base::LockGuard<base::Mutex> lock(&dispatcher.mutex_);
618 ASSERT_TRUE(dispatcher.abort_);
619 }
620
621 // Release background task.
622 dispatcher.semaphore_for_testing_.Signal();
623
624 // Busy loop until the background task scheduled another AbortTask task.
625 while (!platform.ForegroundTasksPending()) {
626 }
627
628 platform.RunForegroundTasks();
629 ASSERT_TRUE(dispatcher.jobs_.empty());
630 {
631 base::LockGuard<base::Mutex> lock(&dispatcher.mutex_);
632 ASSERT_FALSE(dispatcher.abort_);
633 }
634
635 ASSERT_TRUE(platform.IdleTaskPending());
636 platform.RunIdleTask(5.0, 1.0);
637 ASSERT_FALSE(platform.BackgroundTasksPending());
638 ASSERT_FALSE(platform.ForegroundTasksPending());
639
640 // Now it's possible to enqueue new functions again.
641 ASSERT_TRUE(dispatcher.Enqueue(shared2));
642 ASSERT_TRUE(platform.IdleTaskPending());
643 ASSERT_FALSE(platform.BackgroundTasksPending());
644 ASSERT_FALSE(platform.ForegroundTasksPending());
645 platform.ClearIdleTask();
646 }
647
648 TEST_F(IgnitionCompilerDispatcherTest, FinishNowDuringAbortAll) {
649 MockPlatform platform;
650 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
651
652 const char script[] =
653 "function g() { var y = 1; function f13(x) { return x * y }; return f13; "
654 "} g();";
655 Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
656 Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
657
658 ASSERT_FALSE(platform.IdleTaskPending());
659 ASSERT_TRUE(dispatcher.Enqueue(shared));
660 ASSERT_TRUE(platform.IdleTaskPending());
661
662 ASSERT_EQ(dispatcher.jobs_.size(), 1u);
663 ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
664 CompileJobStatus::kInitial);
665
666 // Make compiling super expensive, and advance job as much as possible on the
667 // foreground thread.
668 dispatcher.tracer_->RecordCompile(50000.0, 1);
669 platform.RunIdleTask(10.0, 0.0);
670 ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
671 CompileJobStatus::kReadyToCompile);
672
673 ASSERT_TRUE(dispatcher.IsEnqueued(shared));
674 ASSERT_FALSE(shared->is_compiled());
675 ASSERT_FALSE(platform.IdleTaskPending());
676 ASSERT_TRUE(platform.BackgroundTasksPending());
677
678 // Kick off background tasks and freeze them.
679 dispatcher.block_for_testing_.SetValue(true);
680 platform.RunBackgroundTasks(V8::GetCurrentPlatform());
681
682 // Busy loop until the background task started running.
683 while (dispatcher.block_for_testing_.Value()) {
684 }
685 dispatcher.AbortAll(CompilerDispatcher::BlockingBehavior::kDontBlock);
686 ASSERT_TRUE(platform.ForegroundTasksPending());
687
688 // Run the first AbortTask. Since the background job is still pending, it
689 // can't do anything.
690 platform.RunForegroundTasks();
691 {
692 base::LockGuard<base::Mutex> lock(&dispatcher.mutex_);
693 ASSERT_TRUE(dispatcher.abort_);
694 }
695
696 // While the background thread holds on to a job, it is still enqueud.
697 ASSERT_TRUE(dispatcher.IsEnqueued(shared));
698
699 // Release background task.
700 dispatcher.semaphore_for_testing_.Signal();
701
702 // Force the compilation to finish, even while aborting.
703 ASSERT_TRUE(dispatcher.FinishNow(shared));
704 ASSERT_TRUE(dispatcher.jobs_.empty());
705 {
706 base::LockGuard<base::Mutex> lock(&dispatcher.mutex_);
707 ASSERT_FALSE(dispatcher.abort_);
708 }
709
710 ASSERT_TRUE(platform.ForegroundTasksPending());
711 ASSERT_TRUE(platform.IdleTaskPending());
712 ASSERT_FALSE(platform.BackgroundTasksPending());
713 platform.ClearForegroundTasks();
714 platform.ClearIdleTask();
715 }
716
462 } // namespace internal 717 } // namespace internal
463 } // namespace v8 718 } // namespace v8
OLDNEW
« no previous file with comments | « test/unittests/cancelable-tasks-unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698