Skip to content

Commit 9f5a10d

Browse files
committed
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.
1 parent f0679db commit 9f5a10d

File tree

6 files changed

+179
-131
lines changed

6 files changed

+179
-131
lines changed

doc/api/perf_hooks.md

Lines changed: 148 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -131,62 +131,9 @@ added:
131131
* `active` {number}
132132
* `utilization` {number}
133133

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()`][]).
148-
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.
134+
This is an alias of [`perf_hooks.eventLoopUtilization()`][].
186135

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.
136+
_This property is an extension by Node.js. It is not available in Web browsers._
190137

191138
### `performance.getEntries()`
192139

@@ -439,62 +386,9 @@ changes:
439386
`perf_hooks.createHistogram()` that will record runtime durations in
440387
nanoseconds.
441388

442-
_This property is an extension by Node.js. It is not available in Web browsers._
443-
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-
}
389+
This is an alias of [`perf_hooks.timerify()`][].
479390

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.
391+
_This property is an extension by Node.js. It is not available in Web browsers._
498392

499393
### `performance.toJSON()`
500394

@@ -1722,6 +1616,78 @@ added:
17221616

17231617
Returns a {RecordableHistogram}.
17241618

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

17271693
<!-- YAML
@@ -1775,6 +1741,76 @@ console.log(h.percentile(50));
17751741
console.log(h.percentile(99));
17761742
```
17771743

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

17801816
<!-- YAML
@@ -2310,3 +2346,5 @@ dns.promises.resolve('localhost');
23102346
[`timeOrigin`]: https://w3c.github.io/hr-time/#dom-performance-timeorigin
23112347
[`window.performance.toJSON`]: https://developer.mozilla.org/en-US/docs/Web/API/Performance/toJSON
23122348
[`window.performance`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/performance
2349+
[`perf_hooks.eventLoopUtilization()`]: #perf_hookseventlooputilizationutilization1-utilization2
2350+
[`perf_hooks.timerify()`]: #perf_hookstimerifyfn-options

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)