Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 89f056b

Browse files
trevnorrisFishrock123
authored andcommittedJan 6, 2016
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: nodejs#3780 Reviewed-By: Fedor Indutny <[email protected]>
1 parent c8fc217 commit 89f056b

File tree

3 files changed

+46
-12
lines changed

3 files changed

+46
-12
lines changed
 

‎benchmark/misc/bench-hrtime.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
5+
const bench = common.createBenchmark(main, {
6+
n: [1e6]
7+
});
8+
9+
10+
function main(conf) {
11+
const n = conf.n >>> 0;
12+
13+
bench.start();
14+
for (var i = 0; i < n; i++) {
15+
process.hrtime();
16+
}
17+
bench.end(n);
18+
}

‎src/node.cc

+13-12
Original file line numberDiff line numberDiff line change
@@ -2132,22 +2132,23 @@ void Hrtime(const FunctionCallbackInfo<Value>& args) {
21322132

21332133
uint64_t t = uv_hrtime();
21342134

2135-
if (args.Length() > 0) {
2136-
// return a time diff tuple
2137-
if (!args[0]->IsArray()) {
2135+
if (!args[1]->IsUndefined()) {
2136+
if (!args[1]->IsArray()) {
21382137
return env->ThrowTypeError(
2139-
"process.hrtime() only accepts an Array tuple.");
2138+
"process.hrtime() only accepts an Array tuple");
21402139
}
2141-
Local<Array> inArray = Local<Array>::Cast(args[0]);
2142-
uint64_t seconds = inArray->Get(0)->Uint32Value();
2143-
uint64_t nanos = inArray->Get(1)->Uint32Value();
2144-
t -= (seconds * NANOS_PER_SEC) + nanos;
2140+
args.GetReturnValue().Set(true);
21452141
}
21462142

2147-
Local<Array> tuple = Array::New(env->isolate(), 2);
2148-
tuple->Set(0, Integer::NewFromUnsigned(env->isolate(), t / NANOS_PER_SEC));
2149-
tuple->Set(1, Integer::NewFromUnsigned(env->isolate(), t % NANOS_PER_SEC));
2150-
args.GetReturnValue().Set(tuple);
2143+
Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer();
2144+
uint32_t* fields = static_cast<uint32_t*>(ab->GetContents().Data());
2145+
2146+
// These three indices will contain the values for the hrtime tuple. The
2147+
// seconds value is broken into the upper/lower 32 bits and stored in two
2148+
// uint32 fields to be converted back in JS.
2149+
fields[0] = (t / NANOS_PER_SEC) >> 32;
2150+
fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
2151+
fields[2] = t % NANOS_PER_SEC;
21512152
}
21522153

21532154
extern "C" void node_module_register(void* m) {

‎src/node.js

+15
Original file line numberDiff line numberDiff line change
@@ -181,12 +181,27 @@
181181
}
182182

183183
startup.setupProcessObject = function() {
184+
const _hrtime = process.hrtime;
185+
const hrValues = new Uint32Array(3);
186+
184187
process._setupProcessObject(pushValueToArray);
185188

186189
function pushValueToArray() {
187190
for (var i = 0; i < arguments.length; i++)
188191
this.push(arguments[i]);
189192
}
193+
194+
process.hrtime = function hrtime(ar) {
195+
const ret = [0, 0];
196+
if (_hrtime(hrValues, ar)) {
197+
ret[0] = (hrValues[0] * 0x100000000 + hrValues[1]) - ar[0];
198+
ret[1] = hrValues[2] - ar[1];
199+
} else {
200+
ret[0] = hrValues[0] * 0x100000000 + hrValues[1];
201+
ret[1] = hrValues[2];
202+
}
203+
return ret;
204+
};
190205
};
191206

192207
startup.globalVariables = function() {

0 commit comments

Comments
 (0)
Please sign in to comment.