• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/libplatform/default-platform.h"
6 
7 #include <algorithm>
8 #include <queue>
9 
10 #include "include/libplatform/libplatform.h"
11 #include "src/base/debug/stack_trace.h"
12 #include "src/base/logging.h"
13 #include "src/base/page-allocator.h"
14 #include "src/base/platform/platform.h"
15 #include "src/base/platform/time.h"
16 #include "src/base/sys-info.h"
17 #include "src/libplatform/default-foreground-task-runner.h"
18 #include "src/libplatform/default-job.h"
19 #include "src/libplatform/default-worker-threads-task-runner.h"
20 
21 namespace v8 {
22 namespace platform {
23 
24 namespace {
25 
PrintStackTrace()26 void PrintStackTrace() {
27   v8::base::debug::StackTrace trace;
28   trace.Print();
29   // Avoid dumping duplicate stack trace on abort signal.
30   v8::base::debug::DisableSignalStackDump();
31 }
32 
33 }  // namespace
34 
NewDefaultPlatform(int thread_pool_size,IdleTaskSupport idle_task_support,InProcessStackDumping in_process_stack_dumping,std::unique_ptr<v8::TracingController> tracing_controller)35 std::unique_ptr<v8::Platform> NewDefaultPlatform(
36     int thread_pool_size, IdleTaskSupport idle_task_support,
37     InProcessStackDumping in_process_stack_dumping,
38     std::unique_ptr<v8::TracingController> tracing_controller) {
39   if (in_process_stack_dumping == InProcessStackDumping::kEnabled) {
40     v8::base::debug::EnableInProcessStackDumping();
41   }
42   auto platform = std::make_unique<DefaultPlatform>(
43       thread_pool_size, idle_task_support, std::move(tracing_controller));
44   platform->EnsureBackgroundTaskRunnerInitialized();
45   return platform;
46 }
47 
NewDefaultJobHandle(Platform * platform,TaskPriority priority,std::unique_ptr<JobTask> job_task,size_t num_worker_threads)48 V8_PLATFORM_EXPORT std::unique_ptr<JobHandle> NewDefaultJobHandle(
49     Platform* platform, TaskPriority priority,
50     std::unique_ptr<JobTask> job_task, size_t num_worker_threads) {
51   return std::make_unique<DefaultJobHandle>(std::make_shared<DefaultJobState>(
52       platform, std::move(job_task), priority, num_worker_threads));
53 }
54 
PumpMessageLoop(v8::Platform * platform,v8::Isolate * isolate,MessageLoopBehavior behavior)55 bool PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate,
56                      MessageLoopBehavior behavior) {
57   return static_cast<DefaultPlatform*>(platform)->PumpMessageLoop(isolate,
58                                                                   behavior);
59 }
60 
RunIdleTasks(v8::Platform * platform,v8::Isolate * isolate,double idle_time_in_seconds)61 void RunIdleTasks(v8::Platform* platform, v8::Isolate* isolate,
62                   double idle_time_in_seconds) {
63   static_cast<DefaultPlatform*>(platform)->RunIdleTasks(isolate,
64                                                         idle_time_in_seconds);
65 }
66 
SetTracingController(v8::Platform * platform,v8::platform::tracing::TracingController * tracing_controller)67 void SetTracingController(
68     v8::Platform* platform,
69     v8::platform::tracing::TracingController* tracing_controller) {
70   static_cast<DefaultPlatform*>(platform)->SetTracingController(
71       std::unique_ptr<v8::TracingController>(tracing_controller));
72 }
73 
NotifyIsolateShutdown(v8::Platform * platform,Isolate * isolate)74 void NotifyIsolateShutdown(v8::Platform* platform, Isolate* isolate) {
75   static_cast<DefaultPlatform*>(platform)->NotifyIsolateShutdown(isolate);
76 }
77 
78 namespace {
79 constexpr int kMaxThreadPoolSize = 16;
80 
GetActualThreadPoolSize(int thread_pool_size)81 int GetActualThreadPoolSize(int thread_pool_size) {
82   DCHECK_GE(thread_pool_size, 0);
83   if (thread_pool_size < 1) {
84     thread_pool_size = base::SysInfo::NumberOfProcessors() - 1;
85   }
86   return std::max(std::min(thread_pool_size, kMaxThreadPoolSize), 1);
87 }
88 }  // namespace
89 
DefaultPlatform(int thread_pool_size,IdleTaskSupport idle_task_support,std::unique_ptr<v8::TracingController> tracing_controller)90 DefaultPlatform::DefaultPlatform(
91     int thread_pool_size, IdleTaskSupport idle_task_support,
92     std::unique_ptr<v8::TracingController> tracing_controller)
93     : thread_pool_size_(GetActualThreadPoolSize(thread_pool_size)),
94       idle_task_support_(idle_task_support),
95       tracing_controller_(std::move(tracing_controller)),
96       page_allocator_(std::make_unique<v8::base::PageAllocator>()) {
97   if (!tracing_controller_) {
98     tracing::TracingController* controller = new tracing::TracingController();
99 #if !defined(V8_USE_PERFETTO)
100     controller->Initialize(nullptr);
101 #endif
102     tracing_controller_.reset(controller);
103   }
104 }
105 
~DefaultPlatform()106 DefaultPlatform::~DefaultPlatform() {
107   base::MutexGuard guard(&lock_);
108   if (worker_threads_task_runner_) worker_threads_task_runner_->Terminate();
109   for (const auto& it : foreground_task_runner_map_) {
110     it.second->Terminate();
111   }
112 }
113 
114 namespace {
115 
DefaultTimeFunction()116 double DefaultTimeFunction() {
117   return base::TimeTicks::HighResolutionNow().ToInternalValue() /
118          static_cast<double>(base::Time::kMicrosecondsPerSecond);
119 }
120 
121 }  // namespace
122 
EnsureBackgroundTaskRunnerInitialized()123 void DefaultPlatform::EnsureBackgroundTaskRunnerInitialized() {
124   base::MutexGuard guard(&lock_);
125   if (!worker_threads_task_runner_) {
126     worker_threads_task_runner_ =
127         std::make_shared<DefaultWorkerThreadsTaskRunner>(
128             thread_pool_size_, time_function_for_testing_
129                                    ? time_function_for_testing_
130                                    : DefaultTimeFunction);
131   }
132 }
133 
SetTimeFunctionForTesting(DefaultPlatform::TimeFunction time_function)134 void DefaultPlatform::SetTimeFunctionForTesting(
135     DefaultPlatform::TimeFunction time_function) {
136   base::MutexGuard guard(&lock_);
137   time_function_for_testing_ = time_function;
138   // The time function has to be right after the construction of the platform.
139   DCHECK(foreground_task_runner_map_.empty());
140 }
141 
PumpMessageLoop(v8::Isolate * isolate,MessageLoopBehavior wait_for_work)142 bool DefaultPlatform::PumpMessageLoop(v8::Isolate* isolate,
143                                       MessageLoopBehavior wait_for_work) {
144   bool failed_result = wait_for_work == MessageLoopBehavior::kWaitForWork;
145   std::shared_ptr<DefaultForegroundTaskRunner> task_runner;
146   {
147     base::MutexGuard guard(&lock_);
148     auto it = foreground_task_runner_map_.find(isolate);
149     if (it == foreground_task_runner_map_.end()) return failed_result;
150     task_runner = it->second;
151   }
152 
153   std::unique_ptr<Task> task = task_runner->PopTaskFromQueue(wait_for_work);
154   if (!task) return failed_result;
155 
156   DefaultForegroundTaskRunner::RunTaskScope scope(task_runner);
157   task->Run();
158   return true;
159 }
160 
RunIdleTasks(v8::Isolate * isolate,double idle_time_in_seconds)161 void DefaultPlatform::RunIdleTasks(v8::Isolate* isolate,
162                                    double idle_time_in_seconds) {
163   DCHECK_EQ(IdleTaskSupport::kEnabled, idle_task_support_);
164   std::shared_ptr<DefaultForegroundTaskRunner> task_runner;
165   {
166     base::MutexGuard guard(&lock_);
167     if (foreground_task_runner_map_.find(isolate) ==
168         foreground_task_runner_map_.end()) {
169       return;
170     }
171     task_runner = foreground_task_runner_map_[isolate];
172   }
173   double deadline_in_seconds =
174       MonotonicallyIncreasingTime() + idle_time_in_seconds;
175 
176   while (deadline_in_seconds > MonotonicallyIncreasingTime()) {
177     std::unique_ptr<IdleTask> task = task_runner->PopTaskFromIdleQueue();
178     if (!task) return;
179     DefaultForegroundTaskRunner::RunTaskScope scope(task_runner);
180     task->Run(deadline_in_seconds);
181   }
182 }
183 
GetForegroundTaskRunner(v8::Isolate * isolate)184 std::shared_ptr<TaskRunner> DefaultPlatform::GetForegroundTaskRunner(
185     v8::Isolate* isolate) {
186   base::MutexGuard guard(&lock_);
187   if (foreground_task_runner_map_.find(isolate) ==
188       foreground_task_runner_map_.end()) {
189     foreground_task_runner_map_.insert(std::make_pair(
190         isolate, std::make_shared<DefaultForegroundTaskRunner>(
191                      idle_task_support_, time_function_for_testing_
192                                              ? time_function_for_testing_
193                                              : DefaultTimeFunction)));
194   }
195   return foreground_task_runner_map_[isolate];
196 }
197 
CallOnWorkerThread(std::unique_ptr<Task> task)198 void DefaultPlatform::CallOnWorkerThread(std::unique_ptr<Task> task) {
199   EnsureBackgroundTaskRunnerInitialized();
200   worker_threads_task_runner_->PostTask(std::move(task));
201 }
202 
CallDelayedOnWorkerThread(std::unique_ptr<Task> task,double delay_in_seconds)203 void DefaultPlatform::CallDelayedOnWorkerThread(std::unique_ptr<Task> task,
204                                                 double delay_in_seconds) {
205   EnsureBackgroundTaskRunnerInitialized();
206   worker_threads_task_runner_->PostDelayedTask(std::move(task),
207                                                delay_in_seconds);
208 }
209 
IdleTasksEnabled(Isolate * isolate)210 bool DefaultPlatform::IdleTasksEnabled(Isolate* isolate) {
211   return idle_task_support_ == IdleTaskSupport::kEnabled;
212 }
213 
PostJob(TaskPriority priority,std::unique_ptr<JobTask> job_task)214 std::unique_ptr<JobHandle> DefaultPlatform::PostJob(
215     TaskPriority priority, std::unique_ptr<JobTask> job_task) {
216   size_t num_worker_threads = NumberOfWorkerThreads();
217   if (priority == TaskPriority::kBestEffort && num_worker_threads > 2) {
218     num_worker_threads = 2;
219   }
220   return NewDefaultJobHandle(this, priority, std::move(job_task),
221                              num_worker_threads);
222 }
223 
MonotonicallyIncreasingTime()224 double DefaultPlatform::MonotonicallyIncreasingTime() {
225   if (time_function_for_testing_) return time_function_for_testing_();
226   return DefaultTimeFunction();
227 }
228 
CurrentClockTimeMillis()229 double DefaultPlatform::CurrentClockTimeMillis() {
230   return base::OS::TimeCurrentMillis();
231 }
232 
GetTracingController()233 TracingController* DefaultPlatform::GetTracingController() {
234   return tracing_controller_.get();
235 }
236 
SetTracingController(std::unique_ptr<v8::TracingController> tracing_controller)237 void DefaultPlatform::SetTracingController(
238     std::unique_ptr<v8::TracingController> tracing_controller) {
239   DCHECK_NOT_NULL(tracing_controller.get());
240   tracing_controller_ = std::move(tracing_controller);
241 }
242 
NumberOfWorkerThreads()243 int DefaultPlatform::NumberOfWorkerThreads() { return thread_pool_size_; }
244 
GetStackTracePrinter()245 Platform::StackTracePrinter DefaultPlatform::GetStackTracePrinter() {
246   return PrintStackTrace;
247 }
248 
GetPageAllocator()249 v8::PageAllocator* DefaultPlatform::GetPageAllocator() {
250   return page_allocator_.get();
251 }
252 
NotifyIsolateShutdown(Isolate * isolate)253 void DefaultPlatform::NotifyIsolateShutdown(Isolate* isolate) {
254   base::MutexGuard guard(&lock_);
255   auto it = foreground_task_runner_map_.find(isolate);
256   if (it != foreground_task_runner_map_.end()) {
257     it->second->Terminate();
258     foreground_task_runner_map_.erase(it);
259   }
260 }
261 
262 }  // namespace platform
263 }  // namespace v8
264