Skip to content

Commit 51a57f2

Browse files
authored
perf_hooks: move non-standard performance properties to perf_hooks
`performance.eventLoopUtilization` and `performance.timerify` are not part of the Web API. Expose these two functions directly on the `perf_hooks` module. PR-URL: nodejs/node#60370 Fixes: nodejs/node#60368 Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Marco Ippolito <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
1 parent 4fe325d commit 51a57f2

File tree

6 files changed

+186
-131
lines changed

6 files changed

+186
-131
lines changed

doc/api/perf_hooks.md

Lines changed: 155 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ the Resource Timeline. If `name` is provided, removes only the named resource.
120120
added:
121121
- v14.10.0
122122
- v12.19.0
123+
changes:
124+
- version: REPLACEME
125+
pr-url: https://github.com/nodejs/node/pull/60370
126+
description: Added `perf_hooks.eventLoopUtilization` alias.
123127
-->
124128

125129
* `utilization1` {Object} The result of a previous call to
@@ -131,62 +135,9 @@ added:
131135
* `active` {number}
132136
* `utilization` {number}
133137

134-
The `eventLoopUtilization()` method returns an object that contains the
135-
cumulative duration of time the event loop has been both idle and active as a
136-
high resolution milliseconds timer. The `utilization` value is the calculated
137-
Event Loop Utilization (ELU).
138-
139-
If bootstrapping has not yet finished on the main thread the properties have
140-
the value of `0`. The ELU is immediately available on [Worker threads][] since
141-
bootstrap happens within the event loop.
142-
143-
Both `utilization1` and `utilization2` are optional parameters.
144-
145-
If `utilization1` is passed, then the delta between the current call's `active`
146-
and `idle` times, as well as the corresponding `utilization` value are
147-
calculated and returned (similar to [`process.hrtime()`][]).
138+
This is an alias of [`perf_hooks.eventLoopUtilization()`][].
148139

149-
If `utilization1` and `utilization2` are both passed, then the delta is
150-
calculated between the two arguments. This is a convenience option because,
151-
unlike [`process.hrtime()`][], calculating the ELU is more complex than a
152-
single subtraction.
153-
154-
ELU is similar to CPU utilization, except that it only measures event loop
155-
statistics and not CPU usage. It represents the percentage of time the event
156-
loop has spent outside the event loop's event provider (e.g. `epoll_wait`).
157-
No other CPU idle time is taken into consideration. The following is an example
158-
of how a mostly idle process will have a high ELU.
159-
160-
```mjs
161-
import { eventLoopUtilization } from 'node:perf_hooks';
162-
import { spawnSync } from 'node:child_process';
163-
164-
setImmediate(() => {
165-
const elu = eventLoopUtilization();
166-
spawnSync('sleep', ['5']);
167-
console.log(eventLoopUtilization(elu).utilization);
168-
});
169-
```
170-
171-
```cjs
172-
'use strict';
173-
const { eventLoopUtilization } = require('node:perf_hooks').performance;
174-
const { spawnSync } = require('node:child_process');
175-
176-
setImmediate(() => {
177-
const elu = eventLoopUtilization();
178-
spawnSync('sleep', ['5']);
179-
console.log(eventLoopUtilization(elu).utilization);
180-
});
181-
```
182-
183-
Although the CPU is mostly idle while running this script, the value of
184-
`utilization` is `1`. This is because the call to
185-
[`child_process.spawnSync()`][] blocks the event loop from proceeding.
186-
187-
Passing in a user-defined object instead of the result of a previous call to
188-
`eventLoopUtilization()` will lead to undefined behavior. The return values
189-
are not guaranteed to reflect any correct state of the event loop.
140+
_This property is an extension by Node.js. It is not available in Web browsers._
190141

191142
### `performance.getEntries()`
192143

@@ -424,6 +375,9 @@ which the current `node` process began, measured in Unix time.
424375
<!-- YAML
425376
added: v8.5.0
426377
changes:
378+
- version: REPLACEME
379+
pr-url: https://github.com/nodejs/node/pull/60370
380+
description: Added `perf_hooks.timerify` alias.
427381
- version: v16.0.0
428382
pr-url: https://github.com/nodejs/node/pull/37475
429383
description: Added the histogram option.
@@ -439,62 +393,9 @@ changes:
439393
`perf_hooks.createHistogram()` that will record runtime durations in
440394
nanoseconds.
441395

442-
_This property is an extension by Node.js. It is not available in Web browsers._
396+
This is an alias of [`perf_hooks.timerify()`][].
443397

444-
Wraps a function within a new function that measures the running time of the
445-
wrapped function. A `PerformanceObserver` must be subscribed to the `'function'`
446-
event type in order for the timing details to be accessed.
447-
448-
```mjs
449-
import { performance, PerformanceObserver } from 'node:perf_hooks';
450-
451-
function someFunction() {
452-
console.log('hello world');
453-
}
454-
455-
const wrapped = performance.timerify(someFunction);
456-
457-
const obs = new PerformanceObserver((list) => {
458-
console.log(list.getEntries()[0].duration);
459-
460-
performance.clearMarks();
461-
performance.clearMeasures();
462-
obs.disconnect();
463-
});
464-
obs.observe({ entryTypes: ['function'] });
465-
466-
// A performance timeline entry will be created
467-
wrapped();
468-
```
469-
470-
```cjs
471-
const {
472-
performance,
473-
PerformanceObserver,
474-
} = require('node:perf_hooks');
475-
476-
function someFunction() {
477-
console.log('hello world');
478-
}
479-
480-
const wrapped = performance.timerify(someFunction);
481-
482-
const obs = new PerformanceObserver((list) => {
483-
console.log(list.getEntries()[0].duration);
484-
485-
performance.clearMarks();
486-
performance.clearMeasures();
487-
obs.disconnect();
488-
});
489-
obs.observe({ entryTypes: ['function'] });
490-
491-
// A performance timeline entry will be created
492-
wrapped();
493-
```
494-
495-
If the wrapped function returns a promise, a finally handler will be attached
496-
to the promise and the duration will be reported once the finally handler is
497-
invoked.
398+
_This property is an extension by Node.js. It is not available in Web browsers._
498399

499400
### `performance.toJSON()`
500401

@@ -1722,6 +1623,78 @@ added:
17221623

17231624
Returns a {RecordableHistogram}.
17241625

1626+
## `perf_hooks.eventLoopUtilization([utilization1[, utilization2]])`
1627+
1628+
<!-- YAML
1629+
added: REPLACEME
1630+
-->
1631+
1632+
* `utilization1` {Object} The result of a previous call to
1633+
`eventLoopUtilization()`.
1634+
* `utilization2` {Object} The result of a previous call to
1635+
`eventLoopUtilization()` prior to `utilization1`.
1636+
* Returns: {Object}
1637+
* `idle` {number}
1638+
* `active` {number}
1639+
* `utilization` {number}
1640+
1641+
The `eventLoopUtilization()` function returns an object that contains the
1642+
cumulative duration of time the event loop has been both idle and active as a
1643+
high resolution milliseconds timer. The `utilization` value is the calculated
1644+
Event Loop Utilization (ELU).
1645+
1646+
If bootstrapping has not yet finished on the main thread the properties have
1647+
the value of `0`. The ELU is immediately available on [Worker threads][] since
1648+
bootstrap happens within the event loop.
1649+
1650+
Both `utilization1` and `utilization2` are optional parameters.
1651+
1652+
If `utilization1` is passed, then the delta between the current call's `active`
1653+
and `idle` times, as well as the corresponding `utilization` value are
1654+
calculated and returned (similar to [`process.hrtime()`][]).
1655+
1656+
If `utilization1` and `utilization2` are both passed, then the delta is
1657+
calculated between the two arguments. This is a convenience option because,
1658+
unlike [`process.hrtime()`][], calculating the ELU is more complex than a
1659+
single subtraction.
1660+
1661+
ELU is similar to CPU utilization, except that it only measures event loop
1662+
statistics and not CPU usage. It represents the percentage of time the event
1663+
loop has spent outside the event loop's event provider (e.g. `epoll_wait`).
1664+
No other CPU idle time is taken into consideration. The following is an example
1665+
of how a mostly idle process will have a high ELU.
1666+
1667+
```mjs
1668+
import { eventLoopUtilization } from 'node:perf_hooks';
1669+
import { spawnSync } from 'node:child_process';
1670+
1671+
setImmediate(() => {
1672+
const elu = eventLoopUtilization();
1673+
spawnSync('sleep', ['5']);
1674+
console.log(eventLoopUtilization(elu).utilization);
1675+
});
1676+
```
1677+
1678+
```cjs
1679+
'use strict';
1680+
const { eventLoopUtilization } = require('node:perf_hooks');
1681+
const { spawnSync } = require('node:child_process');
1682+
1683+
setImmediate(() => {
1684+
const elu = eventLoopUtilization();
1685+
spawnSync('sleep', ['5']);
1686+
console.log(eventLoopUtilization(elu).utilization);
1687+
});
1688+
```
1689+
1690+
Although the CPU is mostly idle while running this script, the value of
1691+
`utilization` is `1`. This is because the call to
1692+
[`child_process.spawnSync()`][] blocks the event loop from proceeding.
1693+
1694+
Passing in a user-defined object instead of the result of a previous call to
1695+
`eventLoopUtilization()` will lead to undefined behavior. The return values
1696+
are not guaranteed to reflect any correct state of the event loop.
1697+
17251698
## `perf_hooks.monitorEventLoopDelay([options])`
17261699

17271700
<!-- YAML
@@ -1775,6 +1748,76 @@ console.log(h.percentile(50));
17751748
console.log(h.percentile(99));
17761749
```
17771750

1751+
## `perf_hooks.timerify(fn[, options])`
1752+
1753+
<!-- YAML
1754+
added: REPLACEME
1755+
-->
1756+
1757+
* `fn` {Function}
1758+
* `options` {Object}
1759+
* `histogram` {RecordableHistogram} A histogram object created using
1760+
`perf_hooks.createHistogram()` that will record runtime durations in
1761+
nanoseconds.
1762+
1763+
_This property is an extension by Node.js. It is not available in Web browsers._
1764+
1765+
Wraps a function within a new function that measures the running time of the
1766+
wrapped function. A `PerformanceObserver` must be subscribed to the `'function'`
1767+
event type in order for the timing details to be accessed.
1768+
1769+
```mjs
1770+
import { timerify, performance, PerformanceObserver } from 'node:perf_hooks';
1771+
1772+
function someFunction() {
1773+
console.log('hello world');
1774+
}
1775+
1776+
const wrapped = timerify(someFunction);
1777+
1778+
const obs = new PerformanceObserver((list) => {
1779+
console.log(list.getEntries()[0].duration);
1780+
1781+
performance.clearMarks();
1782+
performance.clearMeasures();
1783+
obs.disconnect();
1784+
});
1785+
obs.observe({ entryTypes: ['function'] });
1786+
1787+
// A performance timeline entry will be created
1788+
wrapped();
1789+
```
1790+
1791+
```cjs
1792+
const {
1793+
timerify,
1794+
performance,
1795+
PerformanceObserver,
1796+
} = require('node:perf_hooks');
1797+
1798+
function someFunction() {
1799+
console.log('hello world');
1800+
}
1801+
1802+
const wrapped = timerify(someFunction);
1803+
1804+
const obs = new PerformanceObserver((list) => {
1805+
console.log(list.getEntries()[0].duration);
1806+
1807+
performance.clearMarks();
1808+
performance.clearMeasures();
1809+
obs.disconnect();
1810+
});
1811+
obs.observe({ entryTypes: ['function'] });
1812+
1813+
// A performance timeline entry will be created
1814+
wrapped();
1815+
```
1816+
1817+
If the wrapped function returns a promise, a finally handler will be attached
1818+
to the promise and the duration will be reported once the finally handler is
1819+
invoked.
1820+
17781821
## Class: `Histogram`
17791822

17801823
<!-- YAML
@@ -2306,6 +2349,8 @@ dns.promises.resolve('localhost');
23062349
[Worker threads]: worker_threads.md#worker-threads
23072350
[`'exit'`]: process.md#event-exit
23082351
[`child_process.spawnSync()`]: child_process.md#child_processspawnsynccommand-args-options
2352+
[`perf_hooks.eventLoopUtilization()`]: #perf_hookseventlooputilizationutilization1-utilization2
2353+
[`perf_hooks.timerify()`]: #perf_hookstimerifyfn-options
23092354
[`process.hrtime()`]: process.md#processhrtimetime
23102355
[`timeOrigin`]: https://w3c.github.io/hr-time/#dom-performance-timeorigin
23112356
[`window.performance.toJSON`]: https://developer.mozilla.org/en-US/docs/Web/API/Performance/toJSON

doc/api/worker_threads.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,7 +1838,7 @@ added:
18381838
-->
18391839

18401840
An object that can be used to query performance information from a worker
1841-
instance. Similar to [`perf_hooks.performance`][].
1841+
instance.
18421842

18431843
#### `performance.eventLoopUtilization([utilization1[, utilization2]])`
18441844

@@ -2240,8 +2240,7 @@ thread spawned will spawn another until the application crashes.
22402240
[`fs.open()`]: fs.md#fsopenpath-flags-mode-callback
22412241
[`markAsUntransferable()`]: #worker_threadsmarkasuntransferableobject
22422242
[`node:cluster` module]: cluster.md
2243-
[`perf_hooks.performance`]: perf_hooks.md#perf_hooksperformance
2244-
[`perf_hooks` `eventLoopUtilization()`]: perf_hooks.md#performanceeventlooputilizationutilization1-utilization2
2243+
[`perf_hooks` `eventLoopUtilization()`]: perf_hooks.md#perf_hookseventlooputilizationutilization1-utilization2
22452244
[`port.on('message')`]: #event-message
22462245
[`port.onmessage()`]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort/onmessage
22472246
[`port.postMessage()`]: #portpostmessagevalue-transferlist

lib/perf_hooks.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ const {
2828
} = require('internal/histogram');
2929

3030
const monitorEventLoopDelay = require('internal/perf/event_loop_delay');
31+
const { eventLoopUtilization } = require('internal/perf/event_loop_utilization');
32+
const timerify = require('internal/perf/timerify');
3133

3234
module.exports = {
3335
Performance,
@@ -38,6 +40,8 @@ module.exports = {
3840
PerformanceObserverEntryList,
3941
PerformanceResourceTiming,
4042
monitorEventLoopDelay,
43+
eventLoopUtilization,
44+
timerify,
4145
createHistogram,
4246
performance,
4347
};

test/parallel/test-performance-eventlooputil.js renamed to test/parallel/test-perf-hooks-eventlooputilization.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ const TIMEOUT = 10;
66
const SPIN_DUR = 50;
77

88
const assert = require('assert');
9-
const { performance } = require('perf_hooks');
9+
const { performance, eventLoopUtilization } = require('perf_hooks');
1010
const { Worker, parentPort } = require('worker_threads');
1111

12-
const { nodeTiming, eventLoopUtilization } = performance;
12+
// Verifies that `performance.eventLoopUtilization` is an alias of
13+
// `perf_hooks.eventLoopUtilization`.
14+
assert.strictEqual(performance.eventLoopUtilization, eventLoopUtilization);
15+
const { nodeTiming } = performance;
1316
const elu = eventLoopUtilization();
1417

1518
// Take into account whether this test was started as a Worker.

0 commit comments

Comments
 (0)