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

Side by Side Diff: src/compiler-dispatcher/compiler-dispatcher.cc

Issue 2614433002: Revert of Use background tasks for the compiler dispatcher (Closed)
Patch Set: 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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
59 try_catch.ReThrow(); 59 try_catch.ReThrow();
60 } 60 }
61 return job->status() != CompileJobStatus::kFailed; 61 return job->status() != CompileJobStatus::kFailed;
62 } 62 }
63 63
64 bool IsFinished(CompilerDispatcherJob* job) { 64 bool IsFinished(CompilerDispatcherJob* job) {
65 return job->status() == CompileJobStatus::kDone || 65 return job->status() == CompileJobStatus::kDone ||
66 job->status() == CompileJobStatus::kFailed; 66 job->status() == CompileJobStatus::kFailed;
67 } 67 }
68 68
69 bool CanRunOnAnyThread(CompilerDispatcherJob* job) {
70 return (job->status() == CompileJobStatus::kReadyToParse &&
71 job->can_parse_on_background_thread()) ||
72 (job->status() == CompileJobStatus::kReadyToCompile &&
73 job->can_compile_on_background_thread());
74 }
75
76 void DoNextStepOnBackgroundThread(CompilerDispatcherJob* job) {
77 DCHECK(CanRunOnAnyThread(job));
78 switch (job->status()) {
79 case CompileJobStatus::kReadyToParse:
80 job->Parse();
81 break;
82
83 case CompileJobStatus::kReadyToCompile:
84 job->Compile();
85 break;
86
87 default:
88 UNREACHABLE();
89 }
90 }
91
92 // Theoretically we get 50ms of idle time max, however it's unlikely that 69 // 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. 70 // we'll get all of it so try to be a conservative.
94 const double kMaxIdleTimeToExpectInMs = 40; 71 const double kMaxIdleTimeToExpectInMs = 40;
95 72
96 } // namespace 73 } // namespace
97 74
98 class CompilerDispatcher::BackgroundTask : public CancelableTask {
99 public:
100 BackgroundTask(Isolate* isolate, CancelableTaskManager* task_manager,
101 CompilerDispatcher* dispatcher);
102 ~BackgroundTask() override;
103
104 // CancelableTask implementation.
105 void RunInternal() override;
106
107 private:
108 CompilerDispatcher* dispatcher_;
109
110 DISALLOW_COPY_AND_ASSIGN(BackgroundTask);
111 };
112
113 CompilerDispatcher::BackgroundTask::BackgroundTask(
114 Isolate* isolate, CancelableTaskManager* task_manager,
115 CompilerDispatcher* dispatcher)
116 : CancelableTask(isolate, task_manager), dispatcher_(dispatcher) {}
117
118 CompilerDispatcher::BackgroundTask::~BackgroundTask() {}
119
120 void CompilerDispatcher::BackgroundTask::RunInternal() {
121 dispatcher_->DoBackgroundWork();
122 }
123
124 class CompilerDispatcher::IdleTask : public CancelableIdleTask { 75 class CompilerDispatcher::IdleTask : public CancelableIdleTask {
125 public: 76 public:
126 IdleTask(Isolate* isolate, CancelableTaskManager* task_manager, 77 IdleTask(Isolate* isolate, CompilerDispatcher* dispatcher);
127 CompilerDispatcher* dispatcher);
128 ~IdleTask() override; 78 ~IdleTask() override;
129 79
130 // CancelableIdleTask implementation. 80 // CancelableIdleTask implementation.
131 void RunInternal(double deadline_in_seconds) override; 81 void RunInternal(double deadline_in_seconds) override;
132 82
133 private: 83 private:
134 CompilerDispatcher* dispatcher_; 84 CompilerDispatcher* dispatcher_;
135 85
136 DISALLOW_COPY_AND_ASSIGN(IdleTask); 86 DISALLOW_COPY_AND_ASSIGN(IdleTask);
137 }; 87 };
138 88
139 CompilerDispatcher::IdleTask::IdleTask(Isolate* isolate, 89 CompilerDispatcher::IdleTask::IdleTask(Isolate* isolate,
140 CancelableTaskManager* task_manager,
141 CompilerDispatcher* dispatcher) 90 CompilerDispatcher* dispatcher)
142 : CancelableIdleTask(isolate, task_manager), dispatcher_(dispatcher) {} 91 : CancelableIdleTask(isolate), dispatcher_(dispatcher) {}
143 92
144 CompilerDispatcher::IdleTask::~IdleTask() {} 93 CompilerDispatcher::IdleTask::~IdleTask() {}
145 94
146 void CompilerDispatcher::IdleTask::RunInternal(double deadline_in_seconds) { 95 void CompilerDispatcher::IdleTask::RunInternal(double deadline_in_seconds) {
147 dispatcher_->DoIdleWork(deadline_in_seconds); 96 dispatcher_->DoIdleWork(deadline_in_seconds);
148 } 97 }
149 98
150 CompilerDispatcher::CompilerDispatcher(Isolate* isolate, Platform* platform, 99 CompilerDispatcher::CompilerDispatcher(Isolate* isolate, Platform* platform,
151 size_t max_stack_size) 100 size_t max_stack_size)
152 : isolate_(isolate), 101 : isolate_(isolate),
153 platform_(platform), 102 platform_(platform),
154 max_stack_size_(max_stack_size), 103 max_stack_size_(max_stack_size),
155 tracer_(new CompilerDispatcherTracer(isolate_)), 104 tracer_(new CompilerDispatcherTracer(isolate_)),
156 task_manager_(new CancelableTaskManager()), 105 idle_task_scheduled_(false) {}
157 idle_task_scheduled_(false),
158 num_scheduled_background_tasks_(0),
159 main_thread_blocking_on_job_(nullptr) {}
160 106
161 CompilerDispatcher::~CompilerDispatcher() { 107 CompilerDispatcher::~CompilerDispatcher() {
162 // To avoid crashing in unit tests due to unfished jobs. 108 // To avoid crashing in unit tests due to unfished jobs.
163 AbortAll(BlockingBehavior::kBlock); 109 AbortAll(BlockingBehavior::kBlock);
164 task_manager_->CancelAndWait();
165 } 110 }
166 111
167 bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) { 112 bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) {
168 if (!IsEnabled()) return false; 113 if (!IsEnabled()) return false;
169 114
170 // We only handle functions (no eval / top-level code / wasm) that are 115 // We only handle functions (no eval / top-level code / wasm) that are
171 // attached to a script. 116 // attached to a script.
172 if (!function->script()->IsScript() || !function->is_function() || 117 if (!function->script()->IsScript() || !function->is_function() ||
173 function->asm_function() || function->native()) { 118 function->asm_function() || function->native()) {
174 return false; 119 return false;
(...skipping 11 matching lines...) Expand all
186 131
187 bool CompilerDispatcher::IsEnabled() const { 132 bool CompilerDispatcher::IsEnabled() const {
188 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); 133 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
189 return FLAG_compiler_dispatcher && platform_->IdleTasksEnabled(v8_isolate); 134 return FLAG_compiler_dispatcher && platform_->IdleTasksEnabled(v8_isolate);
190 } 135 }
191 136
192 bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const { 137 bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const {
193 return GetJobFor(function) != jobs_.end(); 138 return GetJobFor(function) != jobs_.end();
194 } 139 }
195 140
196 void CompilerDispatcher::WaitForJobIfRunningOnBackground(
197 CompilerDispatcherJob* job) {
198 base::LockGuard<base::Mutex> lock(&mutex_);
199 if (running_background_jobs_.find(job) == running_background_jobs_.end()) {
200 pending_background_jobs_.erase(job);
201 return;
202 }
203 DCHECK_NULL(main_thread_blocking_on_job_);
204 main_thread_blocking_on_job_ = job;
205 while (main_thread_blocking_on_job_ != nullptr) {
206 main_thread_blocking_signal_.Wait(&mutex_);
207 }
208 DCHECK(pending_background_jobs_.find(job) == pending_background_jobs_.end());
209 DCHECK(running_background_jobs_.find(job) == running_background_jobs_.end());
210 }
211
212 bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) { 141 bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
213 JobMap::const_iterator job = GetJobFor(function); 142 JobMap::const_iterator job = GetJobFor(function);
214 CHECK(job != jobs_.end()); 143 CHECK(job != jobs_.end());
215 144
216 WaitForJobIfRunningOnBackground(job->second.get()); 145 // TODO(jochen): Check if there's an in-flight background task working on this
146 // job.
217 while (!IsFinished(job->second.get())) { 147 while (!IsFinished(job->second.get())) {
218 DoNextStepOnMainThread(isolate_, job->second.get(), 148 DoNextStepOnMainThread(isolate_, job->second.get(),
219 ExceptionHandling::kThrow); 149 ExceptionHandling::kThrow);
220 } 150 }
221 bool result = job->second->status() != CompileJobStatus::kFailed; 151 bool result = job->second->status() != CompileJobStatus::kFailed;
222 job->second->ResetOnMainThread(); 152 job->second->ResetOnMainThread();
223 jobs_.erase(job); 153 jobs_.erase(job);
224 return result; 154 return result;
225 } 155 }
226 156
157 void CompilerDispatcher::Abort(Handle<SharedFunctionInfo> function,
158 BlockingBehavior blocking) {
159 USE(blocking);
160 JobMap::const_iterator job = GetJobFor(function);
161 CHECK(job != jobs_.end());
162
163 // TODO(jochen): Check if there's an in-flight background task working on this
164 // job.
165 job->second->ResetOnMainThread();
166 jobs_.erase(job);
167 }
168
227 void CompilerDispatcher::AbortAll(BlockingBehavior blocking) { 169 void CompilerDispatcher::AbortAll(BlockingBehavior blocking) {
228 // TODO(jochen): Implement support for non-blocking abort. 170 USE(blocking);
229 DCHECK(blocking == BlockingBehavior::kBlock); 171 // TODO(jochen): Check if there's an in-flight background task working on this
172 // job.
230 for (auto& kv : jobs_) { 173 for (auto& kv : jobs_) {
231 WaitForJobIfRunningOnBackground(kv.second.get());
232 kv.second->ResetOnMainThread(); 174 kv.second->ResetOnMainThread();
233 } 175 }
234 jobs_.clear(); 176 jobs_.clear();
235 } 177 }
236 178
237 CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::GetJobFor( 179 CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::GetJobFor(
238 Handle<SharedFunctionInfo> shared) const { 180 Handle<SharedFunctionInfo> shared) const {
239 if (!shared->script()->IsScript()) return jobs_.end(); 181 if (!shared->script()->IsScript()) return jobs_.end();
240 std::pair<int, int> key(Script::cast(shared->script())->id(), 182 std::pair<int, int> key(Script::cast(shared->script())->id(),
241 shared->function_literal_id()); 183 shared->function_literal_id());
242 auto range = jobs_.equal_range(key); 184 auto range = jobs_.equal_range(key);
243 for (auto job = range.first; job != range.second; ++job) { 185 for (auto job = range.first; job != range.second; ++job) {
244 if (job->second->IsAssociatedWith(shared)) return job; 186 if (job->second->IsAssociatedWith(shared)) return job;
245 } 187 }
246 return jobs_.end(); 188 return jobs_.end();
247 } 189 }
248 190
249 void CompilerDispatcher::ScheduleIdleTaskFromAnyThread() { 191 void CompilerDispatcher::ScheduleIdleTaskIfNeeded() {
250 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); 192 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
251 DCHECK(platform_->IdleTasksEnabled(v8_isolate)); 193 DCHECK(platform_->IdleTasksEnabled(v8_isolate));
252 { 194 if (idle_task_scheduled_) return;
253 base::LockGuard<base::Mutex> lock(&mutex_);
254 if (idle_task_scheduled_) return;
255 idle_task_scheduled_ = true;
256 }
257 platform_->CallIdleOnForegroundThread(
258 v8_isolate, new IdleTask(isolate_, task_manager_.get(), this));
259 }
260
261 void CompilerDispatcher::ScheduleIdleTaskIfNeeded() {
262 if (jobs_.empty()) return; 195 if (jobs_.empty()) return;
263 ScheduleIdleTaskFromAnyThread(); 196 idle_task_scheduled_ = true;
264 } 197 platform_->CallIdleOnForegroundThread(v8_isolate,
265 198 new IdleTask(isolate_, this));
266 void CompilerDispatcher::ConsiderJobForBackgroundProcessing(
267 CompilerDispatcherJob* job) {
268 if (!CanRunOnAnyThread(job)) return;
269 {
270 base::LockGuard<base::Mutex> lock(&mutex_);
271 pending_background_jobs_.insert(job);
272 }
273 ScheduleMoreBackgroundTasksIfNeeded();
274 }
275
276 void CompilerDispatcher::ScheduleMoreBackgroundTasksIfNeeded() {
277 if (FLAG_single_threaded) return;
278 {
279 base::LockGuard<base::Mutex> lock(&mutex_);
280 if (pending_background_jobs_.empty()) return;
281 if (platform_->NumberOfAvailableBackgroundThreads() <=
282 num_scheduled_background_tasks_) {
283 return;
284 }
285 ++num_scheduled_background_tasks_;
286 }
287 platform_->CallOnBackgroundThread(
288 new BackgroundTask(isolate_, task_manager_.get(), this),
289 v8::Platform::kShortRunningTask);
290 }
291
292 void CompilerDispatcher::DoBackgroundWork() {
293 CompilerDispatcherJob* job = nullptr;
294 {
295 base::LockGuard<base::Mutex> lock(&mutex_);
296 --num_scheduled_background_tasks_;
297 if (!pending_background_jobs_.empty()) {
298 auto it = pending_background_jobs_.begin();
299 job = *it;
300 pending_background_jobs_.erase(it);
301 running_background_jobs_.insert(job);
302 }
303 }
304 if (job == nullptr) return;
305 DoNextStepOnBackgroundThread(job);
306
307 ScheduleMoreBackgroundTasksIfNeeded();
308 // Unconditionally schedule an idle task, as all background steps have to be
309 // followed by a main thread step.
310 ScheduleIdleTaskFromAnyThread();
311
312 {
313 base::LockGuard<base::Mutex> lock(&mutex_);
314 running_background_jobs_.erase(job);
315
316 if (main_thread_blocking_on_job_ == job) {
317 main_thread_blocking_on_job_ = nullptr;
318 main_thread_blocking_signal_.NotifyOne();
319 }
320 }
321 // Don't touch |this| anymore after this point, as it might have been
322 // deleted.
323 } 199 }
324 200
325 void CompilerDispatcher::DoIdleWork(double deadline_in_seconds) { 201 void CompilerDispatcher::DoIdleWork(double deadline_in_seconds) {
326 { 202 idle_task_scheduled_ = false;
327 base::LockGuard<base::Mutex> lock(&mutex_);
328 idle_task_scheduled_ = false;
329 }
330 203
331 // Number of jobs that are unlikely to make progress during any idle callback 204 // Number of jobs that are unlikely to make progress during any idle callback
332 // due to their estimated duration. 205 // due to their estimated duration.
333 size_t too_long_jobs = 0; 206 size_t too_long_jobs = 0;
334 207
335 // Iterate over all available jobs & remaining time. For each job, decide 208 // Iterate over all available jobs & remaining time. For each job, decide
336 // whether to 1) skip it (if it would take too long), 2) erase it (if it's 209 // whether to 1) skip it (if it would take too long), 2) erase it (if it's
337 // finished), or 3) make progress on it. 210 // finished), or 3) make progress on it.
338 double idle_time_in_seconds = 211 double idle_time_in_seconds =
339 deadline_in_seconds - platform_->MonotonicallyIncreasingTime(); 212 deadline_in_seconds - platform_->MonotonicallyIncreasingTime();
340 for (auto job = jobs_.begin(); 213 for (auto job = jobs_.begin();
341 job != jobs_.end() && idle_time_in_seconds > 0.0; 214 job != jobs_.end() && idle_time_in_seconds > 0.0;
342 idle_time_in_seconds = 215 idle_time_in_seconds =
343 deadline_in_seconds - platform_->MonotonicallyIncreasingTime()) { 216 deadline_in_seconds - platform_->MonotonicallyIncreasingTime()) {
344 // Don't work on jobs that are being worked on by background tasks.
345 // Similarly, remove jobs we work on from the set of available background
346 // jobs.
347 std::unique_ptr<base::LockGuard<base::Mutex>> lock(
348 new base::LockGuard<base::Mutex>(&mutex_));
349 if (running_background_jobs_.find(job->second.get()) !=
350 running_background_jobs_.end()) {
351 ++job;
352 continue;
353 }
354 auto it = pending_background_jobs_.find(job->second.get());
355 double estimate_in_ms = job->second->EstimateRuntimeOfNextStepInMs(); 217 double estimate_in_ms = job->second->EstimateRuntimeOfNextStepInMs();
356 if (idle_time_in_seconds < 218 if (idle_time_in_seconds <
357 (estimate_in_ms / 219 (estimate_in_ms /
358 static_cast<double>(base::Time::kMillisecondsPerSecond))) { 220 static_cast<double>(base::Time::kMillisecondsPerSecond))) {
359 // If there's not enough time left, try to estimate whether we would 221 // If there's not enough time left, try to estimate whether we would
360 // have managed to finish the job in a large idle task to assess 222 // have managed to finish the job in a large idle task to assess
361 // whether we should ask for another idle callback. 223 // whether we should ask for another idle callback.
362 if (estimate_in_ms > kMaxIdleTimeToExpectInMs) ++too_long_jobs; 224 if (estimate_in_ms > kMaxIdleTimeToExpectInMs) ++too_long_jobs;
363 if (it == pending_background_jobs_.end()) {
364 lock.reset();
365 ConsiderJobForBackgroundProcessing(job->second.get());
366 }
367 ++job; 225 ++job;
368 } else if (IsFinished(job->second.get())) { 226 } else if (IsFinished(job->second.get())) {
369 DCHECK(it == pending_background_jobs_.end());
370 job->second->ResetOnMainThread(); 227 job->second->ResetOnMainThread();
371 job = jobs_.erase(job); 228 job = jobs_.erase(job);
372 continue; 229 break;
373 } else { 230 } else {
374 // Do one step, and keep processing the job (as we don't advance the 231 // Do one step, and keep processing the job (as we don't advance the
375 // iterator). 232 // iterator).
376 if (it != pending_background_jobs_.end()) {
377 pending_background_jobs_.erase(it);
378 }
379 lock.reset();
380 DoNextStepOnMainThread(isolate_, job->second.get(), 233 DoNextStepOnMainThread(isolate_, job->second.get(),
381 ExceptionHandling::kSwallow); 234 ExceptionHandling::kSwallow);
382 } 235 }
383 } 236 }
384 if (jobs_.size() > too_long_jobs) ScheduleIdleTaskIfNeeded(); 237 if (jobs_.size() > too_long_jobs) ScheduleIdleTaskIfNeeded();
385 } 238 }
386 239
387 } // namespace internal 240 } // namespace internal
388 } // namespace v8 241 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler-dispatcher/compiler-dispatcher.h ('k') | test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698