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

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

Issue 2606263002: Use background tasks for the compiler dispatcher (Closed)
Patch Set: unit tests 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
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/compiler-dispatcher/compiler-dispatcher-job.h" 9 #include "src/compiler-dispatcher/compiler-dispatcher-job.h"
10 #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h"
9 #include "src/flags.h" 11 #include "src/flags.h"
10 #include "src/handles.h" 12 #include "src/handles.h"
11 #include "src/objects-inl.h" 13 #include "src/objects-inl.h"
14 #include "src/v8.h"
12 #include "test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h" 15 #include "test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h"
13 #include "test/unittests/test-utils.h" 16 #include "test/unittests/test-utils.h"
14 #include "testing/gtest/include/gtest/gtest.h" 17 #include "testing/gtest/include/gtest/gtest.h"
15 18
16 namespace v8 { 19 namespace v8 {
17 namespace internal { 20 namespace internal {
18 21
19 class CompilerDispatcherTest : public TestWithContext { 22 class CompilerDispatcherTest : public TestWithContext {
20 public: 23 public:
21 CompilerDispatcherTest() = default; 24 CompilerDispatcherTest() = default;
(...skipping 11 matching lines...) Expand all
33 } 36 }
34 37
35 private: 38 private:
36 static bool old_flag_; 39 static bool old_flag_;
37 40
38 DISALLOW_COPY_AND_ASSIGN(CompilerDispatcherTest); 41 DISALLOW_COPY_AND_ASSIGN(CompilerDispatcherTest);
39 }; 42 };
40 43
41 bool CompilerDispatcherTest::old_flag_; 44 bool CompilerDispatcherTest::old_flag_;
42 45
46 class IgnitionCompilerDispatcherTest : public CompilerDispatcherTest {
47 public:
48 IgnitionCompilerDispatcherTest() = default;
49 ~IgnitionCompilerDispatcherTest() override = default;
50
51 static void SetUpTestCase() {
52 old_flag_ = i::FLAG_ignition;
53 i::FLAG_ignition = true;
vogelheim 2017/01/03 10:32:37 Is this necessary? unittests/ uses gtest, which h
jochen (gone - plz use gerrit) 2017/01/03 12:59:36 I never heard of that? how does it work? I need t
54 CompilerDispatcherTest::SetUpTestCase();
55 }
56
57 static void TearDownTestCase() {
58 CompilerDispatcherTest::TearDownTestCase();
59 i::FLAG_ignition = old_flag_;
60 }
61
62 private:
63 static bool old_flag_;
64 DISALLOW_COPY_AND_ASSIGN(IgnitionCompilerDispatcherTest);
65 };
66
67 bool IgnitionCompilerDispatcherTest::old_flag_;
68
43 namespace { 69 namespace {
44 70
45 class MockPlatform : public v8::Platform { 71 class MockPlatform : public v8::Platform {
46 public: 72 public:
47 MockPlatform() : task_(nullptr), time_(0.0), time_step_(0.0) {} 73 MockPlatform() : idle_task_(nullptr), time_(0.0), time_step_(0.0), sem_(0) {}
48 ~MockPlatform() override = default; 74 ~MockPlatform() override {
75 EXPECT_TRUE(tasks_.empty());
76 EXPECT_TRUE(idle_task_ == nullptr);
77 }
78
79 size_t NumberOfAvailableBackgroundThreads() override { return 1; }
49 80
50 void CallOnBackgroundThread(Task* task, 81 void CallOnBackgroundThread(Task* task,
51 ExpectedRuntime expected_runtime) override { 82 ExpectedRuntime expected_runtime) override {
52 UNREACHABLE(); 83 tasks_.push_back(task);
53 } 84 }
54 85
55 void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override { 86 void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
56 UNREACHABLE(); 87 UNREACHABLE();
57 } 88 }
58 89
59 void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task, 90 void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
60 double delay_in_seconds) override { 91 double delay_in_seconds) override {
61 UNREACHABLE(); 92 UNREACHABLE();
62 } 93 }
63 94
64 void CallIdleOnForegroundThread(v8::Isolate* isolate, 95 void CallIdleOnForegroundThread(v8::Isolate* isolate,
65 IdleTask* task) override { 96 IdleTask* task) override {
66 task_ = task; 97 idle_task_ = task;
vogelheim 2017/01/03 10:32:37 ASSERT_TRUE(idle_task_ == nullptr) before this lin
jochen (gone - plz use gerrit) 2017/01/03 12:59:36 done
67 } 98 }
68 99
69 bool IdleTasksEnabled(v8::Isolate* isolate) override { return true; } 100 bool IdleTasksEnabled(v8::Isolate* isolate) override { return true; }
70 101
71 double MonotonicallyIncreasingTime() override { 102 double MonotonicallyIncreasingTime() override {
72 time_ += time_step_; 103 time_ += time_step_;
73 return time_; 104 return time_;
74 } 105 }
75 106
76 void RunIdleTask(double deadline_in_seconds, double time_step) { 107 void RunIdleTask(double deadline_in_seconds, double time_step) {
77 ASSERT_TRUE(task_ != nullptr); 108 ASSERT_TRUE(idle_task_ != nullptr);
78 time_step_ = time_step; 109 time_step_ = time_step;
79 IdleTask* task = task_; 110 IdleTask* task = idle_task_;
80 task_ = nullptr; 111 idle_task_ = nullptr;
81 task->Run(deadline_in_seconds); 112 task->Run(deadline_in_seconds);
82 delete task; 113 delete task;
83 } 114 }
84 115
85 bool IdleTaskPending() const { return !!task_; } 116 bool IdleTaskPending() const { return !!idle_task_; }
vogelheim 2017/01/03 10:32:37 nitpick: The !! is a no-op here, since pointer-to-
117
118 bool BackgroundTasksPending() const { return !tasks_.empty(); }
119
120 void RunBackgroundTasksAndBlock(Platform* platform) {
121 std::vector<Task*> tasks;
122 tasks.swap(tasks_);
123 platform->CallOnBackgroundThread(new TaskWrapper(this, tasks, true),
124 kShortRunningTask);
125 sem_.Wait();
126 }
127
128 void RunBackgroundTasks(Platform* platform) {
129 std::vector<Task*> tasks;
130 tasks.swap(tasks_);
131 platform->CallOnBackgroundThread(new TaskWrapper(this, tasks, false),
132 kShortRunningTask);
133 }
134
135 void ClearBackgroundTasks() {
136 std::vector<Task*> tasks;
137 tasks.swap(tasks_);
138 for (auto&& task : tasks) {
vogelheim 2017/01/03 10:32:37 C++ question: Why the auto&& ? (I take it this ma
jochen (gone - plz use gerrit) 2017/01/03 12:59:36 no reason actually, using auto& now
139 delete task;
140 }
141 }
142
143 void ClearIdleTask() {
144 ASSERT_TRUE(idle_task_ != nullptr);
145 delete idle_task_;
146 idle_task_ = nullptr;
147 }
86 148
87 private: 149 private:
88 IdleTask* task_; 150 class TaskWrapper : public Task {
151 public:
152 TaskWrapper(MockPlatform* platform, const std::vector<Task*>& tasks,
153 bool signal)
154 : platform_(platform), tasks_(tasks), signal_(signal) {}
155 ~TaskWrapper() = default;
156
157 void Run() override {
158 for (auto&& task : tasks_) {
159 task->Run();
160 delete task;
161 }
162 if (signal_) platform_->sem_.Signal();
163 }
164
165 private:
166 MockPlatform* platform_;
167 std::vector<Task*> tasks_;
168 bool signal_;
169
170 DISALLOW_COPY_AND_ASSIGN(TaskWrapper);
171 };
172
173 IdleTask* idle_task_;
89 double time_; 174 double time_;
90 double time_step_; 175 double time_step_;
91 176
177 std::vector<Task*> tasks_;
178 base::Semaphore sem_;
179
92 DISALLOW_COPY_AND_ASSIGN(MockPlatform); 180 DISALLOW_COPY_AND_ASSIGN(MockPlatform);
93 }; 181 };
94 182
95 } // namespace 183 } // namespace
96 184
97 TEST_F(CompilerDispatcherTest, Construct) { 185 TEST_F(CompilerDispatcherTest, Construct) {
98 MockPlatform platform; 186 MockPlatform platform;
99 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); 187 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
100 } 188 }
101 189
102 TEST_F(CompilerDispatcherTest, IsEnqueued) { 190 TEST_F(CompilerDispatcherTest, IsEnqueued) {
103 MockPlatform platform; 191 MockPlatform platform;
104 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); 192 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
105 193
106 const char script[] = 194 const char script[] =
107 "function g() { var y = 1; function f1(x) { return x * y }; return f1; } " 195 "function g() { var y = 1; function f1(x) { return x * y }; return f1; } "
108 "g();"; 196 "g();";
109 Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script)); 197 Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
110 Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); 198 Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
111 199
112 ASSERT_FALSE(dispatcher.IsEnqueued(shared)); 200 ASSERT_FALSE(dispatcher.IsEnqueued(shared));
113 ASSERT_TRUE(dispatcher.Enqueue(shared)); 201 ASSERT_TRUE(dispatcher.Enqueue(shared));
114 ASSERT_TRUE(dispatcher.IsEnqueued(shared)); 202 ASSERT_TRUE(dispatcher.IsEnqueued(shared));
115 dispatcher.Abort(shared, CompilerDispatcher::BlockingBehavior::kBlock); 203 dispatcher.AbortAll(CompilerDispatcher::BlockingBehavior::kBlock);
116 ASSERT_FALSE(dispatcher.IsEnqueued(shared)); 204 ASSERT_FALSE(dispatcher.IsEnqueued(shared));
205 ASSERT_TRUE(platform.IdleTaskPending());
206 platform.ClearIdleTask();
117 } 207 }
118 208
119 TEST_F(CompilerDispatcherTest, FinishNow) { 209 TEST_F(CompilerDispatcherTest, FinishNow) {
120 MockPlatform platform; 210 MockPlatform platform;
121 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); 211 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
122 212
123 const char script[] = 213 const char script[] =
124 "function g() { var y = 1; function f2(x) { return x * y }; return f2; } " 214 "function g() { var y = 1; function f2(x) { return x * y }; return f2; } "
125 "g();"; 215 "g();";
126 Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script)); 216 Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
127 Handle<SharedFunctionInfo> shared(f->shared(), i_isolate()); 217 Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
128 218
129 ASSERT_FALSE(shared->is_compiled()); 219 ASSERT_FALSE(shared->is_compiled());
130 ASSERT_TRUE(dispatcher.Enqueue(shared)); 220 ASSERT_TRUE(dispatcher.Enqueue(shared));
131 ASSERT_TRUE(dispatcher.FinishNow(shared)); 221 ASSERT_TRUE(dispatcher.FinishNow(shared));
132 // Finishing removes the SFI from the queue. 222 // Finishing removes the SFI from the queue.
133 ASSERT_FALSE(dispatcher.IsEnqueued(shared)); 223 ASSERT_FALSE(dispatcher.IsEnqueued(shared));
134 ASSERT_TRUE(shared->is_compiled()); 224 ASSERT_TRUE(shared->is_compiled());
225 ASSERT_TRUE(platform.IdleTaskPending());
226 platform.ClearIdleTask();
135 } 227 }
136 228
137 TEST_F(CompilerDispatcherTest, IdleTask) { 229 TEST_F(CompilerDispatcherTest, IdleTask) {
138 MockPlatform platform; 230 MockPlatform platform;
139 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); 231 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
140 232
141 const char script[] = 233 const char script[] =
142 "function g() { var y = 1; function f3(x) { return x * y }; return f3; } " 234 "function g() { var y = 1; function f3(x) { return x * y }; return f3; } "
143 "g();"; 235 "g();";
144 Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script)); 236 Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 ASSERT_TRUE(dispatcher.IsEnqueued(shared)); 273 ASSERT_TRUE(dispatcher.IsEnqueued(shared));
182 ASSERT_FALSE(shared->is_compiled()); 274 ASSERT_FALSE(shared->is_compiled());
183 ASSERT_TRUE(platform.IdleTaskPending()); 275 ASSERT_TRUE(platform.IdleTaskPending());
184 276
185 // The job should be still scheduled for the main thread, but ready for 277 // The job should be still scheduled for the main thread, but ready for
186 // parsing. 278 // parsing.
187 ASSERT_EQ(dispatcher.jobs_.size(), 1u); 279 ASSERT_EQ(dispatcher.jobs_.size(), 1u);
188 ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() == 280 ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
189 CompileJobStatus::kReadyToParse); 281 CompileJobStatus::kReadyToParse);
190 282
191 // Only grant a lot of idle time and freeze time. 283 // Now grant a lot of idle time and freeze time.
192 platform.RunIdleTask(1000.0, 0.0); 284 platform.RunIdleTask(1000.0, 0.0);
193 285
194 ASSERT_FALSE(dispatcher.IsEnqueued(shared)); 286 ASSERT_FALSE(dispatcher.IsEnqueued(shared));
195 ASSERT_TRUE(shared->is_compiled()); 287 ASSERT_TRUE(shared->is_compiled());
196 ASSERT_FALSE(platform.IdleTaskPending()); 288 ASSERT_FALSE(platform.IdleTaskPending());
197 } 289 }
198 290
199 TEST_F(CompilerDispatcherTest, IdleTaskException) { 291 TEST_F(CompilerDispatcherTest, IdleTaskException) {
200 MockPlatform platform; 292 MockPlatform platform;
201 CompilerDispatcher dispatcher(i_isolate(), &platform, 50); 293 CompilerDispatcher dispatcher(i_isolate(), &platform, 50);
(...skipping 16 matching lines...) Expand all
218 310
219 // Since time doesn't progress on the MockPlatform, this is enough idle time 311 // Since time doesn't progress on the MockPlatform, this is enough idle time
220 // to finish compiling the function. 312 // to finish compiling the function.
221 platform.RunIdleTask(1000.0, 0.0); 313 platform.RunIdleTask(1000.0, 0.0);
222 314
223 ASSERT_FALSE(dispatcher.IsEnqueued(shared)); 315 ASSERT_FALSE(dispatcher.IsEnqueued(shared));
224 ASSERT_FALSE(shared->is_compiled()); 316 ASSERT_FALSE(shared->is_compiled());
225 ASSERT_FALSE(try_catch.HasCaught()); 317 ASSERT_FALSE(try_catch.HasCaught());
226 } 318 }
227 319
320 TEST_F(IgnitionCompilerDispatcherTest, CompileOnBackgroundThread) {
321 MockPlatform platform;
marja 2017/01/03 10:42:41 You could make MockPlatform a member of CompilerDi
jochen (gone - plz use gerrit) 2017/01/03 12:59:36 meh, unless you feel strongly about this
marja 2017/01/03 13:14:57 I don't :)
322 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
323
324 const char script[] =
325 "function g() { var y = 1; function f6(x) { return x * y }; return f6; } "
326 "g();";
327 Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
328 Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
329
330 ASSERT_FALSE(platform.IdleTaskPending());
331 ASSERT_TRUE(dispatcher.Enqueue(shared));
332 ASSERT_TRUE(platform.IdleTaskPending());
333
334 ASSERT_EQ(dispatcher.jobs_.size(), 1u);
335 ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
336 CompileJobStatus::kInitial);
337
338 // Make compiling super expensive, and advance job as much as possible on the
339 // foreground thread.
340 dispatcher.tracer_->RecordCompile(50000.0, 1);
341 platform.RunIdleTask(10.0, 0.0);
342 ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
343 CompileJobStatus::kReadyToCompile);
344
345 ASSERT_TRUE(dispatcher.IsEnqueued(shared));
346 ASSERT_FALSE(shared->is_compiled());
347 ASSERT_FALSE(platform.IdleTaskPending());
348 ASSERT_TRUE(platform.BackgroundTasksPending());
349
350 platform.RunBackgroundTasksAndBlock(V8::GetCurrentPlatform());
351
352 ASSERT_TRUE(platform.IdleTaskPending());
353 ASSERT_FALSE(platform.BackgroundTasksPending());
354 ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
355 CompileJobStatus::kCompiled);
356
357 // Now grant a lot of idle time and freeze time.
358 platform.RunIdleTask(1000.0, 0.0);
vogelheim 2017/01/03 10:32:37 [For my understanding:] What does this step accomp
jochen (gone - plz use gerrit) 2017/01/03 12:59:36 this step does the final step of compilation which
359
360 ASSERT_FALSE(dispatcher.IsEnqueued(shared));
361 ASSERT_TRUE(shared->is_compiled());
362 ASSERT_FALSE(platform.IdleTaskPending());
363 }
364
365 TEST_F(IgnitionCompilerDispatcherTest, FinishNowWithBackgroundTask) {
366 MockPlatform platform;
367 CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size);
368
369 const char script[] =
370 "function g() { var y = 1; function f7(x) { return x * y }; return f7; } "
371 "g();";
372 Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
373 Handle<SharedFunctionInfo> shared(f->shared(), i_isolate());
374
375 ASSERT_FALSE(platform.IdleTaskPending());
376 ASSERT_TRUE(dispatcher.Enqueue(shared));
377 ASSERT_TRUE(platform.IdleTaskPending());
378
379 ASSERT_EQ(dispatcher.jobs_.size(), 1u);
380 ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
381 CompileJobStatus::kInitial);
382
383 // Make compiling super expensive, and advance job as much as possible on the
384 // foreground thread.
385 dispatcher.tracer_->RecordCompile(50000.0, 1);
386 platform.RunIdleTask(10.0, 0.0);
387 ASSERT_TRUE(dispatcher.jobs_.begin()->second->status() ==
388 CompileJobStatus::kReadyToCompile);
389
390 ASSERT_TRUE(dispatcher.IsEnqueued(shared));
391 ASSERT_FALSE(shared->is_compiled());
392 ASSERT_FALSE(platform.IdleTaskPending());
393 ASSERT_TRUE(platform.BackgroundTasksPending());
394
395 platform.RunBackgroundTasks(V8::GetCurrentPlatform());
marja 2017/01/03 10:42:41 For documenting what happens, you could assert the
jochen (gone - plz use gerrit) 2017/01/03 12:59:36 RunBackgroundTasks() does not block, so this test
396
397 ASSERT_TRUE(dispatcher.FinishNow(shared));
398 // Finishing removes the SFI from the queue.
399 ASSERT_FALSE(dispatcher.IsEnqueued(shared));
400 ASSERT_TRUE(shared->is_compiled());
401 ASSERT_FALSE(platform.IdleTaskPending());
402 ASSERT_FALSE(platform.BackgroundTasksPending());
403 }
404
228 } // namespace internal 405 } // namespace internal
229 } // namespace v8 406 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698