Skip to content

Commit ddec63d

Browse files
joyeecheungnodejs-github-bot
authored andcommitted
src: add more debug logs and comments in NodePlatform
PR-URL: #58047 Refs: #47452 Refs: #54918 Reviewed-By: Stephen Belanger <[email protected]>
1 parent c2d8156 commit ddec63d

File tree

3 files changed

+156
-15
lines changed

3 files changed

+156
-15
lines changed

src/debug_utils.h

+2
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

+131-13
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

+23-2
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)