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

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

Issue 2606263002: Use background tasks for the compiler dispatcher (Closed)
Patch Set: 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
« no previous file with comments | « src/compiler-dispatcher/compiler-dispatcher.h ('k') | src/flag-definitions.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..bf7005a26ffe394466b5c0ed5cace315c36ea5d4 100644
--- a/src/compiler-dispatcher/compiler-dispatcher.cc
+++ b/src/compiler-dispatcher/compiler-dispatcher.cc
@@ -66,12 +66,59 @@ 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, CompilerDispatcher* dispatcher);
+ ~BackgroundTask() override;
+
+ // CancelableTask implementation.
+ void RunInternal() override;
+
+ private:
+ CompilerDispatcher* dispatcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackgroundTask);
+};
+
+CompilerDispatcher::BackgroundTask::BackgroundTask(
+ Isolate* isolate, CompilerDispatcher* dispatcher)
+ : CancelableTask(isolate), dispatcher_(dispatcher) {}
+
+CompilerDispatcher::BackgroundTask::~BackgroundTask() {}
+
+void CompilerDispatcher::BackgroundTask::RunInternal() {
+ dispatcher_->DoBackgroundWork();
+}
+
class CompilerDispatcher::IdleTask : public CancelableIdleTask {
public:
IdleTask(Isolate* isolate, CompilerDispatcher* dispatcher);
@@ -102,7 +149,10 @@ CompilerDispatcher::CompilerDispatcher(Isolate* isolate, Platform* platform,
platform_(platform),
max_stack_size_(max_stack_size),
tracer_(new CompilerDispatcherTracer(isolate_)),
- idle_task_scheduled_(false) {}
+ idle_task_scheduled_(false),
+ num_scheduled_background_tasks_(0),
+ num_available_background_jobs_(0),
+ main_thread_blocking_on_job_(nullptr) {}
CompilerDispatcher::~CompilerDispatcher() {
// To avoid crashing in unit tests due to unfished jobs.
@@ -131,19 +181,33 @@ bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) {
bool CompilerDispatcher::IsEnabled() const {
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
- return FLAG_compiler_dispatcher && platform_->IdleTasksEnabled(v8_isolate);
+ return FLAG_compiler_dispatcher && platform_->IdleTasksEnabled(v8_isolate) &&
+ platform_->NumberOfAvailableBackgroundThreads() > 0;
vogelheim 2017/01/02 17:16:24 Generally speaking, it would be nice if the dispat
jochen (gone - plz use gerrit) 2017/01/02 19:39:39 fair point. Since we only schedule background task
}
bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const {
return GetJobFor(function) != jobs_.end();
}
+void CompilerDispatcher::EnsureNotOnBackground(CompilerDispatcherJob* job) {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ if (running_background_jobs_.find(job) == running_background_jobs_.end()) {
+ pending_background_jobs_.erase(job);
vogelheim 2017/01/02 17:16:24 Do you need to update num_available_background_job
jochen (gone - plz use gerrit) 2017/01/02 19:39:39 actually, I don't need that variable anymore, so I
+ 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());
+}
+
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.
+ EnsureNotOnBackground(job->second.get());
while (!IsFinished(job->second.get())) {
DoNextStepOnMainThread(isolate_, job->second.get(),
ExceptionHandling::kThrow);
@@ -160,17 +224,15 @@ void CompilerDispatcher::Abort(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.
+ EnsureNotOnBackground(job->second.get());
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.
for (auto& kv : jobs_) {
+ EnsureNotOnBackground(kv.second.get());
kv.second->ResetOnMainThread();
}
jobs_.clear();
@@ -198,6 +260,56 @@ void CompilerDispatcher::ScheduleIdleTaskIfNeeded() {
new IdleTask(isolate_, this));
}
+void CompilerDispatcher::ConsiderJobForBackgroundProcessing(
+ CompilerDispatcherJob* job) {
+ if (!CanRunOnAnyThread(job)) return;
+ {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ pending_background_jobs_.insert(job);
+ ++num_available_background_jobs_;
+ }
+ ScheduleMoreBackgroundTasksIfNeeded();
+}
+
+void CompilerDispatcher::ScheduleMoreBackgroundTasksIfNeeded() {
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ if (num_available_background_jobs_ == 0) return;
+ if (platform_->NumberOfAvailableBackgroundThreads() <=
+ num_scheduled_background_tasks_) {
+ return;
+ }
+ ++num_scheduled_background_tasks_;
+ platform_->CallOnBackgroundThread(new BackgroundTask(isolate_, 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);
+ --num_available_background_jobs_;
+ }
+ }
+ if (job == nullptr) return;
+ DoNextStepOnBackgroundThread(job);
+ {
+ 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();
+ }
+ }
+ ScheduleMoreBackgroundTasksIfNeeded();
+}
+
void CompilerDispatcher::DoIdleWork(double deadline_in_seconds) {
idle_task_scheduled_ = false;
@@ -214,6 +326,22 @@ 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.
+ base::LockGuard<base::Mutex> lock(&mutex_);
+ if (running_background_jobs_.find(job->second.get()) !=
+ running_background_jobs_.end()) {
+ ++job;
+ continue;
+ }
+ auto it = pending_background_jobs_.find(job->second.get());
+ if (it != pending_background_jobs_.end()) {
+ pending_background_jobs_.erase(it);
+ --num_available_background_jobs_;
+ }
vogelheim 2017/01/02 17:16:24 This logic is a bit weird, because first we take i
+ }
vogelheim 2017/01/02 17:16:24 [opinion ahead; feel free to ignore:] The can-id
jochen (gone - plz use gerrit) 2017/01/02 19:39:39 the can-idle property can change, when the estimat
vogelheim 2017/01/03 10:32:37 Hmm. Not sure I'm willing to give this up yet. For
jochen (gone - plz use gerrit) 2017/01/03 12:59:35 in d8, we do get predictable idle work calls, howe
double estimate_in_ms = job->second->EstimateRuntimeOfNextStepInMs();
if (idle_time_in_seconds <
(estimate_in_ms /
@@ -222,6 +350,7 @@ 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;
+ ConsiderJobForBackgroundProcessing(job->second.get());
++job;
} else if (IsFinished(job->second.get())) {
job->second->ResetOnMainThread();
« no previous file with comments | « src/compiler-dispatcher/compiler-dispatcher.h ('k') | src/flag-definitions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698