xref: /third_party/node/lib/internal/perf/timerify.js (revision 1cb0ef41)
1'use strict';
2
3const {
4  FunctionPrototypeBind,
5  ObjectDefineProperties,
6  MathCeil,
7  ReflectApply,
8  ReflectConstruct,
9} = primordials;
10
11const { InternalPerformanceEntry } = require('internal/perf/performance_entry');
12const { now } = require('internal/perf/utils');
13
14const {
15  validateFunction,
16  validateObject,
17} = require('internal/validators');
18
19const {
20  isHistogram,
21} = require('internal/histogram');
22
23const {
24  codes: {
25    ERR_INVALID_ARG_TYPE,
26  },
27} = require('internal/errors');
28
29const {
30  enqueue,
31} = require('internal/perf/observe');
32
33const {
34  kEmptyObject,
35} = require('internal/util');
36
37function processComplete(name, start, args, histogram) {
38  const duration = now() - start;
39  if (histogram !== undefined)
40    histogram.record(MathCeil(duration * 1e6));
41  const entry =
42    new InternalPerformanceEntry(
43      name,
44      'function',
45      start,
46      duration,
47      args);
48
49  for (let n = 0; n < args.length; n++)
50    entry[n] = args[n];
51
52  enqueue(entry);
53}
54
55function timerify(fn, options = kEmptyObject) {
56  validateFunction(fn, 'fn');
57
58  validateObject(options, 'options');
59  const {
60    histogram,
61  } = options;
62
63  if (histogram !== undefined &&
64      (!isHistogram(histogram) || typeof histogram.record !== 'function')) {
65    throw new ERR_INVALID_ARG_TYPE(
66      'options.histogram',
67      'RecordableHistogram',
68      histogram);
69  }
70
71  function timerified(...args) {
72    const isConstructorCall = new.target !== undefined;
73    const start = now();
74    const result = isConstructorCall ?
75      ReflectConstruct(fn, args, fn) :
76      ReflectApply(fn, this, args);
77    if (!isConstructorCall && typeof result?.finally === 'function') {
78      return result.finally(
79        FunctionPrototypeBind(
80          processComplete,
81          result,
82          fn.name,
83          start,
84          args,
85          histogram));
86    }
87    processComplete(fn.name, start, args, histogram);
88    return result;
89  }
90
91  ObjectDefineProperties(timerified, {
92    length: {
93      __proto__: null,
94      configurable: false,
95      enumerable: true,
96      value: fn.length,
97    },
98    name: {
99      __proto__: null,
100      configurable: false,
101      enumerable: true,
102      value: `timerified ${fn.name}`,
103    },
104  });
105
106  return timerified;
107}
108
109module.exports = timerify;
110