mirror of https://github.com/nodejs/node.git
perf_hooks: multiple fixes for Histogram
* The createHistogram(options) options weren't actually implemented * Add a new count property that tracks the number of samples * Adds BigInt options for relevant properties * Adds add(other) method for RecordableHistogram * Cleans up and expands tests * Eliminates unnecessary ELDHistogram native class * Improve/Simplify histogram transfer impl Signed-off-by: James M Snell <jasnell@gmail.com> perf_hooks: simplify Histogram constructor options Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/41153 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
665b404e65
commit
23637e9a3b
|
@ -817,10 +817,11 @@ added:
|
||||||
-->
|
-->
|
||||||
|
|
||||||
* `options` {Object}
|
* `options` {Object}
|
||||||
* `min` {number|bigint} The minimum recordable value. Must be an integer
|
* `lowest` {number|bigint} The lowest discernible value. Must be an integer
|
||||||
value greater than 0. **Default:** `1`.
|
value greater than 0. **Default:** `1`.
|
||||||
* `max` {number|bigint} The maximum recordable value. Must be an integer
|
* `highest` {number|bigint} The highest recordable value. Must be an integer
|
||||||
value greater than `min`. **Default:** `Number.MAX_SAFE_INTEGER`.
|
value that is equal to or greater than two times `min`.
|
||||||
|
**Default:** `Number.MAX_SAFE_INTEGER`.
|
||||||
* `figures` {number} The number of accuracy digits. Must be a number between
|
* `figures` {number} The number of accuracy digits. Must be a number between
|
||||||
`1` and `5`. **Default:** `3`.
|
`1` and `5`. **Default:** `3`.
|
||||||
* Returns {RecordableHistogram}
|
* Returns {RecordableHistogram}
|
||||||
|
@ -870,6 +871,26 @@ console.log(h.percentile(99));
|
||||||
added: v11.10.0
|
added: v11.10.0
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
### `histogram.count`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* {number}
|
||||||
|
|
||||||
|
The number of samples recorded by the histogram.
|
||||||
|
|
||||||
|
### `histogram.countBigInt`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* {bigint}
|
||||||
|
|
||||||
|
The number of samples recorded by the histogram.
|
||||||
|
|
||||||
### `histogram.exceeds`
|
### `histogram.exceeds`
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
|
@ -881,6 +902,17 @@ added: v11.10.0
|
||||||
The number of times the event loop delay exceeded the maximum 1 hour event
|
The number of times the event loop delay exceeded the maximum 1 hour event
|
||||||
loop delay threshold.
|
loop delay threshold.
|
||||||
|
|
||||||
|
### `histogram.exceedsBigInt`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* {bigint}
|
||||||
|
|
||||||
|
The number of times the event loop delay exceeded the maximum 1 hour event
|
||||||
|
loop delay threshold.
|
||||||
|
|
||||||
### `histogram.max`
|
### `histogram.max`
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
|
@ -891,6 +923,16 @@ added: v11.10.0
|
||||||
|
|
||||||
The maximum recorded event loop delay.
|
The maximum recorded event loop delay.
|
||||||
|
|
||||||
|
### `histogram.maxBigInt`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* {bigint}
|
||||||
|
|
||||||
|
The maximum recorded event loop delay.
|
||||||
|
|
||||||
### `histogram.mean`
|
### `histogram.mean`
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
|
@ -911,6 +953,16 @@ added: v11.10.0
|
||||||
|
|
||||||
The minimum recorded event loop delay.
|
The minimum recorded event loop delay.
|
||||||
|
|
||||||
|
### `histogram.minBigInt`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* {bigint}
|
||||||
|
|
||||||
|
The minimum recorded event loop delay.
|
||||||
|
|
||||||
### `histogram.percentile(percentile)`
|
### `histogram.percentile(percentile)`
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
|
@ -922,6 +974,17 @@ added: v11.10.0
|
||||||
|
|
||||||
Returns the value at the given percentile.
|
Returns the value at the given percentile.
|
||||||
|
|
||||||
|
### `histogram.percentileBigInt(percentile)`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* `percentile` {number} A percentile value in the range (0, 100).
|
||||||
|
* Returns: {bigint}
|
||||||
|
|
||||||
|
Returns the value at the given percentile.
|
||||||
|
|
||||||
### `histogram.percentiles`
|
### `histogram.percentiles`
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
|
@ -932,6 +995,16 @@ added: v11.10.0
|
||||||
|
|
||||||
Returns a `Map` object detailing the accumulated percentile distribution.
|
Returns a `Map` object detailing the accumulated percentile distribution.
|
||||||
|
|
||||||
|
### `histogram.percentilesBigInt`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* {Map}
|
||||||
|
|
||||||
|
Returns a `Map` object detailing the accumulated percentile distribution.
|
||||||
|
|
||||||
### `histogram.reset()`
|
### `histogram.reset()`
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
|
@ -990,6 +1063,16 @@ added:
|
||||||
- v14.18.0
|
- v14.18.0
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
### `histogram.add(other)`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* `other` {RecordableHistogram}
|
||||||
|
|
||||||
|
Adds the values from `other` to this histogram.
|
||||||
|
|
||||||
### `histogram.record(val)`
|
### `histogram.record(val)`
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
MapPrototypeEntries,
|
||||||
NumberIsNaN,
|
NumberIsNaN,
|
||||||
NumberIsInteger,
|
NumberIsInteger,
|
||||||
NumberMAX_SAFE_INTEGER,
|
NumberMAX_SAFE_INTEGER,
|
||||||
ObjectSetPrototypeOf,
|
ObjectFromEntries,
|
||||||
|
ReflectConstruct,
|
||||||
SafeMap,
|
SafeMap,
|
||||||
Symbol,
|
Symbol,
|
||||||
} = primordials;
|
} = primordials;
|
||||||
|
@ -24,33 +26,36 @@ const {
|
||||||
ERR_ILLEGAL_CONSTRUCTOR,
|
ERR_ILLEGAL_CONSTRUCTOR,
|
||||||
ERR_INVALID_ARG_VALUE,
|
ERR_INVALID_ARG_VALUE,
|
||||||
ERR_INVALID_ARG_TYPE,
|
ERR_INVALID_ARG_TYPE,
|
||||||
|
ERR_INVALID_THIS,
|
||||||
ERR_OUT_OF_RANGE,
|
ERR_OUT_OF_RANGE,
|
||||||
},
|
},
|
||||||
} = require('internal/errors');
|
} = require('internal/errors');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
validateInteger,
|
||||||
validateNumber,
|
validateNumber,
|
||||||
|
validateObject,
|
||||||
|
validateUint32,
|
||||||
} = require('internal/validators');
|
} = require('internal/validators');
|
||||||
|
|
||||||
const kDestroy = Symbol('kDestroy');
|
const kDestroy = Symbol('kDestroy');
|
||||||
const kHandle = Symbol('kHandle');
|
const kHandle = Symbol('kHandle');
|
||||||
const kMap = Symbol('kMap');
|
const kMap = Symbol('kMap');
|
||||||
|
const kRecordable = Symbol('kRecordable');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
kClone,
|
kClone,
|
||||||
kDeserialize,
|
kDeserialize,
|
||||||
JSTransferable,
|
makeTransferable,
|
||||||
} = require('internal/worker/js_transferable');
|
} = require('internal/worker/js_transferable');
|
||||||
|
|
||||||
function isHistogram(object) {
|
function isHistogram(object) {
|
||||||
return object?.[kHandle] !== undefined;
|
return object?.[kHandle] !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Histogram extends JSTransferable {
|
class Histogram {
|
||||||
constructor(internal) {
|
constructor() {
|
||||||
super();
|
throw new ERR_ILLEGAL_CONSTRUCTOR();
|
||||||
this[kHandle] = internal;
|
|
||||||
this[kMap] = new SafeMap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[kInspect](depth, options) {
|
[kInspect](depth, options) {
|
||||||
|
@ -68,31 +73,118 @@ class Histogram extends JSTransferable {
|
||||||
mean: this.mean,
|
mean: this.mean,
|
||||||
exceeds: this.exceeds,
|
exceeds: this.exceeds,
|
||||||
stddev: this.stddev,
|
stddev: this.stddev,
|
||||||
|
count: this.count,
|
||||||
percentiles: this.percentiles,
|
percentiles: this.percentiles,
|
||||||
}, opts)}`;
|
}, opts)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @readonly
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
get count() {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
|
return this[kHandle]?.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @readonly
|
||||||
|
* @type {bigint}
|
||||||
|
*/
|
||||||
|
get countBigInt() {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
|
return this[kHandle]?.countBigInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @readonly
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
get min() {
|
get min() {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
return this[kHandle]?.min();
|
return this[kHandle]?.min();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @readonly
|
||||||
|
* @type {bigint}
|
||||||
|
*/
|
||||||
|
get minBigInt() {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
|
return this[kHandle]?.minBigInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @readonly
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
get max() {
|
get max() {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
return this[kHandle]?.max();
|
return this[kHandle]?.max();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @readonly
|
||||||
|
* @type {bigint}
|
||||||
|
*/
|
||||||
|
get maxBigInt() {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
|
return this[kHandle]?.maxBigInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @readonly
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
get mean() {
|
get mean() {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
return this[kHandle]?.mean();
|
return this[kHandle]?.mean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @readonly
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
get exceeds() {
|
get exceeds() {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
return this[kHandle]?.exceeds();
|
return this[kHandle]?.exceeds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @readonly
|
||||||
|
* @type {bigint}
|
||||||
|
*/
|
||||||
|
get exceedsBigInt() {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
|
return this[kHandle]?.exceedsBigInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @readonly
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
get stddev() {
|
get stddev() {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
return this[kHandle]?.stddev();
|
return this[kHandle]?.stddev();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} percentile
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
percentile(percentile) {
|
percentile(percentile) {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
validateNumber(percentile, 'percentile');
|
validateNumber(percentile, 'percentile');
|
||||||
|
|
||||||
if (NumberIsNaN(percentile) || percentile <= 0 || percentile > 100)
|
if (NumberIsNaN(percentile) || percentile <= 0 || percentile > 100)
|
||||||
|
@ -101,31 +193,77 @@ class Histogram extends JSTransferable {
|
||||||
return this[kHandle]?.percentile(percentile);
|
return this[kHandle]?.percentile(percentile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} percentile
|
||||||
|
* @returns {bigint}
|
||||||
|
*/
|
||||||
|
percentileBigInt(percentile) {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
|
validateNumber(percentile, 'percentile');
|
||||||
|
|
||||||
|
if (NumberIsNaN(percentile) || percentile <= 0 || percentile > 100)
|
||||||
|
throw new ERR_INVALID_ARG_VALUE.RangeError('percentile', percentile);
|
||||||
|
|
||||||
|
return this[kHandle]?.percentileBigInt(percentile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @readonly
|
||||||
|
* @type {Map<number,number>}
|
||||||
|
*/
|
||||||
get percentiles() {
|
get percentiles() {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
this[kMap].clear();
|
this[kMap].clear();
|
||||||
this[kHandle]?.percentiles(this[kMap]);
|
this[kHandle]?.percentiles(this[kMap]);
|
||||||
return this[kMap];
|
return this[kMap];
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
/**
|
||||||
this[kHandle]?.reset();
|
* @readonly
|
||||||
|
* @type {Map<number,bigint>}
|
||||||
|
*/
|
||||||
|
get percentilesBigInt() {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
|
this[kMap].clear();
|
||||||
|
this[kHandle]?.percentilesBigInt(this[kMap]);
|
||||||
|
return this[kMap];
|
||||||
}
|
}
|
||||||
|
|
||||||
[kDestroy]() {
|
/**
|
||||||
this[kHandle] = undefined;
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
reset() {
|
||||||
|
if (!isHistogram(this))
|
||||||
|
throw new ERR_INVALID_THIS('Histogram');
|
||||||
|
this[kHandle]?.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
[kClone]() {
|
[kClone]() {
|
||||||
const handle = this[kHandle];
|
const handle = this[kHandle];
|
||||||
return {
|
return {
|
||||||
data: { handle },
|
data: { handle },
|
||||||
deserializeInfo: 'internal/histogram:InternalHistogram'
|
deserializeInfo: 'internal/histogram:internalHistogram'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[kDeserialize]({ handle }) {
|
[kDeserialize]({ handle }) {
|
||||||
this[kHandle] = handle;
|
this[kHandle] = handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
count: this.count,
|
||||||
|
min: this.min,
|
||||||
|
max: this.max,
|
||||||
|
mean: this.mean,
|
||||||
|
exceeds: this.exceeds,
|
||||||
|
stddev: this.stddev,
|
||||||
|
percentiles: ObjectFromEntries(MapPrototypeEntries(this.percentiles))
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RecordableHistogram extends Histogram {
|
class RecordableHistogram extends Histogram {
|
||||||
|
@ -133,7 +271,13 @@ class RecordableHistogram extends Histogram {
|
||||||
throw new ERR_ILLEGAL_CONSTRUCTOR();
|
throw new ERR_ILLEGAL_CONSTRUCTOR();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number|bigint} val
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
record(val) {
|
record(val) {
|
||||||
|
if (this[kRecordable] === undefined)
|
||||||
|
throw new ERR_INVALID_THIS('RecordableHistogram');
|
||||||
if (typeof val === 'bigint') {
|
if (typeof val === 'bigint') {
|
||||||
this[kHandle]?.record(val);
|
this[kHandle]?.record(val);
|
||||||
return;
|
return;
|
||||||
|
@ -148,56 +292,93 @@ class RecordableHistogram extends Histogram {
|
||||||
this[kHandle]?.record(val);
|
this[kHandle]?.record(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
recordDelta() {
|
recordDelta() {
|
||||||
|
if (this[kRecordable] === undefined)
|
||||||
|
throw new ERR_INVALID_THIS('RecordableHistogram');
|
||||||
this[kHandle]?.recordDelta();
|
this[kHandle]?.recordDelta();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {RecordableHistogram} other
|
||||||
|
*/
|
||||||
|
add(other) {
|
||||||
|
if (this[kRecordable] === undefined)
|
||||||
|
throw new ERR_INVALID_THIS('RecordableHistogram');
|
||||||
|
if (other[kRecordable] === undefined)
|
||||||
|
throw new ERR_INVALID_ARG_TYPE('other', 'RecordableHistogram', other);
|
||||||
|
this[kHandle]?.add(other[kHandle]);
|
||||||
|
}
|
||||||
|
|
||||||
[kClone]() {
|
[kClone]() {
|
||||||
const handle = this[kHandle];
|
const handle = this[kHandle];
|
||||||
return {
|
return {
|
||||||
data: { handle },
|
data: { handle },
|
||||||
deserializeInfo: 'internal/histogram:InternalRecordableHistogram'
|
deserializeInfo: 'internal/histogram:internalRecordableHistogram'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[kDeserialize]({ handle }) {
|
||||||
|
this[kHandle] = handle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class InternalHistogram extends JSTransferable {
|
function internalHistogram(handle) {
|
||||||
constructor(handle) {
|
return makeTransferable(ReflectConstruct(
|
||||||
super();
|
function() {
|
||||||
this[kHandle] = handle;
|
this[kHandle] = handle;
|
||||||
this[kMap] = new SafeMap();
|
this[kMap] = new SafeMap();
|
||||||
|
}, [], Histogram));
|
||||||
}
|
}
|
||||||
}
|
internalHistogram.prototype[kDeserialize] = () => {};
|
||||||
|
|
||||||
class InternalRecordableHistogram extends JSTransferable {
|
function internalRecordableHistogram(handle) {
|
||||||
constructor(handle) {
|
return makeTransferable(ReflectConstruct(
|
||||||
super();
|
function() {
|
||||||
this[kHandle] = handle;
|
this[kHandle] = handle;
|
||||||
this[kMap] = new SafeMap();
|
this[kMap] = new SafeMap();
|
||||||
|
this[kRecordable] = true;
|
||||||
|
}, [], RecordableHistogram));
|
||||||
}
|
}
|
||||||
|
internalRecordableHistogram.prototype[kDeserialize] = () => {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{
|
||||||
|
* lowest? : number,
|
||||||
|
* highest? : number,
|
||||||
|
* figures? : number
|
||||||
|
* }} [options]
|
||||||
|
* @returns {RecordableHistogram}
|
||||||
|
*/
|
||||||
|
function createHistogram(options = {}) {
|
||||||
|
validateObject(options, 'options');
|
||||||
|
const {
|
||||||
|
lowest = 1,
|
||||||
|
highest = NumberMAX_SAFE_INTEGER,
|
||||||
|
figures = 3,
|
||||||
|
} = options;
|
||||||
|
if (typeof lowest !== 'bigint')
|
||||||
|
validateInteger(lowest, 'options.lowest', 1, NumberMAX_SAFE_INTEGER);
|
||||||
|
if (typeof highest !== 'bigint') {
|
||||||
|
validateInteger(highest, 'options.highest',
|
||||||
|
2 * lowest, NumberMAX_SAFE_INTEGER);
|
||||||
|
} else if (highest < 2n * lowest) {
|
||||||
|
throw new ERR_INVALID_ARG_VALUE.RangeError('options.highest', highest);
|
||||||
}
|
}
|
||||||
|
validateUint32(figures, 'options.figures', 1, 5);
|
||||||
InternalHistogram.prototype.constructor = Histogram;
|
return internalRecordableHistogram(new _Histogram(lowest, highest, figures));
|
||||||
ObjectSetPrototypeOf(
|
|
||||||
InternalHistogram.prototype,
|
|
||||||
Histogram.prototype);
|
|
||||||
|
|
||||||
InternalRecordableHistogram.prototype.constructor = RecordableHistogram;
|
|
||||||
ObjectSetPrototypeOf(
|
|
||||||
InternalRecordableHistogram.prototype,
|
|
||||||
RecordableHistogram.prototype);
|
|
||||||
|
|
||||||
function createHistogram() {
|
|
||||||
return new InternalRecordableHistogram(new _Histogram());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Histogram,
|
Histogram,
|
||||||
RecordableHistogram,
|
RecordableHistogram,
|
||||||
InternalHistogram,
|
internalHistogram,
|
||||||
InternalRecordableHistogram,
|
internalRecordableHistogram,
|
||||||
isHistogram,
|
isHistogram,
|
||||||
kDestroy,
|
kDestroy,
|
||||||
kHandle,
|
kHandle,
|
||||||
|
kMap,
|
||||||
createHistogram,
|
createHistogram,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
const {
|
const {
|
||||||
|
ReflectConstruct,
|
||||||
|
SafeMap,
|
||||||
Symbol,
|
Symbol,
|
||||||
} = primordials;
|
} = primordials;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
codes: {
|
codes: {
|
||||||
ERR_ILLEGAL_CONSTRUCTOR,
|
ERR_ILLEGAL_CONSTRUCTOR,
|
||||||
|
ERR_INVALID_THIS,
|
||||||
}
|
}
|
||||||
} = require('internal/errors');
|
} = require('internal/errors');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
ELDHistogram: _ELDHistogram,
|
createELDHistogram,
|
||||||
} = internalBinding('performance');
|
} = internalBinding('performance');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -21,25 +24,38 @@ const {
|
||||||
const {
|
const {
|
||||||
Histogram,
|
Histogram,
|
||||||
kHandle,
|
kHandle,
|
||||||
|
kMap,
|
||||||
} = require('internal/histogram');
|
} = require('internal/histogram');
|
||||||
|
|
||||||
|
const {
|
||||||
|
makeTransferable,
|
||||||
|
} = require('internal/worker/js_transferable');
|
||||||
|
|
||||||
const kEnabled = Symbol('kEnabled');
|
const kEnabled = Symbol('kEnabled');
|
||||||
|
|
||||||
class ELDHistogram extends Histogram {
|
class ELDHistogram extends Histogram {
|
||||||
constructor(i) {
|
constructor(i) {
|
||||||
if (!(i instanceof _ELDHistogram)) {
|
|
||||||
throw new ERR_ILLEGAL_CONSTRUCTOR();
|
throw new ERR_ILLEGAL_CONSTRUCTOR();
|
||||||
}
|
}
|
||||||
super(i);
|
|
||||||
this[kEnabled] = false;
|
/**
|
||||||
}
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
enable() {
|
enable() {
|
||||||
|
if (this[kEnabled] === undefined)
|
||||||
|
throw new ERR_INVALID_THIS('ELDHistogram');
|
||||||
if (this[kEnabled]) return false;
|
if (this[kEnabled]) return false;
|
||||||
this[kEnabled] = true;
|
this[kEnabled] = true;
|
||||||
this[kHandle].start();
|
this[kHandle].start();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
disable() {
|
disable() {
|
||||||
|
if (this[kEnabled] === undefined)
|
||||||
|
throw new ERR_INVALID_THIS('ELDHistogram');
|
||||||
if (!this[kEnabled]) return false;
|
if (!this[kEnabled]) return false;
|
||||||
this[kEnabled] = false;
|
this[kEnabled] = false;
|
||||||
this[kHandle].stop();
|
this[kHandle].stop();
|
||||||
|
@ -47,13 +63,24 @@ class ELDHistogram extends Histogram {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{
|
||||||
|
* resolution : number
|
||||||
|
* }} [options]
|
||||||
|
* @returns {ELDHistogram}
|
||||||
|
*/
|
||||||
function monitorEventLoopDelay(options = {}) {
|
function monitorEventLoopDelay(options = {}) {
|
||||||
validateObject(options, 'options');
|
validateObject(options, 'options');
|
||||||
|
|
||||||
const { resolution = 10 } = options;
|
const { resolution = 10 } = options;
|
||||||
validateInteger(resolution, 'options.resolution', 1);
|
validateInteger(resolution, 'options.resolution', 1);
|
||||||
|
|
||||||
return new ELDHistogram(new _ELDHistogram(resolution));
|
return makeTransferable(ReflectConstruct(
|
||||||
|
function() {
|
||||||
|
this[kEnabled] = false;
|
||||||
|
this[kHandle] = createELDHistogram(resolution);
|
||||||
|
this[kMap] = new SafeMap();
|
||||||
|
}, [], ELDHistogram));
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = monitorEventLoopDelay;
|
module.exports = monitorEventLoopDelay;
|
||||||
|
|
|
@ -13,35 +13,49 @@ void Histogram::Reset() {
|
||||||
Mutex::ScopedLock lock(mutex_);
|
Mutex::ScopedLock lock(mutex_);
|
||||||
hdr_reset(histogram_.get());
|
hdr_reset(histogram_.get());
|
||||||
exceeds_ = 0;
|
exceeds_ = 0;
|
||||||
|
count_ = 0;
|
||||||
prev_ = 0;
|
prev_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t Histogram::Min() {
|
double Histogram::Add(const Histogram& other) {
|
||||||
|
Mutex::ScopedLock lock(mutex_);
|
||||||
|
count_ += other.count_;
|
||||||
|
exceeds_ += other.exceeds_;
|
||||||
|
if (other.prev_ > prev_)
|
||||||
|
prev_ = other.prev_;
|
||||||
|
return static_cast<double>(hdr_add(histogram_.get(), other.histogram_.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Histogram::Count() const {
|
||||||
|
Mutex::ScopedLock lock(mutex_);
|
||||||
|
return count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t Histogram::Min() const {
|
||||||
Mutex::ScopedLock lock(mutex_);
|
Mutex::ScopedLock lock(mutex_);
|
||||||
return hdr_min(histogram_.get());
|
return hdr_min(histogram_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t Histogram::Max() {
|
int64_t Histogram::Max() const {
|
||||||
Mutex::ScopedLock lock(mutex_);
|
Mutex::ScopedLock lock(mutex_);
|
||||||
return hdr_max(histogram_.get());
|
return hdr_max(histogram_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
double Histogram::Mean() {
|
double Histogram::Mean() const {
|
||||||
Mutex::ScopedLock lock(mutex_);
|
Mutex::ScopedLock lock(mutex_);
|
||||||
return hdr_mean(histogram_.get());
|
return hdr_mean(histogram_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
double Histogram::Stddev() {
|
double Histogram::Stddev() const {
|
||||||
Mutex::ScopedLock lock(mutex_);
|
Mutex::ScopedLock lock(mutex_);
|
||||||
return hdr_stddev(histogram_.get());
|
return hdr_stddev(histogram_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
double Histogram::Percentile(double percentile) {
|
int64_t Histogram::Percentile(double percentile) const {
|
||||||
Mutex::ScopedLock lock(mutex_);
|
Mutex::ScopedLock lock(mutex_);
|
||||||
CHECK_GT(percentile, 0);
|
CHECK_GT(percentile, 0);
|
||||||
CHECK_LE(percentile, 100);
|
CHECK_LE(percentile, 100);
|
||||||
return static_cast<double>(
|
return hdr_value_at_percentile(histogram_.get(), percentile);
|
||||||
hdr_value_at_percentile(histogram_.get(), percentile));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
|
@ -51,27 +65,32 @@ void Histogram::Percentiles(Iterator&& fn) {
|
||||||
hdr_iter_percentile_init(&iter, histogram_.get(), 1);
|
hdr_iter_percentile_init(&iter, histogram_.get(), 1);
|
||||||
while (hdr_iter_next(&iter)) {
|
while (hdr_iter_next(&iter)) {
|
||||||
double key = iter.specifics.percentiles.percentile;
|
double key = iter.specifics.percentiles.percentile;
|
||||||
double value = static_cast<double>(iter.value);
|
fn(key, iter.value);
|
||||||
fn(key, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Histogram::Record(int64_t value) {
|
bool Histogram::Record(int64_t value) {
|
||||||
Mutex::ScopedLock lock(mutex_);
|
Mutex::ScopedLock lock(mutex_);
|
||||||
return hdr_record_value(histogram_.get(), value);
|
bool recorded = hdr_record_value(histogram_.get(), value);
|
||||||
|
if (!recorded)
|
||||||
|
exceeds_++;
|
||||||
|
else
|
||||||
|
count_++;
|
||||||
|
return recorded;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Histogram::RecordDelta() {
|
uint64_t Histogram::RecordDelta() {
|
||||||
Mutex::ScopedLock lock(mutex_);
|
Mutex::ScopedLock lock(mutex_);
|
||||||
uint64_t time = uv_hrtime();
|
uint64_t time = uv_hrtime();
|
||||||
uint64_t delta = 0;
|
int64_t delta = 0;
|
||||||
if (prev_ > 0) {
|
if (prev_ > 0) {
|
||||||
|
CHECK_GE(time, prev_);
|
||||||
delta = time - prev_;
|
delta = time - prev_;
|
||||||
if (delta > 0) {
|
if (hdr_record_value(histogram_.get(), delta))
|
||||||
if (!hdr_record_value(histogram_.get(), delta) && exceeds_ < 0xFFFFFFFF)
|
count_++;
|
||||||
|
else
|
||||||
exceeds_++;
|
exceeds_++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
prev_ = time;
|
prev_ = time;
|
||||||
return delta;
|
return delta;
|
||||||
}
|
}
|
||||||
|
|
280
src/histogram.cc
280
src/histogram.cc
|
@ -10,16 +10,21 @@ namespace node {
|
||||||
using v8::BigInt;
|
using v8::BigInt;
|
||||||
using v8::FunctionCallbackInfo;
|
using v8::FunctionCallbackInfo;
|
||||||
using v8::FunctionTemplate;
|
using v8::FunctionTemplate;
|
||||||
|
using v8::Integer;
|
||||||
using v8::Local;
|
using v8::Local;
|
||||||
using v8::Map;
|
using v8::Map;
|
||||||
using v8::Number;
|
using v8::Number;
|
||||||
using v8::Object;
|
using v8::Object;
|
||||||
using v8::String;
|
using v8::String;
|
||||||
|
using v8::Uint32;
|
||||||
using v8::Value;
|
using v8::Value;
|
||||||
|
|
||||||
Histogram::Histogram(int64_t lowest, int64_t highest, int figures) {
|
Histogram::Histogram(const Options& options) {
|
||||||
hdr_histogram* histogram;
|
hdr_histogram* histogram;
|
||||||
CHECK_EQ(0, hdr_init(lowest, highest, figures, &histogram));
|
CHECK_EQ(0, hdr_init(options.lowest,
|
||||||
|
options.highest,
|
||||||
|
options.figures,
|
||||||
|
&histogram));
|
||||||
histogram_.reset(histogram);
|
histogram_.reset(histogram);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,8 +32,8 @@ void Histogram::MemoryInfo(MemoryTracker* tracker) const {
|
||||||
tracker->TrackFieldWithSize("histogram", GetMemorySize());
|
tracker->TrackFieldWithSize("histogram", GetMemorySize());
|
||||||
}
|
}
|
||||||
|
|
||||||
HistogramImpl::HistogramImpl(int64_t lowest, int64_t highest, int figures)
|
HistogramImpl::HistogramImpl(const Histogram::Options& options)
|
||||||
: histogram_(new Histogram(lowest, highest, figures)) {}
|
: histogram_(new Histogram(options)) {}
|
||||||
|
|
||||||
HistogramImpl::HistogramImpl(std::shared_ptr<Histogram> histogram)
|
HistogramImpl::HistogramImpl(std::shared_ptr<Histogram> histogram)
|
||||||
: histogram_(std::move(histogram)) {}
|
: histogram_(std::move(histogram)) {}
|
||||||
|
@ -36,11 +41,9 @@ HistogramImpl::HistogramImpl(std::shared_ptr<Histogram> histogram)
|
||||||
HistogramBase::HistogramBase(
|
HistogramBase::HistogramBase(
|
||||||
Environment* env,
|
Environment* env,
|
||||||
Local<Object> wrap,
|
Local<Object> wrap,
|
||||||
int64_t lowest,
|
const Histogram::Options& options)
|
||||||
int64_t highest,
|
|
||||||
int figures)
|
|
||||||
: BaseObject(env, wrap),
|
: BaseObject(env, wrap),
|
||||||
HistogramImpl(lowest, highest, figures) {
|
HistogramImpl(options) {
|
||||||
MakeWeak();
|
MakeWeak();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +60,22 @@ void HistogramBase::MemoryInfo(MemoryTracker* tracker) const {
|
||||||
tracker->TrackField("histogram", histogram());
|
tracker->TrackField("histogram", histogram());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistogramBase::GetCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||||
|
HistogramBase* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
double value = static_cast<double>((*histogram)->Count());
|
||||||
|
args.GetReturnValue().Set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistogramBase::GetCountBigInt(
|
||||||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
HistogramBase* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
args.GetReturnValue().Set(
|
||||||
|
BigInt::NewFromUnsigned(env->isolate(), (*histogram)->Count()));
|
||||||
|
}
|
||||||
|
|
||||||
void HistogramBase::GetMin(const FunctionCallbackInfo<Value>& args) {
|
void HistogramBase::GetMin(const FunctionCallbackInfo<Value>& args) {
|
||||||
HistogramBase* histogram;
|
HistogramBase* histogram;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
@ -64,6 +83,13 @@ void HistogramBase::GetMin(const FunctionCallbackInfo<Value>& args) {
|
||||||
args.GetReturnValue().Set(value);
|
args.GetReturnValue().Set(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistogramBase::GetMinBigInt(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
HistogramBase* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
args.GetReturnValue().Set(BigInt::New(env->isolate(), (*histogram)->Min()));
|
||||||
|
}
|
||||||
|
|
||||||
void HistogramBase::GetMax(const FunctionCallbackInfo<Value>& args) {
|
void HistogramBase::GetMax(const FunctionCallbackInfo<Value>& args) {
|
||||||
HistogramBase* histogram;
|
HistogramBase* histogram;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
@ -71,6 +97,14 @@ void HistogramBase::GetMax(const FunctionCallbackInfo<Value>& args) {
|
||||||
args.GetReturnValue().Set(value);
|
args.GetReturnValue().Set(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistogramBase::GetMaxBigInt(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
HistogramBase* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
args.GetReturnValue().Set(
|
||||||
|
BigInt::New(env->isolate(), (*histogram)->Max()));
|
||||||
|
}
|
||||||
|
|
||||||
void HistogramBase::GetMean(const FunctionCallbackInfo<Value>& args) {
|
void HistogramBase::GetMean(const FunctionCallbackInfo<Value>& args) {
|
||||||
HistogramBase* histogram;
|
HistogramBase* histogram;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
@ -84,6 +118,14 @@ void HistogramBase::GetExceeds(const FunctionCallbackInfo<Value>& args) {
|
||||||
args.GetReturnValue().Set(value);
|
args.GetReturnValue().Set(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistogramBase::GetExceedsBigInt(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
HistogramBase* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
args.GetReturnValue().Set(
|
||||||
|
BigInt::NewFromUnsigned(env->isolate(), (*histogram)->Exceeds()));
|
||||||
|
}
|
||||||
|
|
||||||
void HistogramBase::GetStddev(const FunctionCallbackInfo<Value>& args) {
|
void HistogramBase::GetStddev(const FunctionCallbackInfo<Value>& args) {
|
||||||
HistogramBase* histogram;
|
HistogramBase* histogram;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
@ -95,7 +137,19 @@ void HistogramBase::GetPercentile(const FunctionCallbackInfo<Value>& args) {
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
CHECK(args[0]->IsNumber());
|
CHECK(args[0]->IsNumber());
|
||||||
double percentile = args[0].As<Number>()->Value();
|
double percentile = args[0].As<Number>()->Value();
|
||||||
args.GetReturnValue().Set((*histogram)->Percentile(percentile));
|
double value = static_cast<double>((*histogram)->Percentile(percentile));
|
||||||
|
args.GetReturnValue().Set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistogramBase::GetPercentileBigInt(
|
||||||
|
const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
HistogramBase* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
CHECK(args[0]->IsNumber());
|
||||||
|
double percentile = args[0].As<Number>()->Value();
|
||||||
|
int64_t value = (*histogram)->Percentile(percentile);
|
||||||
|
args.GetReturnValue().Set(BigInt::New(env->isolate(), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistogramBase::GetPercentiles(const FunctionCallbackInfo<Value>& args) {
|
void HistogramBase::GetPercentiles(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
@ -104,11 +158,26 @@ void HistogramBase::GetPercentiles(const FunctionCallbackInfo<Value>& args) {
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
CHECK(args[0]->IsMap());
|
CHECK(args[0]->IsMap());
|
||||||
Local<Map> map = args[0].As<Map>();
|
Local<Map> map = args[0].As<Map>();
|
||||||
(*histogram)->Percentiles([map, env](double key, double value) {
|
(*histogram)->Percentiles([map, env](double key, int64_t value) {
|
||||||
map->Set(
|
map->Set(
|
||||||
env->context(),
|
env->context(),
|
||||||
Number::New(env->isolate(), key),
|
Number::New(env->isolate(), key),
|
||||||
Number::New(env->isolate(), value)).IsEmpty();
|
Number::New(env->isolate(), static_cast<double>(value))).IsEmpty();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistogramBase::GetPercentilesBigInt(
|
||||||
|
const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
HistogramBase* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
CHECK(args[0]->IsMap());
|
||||||
|
Local<Map> map = args[0].As<Map>();
|
||||||
|
(*histogram)->Percentiles([map, env](double key, int64_t value) {
|
||||||
|
map->Set(
|
||||||
|
env->context(),
|
||||||
|
Number::New(env->isolate(), key),
|
||||||
|
BigInt::New(env->isolate(), value)).IsEmpty();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,11 +207,22 @@ void HistogramBase::Record(const FunctionCallbackInfo<Value>& args) {
|
||||||
(*histogram)->Record(value);
|
(*histogram)->Record(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistogramBase::Add(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
HistogramBase* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
|
||||||
|
CHECK(GetConstructorTemplate(env)->HasInstance(args[0]));
|
||||||
|
HistogramBase* other;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&other, args[0]);
|
||||||
|
|
||||||
|
double count = (*histogram)->Add(*(other->histogram()));
|
||||||
|
args.GetReturnValue().Set(count);
|
||||||
|
}
|
||||||
|
|
||||||
BaseObjectPtr<HistogramBase> HistogramBase::Create(
|
BaseObjectPtr<HistogramBase> HistogramBase::Create(
|
||||||
Environment* env,
|
Environment* env,
|
||||||
int64_t lowest,
|
const Histogram::Options& options) {
|
||||||
int64_t highest,
|
|
||||||
int figures) {
|
|
||||||
Local<Object> obj;
|
Local<Object> obj;
|
||||||
if (!GetConstructorTemplate(env)
|
if (!GetConstructorTemplate(env)
|
||||||
->InstanceTemplate()
|
->InstanceTemplate()
|
||||||
|
@ -150,8 +230,7 @@ BaseObjectPtr<HistogramBase> HistogramBase::Create(
|
||||||
return BaseObjectPtr<HistogramBase>();
|
return BaseObjectPtr<HistogramBase>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeBaseObject<HistogramBase>(
|
return MakeBaseObject<HistogramBase>(env, obj, options);
|
||||||
env, obj, lowest, highest, figures);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseObjectPtr<HistogramBase> HistogramBase::Create(
|
BaseObjectPtr<HistogramBase> HistogramBase::Create(
|
||||||
|
@ -169,7 +248,32 @@ BaseObjectPtr<HistogramBase> HistogramBase::Create(
|
||||||
void HistogramBase::New(const FunctionCallbackInfo<Value>& args) {
|
void HistogramBase::New(const FunctionCallbackInfo<Value>& args) {
|
||||||
CHECK(args.IsConstructCall());
|
CHECK(args.IsConstructCall());
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
new HistogramBase(env, args.This());
|
|
||||||
|
CHECK_IMPLIES(!args[0]->IsNumber(), args[0]->IsBigInt());
|
||||||
|
CHECK_IMPLIES(!args[1]->IsNumber(), args[1]->IsBigInt());
|
||||||
|
CHECK(args[2]->IsUint32());
|
||||||
|
|
||||||
|
int64_t lowest = 1;
|
||||||
|
int64_t highest = std::numeric_limits<int64_t>::max();
|
||||||
|
|
||||||
|
bool lossless_ignored;
|
||||||
|
|
||||||
|
if (args[0]->IsNumber()) {
|
||||||
|
lowest = args[0].As<Integer>()->Value();
|
||||||
|
} else if (args[0]->IsBigInt()) {
|
||||||
|
lowest = args[0].As<BigInt>()->Int64Value(&lossless_ignored);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[1]->IsNumber()) {
|
||||||
|
highest = args[1].As<Integer>()->Value();
|
||||||
|
} else if (args[1]->IsBigInt()) {
|
||||||
|
highest = args[1].As<BigInt>()->Int64Value(&lossless_ignored);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t figures = args[2].As<Uint32>()->Value();
|
||||||
|
new HistogramBase(env, args.This(), Histogram::Options {
|
||||||
|
lowest, highest, figures
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<FunctionTemplate> HistogramBase::GetConstructorTemplate(
|
Local<FunctionTemplate> HistogramBase::GetConstructorTemplate(
|
||||||
|
@ -184,16 +288,26 @@ Local<FunctionTemplate> HistogramBase::GetConstructorTemplate(
|
||||||
|
|
||||||
tmpl->InstanceTemplate()->SetInternalFieldCount(
|
tmpl->InstanceTemplate()->SetInternalFieldCount(
|
||||||
HistogramBase::kInternalFieldCount);
|
HistogramBase::kInternalFieldCount);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "count", GetCount);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "countBigInt", GetCountBigInt);
|
||||||
env->SetProtoMethodNoSideEffect(tmpl, "exceeds", GetExceeds);
|
env->SetProtoMethodNoSideEffect(tmpl, "exceeds", GetExceeds);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "exceedsBigInt", GetExceedsBigInt);
|
||||||
env->SetProtoMethodNoSideEffect(tmpl, "min", GetMin);
|
env->SetProtoMethodNoSideEffect(tmpl, "min", GetMin);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "minBigInt", GetMinBigInt);
|
||||||
env->SetProtoMethodNoSideEffect(tmpl, "max", GetMax);
|
env->SetProtoMethodNoSideEffect(tmpl, "max", GetMax);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "maxBigInt", GetMaxBigInt);
|
||||||
env->SetProtoMethodNoSideEffect(tmpl, "mean", GetMean);
|
env->SetProtoMethodNoSideEffect(tmpl, "mean", GetMean);
|
||||||
env->SetProtoMethodNoSideEffect(tmpl, "stddev", GetStddev);
|
env->SetProtoMethodNoSideEffect(tmpl, "stddev", GetStddev);
|
||||||
env->SetProtoMethodNoSideEffect(tmpl, "percentile", GetPercentile);
|
env->SetProtoMethodNoSideEffect(tmpl, "percentile", GetPercentile);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "percentileBigInt",
|
||||||
|
GetPercentileBigInt);
|
||||||
env->SetProtoMethodNoSideEffect(tmpl, "percentiles", GetPercentiles);
|
env->SetProtoMethodNoSideEffect(tmpl, "percentiles", GetPercentiles);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "percentilesBigInt",
|
||||||
|
GetPercentilesBigInt);
|
||||||
env->SetProtoMethod(tmpl, "reset", DoReset);
|
env->SetProtoMethod(tmpl, "reset", DoReset);
|
||||||
env->SetProtoMethod(tmpl, "record", Record);
|
env->SetProtoMethod(tmpl, "record", Record);
|
||||||
env->SetProtoMethod(tmpl, "recordDelta", RecordDelta);
|
env->SetProtoMethod(tmpl, "recordDelta", RecordDelta);
|
||||||
|
env->SetProtoMethod(tmpl, "add", Add);
|
||||||
env->set_histogram_ctor_template(tmpl);
|
env->set_histogram_ctor_template(tmpl);
|
||||||
}
|
}
|
||||||
return tmpl;
|
return tmpl;
|
||||||
|
@ -202,16 +316,24 @@ Local<FunctionTemplate> HistogramBase::GetConstructorTemplate(
|
||||||
void HistogramBase::RegisterExternalReferences(
|
void HistogramBase::RegisterExternalReferences(
|
||||||
ExternalReferenceRegistry* registry) {
|
ExternalReferenceRegistry* registry) {
|
||||||
registry->Register(New);
|
registry->Register(New);
|
||||||
|
registry->Register(GetCount);
|
||||||
|
registry->Register(GetCountBigInt);
|
||||||
registry->Register(GetExceeds);
|
registry->Register(GetExceeds);
|
||||||
|
registry->Register(GetExceedsBigInt);
|
||||||
registry->Register(GetMin);
|
registry->Register(GetMin);
|
||||||
|
registry->Register(GetMinBigInt);
|
||||||
registry->Register(GetMax);
|
registry->Register(GetMax);
|
||||||
|
registry->Register(GetMaxBigInt);
|
||||||
registry->Register(GetMean);
|
registry->Register(GetMean);
|
||||||
registry->Register(GetStddev);
|
registry->Register(GetStddev);
|
||||||
registry->Register(GetPercentile);
|
registry->Register(GetPercentile);
|
||||||
|
registry->Register(GetPercentileBigInt);
|
||||||
registry->Register(GetPercentiles);
|
registry->Register(GetPercentiles);
|
||||||
|
registry->Register(GetPercentilesBigInt);
|
||||||
registry->Register(DoReset);
|
registry->Register(DoReset);
|
||||||
registry->Register(Record);
|
registry->Register(Record);
|
||||||
registry->Register(RecordDelta);
|
registry->Register(RecordDelta);
|
||||||
|
registry->Register(Add);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistogramBase::Initialize(Environment* env, Local<Object> target) {
|
void HistogramBase::Initialize(Environment* env, Local<Object> target) {
|
||||||
|
@ -242,13 +364,22 @@ Local<FunctionTemplate> IntervalHistogram::GetConstructorTemplate(
|
||||||
tmpl->Inherit(HandleWrap::GetConstructorTemplate(env));
|
tmpl->Inherit(HandleWrap::GetConstructorTemplate(env));
|
||||||
tmpl->InstanceTemplate()->SetInternalFieldCount(
|
tmpl->InstanceTemplate()->SetInternalFieldCount(
|
||||||
HistogramBase::kInternalFieldCount);
|
HistogramBase::kInternalFieldCount);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "count", GetCount);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "countBigInt", GetCountBigInt);
|
||||||
env->SetProtoMethodNoSideEffect(tmpl, "exceeds", GetExceeds);
|
env->SetProtoMethodNoSideEffect(tmpl, "exceeds", GetExceeds);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "exceedsBigInt", GetExceedsBigInt);
|
||||||
env->SetProtoMethodNoSideEffect(tmpl, "min", GetMin);
|
env->SetProtoMethodNoSideEffect(tmpl, "min", GetMin);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "minBigInt", GetMinBigInt);
|
||||||
env->SetProtoMethodNoSideEffect(tmpl, "max", GetMax);
|
env->SetProtoMethodNoSideEffect(tmpl, "max", GetMax);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "maxBigInt", GetMaxBigInt);
|
||||||
env->SetProtoMethodNoSideEffect(tmpl, "mean", GetMean);
|
env->SetProtoMethodNoSideEffect(tmpl, "mean", GetMean);
|
||||||
env->SetProtoMethodNoSideEffect(tmpl, "stddev", GetStddev);
|
env->SetProtoMethodNoSideEffect(tmpl, "stddev", GetStddev);
|
||||||
env->SetProtoMethodNoSideEffect(tmpl, "percentile", GetPercentile);
|
env->SetProtoMethodNoSideEffect(tmpl, "percentile", GetPercentile);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "percentileBigInt",
|
||||||
|
GetPercentileBigInt);
|
||||||
env->SetProtoMethodNoSideEffect(tmpl, "percentiles", GetPercentiles);
|
env->SetProtoMethodNoSideEffect(tmpl, "percentiles", GetPercentiles);
|
||||||
|
env->SetProtoMethodNoSideEffect(tmpl, "percentilesBigInt",
|
||||||
|
GetPercentilesBigInt);
|
||||||
env->SetProtoMethod(tmpl, "reset", DoReset);
|
env->SetProtoMethod(tmpl, "reset", DoReset);
|
||||||
env->SetProtoMethod(tmpl, "start", Start);
|
env->SetProtoMethod(tmpl, "start", Start);
|
||||||
env->SetProtoMethod(tmpl, "stop", Stop);
|
env->SetProtoMethod(tmpl, "stop", Stop);
|
||||||
|
@ -259,13 +390,20 @@ Local<FunctionTemplate> IntervalHistogram::GetConstructorTemplate(
|
||||||
|
|
||||||
void IntervalHistogram::RegisterExternalReferences(
|
void IntervalHistogram::RegisterExternalReferences(
|
||||||
ExternalReferenceRegistry* registry) {
|
ExternalReferenceRegistry* registry) {
|
||||||
|
registry->Register(GetCount);
|
||||||
|
registry->Register(GetCountBigInt);
|
||||||
registry->Register(GetExceeds);
|
registry->Register(GetExceeds);
|
||||||
|
registry->Register(GetExceedsBigInt);
|
||||||
registry->Register(GetMin);
|
registry->Register(GetMin);
|
||||||
|
registry->Register(GetMinBigInt);
|
||||||
registry->Register(GetMax);
|
registry->Register(GetMax);
|
||||||
|
registry->Register(GetMaxBigInt);
|
||||||
registry->Register(GetMean);
|
registry->Register(GetMean);
|
||||||
registry->Register(GetStddev);
|
registry->Register(GetStddev);
|
||||||
registry->Register(GetPercentile);
|
registry->Register(GetPercentile);
|
||||||
|
registry->Register(GetPercentileBigInt);
|
||||||
registry->Register(GetPercentiles);
|
registry->Register(GetPercentiles);
|
||||||
|
registry->Register(GetPercentilesBigInt);
|
||||||
registry->Register(DoReset);
|
registry->Register(DoReset);
|
||||||
registry->Register(Start);
|
registry->Register(Start);
|
||||||
registry->Register(Stop);
|
registry->Register(Stop);
|
||||||
|
@ -276,24 +414,48 @@ IntervalHistogram::IntervalHistogram(
|
||||||
Local<Object> wrap,
|
Local<Object> wrap,
|
||||||
AsyncWrap::ProviderType type,
|
AsyncWrap::ProviderType type,
|
||||||
int32_t interval,
|
int32_t interval,
|
||||||
int64_t lowest,
|
std::function<void(Histogram&)> on_interval,
|
||||||
int64_t highest,
|
const Histogram::Options& options)
|
||||||
int figures)
|
|
||||||
: HandleWrap(
|
: HandleWrap(
|
||||||
env,
|
env,
|
||||||
wrap,
|
wrap,
|
||||||
reinterpret_cast<uv_handle_t*>(&timer_),
|
reinterpret_cast<uv_handle_t*>(&timer_),
|
||||||
type),
|
type),
|
||||||
HistogramImpl(lowest, highest, figures),
|
HistogramImpl(options),
|
||||||
interval_(interval) {
|
interval_(interval),
|
||||||
|
on_interval_(std::move(on_interval)) {
|
||||||
MakeWeak();
|
MakeWeak();
|
||||||
uv_timer_init(env->event_loop(), &timer_);
|
uv_timer_init(env->event_loop(), &timer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BaseObjectPtr<IntervalHistogram> IntervalHistogram::Create(
|
||||||
|
Environment* env,
|
||||||
|
int32_t interval,
|
||||||
|
std::function<void(Histogram&)> on_interval,
|
||||||
|
const Histogram::Options& options) {
|
||||||
|
Local<Object> obj;
|
||||||
|
if (!GetConstructorTemplate(env)
|
||||||
|
->InstanceTemplate()
|
||||||
|
->NewInstance(env->context()).ToLocal(&obj)) {
|
||||||
|
return BaseObjectPtr<IntervalHistogram>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return MakeBaseObject<IntervalHistogram>(
|
||||||
|
env,
|
||||||
|
obj,
|
||||||
|
AsyncWrap::PROVIDER_ELDHISTOGRAM,
|
||||||
|
interval,
|
||||||
|
std::move(on_interval),
|
||||||
|
options);
|
||||||
|
}
|
||||||
|
|
||||||
void IntervalHistogram::TimerCB(uv_timer_t* handle) {
|
void IntervalHistogram::TimerCB(uv_timer_t* handle) {
|
||||||
IntervalHistogram* histogram =
|
IntervalHistogram* histogram =
|
||||||
ContainerOf(&IntervalHistogram::timer_, handle);
|
ContainerOf(&IntervalHistogram::timer_, handle);
|
||||||
histogram->OnInterval();
|
|
||||||
|
Histogram* h = histogram->histogram().get();
|
||||||
|
|
||||||
|
histogram->on_interval_(*h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntervalHistogram::MemoryInfo(MemoryTracker* tracker) const {
|
void IntervalHistogram::MemoryInfo(MemoryTracker* tracker) const {
|
||||||
|
@ -327,6 +489,22 @@ void IntervalHistogram::Stop(const FunctionCallbackInfo<Value>& args) {
|
||||||
histogram->OnStop();
|
histogram->OnStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IntervalHistogram::GetCount(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
IntervalHistogram* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
double value = static_cast<double>((*histogram)->Count());
|
||||||
|
args.GetReturnValue().Set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntervalHistogram::GetCountBigInt(
|
||||||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
IntervalHistogram* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
args.GetReturnValue().Set(
|
||||||
|
BigInt::NewFromUnsigned(env->isolate(), (*histogram)->Count()));
|
||||||
|
}
|
||||||
|
|
||||||
void IntervalHistogram::GetMin(const FunctionCallbackInfo<Value>& args) {
|
void IntervalHistogram::GetMin(const FunctionCallbackInfo<Value>& args) {
|
||||||
IntervalHistogram* histogram;
|
IntervalHistogram* histogram;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
@ -334,6 +512,13 @@ void IntervalHistogram::GetMin(const FunctionCallbackInfo<Value>& args) {
|
||||||
args.GetReturnValue().Set(value);
|
args.GetReturnValue().Set(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IntervalHistogram::GetMinBigInt(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
IntervalHistogram* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
args.GetReturnValue().Set(BigInt::New(env->isolate(), (*histogram)->Min()));
|
||||||
|
}
|
||||||
|
|
||||||
void IntervalHistogram::GetMax(const FunctionCallbackInfo<Value>& args) {
|
void IntervalHistogram::GetMax(const FunctionCallbackInfo<Value>& args) {
|
||||||
IntervalHistogram* histogram;
|
IntervalHistogram* histogram;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
@ -341,6 +526,13 @@ void IntervalHistogram::GetMax(const FunctionCallbackInfo<Value>& args) {
|
||||||
args.GetReturnValue().Set(value);
|
args.GetReturnValue().Set(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IntervalHistogram::GetMaxBigInt(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
IntervalHistogram* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
args.GetReturnValue().Set(BigInt::New(env->isolate(), (*histogram)->Min()));
|
||||||
|
}
|
||||||
|
|
||||||
void IntervalHistogram::GetMean(const FunctionCallbackInfo<Value>& args) {
|
void IntervalHistogram::GetMean(const FunctionCallbackInfo<Value>& args) {
|
||||||
IntervalHistogram* histogram;
|
IntervalHistogram* histogram;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
@ -354,6 +546,15 @@ void IntervalHistogram::GetExceeds(const FunctionCallbackInfo<Value>& args) {
|
||||||
args.GetReturnValue().Set(value);
|
args.GetReturnValue().Set(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IntervalHistogram::GetExceedsBigInt(
|
||||||
|
const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
IntervalHistogram* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
args.GetReturnValue().Set(
|
||||||
|
BigInt::New(env->isolate(), (*histogram)->Exceeds()));
|
||||||
|
}
|
||||||
|
|
||||||
void IntervalHistogram::GetStddev(const FunctionCallbackInfo<Value>& args) {
|
void IntervalHistogram::GetStddev(const FunctionCallbackInfo<Value>& args) {
|
||||||
IntervalHistogram* histogram;
|
IntervalHistogram* histogram;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
@ -365,7 +566,19 @@ void IntervalHistogram::GetPercentile(const FunctionCallbackInfo<Value>& args) {
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
CHECK(args[0]->IsNumber());
|
CHECK(args[0]->IsNumber());
|
||||||
double percentile = args[0].As<Number>()->Value();
|
double percentile = args[0].As<Number>()->Value();
|
||||||
args.GetReturnValue().Set((*histogram)->Percentile(percentile));
|
double value = static_cast<double>((*histogram)->Percentile(percentile));
|
||||||
|
args.GetReturnValue().Set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntervalHistogram::GetPercentileBigInt(
|
||||||
|
const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
IntervalHistogram* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
CHECK(args[0]->IsNumber());
|
||||||
|
double percentile = args[0].As<Number>()->Value();
|
||||||
|
int64_t value = (*histogram)->Percentile(percentile);
|
||||||
|
args.GetReturnValue().Set(BigInt::New(env->isolate(), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntervalHistogram::GetPercentiles(
|
void IntervalHistogram::GetPercentiles(
|
||||||
|
@ -375,11 +588,26 @@ void IntervalHistogram::GetPercentiles(
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
CHECK(args[0]->IsMap());
|
CHECK(args[0]->IsMap());
|
||||||
Local<Map> map = args[0].As<Map>();
|
Local<Map> map = args[0].As<Map>();
|
||||||
(*histogram)->Percentiles([map, env](double key, double value) {
|
(*histogram)->Percentiles([map, env](double key, int64_t value) {
|
||||||
map->Set(
|
map->Set(
|
||||||
env->context(),
|
env->context(),
|
||||||
Number::New(env->isolate(), key),
|
Number::New(env->isolate(), key),
|
||||||
Number::New(env->isolate(), value)).IsEmpty();
|
Number::New(env->isolate(), static_cast<double>(value))).IsEmpty();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntervalHistogram::GetPercentilesBigInt(
|
||||||
|
const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
IntervalHistogram* histogram;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
|
||||||
|
CHECK(args[0]->IsMap());
|
||||||
|
Local<Map> map = args[0].As<Map>();
|
||||||
|
(*histogram)->Percentiles([map, env](double key, int64_t value) {
|
||||||
|
map->Set(
|
||||||
|
env->context(),
|
||||||
|
Number::New(env->isolate(), key),
|
||||||
|
BigInt::New(env->isolate(), value)).IsEmpty();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,23 +24,29 @@ constexpr int kDefaultHistogramFigures = 3;
|
||||||
|
|
||||||
class Histogram : public MemoryRetainer {
|
class Histogram : public MemoryRetainer {
|
||||||
public:
|
public:
|
||||||
Histogram(
|
struct Options {
|
||||||
int64_t lowest = 1,
|
int64_t lowest = 1;
|
||||||
int64_t highest = std::numeric_limits<int64_t>::max(),
|
int64_t highest = std::numeric_limits<int64_t>::max();
|
||||||
int figures = kDefaultHistogramFigures);
|
int figures = kDefaultHistogramFigures;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit Histogram(const Options& options);
|
||||||
virtual ~Histogram() = default;
|
virtual ~Histogram() = default;
|
||||||
|
|
||||||
inline bool Record(int64_t value);
|
inline bool Record(int64_t value);
|
||||||
inline void Reset();
|
inline void Reset();
|
||||||
inline int64_t Min();
|
inline int64_t Min() const;
|
||||||
inline int64_t Max();
|
inline int64_t Max() const;
|
||||||
inline double Mean();
|
inline double Mean() const;
|
||||||
inline double Stddev();
|
inline double Stddev() const;
|
||||||
inline double Percentile(double percentile);
|
inline int64_t Percentile(double percentile) const;
|
||||||
inline int64_t Exceeds() const { return exceeds_; }
|
inline size_t Exceeds() const { return exceeds_; }
|
||||||
|
inline size_t Count() const;
|
||||||
|
|
||||||
inline uint64_t RecordDelta();
|
inline uint64_t RecordDelta();
|
||||||
|
|
||||||
|
inline double Add(const Histogram& other);
|
||||||
|
|
||||||
// Iterator is a function type that takes two doubles as argument, one for
|
// Iterator is a function type that takes two doubles as argument, one for
|
||||||
// percentile and one for the value at that percentile.
|
// percentile and one for the value at that percentile.
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
|
@ -55,20 +61,20 @@ class Histogram : public MemoryRetainer {
|
||||||
private:
|
private:
|
||||||
using HistogramPointer = DeleteFnPtr<hdr_histogram, hdr_close>;
|
using HistogramPointer = DeleteFnPtr<hdr_histogram, hdr_close>;
|
||||||
HistogramPointer histogram_;
|
HistogramPointer histogram_;
|
||||||
int64_t exceeds_ = 0;
|
|
||||||
uint64_t prev_ = 0;
|
uint64_t prev_ = 0;
|
||||||
|
size_t exceeds_ = 0;
|
||||||
|
size_t count_ = 0;
|
||||||
Mutex mutex_;
|
Mutex mutex_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HistogramImpl {
|
class HistogramImpl {
|
||||||
public:
|
public:
|
||||||
HistogramImpl(int64_t lowest, int64_t highest, int figures);
|
explicit HistogramImpl(
|
||||||
|
const Histogram::Options& options = Histogram::Options {});
|
||||||
explicit HistogramImpl(std::shared_ptr<Histogram> histogram);
|
explicit HistogramImpl(std::shared_ptr<Histogram> histogram);
|
||||||
|
|
||||||
Histogram* operator->() { return histogram_.get(); }
|
Histogram* operator->() { return histogram_.get(); }
|
||||||
|
|
||||||
protected:
|
|
||||||
const std::shared_ptr<Histogram>& histogram() const { return histogram_; }
|
const std::shared_ptr<Histogram>& histogram() const { return histogram_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -84,9 +90,7 @@ class HistogramBase : public BaseObject, public HistogramImpl {
|
||||||
|
|
||||||
static BaseObjectPtr<HistogramBase> Create(
|
static BaseObjectPtr<HistogramBase> Create(
|
||||||
Environment* env,
|
Environment* env,
|
||||||
int64_t lowest = 1,
|
const Histogram::Options& options = Histogram::Options {});
|
||||||
int64_t highest = std::numeric_limits<int64_t>::max(),
|
|
||||||
int figures = kDefaultHistogramFigures);
|
|
||||||
|
|
||||||
static BaseObjectPtr<HistogramBase> Create(
|
static BaseObjectPtr<HistogramBase> Create(
|
||||||
Environment* env,
|
Environment* env,
|
||||||
|
@ -98,6 +102,12 @@ class HistogramBase : public BaseObject, public HistogramImpl {
|
||||||
SET_MEMORY_INFO_NAME(HistogramBase)
|
SET_MEMORY_INFO_NAME(HistogramBase)
|
||||||
SET_SELF_SIZE(HistogramBase)
|
SET_SELF_SIZE(HistogramBase)
|
||||||
|
|
||||||
|
static void GetCountBigInt(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
static void GetMinBigInt(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
static void GetMaxBigInt(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
static void GetExceedsBigInt(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
|
||||||
|
static void GetCount(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void GetMin(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void GetMin(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void GetMax(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void GetMax(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void GetMean(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void GetMean(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
@ -105,18 +115,21 @@ class HistogramBase : public BaseObject, public HistogramImpl {
|
||||||
static void GetStddev(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void GetStddev(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void GetPercentile(
|
static void GetPercentile(
|
||||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
static void GetPercentileBigInt(
|
||||||
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void GetPercentiles(
|
static void GetPercentiles(
|
||||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
static void GetPercentilesBigInt(
|
||||||
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void DoReset(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void DoReset(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void Record(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void Record(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void RecordDelta(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void RecordDelta(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
static void Add(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
|
||||||
HistogramBase(
|
HistogramBase(
|
||||||
Environment* env,
|
Environment* env,
|
||||||
v8::Local<v8::Object> wrap,
|
v8::Local<v8::Object> wrap,
|
||||||
int64_t lowest = 1,
|
const Histogram::Options& options = Histogram::Options {});
|
||||||
int64_t highest = std::numeric_limits<int64_t>::max(),
|
|
||||||
int figures = kDefaultHistogramFigures);
|
|
||||||
|
|
||||||
HistogramBase(
|
HistogramBase(
|
||||||
Environment* env,
|
Environment* env,
|
||||||
|
@ -164,23 +177,24 @@ class IntervalHistogram : public HandleWrap, public HistogramImpl {
|
||||||
|
|
||||||
static BaseObjectPtr<IntervalHistogram> Create(
|
static BaseObjectPtr<IntervalHistogram> Create(
|
||||||
Environment* env,
|
Environment* env,
|
||||||
int64_t lowest = 1,
|
int32_t interval,
|
||||||
int64_t highest = std::numeric_limits<int64_t>::max(),
|
std::function<void(Histogram&)> on_interval,
|
||||||
int figures = kDefaultHistogramFigures);
|
const Histogram::Options& options);
|
||||||
|
|
||||||
virtual void OnInterval() = 0;
|
|
||||||
|
|
||||||
void MemoryInfo(MemoryTracker* tracker) const override;
|
|
||||||
|
|
||||||
IntervalHistogram(
|
IntervalHistogram(
|
||||||
Environment* env,
|
Environment* env,
|
||||||
v8::Local<v8::Object> wrap,
|
v8::Local<v8::Object> wrap,
|
||||||
AsyncWrap::ProviderType type,
|
AsyncWrap::ProviderType type,
|
||||||
int32_t interval,
|
int32_t interval,
|
||||||
int64_t lowest = 1,
|
std::function<void(Histogram&)> on_interval,
|
||||||
int64_t highest = std::numeric_limits<int64_t>::max(),
|
const Histogram::Options& options = Histogram::Options {});
|
||||||
int figures = kDefaultHistogramFigures);
|
|
||||||
|
|
||||||
|
static void GetCountBigInt(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
static void GetMinBigInt(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
static void GetMaxBigInt(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
static void GetExceedsBigInt(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
|
||||||
|
static void GetCount(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void GetMin(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void GetMin(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void GetMax(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void GetMax(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void GetMean(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void GetMean(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
@ -188,8 +202,12 @@ class IntervalHistogram : public HandleWrap, public HistogramImpl {
|
||||||
static void GetStddev(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void GetStddev(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void GetPercentile(
|
static void GetPercentile(
|
||||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
static void GetPercentileBigInt(
|
||||||
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void GetPercentiles(
|
static void GetPercentiles(
|
||||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
static void GetPercentilesBigInt(
|
||||||
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void DoReset(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void DoReset(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void Start(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void Start(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void Stop(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void Stop(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
@ -199,6 +217,10 @@ class IntervalHistogram : public HandleWrap, public HistogramImpl {
|
||||||
}
|
}
|
||||||
std::unique_ptr<worker::TransferData> CloneForMessaging() const override;
|
std::unique_ptr<worker::TransferData> CloneForMessaging() const override;
|
||||||
|
|
||||||
|
void MemoryInfo(MemoryTracker* tracker) const override;
|
||||||
|
SET_MEMORY_INFO_NAME(IntervalHistogram)
|
||||||
|
SET_SELF_SIZE(IntervalHistogram)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void TimerCB(uv_timer_t* handle);
|
static void TimerCB(uv_timer_t* handle);
|
||||||
void OnStart(StartFlags flags = StartFlags::RESET);
|
void OnStart(StartFlags flags = StartFlags::RESET);
|
||||||
|
@ -206,6 +228,7 @@ class IntervalHistogram : public HandleWrap, public HistogramImpl {
|
||||||
|
|
||||||
bool enabled_ = false;
|
bool enabled_ = false;
|
||||||
int32_t interval_ = 0;
|
int32_t interval_ = 0;
|
||||||
|
std::function<void(Histogram&)> on_interval_;
|
||||||
uv_timer_t timer_;
|
uv_timer_t timer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -234,51 +234,25 @@ void LoopIdleTime(const FunctionCallbackInfo<Value>& args) {
|
||||||
args.GetReturnValue().Set(1.0 * idle_time / 1e6);
|
args.GetReturnValue().Set(1.0 * idle_time / 1e6);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event Loop Timing Histogram
|
void CreateELDHistogram(const FunctionCallbackInfo<Value>& args) {
|
||||||
void ELDHistogram::New(const FunctionCallbackInfo<Value>& args) {
|
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
CHECK(args.IsConstructCall());
|
int64_t interval = args[0].As<Integer>()->Value();
|
||||||
int64_t resolution = args[0].As<Integer>()->Value();
|
CHECK_GT(interval, 0);
|
||||||
CHECK_GT(resolution, 0);
|
BaseObjectPtr<IntervalHistogram> histogram =
|
||||||
new ELDHistogram(env, args.This(), resolution);
|
IntervalHistogram::Create(env, interval, [](Histogram& histogram) {
|
||||||
}
|
uint64_t delta = histogram.RecordDelta();
|
||||||
|
|
||||||
void ELDHistogram::Initialize(Environment* env, Local<Object> target) {
|
|
||||||
Local<FunctionTemplate> tmpl = env->NewFunctionTemplate(New);
|
|
||||||
tmpl->Inherit(IntervalHistogram::GetConstructorTemplate(env));
|
|
||||||
tmpl->InstanceTemplate()->SetInternalFieldCount(
|
|
||||||
ELDHistogram::kInternalFieldCount);
|
|
||||||
env->SetConstructorFunction(target, "ELDHistogram", tmpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ELDHistogram::RegisterExternalReferences(
|
|
||||||
ExternalReferenceRegistry* registry) {
|
|
||||||
registry->Register(New);
|
|
||||||
IntervalHistogram::RegisterExternalReferences(registry);
|
|
||||||
}
|
|
||||||
|
|
||||||
ELDHistogram::ELDHistogram(
|
|
||||||
Environment* env,
|
|
||||||
Local<Object> wrap,
|
|
||||||
int64_t interval)
|
|
||||||
: IntervalHistogram(
|
|
||||||
env,
|
|
||||||
wrap,
|
|
||||||
AsyncWrap::PROVIDER_ELDHISTOGRAM,
|
|
||||||
interval, 1, 3.6e12, 3) {}
|
|
||||||
|
|
||||||
void ELDHistogram::OnInterval() {
|
|
||||||
uint64_t delta = histogram()->RecordDelta();
|
|
||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
|
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
|
||||||
"delay", delta);
|
"delay", delta);
|
||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
|
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
|
||||||
"min", histogram()->Min());
|
"min", histogram.Min());
|
||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
|
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
|
||||||
"max", histogram()->Max());
|
"max", histogram.Max());
|
||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
|
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
|
||||||
"mean", histogram()->Mean());
|
"mean", histogram.Mean());
|
||||||
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
|
TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
|
||||||
"stddev", histogram()->Stddev());
|
"stddev", histogram.Stddev());
|
||||||
|
}, Histogram::Options { 1000 });
|
||||||
|
args.GetReturnValue().Set(histogram->object());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetTimeOrigin(const FunctionCallbackInfo<Value>& args) {
|
void GetTimeOrigin(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
@ -326,6 +300,7 @@ void Initialize(Local<Object> target,
|
||||||
env->SetMethod(target, "loopIdleTime", LoopIdleTime);
|
env->SetMethod(target, "loopIdleTime", LoopIdleTime);
|
||||||
env->SetMethod(target, "getTimeOrigin", GetTimeOrigin);
|
env->SetMethod(target, "getTimeOrigin", GetTimeOrigin);
|
||||||
env->SetMethod(target, "getTimeOriginTimestamp", GetTimeOriginTimeStamp);
|
env->SetMethod(target, "getTimeOriginTimestamp", GetTimeOriginTimeStamp);
|
||||||
|
env->SetMethod(target, "createELDHistogram", CreateELDHistogram);
|
||||||
|
|
||||||
Local<Object> constants = Object::New(isolate);
|
Local<Object> constants = Object::New(isolate);
|
||||||
|
|
||||||
|
@ -368,7 +343,6 @@ void Initialize(Local<Object> target,
|
||||||
attr).ToChecked();
|
attr).ToChecked();
|
||||||
|
|
||||||
HistogramBase::Initialize(env, target);
|
HistogramBase::Initialize(env, target);
|
||||||
ELDHistogram::Initialize(env, target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
||||||
|
@ -380,8 +354,9 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
||||||
registry->Register(LoopIdleTime);
|
registry->Register(LoopIdleTime);
|
||||||
registry->Register(GetTimeOrigin);
|
registry->Register(GetTimeOrigin);
|
||||||
registry->Register(GetTimeOriginTimeStamp);
|
registry->Register(GetTimeOriginTimeStamp);
|
||||||
|
registry->Register(CreateELDHistogram);
|
||||||
HistogramBase::RegisterExternalReferences(registry);
|
HistogramBase::RegisterExternalReferences(registry);
|
||||||
ELDHistogram::RegisterExternalReferences(registry);
|
IntervalHistogram::RegisterExternalReferences(registry);
|
||||||
}
|
}
|
||||||
} // namespace performance
|
} // namespace performance
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
|
|
@ -160,23 +160,6 @@ struct GCPerformanceEntryTraits {
|
||||||
|
|
||||||
using GCPerformanceEntry = PerformanceEntry<GCPerformanceEntryTraits>;
|
using GCPerformanceEntry = PerformanceEntry<GCPerformanceEntryTraits>;
|
||||||
|
|
||||||
class ELDHistogram : public IntervalHistogram {
|
|
||||||
public:
|
|
||||||
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
|
|
||||||
static void Initialize(Environment* env, v8::Local<v8::Object> target);
|
|
||||||
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
||||||
|
|
||||||
ELDHistogram(
|
|
||||||
Environment* env,
|
|
||||||
v8::Local<v8::Object> wrap,
|
|
||||||
int64_t interval);
|
|
||||||
|
|
||||||
void OnInterval() override;
|
|
||||||
|
|
||||||
SET_MEMORY_INFO_NAME(ELDHistogram)
|
|
||||||
SET_SELF_SIZE(ELDHistogram)
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace performance
|
} // namespace performance
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
|
||||||
|
|
|
@ -1,54 +1,75 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const assert = require('assert');
|
|
||||||
|
const {
|
||||||
|
ok,
|
||||||
|
strictEqual,
|
||||||
|
throws,
|
||||||
|
} = require('assert');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
createHistogram,
|
createHistogram,
|
||||||
monitorEventLoopDelay,
|
monitorEventLoopDelay,
|
||||||
} = require('perf_hooks');
|
} = require('perf_hooks');
|
||||||
|
|
||||||
const { inspect } = require('util');
|
const { inspect } = require('util');
|
||||||
|
|
||||||
{
|
{
|
||||||
const h = createHistogram();
|
const h = createHistogram();
|
||||||
|
|
||||||
assert.strictEqual(h.min, 9223372036854776000);
|
strictEqual(h.min, 9223372036854776000);
|
||||||
assert.strictEqual(h.max, 0);
|
strictEqual(h.minBigInt, 9223372036854775807n);
|
||||||
assert.strictEqual(h.exceeds, 0);
|
strictEqual(h.max, 0);
|
||||||
assert(Number.isNaN(h.mean));
|
strictEqual(h.maxBigInt, 0n);
|
||||||
assert(Number.isNaN(h.stddev));
|
strictEqual(h.exceeds, 0);
|
||||||
|
strictEqual(h.exceedsBigInt, 0n);
|
||||||
|
ok(Number.isNaN(h.mean));
|
||||||
|
ok(Number.isNaN(h.stddev));
|
||||||
|
|
||||||
|
strictEqual(h.count, 0);
|
||||||
|
strictEqual(h.countBigInt, 0n);
|
||||||
|
|
||||||
h.record(1);
|
h.record(1);
|
||||||
|
|
||||||
|
strictEqual(h.count, 1);
|
||||||
|
strictEqual(h.countBigInt, 1n);
|
||||||
|
|
||||||
[false, '', {}, undefined, null].forEach((i) => {
|
[false, '', {}, undefined, null].forEach((i) => {
|
||||||
assert.throws(() => h.record(i), {
|
throws(() => h.record(i), {
|
||||||
code: 'ERR_INVALID_ARG_TYPE'
|
code: 'ERR_INVALID_ARG_TYPE'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
assert.throws(() => h.record(0, Number.MAX_SAFE_INTEGER + 1), {
|
throws(() => h.record(0, Number.MAX_SAFE_INTEGER + 1), {
|
||||||
code: 'ERR_OUT_OF_RANGE'
|
code: 'ERR_OUT_OF_RANGE'
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.strictEqual(h.min, 1);
|
strictEqual(h.min, 1);
|
||||||
assert.strictEqual(h.max, 1);
|
strictEqual(h.minBigInt, 1n);
|
||||||
assert.strictEqual(h.exceeds, 0);
|
strictEqual(h.max, 1);
|
||||||
assert.strictEqual(h.mean, 1);
|
strictEqual(h.maxBigInt, 1n);
|
||||||
assert.strictEqual(h.stddev, 0);
|
strictEqual(h.exceeds, 0);
|
||||||
|
strictEqual(h.mean, 1);
|
||||||
|
strictEqual(h.stddev, 0);
|
||||||
|
|
||||||
assert.strictEqual(h.percentile(1), 1);
|
strictEqual(h.percentile(1), 1);
|
||||||
assert.strictEqual(h.percentile(100), 1);
|
strictEqual(h.percentile(100), 1);
|
||||||
|
|
||||||
|
strictEqual(h.percentileBigInt(1), 1n);
|
||||||
|
strictEqual(h.percentileBigInt(100), 1n);
|
||||||
|
|
||||||
const mc = new MessageChannel();
|
const mc = new MessageChannel();
|
||||||
mc.port1.onmessage = common.mustCall(({ data }) => {
|
mc.port1.onmessage = common.mustCall(({ data }) => {
|
||||||
assert.strictEqual(h.min, 1);
|
strictEqual(h.min, 1);
|
||||||
assert.strictEqual(h.max, 1);
|
strictEqual(h.max, 1);
|
||||||
assert.strictEqual(h.exceeds, 0);
|
strictEqual(h.exceeds, 0);
|
||||||
assert.strictEqual(h.mean, 1);
|
strictEqual(h.mean, 1);
|
||||||
assert.strictEqual(h.stddev, 0);
|
strictEqual(h.stddev, 0);
|
||||||
|
|
||||||
data.record(2n);
|
data.record(2n);
|
||||||
data.recordDelta();
|
data.recordDelta();
|
||||||
|
|
||||||
assert.strictEqual(h.max, 2);
|
strictEqual(h.max, 2);
|
||||||
|
|
||||||
mc.port1.close();
|
mc.port1.close();
|
||||||
});
|
});
|
||||||
|
@ -57,13 +78,15 @@ const { inspect } = require('util');
|
||||||
|
|
||||||
{
|
{
|
||||||
const e = monitorEventLoopDelay();
|
const e = monitorEventLoopDelay();
|
||||||
|
strictEqual(e.count, 0);
|
||||||
e.enable();
|
e.enable();
|
||||||
const mc = new MessageChannel();
|
const mc = new MessageChannel();
|
||||||
mc.port1.onmessage = common.mustCall(({ data }) => {
|
mc.port1.onmessage = common.mustCall(({ data }) => {
|
||||||
assert(typeof data.min, 'number');
|
strictEqual(typeof data.min, 'number');
|
||||||
assert(data.min > 0);
|
ok(data.min > 0);
|
||||||
assert.strictEqual(data.disable, undefined);
|
ok(data.count > 0);
|
||||||
assert.strictEqual(data.enable, undefined);
|
strictEqual(data.disable, undefined);
|
||||||
|
strictEqual(data.enable, undefined);
|
||||||
mc.port1.close();
|
mc.port1.close();
|
||||||
});
|
});
|
||||||
setTimeout(() => mc.port2.postMessage(e), 100);
|
setTimeout(() => mc.port2.postMessage(e), 100);
|
||||||
|
@ -71,12 +94,66 @@ const { inspect } = require('util');
|
||||||
|
|
||||||
{
|
{
|
||||||
const h = createHistogram();
|
const h = createHistogram();
|
||||||
assert(inspect(h, { depth: null }).startsWith('Histogram'));
|
ok(inspect(h, { depth: null }).startsWith('Histogram'));
|
||||||
assert.strictEqual(inspect(h, { depth: -1 }), '[RecordableHistogram]');
|
strictEqual(inspect(h, { depth: -1 }), '[RecordableHistogram]');
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Tests that RecordableHistogram is impossible to construct manually
|
// Tests that RecordableHistogram is impossible to construct manually
|
||||||
const h = createHistogram();
|
const h = createHistogram();
|
||||||
assert.throws(() => new h.constructor(), { code: 'ERR_ILLEGAL_CONSTRUCTOR' });
|
throws(() => new h.constructor(), { code: 'ERR_ILLEGAL_CONSTRUCTOR' });
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
[
|
||||||
|
'hello',
|
||||||
|
1,
|
||||||
|
null,
|
||||||
|
].forEach((i) => {
|
||||||
|
throws(() => createHistogram(i), { code: 'ERR_INVALID_ARG_TYPE' });
|
||||||
|
});
|
||||||
|
|
||||||
|
[
|
||||||
|
'hello',
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
{},
|
||||||
|
].forEach((i) => {
|
||||||
|
throws(() => createHistogram({ lowest: i }), {
|
||||||
|
code: 'ERR_INVALID_ARG_TYPE',
|
||||||
|
});
|
||||||
|
throws(() => createHistogram({ highest: i }), {
|
||||||
|
code: 'ERR_INVALID_ARG_TYPE',
|
||||||
|
});
|
||||||
|
throws(() => createHistogram({ figures: i }), {
|
||||||
|
code: 'ERR_INVALID_ARG_TYPE',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
createHistogram({ lowest: 1, highest: 11, figures: 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const h1 = createHistogram();
|
||||||
|
const h2 = createHistogram();
|
||||||
|
|
||||||
|
h1.record(1);
|
||||||
|
|
||||||
|
strictEqual(h2.count, 0);
|
||||||
|
strictEqual(h1.count, 1);
|
||||||
|
|
||||||
|
h2.add(h1);
|
||||||
|
|
||||||
|
strictEqual(h2.count, 1);
|
||||||
|
|
||||||
|
[
|
||||||
|
'hello',
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
{},
|
||||||
|
].forEach((i) => {
|
||||||
|
throws(() => h1.add(i), {
|
||||||
|
code: 'ERR_INVALID_ARG_TYPE',
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue