OLD | NEW |
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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 | 86 |
87 default: | 87 default: |
88 UNREACHABLE(); | 88 UNREACHABLE(); |
89 } | 89 } |
90 } | 90 } |
91 | 91 |
92 // 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 |
93 // 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. |
94 const double kMaxIdleTimeToExpectInMs = 40; | 94 const double kMaxIdleTimeToExpectInMs = 40; |
95 | 95 |
| 96 class MemoryPressureTask : public CancelableTask { |
| 97 public: |
| 98 MemoryPressureTask(Isolate* isolate, CancelableTaskManager* task_manager, |
| 99 CompilerDispatcher* dispatcher); |
| 100 ~MemoryPressureTask() override; |
| 101 |
| 102 // CancelableTask implementation. |
| 103 void RunInternal() override; |
| 104 |
| 105 private: |
| 106 CompilerDispatcher* dispatcher_; |
| 107 |
| 108 DISALLOW_COPY_AND_ASSIGN(MemoryPressureTask); |
| 109 }; |
| 110 |
| 111 MemoryPressureTask::MemoryPressureTask(Isolate* isolate, |
| 112 CancelableTaskManager* task_manager, |
| 113 CompilerDispatcher* dispatcher) |
| 114 : CancelableTask(isolate, task_manager), dispatcher_(dispatcher) {} |
| 115 |
| 116 MemoryPressureTask::~MemoryPressureTask() {} |
| 117 |
| 118 void MemoryPressureTask::RunInternal() { |
| 119 dispatcher_->AbortAll(CompilerDispatcher::BlockingBehavior::kDontBlock); |
| 120 } |
| 121 |
96 } // namespace | 122 } // namespace |
97 | 123 |
98 class CompilerDispatcher::AbortTask : public CancelableTask { | 124 class CompilerDispatcher::AbortTask : public CancelableTask { |
99 public: | 125 public: |
100 AbortTask(Isolate* isolate, CancelableTaskManager* task_manager, | 126 AbortTask(Isolate* isolate, CancelableTaskManager* task_manager, |
101 CompilerDispatcher* dispatcher); | 127 CompilerDispatcher* dispatcher); |
102 ~AbortTask() override; | 128 ~AbortTask() override; |
103 | 129 |
104 // CancelableTask implementation. | 130 // CancelableTask implementation. |
105 void RunInternal() override; | 131 void RunInternal() override; |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 dispatcher_->DoIdleWork(deadline_in_seconds); | 199 dispatcher_->DoIdleWork(deadline_in_seconds); |
174 } | 200 } |
175 | 201 |
176 CompilerDispatcher::CompilerDispatcher(Isolate* isolate, Platform* platform, | 202 CompilerDispatcher::CompilerDispatcher(Isolate* isolate, Platform* platform, |
177 size_t max_stack_size) | 203 size_t max_stack_size) |
178 : isolate_(isolate), | 204 : isolate_(isolate), |
179 platform_(platform), | 205 platform_(platform), |
180 max_stack_size_(max_stack_size), | 206 max_stack_size_(max_stack_size), |
181 tracer_(new CompilerDispatcherTracer(isolate_)), | 207 tracer_(new CompilerDispatcherTracer(isolate_)), |
182 task_manager_(new CancelableTaskManager()), | 208 task_manager_(new CancelableTaskManager()), |
| 209 memory_pressure_level_(MemoryPressureLevel::kNone), |
183 abort_(false), | 210 abort_(false), |
184 idle_task_scheduled_(false), | 211 idle_task_scheduled_(false), |
185 num_scheduled_background_tasks_(0), | 212 num_scheduled_background_tasks_(0), |
186 main_thread_blocking_on_job_(nullptr), | 213 main_thread_blocking_on_job_(nullptr), |
187 block_for_testing_(false), | 214 block_for_testing_(false), |
188 semaphore_for_testing_(0) {} | 215 semaphore_for_testing_(0) {} |
189 | 216 |
190 CompilerDispatcher::~CompilerDispatcher() { | 217 CompilerDispatcher::~CompilerDispatcher() { |
191 // To avoid crashing in unit tests due to unfished jobs. | 218 // To avoid crashing in unit tests due to unfished jobs. |
192 AbortAll(BlockingBehavior::kBlock); | 219 AbortAll(BlockingBehavior::kBlock); |
193 task_manager_->CancelAndWait(); | 220 task_manager_->CancelAndWait(); |
194 } | 221 } |
195 | 222 |
196 bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) { | 223 bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) { |
197 if (!IsEnabled()) return false; | 224 if (!IsEnabled()) return false; |
198 | 225 |
| 226 if (memory_pressure_level_.Value() != MemoryPressureLevel::kNone) { |
| 227 return false; |
| 228 } |
| 229 |
199 { | 230 { |
200 base::LockGuard<base::Mutex> lock(&mutex_); | 231 base::LockGuard<base::Mutex> lock(&mutex_); |
201 if (abort_) return false; | 232 if (abort_) return false; |
202 } | 233 } |
203 | 234 |
204 // We only handle functions (no eval / top-level code / wasm) that are | 235 // We only handle functions (no eval / top-level code / wasm) that are |
205 // attached to a script. | 236 // attached to a script. |
206 if (!function->script()->IsScript() || !function->is_function() || | 237 if (!function->script()->IsScript() || !function->is_function() || |
207 function->asm_function() || function->native()) { | 238 function->asm_function() || function->native()) { |
208 return false; | 239 return false; |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
312 } | 343 } |
313 job->second->ResetOnMainThread(); | 344 job->second->ResetOnMainThread(); |
314 jobs_.erase(job); | 345 jobs_.erase(job); |
315 } | 346 } |
316 if (jobs_.empty()) { | 347 if (jobs_.empty()) { |
317 base::LockGuard<base::Mutex> lock(&mutex_); | 348 base::LockGuard<base::Mutex> lock(&mutex_); |
318 abort_ = false; | 349 abort_ = false; |
319 } | 350 } |
320 } | 351 } |
321 | 352 |
| 353 void CompilerDispatcher::MemoryPressureNotification( |
| 354 v8::MemoryPressureLevel level, bool is_isolate_locked) { |
| 355 MemoryPressureLevel previous = memory_pressure_level_.Value(); |
| 356 memory_pressure_level_.SetValue(level); |
| 357 // If we're already under pressure, we haven't accepted new tasks meanwhile |
| 358 // and can just return. If we're no longer under pressure, we're also done. |
| 359 if (previous != MemoryPressureLevel::kNone || |
| 360 level == MemoryPressureLevel::kNone) { |
| 361 return; |
| 362 } |
| 363 if (is_isolate_locked) { |
| 364 AbortAll(BlockingBehavior::kDontBlock); |
| 365 } else { |
| 366 { |
| 367 base::LockGuard<base::Mutex> lock(&mutex_); |
| 368 if (abort_) return; |
| 369 // By going into abort mode here, and clearing the |
| 370 // pending_background_jobs_, we at keep existing background jobs from |
| 371 // picking up more work before the MemoryPressureTask gets executed. |
| 372 abort_ = true; |
| 373 pending_background_jobs_.clear(); |
| 374 } |
| 375 platform_->CallOnForegroundThread( |
| 376 reinterpret_cast<v8::Isolate*>(isolate_), |
| 377 new MemoryPressureTask(isolate_, task_manager_.get(), this)); |
| 378 } |
| 379 } |
| 380 |
322 CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::GetJobFor( | 381 CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::GetJobFor( |
323 Handle<SharedFunctionInfo> shared) const { | 382 Handle<SharedFunctionInfo> shared) const { |
324 if (!shared->script()->IsScript()) return jobs_.end(); | 383 if (!shared->script()->IsScript()) return jobs_.end(); |
325 std::pair<int, int> key(Script::cast(shared->script())->id(), | 384 std::pair<int, int> key(Script::cast(shared->script())->id(), |
326 shared->function_literal_id()); | 385 shared->function_literal_id()); |
327 auto range = jobs_.equal_range(key); | 386 auto range = jobs_.equal_range(key); |
328 for (auto job = range.first; job != range.second; ++job) { | 387 for (auto job = range.first; job != range.second; ++job) { |
329 if (job->second->IsAssociatedWith(shared)) return job; | 388 if (job->second->IsAssociatedWith(shared)) return job; |
330 } | 389 } |
331 return jobs_.end(); | 390 return jobs_.end(); |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 lock.reset(); | 549 lock.reset(); |
491 DoNextStepOnMainThread(isolate_, job->second.get(), | 550 DoNextStepOnMainThread(isolate_, job->second.get(), |
492 ExceptionHandling::kSwallow); | 551 ExceptionHandling::kSwallow); |
493 } | 552 } |
494 } | 553 } |
495 if (jobs_.size() > too_long_jobs) ScheduleIdleTaskIfNeeded(); | 554 if (jobs_.size() > too_long_jobs) ScheduleIdleTaskIfNeeded(); |
496 } | 555 } |
497 | 556 |
498 } // namespace internal | 557 } // namespace internal |
499 } // namespace v8 | 558 } // namespace v8 |
OLD | NEW |