Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 717d9a7

Browse filesBrowse files
IlyasShabiaduh95
authored andcommitted
v8: add heap profile API
PR-URL: #62273 Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 761a967 commit 717d9a7
Copy full SHA for 717d9a7

12 files changed

+518-70Lines changed: 518 additions & 70 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎doc/api/v8.md‎

Copy file name to clipboardExpand all lines: doc/api/v8.md
+92Lines changed: 92 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -1617,6 +1617,32 @@ added:
16171617
16181618
Stopping collecting the profile and the profile will be discarded.
16191619
1620+
## Class: `SyncHeapProfileHandle`
1621+
1622+
<!-- YAML
1623+
added: REPLACEME
1624+
-->
1625+
1626+
> Stability: 1 - Experimental
1627+
1628+
### `syncHeapProfileHandle.stop()`
1629+
1630+
<!-- YAML
1631+
added: REPLACEME
1632+
-->
1633+
1634+
* Returns: {string}
1635+
1636+
Stopping collecting the profile and return the profile data.
1637+
1638+
### `syncHeapProfileHandle[Symbol.dispose]()`
1639+
1640+
<!-- YAML
1641+
added: REPLACEME
1642+
-->
1643+
1644+
Stopping collecting the profile and the profile will be discarded.
1645+
16201646
## Class: `CPUProfileHandle`
16211647
16221648
<!-- YAML
@@ -1764,6 +1790,72 @@ const profile = handle.stop();
17641790
console.log(profile);
17651791
```
17661792
1793+
## `v8.startHeapProfile([options])`
1794+
1795+
<!-- YAML
1796+
added: REPLACEME
1797+
-->
1798+
1799+
* `options` {Object}
1800+
* `sampleInterval` {number} The average sampling interval in bytes.
1801+
**Default:** `524288` (512 KiB).
1802+
* `stackDepth` {integer} The maximum stack depth for samples.
1803+
**Default:** `16`.
1804+
* `forceGC` {boolean} Force garbage collection before taking the profile.
1805+
**Default:** `false`.
1806+
* `includeObjectsCollectedByMajorGC` {boolean} Include objects collected
1807+
by major GC. **Default:** `false`.
1808+
* `includeObjectsCollectedByMinorGC` {boolean} Include objects collected
1809+
by minor GC. **Default:** `false`.
1810+
* Returns: {SyncHeapProfileHandle}
1811+
1812+
Starting a heap profile then return a `SyncHeapProfileHandle` object.
1813+
This API supports `using` syntax.
1814+
1815+
```cjs
1816+
const v8 = require('node:v8');
1817+
1818+
const handle = v8.startHeapProfile();
1819+
const profile = handle.stop();
1820+
console.log(profile);
1821+
```
1822+
1823+
```mjs
1824+
import v8 from 'node:v8';
1825+
1826+
const handle = v8.startHeapProfile();
1827+
const profile = handle.stop();
1828+
console.log(profile);
1829+
```
1830+
1831+
With custom parameters:
1832+
1833+
```cjs
1834+
const v8 = require('node:v8');
1835+
1836+
const handle = v8.startHeapProfile({
1837+
sampleInterval: 1024,
1838+
stackDepth: 8,
1839+
forceGC: true,
1840+
includeObjectsCollectedByMajorGC: true,
1841+
});
1842+
const profile = handle.stop();
1843+
console.log(profile);
1844+
```
1845+
1846+
```mjs
1847+
import v8 from 'node:v8';
1848+
1849+
const handle = v8.startHeapProfile({
1850+
sampleInterval: 1024,
1851+
stackDepth: 8,
1852+
forceGC: true,
1853+
includeObjectsCollectedByMajorGC: true,
1854+
});
1855+
const profile = handle.stop();
1856+
console.log(profile);
1857+
```
1858+
17671859
[CppHeap]: https://v8docs.nodesource.com/node-22.4/d9/dc4/classv8_1_1_cpp_heap.html
17681860
[HTML structured clone algorithm]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
17691861
[Hook Callbacks]: #hook-callbacks
Collapse file

‎doc/api/worker_threads.md‎

Copy file name to clipboardExpand all lines: doc/api/worker_threads.md
+42-1Lines changed: 42 additions & 1 deletion
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -2005,14 +2005,25 @@ w.on('online', async () => {
20052005
});
20062006
```
20072007
2008-
### `worker.startHeapProfile()`
2008+
### `worker.startHeapProfile([options])`
20092009
20102010
<!-- YAML
20112011
added:
20122012
- v24.9.0
20132013
- v22.20.0
20142014
-->
20152015
2016+
* `options` {Object}
2017+
* `sampleInterval` {number} The average sampling interval in bytes.
2018+
**Default:** `524288` (512 KiB).
2019+
* `stackDepth` {integer} The maximum stack depth for samples.
2020+
**Default:** `16`.
2021+
* `forceGC` {boolean} Force garbage collection before taking the profile.
2022+
**Default:** `false`.
2023+
* `includeObjectsCollectedByMajorGC` {boolean} Include objects collected
2024+
by major GC. **Default:** `false`.
2025+
* `includeObjectsCollectedByMinorGC` {boolean} Include objects collected
2026+
by minor GC. **Default:** `false`.
20162027
* Returns: {Promise}
20172028
20182029
Starting a Heap profile then return a Promise that fulfills with an error
@@ -2034,6 +2045,22 @@ worker.on('online', async () => {
20342045
});
20352046
```
20362047
2048+
```mjs
2049+
import { Worker } from 'node:worker_threads';
2050+
2051+
const worker = new Worker(`
2052+
const { parentPort } = require('node:worker_threads');
2053+
parentPort.on('message', () => {});
2054+
`, { eval: true });
2055+
2056+
worker.on('online', async () => {
2057+
const handle = await worker.startHeapProfile();
2058+
const profile = await handle.stop();
2059+
console.log(profile);
2060+
worker.terminate();
2061+
});
2062+
```
2063+
20372064
`await using` example.
20382065
20392066
```cjs
@@ -2050,6 +2077,20 @@ w.on('online', async () => {
20502077
});
20512078
```
20522079
2080+
```mjs
2081+
import { Worker } from 'node:worker_threads';
2082+
2083+
const w = new Worker(`
2084+
const { parentPort } = require('node:worker_threads');
2085+
parentPort.on('message', () => {});
2086+
`, { eval: true });
2087+
2088+
w.on('online', async () => {
2089+
// Stop profile automatically when return and profile will be discarded
2090+
await using handle = await w.startHeapProfile();
2091+
});
2092+
```
2093+
20532094
### `worker.stderr`
20542095
20552096
<!-- YAML
Collapse file

‎lib/internal/v8/heap_profile.js‎

Copy file name to clipboard
+49Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
3+
const {
4+
validateBoolean,
5+
validateInteger,
6+
validateInt32,
7+
validateObject,
8+
} = require('internal/validators');
9+
10+
const {
11+
kSamplingNoFlags,
12+
kSamplingForceGC,
13+
kSamplingIncludeObjectsCollectedByMajorGC,
14+
kSamplingIncludeObjectsCollectedByMinorGC,
15+
} = internalBinding('v8');
16+
17+
function normalizeHeapProfileOptions(options = {}) {
18+
validateObject(options, 'options');
19+
const {
20+
sampleInterval = 512 * 1024,
21+
stackDepth = 16,
22+
forceGC = false,
23+
includeObjectsCollectedByMajorGC = false,
24+
includeObjectsCollectedByMinorGC = false,
25+
} = options;
26+
27+
validateInteger(sampleInterval, 'options.sampleInterval', 1);
28+
validateInt32(stackDepth, 'options.stackDepth', 0);
29+
validateBoolean(forceGC, 'options.forceGC');
30+
validateBoolean(includeObjectsCollectedByMajorGC,
31+
'options.includeObjectsCollectedByMajorGC');
32+
validateBoolean(includeObjectsCollectedByMinorGC,
33+
'options.includeObjectsCollectedByMinorGC');
34+
35+
let flags = kSamplingNoFlags;
36+
if (forceGC) flags |= kSamplingForceGC;
37+
if (includeObjectsCollectedByMajorGC) {
38+
flags |= kSamplingIncludeObjectsCollectedByMajorGC;
39+
}
40+
if (includeObjectsCollectedByMinorGC) {
41+
flags |= kSamplingIncludeObjectsCollectedByMinorGC;
42+
}
43+
44+
return { sampleInterval, stackDepth, flags };
45+
}
46+
47+
module.exports = {
48+
normalizeHeapProfileOptions,
49+
};
Collapse file

‎lib/internal/worker.js‎

Copy file name to clipboardExpand all lines: lib/internal/worker.js
+23-3Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,13 @@ const {
6565
constructSharedArrayBuffer,
6666
kEmptyObject,
6767
} = require('internal/util');
68-
const { validateArray, validateString, validateObject, validateNumber } = require('internal/validators');
68+
const {
69+
validateArray,
70+
validateString,
71+
validateObject,
72+
validateNumber,
73+
} = require('internal/validators');
74+
let normalizeHeapProfileOptions;
6975
const {
7076
throwIfBuildingSnapshot,
7177
} = require('internal/v8/startup_snapshot');
@@ -582,8 +588,22 @@ class Worker extends EventEmitter {
582588
});
583589
}
584590

585-
startHeapProfile() {
586-
const startTaker = this[kHandle]?.startHeapProfile();
591+
/**
592+
* @param {object} [options]
593+
* @param {number} [options.sampleInterval]
594+
* @param {number} [options.stackDepth]
595+
* @param {boolean} [options.forceGC]
596+
* @param {boolean} [options.includeObjectsCollectedByMajorGC]
597+
* @param {boolean} [options.includeObjectsCollectedByMinorGC]
598+
* @returns {Promise}
599+
*/
600+
startHeapProfile(options) {
601+
normalizeHeapProfileOptions ??=
602+
require('internal/v8/heap_profile').normalizeHeapProfileOptions;
603+
const { sampleInterval, stackDepth, flags } =
604+
normalizeHeapProfileOptions(options);
605+
const startTaker = this[kHandle]?.startHeapProfile(
606+
sampleInterval, stackDepth, flags);
587607
return new Promise((resolve, reject) => {
588608
if (!startTaker) return reject(new ERR_WORKER_NOT_RUNNING());
589609
startTaker.ondone = (err) => {
Collapse file

‎lib/v8.js‎

Copy file name to clipboardExpand all lines: lib/v8.js
+40-1Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ const {
4040
const { Buffer } = require('buffer');
4141
const {
4242
validateString,
43-
validateUint32,
4443
validateOneOf,
44+
validateUint32,
4545
} = require('internal/validators');
4646
const {
4747
Serializer,
@@ -50,6 +50,9 @@ const {
5050
const {
5151
namespace: startupSnapshot,
5252
} = require('internal/v8/startup_snapshot');
53+
const {
54+
normalizeHeapProfileOptions,
55+
} = require('internal/v8/heap_profile');
5356

5457
let profiler = {};
5558
if (internalBinding('config').hasInspector) {
@@ -115,6 +118,8 @@ const {
115118
setFlagsFromString: _setFlagsFromString,
116119
startCpuProfile: _startCpuProfile,
117120
stopCpuProfile: _stopCpuProfile,
121+
startHeapProfile: _startHeapProfile,
122+
stopHeapProfile: _stopHeapProfile,
118123
isStringOneByteRepresentation: _isStringOneByteRepresentation,
119124
updateHeapStatisticsBuffer,
120125
updateHeapSpaceStatisticsBuffer,
@@ -191,6 +196,22 @@ class SyncCPUProfileHandle {
191196
}
192197
}
193198

199+
class SyncHeapProfileHandle {
200+
#stopped = false;
201+
202+
stop() {
203+
if (this.#stopped) {
204+
return;
205+
}
206+
this.#stopped = true;
207+
return _stopHeapProfile();
208+
};
209+
210+
[SymbolDispose]() {
211+
this.stop();
212+
}
213+
}
214+
194215
/**
195216
* Starting CPU Profile.
196217
* @returns {SyncCPUProfileHandle}
@@ -200,6 +221,23 @@ function startCpuProfile() {
200221
return new SyncCPUProfileHandle(id);
201222
}
202223

224+
/**
225+
* Starting Heap Profile.
226+
* @param {object} [options]
227+
* @param {number} [options.sampleInterval]
228+
* @param {number} [options.stackDepth]
229+
* @param {boolean} [options.forceGC]
230+
* @param {boolean} [options.includeObjectsCollectedByMajorGC]
231+
* @param {boolean} [options.includeObjectsCollectedByMinorGC]
232+
* @returns {SyncHeapProfileHandle}
233+
*/
234+
function startHeapProfile(options) {
235+
const { sampleInterval, stackDepth, flags } =
236+
normalizeHeapProfileOptions(options);
237+
_startHeapProfile(sampleInterval, stackDepth, flags);
238+
return new SyncHeapProfileHandle();
239+
}
240+
203241
/**
204242
* Return whether this string uses one byte as underlying representation or not.
205243
* @param {string} content
@@ -518,4 +556,5 @@ module.exports = {
518556
GCProfiler,
519557
isStringOneByteRepresentation,
520558
startCpuProfile,
559+
startHeapProfile,
521560
};

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.