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

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

Issue 2573493002: Use idle time to make progress on scheduled compilation jobs (Closed)
Patch Set: updates Created 4 years 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 8d503780cd5511b7af36cbbf865e6037277a5282..64c3723bcf2f9ea6e91de9df40eed457a191394e 100644
--- a/src/compiler-dispatcher/compiler-dispatcher.cc
+++ b/src/compiler-dispatcher/compiler-dispatcher.cc
@@ -4,6 +4,10 @@
#include "src/compiler-dispatcher/compiler-dispatcher.h"
+#include "include/v8-platform.h"
+#include "include/v8.h"
+#include "src/base/platform/time.h"
+#include "src/cancelable-task.h"
#include "src/compiler-dispatcher/compiler-dispatcher-job.h"
#include "src/compiler-dispatcher/compiler-dispatcher-tracer.h"
#include "src/objects-inl.h"
@@ -13,7 +17,12 @@ namespace internal {
namespace {
-bool DoNextStepOnMainThread(CompilerDispatcherJob* job) {
+enum class ExceptionHandling { kSwallow, kKeep };
+
+bool DoNextStepOnMainThread(Isolate* isolate, CompilerDispatcherJob* job,
+ ExceptionHandling exception_handling) {
+ DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
+ v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
switch (job->status()) {
case CompileJobStatus::kInitial:
job->PrepareToParseOnMainThread();
@@ -44,6 +53,10 @@ bool DoNextStepOnMainThread(CompilerDispatcherJob* job) {
break;
}
+ if (exception_handling == ExceptionHandling::kKeep && try_catch.HasCaught()) {
+ DCHECK(job->status() == CompileJobStatus::kFailed);
vogelheim 2016/12/15 15:24:12 nitpick: DCHECK_EQ
jochen (gone - plz use gerrit) 2016/12/15 15:37:59 that would require implementation operator<< for t
+ try_catch.ReThrow();
+ }
return job->status() != CompileJobStatus::kFailed;
}
@@ -52,14 +65,48 @@ bool IsFinished(CompilerDispatcherJob* job) {
job->status() == CompileJobStatus::kFailed;
}
+// Theoretically, we get 50ms of idle time max, however, it's unlikely that
vogelheim 2016/12/15 15:24:11 super nitpick: Remove some of the commas, like:
jochen (gone - plz use gerrit) 2016/12/15 15:37:59 done
+// we'll get all of it, so try to be a conservative.
+const double kMaxIdleTimeToExpectInMs = 40;
+
} // namespace
-CompilerDispatcher::CompilerDispatcher(Isolate* isolate, size_t max_stack_size)
+class CompilerDispatcher::IdleTask : public CancelableIdleTask {
+ public:
+ IdleTask(Isolate* isolate, CompilerDispatcher* dispatcher);
+ ~IdleTask() override;
+
+ // CancelableIdleTask implementation.
+ void RunInternal(double deadline_in_seconds) override;
+
+ private:
+ CompilerDispatcher* dispatcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(IdleTask);
+};
+
+CompilerDispatcher::IdleTask::IdleTask(Isolate* isolate,
+ CompilerDispatcher* dispatcher)
+ : CancelableIdleTask(isolate), dispatcher_(dispatcher) {}
+
+CompilerDispatcher::IdleTask::~IdleTask() {}
+
+void CompilerDispatcher::IdleTask::RunInternal(double deadline_in_seconds) {
+ dispatcher_->DoIdleWork(deadline_in_seconds);
+}
+
+CompilerDispatcher::CompilerDispatcher(Isolate* isolate, Platform* platform,
+ size_t max_stack_size)
: isolate_(isolate),
+ platform_(platform),
max_stack_size_(max_stack_size),
- tracer_(new CompilerDispatcherTracer(isolate_)) {}
+ tracer_(new CompilerDispatcherTracer(isolate_)),
+ idle_task_scheduled_(false) {}
-CompilerDispatcher::~CompilerDispatcher() {}
+CompilerDispatcher::~CompilerDispatcher() {
+ // To avoid crashing in unit tests due to unfished jobs.
+ AbortAll(BlockingBehavior::kBlock);
+}
bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) {
// We only handle functions (no eval / top-level code / wasm) that are
@@ -74,7 +121,9 @@ bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) {
isolate_, tracer_.get(), function, max_stack_size_));
std::pair<int, int> key(Script::cast(function->script())->id(),
function->function_literal_id());
- jobs_.insert(std::make_pair(key, std::move(job)));
+ JobMap::const_iterator it = jobs_.insert(std::make_pair(key, std::move(job)));
+ ClassifyJob(it);
+ ScheduleIdleTaskIfNeeded();
return true;
}
@@ -89,9 +138,13 @@ bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
// TODO(jochen): Check if there's an in-flight background task working on this
// job.
while (!IsFinished(job->second.get())) {
- DoNextStepOnMainThread(job->second.get());
+ DoNextStepOnMainThread(isolate_, job->second.get(),
+ ExceptionHandling::kKeep);
}
bool result = job->second->status() != CompileJobStatus::kFailed;
+ job->second->ResetOnMainThread();
+ jobs_for_background_thread_.erase(job);
+ jobs_for_main_thread_.erase(job);
jobs_.erase(job);
return result;
}
@@ -104,6 +157,9 @@ void CompilerDispatcher::Abort(Handle<SharedFunctionInfo> function,
// TODO(jochen): Check if there's an in-flight background task working on this
// job.
+ job->second->ResetOnMainThread();
+ jobs_for_background_thread_.erase(job);
+ jobs_for_main_thread_.erase(job);
jobs_.erase(job);
}
@@ -111,6 +167,11 @@ 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_) {
+ kv.second->ResetOnMainThread();
+ }
+ jobs_for_background_thread_.clear();
+ jobs_for_main_thread_.clear();
jobs_.clear();
}
@@ -126,5 +187,89 @@ CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::GetJobFor(
return jobs_.end();
}
+void CompilerDispatcher::ScheduleIdleTaskIfNeeded() {
+ v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
+ if (!platform_->IdleTasksEnabled(v8_isolate)) return;
+ if (idle_task_scheduled_) return;
+ if (jobs_.empty()) return;
+ idle_task_scheduled_ = true;
+ platform_->CallIdleOnForegroundThread(v8_isolate,
+ new IdleTask(isolate_, this));
+}
+
+void CompilerDispatcher::DoIdleWork(double deadline_in_seconds) {
+ idle_task_scheduled_ = false;
+
+ DoIdleWorkForJobSet(deadline_in_seconds, &jobs_for_main_thread_);
+ if (deadline_in_seconds <= platform_->MonotonicallyIncreasingTime()) return;
+ DoIdleWorkForJobSet(deadline_in_seconds, &jobs_for_background_thread_);
+}
+
+void CompilerDispatcher::DoIdleWorkForJobSet(
marja 2016/12/15 15:56:43 Can you add some high-level comments to CompilerDi
+ double deadline_in_seconds,
+ std::unordered_set<JobMap::const_iterator, JobIteratorHash>* job_set) {
+ bool work_left = false;
+
+ for (auto it = job_set->begin(); it != job_set->end();) {
+ double idle_time_in_seconds =
+ deadline_in_seconds - platform_->MonotonicallyIncreasingTime();
+ if (idle_time_in_seconds <= 0.0) {
+ work_left = true;
+ break;
+ }
+
+ auto job = (*it);
+ // We'll put the job back on the right queue if we don't manage to process
+ // it completely.
+ it = jobs_for_main_thread_.erase(it);
marja 2016/12/15 15:56:43 How is this supposed to work? it is an iterator fo
jochen (gone - plz use gerrit) 2016/12/15 20:18:44 erase() in C++11 returns the next iterator, it's s
+
+ // Advance the current job as much as possible.
+ for (;;) {
+ double estimate_in_ms = job->second->EstimateRuntimeOfNextStepInMs();
+ if (idle_time_in_seconds <
+ (estimate_in_ms /
+ static_cast<double>(base::Time::kMillisecondsPerSecond))) {
+ // If there's not enough time left, try to estimate whether we would
+ // 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) work_left = true;
+ // As there's remaining work, put the job back on the queue.
+ ClassifyJob(job);
marja 2016/12/15 15:56:43 As job_set is a pointer to one of the underlying u
marja 2016/12/15 15:56:43 The interaction between the queues and the job set
jochen (gone - plz use gerrit) 2016/12/15 20:18:44 once we also have a background scheduler, they'll
+ break;
+ }
+ DoNextStepOnMainThread(isolate_, job->second.get(),
+ ExceptionHandling::kSwallow);
+
+ if (IsFinished(job->second.get())) {
+ job->second->ResetOnMainThread();
+ jobs_.erase(job);
marja 2016/12/15 15:56:43 There's jobs_ and job_set, could you name them som
+ break;
+ }
+
+ idle_time_in_seconds =
+ deadline_in_seconds - platform_->MonotonicallyIncreasingTime();
+ }
+ }
+ if (work_left) ScheduleIdleTaskIfNeeded();
vogelheim 2016/12/15 15:24:12 This would potentially be called twice, since DoId
vogelheim 2016/12/15 15:24:12 At this point, wouldn't (work_left == !job_set.emp
jochen (gone - plz use gerrit) 2016/12/15 15:37:59 I found it more readable to put it here, instead o
+}
+
+void CompilerDispatcher::ClassifyJob(JobMap::const_iterator it) {
marja 2016/12/15 15:56:43 This function name is misleading, it doesn't just
+ bool can_go_on_background_thread = false;
+ CompilerDispatcherJob* job = it->second.get();
+ if (job->status() == CompileJobStatus::kReadyToParse &&
+ job->can_parse_on_background_thread()) {
+ can_go_on_background_thread = true;
+ } else if (job->status() == CompileJobStatus::kReadyToCompile &&
+ job->can_compile_on_background_thread()) {
+ can_go_on_background_thread = true;
+ }
vogelheim 2016/12/15 15:24:11 style nitpick; feel free to ignore... The if-else
jochen (gone - plz use gerrit) 2016/12/15 15:37:59 done
+
+ if (can_go_on_background_thread) {
+ jobs_for_background_thread_.insert(it);
+ } else {
+ jobs_for_main_thread_.insert(it);
+ }
+}
+
} // namespace internal
} // namespace v8

Powered by Google App Engine
This is Rietveld 408576698