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

Side by Side 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 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"
8 #include "include/v8.h"
9 #include "src/base/platform/time.h"
10 #include "src/cancelable-task.h"
7 #include "src/compiler-dispatcher/compiler-dispatcher-job.h" 11 #include "src/compiler-dispatcher/compiler-dispatcher-job.h"
8 #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" 12 #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h"
9 #include "src/objects-inl.h" 13 #include "src/objects-inl.h"
10 14
11 namespace v8 { 15 namespace v8 {
12 namespace internal { 16 namespace internal {
13 17
14 namespace { 18 namespace {
15 19
16 bool DoNextStepOnMainThread(CompilerDispatcherJob* job) { 20 enum class ExceptionHandling { kSwallow, kThrow };
21
22 bool DoNextStepOnMainThread(Isolate* isolate, CompilerDispatcherJob* job,
23 ExceptionHandling exception_handling) {
24 DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
25 v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
17 switch (job->status()) { 26 switch (job->status()) {
18 case CompileJobStatus::kInitial: 27 case CompileJobStatus::kInitial:
19 job->PrepareToParseOnMainThread(); 28 job->PrepareToParseOnMainThread();
20 break; 29 break;
21 30
22 case CompileJobStatus::kReadyToParse: 31 case CompileJobStatus::kReadyToParse:
23 job->Parse(); 32 job->Parse();
24 break; 33 break;
25 34
26 case CompileJobStatus::kParsed: 35 case CompileJobStatus::kParsed:
(...skipping 10 matching lines...) Expand all
37 46
38 case CompileJobStatus::kCompiled: 47 case CompileJobStatus::kCompiled:
39 job->FinalizeCompilingOnMainThread(); 48 job->FinalizeCompilingOnMainThread();
40 break; 49 break;
41 50
42 case CompileJobStatus::kFailed: 51 case CompileJobStatus::kFailed:
43 case CompileJobStatus::kDone: 52 case CompileJobStatus::kDone:
44 break; 53 break;
45 } 54 }
46 55
56 if (exception_handling == ExceptionHandling::kThrow &&
57 try_catch.HasCaught()) {
58 DCHECK(job->status() == CompileJobStatus::kFailed);
59 try_catch.ReThrow();
60 }
47 return job->status() != CompileJobStatus::kFailed; 61 return job->status() != CompileJobStatus::kFailed;
48 } 62 }
49 63
50 bool IsFinished(CompilerDispatcherJob* job) { 64 bool IsFinished(CompilerDispatcherJob* job) {
51 return job->status() == CompileJobStatus::kDone || 65 return job->status() == CompileJobStatus::kDone ||
52 job->status() == CompileJobStatus::kFailed; 66 job->status() == CompileJobStatus::kFailed;
53 } 67 }
54 68
69 // Theoretically we get 50ms of idle time max, however it's unlikely that
70 // we'll get all of it so try to be a conservative.
71 const double kMaxIdleTimeToExpectInMs = 40;
72
55 } // namespace 73 } // namespace
56 74
57 CompilerDispatcher::CompilerDispatcher(Isolate* isolate, size_t max_stack_size) 75 class CompilerDispatcher::IdleTask : public CancelableIdleTask {
76 public:
77 IdleTask(Isolate* isolate, CompilerDispatcher* dispatcher);
78 ~IdleTask() override;
79
80 // CancelableIdleTask implementation.
81 void RunInternal(double deadline_in_seconds) override;
82
83 private:
84 CompilerDispatcher* dispatcher_;
85
86 DISALLOW_COPY_AND_ASSIGN(IdleTask);
87 };
88
89 CompilerDispatcher::IdleTask::IdleTask(Isolate* isolate,
90 CompilerDispatcher* dispatcher)
91 : CancelableIdleTask(isolate), dispatcher_(dispatcher) {}
92
93 CompilerDispatcher::IdleTask::~IdleTask() {}
94
95 void CompilerDispatcher::IdleTask::RunInternal(double deadline_in_seconds) {
96 dispatcher_->DoIdleWork(deadline_in_seconds);
97 }
98
99 CompilerDispatcher::CompilerDispatcher(Isolate* isolate, Platform* platform,
100 size_t max_stack_size)
58 : isolate_(isolate), 101 : isolate_(isolate),
102 platform_(platform),
59 max_stack_size_(max_stack_size), 103 max_stack_size_(max_stack_size),
60 tracer_(new CompilerDispatcherTracer(isolate_)) {} 104 tracer_(new CompilerDispatcherTracer(isolate_)),
105 idle_task_scheduled_(false) {}
61 106
62 CompilerDispatcher::~CompilerDispatcher() {} 107 CompilerDispatcher::~CompilerDispatcher() {
108 // To avoid crashing in unit tests due to unfished jobs.
109 AbortAll(BlockingBehavior::kBlock);
110 }
63 111
64 bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) { 112 bool CompilerDispatcher::Enqueue(Handle<SharedFunctionInfo> function) {
65 // We only handle functions (no eval / top-level code / wasm) that are 113 // We only handle functions (no eval / top-level code / wasm) that are
66 // attached to a script. 114 // attached to a script.
67 if (!function->script()->IsScript() || !function->is_function() || 115 if (!function->script()->IsScript() || !function->is_function() ||
68 function->asm_function() || function->native()) { 116 function->asm_function() || function->native()) {
69 return false; 117 return false;
70 } 118 }
71 119
72 if (IsEnqueued(function)) return true; 120 if (IsEnqueued(function)) return true;
73 std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob( 121 std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
74 isolate_, tracer_.get(), function, max_stack_size_)); 122 isolate_, tracer_.get(), function, max_stack_size_));
75 std::pair<int, int> key(Script::cast(function->script())->id(), 123 std::pair<int, int> key(Script::cast(function->script())->id(),
76 function->function_literal_id()); 124 function->function_literal_id());
77 jobs_.insert(std::make_pair(key, std::move(job))); 125 jobs_.insert(std::make_pair(key, std::move(job)));
126 ScheduleIdleTaskIfNeeded();
78 return true; 127 return true;
79 } 128 }
80 129
81 bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const { 130 bool CompilerDispatcher::IsEnqueued(Handle<SharedFunctionInfo> function) const {
82 return GetJobFor(function) != jobs_.end(); 131 return GetJobFor(function) != jobs_.end();
83 } 132 }
84 133
85 bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) { 134 bool CompilerDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
86 JobMap::const_iterator job = GetJobFor(function); 135 JobMap::const_iterator job = GetJobFor(function);
87 CHECK(job != jobs_.end()); 136 CHECK(job != jobs_.end());
88 137
89 // TODO(jochen): Check if there's an in-flight background task working on this 138 // TODO(jochen): Check if there's an in-flight background task working on this
90 // job. 139 // job.
91 while (!IsFinished(job->second.get())) { 140 while (!IsFinished(job->second.get())) {
92 DoNextStepOnMainThread(job->second.get()); 141 DoNextStepOnMainThread(isolate_, job->second.get(),
142 ExceptionHandling::kThrow);
93 } 143 }
94 bool result = job->second->status() != CompileJobStatus::kFailed; 144 bool result = job->second->status() != CompileJobStatus::kFailed;
145 job->second->ResetOnMainThread();
95 jobs_.erase(job); 146 jobs_.erase(job);
96 return result; 147 return result;
97 } 148 }
98 149
99 void CompilerDispatcher::Abort(Handle<SharedFunctionInfo> function, 150 void CompilerDispatcher::Abort(Handle<SharedFunctionInfo> function,
100 BlockingBehavior blocking) { 151 BlockingBehavior blocking) {
101 USE(blocking); 152 USE(blocking);
102 JobMap::const_iterator job = GetJobFor(function); 153 JobMap::const_iterator job = GetJobFor(function);
103 CHECK(job != jobs_.end()); 154 CHECK(job != jobs_.end());
104 155
105 // TODO(jochen): Check if there's an in-flight background task working on this 156 // TODO(jochen): Check if there's an in-flight background task working on this
106 // job. 157 // job.
158 job->second->ResetOnMainThread();
107 jobs_.erase(job); 159 jobs_.erase(job);
108 } 160 }
109 161
110 void CompilerDispatcher::AbortAll(BlockingBehavior blocking) { 162 void CompilerDispatcher::AbortAll(BlockingBehavior blocking) {
111 USE(blocking); 163 USE(blocking);
112 // TODO(jochen): Check if there's an in-flight background task working on this 164 // TODO(jochen): Check if there's an in-flight background task working on this
113 // job. 165 // job.
166 for (auto& kv : jobs_) {
167 kv.second->ResetOnMainThread();
168 }
114 jobs_.clear(); 169 jobs_.clear();
115 } 170 }
116 171
117 CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::GetJobFor( 172 CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::GetJobFor(
118 Handle<SharedFunctionInfo> shared) const { 173 Handle<SharedFunctionInfo> shared) const {
119 if (!shared->script()->IsScript()) return jobs_.end(); 174 if (!shared->script()->IsScript()) return jobs_.end();
120 std::pair<int, int> key(Script::cast(shared->script())->id(), 175 std::pair<int, int> key(Script::cast(shared->script())->id(),
121 shared->function_literal_id()); 176 shared->function_literal_id());
122 auto range = jobs_.equal_range(key); 177 auto range = jobs_.equal_range(key);
123 for (auto job = range.first; job != range.second; ++job) { 178 for (auto job = range.first; job != range.second; ++job) {
124 if (job->second->IsAssociatedWith(shared)) return job; 179 if (job->second->IsAssociatedWith(shared)) return job;
125 } 180 }
126 return jobs_.end(); 181 return jobs_.end();
127 } 182 }
128 183
184 void CompilerDispatcher::ScheduleIdleTaskIfNeeded() {
185 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
186 if (!platform_->IdleTasksEnabled(v8_isolate)) return;
187 if (idle_task_scheduled_) return;
188 if (jobs_.empty()) return;
189 idle_task_scheduled_ = true;
190 platform_->CallIdleOnForegroundThread(v8_isolate,
191 new IdleTask(isolate_, this));
192 }
193
194 void CompilerDispatcher::DoIdleWork(double deadline_in_seconds) {
195 idle_task_scheduled_ = false;
196
197 // Number of jobs that are unlikely to make progress during any idle callback
198 // due to their estimated duration.
199 size_t too_long_jobs = 0;
200
201 // Iterate over all available jobs & remaining time. For each job, decide
202 // whether to 1) skip it (if it would take too long), 2) erase it (if it's
203 // finished), or 3) make progress on it.
204 double idle_time_in_seconds =
205 deadline_in_seconds - platform_->MonotonicallyIncreasingTime();
206 for (auto job = jobs_.begin();
207 job != jobs_.end() && idle_time_in_seconds > 0.0;
208 idle_time_in_seconds =
209 deadline_in_seconds - platform_->MonotonicallyIncreasingTime()) {
210 double estimate_in_ms = job->second->EstimateRuntimeOfNextStepInMs();
211 if (idle_time_in_seconds <
212 (estimate_in_ms /
213 static_cast<double>(base::Time::kMillisecondsPerSecond))) {
214 // If there's not enough time left, try to estimate whether we would
215 // have managed to finish the job in a large idle task to assess
216 // whether we should ask for another idle callback.
217 if (estimate_in_ms > kMaxIdleTimeToExpectInMs) ++too_long_jobs;
218 ++job;
219 } else if (IsFinished(job->second.get())) {
220 job->second->ResetOnMainThread();
221 job = jobs_.erase(job);
222 break;
223 } else {
224 // Do one step, and keep processing the job (as we don't advance the
225 // iterator).
226 DoNextStepOnMainThread(isolate_, job->second.get(),
227 ExceptionHandling::kSwallow);
228 }
229 }
230 if (jobs_.size() > too_long_jobs) ScheduleIdleTaskIfNeeded();
231 }
232
129 } // namespace internal 233 } // namespace internal
130 } // namespace v8 234 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler-dispatcher/compiler-dispatcher.h ('k') | src/compiler-dispatcher/compiler-dispatcher-job.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698