perf_hooks: reduce overhead of createHistogram

PR-URL: https://github.com/nodejs/node/pull/50074
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
This commit is contained in:
Vinícius Lourenço 2023-10-05 21:39:55 -03:00 committed by Node.js GitHub Bot
parent 8e814e3b82
commit adaef03216
3 changed files with 82 additions and 20 deletions

View File

@ -0,0 +1,24 @@
'use strict';
const assert = require('assert');
const common = require('../common.js');
const { createHistogram } = require('perf_hooks');
const bench = common.createBenchmark(main, {
n: [1e5],
});
let _histogram;
function main({ n }) {
const histogram = createHistogram();
bench.start();
for (let i = 0; i < n; i++)
_histogram = structuredClone(histogram);
bench.end(n);
// Avoid V8 deadcode (elimination)
assert.ok(_histogram);
}

View File

@ -0,0 +1,22 @@
'use strict';
const assert = require('assert');
const common = require('../common.js');
const { createHistogram } = require('perf_hooks');
const bench = common.createBenchmark(main, {
n: [1e5],
});
let _histogram;
function main({ n }) {
bench.start();
for (let i = 0; i < n; i++)
_histogram = createHistogram();
bench.end(n);
// Avoid V8 deadcode (elimination)
assert.ok(_histogram);
}

View File

@ -52,9 +52,13 @@ function isHistogram(object) {
return object?.[kHandle] !== undefined; return object?.[kHandle] !== undefined;
} }
const kSkipThrow = Symbol('kSkipThrow');
class Histogram { class Histogram {
constructor() { constructor(skipThrowSymbol = undefined) {
throw new ERR_ILLEGAL_CONSTRUCTOR(); if (skipThrowSymbol !== kSkipThrow) {
throw new ERR_ILLEGAL_CONSTRUCTOR();
}
} }
[kInspect](depth, options) { [kInspect](depth, options) {
@ -242,7 +246,7 @@ class Histogram {
const handle = this[kHandle]; const handle = this[kHandle];
return { return {
data: { handle }, data: { handle },
deserializeInfo: 'internal/histogram:internalHistogram', deserializeInfo: 'internal/histogram:ClonedHistogram',
}; };
} }
@ -264,8 +268,12 @@ class Histogram {
} }
class RecordableHistogram extends Histogram { class RecordableHistogram extends Histogram {
constructor() { constructor(skipThrowSymbol = undefined) {
throw new ERR_ILLEGAL_CONSTRUCTOR(); if (skipThrowSymbol !== kSkipThrow) {
throw new ERR_ILLEGAL_CONSTRUCTOR();
}
super(skipThrowSymbol);
} }
/** /**
@ -309,7 +317,7 @@ class RecordableHistogram extends Histogram {
const handle = this[kHandle]; const handle = this[kHandle];
return { return {
data: { handle }, data: { handle },
deserializeInfo: 'internal/histogram:internalRecordableHistogram', deserializeInfo: 'internal/histogram:ClonedRecordableHistogram',
}; };
} }
@ -318,7 +326,7 @@ class RecordableHistogram extends Histogram {
} }
} }
function internalHistogram(handle) { function ClonedHistogram(handle) {
return ReflectConstruct( return ReflectConstruct(
function() { function() {
markTransferMode(this, true, false); markTransferMode(this, true, false);
@ -326,18 +334,26 @@ function internalHistogram(handle) {
this[kMap] = new SafeMap(); this[kMap] = new SafeMap();
}, [], Histogram); }, [], Histogram);
} }
internalHistogram.prototype[kDeserialize] = () => {};
function internalRecordableHistogram(handle) { ClonedHistogram.prototype[kDeserialize] = () => { };
return ReflectConstruct(
function() { function ClonedRecordableHistogram(handle) {
markTransferMode(this, true, false); const histogram = new RecordableHistogram(kSkipThrow);
this[kHandle] = handle;
this[kMap] = new SafeMap(); markTransferMode(histogram, true, false);
this[kRecordable] = true; histogram[kRecordable] = true;
}, [], RecordableHistogram); histogram[kMap] = new SafeMap();
histogram[kHandle] = handle;
histogram.constructor = RecordableHistogram;
return histogram;
}
ClonedRecordableHistogram.prototype[kDeserialize] = () => { };
function createRecordableHistogram(handle) {
return new ClonedRecordableHistogram(handle);
} }
internalRecordableHistogram.prototype[kDeserialize] = () => {};
/** /**
* @param {{ * @param {{
@ -363,14 +379,14 @@ function createHistogram(options = kEmptyObject) {
throw new ERR_INVALID_ARG_VALUE.RangeError('options.highest', highest); throw new ERR_INVALID_ARG_VALUE.RangeError('options.highest', highest);
} }
validateInteger(figures, 'options.figures', 1, 5); validateInteger(figures, 'options.figures', 1, 5);
return internalRecordableHistogram(new _Histogram(lowest, highest, figures)); return createRecordableHistogram(new _Histogram(lowest, highest, figures));
} }
module.exports = { module.exports = {
Histogram, Histogram,
RecordableHistogram, RecordableHistogram,
internalHistogram, ClonedHistogram,
internalRecordableHistogram, ClonedRecordableHistogram,
isHistogram, isHistogram,
kDestroy, kDestroy,
kHandle, kHandle,