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 0478e40

Browse filesBrowse files
joyeecheungRafaelGSS
authored andcommitted
lib: add options to the heap snapshot APIs
Support configuration of the HeapSnapshotMode and NumericsMode fields inf HeapSnapshotOptions in the JS APIs for heap snapshots. PR-URL: #44989 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent ba45373 commit 0478e40
Copy full SHA for 0478e40
Expand file treeCollapse file tree

16 files changed

+322
-33
lines changed
Open diff view settings
Collapse file

‎doc/api/v8.md‎

Copy file name to clipboardExpand all lines: doc/api/v8.md
+21-3Lines changed: 21 additions & 3 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,23 @@ following properties:
6161
}
6262
```
6363

64-
## `v8.getHeapSnapshot()`
64+
## `v8.getHeapSnapshot([options])`
6565

6666
<!-- YAML
6767
added: v11.13.0
68+
changes:
69+
- version: REPLACEME
70+
pr-url: https://github.com/nodejs/node/pull/44989
71+
description: Support options to configure the heap snapshot.
6872
-->
6973

70-
* Returns: {stream.Readable} A Readable Stream containing the V8 heap snapshot
74+
* `options` {Object}
75+
* `exposeInternals` {boolean} If true, expose internals in the heap snapshot.
76+
**Default:** `false`.
77+
* `exposeNumericValues` {boolean} If true, expose numeric values in
78+
artificial fields. **Default:** `false`.
79+
80+
* Returns: {stream.Readable} A Readable containing the V8 heap snapshot.
7181

7282
Generates a snapshot of the current V8 heap and returns a Readable
7383
Stream that may be used to read the JSON serialized representation.
@@ -289,11 +299,14 @@ by [`NODE_V8_COVERAGE`][].
289299
When the process is about to exit, one last coverage will still be written to
290300
disk unless [`v8.stopCoverage()`][] is invoked before the process exits.
291301

292-
## `v8.writeHeapSnapshot([filename])`
302+
## `v8.writeHeapSnapshot([filename[,options]])`
293303

294304
<!-- YAML
295305
added: v11.13.0
296306
changes:
307+
- version: REPLACEME
308+
pr-url: https://github.com/nodejs/node/pull/44989
309+
description: Support options to configure the heap snapshot.
297310
- version: v18.0.0
298311
pr-url: https://github.com/nodejs/node/pull/41373
299312
description: An exception will now be thrown if the file could not be written.
@@ -308,6 +321,11 @@ changes:
308321
generated, where `{pid}` will be the PID of the Node.js process,
309322
`{thread_id}` will be `0` when `writeHeapSnapshot()` is called from
310323
the main Node.js thread or the id of a worker thread.
324+
* `options` {Object}
325+
* `exposeInternals` {boolean} If true, expose internals in the heap snapshot.
326+
**Default:** `false`.
327+
* `exposeNumericValues` {boolean} If true, expose numeric values in
328+
artificial fields. **Default:** `false`.
311329
* Returns: {string} The filename where the snapshot was saved.
312330

313331
Generates a snapshot of the current V8 heap and writes it to a JSON
Collapse file

‎doc/api/worker_threads.md‎

Copy file name to clipboardExpand all lines: doc/api/worker_threads.md
+11-2Lines changed: 11 additions & 2 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -1067,14 +1067,23 @@ added: v10.5.0
10671067
The `'online'` event is emitted when the worker thread has started executing
10681068
JavaScript code.
10691069

1070-
### `worker.getHeapSnapshot()`
1070+
### `worker.getHeapSnapshot([options])`
10711071

10721072
<!-- YAML
10731073
added:
10741074
- v13.9.0
10751075
- v12.17.0
1076+
changes:
1077+
- version: REPLACEME
1078+
pr-url: https://github.com/nodejs/node/pull/44989
1079+
description: Support options to configure the heap snapshot.
10761080
-->
10771081

1082+
* `options` {Object}
1083+
* `exposeInternals` {boolean} If true, expose internals in the heap snapshot.
1084+
**Default:** `false`.
1085+
* `exposeNumericValues` {boolean} If true, expose numeric values in
1086+
artificial fields. **Default:** `false`.
10781087
* Returns: {Promise} A promise for a Readable Stream containing
10791088
a V8 heap snapshot
10801089

@@ -1379,7 +1388,7 @@ thread spawned will spawn another until the application crashes.
13791388
[`require('node:worker_threads').threadId`]: #workerthreadid
13801389
[`require('node:worker_threads').workerData`]: #workerworkerdata
13811390
[`trace_events`]: tracing.md
1382-
[`v8.getHeapSnapshot()`]: v8.md#v8getheapsnapshot
1391+
[`v8.getHeapSnapshot()`]: v8.md#v8getheapsnapshotoptions
13831392
[`vm`]: vm.md
13841393
[`worker.SHARE_ENV`]: #workershare_env
13851394
[`worker.on('message')`]: #event-message_1
Collapse file

‎lib/internal/heap_utils.js‎

Copy file name to clipboardExpand all lines: lib/internal/heap_utils.js
+17-2Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,30 @@
11
'use strict';
22
const {
3-
Symbol
3+
Symbol,
4+
Uint8Array,
45
} = primordials;
56
const {
67
kUpdateTimer,
78
onStreamRead,
89
} = require('internal/stream_base_commons');
910
const { owner_symbol } = require('internal/async_hooks').symbols;
1011
const { Readable } = require('stream');
12+
const { validateObject, validateBoolean } = require('internal/validators');
13+
const { kEmptyObject } = require('internal/util');
1114

1215
const kHandle = Symbol('kHandle');
1316

17+
function getHeapSnapshotOptions(options = kEmptyObject) {
18+
validateObject(options, 'options');
19+
const {
20+
exposeInternals = false,
21+
exposeNumericValues = false,
22+
} = options;
23+
validateBoolean(exposeInternals, 'options.exposeInternals');
24+
validateBoolean(exposeNumericValues, 'options.exposeNumericValues');
25+
return new Uint8Array([+exposeInternals, +exposeNumericValues]);
26+
}
27+
1428
class HeapSnapshotStream extends Readable {
1529
constructor(handle) {
1630
super({ autoDestroy: true });
@@ -37,5 +51,6 @@ class HeapSnapshotStream extends Readable {
3751
}
3852

3953
module.exports = {
40-
HeapSnapshotStream
54+
getHeapSnapshotOptions,
55+
HeapSnapshotStream,
4156
};
Collapse file

‎lib/internal/worker.js‎

Copy file name to clipboardExpand all lines: lib/internal/worker.js
+7-3Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -416,12 +416,16 @@ class Worker extends EventEmitter {
416416
return makeResourceLimits(this[kHandle].getResourceLimits());
417417
}
418418

419-
getHeapSnapshot() {
420-
const heapSnapshotTaker = this[kHandle] && this[kHandle].takeHeapSnapshot();
419+
getHeapSnapshot(options) {
420+
const {
421+
HeapSnapshotStream,
422+
getHeapSnapshotOptions
423+
} = require('internal/heap_utils');
424+
const optionsArray = getHeapSnapshotOptions(options);
425+
const heapSnapshotTaker = this[kHandle]?.takeHeapSnapshot(optionsArray);
421426
return new Promise((resolve, reject) => {
422427
if (!heapSnapshotTaker) return reject(new ERR_WORKER_NOT_RUNNING());
423428
heapSnapshotTaker.ondone = (handle) => {
424-
const { HeapSnapshotStream } = require('internal/heap_utils');
425429
resolve(new HeapSnapshotStream(handle));
426430
};
427431
});
Collapse file

‎lib/v8.js‎

Copy file name to clipboardExpand all lines: lib/v8.js
+18-5Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,31 +57,44 @@ const {
5757
createHeapSnapshotStream,
5858
triggerHeapSnapshot
5959
} = internalBinding('heap_utils');
60-
const { HeapSnapshotStream } = require('internal/heap_utils');
60+
const {
61+
HeapSnapshotStream,
62+
getHeapSnapshotOptions
63+
} = require('internal/heap_utils');
6164
const promiseHooks = require('internal/promise_hooks');
6265
const { getOptionValue } = require('internal/options');
6366

6467
/**
6568
* Generates a snapshot of the current V8 heap
6669
* and writes it to a JSON file.
6770
* @param {string} [filename]
71+
* @param {{
72+
* exposeInternals?: boolean,
73+
* exposeNumericValues?: boolean
74+
* }} [options]
6875
* @returns {string}
6976
*/
70-
function writeHeapSnapshot(filename) {
77+
function writeHeapSnapshot(filename, options) {
7178
if (filename !== undefined) {
7279
filename = getValidatedPath(filename);
7380
filename = toNamespacedPath(filename);
7481
}
75-
return triggerHeapSnapshot(filename);
82+
const optionArray = getHeapSnapshotOptions(options);
83+
return triggerHeapSnapshot(filename, optionArray);
7684
}
7785

7886
/**
7987
* Generates a snapshot of the current V8 heap
8088
* and returns a Readable Stream.
89+
* @param {{
90+
* exposeInternals?: boolean,
91+
* exposeNumericValues?: boolean
92+
* }} [options]
8193
* @returns {import('./stream.js').Readable}
8294
*/
83-
function getHeapSnapshot() {
84-
const handle = createHeapSnapshotStream();
95+
function getHeapSnapshot(options) {
96+
const optionArray = getHeapSnapshotOptions(options);
97+
const handle = createHeapSnapshotStream(optionArray);
8598
assert(handle);
8699
return new HeapSnapshotStream(handle);
87100
}
Collapse file

‎src/env.cc‎

Copy file name to clipboardExpand all lines: src/env.cc
+5-1Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ using v8::EscapableHandleScope;
3939
using v8::Function;
4040
using v8::FunctionTemplate;
4141
using v8::HandleScope;
42+
using v8::HeapProfiler;
4243
using v8::HeapSpaceStatistics;
4344
using v8::Integer;
4445
using v8::Isolate;
@@ -1790,7 +1791,10 @@ size_t Environment::NearHeapLimitCallback(void* data,
17901791

17911792
Debug(env, DebugCategory::DIAGNOSTICS, "Start generating %s...\n", *name);
17921793

1793-
heap::WriteSnapshot(env, filename.c_str());
1794+
HeapProfiler::HeapSnapshotOptions options;
1795+
options.numerics_mode = HeapProfiler::NumericsMode::kExposeNumericValues;
1796+
options.snapshot_mode = HeapProfiler::HeapSnapshotMode::kExposeInternals;
1797+
heap::WriteSnapshot(env, filename.c_str(), options);
17941798
env->heap_limit_snapshot_taken_ += 1;
17951799

17961800
Debug(env,
Collapse file

‎src/heap_utils.cc‎

Copy file name to clipboardExpand all lines: src/heap_utils.cc
+35-12Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ using v8::FunctionCallbackInfo;
2525
using v8::FunctionTemplate;
2626
using v8::Global;
2727
using v8::HandleScope;
28+
using v8::HeapProfiler;
2829
using v8::HeapSnapshot;
2930
using v8::Isolate;
3031
using v8::JustVoid;
@@ -36,6 +37,7 @@ using v8::Number;
3637
using v8::Object;
3738
using v8::ObjectTemplate;
3839
using v8::String;
40+
using v8::Uint8Array;
3941
using v8::Value;
4042

4143
namespace node {
@@ -340,15 +342,19 @@ class HeapSnapshotStream : public AsyncWrap,
340342
HeapSnapshotPointer snapshot_;
341343
};
342344

343-
inline void TakeSnapshot(Environment* env, v8::OutputStream* out) {
344-
HeapSnapshotPointer snapshot {
345-
env->isolate()->GetHeapProfiler()->TakeHeapSnapshot() };
345+
inline void TakeSnapshot(Environment* env,
346+
v8::OutputStream* out,
347+
HeapProfiler::HeapSnapshotOptions options) {
348+
HeapSnapshotPointer snapshot{
349+
env->isolate()->GetHeapProfiler()->TakeHeapSnapshot(options)};
346350
snapshot->Serialize(out, HeapSnapshot::kJSON);
347351
}
348352

349353
} // namespace
350354

351-
Maybe<void> WriteSnapshot(Environment* env, const char* filename) {
355+
Maybe<void> WriteSnapshot(Environment* env,
356+
const char* filename,
357+
HeapProfiler::HeapSnapshotOptions options) {
352358
uv_fs_t req;
353359
int err;
354360

@@ -365,7 +371,7 @@ Maybe<void> WriteSnapshot(Environment* env, const char* filename) {
365371
}
366372

367373
FileOutputStream stream(fd, &req);
368-
TakeSnapshot(env, &stream);
374+
TakeSnapshot(env, &stream, options);
369375
if ((err = stream.status()) < 0) {
370376
env->ThrowUVException(err, "write", nullptr, filename);
371377
return Nothing<void>();
@@ -410,10 +416,28 @@ BaseObjectPtr<AsyncWrap> CreateHeapSnapshotStream(
410416
return MakeBaseObject<HeapSnapshotStream>(env, std::move(snapshot), obj);
411417
}
412418

419+
HeapProfiler::HeapSnapshotOptions GetHeapSnapshotOptions(
420+
Local<Value> options_value) {
421+
CHECK(options_value->IsUint8Array());
422+
Local<Uint8Array> arr = options_value.As<Uint8Array>();
423+
uint8_t* options =
424+
static_cast<uint8_t*>(arr->Buffer()->Data()) + arr->ByteOffset();
425+
HeapProfiler::HeapSnapshotOptions result;
426+
result.snapshot_mode = options[0]
427+
? HeapProfiler::HeapSnapshotMode::kExposeInternals
428+
: HeapProfiler::HeapSnapshotMode::kRegular;
429+
result.numerics_mode = options[1]
430+
? HeapProfiler::NumericsMode::kExposeNumericValues
431+
: HeapProfiler::NumericsMode::kHideNumericValues;
432+
return result;
433+
}
434+
413435
void CreateHeapSnapshotStream(const FunctionCallbackInfo<Value>& args) {
414436
Environment* env = Environment::GetCurrent(args);
415-
HeapSnapshotPointer snapshot {
416-
env->isolate()->GetHeapProfiler()->TakeHeapSnapshot() };
437+
CHECK_EQ(args.Length(), 1);
438+
auto options = GetHeapSnapshotOptions(args[0]);
439+
HeapSnapshotPointer snapshot{
440+
env->isolate()->GetHeapProfiler()->TakeHeapSnapshot(options)};
417441
CHECK(snapshot);
418442
BaseObjectPtr<AsyncWrap> stream =
419443
CreateHeapSnapshotStream(env, std::move(snapshot));
@@ -424,13 +448,13 @@ void CreateHeapSnapshotStream(const FunctionCallbackInfo<Value>& args) {
424448
void TriggerHeapSnapshot(const FunctionCallbackInfo<Value>& args) {
425449
Environment* env = Environment::GetCurrent(args);
426450
Isolate* isolate = args.GetIsolate();
427-
451+
CHECK_EQ(args.Length(), 2);
428452
Local<Value> filename_v = args[0];
453+
auto options = GetHeapSnapshotOptions(args[1]);
429454

430455
if (filename_v->IsUndefined()) {
431456
DiagnosticFilename name(env, "Heap", "heapsnapshot");
432-
if (WriteSnapshot(env, *name).IsNothing())
433-
return;
457+
if (WriteSnapshot(env, *name, options).IsNothing()) return;
434458
if (String::NewFromUtf8(isolate, *name).ToLocal(&filename_v)) {
435459
args.GetReturnValue().Set(filename_v);
436460
}
@@ -439,8 +463,7 @@ void TriggerHeapSnapshot(const FunctionCallbackInfo<Value>& args) {
439463

440464
BufferValue path(isolate, filename_v);
441465
CHECK_NOT_NULL(*path);
442-
if (WriteSnapshot(env, *path).IsNothing())
443-
return;
466+
if (WriteSnapshot(env, *path, options).IsNothing()) return;
444467
return args.GetReturnValue().Set(filename_v);
445468
}
446469

Collapse file

‎src/node_internals.h‎

Copy file name to clipboardExpand all lines: src/node_internals.h
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,9 @@ class DiagnosticFilename {
382382
};
383383

384384
namespace heap {
385-
v8::Maybe<void> WriteSnapshot(Environment* env, const char* filename);
385+
v8::Maybe<void> WriteSnapshot(Environment* env,
386+
const char* filename,
387+
v8::HeapProfiler::HeapSnapshotOptions options);
386388
}
387389

388390
namespace heap {
@@ -423,6 +425,12 @@ std::ostream& operator<<(std::ostream& output,
423425
}
424426

425427
bool linux_at_secure();
428+
429+
namespace heap {
430+
v8::HeapProfiler::HeapSnapshotOptions GetHeapSnapshotOptions(
431+
v8::Local<v8::Value> options);
432+
} // namespace heap
433+
426434
} // namespace node
427435

428436
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
Collapse file

‎src/node_worker.cc‎

Copy file name to clipboardExpand all lines: src/node_worker.cc
+5-3Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,8 @@ class WorkerHeapSnapshotTaker : public AsyncWrap {
778778
void Worker::TakeHeapSnapshot(const FunctionCallbackInfo<Value>& args) {
779779
Worker* w;
780780
ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
781+
CHECK_EQ(args.Length(), 1);
782+
auto options = heap::GetHeapSnapshotOptions(args[0]);
781783

782784
Debug(w, "Worker %llu taking heap snapshot", w->thread_id_.id);
783785

@@ -797,10 +799,10 @@ void Worker::TakeHeapSnapshot(const FunctionCallbackInfo<Value>& args) {
797799

798800
// Interrupt the worker thread and take a snapshot, then schedule a call
799801
// on the parent thread that turns that snapshot into a readable stream.
800-
bool scheduled = w->RequestInterrupt([taker = std::move(taker),
801-
env](Environment* worker_env) mutable {
802+
bool scheduled = w->RequestInterrupt([taker = std::move(taker), env, options](
803+
Environment* worker_env) mutable {
802804
heap::HeapSnapshotPointer snapshot{
803-
worker_env->isolate()->GetHeapProfiler()->TakeHeapSnapshot()};
805+
worker_env->isolate()->GetHeapProfiler()->TakeHeapSnapshot(options)};
804806
CHECK(snapshot);
805807

806808
// Here, the worker thread temporarily owns the WorkerHeapSnapshotTaker

0 commit comments

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