Skip to content

Commit 63656d2

Browse files
joyeecheungaduh95
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 4ccf824 commit 63656d2

File tree

3 files changed

+154
-15
lines changed

3 files changed

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

+129-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
std::unique_ptr<PlatformWorkerData>
2953
worker_data(static_cast<PlatformWorkerData*>(data));
@@ -39,8 +63,18 @@ static void PlatformWorkerThread(void* data) {
3963
worker_data->platform_workers_ready->Signal(lock);
4064
}
4165

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

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

142185
void Run() override {
143186
uint64_t delay_millis = llround(delay_in_seconds_ * 1000);
@@ -172,15 +215,21 @@ class WorkerThreadsTaskRunner::DelayedTaskScheduler {
172215
}
173216

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

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

183-
WorkerThreadsTaskRunner::WorkerThreadsTaskRunner(int thread_pool_size) {
230+
WorkerThreadsTaskRunner::WorkerThreadsTaskRunner(
231+
int thread_pool_size, PlatformDebugLogLevel debug_log_level)
232+
: debug_log_level_(debug_log_level) {
184233
Mutex platform_workers_mutex;
185234
ConditionVariable platform_workers_ready;
186235

@@ -192,10 +241,13 @@ WorkerThreadsTaskRunner::WorkerThreadsTaskRunner(int thread_pool_size) {
192241
threads_.push_back(delayed_task_scheduler_->Start());
193242

194243
for (int i = 0; i < thread_pool_size; i++) {
195-
PlatformWorkerData* worker_data = new PlatformWorkerData{
196-
&pending_worker_tasks_, &platform_workers_mutex,
197-
&platform_workers_ready, &pending_platform_workers, i
198-
};
244+
PlatformWorkerData* worker_data =
245+
new PlatformWorkerData{&pending_worker_tasks_,
246+
&platform_workers_mutex,
247+
&platform_workers_ready,
248+
&pending_platform_workers,
249+
i,
250+
debug_log_level_};
199251
std::unique_ptr<uv_thread_t> t { new uv_thread_t() };
200252
if (uv_thread_create(t.get(), PlatformWorkerThread,
201253
worker_data) != 0) {
@@ -237,8 +289,8 @@ int WorkerThreadsTaskRunner::NumberOfWorkerThreads() const {
237289
}
238290

239291
PerIsolatePlatformData::PerIsolatePlatformData(
240-
Isolate* isolate, uv_loop_t* loop)
241-
: isolate_(isolate), loop_(loop) {
292+
Isolate* isolate, uv_loop_t* loop, PlatformDebugLogLevel debug_log_level)
293+
: isolate_(isolate), loop_(loop), debug_log_level_(debug_log_level) {
242294
flush_tasks_ = new uv_async_t();
243295
CHECK_EQ(0, uv_async_init(loop, flush_tasks_, FlushTasks));
244296
flush_tasks_->data = static_cast<void*>(this);
@@ -264,6 +316,14 @@ void PerIsolatePlatformData::PostTask(std::unique_ptr<Task> task) {
264316
// the foreground task runner is being cleaned up by Shutdown(). In that
265317
// case, make sure we wait until the shutdown is completed (which leads
266318
// to flush_tasks_ == nullptr, and the task will be discarded).
319+
if (debug_log_level_ != PlatformDebugLogLevel::kNone) {
320+
fprintf(stderr, "\nPerIsolatePlatformData::PostTaskImpl %p", task.get());
321+
if (debug_log_level_ == PlatformDebugLogLevel::kVerbose) {
322+
DumpNativeBacktrace(stderr);
323+
}
324+
fflush(stderr);
325+
}
326+
267327
auto locked = foreground_tasks_.Lock();
268328
if (flush_tasks_ == nullptr) return;
269329
locked.Push(std::move(task));
@@ -272,6 +332,17 @@ void PerIsolatePlatformData::PostTask(std::unique_ptr<Task> task) {
272332

273333
void PerIsolatePlatformData::PostDelayedTask(
274334
std::unique_ptr<Task> task, double delay_in_seconds) {
335+
if (debug_log_level_ != PlatformDebugLogLevel::kNone) {
336+
fprintf(stderr,
337+
"\nPerIsolatePlatformData::PostDelayedTaskImpl %p %f",
338+
task.get(),
339+
delay_in_seconds);
340+
if (debug_log_level_ == PlatformDebugLogLevel::kVerbose) {
341+
DumpNativeBacktrace(stderr);
342+
}
343+
fflush(stderr);
344+
}
345+
275346
auto locked = foreground_delayed_tasks_.Lock();
276347
if (flush_tasks_ == nullptr) return;
277348
std::unique_ptr<DelayedTask> delayed(new DelayedTask());
@@ -339,6 +410,16 @@ void PerIsolatePlatformData::DecreaseHandleCount() {
339410
NodePlatform::NodePlatform(int thread_pool_size,
340411
v8::TracingController* tracing_controller,
341412
v8::PageAllocator* page_allocator) {
413+
if (per_process::enabled_debug_list.enabled(
414+
DebugCategory::PLATFORM_VERBOSE)) {
415+
debug_log_level_ = PlatformDebugLogLevel::kVerbose;
416+
} else if (per_process::enabled_debug_list.enabled(
417+
DebugCategory::PLATFORM_MINIMAL)) {
418+
debug_log_level_ = PlatformDebugLogLevel::kMinimal;
419+
} else {
420+
debug_log_level_ = PlatformDebugLogLevel::kNone;
421+
}
422+
342423
if (tracing_controller != nullptr) {
343424
tracing_controller_ = tracing_controller;
344425
} else {
@@ -355,8 +436,8 @@ NodePlatform::NodePlatform(int thread_pool_size,
355436
DCHECK_EQ(GetTracingController(), tracing_controller_);
356437

357438
thread_pool_size = GetActualThreadPoolSize(thread_pool_size);
358-
worker_thread_task_runner_ =
359-
std::make_shared<WorkerThreadsTaskRunner>(thread_pool_size);
439+
worker_thread_task_runner_ = std::make_shared<WorkerThreadsTaskRunner>(
440+
thread_pool_size, debug_log_level_);
360441
}
361442

362443
NodePlatform::~NodePlatform() {
@@ -365,7 +446,8 @@ NodePlatform::~NodePlatform() {
365446

366447
void NodePlatform::RegisterIsolate(Isolate* isolate, uv_loop_t* loop) {
367448
Mutex::ScopedLock lock(per_isolate_mutex_);
368-
auto delegate = std::make_shared<PerIsolatePlatformData>(isolate, loop);
449+
auto delegate =
450+
std::make_shared<PerIsolatePlatformData>(isolate, loop, debug_log_level_);
369451
IsolatePlatformDelegate* ptr = delegate.get();
370452
auto insertion = per_isolate_.emplace(
371453
isolate,
@@ -520,6 +602,17 @@ void NodePlatform::PostTaskOnWorkerThreadImpl(
520602
v8::TaskPriority priority,
521603
std::unique_ptr<v8::Task> task,
522604
const v8::SourceLocation& location) {
605+
if (debug_log_level_ != PlatformDebugLogLevel::kNone) {
606+
fprintf(stderr,
607+
"\nNodePlatform::PostTaskOnWorkerThreadImpl %s %p",
608+
GetTaskPriorityName(priority),
609+
task.get());
610+
PrintSourceLocation(location);
611+
if (debug_log_level_ == PlatformDebugLogLevel::kVerbose) {
612+
DumpNativeBacktrace(stderr);
613+
}
614+
fflush(stderr);
615+
}
523616
worker_thread_task_runner_->PostTask(std::move(task));
524617
}
525618

@@ -528,6 +621,18 @@ void NodePlatform::PostDelayedTaskOnWorkerThreadImpl(
528621
std::unique_ptr<v8::Task> task,
529622
double delay_in_seconds,
530623
const v8::SourceLocation& location) {
624+
if (debug_log_level_ != PlatformDebugLogLevel::kNone) {
625+
fprintf(stderr,
626+
"\nNodePlatform::PostDelayedTaskOnWorkerThreadImpl %s %p %f",
627+
GetTaskPriorityName(priority),
628+
task.get(),
629+
delay_in_seconds);
630+
PrintSourceLocation(location);
631+
if (debug_log_level_ == PlatformDebugLogLevel::kVerbose) {
632+
DumpNativeBacktrace(stderr);
633+
}
634+
fflush(stderr);
635+
}
531636
worker_thread_task_runner_->PostDelayedTask(std::move(task),
532637
delay_in_seconds);
533638
}
@@ -557,6 +662,17 @@ std::unique_ptr<v8::JobHandle> NodePlatform::CreateJobImpl(
557662
v8::TaskPriority priority,
558663
std::unique_ptr<v8::JobTask> job_task,
559664
const v8::SourceLocation& location) {
665+
if (debug_log_level_ != PlatformDebugLogLevel::kNone) {
666+
fprintf(stderr,
667+
"\nNodePlatform::CreateJobImpl %s %p",
668+
GetTaskPriorityName(priority),
669+
job_task.get());
670+
PrintSourceLocation(location);
671+
if (debug_log_level_ == PlatformDebugLogLevel::kVerbose) {
672+
DumpNativeBacktrace(stderr);
673+
}
674+
fflush(stderr);
675+
}
560676
return v8::platform::NewDefaultJobHandle(
561677
this, priority, std::move(job_task), NumberOfWorkerThreads());
562678
}

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;
@@ -126,12 +135,14 @@ class PerIsolatePlatformData :
126135
typedef std::unique_ptr<DelayedTask, void(*)(DelayedTask*)>
127136
DelayedTaskPointer;
128137
std::vector<DelayedTaskPointer> scheduled_delayed_tasks_;
138+
PlatformDebugLogLevel debug_log_level_ = PlatformDebugLogLevel::kNone;
129139
};
130140

131141
// This acts as the single worker thread task runner for all Isolates.
132142
class WorkerThreadsTaskRunner {
133143
public:
134-
explicit WorkerThreadsTaskRunner(int thread_pool_size);
144+
explicit WorkerThreadsTaskRunner(int thread_pool_size,
145+
PlatformDebugLogLevel debug_log_level);
135146

136147
void PostTask(std::unique_ptr<v8::Task> task);
137148
void PostDelayedTask(std::unique_ptr<v8::Task> task,
@@ -143,12 +154,21 @@ class WorkerThreadsTaskRunner {
143154
int NumberOfWorkerThreads() const;
144155

145156
private:
157+
// A queue shared by all threads. The consumers are the worker threads which
158+
// take tasks from it to run in PlatformWorkerThread(). The producers can be
159+
// any thread. Both the foreground thread and the worker threads can push
160+
// tasks into the queue via v8::Platform::PostTaskOnWorkerThread() which
161+
// eventually calls PostTask() on this class. When any thread calls
162+
// v8::Platform::PostDelayedTaskOnWorkerThread(), the DelayedTaskScheduler
163+
// thread will schedule a timer that pushes the delayed tasks back into this
164+
// queue when the timer expires.
146165
TaskQueue<v8::Task> pending_worker_tasks_;
147166

148167
class DelayedTaskScheduler;
149168
std::unique_ptr<DelayedTaskScheduler> delayed_task_scheduler_;
150169

151170
std::vector<std::unique_ptr<uv_thread_t>> threads_;
171+
PlatformDebugLogLevel debug_log_level_ = PlatformDebugLogLevel::kNone;
152172
};
153173

154174
class NodePlatform : public MultiIsolatePlatform {
@@ -208,6 +228,7 @@ class NodePlatform : public MultiIsolatePlatform {
208228
v8::PageAllocator* page_allocator_;
209229
std::shared_ptr<WorkerThreadsTaskRunner> worker_thread_task_runner_;
210230
bool has_shut_down_ = false;
231+
PlatformDebugLogLevel debug_log_level_ = PlatformDebugLogLevel::kNone;
211232
};
212233

213234
} // namespace node

0 commit comments

Comments
 (0)