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

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