-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
perf_hooks: precise mode for monitorEventLoopDelay #32018
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
334af98
31da304
6685c7e
ae29599
6ef15b7
4e8a342
fa5c98e
5fbad01
2a211b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -474,7 +474,7 @@ static void ELDHistogramNew(const FunctionCallbackInfo<Value>& args) { | |||||||||||||||||||||||||
Environment* env = Environment::GetCurrent(args); | ||||||||||||||||||||||||||
CHECK(args.IsConstructCall()); | ||||||||||||||||||||||||||
int32_t resolution = args[0]->IntegerValue(env->context()).FromJust(); | ||||||||||||||||||||||||||
CHECK_GT(resolution, 0); | ||||||||||||||||||||||||||
CHECK_GE(resolution, 0); | ||||||||||||||||||||||||||
new ELDHistogram(env, args.This(), resolution); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} // namespace | ||||||||||||||||||||||||||
|
@@ -489,29 +489,61 @@ ELDHistogram::ELDHistogram( | |||||||||||||||||||||||||
Histogram(1, 3.6e12), | ||||||||||||||||||||||||||
resolution_(resolution) { | ||||||||||||||||||||||||||
MakeWeak(); | ||||||||||||||||||||||||||
uv_timer_init(env->event_loop(), &timer_); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// Since we pass `timer_` to `HandleWrap` constructor - we have to | ||||||||||||||||||||||||||
// initialize it here. It is equally important to have it initialized for | ||||||||||||||||||||||||||
// correct operation of `Close()` below. | ||||||||||||||||||||||||||
CHECK_EQ(uv_timer_init(env->event_loop(), &timer_), 0); | ||||||||||||||||||||||||||
indutny marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
if (is_precise()) { | ||||||||||||||||||||||||||
CHECK_EQ(uv_prepare_init(env->event_loop(), &prepare_), 0); | ||||||||||||||||||||||||||
CHECK_EQ(uv_check_init(env->event_loop(), &check_), 0); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
void ELDHistogram::Close(Local<Value> close_callback) { | ||||||||||||||||||||||||||
// HandleWrap::Close will call `uv_close()` on `timer_` and | ||||||||||||||||||||||||||
// deallocate `ELDHistogram` in `HandleWrap::OnClose`. | ||||||||||||||||||||||||||
// Therefore, it is safe to call `uv_close` with `nullptr` here since | ||||||||||||||||||||||||||
// both `prepare_` and `check_`. | ||||||||||||||||||||||||||
if (is_precise() && !IsHandleClosing()) { | ||||||||||||||||||||||||||
uv_close(reinterpret_cast<uv_handle_t*>(&prepare_), nullptr); | ||||||||||||||||||||||||||
uv_close(reinterpret_cast<uv_handle_t*>(&check_), nullptr); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
HandleWrap::Close(close_callback); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
void ELDHistogram::TraceHistogram() { | ||||||||||||||||||||||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop), "min", Min()); | ||||||||||||||||||||||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop), "max", Max()); | ||||||||||||||||||||||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop), "mean", Mean()); | ||||||||||||||||||||||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop), "stddev", Stddev()); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
void ELDHistogram::DelayIntervalCallback(uv_timer_t* req) { | ||||||||||||||||||||||||||
ELDHistogram* histogram = ContainerOf(&ELDHistogram::timer_, req); | ||||||||||||||||||||||||||
histogram->RecordDelta(); | ||||||||||||||||||||||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop), | ||||||||||||||||||||||||||
"min", histogram->Min()); | ||||||||||||||||||||||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop), | ||||||||||||||||||||||||||
"max", histogram->Max()); | ||||||||||||||||||||||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop), | ||||||||||||||||||||||||||
"mean", histogram->Mean()); | ||||||||||||||||||||||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop), | ||||||||||||||||||||||||||
"stddev", histogram->Stddev()); | ||||||||||||||||||||||||||
histogram->RecordCoarseDelta(); | ||||||||||||||||||||||||||
histogram->TraceHistogram(); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
bool ELDHistogram::RecordDelta() { | ||||||||||||||||||||||||||
void ELDHistogram::CheckCallback(uv_check_t* handle) { | ||||||||||||||||||||||||||
ELDHistogram* histogram = ContainerOf(&ELDHistogram::check_, handle); | ||||||||||||||||||||||||||
histogram->RecordPreciseDelayStart(); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
void ELDHistogram::PrepareCallback(uv_prepare_t* handle) { | ||||||||||||||||||||||||||
ELDHistogram* histogram = ContainerOf(&ELDHistogram::prepare_, handle); | ||||||||||||||||||||||||||
histogram->RecordPreciseDelayStop(); | ||||||||||||||||||||||||||
histogram->TraceHistogram(); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
void ELDHistogram::RecordCoarseDelta() { | ||||||||||||||||||||||||||
uint64_t time = uv_hrtime(); | ||||||||||||||||||||||||||
bool ret = true; | ||||||||||||||||||||||||||
if (prev_ > 0) { | ||||||||||||||||||||||||||
int64_t delta = time - prev_; | ||||||||||||||||||||||||||
if (delta > 0) { | ||||||||||||||||||||||||||
ret = Record(delta); | ||||||||||||||||||||||||||
bool ret = Record(delta); | ||||||||||||||||||||||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop), | ||||||||||||||||||||||||||
"delay", delta); | ||||||||||||||||||||||||||
if (!ret) { | ||||||||||||||||||||||||||
|
@@ -525,25 +557,76 @@ bool ELDHistogram::RecordDelta() { | |||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
prev_ = time; | ||||||||||||||||||||||||||
return ret; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
void ELDHistogram::RecordPreciseDelayStart() { | ||||||||||||||||||||||||||
prev_ = uv_hrtime(); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
void ELDHistogram::RecordPreciseDelayStop() { | ||||||||||||||||||||||||||
if (prev_ == 0) { | ||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
Comment on lines
+567
to
+569
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Super minor nit... as of late we've been moving away from
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it part of official code style for Node.js? If there any way to persuade, I'd insist that we keep parens even though (as many of you certainly know and remember) I was a proponent of omitting them. That apple kernel bug that was fixed some time ago has convinced me that omitting parens is error prone. I don't have a link to the kernel fix anymore, but it looked like this: if (something)
if (something_else)
do_something(); Forgetting to put an That being said, I don't insist on changing existing code. Still it'd be great to write new code differently! |
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
uint64_t time = uv_hrtime(); | ||||||||||||||||||||||||||
int64_t delta = time - prev_; | ||||||||||||||||||||||||||
if (delta <= 0) { | ||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
Comment on lines
+573
to
+575
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit...
Suggested change
|
||||||||||||||||||||||||||
bool ret = Record(delta); | ||||||||||||||||||||||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop), | ||||||||||||||||||||||||||
"delay", delta); | ||||||||||||||||||||||||||
if (ret) { | ||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
if (exceeds_ < 0xFFFFFFFF) { | ||||||||||||||||||||||||||
exceeds_++; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
Comment on lines
+579
to
+584
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit...
Suggested change
|
||||||||||||||||||||||||||
ProcessEmitWarning( | ||||||||||||||||||||||||||
env(), | ||||||||||||||||||||||||||
"Event loop delay exceeded 1 hour: %" PRId64 " nanoseconds", | ||||||||||||||||||||||||||
delta); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
bool ELDHistogram::Enable() { | ||||||||||||||||||||||||||
if (enabled_ || IsHandleClosing()) return false; | ||||||||||||||||||||||||||
enabled_ = true; | ||||||||||||||||||||||||||
prev_ = 0; | ||||||||||||||||||||||||||
uv_timer_start(&timer_, | ||||||||||||||||||||||||||
DelayIntervalCallback, | ||||||||||||||||||||||||||
resolution_, | ||||||||||||||||||||||||||
resolution_); | ||||||||||||||||||||||||||
uv_unref(reinterpret_cast<uv_handle_t*>(&timer_)); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
if (is_precise()) { | ||||||||||||||||||||||||||
// `uv_prepare_start`/`uv_check_start` prepend the handles to the queue. | ||||||||||||||||||||||||||
// Newly started handles will have their callbacks invoked **before** the | ||||||||||||||||||||||||||
// old handles' callbacks. | ||||||||||||||||||||||||||
// | ||||||||||||||||||||||||||
// This is important because of `immediate_check_handle` in `src/env.cc`. | ||||||||||||||||||||||||||
// `immediate_check_handle` is used for invoking user callbacks queued with | ||||||||||||||||||||||||||
// `setImmediate()` API call. `ELDHistogram` has to record the delay | ||||||||||||||||||||||||||
// induced by `setImmediate()` callbacks too so the order of handles is | ||||||||||||||||||||||||||
// important. | ||||||||||||||||||||||||||
CHECK_EQ(uv_prepare_start(&prepare_, PrepareCallback), 0); | ||||||||||||||||||||||||||
CHECK_EQ(uv_check_start(&check_, CheckCallback), 0); | ||||||||||||||||||||||||||
uv_unref(reinterpret_cast<uv_handle_t*>(&prepare_)); | ||||||||||||||||||||||||||
uv_unref(reinterpret_cast<uv_handle_t*>(&check_)); | ||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||
CHECK_EQ(uv_timer_start(&timer_, | ||||||||||||||||||||||||||
DelayIntervalCallback, | ||||||||||||||||||||||||||
resolution_, | ||||||||||||||||||||||||||
resolution_), | ||||||||||||||||||||||||||
0); | ||||||||||||||||||||||||||
uv_unref(reinterpret_cast<uv_handle_t*>(&timer_)); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
return true; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
bool ELDHistogram::Disable() { | ||||||||||||||||||||||||||
if (!enabled_ || IsHandleClosing()) return false; | ||||||||||||||||||||||||||
enabled_ = false; | ||||||||||||||||||||||||||
uv_timer_stop(&timer_); | ||||||||||||||||||||||||||
if (is_precise()) { | ||||||||||||||||||||||||||
CHECK_EQ(uv_prepare_stop(&prepare_), 0); | ||||||||||||||||||||||||||
CHECK_EQ(uv_check_stop(&check_), 0); | ||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||
CHECK_EQ(uv_timer_stop(&timer_), 0); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
return true; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
Uh oh!
There was an error while loading. Please reload this page.