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

Side by Side Diff: src/compiler-dispatcher/compiler-dispatcher.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
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 "include/v8.h" 8 #include "include/v8.h"
9 #include "src/base/platform/time.h" 9 #include "src/base/platform/time.h"
10 #include "src/cancelable-task.h" 10 #include "src/cancelable-task.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 45
46 case CompileJobStatus::kCompiled: 46 case CompileJobStatus::kCompiled:
47 job->FinalizeCompilingOnMainThread(); 47 job->FinalizeCompilingOnMainThread();
48 break; 48 break;
49 49
50 case CompileJobStatus::kFailed: 50 case CompileJobStatus::kFailed:
51 case CompileJobStatus::kDone: 51 case CompileJobStatus::kDone:
52 break; 52 break;
53 } 53 }
54 54
55 if (job->status() == CompileJobStatus::kFailed) { 55 DCHECK_EQ(job->status() == CompileJobStatus::kFailed,
56 DCHECK(isolate->has_pending_exception()); 56 isolate->has_pending_exception());
57 if (exception_handling == ExceptionHandling::kSwallow) { 57 if (job->status() == CompileJobStatus::kFailed &&
58 isolate->clear_pending_exception(); 58 exception_handling == ExceptionHandling::kSwallow) {
59 } 59 isolate->clear_pending_exception();
60 } else {
61 DCHECK(!isolate->has_pending_exception());
62 } 60 }
63 return job->status() != CompileJobStatus::kFailed; 61 return job->status() != CompileJobStatus::kFailed;
64 } 62 }
65 63
66 bool IsFinished(CompilerDispatcherJob* job) { 64 bool IsFinished(CompilerDispatcherJob* job) {
67 return job->status() == CompileJobStatus::kDone || 65 return job->status() == CompileJobStatus::kDone ||
68 job->status() == CompileJobStatus::kFailed; 66 job->status() == CompileJobStatus::kFailed;
69 } 67 }
70 68
71 bool CanRunOnAnyThread(CompilerDispatcherJob* job) { 69 bool CanRunOnAnyThread(CompilerDispatcherJob* job) {
(...skipping 18 matching lines...) Expand all
90 UNREACHABLE(); 88 UNREACHABLE();
91 } 89 }
92 } 90 }
93 91
94 // Theoretically we get 50ms of idle time max, however it's unlikely that 92 // Theoretically we get 50ms of idle time max, however it's unlikely that
95 // we'll get all of it so try to be a conservative. 93 // we'll get all of it so try to be a conservative.
96 const double kMaxIdleTimeToExpectInMs = 40; 94 const double kMaxIdleTimeToExpectInMs = 40;
97 95
98 } // namespace 96 } // namespace
99 97
98 class CompilerDispatcher::AbortTask : public CancelableTask {
99 public:
100 AbortTask(Isolate* isolate, CancelableTaskManager* task_manager,
101 CompilerDispatcher* dispatcher);
102 ~AbortTask() override;
103
104 // CancelableTask implementation.
105 void RunInternal() override;
106
107 private:
108 CompilerDispatcher* dispatcher_;
109
110 DISALLOW_COPY_AND_ASSIGN(AbortTask);
111 };
112
113 CompilerDispatcher::AbortTask::AbortTask(Isolate* isolate,
114 CancelableTaskManager* task_manager,
115 CompilerDispatcher* dispatcher)
116 : CancelableTask(isolate, task_manager), dispatcher_(dispatcher) {}
117
118 CompilerDispatcher::AbortTask::~AbortTask() {}
119
120 void CompilerDispatcher::AbortTask::RunInternal() {
121 dispatcher_->AbortInactiveJobs();
122 }
123
100 class CompilerDispatcher::BackgroundTask : public CancelableTask { 124 class CompilerDispatcher::BackgroundTask : public CancelableTask {
101 public: 125 public:
102 BackgroundTask(Isolate* isolate, CancelableTaskManager* task_manager, 126 BackgroundTask(Isolate* isolate, CancelableTaskManager* task_manager,
103 CompilerDispatcher* dispatcher); 127 CompilerDispatcher* dispatcher);
104 ~BackgroundTask() override; 128 ~BackgroundTask() override;
105 129
106 // CancelableTask implementation. 130 // CancelableTask implementation.
107 void RunInternal() override; 131 void RunInternal() override;
108 132
109 private: 133 private:
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 dispatcher_->DoIdleWork(deadline_in_seconds); 173 dispatcher_->DoIdleWork(deadline_in_seconds);
150 } 174 }
151 175
152 CompilerDispatcher::CompilerDispatcher(Isolate* isolate, Platform* platform, 176 CompilerDispatcher::CompilerDispatcher(Isolate* isolate, Platform* platform,
153 size_t max_stack_size) 177 size_t max_stack_size)
154 : isolate_(isolate), 178 : isolate_(isolate),
155 platform_(platform), 179 platform_(platform),
156 max_stack_size_(max_stack_size), 180 max_stack_size_(max_stack_size),
157 tracer_(new CompilerDispatcherTracer(isolate_)), 181 tracer_(new CompilerDispatcherTracer(isolate_)),
158 task_manager_(new CancelableTaskManager()), 182 task_manager_(new CancelableTaskManager()),
183 abort_(false),
159 idle_task_scheduled_(false), 184 idle_task_scheduled_(false),
160 num_scheduled_background_tasks_(0), 185 num_scheduled_background_tasks_(0),
161 main_thread_blocking_on_job_(nullptr) {} 186 main_thread_blocking_on_job_(nullptr),
187 block_for_testing_(false),
188 semaphore_for_testing_(0) {}
162 189
163 CompilerDispatcher::~CompilerDispatcher() { 190 CompilerDispatcher::~CompilerDispatcher() {
164 // To avoid crashing in unit tests due to unfished jobs. 191 // To avoid crashing in unit tests due to unfished jobs.
165 AbortAll(BlockingBehavior::kBlock); 192 AbortAll(BlockingBehavior::kBlock);
166 task_manager_->CancelAndWait(); 193 task_manager_->CancelAndWait();
167 } 194 }
168 195
169 bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) { 196 bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) {
170 if (!IsEnabled()) return false; 197 if (!IsEnabled()) return false;
171 198
199 {
200 base::LockGuard<base::Mutex> lock(&mutex_);
201 if (abort_) return false;
202 }
203
172 // We only handle functions (no eval / top-level code / wasm) that are 204 // We only handle functions (no eval / top-level code / wasm) that are
173 // attached to a script. 205 // attached to a script.
174 if (!function->script()->IsScript() || !function->is_function() || 206 if (!function->script()->IsScript() || !function->is_function() ||
175 function->asm_function() || function->native()) { 207 function->asm_function() || function->native()) {
176 return false; 208 return false;
177 } 209 }
178 210
179 if (IsEnqueued(function)) return true; 211 if (IsEnqueued(function)) return true;
180 std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob( 212 std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
181 isolate_, tracer_.get(), function, max_stack_size_)); 213 isolate_, tracer_.get(), function, max_stack_size_));
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 CHECK(job != jobs_.end()); 248 CHECK(job != jobs_.end());
217 249
218 WaitForJobIfRunningOnBackground(job->second.get()); 250 WaitForJobIfRunningOnBackground(job->second.get());
219 while (!IsFinished(job->second.get())) { 251 while (!IsFinished(job->second.get())) {
220 DoNextStepOnMainThread(isolate_, job->second.get(), 252 DoNextStepOnMainThread(isolate_, job->second.get(),
221 ExceptionHandling::kThrow); 253 ExceptionHandling::kThrow);
222 } 254 }
223 bool result = job->second->status() != CompileJobStatus::kFailed; 255 bool result = job->second->status() != CompileJobStatus::kFailed;
224 job->second->ResetOnMainThread(); 256 job->second->ResetOnMainThread();
225 jobs_.erase(job); 257 jobs_.erase(job);
258 if (jobs_.empty()) {
259 base::LockGuard<base::Mutex> lock(&mutex_);
260 abort_ = false;
261 }
226 return result; 262 return result;
227 } 263 }
228 264
229 void CompilerDispatcher::AbortAll(BlockingBehavior blocking) { 265 void CompilerDispatcher::AbortAll(BlockingBehavior blocking) {
230 // TODO(jochen): Implement support for non-blocking abort. 266 bool background_tasks_running =
231 DCHECK(blocking == BlockingBehavior::kBlock); 267 task_manager_->TryAbortAll() == CancelableTaskManager::kTaskRunning;
232 for (auto& kv : jobs_) { 268 if (!background_tasks_running || blocking == BlockingBehavior::kBlock) {
233 WaitForJobIfRunningOnBackground(kv.second.get()); 269 for (auto& it : jobs_) {
234 kv.second->ResetOnMainThread(); 270 WaitForJobIfRunningOnBackground(it.second.get());
271 it.second->ResetOnMainThread();
272 }
273 jobs_.clear();
274 {
275 base::LockGuard<base::Mutex> lock(&mutex_);
276 DCHECK(pending_background_jobs_.empty());
277 DCHECK(running_background_jobs_.empty());
278 abort_ = false;
279 }
280 return;
235 } 281 }
236 jobs_.clear(); 282
283 {
284 base::LockGuard<base::Mutex> lock(&mutex_);
285 abort_ = true;
286 pending_background_jobs_.clear();
287 }
288 AbortInactiveJobs();
289
290 // All running background jobs might already have scheduled idle tasks instead
291 // of abort tasks. Schedule a single abort task here to make sure they get
292 // processed as soon as possible (and not first when we have idle time).
293 ScheduleAbortTask();
294 }
295
296 void CompilerDispatcher::AbortInactiveJobs() {
297 {
298 base::LockGuard<base::Mutex> lock(&mutex_);
299 // Since we schedule two abort tasks per async abort, we might end up
300 // here with nothing left to do.
301 if (!abort_) return;
302 }
303 for (auto it = jobs_.begin(); it != jobs_.end();) {
304 auto job = it;
305 ++it;
306 {
307 base::LockGuard<base::Mutex> lock(&mutex_);
308 if (running_background_jobs_.find(job->second.get()) !=
309 running_background_jobs_.end()) {
310 continue;
311 }
312 }
313 job->second->ResetOnMainThread();
314 jobs_.erase(job);
315 }
316 if (jobs_.empty()) {
317 base::LockGuard<base::Mutex> lock(&mutex_);
318 abort_ = false;
319 }
237 } 320 }
238 321
239 CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::GetJobFor( 322 CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::GetJobFor(
240 Handle<SharedFunctionInfo> shared) const { 323 Handle<SharedFunctionInfo> shared) const {
241 if (!shared->script()->IsScript()) return jobs_.end(); 324 if (!shared->script()->IsScript()) return jobs_.end();
242 std::pair<int, int> key(Script::cast(shared->script())->id(), 325 std::pair<int, int> key(Script::cast(shared->script())->id(),
243 shared->function_literal_id()); 326 shared->function_literal_id());
244 auto range = jobs_.equal_range(key); 327 auto range = jobs_.equal_range(key);
245 for (auto job = range.first; job != range.second; ++job) { 328 for (auto job = range.first; job != range.second; ++job) {
246 if (job->second->IsAssociatedWith(shared)) return job; 329 if (job->second->IsAssociatedWith(shared)) return job;
(...skipping 11 matching lines...) Expand all
258 } 341 }
259 platform_->CallIdleOnForegroundThread( 342 platform_->CallIdleOnForegroundThread(
260 v8_isolate, new IdleTask(isolate_, task_manager_.get(), this)); 343 v8_isolate, new IdleTask(isolate_, task_manager_.get(), this));
261 } 344 }
262 345
263 void CompilerDispatcher::ScheduleIdleTaskIfNeeded() { 346 void CompilerDispatcher::ScheduleIdleTaskIfNeeded() {
264 if (jobs_.empty()) return; 347 if (jobs_.empty()) return;
265 ScheduleIdleTaskFromAnyThread(); 348 ScheduleIdleTaskFromAnyThread();
266 } 349 }
267 350
351 void CompilerDispatcher::ScheduleAbortTask() {
352 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
353 platform_->CallOnForegroundThread(
354 v8_isolate, new AbortTask(isolate_, task_manager_.get(), this));
355 }
356
268 void CompilerDispatcher::ConsiderJobForBackgroundProcessing( 357 void CompilerDispatcher::ConsiderJobForBackgroundProcessing(
269 CompilerDispatcherJob* job) { 358 CompilerDispatcherJob* job) {
270 if (!CanRunOnAnyThread(job)) return; 359 if (!CanRunOnAnyThread(job)) return;
271 { 360 {
272 base::LockGuard<base::Mutex> lock(&mutex_); 361 base::LockGuard<base::Mutex> lock(&mutex_);
273 pending_background_jobs_.insert(job); 362 pending_background_jobs_.insert(job);
274 } 363 }
275 ScheduleMoreBackgroundTasksIfNeeded(); 364 ScheduleMoreBackgroundTasksIfNeeded();
276 } 365 }
277 366
(...skipping 19 matching lines...) Expand all
297 base::LockGuard<base::Mutex> lock(&mutex_); 386 base::LockGuard<base::Mutex> lock(&mutex_);
298 --num_scheduled_background_tasks_; 387 --num_scheduled_background_tasks_;
299 if (!pending_background_jobs_.empty()) { 388 if (!pending_background_jobs_.empty()) {
300 auto it = pending_background_jobs_.begin(); 389 auto it = pending_background_jobs_.begin();
301 job = *it; 390 job = *it;
302 pending_background_jobs_.erase(it); 391 pending_background_jobs_.erase(it);
303 running_background_jobs_.insert(job); 392 running_background_jobs_.insert(job);
304 } 393 }
305 } 394 }
306 if (job == nullptr) return; 395 if (job == nullptr) return;
396
397 if (V8_UNLIKELY(block_for_testing_.Value())) {
398 block_for_testing_.SetValue(false);
399 semaphore_for_testing_.Wait();
400 }
401
307 DoNextStepOnBackgroundThread(job); 402 DoNextStepOnBackgroundThread(job);
308 403
309 ScheduleMoreBackgroundTasksIfNeeded(); 404 ScheduleMoreBackgroundTasksIfNeeded();
310 // Unconditionally schedule an idle task, as all background steps have to be 405 // Unconditionally schedule an idle task, as all background steps have to be
311 // followed by a main thread step. 406 // followed by a main thread step.
312 ScheduleIdleTaskFromAnyThread(); 407 ScheduleIdleTaskFromAnyThread();
313 408
314 { 409 {
315 base::LockGuard<base::Mutex> lock(&mutex_); 410 base::LockGuard<base::Mutex> lock(&mutex_);
316 running_background_jobs_.erase(job); 411 running_background_jobs_.erase(job);
317 412
413 if (running_background_jobs_.empty() && abort_) {
414 // This is the last background job that finished. The abort task
415 // scheduled by AbortAll might already have ran, so schedule another
416 // one to be on the safe side.
417 ScheduleAbortTask();
418 }
419
318 if (main_thread_blocking_on_job_ == job) { 420 if (main_thread_blocking_on_job_ == job) {
319 main_thread_blocking_on_job_ = nullptr; 421 main_thread_blocking_on_job_ = nullptr;
320 main_thread_blocking_signal_.NotifyOne(); 422 main_thread_blocking_signal_.NotifyOne();
321 } 423 }
322 } 424 }
323 // Don't touch |this| anymore after this point, as it might have been 425 // Don't touch |this| anymore after this point, as it might have been
324 // deleted. 426 // deleted.
325 } 427 }
326 428
327 void CompilerDispatcher::DoIdleWork(double deadline_in_seconds) { 429 void CompilerDispatcher::DoIdleWork(double deadline_in_seconds) {
430 bool aborted = false;
328 { 431 {
329 base::LockGuard<base::Mutex> lock(&mutex_); 432 base::LockGuard<base::Mutex> lock(&mutex_);
330 idle_task_scheduled_ = false; 433 idle_task_scheduled_ = false;
434 aborted = abort_;
435 }
436
437 if (aborted) {
438 AbortInactiveJobs();
439 return;
331 } 440 }
332 441
333 // Number of jobs that are unlikely to make progress during any idle callback 442 // Number of jobs that are unlikely to make progress during any idle callback
334 // due to their estimated duration. 443 // due to their estimated duration.
335 size_t too_long_jobs = 0; 444 size_t too_long_jobs = 0;
336 445
337 // Iterate over all available jobs & remaining time. For each job, decide 446 // Iterate over all available jobs & remaining time. For each job, decide
338 // whether to 1) skip it (if it would take too long), 2) erase it (if it's 447 // whether to 1) skip it (if it would take too long), 2) erase it (if it's
339 // finished), or 3) make progress on it. 448 // finished), or 3) make progress on it.
340 double idle_time_in_seconds = 449 double idle_time_in_seconds =
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 lock.reset(); 490 lock.reset();
382 DoNextStepOnMainThread(isolate_, job->second.get(), 491 DoNextStepOnMainThread(isolate_, job->second.get(),
383 ExceptionHandling::kSwallow); 492 ExceptionHandling::kSwallow);
384 } 493 }
385 } 494 }
386 if (jobs_.size() > too_long_jobs) ScheduleIdleTaskIfNeeded(); 495 if (jobs_.size() > too_long_jobs) ScheduleIdleTaskIfNeeded();
387 } 496 }
388 497
389 } // namespace internal 498 } // namespace internal
390 } // namespace v8 499 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler-dispatcher/compiler-dispatcher.h ('k') | test/unittests/cancelable-tasks-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698