process: improve process.hrtime
* Add benchmarks for diffing a previous result * Improvements to the documentation, including type annotation * Update the outdated comments in src/node.cc, improve comments in lib/internal/process.js * Check the argument is an Array Tuple with length 2 PR-URL: https://github.com/nodejs/node/pull/10764 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Brian White <mscdex@mscdex.net>
This commit is contained in:
parent
9fcd842279
commit
a647d82f83
@ -1,18 +1,32 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
const bench = common.createBenchmark(main, {
|
const bench = common.createBenchmark(main, {
|
||||||
n: [1e6]
|
n: [1e6],
|
||||||
|
type: ['raw', 'diff']
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function main(conf) {
|
function main(conf) {
|
||||||
const n = conf.n >>> 0;
|
const n = conf.n | 0;
|
||||||
|
const hrtime = process.hrtime;
|
||||||
|
var noDead = hrtime();
|
||||||
|
var i;
|
||||||
|
|
||||||
|
if (conf.type === 'raw') {
|
||||||
bench.start();
|
bench.start();
|
||||||
for (var i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
process.hrtime();
|
noDead = hrtime();
|
||||||
|
}
|
||||||
|
bench.end(n);
|
||||||
|
} else {
|
||||||
|
bench.start();
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
noDead = hrtime(noDead);
|
||||||
}
|
}
|
||||||
bench.end(n);
|
bench.end(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert.ok(Array.isArray(noDead));
|
||||||
|
}
|
||||||
|
@ -1016,18 +1016,25 @@ Android)
|
|||||||
added: v0.7.6
|
added: v0.7.6
|
||||||
-->
|
-->
|
||||||
|
|
||||||
The `process.hrtime()` method returns the current high-resolution real time in a
|
* `time` {Array} The result of a previous call to `process.hrtime()`
|
||||||
`[seconds, nanoseconds]` tuple Array. `time` is an optional parameter that must
|
* Returns: {Array}
|
||||||
be the result of a previous `process.hrtime()` call (and therefore, a real time
|
|
||||||
in a `[seconds, nanoseconds]` tuple Array containing a previous time) to diff
|
|
||||||
with the current time. These times are relative to an arbitrary time in the
|
|
||||||
past, and not related to the time of day and therefore not subject to clock
|
|
||||||
drift. The primary use is for measuring performance between intervals.
|
|
||||||
|
|
||||||
Passing in the result of a previous call to `process.hrtime()` is useful for
|
The `process.hrtime()` method returns the current high-resolution real time
|
||||||
calculating an amount of time passed between calls:
|
in a `[seconds, nanoseconds]` tuple Array, where `nanoseconds` is the
|
||||||
|
remaining part of the real time that can't be represented in second precision.
|
||||||
|
|
||||||
|
`time` is an optional parameter that must be the result of a previous
|
||||||
|
`process.hrtime()` call to diff with the current time. If the parameter
|
||||||
|
passed in is not a tuple Array, a `TypeError` will be thrown. Passing in a
|
||||||
|
user-defined array instead of the result of a previous call to
|
||||||
|
`process.hrtime()` will lead to undefined behavior.
|
||||||
|
|
||||||
|
These times are relative to an arbitrary time in the
|
||||||
|
past, and not related to the time of day and therefore not subject to clock
|
||||||
|
drift. The primary use is for measuring performance between intervals:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
const NS_PER_SEC = 1e9;
|
||||||
var time = process.hrtime();
|
var time = process.hrtime();
|
||||||
// [ 1800216, 25 ]
|
// [ 1800216, 25 ]
|
||||||
|
|
||||||
@ -1035,14 +1042,11 @@ setTimeout(() => {
|
|||||||
var diff = process.hrtime(time);
|
var diff = process.hrtime(time);
|
||||||
// [ 1, 552 ]
|
// [ 1, 552 ]
|
||||||
|
|
||||||
console.log(`Benchmark took ${diff[0] * 1e9 + diff[1]} nanoseconds`);
|
console.log(`Benchmark took ${diff[0] * NS_PER_SEC + diff[1]} nanoseconds`);
|
||||||
// benchmark took 1000000527 nanoseconds
|
// benchmark took 1000000527 nanoseconds
|
||||||
}, 1000);
|
}, 1000);
|
||||||
```
|
```
|
||||||
|
|
||||||
Constructing an array by some method other than calling `process.hrtime()` and
|
|
||||||
passing the result to process.hrtime() will result in undefined behavior.
|
|
||||||
|
|
||||||
|
|
||||||
## process.initgroups(user, extra_group)
|
## process.initgroups(user, extra_group)
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
|
@ -73,19 +73,22 @@ function setup_cpuUsage() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The 3 entries filled in by the original process.hrtime contains
|
||||||
|
// the upper/lower 32 bits of the second part of the value,
|
||||||
|
// and the renamining nanoseconds of the value.
|
||||||
function setup_hrtime() {
|
function setup_hrtime() {
|
||||||
const _hrtime = process.hrtime;
|
const _hrtime = process.hrtime;
|
||||||
const hrValues = new Uint32Array(3);
|
const hrValues = new Uint32Array(3);
|
||||||
|
|
||||||
process.hrtime = function hrtime(ar) {
|
process.hrtime = function hrtime(time) {
|
||||||
_hrtime(hrValues);
|
_hrtime(hrValues);
|
||||||
|
|
||||||
if (typeof ar !== 'undefined') {
|
if (time !== undefined) {
|
||||||
if (Array.isArray(ar)) {
|
if (Array.isArray(time) && time.length === 2) {
|
||||||
const sec = (hrValues[0] * 0x100000000 + hrValues[1]) - ar[0];
|
const sec = (hrValues[0] * 0x100000000 + hrValues[1]) - time[0];
|
||||||
const nsec = hrValues[2] - ar[1];
|
const nsec = hrValues[2] - time[1];
|
||||||
return [nsec < 0 ? sec - 1 : sec, nsec < 0 ? nsec + 1e9 : nsec];
|
const needsBorrow = nsec < 0;
|
||||||
|
return [needsBorrow ? sec - 1 : sec, needsBorrow ? nsec + 1e9 : nsec];
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new TypeError('process.hrtime() only accepts an Array tuple');
|
throw new TypeError('process.hrtime() only accepts an Array tuple');
|
||||||
@ -98,7 +101,6 @@ function setup_hrtime() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function setupConfig(_source) {
|
function setupConfig(_source) {
|
||||||
// NativeModule._source
|
// NativeModule._source
|
||||||
// used for `process.config`, but not a real module
|
// used for `process.config`, but not a real module
|
||||||
|
12
src/node.cc
12
src/node.cc
@ -2274,18 +2274,18 @@ void Kill(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
// Hrtime exposes libuv's uv_hrtime() high-resolution timer.
|
// Hrtime exposes libuv's uv_hrtime() high-resolution timer.
|
||||||
// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds,
|
// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds,
|
||||||
// so this function instead returns an Array with 2 entries representing seconds
|
// so this function instead fills in an Uint32Array with 3 entries,
|
||||||
// and nanoseconds, to avoid any integer overflow possibility.
|
// to avoid any integer overflow possibility.
|
||||||
// Pass in an Array from a previous hrtime() call to instead get a time diff.
|
// The first two entries contain the second part of the value
|
||||||
|
// broken into the upper/lower 32 bits to be converted back in JS,
|
||||||
|
// because there is no Uint64Array in JS.
|
||||||
|
// The third entry contains the remaining nanosecond part of the value.
|
||||||
void Hrtime(const FunctionCallbackInfo<Value>& args) {
|
void Hrtime(const FunctionCallbackInfo<Value>& args) {
|
||||||
uint64_t t = uv_hrtime();
|
uint64_t t = uv_hrtime();
|
||||||
|
|
||||||
Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer();
|
Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer();
|
||||||
uint32_t* fields = static_cast<uint32_t*>(ab->GetContents().Data());
|
uint32_t* fields = static_cast<uint32_t*>(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[0] = (t / NANOS_PER_SEC) >> 32;
|
||||||
fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
|
fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
|
||||||
fields[2] = t % NANOS_PER_SEC;
|
fields[2] = t % NANOS_PER_SEC;
|
||||||
|
@ -15,14 +15,21 @@ validateTuple(process.hrtime(tuple));
|
|||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
process.hrtime(1);
|
process.hrtime(1);
|
||||||
}, /^TypeError: process.hrtime\(\) only accepts an Array tuple$/);
|
}, /^TypeError: process.hrtime\(\) only accepts an Array tuple$/);
|
||||||
|
assert.throws(() => {
|
||||||
|
process.hrtime([]);
|
||||||
|
}, /^TypeError: process.hrtime\(\) only accepts an Array tuple$/);
|
||||||
|
assert.throws(() => {
|
||||||
|
process.hrtime([1]);
|
||||||
|
}, /^TypeError: process.hrtime\(\) only accepts an Array tuple$/);
|
||||||
|
assert.throws(() => {
|
||||||
|
process.hrtime([1, 2, 3]);
|
||||||
|
}, /^TypeError: process.hrtime\(\) only accepts an Array tuple$/);
|
||||||
|
|
||||||
function validateTuple(tuple) {
|
function validateTuple(tuple) {
|
||||||
assert(Array.isArray(tuple));
|
assert(Array.isArray(tuple));
|
||||||
assert.strictEqual(tuple.length, 2);
|
assert.strictEqual(tuple.length, 2);
|
||||||
tuple.forEach((v) => {
|
assert(Number.isInteger(tuple[0]));
|
||||||
assert.strictEqual(typeof v, 'number');
|
assert(Number.isInteger(tuple[1]));
|
||||||
assert.strictEqual(isFinite(v), true);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const diff = process.hrtime([0, 1e9 - 1]);
|
const diff = process.hrtime([0, 1e9 - 1]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user