• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const {
4  NumberIsNaN,
5  NumberIsInteger,
6  NumberMAX_SAFE_INTEGER,
7  ObjectSetPrototypeOf,
8  SafeMap,
9  Symbol,
10  TypeError,
11} = primordials;
12
13const {
14  Histogram: _Histogram
15} = internalBinding('performance');
16
17const {
18  customInspectSymbol: kInspect,
19} = require('internal/util');
20
21const { inspect } = require('util');
22
23const {
24  codes: {
25    ERR_INVALID_ARG_VALUE,
26    ERR_INVALID_ARG_TYPE,
27    ERR_OUT_OF_RANGE,
28  },
29} = require('internal/errors');
30
31const kDestroy = Symbol('kDestroy');
32const kHandle = Symbol('kHandle');
33const kMap = Symbol('kMap');
34
35const {
36  kClone,
37  kDeserialize,
38  JSTransferable,
39} = require('internal/worker/js_transferable');
40
41class Histogram extends JSTransferable {
42  constructor(internal) {
43    super();
44    this[kHandle] = internal;
45    this[kMap] = new SafeMap();
46  }
47
48  [kInspect](depth, options) {
49    if (depth < 0)
50      return this;
51
52    const opts = {
53      ...options,
54      depth: options.depth == null ? null : options.depth - 1
55    };
56
57    return `Histogram ${inspect({
58      min: this.min,
59      max: this.max,
60      mean: this.mean,
61      exceeds: this.exceeds,
62      stddev: this.stddev,
63      percentiles: this.percentiles,
64    }, opts)}`;
65  }
66
67  get min() {
68    return this[kHandle]?.min();
69  }
70
71  get max() {
72    return this[kHandle]?.max();
73  }
74
75  get mean() {
76    return this[kHandle]?.mean();
77  }
78
79  get exceeds() {
80    return this[kHandle]?.exceeds();
81  }
82
83  get stddev() {
84    return this[kHandle]?.stddev();
85  }
86
87  percentile(percentile) {
88    if (typeof percentile !== 'number')
89      throw new ERR_INVALID_ARG_TYPE('percentile', 'number', percentile);
90
91    if (NumberIsNaN(percentile) || percentile <= 0 || percentile > 100)
92      throw new ERR_INVALID_ARG_VALUE.RangeError('percentile', percentile);
93
94    return this[kHandle]?.percentile(percentile);
95  }
96
97  get percentiles() {
98    this[kMap].clear();
99    this[kHandle]?.percentiles(this[kMap]);
100    return this[kMap];
101  }
102
103  reset() {
104    this[kHandle]?.reset();
105  }
106
107  [kDestroy]() {
108    this[kHandle] = undefined;
109  }
110
111  [kClone]() {
112    const handle = this[kHandle];
113    return {
114      data: { handle },
115      deserializeInfo: 'internal/histogram:InternalHistogram'
116    };
117  }
118
119  [kDeserialize]({ handle }) {
120    this[kHandle] = handle;
121  }
122}
123
124class RecordableHistogram extends Histogram {
125  constructor() {
126    // eslint-disable-next-line no-restricted-syntax
127    throw new TypeError('illegal constructor');
128  }
129
130  record(val) {
131    if (typeof val === 'bigint') {
132      this[kHandle]?.record(val);
133      return;
134    }
135
136    if (!NumberIsInteger(val))
137      throw new ERR_INVALID_ARG_TYPE('val', ['integer', 'bigint'], val);
138
139    if (val < 1 || val > NumberMAX_SAFE_INTEGER)
140      throw new ERR_OUT_OF_RANGE('val', 'a safe integer greater than 0', val);
141
142    this[kHandle]?.record(val);
143  }
144
145  recordDelta() {
146    this[kHandle]?.recordDelta();
147  }
148
149  [kClone]() {
150    const handle = this[kHandle];
151    return {
152      data: { handle },
153      deserializeInfo: 'internal/histogram:InternalRecordableHistogram'
154    };
155  }
156}
157
158class InternalHistogram extends JSTransferable {
159  constructor(handle) {
160    super();
161    this[kHandle] = handle;
162    this[kMap] = new SafeMap();
163  }
164}
165
166class InternalRecordableHistogram extends JSTransferable {
167  constructor(handle) {
168    super();
169    this[kHandle] = handle;
170    this[kMap] = new SafeMap();
171  }
172}
173
174InternalHistogram.prototype.constructor = Histogram;
175ObjectSetPrototypeOf(
176  InternalHistogram.prototype,
177  Histogram.prototype);
178
179InternalRecordableHistogram.prototype.constructor = RecordableHistogram;
180ObjectSetPrototypeOf(
181  InternalRecordableHistogram.prototype,
182  RecordableHistogram.prototype);
183
184function createHistogram() {
185  return new InternalRecordableHistogram(new _Histogram());
186}
187
188module.exports = {
189  Histogram,
190  RecordableHistogram,
191  InternalHistogram,
192  InternalRecordableHistogram,
193  kDestroy,
194  kHandle,
195  createHistogram,
196};
197