Skip to content

Commit a986158

Browse files
committed
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: #18486 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Jeremiah Senkpiel <[email protected]>
1 parent 9b8e1c2 commit a986158

File tree

2 files changed

+16
-10
lines changed

2 files changed

+16
-10
lines changed

lib/timers.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,11 @@ function TimersList(msecs, unrefed) {
223223

224224
// adds listOnTimeout to the C++ object prototype, as
225225
// V8 would not inline it otherwise.
226-
TimerWrap.prototype[kOnTimeout] = function listOnTimeout() {
226+
TimerWrap.prototype[kOnTimeout] = function listOnTimeout(now) {
227227
var list = this._list;
228228
var msecs = list.msecs;
229229

230230
debug('timeout callback %d', msecs);
231-
232-
var now = TimerWrap.now();
233231
debug('now: %d', now);
234232

235233
var diff, timer;
@@ -430,11 +428,12 @@ setTimeout[internalUtil.promisify.custom] = function(after, value) {
430428
exports.setTimeout = setTimeout;
431429

432430

433-
function ontimeout(timer) {
431+
function ontimeout(timer, start) {
434432
var args = timer._timerArgs;
435433
if (typeof timer._onTimeout !== 'function')
436434
return promiseResolve(timer._onTimeout, args[0]);
437-
const start = TimerWrap.now();
435+
if (start === undefined && timer._repeat)
436+
start = TimerWrap.now();
438437
if (!args)
439438
timer._onTimeout();
440439
else
@@ -518,11 +517,11 @@ exports.clearInterval = function(timer) {
518517
};
519518

520519

521-
function unrefdHandle() {
520+
function unrefdHandle(now) {
522521
try {
523522
// Don't attempt to call the callback if it is not a function.
524523
if (typeof this.owner._onTimeout === 'function') {
525-
ontimeout(this.owner);
524+
ontimeout(this.owner, now);
526525
}
527526
} finally {
528527
// Make sure we clean up if the callback is no longer a function

src/timer_wrap.cc

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ using v8::FunctionTemplate;
3737
using v8::HandleScope;
3838
using v8::Integer;
3939
using v8::Local;
40+
using v8::Number;
4041
using v8::Object;
4142
using v8::String;
4243
using v8::Value;
@@ -139,8 +140,10 @@ class TimerWrap : public HandleWrap {
139140
HandleScope handle_scope(env->isolate());
140141
Context::Scope context_scope(env->context());
141142
Local<Value> ret;
143+
Local<Value> args[1];
142144
do {
143-
ret = wrap->MakeCallback(kOnTimeout, 0, nullptr).ToLocalChecked();
145+
args[0] = GetNow(env);
146+
ret = wrap->MakeCallback(kOnTimeout, 1, args).ToLocalChecked();
144147
} while (ret->IsUndefined() &&
145148
!env->tick_info()->has_thrown() &&
146149
wrap->object()->Get(env->context(),
@@ -150,14 +153,18 @@ class TimerWrap : public HandleWrap {
150153

151154
static void Now(const FunctionCallbackInfo<Value>& args) {
152155
Environment* env = Environment::GetCurrent(args);
156+
args.GetReturnValue().Set(GetNow(env));
157+
}
158+
159+
static Local<Value> GetNow(Environment* env) {
153160
uv_update_time(env->event_loop());
154161
uint64_t now = uv_now(env->event_loop());
155162
CHECK(now >= env->timer_base());
156163
now -= env->timer_base();
157164
if (now <= 0xfffffff)
158-
args.GetReturnValue().Set(static_cast<uint32_t>(now));
165+
return Integer::New(env->isolate(), static_cast<uint32_t>(now));
159166
else
160-
args.GetReturnValue().Set(static_cast<double>(now));
167+
return Number::New(env->isolate(), static_cast<double>(now));
161168
}
162169

163170
uv_timer_t handle_;

0 commit comments

Comments
 (0)