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..978aa1996d0b9fb972c433c8731ac5ec3efaf61a 100644 |
--- a/src/compiler-dispatcher/compiler-dispatcher.cc |
+++ b/src/compiler-dispatcher/compiler-dispatcher.cc |
@@ -4,6 +4,12 @@ |
#include "src/compiler-dispatcher/compiler-dispatcher.h" |
+#include <queue> |
+ |
+#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 +19,11 @@ namespace internal { |
namespace { |
-bool DoNextStepOnMainThread(CompilerDispatcherJob* job) { |
+enum class ExceptionHandling { kSwallow, kKeep }; |
+ |
+bool DoNextStepOnMainThread(Isolate* isolate, CompilerDispatcherJob* job, |
+ ExceptionHandling exception_handling) { |
+ v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate)); |
switch (job->status()) { |
case CompileJobStatus::kInitial: |
job->PrepareToParseOnMainThread(); |
@@ -44,6 +54,9 @@ bool DoNextStepOnMainThread(CompilerDispatcherJob* job) { |
break; |
} |
+ if (exception_handling == ExceptionHandling::kKeep && try_catch.HasCaught()) { |
+ try_catch.ReThrow(); |
+ } |
marja
2016/12/13 09:09:01
Can we assert here that if the try catch has caugh
jochen (gone - plz use gerrit)
2016/12/15 13:54:34
done
|
return job->status() != CompileJobStatus::kFailed; |
} |
@@ -54,10 +67,37 @@ bool IsFinished(CompilerDispatcherJob* job) { |
} // 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. |
vogelheim
2016/12/12 17:51:32
I don't understand the comment. If the intention i
jochen (gone - plz use gerrit)
2016/12/12 20:28:25
it's a common pattern in chromium code as it has m
vogelheim
2016/12/13 09:40:33
Acknowledged.
|
+ 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() {} |
@@ -75,6 +115,7 @@ bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) { |
std::pair<int, int> key(Script::cast(function->script())->id(), |
function->function_literal_id()); |
jobs_.insert(std::make_pair(key, std::move(job))); |
+ ScheduleIdleTaskIfNeeded(); |
return true; |
} |
@@ -89,9 +130,11 @@ 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_.erase(job); |
return result; |
} |
@@ -104,6 +147,7 @@ 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_.erase(job); |
} |
@@ -111,6 +155,9 @@ 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_.clear(); |
} |
@@ -126,5 +173,69 @@ 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; |
marja
2016/12/13 09:09:01
Could you add assert(we're on the main thread) to
|
+ |
+ // Collect all candidates for running their respective next step during |
+ // idle time and sort by how long they're likely to take. |
marja
2016/12/13 09:09:01
Hmm, it looks inefficient to iterate through all i
|
+ auto cmp = [](const std::pair<double, JobMap::const_iterator>& a, |
+ const std::pair<double, JobMap::const_iterator>& b) { |
+ return a.first < b.first; |
+ }; |
+ std::priority_queue<std::pair<double, JobMap::const_iterator>, |
+ std::vector<std::pair<double, JobMap::const_iterator>>, |
+ decltype(cmp)> |
+ runtimes(cmp); |
+ for (JobMap::const_iterator it = jobs_.begin(); it != jobs_.end(); ++it) { |
+ if (IsFinished(it->second.get())) continue; |
+ // TODO(jochen): Check if there's an in-flight background task working on |
+ // this job. |
+ runtimes.push(std::make_pair( |
+ it->second->EstimateRuntimeOfNextStepInMs() / |
vogelheim
2016/12/12 17:51:32
Every one of these will look the same lock, right?
jochen (gone - plz use gerrit)
2016/12/12 20:28:25
right, dunno how much of an issue that is?
|
+ static_cast<double>(base::Time::kMillisecondsPerSecond), |
+ it)); |
+ } |
+ |
+ for (double idle_time_in_seconds = |
marja
2016/12/13 09:21:13
What if coming up with the priority queue takes so
|
+ deadline_in_seconds - platform_->MonotonicallyIncreasingTime(); |
+ idle_time_in_seconds > 0.0; |
+ idle_time_in_seconds = |
+ deadline_in_seconds - platform_->MonotonicallyIncreasingTime()) { |
marja
2016/12/13 09:09:01
This loop is mildly confusing.
Why not just:
whi
|
+ // Skip jobs we can't do in the remaining time budget. |
+ while (!runtimes.empty() && runtimes.top().first > idle_time_in_seconds) { |
+ runtimes.pop(); |
vogelheim
2016/12/12 17:51:32
If runtimes is a priority queue by expected runtim
vogelheim
2016/12/12 17:51:32
[Not sure:] What happens when there is a job whose
jochen (gone - plz use gerrit)
2016/12/12 20:28:25
So far, the biggest task comes first. I guess I co
vogelheim
2016/12/13 09:40:33
Ah, I misread that and assumed we'd process tasks
|
+ } |
+ if (runtimes.empty()) break; |
+ |
+ JobMap::const_iterator job = runtimes.top().second; |
+ runtimes.pop(); |
+ DoNextStepOnMainThread(isolate_, job->second.get(), |
+ ExceptionHandling::kSwallow); |
+ |
+ if (IsFinished(job->second.get())) { |
+ job->second->ResetOnMainThread(); |
+ jobs_.erase(job); |
+ continue; |
+ } |
+ |
+ // Put the job back on the queue in case there is time left. |
+ runtimes.push(std::make_pair( |
+ job->second->EstimateRuntimeOfNextStepInMs() / |
+ static_cast<double>(base::Time::kMillisecondsPerSecond), |
+ job)); |
vogelheim
2016/12/12 17:51:32
[Not sure:] It might make sense to store
auto cu
jochen (gone - plz use gerrit)
2016/12/12 20:28:25
we still need the mutex, because after having made
vogelheim
2016/12/13 09:40:33
Ah.
For my understanding: Why would the time esti
jochen (gone - plz use gerrit)
2016/12/15 13:54:34
in line 222 the job does one step, and i gets rein
|
+ } |
+ ScheduleIdleTaskIfNeeded(); |
+} |
+ |
} // namespace internal |
} // namespace v8 |