Skip to content

Commit d2f5ceb

Browse files
joyeecheungRafaelGSS
authored andcommitted
src: add more debug logs and comments in NodePlatform
PR-URL: #58047 Refs: #47452 Refs: #54918 Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
1 parent a0077c9 commit d2f5ceb

File tree

3 files changed

+156
-15
lines changed

3 files changed

+156
-15
lines changed

src/debug_utils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ void NODE_EXTERN_PRIVATE FWrite(FILE* file, const std::string& str);
5555
V(MKSNAPSHOT) \
5656
V(SNAPSHOT_SERDES) \
5757
V(PERMISSION_MODEL) \
58+
V(PLATFORM_MINIMAL) \
59+
V(PLATFORM_VERBOSE) \
5860
V(QUIC)
5961

6062
enum class DebugCategory : unsigned int {

src/node_platform.cc

Lines changed: 131 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ using v8::Isolate;
1313
using v8::Object;
1414
using v8::Platform;
1515
using v8::Task;
16+
using v8::TaskPriority;
1617

1718
namespace {
1819

@@ -22,8 +23,31 @@ struct PlatformWorkerData {
2223
ConditionVariable* platform_workers_ready;
2324
int* pending_platform_workers;
2425
int id;
26+
PlatformDebugLogLevel debug_log_level;
2527
};
2628

29+
const char* GetTaskPriorityName(TaskPriority priority) {
30+
switch (priority) {
31+
case TaskPriority::kUserBlocking:
32+
return "UserBlocking";
33+
case TaskPriority::kUserVisible:
34+
return "UserVisible";
35+
case TaskPriority::kBestEffort:
36+
return "BestEffort";
37+
default:
38+
return "Unknown";
39+
}
40+
}
41+
42+
static void PrintSourceLocation(const v8::SourceLocation& location) {
43+
auto loc = location.ToString();
44+
if (!loc.empty()) {
45+
fprintf(stderr, " %s\n", loc.c_str());
46+
} else {
47+
fprintf(stderr, " <no location>\n");
48+
}
49+
}
50+
2751
static void PlatformWorkerThread(void* data) {
2852
uv_thread_setname("V8Worker");
2953
std::unique_ptr<PlatformWorkerData>
@@ -40,8 +64,18 @@ static void PlatformWorkerThread(void* data) {
4064
worker_data->platform_workers_ready->Signal(lock);
4165
}
4266

67+
bool debug_log_enabled =
68+
worker_data->debug_log_level != PlatformDebugLogLevel::kNone;
69+
int id = worker_data->id;
4370
while (std::unique_ptr<Task> task =
4471
pending_worker_tasks->Lock().BlockingPop()) {
72+
if (debug_log_enabled) {
73+
fprintf(stderr,
74+
"\nPlatformWorkerThread %d running task %p\n",
75+
id,
76+
task.get());
77+
fflush(stderr);
78+
}
4579
task->Run();
4680
pending_worker_tasks->Lock().NotifyOfCompletion();
4781
}
@@ -75,6 +109,12 @@ class WorkerThreadsTaskRunner::DelayedTaskScheduler {
75109

76110
void PostDelayedTask(std::unique_ptr<Task> task, double delay_in_seconds) {
77111
auto locked = tasks_.Lock();
112+
113+
// The delayed task scheuler is on is own thread with its own loop that
114+
// runs the timers for the scheduled tasks to pop the original task back
115+
// into the the worker task queue. This first pushes the tasks that
116+
// schedules the timers into the local task queue that will be flushed
117+
// by the local event loop.
78118
locked.Push(std::make_unique<ScheduleTask>(
79119
this, std::move(task), delay_in_seconds));
80120
uv_async_send(&flush_tasks_);
@@ -109,6 +149,9 @@ class WorkerThreadsTaskRunner::DelayedTaskScheduler {
109149
while (!tasks_to_run.empty()) {
110150
std::unique_ptr<Task> task = std::move(tasks_to_run.front());
111151
tasks_to_run.pop();
152+
// This runs either the ScheduleTasks that scheduels the timers to
153+
// pop the tasks back into the worker task runner queue, or the
154+
// or the StopTasks to stop the timers and drop all the pending tasks.
112155
task->Run();
113156
}
114157
}
@@ -136,9 +179,9 @@ class WorkerThreadsTaskRunner::DelayedTaskScheduler {
136179
ScheduleTask(DelayedTaskScheduler* scheduler,
137180
std::unique_ptr<Task> task,
138181
double delay_in_seconds)
139-
: scheduler_(scheduler),
140-
task_(std::move(task)),
141-
delay_in_seconds_(delay_in_seconds) {}
182+
: scheduler_(scheduler),
183+
task_(std::move(task)),
184+
delay_in_seconds_(delay_in_seconds) {}
142185

143186
void Run() override {
144187
uint64_t delay_millis = llround(delay_in_seconds_ * 1000);
@@ -173,15 +216,21 @@ class WorkerThreadsTaskRunner::DelayedTaskScheduler {
173216
}
174217

175218
uv_sem_t ready_;
219+
// Task queue in the worker thread task runner, we push the delayed task back
220+
// to it when the timer expires.
176221
TaskQueue<Task>* pending_worker_tasks_;
177222

223+
// Locally scheduled tasks to be poped into the worker task runner queue.
224+
// It is flushed whenever the next closest timer expires.
178225
TaskQueue<Task> tasks_;
179226
uv_loop_t loop_;
180227
uv_async_t flush_tasks_;
181228
std::unordered_set<uv_timer_t*> timers_;
182229
};
183230

184-
WorkerThreadsTaskRunner::WorkerThreadsTaskRunner(int thread_pool_size) {
231+
WorkerThreadsTaskRunner::WorkerThreadsTaskRunner(
232+
int thread_pool_size, PlatformDebugLogLevel debug_log_level)
233+
: debug_log_level_(debug_log_level) {
185234
Mutex platform_workers_mutex;
186235
ConditionVariable platform_workers_ready;
187236

@@ -193,10 +242,13 @@ WorkerThreadsTaskRunner::WorkerThreadsTaskRunner(int thread_pool_size) {
193242
threads_.push_back(delayed_task_scheduler_->Start());
194243

195244
for (int i = 0; i < thread_pool_size; i++) {
196-
PlatformWorkerData* worker_data = new PlatformWorkerData{
197-
&pending_worker_tasks_, &platform_workers_mutex,
198-
&platform_workers_ready, &pending_platform_workers, i
199-
};
245+
PlatformWorkerData* worker_data =
246+
new PlatformWorkerData{&pending_worker_tasks_,
247+
&platform_workers_mutex,
248+
&platform_workers_ready,
249+
&pending_platform_workers,
250+
i,
251+
debug_log_level_};
200252
std::unique_ptr<uv_thread_t> t { new uv_thread_t() };
201253
if (uv_thread_create(t.get(), PlatformWorkerThread,
202254
worker_data) != 0) {
@@ -238,8 +290,8 @@ int WorkerThreadsTaskRunner::NumberOfWorkerThreads() const {
238290
}
239291

240292
PerIsolatePlatformData::PerIsolatePlatformData(
241-
Isolate* isolate, uv_loop_t* loop)
242-
: isolate_(isolate), loop_(loop) {
293+
Isolate* isolate, uv_loop_t* loop, PlatformDebugLogLevel debug_log_level)
294+
: isolate_(isolate), loop_(loop), debug_log_level_(debug_log_level) {
243295
flush_tasks_ = new uv_async_t();
244296
CHECK_EQ(0, uv_async_init(loop, flush_tasks_, FlushTasks));
245297
flush_tasks_->data = static_cast<void*>(this);
@@ -267,6 +319,15 @@ void PerIsolatePlatformData::PostTaskImpl(std::unique_ptr<Task> task,
267319
// the foreground task runner is being cleaned up by Shutdown(). In that
268320
// case, make sure we wait until the shutdown is completed (which leads
269321
// to flush_tasks_ == nullptr, and the task will be discarded).
322+
if (debug_log_level_ != PlatformDebugLogLevel::kNone) {
323+
fprintf(stderr, "\nPerIsolatePlatformData::PostTaskImpl %p", task.get());
324+
PrintSourceLocation(location);
325+
if (debug_log_level_ == PlatformDebugLogLevel::kVerbose) {
326+
DumpNativeBacktrace(stderr);
327+
}
328+
fflush(stderr);
329+
}
330+
270331
auto locked = foreground_tasks_.Lock();
271332
if (flush_tasks_ == nullptr) return;
272333
locked.Push(std::move(task));
@@ -277,6 +338,18 @@ void PerIsolatePlatformData::PostDelayedTaskImpl(
277338
std::unique_ptr<Task> task,
278339
double delay_in_seconds,
279340
const v8::SourceLocation& location) {
341+
if (debug_log_level_ != PlatformDebugLogLevel::kNone) {
342+
fprintf(stderr,
343+
"\nPerIsolatePlatformData::PostDelayedTaskImpl %p %f",
344+
task.get(),
345+
delay_in_seconds);
346+
PrintSourceLocation(location);
347+
if (debug_log_level_ == PlatformDebugLogLevel::kVerbose) {
348+
DumpNativeBacktrace(stderr);
349+
}
350+
fflush(stderr);
351+
}
352+
280353
auto locked = foreground_delayed_tasks_.Lock();
281354
if (flush_tasks_ == nullptr) return;
282355
std::unique_ptr<DelayedTask> delayed(new DelayedTask());
@@ -346,6 +419,16 @@ void PerIsolatePlatformData::DecreaseHandleCount() {
346419
NodePlatform::NodePlatform(int thread_pool_size,
347420
v8::TracingController* tracing_controller,
348421
v8::PageAllocator* page_allocator) {
422+
if (per_process::enabled_debug_list.enabled(
423+
DebugCategory::PLATFORM_VERBOSE)) {
424+
debug_log_level_ = PlatformDebugLogLevel::kVerbose;
425+
} else if (per_process::enabled_debug_list.enabled(
426+
DebugCategory::PLATFORM_MINIMAL)) {
427+
debug_log_level_ = PlatformDebugLogLevel::kMinimal;
428+
} else {
429+
debug_log_level_ = PlatformDebugLogLevel::kNone;
430+
}
431+
349432
if (tracing_controller != nullptr) {
350433
tracing_controller_ = tracing_controller;
351434
} else {
@@ -362,8 +445,8 @@ NodePlatform::NodePlatform(int thread_pool_size,
362445
DCHECK_EQ(GetTracingController(), tracing_controller_);
363446

364447
thread_pool_size = GetActualThreadPoolSize(thread_pool_size);
365-
worker_thread_task_runner_ =
366-
std::make_shared<WorkerThreadsTaskRunner>(thread_pool_size);
448+
worker_thread_task_runner_ = std::make_shared<WorkerThreadsTaskRunner>(
449+
thread_pool_size, debug_log_level_);
367450
}
368451

369452
NodePlatform::~NodePlatform() {
@@ -372,7 +455,8 @@ NodePlatform::~NodePlatform() {
372455

373456
void NodePlatform::RegisterIsolate(Isolate* isolate, uv_loop_t* loop) {
374457
Mutex::ScopedLock lock(per_isolate_mutex_);
375-
auto delegate = std::make_shared<PerIsolatePlatformData>(isolate, loop);
458+
auto delegate =
459+
std::make_shared<PerIsolatePlatformData>(isolate, loop, debug_log_level_);
376460
IsolatePlatformDelegate* ptr = delegate.get();
377461
auto insertion = per_isolate_.emplace(
378462
isolate,
@@ -527,6 +611,17 @@ void NodePlatform::PostTaskOnWorkerThreadImpl(
527611
v8::TaskPriority priority,
528612
std::unique_ptr<v8::Task> task,
529613
const v8::SourceLocation& location) {
614+
if (debug_log_level_ != PlatformDebugLogLevel::kNone) {
615+
fprintf(stderr,
616+
"\nNodePlatform::PostTaskOnWorkerThreadImpl %s %p",
617+
GetTaskPriorityName(priority),
618+
task.get());
619+
PrintSourceLocation(location);
620+
if (debug_log_level_ == PlatformDebugLogLevel::kVerbose) {
621+
DumpNativeBacktrace(stderr);
622+
}
623+
fflush(stderr);
624+
}
530625
worker_thread_task_runner_->PostTask(std::move(task));
531626
}
532627

@@ -535,6 +630,18 @@ void NodePlatform::PostDelayedTaskOnWorkerThreadImpl(
535630
std::unique_ptr<v8::Task> task,
536631
double delay_in_seconds,
537632
const v8::SourceLocation& location) {
633+
if (debug_log_level_ != PlatformDebugLogLevel::kNone) {
634+
fprintf(stderr,
635+
"\nNodePlatform::PostDelayedTaskOnWorkerThreadImpl %s %p %f",
636+
GetTaskPriorityName(priority),
637+
task.get(),
638+
delay_in_seconds);
639+
PrintSourceLocation(location);
640+
if (debug_log_level_ == PlatformDebugLogLevel::kVerbose) {
641+
DumpNativeBacktrace(stderr);
642+
}
643+
fflush(stderr);
644+
}
538645
worker_thread_task_runner_->PostDelayedTask(std::move(task),
539646
delay_in_seconds);
540647
}
@@ -564,6 +671,17 @@ std::unique_ptr<v8::JobHandle> NodePlatform::CreateJobImpl(
564671
v8::TaskPriority priority,
565672
std::unique_ptr<v8::JobTask> job_task,
566673
const v8::SourceLocation& location) {
674+
if (debug_log_level_ != PlatformDebugLogLevel::kNone) {
675+
fprintf(stderr,
676+
"\nNodePlatform::CreateJobImpl %s %p",
677+
GetTaskPriorityName(priority),
678+
job_task.get());
679+
PrintSourceLocation(location);
680+
if (debug_log_level_ == PlatformDebugLogLevel::kVerbose) {
681+
DumpNativeBacktrace(stderr);
682+
}
683+
fflush(stderr);
684+
}
567685
return v8::platform::NewDefaultJobHandle(
568686
this, priority, std::move(job_task), NumberOfWorkerThreads());
569687
}

src/node_platform.h

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,22 @@ struct DelayedTask {
6161
std::shared_ptr<PerIsolatePlatformData> platform_data;
6262
};
6363

64+
enum class PlatformDebugLogLevel {
65+
kNone = 0,
66+
kMinimal = 1,
67+
kVerbose = 2,
68+
};
69+
6470
// This acts as the foreground task runner for a given Isolate.
6571
class PerIsolatePlatformData
6672
: public IsolatePlatformDelegate,
6773
public v8::TaskRunner,
6874
public std::enable_shared_from_this<PerIsolatePlatformData> {
6975
public:
70-
PerIsolatePlatformData(v8::Isolate* isolate, uv_loop_t* loop);
76+
PerIsolatePlatformData(
77+
v8::Isolate* isolate,
78+
uv_loop_t* loop,
79+
PlatformDebugLogLevel debug_log_level = PlatformDebugLogLevel::kNone);
7180
~PerIsolatePlatformData() override;
7281

7382
std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner() override;
@@ -134,12 +143,14 @@ class PerIsolatePlatformData
134143
typedef std::unique_ptr<DelayedTask, void (*)(DelayedTask*)>
135144
DelayedTaskPointer;
136145
std::vector<DelayedTaskPointer> scheduled_delayed_tasks_;
146+
PlatformDebugLogLevel debug_log_level_ = PlatformDebugLogLevel::kNone;
137147
};
138148

139149
// This acts as the single worker thread task runner for all Isolates.
140150
class WorkerThreadsTaskRunner {
141151
public:
142-
explicit WorkerThreadsTaskRunner(int thread_pool_size);
152+
explicit WorkerThreadsTaskRunner(int thread_pool_size,
153+
PlatformDebugLogLevel debug_log_level);
143154

144155
void PostTask(std::unique_ptr<v8::Task> task);
145156
void PostDelayedTask(std::unique_ptr<v8::Task> task, double delay_in_seconds);
@@ -150,12 +161,21 @@ class WorkerThreadsTaskRunner {
150161
int NumberOfWorkerThreads() const;
151162

152163
private:
164+
// A queue shared by all threads. The consumers are the worker threads which
165+
// take tasks from it to run in PlatformWorkerThread(). The producers can be
166+
// any thread. Both the foreground thread and the worker threads can push
167+
// tasks into the queue via v8::Platform::PostTaskOnWorkerThread() which
168+
// eventually calls PostTask() on this class. When any thread calls
169+
// v8::Platform::PostDelayedTaskOnWorkerThread(), the DelayedTaskScheduler
170+
// thread will schedule a timer that pushes the delayed tasks back into this
171+
// queue when the timer expires.
153172
TaskQueue<v8::Task> pending_worker_tasks_;
154173

155174
class DelayedTaskScheduler;
156175
std::unique_ptr<DelayedTaskScheduler> delayed_task_scheduler_;
157176

158177
std::vector<std::unique_ptr<uv_thread_t>> threads_;
178+
PlatformDebugLogLevel debug_log_level_ = PlatformDebugLogLevel::kNone;
159179
};
160180

161181
class NodePlatform : public MultiIsolatePlatform {
@@ -216,6 +236,7 @@ class NodePlatform : public MultiIsolatePlatform {
216236
v8::PageAllocator* page_allocator_;
217237
std::shared_ptr<WorkerThreadsTaskRunner> worker_thread_task_runner_;
218238
bool has_shut_down_ = false;
239+
PlatformDebugLogLevel debug_log_level_ = PlatformDebugLogLevel::kNone;
219240
};
220241

221242
} // namespace node

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy