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

Unified Diff: src/compiler-dispatcher/compiler-dispatcher.cc

Issue 2613483002: Reland "Use background tasks for the compiler dispatcher (Closed)
Patch Set: fix Created 3 years, 12 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 side-by-side diff with in-line comments
Download patch
Index: src/compiler-dispatcher/compiler-dispatcher.cc
diff --git a/src/compiler-dispatcher/compiler-dispatcher.cc b/src/compiler-dispatcher/compiler-dispatcher.cc
index 5cf10aa3eb8ac012143c4f4b486d0e69c3bcfc1c..47c04b8b44a39792173dd26443179bf137f9745e 100644
--- a/src/compiler-dispatcher/compiler-dispatcher.cc
+++ b/src/compiler-dispatcher/compiler-dispatcher.cc
@@ -66,15 +66,65 @@ bool IsFinished(CompilerDispatcherJob* job) {
job->status() == CompileJobStatus::kFailed;
}
+bool CanRunOnAnyThread(CompilerDispatcherJob* job) {
+ return (job->status() == CompileJobStatus::kReadyToParse &&
+ job->can_parse_on_background_thread()) ||
+ (job->status() == CompileJobStatus::kReadyToCompile &&
+ job->can_compile_on_background_thread());
+}
+
+void DoNextStepOnBackgroundThread(CompilerDispatcherJob* job) {
+ DCHECK(CanRunOnAnyThread(job));
+ switch (job->status()) {
+ case CompileJobStatus::kReadyToParse:
+ job->Parse();
+ break;
+
+ case CompileJobStatus::kReadyToCompile:
+ job->Compile();
+ break;
+
+ default:
+ UNREACHABLE();
+ }
+}
+
// Theoretically we get 50ms of idle time max, however it's unlikely that
// we'll get all of it so try to be a conservative.
const double kMaxIdleTimeToExpectInMs = 40;
} // namespace
+class CompilerDispatcher::BackgroundTask : public CancelableTask {
+ public:
+ BackgroundTask(Isolate* isolate, CancelableTaskManager* task_manager,
+ CompilerDispatcher* dispatcher);
+ ~BackgroundTask() override;
+
+ // CancelableTask implementation.
+ void RunInternal() override;
+
+ private:
+ CompilerDispatcher* dispatcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackgroundTask);
+};
+
+CompilerDispatcher::BackgroundTask::BackgroundTask(
+ Isolate* isolate, CancelableTaskManager* task_manager,
+ CompilerDispatcher* dispatcher)
+ : CancelableTask(isolate, task_manager), dispatcher_(dispatcher) {}
+
+CompilerDispatcher::BackgroundTask::~BackgroundTask() {}
+
+void CompilerDispatcher::BackgroundTask::RunInternal() {
+ dispatcher_->DoBackgroundWork();
+}
+
class CompilerDispatcher::IdleTask : public CancelableIdleTask {
public:
- IdleTask(Isolate* isolate, CompilerDispatcher* dispatcher);
+ IdleTask(Isolate* isolate, CancelableTaskManager* task_manager,
+ CompilerDispatcher* dispatcher);
~IdleTask() override;
// CancelableIdleTask implementation.
@@ -87,8 +137,9 @@ class CompilerDispatcher::IdleTask : public CancelableIdleTask {
};
CompilerDispatcher::IdleTask::IdleTask(Isolate* isolate,
+ CancelableTaskManager* task_manager,
CompilerDispatcher* dispatcher)
- : CancelableIdleTask(isolate), dispatcher_(dispatcher) {}
+ : CancelableIdleTask(isolate, task_manager), dispatcher_(dispatcher) {}
CompilerDispatcher::IdleTask::~IdleTask() {}
@@ -102,11 +153,15 @@ CompilerDispatcher::CompilerDispatcher(Isolate* isolate, Platform* platform,
platform_(platform),
max_stack_size_(max_stack_size),
tracer_(new CompilerDispatcherTracer(isolate_)),
- idle_task_scheduled_(false) {}
+ task_manager_(new CancelableTaskManager()),
+ idle_task_scheduled_(false),
+ num_scheduled_background_tasks_(0),
+ main_thread_blocking_on_job_(nullptr) {}
CompilerDispatcher::~CompilerDispatcher() {
// To avoid crashing in unit tests due to unfished jobs.
AbortAll(BlockingBehavior::kBlock);
+ task_manager_->CancelAndWait();
}
bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) {
@@ -138,12 +193,27 @@ bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const {
return GetJobFor(function) != jobs_.end();
}
+void CompilerDispatcher::WaitForJobIfRunningOnBackground(
+ CompilerDispatcherJob* job) {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ if (running_background_jobs_.find(job) == running_background_jobs_.end()) {
+ pending_background_jobs_.erase(job);
+ return;
+ }
+ DCHECK_NULL(main_thread_blocking_on_job_);
+ main_thread_blocking_on_job_ = job;
+ while (main_thread_blocking_on_job_ != nullptr) {
+ main_thread_blocking_signal_.Wait(&mutex_);
+ }
+ DCHECK(pending_background_jobs_.find(job) == pending_background_jobs_.end());
+ DCHECK(running_background_jobs_.find(job) == running_background_jobs_.end());
+}
+
bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
JobMap::const_iterator job = GetJobFor(function);
CHECK(job != jobs_.end());
- // TODO(jochen): Check if there's an in-flight background task working on this
- // job.
+ WaitForJobIfRunningOnBackground(job->second.get());
while (!IsFinished(job->second.get())) {
DoNextStepOnMainThread(isolate_, job->second.get(),
ExceptionHandling::kThrow);
@@ -154,23 +224,11 @@ bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
return result;
}
-void CompilerDispatcher::Abort(Handle<SharedFunctionInfo> function,
- BlockingBehavior blocking) {
- USE(blocking);
- JobMap::const_iterator job = GetJobFor(function);
- CHECK(job != jobs_.end());
-
- // TODO(jochen): Check if there's an in-flight background task working on this
- // job.
- job->second->ResetOnMainThread();
- jobs_.erase(job);
-}
-
void CompilerDispatcher::AbortAll(BlockingBehavior blocking) {
- USE(blocking);
- // TODO(jochen): Check if there's an in-flight background task working on this
- // job.
+ // TODO(jochen): Implement support for non-blocking abort.
+ DCHECK(blocking == BlockingBehavior::kBlock);
for (auto& kv : jobs_) {
+ WaitForJobIfRunningOnBackground(kv.second.get());
kv.second->ResetOnMainThread();
}
jobs_.clear();
@@ -188,18 +246,87 @@ CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::GetJobFor(
return jobs_.end();
}
-void CompilerDispatcher::ScheduleIdleTaskIfNeeded() {
+void CompilerDispatcher::ScheduleIdleTaskFromAnyThread() {
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
DCHECK(platform_->IdleTasksEnabled(v8_isolate));
- if (idle_task_scheduled_) return;
+ {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ if (idle_task_scheduled_) return;
+ idle_task_scheduled_ = true;
+ }
+ platform_->CallIdleOnForegroundThread(
+ v8_isolate, new IdleTask(isolate_, task_manager_.get(), this));
+}
+
+void CompilerDispatcher::ScheduleIdleTaskIfNeeded() {
if (jobs_.empty()) return;
- idle_task_scheduled_ = true;
- platform_->CallIdleOnForegroundThread(v8_isolate,
- new IdleTask(isolate_, this));
+ ScheduleIdleTaskFromAnyThread();
+}
+
+void CompilerDispatcher::ConsiderJobForBackgroundProcessing(
+ CompilerDispatcherJob* job) {
+ if (!CanRunOnAnyThread(job)) return;
+ {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ pending_background_jobs_.insert(job);
+ }
+ ScheduleMoreBackgroundTasksIfNeeded();
+}
+
+void CompilerDispatcher::ScheduleMoreBackgroundTasksIfNeeded() {
+ if (FLAG_single_threaded) return;
+ {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ if (pending_background_jobs_.empty()) return;
+ if (platform_->NumberOfAvailableBackgroundThreads() <=
+ num_scheduled_background_tasks_) {
+ return;
+ }
+ ++num_scheduled_background_tasks_;
+ }
+ platform_->CallOnBackgroundThread(
+ new BackgroundTask(isolate_, task_manager_.get(), this),
+ v8::Platform::kShortRunningTask);
+}
+
+void CompilerDispatcher::DoBackgroundWork() {
+ CompilerDispatcherJob* job = nullptr;
+ {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ --num_scheduled_background_tasks_;
+ if (!pending_background_jobs_.empty()) {
+ auto it = pending_background_jobs_.begin();
+ job = *it;
+ pending_background_jobs_.erase(it);
+ running_background_jobs_.insert(job);
+ }
+ }
+ if (job == nullptr) return;
+ DoNextStepOnBackgroundThread(job);
+
+ ScheduleMoreBackgroundTasksIfNeeded();
+ // Unconditionally schedule an idle task, as all background steps have to be
+ // followed by a main thread step.
+ ScheduleIdleTaskFromAnyThread();
+
+ {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ running_background_jobs_.erase(job);
+
+ if (main_thread_blocking_on_job_ == job) {
+ main_thread_blocking_on_job_ = nullptr;
+ main_thread_blocking_signal_.NotifyOne();
+ }
+ }
+ // Don't touch |this| anymore after this point, as it might have been
+ // deleted.
}
void CompilerDispatcher::DoIdleWork(double deadline_in_seconds) {
- idle_task_scheduled_ = false;
+ {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ idle_task_scheduled_ = false;
+ }
// Number of jobs that are unlikely to make progress during any idle callback
// due to their estimated duration.
@@ -214,6 +341,17 @@ void CompilerDispatcher::DoIdleWork(double deadline_in_seconds) {
job != jobs_.end() && idle_time_in_seconds > 0.0;
idle_time_in_seconds =
deadline_in_seconds - platform_->MonotonicallyIncreasingTime()) {
+ // Don't work on jobs that are being worked on by background tasks.
+ // Similarly, remove jobs we work on from the set of available background
+ // jobs.
+ std::unique_ptr<base::LockGuard<base::Mutex>> lock(
+ new base::LockGuard<base::Mutex>(&mutex_));
+ if (running_background_jobs_.find(job->second.get()) !=
+ running_background_jobs_.end()) {
+ ++job;
+ continue;
+ }
+ auto it = pending_background_jobs_.find(job->second.get());
double estimate_in_ms = job->second->EstimateRuntimeOfNextStepInMs();
if (idle_time_in_seconds <
(estimate_in_ms /
@@ -222,14 +360,23 @@ void CompilerDispatcher::DoIdleWork(double deadline_in_seconds) {
// have managed to finish the job in a large idle task to assess
// whether we should ask for another idle callback.
if (estimate_in_ms > kMaxIdleTimeToExpectInMs) ++too_long_jobs;
+ if (it == pending_background_jobs_.end()) {
+ lock.reset();
+ ConsiderJobForBackgroundProcessing(job->second.get());
+ }
++job;
} else if (IsFinished(job->second.get())) {
+ DCHECK(it == pending_background_jobs_.end());
job->second->ResetOnMainThread();
job = jobs_.erase(job);
- break;
+ continue;
} else {
// Do one step, and keep processing the job (as we don't advance the
// iterator).
+ if (it != pending_background_jobs_.end()) {
+ pending_background_jobs_.erase(it);
+ }
+ lock.reset();
DoNextStepOnMainThread(isolate_, job->second.get(),
ExceptionHandling::kSwallow);
}
« 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