From b5315159bfa8d3cd1da5780fdd32dbd87c7f9e14 Mon Sep 17 00:00:00 2001 From: Anatoli Papirovski Date: Wed, 31 Jan 2018 10:34:31 -0500 Subject: [PATCH] timers: re-enter C++ less frequently Pass in Timer.now() as an argument of kOnTimeout instead of always re-entering C++ to get it. Also don't constantly call Timer.now() from ontimeout, even when it isn't needed. Improves performance on our pooled benchmark by upwards of 40%. PR-URL: https://github.com/nodejs/node/pull/18486 Reviewed-By: James M Snell Reviewed-By: Ruben Bridgewater Reviewed-By: Jeremiah Senkpiel --- lib/timers.js | 13 ++++++------- src/timer_wrap.cc | 13 ++++++++++--- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/timers.js b/lib/timers.js index a91de76d7f95bd..83affee7d83e69 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -223,13 +223,11 @@ function TimersList(msecs, unrefed) { // adds listOnTimeout to the C++ object prototype, as // V8 would not inline it otherwise. -TimerWrap.prototype[kOnTimeout] = function listOnTimeout() { +TimerWrap.prototype[kOnTimeout] = function listOnTimeout(now) { var list = this._list; var msecs = list.msecs; debug('timeout callback %d', msecs); - - var now = TimerWrap.now(); debug('now: %d', now); var diff, timer; @@ -430,11 +428,12 @@ setTimeout[internalUtil.promisify.custom] = function(after, value) { exports.setTimeout = setTimeout; -function ontimeout(timer) { +function ontimeout(timer, start) { var args = timer._timerArgs; if (typeof timer._onTimeout !== 'function') return promiseResolve(timer._onTimeout, args[0]); - const start = TimerWrap.now(); + if (start === undefined && timer._repeat) + start = TimerWrap.now(); if (!args) timer._onTimeout(); else @@ -518,11 +517,11 @@ exports.clearInterval = function(timer) { }; -function unrefdHandle() { +function unrefdHandle(now) { try { // Don't attempt to call the callback if it is not a function. if (typeof this.owner._onTimeout === 'function') { - ontimeout(this.owner); + ontimeout(this.owner, now); } } finally { // Make sure we clean up if the callback is no longer a function diff --git a/src/timer_wrap.cc b/src/timer_wrap.cc index 8b596eb4352358..f1b423d3669ed5 100644 --- a/src/timer_wrap.cc +++ b/src/timer_wrap.cc @@ -37,6 +37,7 @@ using v8::FunctionTemplate; using v8::HandleScope; using v8::Integer; using v8::Local; +using v8::Number; using v8::Object; using v8::String; using v8::Value; @@ -139,8 +140,10 @@ class TimerWrap : public HandleWrap { HandleScope handle_scope(env->isolate()); Context::Scope context_scope(env->context()); Local ret; + Local args[1]; do { - ret = wrap->MakeCallback(kOnTimeout, 0, nullptr).ToLocalChecked(); + args[0] = GetNow(env); + ret = wrap->MakeCallback(kOnTimeout, 1, args).ToLocalChecked(); } while (ret->IsUndefined() && !env->tick_info()->has_thrown() && wrap->object()->Get(env->context(), @@ -150,14 +153,18 @@ class TimerWrap : public HandleWrap { static void Now(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); + args.GetReturnValue().Set(GetNow(env)); + } + + static Local GetNow(Environment* env) { uv_update_time(env->event_loop()); uint64_t now = uv_now(env->event_loop()); CHECK(now >= env->timer_base()); now -= env->timer_base(); if (now <= 0xfffffff) - args.GetReturnValue().Set(static_cast(now)); + return Integer::New(env->isolate(), static_cast(now)); else - args.GetReturnValue().Set(static_cast(now)); + return Number::New(env->isolate(), static_cast(now)); } uv_timer_t handle_;