-
-
Notifications
You must be signed in to change notification settings - Fork 35.7k
src: add event loop based metrics into node #62935
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
base: main
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
|
|
@@ -68,6 +68,8 @@ CFunction IntervalHistogram::fast_start_( | |
| CFunction::Make(&IntervalHistogram::FastStart)); | ||
| CFunction IntervalHistogram::fast_stop_( | ||
| CFunction::Make(&IntervalHistogram::FastStop)); | ||
| CFunction ELDHistogram::fast_start_(CFunction::Make(&ELDHistogram::FastStart)); | ||
| CFunction ELDHistogram::fast_stop_(CFunction::Make(&ELDHistogram::FastStop)); | ||
|
|
||
| void HistogramImpl::AddMethods(Isolate* isolate, Local<FunctionTemplate> tmpl) { | ||
| // TODO(@jasnell): The bigint API variations do not yet support fast | ||
|
|
@@ -444,6 +446,148 @@ void IntervalHistogram::FastStop(Local<Value> receiver) { | |
| histogram->OnStop(); | ||
| } | ||
|
|
||
| Local<FunctionTemplate> ELDHistogram::GetConstructorTemplate(Environment* env) { | ||
| Local<FunctionTemplate> tmpl = env->eldhistogram_constructor_template(); | ||
| if (tmpl.IsEmpty()) { | ||
| Isolate* isolate = env->isolate(); | ||
| tmpl = NewFunctionTemplate(isolate, nullptr); | ||
| tmpl->Inherit(HandleWrap::GetConstructorTemplate(env)); | ||
| tmpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "Histogram")); | ||
| auto instance = tmpl->InstanceTemplate(); | ||
| instance->SetInternalFieldCount(ELDHistogram::kInternalFieldCount); | ||
| HistogramImpl::AddMethods(isolate, tmpl); | ||
| SetFastMethod(isolate, instance, "start", Start, &fast_start_); | ||
| SetFastMethod(isolate, instance, "stop", Stop, &fast_stop_); | ||
| env->set_eldhistogram_constructor_template(tmpl); | ||
| } | ||
| return tmpl; | ||
| } | ||
|
|
||
| void ELDHistogram::RegisterExternalReferences( | ||
| ExternalReferenceRegistry* registry) { | ||
| registry->Register(Start); | ||
| registry->Register(Stop); | ||
| registry->Register(fast_start_); | ||
| registry->Register(fast_stop_); | ||
| HistogramImpl::RegisterExternalReferences(registry); | ||
| } | ||
|
|
||
| ELDHistogram::ELDHistogram(Environment* env, | ||
| Local<Object> wrap, | ||
| AsyncWrap::ProviderType type, | ||
| const Histogram::Options& options) | ||
| : HandleWrap( | ||
| env, wrap, reinterpret_cast<uv_handle_t*>(&check_handle_), type), | ||
| HistogramImpl(options) { | ||
| MakeWeak(); | ||
| wrap->SetAlignedPointerInInternalField( | ||
| HistogramImpl::InternalFields::kImplField, | ||
| static_cast<HistogramImpl*>(this), | ||
| EmbedderDataTag::kDefault); | ||
| uv_check_init(env->event_loop(), &check_handle_); | ||
| uv_prepare_init(env->event_loop(), &prepare_handle_); | ||
| uv_unref(reinterpret_cast<uv_handle_t*>(&check_handle_)); | ||
| uv_unref(reinterpret_cast<uv_handle_t*>(&prepare_handle_)); | ||
| prepare_handle_.data = this; | ||
| } | ||
|
|
||
| BaseObjectPtr<ELDHistogram> ELDHistogram::Create( | ||
| Environment* env, const Histogram::Options& options) { | ||
| Local<Object> obj; | ||
| if (!GetConstructorTemplate(env) | ||
| ->InstanceTemplate() | ||
| ->NewInstance(env->context()) | ||
| .ToLocal(&obj)) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| return MakeBaseObject<ELDHistogram>( | ||
| env, obj, AsyncWrap::PROVIDER_ELDHISTOGRAM, options); | ||
| } | ||
|
|
||
| void ELDHistogram::PrepareCB(uv_prepare_t* handle) { | ||
| ELDHistogram* self = static_cast<ELDHistogram*>(handle->data); | ||
| if (!self->enabled_) return; | ||
| self->prepare_time_ = uv_hrtime(); | ||
| self->timeout_ = uv_backend_timeout(handle->loop); | ||
| } | ||
|
|
||
| void ELDHistogram::CheckCB(uv_check_t* handle) { | ||
| ELDHistogram* self = ContainerOf(&ELDHistogram::check_handle_, handle); | ||
| if (!self->enabled_) return; | ||
|
|
||
| uint64_t check_time = uv_hrtime(); | ||
| uint64_t poll_time = check_time - self->prepare_time_; | ||
| uint64_t latency = self->prepare_time_ - self->check_time_; | ||
|
|
||
| if (self->timeout_ >= 0) { | ||
| uint64_t timeout_ns = static_cast<uint64_t>(self->timeout_) * 1000 * 1000; | ||
| if (poll_time > timeout_ns) { | ||
| latency += poll_time - timeout_ns; | ||
| } | ||
| } | ||
|
|
||
| self->histogram()->Record(latency == 0 ? 1 : latency); | ||
| self->check_time_ = check_time; | ||
| } | ||
|
|
||
| void ELDHistogram::MemoryInfo(MemoryTracker* tracker) const { | ||
| tracker->TrackField("histogram", histogram()); | ||
| } | ||
|
|
||
| void ELDHistogram::OnStart(StartFlags flags) { | ||
| if (enabled_ || IsHandleClosing()) return; | ||
| enabled_ = true; | ||
| if (flags == StartFlags::RESET) histogram()->Reset(); | ||
| check_time_ = uv_hrtime(); | ||
| prepare_time_ = check_time_; | ||
| timeout_ = 0; | ||
| uv_check_start(&check_handle_, CheckCB); | ||
| uv_prepare_start(&prepare_handle_, PrepareCB); | ||
| uv_unref(reinterpret_cast<uv_handle_t*>(&check_handle_)); | ||
| uv_unref(reinterpret_cast<uv_handle_t*>(&prepare_handle_)); | ||
| } | ||
|
|
||
| void ELDHistogram::OnStop() { | ||
| if (!enabled_ || IsHandleClosing()) return; | ||
| enabled_ = false; | ||
| uv_check_stop(&check_handle_); | ||
| uv_prepare_stop(&prepare_handle_); | ||
| } | ||
|
|
||
| void ELDHistogram::Close(Local<Value> close_callback) { | ||
| if (IsHandleClosing()) return; | ||
| OnStop(); | ||
| HandleWrap::Close(close_callback); | ||
| uv_close(reinterpret_cast<uv_handle_t*>(&prepare_handle_), nullptr); | ||
| } | ||
|
|
||
| void ELDHistogram::Start(const FunctionCallbackInfo<Value>& args) { | ||
| ELDHistogram* histogram; | ||
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.This()); | ||
| histogram->OnStart(args[0]->IsTrue() ? StartFlags::RESET : StartFlags::NONE); | ||
| } | ||
|
|
||
| void ELDHistogram::FastStart(Local<Value> receiver, bool reset) { | ||
| TRACK_V8_FAST_API_CALL("histogram.eventLoopDelay.start"); | ||
| ELDHistogram* histogram; | ||
| ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver); | ||
| histogram->OnStart(reset ? StartFlags::RESET : StartFlags::NONE); | ||
| } | ||
|
|
||
| void ELDHistogram::Stop(const FunctionCallbackInfo<Value>& args) { | ||
| ELDHistogram* histogram; | ||
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.This()); | ||
| histogram->OnStop(); | ||
| } | ||
|
|
||
| void ELDHistogram::FastStop(Local<Value> receiver) { | ||
| TRACK_V8_FAST_API_CALL("histogram.eventLoopDelay.stop"); | ||
| ELDHistogram* histogram; | ||
| ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver); | ||
| histogram->OnStop(); | ||
| } | ||
|
Comment on lines
+565
to
+589
Member
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. This is duplicating the existing code. Should we abstract it into a single common shape? We can do that as a separate PR, while I think it would be nice to have here as well
Author
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. By this you mean adding a sort of shared template helper between IntervalHistogram and ELDHistogram? Example: StartHandleHistogram being the shared template helper |
||
|
|
||
| void HistogramImpl::GetCount(const FunctionCallbackInfo<Value>& args) { | ||
| HistogramImpl* histogram = HistogramImpl::FromJSObject(args.This()); | ||
| double value = static_cast<double>((*histogram)->Count()); | ||
|
|
@@ -607,6 +751,10 @@ HistogramImpl* HistogramImpl::FromJSObject(Local<Value> value) { | |
| HistogramImpl::kImplField, EmbedderDataTag::kDefault)); | ||
| } | ||
|
|
||
| std::unique_ptr<worker::TransferData> ELDHistogram::CloneForMessaging() const { | ||
| return std::make_unique<HistogramBase::HistogramTransferData>(histogram()); | ||
| } | ||
|
|
||
| std::unique_ptr<worker::TransferData> | ||
| IntervalHistogram::CloneForMessaging() const { | ||
| return std::make_unique<HistogramBase::HistogramTransferData>(histogram()); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| // Flags: --allow-natives-syntax --expose-internals --no-warnings | ||
| 'use strict'; | ||
|
|
||
| const common = require('../common'); | ||
| const assert = require('assert'); | ||
|
|
||
| const { internalBinding } = require('internal/test/binding'); | ||
| const { createELDHistogram } = internalBinding('performance'); | ||
|
|
||
| const histogram = createELDHistogram(1, true); | ||
|
|
||
| function testFastMethods() { | ||
| histogram.start(true); | ||
| histogram.stop(); | ||
| } | ||
|
|
||
| eval('%PrepareFunctionForOptimization(testFastMethods)'); | ||
| testFastMethods(); | ||
| eval('%OptimizeFunctionOnNextCall(testFastMethods)'); | ||
| testFastMethods(); | ||
|
|
||
| if (common.isDebug) { | ||
| const { getV8FastApiCallCount } = internalBinding('debug'); | ||
| assert.strictEqual(getV8FastApiCallCount('histogram.eventLoopDelay.start'), 1); | ||
| assert.strictEqual(getV8FastApiCallCount('histogram.eventLoopDelay.stop'), 1); | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.