summaryrefslogtreecommitdiff
path: root/src/node_perf.cc
diff options
context:
space:
mode:
authorJames M Snell <jasnell@gmail.com>2019-01-07 11:36:35 -0800
committerjasnell <jasnell@gmail.com>2019-02-08 09:20:18 -0800
commitbcdd228f90b3e9e428b584814e7d52627616456a (patch)
treeeed1b405a1fd7e2f78bbf10e82d65c57d2c29105 /src/node_perf.cc
parent679c23f2ae1e62443f8d90e653824007ce174139 (diff)
downloadandroid-node-v8-bcdd228f90b3e9e428b584814e7d52627616456a.tar.gz
android-node-v8-bcdd228f90b3e9e428b584814e7d52627616456a.tar.bz2
android-node-v8-bcdd228f90b3e9e428b584814e7d52627616456a.zip
perf_hooks: implement histogram based api
Add a sampling-based event loop delay monitor. ```js const { monitorEventLoopDelay } = require('perf_hooks'); const h = monitorEventLoopDelay(); h.enable(); h.disable(); console.log(h.percentiles); console.log(h.min); console.log(h.max); console.log(h.mean); console.log(h.stddev); console.log(h.percentile(50)); ``` PR-URL: https://github.com/nodejs/node/pull/25378 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Richard Lau <riclau@uk.ibm.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Diffstat (limited to 'src/node_perf.cc')
-rw-r--r--src/node_perf.cc186
1 files changed, 186 insertions, 0 deletions
diff --git a/src/node_perf.cc b/src/node_perf.cc
index 33dd1d2051..b9c0183a83 100644
--- a/src/node_perf.cc
+++ b/src/node_perf.cc
@@ -1,5 +1,10 @@
+#include "aliased_buffer.h"
#include "node_internals.h"
#include "node_perf.h"
+#include "node_buffer.h"
+#include "node_process.h"
+
+#include <cinttypes>
#ifdef __POSIX__
#include <sys/time.h> // gettimeofday
@@ -20,6 +25,7 @@ using v8::HandleScope;
using v8::Integer;
using v8::Isolate;
using v8::Local;
+using v8::Map;
using v8::MaybeLocal;
using v8::Name;
using v8::NewStringType;
@@ -387,6 +393,168 @@ void Timerify(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(wrap);
}
+// Event Loop Timing Histogram
+namespace {
+static void ELDHistogramMin(const FunctionCallbackInfo<Value>& args) {
+ ELDHistogram* histogram;
+ ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
+ double value = static_cast<double>(histogram->Min());
+ args.GetReturnValue().Set(value);
+}
+
+static void ELDHistogramMax(const FunctionCallbackInfo<Value>& args) {
+ ELDHistogram* histogram;
+ ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
+ double value = static_cast<double>(histogram->Max());
+ args.GetReturnValue().Set(value);
+}
+
+static void ELDHistogramMean(const FunctionCallbackInfo<Value>& args) {
+ ELDHistogram* histogram;
+ ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
+ args.GetReturnValue().Set(histogram->Mean());
+}
+
+static void ELDHistogramExceeds(const FunctionCallbackInfo<Value>& args) {
+ ELDHistogram* histogram;
+ ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
+ double value = static_cast<double>(histogram->Exceeds());
+ args.GetReturnValue().Set(value);
+}
+
+static void ELDHistogramStddev(const FunctionCallbackInfo<Value>& args) {
+ ELDHistogram* histogram;
+ ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
+ args.GetReturnValue().Set(histogram->Stddev());
+}
+
+static void ELDHistogramPercentile(const FunctionCallbackInfo<Value>& args) {
+ ELDHistogram* histogram;
+ ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
+ CHECK(args[0]->IsNumber());
+ double percentile = args[0].As<Number>()->Value();
+ args.GetReturnValue().Set(histogram->Percentile(percentile));
+}
+
+static void ELDHistogramPercentiles(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+ ELDHistogram* histogram;
+ ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
+ CHECK(args[0]->IsMap());
+ Local<Map> map = args[0].As<Map>();
+ histogram->Percentiles([&](double key, double value) {
+ map->Set(env->context(),
+ Number::New(env->isolate(), key),
+ Number::New(env->isolate(), value)).IsEmpty();
+ });
+}
+
+static void ELDHistogramEnable(const FunctionCallbackInfo<Value>& args) {
+ ELDHistogram* histogram;
+ ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
+ args.GetReturnValue().Set(histogram->Enable());
+}
+
+static void ELDHistogramDisable(const FunctionCallbackInfo<Value>& args) {
+ ELDHistogram* histogram;
+ ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
+ args.GetReturnValue().Set(histogram->Disable());
+}
+
+static void ELDHistogramReset(const FunctionCallbackInfo<Value>& args) {
+ ELDHistogram* histogram;
+ ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
+ histogram->ResetState();
+}
+
+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);
+ new ELDHistogram(env, args.This(), resolution);
+}
+} // namespace
+
+ELDHistogram::ELDHistogram(
+ Environment* env,
+ Local<Object> wrap,
+ int32_t resolution) : BaseObject(env, wrap),
+ Histogram(1, 3.6e12),
+ resolution_(resolution) {
+ MakeWeak();
+ timer_ = new uv_timer_t();
+ uv_timer_init(env->event_loop(), timer_);
+ timer_->data = this;
+}
+
+void ELDHistogram::CloseTimer() {
+ if (timer_ == nullptr)
+ return;
+
+ env()->CloseHandle(timer_, [](uv_timer_t* handle) { delete handle; });
+ timer_ = nullptr;
+}
+
+ELDHistogram::~ELDHistogram() {
+ Disable();
+ CloseTimer();
+}
+
+void ELDHistogramDelayInterval(uv_timer_t* req) {
+ ELDHistogram* histogram =
+ reinterpret_cast<ELDHistogram*>(req->data);
+ 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());
+}
+
+bool ELDHistogram::RecordDelta() {
+ uint64_t time = uv_hrtime();
+ bool ret = true;
+ if (prev_ > 0) {
+ int64_t delta = time - prev_;
+ if (delta > 0) {
+ ret = Record(delta);
+ TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
+ "delay", delta);
+ if (!ret) {
+ if (exceeds_ < 0xFFFFFFFF)
+ exceeds_++;
+ ProcessEmitWarning(
+ env(),
+ "Event loop delay exceeded 1 hour: %" PRId64 " nanoseconds",
+ delta);
+ }
+ }
+ }
+ prev_ = time;
+ return ret;
+}
+
+bool ELDHistogram::Enable() {
+ if (enabled_) return false;
+ enabled_ = true;
+ uv_timer_start(timer_,
+ ELDHistogramDelayInterval,
+ resolution_,
+ resolution_);
+ uv_unref(reinterpret_cast<uv_handle_t*>(timer_));
+ return true;
+}
+
+bool ELDHistogram::Disable() {
+ if (!enabled_) return false;
+ enabled_ = false;
+ uv_timer_stop(timer_);
+ return true;
+}
void Initialize(Local<Object> target,
Local<Value> unused,
@@ -456,6 +624,24 @@ void Initialize(Local<Object> target,
env->constants_string(),
constants,
attr).ToChecked();
+
+ Local<String> eldh_classname = FIXED_ONE_BYTE_STRING(isolate, "ELDHistogram");
+ Local<FunctionTemplate> eldh =
+ env->NewFunctionTemplate(ELDHistogramNew);
+ eldh->SetClassName(eldh_classname);
+ eldh->InstanceTemplate()->SetInternalFieldCount(1);
+ env->SetProtoMethod(eldh, "exceeds", ELDHistogramExceeds);
+ env->SetProtoMethod(eldh, "min", ELDHistogramMin);
+ env->SetProtoMethod(eldh, "max", ELDHistogramMax);
+ env->SetProtoMethod(eldh, "mean", ELDHistogramMean);
+ env->SetProtoMethod(eldh, "stddev", ELDHistogramStddev);
+ env->SetProtoMethod(eldh, "percentile", ELDHistogramPercentile);
+ env->SetProtoMethod(eldh, "percentiles", ELDHistogramPercentiles);
+ env->SetProtoMethod(eldh, "enable", ELDHistogramEnable);
+ env->SetProtoMethod(eldh, "disable", ELDHistogramDisable);
+ env->SetProtoMethod(eldh, "reset", ELDHistogramReset);
+ target->Set(context, eldh_classname,
+ eldh->GetFunction(env->context()).ToLocalChecked()).FromJust();
}
} // namespace performance