From 89f056bdf323a77a48997f14196b41ddf76f90b1 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Wed, 11 Nov 2015 00:15:15 -0700 Subject: [PATCH] node: improve performance of hrtime() process.hrtime() was performing too many operations in C++ that could be done faster in JS. Move those operations over by creating a length 4 Uint32Array and perform bitwise operations on the seconds so that it was unnecessary for the native API to do any object creation or set any fields. This has improved performance from ~350 ns/op to ~65 ns/op. Light benchmark included to demonstrate the performance change. PR-URL: https://github.com/nodejs/node/pull/3780 Reviewed-By: Fedor Indutny --- benchmark/misc/bench-hrtime.js | 18 ++++++++++++++++++ src/node.cc | 25 +++++++++++++------------ src/node.js | 15 +++++++++++++++ 3 files changed, 46 insertions(+), 12 deletions(-) create mode 100644 benchmark/misc/bench-hrtime.js diff --git a/benchmark/misc/bench-hrtime.js b/benchmark/misc/bench-hrtime.js new file mode 100644 index 00000000000000..661dff43b0103c --- /dev/null +++ b/benchmark/misc/bench-hrtime.js @@ -0,0 +1,18 @@ +'use strict'; + +const common = require('../common'); + +const bench = common.createBenchmark(main, { + n: [1e6] +}); + + +function main(conf) { + const n = conf.n >>> 0; + + bench.start(); + for (var i = 0; i < n; i++) { + process.hrtime(); + } + bench.end(n); +} diff --git a/src/node.cc b/src/node.cc index be80ab3124d716..e03d541f3ceb32 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2132,22 +2132,23 @@ void Hrtime(const FunctionCallbackInfo& args) { uint64_t t = uv_hrtime(); - if (args.Length() > 0) { - // return a time diff tuple - if (!args[0]->IsArray()) { + if (!args[1]->IsUndefined()) { + if (!args[1]->IsArray()) { return env->ThrowTypeError( - "process.hrtime() only accepts an Array tuple."); + "process.hrtime() only accepts an Array tuple"); } - Local inArray = Local::Cast(args[0]); - uint64_t seconds = inArray->Get(0)->Uint32Value(); - uint64_t nanos = inArray->Get(1)->Uint32Value(); - t -= (seconds * NANOS_PER_SEC) + nanos; + args.GetReturnValue().Set(true); } - Local tuple = Array::New(env->isolate(), 2); - tuple->Set(0, Integer::NewFromUnsigned(env->isolate(), t / NANOS_PER_SEC)); - tuple->Set(1, Integer::NewFromUnsigned(env->isolate(), t % NANOS_PER_SEC)); - args.GetReturnValue().Set(tuple); + Local ab = args[0].As()->Buffer(); + uint32_t* fields = static_cast(ab->GetContents().Data()); + + // These three indices will contain the values for the hrtime tuple. The + // seconds value is broken into the upper/lower 32 bits and stored in two + // uint32 fields to be converted back in JS. + fields[0] = (t / NANOS_PER_SEC) >> 32; + fields[1] = (t / NANOS_PER_SEC) & 0xffffffff; + fields[2] = t % NANOS_PER_SEC; } extern "C" void node_module_register(void* m) { diff --git a/src/node.js b/src/node.js index 8d77adc27c4102..f91b20ef60d28b 100644 --- a/src/node.js +++ b/src/node.js @@ -181,12 +181,27 @@ } startup.setupProcessObject = function() { + const _hrtime = process.hrtime; + const hrValues = new Uint32Array(3); + process._setupProcessObject(pushValueToArray); function pushValueToArray() { for (var i = 0; i < arguments.length; i++) this.push(arguments[i]); } + + process.hrtime = function hrtime(ar) { + const ret = [0, 0]; + if (_hrtime(hrValues, ar)) { + ret[0] = (hrValues[0] * 0x100000000 + hrValues[1]) - ar[0]; + ret[1] = hrValues[2] - ar[1]; + } else { + ret[0] = hrValues[0] * 0x100000000 + hrValues[1]; + ret[1] = hrValues[2]; + } + return ret; + }; }; startup.globalVariables = function() {