diff --git a/benchmark/perf_hooks/histogram-clone.js b/benchmark/perf_hooks/histogram-clone.js new file mode 100644 index 00000000000000..4b610963fa2a0a --- /dev/null +++ b/benchmark/perf_hooks/histogram-clone.js @@ -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); +} diff --git a/benchmark/perf_hooks/histogram-create.js b/benchmark/perf_hooks/histogram-create.js new file mode 100644 index 00000000000000..89ddad1fa79224 --- /dev/null +++ b/benchmark/perf_hooks/histogram-create.js @@ -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); +} diff --git a/lib/internal/histogram.js b/lib/internal/histogram.js index 079fbce50d54e3..cb757313009dc0 100644 --- a/lib/internal/histogram.js +++ b/lib/internal/histogram.js @@ -52,9 +52,13 @@ function isHistogram(object) { return object?.[kHandle] !== undefined; } +const kSkipThrow = Symbol('kSkipThrow'); + class Histogram { - constructor() { - throw new ERR_ILLEGAL_CONSTRUCTOR(); + constructor(skipThrowSymbol = undefined) { + if (skipThrowSymbol !== kSkipThrow) { + throw new ERR_ILLEGAL_CONSTRUCTOR(); + } } [kInspect](depth, options) { @@ -242,7 +246,7 @@ class Histogram { const handle = this[kHandle]; return { data: { handle }, - deserializeInfo: 'internal/histogram:internalHistogram', + deserializeInfo: 'internal/histogram:ClonedHistogram', }; } @@ -264,8 +268,12 @@ class Histogram { } class RecordableHistogram extends Histogram { - constructor() { - throw new ERR_ILLEGAL_CONSTRUCTOR(); + constructor(skipThrowSymbol = undefined) { + if (skipThrowSymbol !== kSkipThrow) { + throw new ERR_ILLEGAL_CONSTRUCTOR(); + } + + super(skipThrowSymbol); } /** @@ -309,7 +317,7 @@ class RecordableHistogram extends Histogram { const handle = this[kHandle]; return { 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( function() { markTransferMode(this, true, false); @@ -326,18 +334,26 @@ function internalHistogram(handle) { this[kMap] = new SafeMap(); }, [], Histogram); } -internalHistogram.prototype[kDeserialize] = () => {}; -function internalRecordableHistogram(handle) { - return ReflectConstruct( - function() { - markTransferMode(this, true, false); - this[kHandle] = handle; - this[kMap] = new SafeMap(); - this[kRecordable] = true; - }, [], RecordableHistogram); +ClonedHistogram.prototype[kDeserialize] = () => { }; + +function ClonedRecordableHistogram(handle) { + const histogram = new RecordableHistogram(kSkipThrow); + + markTransferMode(histogram, true, false); + histogram[kRecordable] = true; + 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 {{ @@ -363,14 +379,14 @@ function createHistogram(options = kEmptyObject) { throw new ERR_INVALID_ARG_VALUE.RangeError('options.highest', highest); } validateInteger(figures, 'options.figures', 1, 5); - return internalRecordableHistogram(new _Histogram(lowest, highest, figures)); + return createRecordableHistogram(new _Histogram(lowest, highest, figures)); } module.exports = { Histogram, RecordableHistogram, - internalHistogram, - internalRecordableHistogram, + ClonedHistogram, + ClonedRecordableHistogram, isHistogram, kDestroy, kHandle,