| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent ba45373 commit 0478e40
16 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -61,13 +61,23 @@ following properties: | |||
| 61 | 61 | } | |
| 62 | 62 | ``` | |
| 63 | 63 | ||
| 64 | - ## `v8.getHeapSnapshot()` | ||
| 64 | + ## `v8.getHeapSnapshot([options])` | ||
| 65 | 65 | ||
| 66 | 66 | <!-- YAML | |
| 67 | 67 | 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. | ||
| 68 | 72 | --> | |
| 69 | 73 | ||
| 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. | ||
| 71 | 81 | ||
| 72 | 82 | Generates a snapshot of the current V8 heap and returns a Readable | |
| 73 | 83 | Stream that may be used to read the JSON serialized representation. | |
@@ -289,11 +299,14 @@ by [`NODE_V8_COVERAGE`][]. | |||
| 289 | 299 | When the process is about to exit, one last coverage will still be written to | |
| 290 | 300 | disk unless [`v8.stopCoverage()`][] is invoked before the process exits. | |
| 291 | 301 | ||
| 292 | - ## `v8.writeHeapSnapshot([filename])` | ||
| 302 | + ## `v8.writeHeapSnapshot([filename[,options]])` | ||
| 293 | 303 | ||
| 294 | 304 | <!-- YAML | |
| 295 | 305 | added: v11.13.0 | |
| 296 | 306 | changes: | |
| 307 | + - version: REPLACEME | ||
| 308 | + pr-url: https://github.com/nodejs/node/pull/44989 | ||
| 309 | + description: Support options to configure the heap snapshot. | ||
| 297 | 310 | - version: v18.0.0 | |
| 298 | 311 | pr-url: https://github.com/nodejs/node/pull/41373 | |
| 299 | 312 | description: An exception will now be thrown if the file could not be written. | |
@@ -308,6 +321,11 @@ changes: | |||
| 308 | 321 | generated, where `{pid}` will be the PID of the Node.js process, | |
| 309 | 322 | `{thread_id}` will be `0` when `writeHeapSnapshot()` is called from | |
| 310 | 323 | 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`. | ||
| 311 | 329 | * Returns: {string} The filename where the snapshot was saved. | |
| 312 | 330 | ||
| 313 | 331 | Generates a snapshot of the current V8 heap and writes it to a JSON | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1067,14 +1067,23 @@ added: v10.5.0 | |||
| 1067 | 1067 | The `'online'` event is emitted when the worker thread has started executing | |
| 1068 | 1068 | JavaScript code. | |
| 1069 | 1069 | ||
| 1070 | - ### `worker.getHeapSnapshot()` | ||
| 1070 | + ### `worker.getHeapSnapshot([options])` | ||
| 1071 | 1071 | ||
| 1072 | 1072 | <!-- YAML | |
| 1073 | 1073 | added: | |
| 1074 | 1074 | - v13.9.0 | |
| 1075 | 1075 | - 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. | ||
| 1076 | 1080 | --> | |
| 1077 | 1081 | ||
| 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`. | ||
| 1078 | 1087 | * Returns: {Promise} A promise for a Readable Stream containing | |
| 1079 | 1088 | a V8 heap snapshot | |
| 1080 | 1089 | ||
@@ -1379,7 +1388,7 @@ thread spawned will spawn another until the application crashes. | |||
| 1379 | 1388 | [`require('node:worker_threads').threadId`]: #workerthreadid | |
| 1380 | 1389 | [`require('node:worker_threads').workerData`]: #workerworkerdata | |
| 1381 | 1390 | [`trace_events`]: tracing.md | |
| 1382 | - [`v8.getHeapSnapshot()`]: v8.md#v8getheapsnapshot | ||
| 1391 | + [`v8.getHeapSnapshot()`]: v8.md#v8getheapsnapshotoptions | ||
| 1383 | 1392 | [`vm`]: vm.md | |
| 1384 | 1393 | [`worker.SHARE_ENV`]: #workershare_env | |
| 1385 | 1394 | [`worker.on('message')`]: #event-message_1 | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,16 +1,30 @@ | |||
| 1 | 1 | 'use strict'; | |
| 2 | 2 | const { | |
| 3 | - Symbol | ||
| 3 | + Symbol, | ||
| 4 | + Uint8Array, | ||
| 4 | 5 | } = primordials; | |
| 5 | 6 | const { | |
| 6 | 7 | kUpdateTimer, | |
| 7 | 8 | onStreamRead, | |
| 8 | 9 | } = require('internal/stream_base_commons'); | |
| 9 | 10 | const { owner_symbol } = require('internal/async_hooks').symbols; | |
| 10 | 11 | const { Readable } = require('stream'); | |
| 12 | + const { validateObject, validateBoolean } = require('internal/validators'); | ||
| 13 | + const { kEmptyObject } = require('internal/util'); | ||
| 11 | 14 | ||
| 12 | 15 | const kHandle = Symbol('kHandle'); | |
| 13 | 16 | ||
| 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 | + | ||
| 14 | 28 | class HeapSnapshotStream extends Readable { | |
| 15 | 29 | constructor(handle) { | |
| 16 | 30 | super({ autoDestroy: true }); | |
@@ -37,5 +51,6 @@ class HeapSnapshotStream extends Readable { | |||
| 37 | 51 | } | |
| 38 | 52 | ||
| 39 | 53 | module.exports = { | |
| 40 | - HeapSnapshotStream | ||
| 54 | + getHeapSnapshotOptions, | ||
| 55 | + HeapSnapshotStream, | ||
| 41 | 56 | }; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -416,12 +416,16 @@ class Worker extends EventEmitter { | |||
| 416 | 416 | return makeResourceLimits(this[kHandle].getResourceLimits()); | |
| 417 | 417 | } | |
| 418 | 418 | ||
| 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); | ||
| 421 | 426 | return new Promise((resolve, reject) => { | |
| 422 | 427 | if (!heapSnapshotTaker) return reject(new ERR_WORKER_NOT_RUNNING()); | |
| 423 | 428 | heapSnapshotTaker.ondone = (handle) => { | |
| 424 | - const { HeapSnapshotStream } = require('internal/heap_utils'); | ||
| 425 | 429 | resolve(new HeapSnapshotStream(handle)); | |
| 426 | 430 | }; | |
| 427 | 431 | }); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -57,31 +57,44 @@ const { | |||
| 57 | 57 | createHeapSnapshotStream, | |
| 58 | 58 | triggerHeapSnapshot | |
| 59 | 59 | } = internalBinding('heap_utils'); | |
| 60 | - const { HeapSnapshotStream } = require('internal/heap_utils'); | ||
| 60 | + const { | ||
| 61 | + HeapSnapshotStream, | ||
| 62 | + getHeapSnapshotOptions | ||
| 63 | + } = require('internal/heap_utils'); | ||
| 61 | 64 | const promiseHooks = require('internal/promise_hooks'); | |
| 62 | 65 | const { getOptionValue } = require('internal/options'); | |
| 63 | 66 | ||
| 64 | 67 | /** | |
| 65 | 68 | * Generates a snapshot of the current V8 heap | |
| 66 | 69 | * and writes it to a JSON file. | |
| 67 | 70 | * @param {string} [filename] | |
| 71 | + * @param {{ | ||
| 72 | + * exposeInternals?: boolean, | ||
| 73 | + * exposeNumericValues?: boolean | ||
| 74 | + * }} [options] | ||
| 68 | 75 | * @returns {string} | |
| 69 | 76 | */ | |
| 70 | - function writeHeapSnapshot(filename) { | ||
| 77 | + function writeHeapSnapshot(filename, options) { | ||
| 71 | 78 | if (filename !== undefined) { | |
| 72 | 79 | filename = getValidatedPath(filename); | |
| 73 | 80 | filename = toNamespacedPath(filename); | |
| 74 | 81 | } | |
| 75 | - return triggerHeapSnapshot(filename); | ||
| 82 | + const optionArray = getHeapSnapshotOptions(options); | ||
| 83 | + return triggerHeapSnapshot(filename, optionArray); | ||
| 76 | 84 | } | |
| 77 | 85 | ||
| 78 | 86 | /** | |
| 79 | 87 | * Generates a snapshot of the current V8 heap | |
| 80 | 88 | * and returns a Readable Stream. | |
| 89 | + * @param {{ | ||
| 90 | + * exposeInternals?: boolean, | ||
| 91 | + * exposeNumericValues?: boolean | ||
| 92 | + * }} [options] | ||
| 81 | 93 | * @returns {import('./stream.js').Readable} | |
| 82 | 94 | */ | |
| 83 | - function getHeapSnapshot() { | ||
| 84 | - const handle = createHeapSnapshotStream(); | ||
| 95 | + function getHeapSnapshot(options) { | ||
| 96 | + const optionArray = getHeapSnapshotOptions(options); | ||
| 97 | + const handle = createHeapSnapshotStream(optionArray); | ||
| 85 | 98 | assert(handle); | |
| 86 | 99 | return new HeapSnapshotStream(handle); | |
| 87 | 100 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -39,6 +39,7 @@ using v8::EscapableHandleScope; | |||
| 39 | 39 | using v8::Function; | |
| 40 | 40 | using v8::FunctionTemplate; | |
| 41 | 41 | using v8::HandleScope; | |
| 42 | + using v8::HeapProfiler; | ||
| 42 | 43 | using v8::HeapSpaceStatistics; | |
| 43 | 44 | using v8::Integer; | |
| 44 | 45 | using v8::Isolate; | |
@@ -1790,7 +1791,10 @@ size_t Environment::NearHeapLimitCallback(void* data, | |||
| 1790 | 1791 | ||
| 1791 | 1792 | Debug(env, DebugCategory::DIAGNOSTICS, "Start generating %s...\n", *name); | |
| 1792 | 1793 | ||
| 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); | ||
| 1794 | 1798 | env->heap_limit_snapshot_taken_ += 1; | |
| 1795 | 1799 | ||
| 1796 | 1800 | Debug(env, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -25,6 +25,7 @@ using v8::FunctionCallbackInfo; | |||
| 25 | 25 | using v8::FunctionTemplate; | |
| 26 | 26 | using v8::Global; | |
| 27 | 27 | using v8::HandleScope; | |
| 28 | + using v8::HeapProfiler; | ||
| 28 | 29 | using v8::HeapSnapshot; | |
| 29 | 30 | using v8::Isolate; | |
| 30 | 31 | using v8::JustVoid; | |
@@ -36,6 +37,7 @@ using v8::Number; | |||
| 36 | 37 | using v8::Object; | |
| 37 | 38 | using v8::ObjectTemplate; | |
| 38 | 39 | using v8::String; | |
| 40 | + using v8::Uint8Array; | ||
| 39 | 41 | using v8::Value; | |
| 40 | 42 | ||
| 41 | 43 | namespace node { | |
@@ -340,15 +342,19 @@ class HeapSnapshotStream : public AsyncWrap, | |||
| 340 | 342 | HeapSnapshotPointer snapshot_; | |
| 341 | 343 | }; | |
| 342 | 344 | ||
| 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)}; | ||
| 346 | 350 | snapshot->Serialize(out, HeapSnapshot::kJSON); | |
| 347 | 351 | } | |
| 348 | 352 | ||
| 349 | 353 | } // namespace | |
| 350 | 354 | ||
| 351 | - Maybe<void> WriteSnapshot(Environment* env, const char* filename) { | ||
| 355 | + Maybe<void> WriteSnapshot(Environment* env, | ||
| 356 | + const char* filename, | ||
| 357 | + HeapProfiler::HeapSnapshotOptions options) { | ||
| 352 | 358 | uv_fs_t req; | |
| 353 | 359 | int err; | |
| 354 | 360 | ||
@@ -365,7 +371,7 @@ Maybe<void> WriteSnapshot(Environment* env, const char* filename) { | |||
| 365 | 371 | } | |
| 366 | 372 | ||
| 367 | 373 | FileOutputStream stream(fd, &req); | |
| 368 | - TakeSnapshot(env, &stream); | ||
| 374 | + TakeSnapshot(env, &stream, options); | ||
| 369 | 375 | if ((err = stream.status()) < 0) { | |
| 370 | 376 | env->ThrowUVException(err, "write", nullptr, filename); | |
| 371 | 377 | return Nothing<void>(); | |
@@ -410,10 +416,28 @@ BaseObjectPtr<AsyncWrap> CreateHeapSnapshotStream( | |||
| 410 | 416 | return MakeBaseObject<HeapSnapshotStream>(env, std::move(snapshot), obj); | |
| 411 | 417 | } | |
| 412 | 418 | ||
| 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 | + | ||
| 413 | 435 | void CreateHeapSnapshotStream(const FunctionCallbackInfo<Value>& args) { | |
| 414 | 436 | 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)}; | ||
| 417 | 441 | CHECK(snapshot); | |
| 418 | 442 | BaseObjectPtr<AsyncWrap> stream = | |
| 419 | 443 | CreateHeapSnapshotStream(env, std::move(snapshot)); | |
@@ -424,13 +448,13 @@ void CreateHeapSnapshotStream(const FunctionCallbackInfo<Value>& args) { | |||
| 424 | 448 | void TriggerHeapSnapshot(const FunctionCallbackInfo<Value>& args) { | |
| 425 | 449 | Environment* env = Environment::GetCurrent(args); | |
| 426 | 450 | Isolate* isolate = args.GetIsolate(); | |
| 427 | - | ||
| 451 | + CHECK_EQ(args.Length(), 2); | ||
| 428 | 452 | Local<Value> filename_v = args[0]; | |
| 453 | + auto options = GetHeapSnapshotOptions(args[1]); | ||
| 429 | 454 | ||
| 430 | 455 | if (filename_v->IsUndefined()) { | |
| 431 | 456 | DiagnosticFilename name(env, "Heap", "heapsnapshot"); | |
| 432 | - if (WriteSnapshot(env, *name).IsNothing()) | ||
| 433 | - return; | ||
| 457 | + if (WriteSnapshot(env, *name, options).IsNothing()) return; | ||
| 434 | 458 | if (String::NewFromUtf8(isolate, *name).ToLocal(&filename_v)) { | |
| 435 | 459 | args.GetReturnValue().Set(filename_v); | |
| 436 | 460 | } | |
@@ -439,8 +463,7 @@ void TriggerHeapSnapshot(const FunctionCallbackInfo<Value>& args) { | |||
| 439 | 463 | ||
| 440 | 464 | BufferValue path(isolate, filename_v); | |
| 441 | 465 | CHECK_NOT_NULL(*path); | |
| 442 | - if (WriteSnapshot(env, *path).IsNothing()) | ||
| 443 | - return; | ||
| 466 | + if (WriteSnapshot(env, *path, options).IsNothing()) return; | ||
| 444 | 467 | return args.GetReturnValue().Set(filename_v); | |
| 445 | 468 | } | |
| 446 | 469 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -382,7 +382,9 @@ class DiagnosticFilename { | |||
| 382 | 382 | }; | |
| 383 | 383 | ||
| 384 | 384 | 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); | ||
| 386 | 388 | } | |
| 387 | 389 | ||
| 388 | 390 | namespace heap { | |
@@ -423,6 +425,12 @@ std::ostream& operator<<(std::ostream& output, | |||
| 423 | 425 | } | |
| 424 | 426 | ||
| 425 | 427 | bool linux_at_secure(); | |
| 428 | + | ||
| 429 | + namespace heap { | ||
| 430 | + v8::HeapProfiler::HeapSnapshotOptions GetHeapSnapshotOptions( | ||
| 431 | + v8::Local<v8::Value> options); | ||
| 432 | + } // namespace heap | ||
| 433 | + | ||
| 426 | 434 | } // namespace node | |
| 427 | 435 | ||
| 428 | 436 | #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -778,6 +778,8 @@ class WorkerHeapSnapshotTaker : public AsyncWrap { | |||
| 778 | 778 | void Worker::TakeHeapSnapshot(const FunctionCallbackInfo<Value>& args) { | |
| 779 | 779 | Worker* w; | |
| 780 | 780 | ASSIGN_OR_RETURN_UNWRAP(&w, args.This()); | |
| 781 | + CHECK_EQ(args.Length(), 1); | ||
| 782 | + auto options = heap::GetHeapSnapshotOptions(args[0]); | ||
| 781 | 783 | ||
| 782 | 784 | Debug(w, "Worker %llu taking heap snapshot", w->thread_id_.id); | |
| 783 | 785 | ||
@@ -797,10 +799,10 @@ void Worker::TakeHeapSnapshot(const FunctionCallbackInfo<Value>& args) { | |||
| 797 | 799 | ||
| 798 | 800 | // Interrupt the worker thread and take a snapshot, then schedule a call | |
| 799 | 801 | // 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 { | ||
| 802 | 804 | heap::HeapSnapshotPointer snapshot{ | |
| 803 | - worker_env->isolate()->GetHeapProfiler()->TakeHeapSnapshot()}; | ||
| 805 | + worker_env->isolate()->GetHeapProfiler()->TakeHeapSnapshot(options)}; | ||
| 804 | 806 | CHECK(snapshot); | |
| 805 | 807 | ||
| 806 | 808 | // Here, the worker thread temporarily owns the WorkerHeapSnapshotTaker | |
| Back | FazBrowse Home | New Git URL |
0 commit comments