diff options
author | cjihrig <cjihrig@gmail.com> | 2019-04-08 10:20:26 -0400 |
---|---|---|
committer | cjihrig <cjihrig@gmail.com> | 2019-04-12 17:16:46 -0400 |
commit | 9b6b567bc4dd8f40bad12528eebf12dac8a8027f (patch) | |
tree | 7e2b9264a4d45f26091f92c099065320abd47f75 | |
parent | 8cf3af14864ac1bee4b3145bec8a8cf3e38edc55 (diff) | |
download | android-node-v8-9b6b567bc4dd8f40bad12528eebf12dac8a8027f.tar.gz android-node-v8-9b6b567bc4dd8f40bad12528eebf12dac8a8027f.tar.bz2 android-node-v8-9b6b567bc4dd8f40bad12528eebf12dac8a8027f.zip |
lib,src,doc: add --heapsnapshot-signal CLI flag
This flag allows heap snapshots to be captured without
modifying application code.
PR-URL: https://github.com/nodejs/node/pull/27133
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
-rw-r--r-- | doc/api/cli.md | 9 | ||||
-rw-r--r-- | doc/node.1 | 3 | ||||
-rw-r--r-- | lib/internal/bootstrap/pre_execution.js | 16 | ||||
-rw-r--r-- | src/node_options.cc | 4 | ||||
-rw-r--r-- | src/node_options.h | 1 | ||||
-rw-r--r-- | test/sequential/test-heapdump-flag.js | 41 |
6 files changed, 74 insertions, 0 deletions
diff --git a/doc/api/cli.md b/doc/api/cli.md index ced8cece1d..60d75a6c04 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -230,6 +230,14 @@ https://github.com/tc39/ecma262/pull/1320. Both of the above may change in future updates, which will be breaking changes. +### `--heapsnapshot-signal=signal` +<!-- YAML +added: REPLACEME +--> + +Generates a heap snapshot each time the process receives the specified signal. +`signal` must be a valid signal name. Disabled by default. + ### `--http-parser=library` <!-- YAML added: v11.4.0 @@ -765,6 +773,7 @@ Node.js options that are allowed are: - `--experimental-vm-modules` - `--force-fips` - `--frozen-intrinsics` +- `--heapsnapshot-signal` - `--icu-data-dir` - `--inspect` - `--inspect-brk` diff --git a/doc/node.1 b/doc/node.1 index e2ac998cab..0fccabc4bc 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -156,6 +156,9 @@ Same requirements as .It Fl -frozen-intrinsics Enable experimental frozen intrinsics support. . +.It Fl -heapsnapshot-signal Ns = Ns Ar signal +Generate heap snapshot on specified signal. +. .It Fl -http-parser Ns = Ns Ar library Chooses an HTTP parser library. Available values are .Sy llhttp diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js index e2b1103f8c..6b1e3fb213 100644 --- a/lib/internal/bootstrap/pre_execution.js +++ b/lib/internal/bootstrap/pre_execution.js @@ -29,6 +29,8 @@ function prepareMainThreadExecution(expandArgv1 = false) { initializeReport(); initializeReportSignalHandlers(); // Main-thread-only. + initializeHeapSnapshotSignalHandlers(); + // If the process is spawned with env NODE_CHANNEL_FD, it's probably // spawned by our child_process module, then initialize IPC. // This attaches some internal event listeners and creates: @@ -166,6 +168,20 @@ function initializeReportSignalHandlers() { addSignalHandler(); } +function initializeHeapSnapshotSignalHandlers() { + const signal = getOptionValue('--heapsnapshot-signal'); + + if (!signal) + return; + + require('internal/validators').validateSignalName(signal); + const { writeHeapSnapshot } = require('v8'); + + process.on(signal, () => { + writeHeapSnapshot(); + }); +} + function setupTraceCategoryState() { const { isTraceCategoryEnabled } = internalBinding('trace_events'); const { toggleTraceCategoryState } = require('internal/process/per_thread'); diff --git a/src/node_options.cc b/src/node_options.cc index 8463765eb6..c307c66a62 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -273,6 +273,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { "experimental frozen intrinsics support", &EnvironmentOptions::frozen_intrinsics, kAllowedInEnvironment); + AddOption("--heapsnapshot-signal", + "Generate heap snapshot on specified signal", + &EnvironmentOptions::heap_snapshot_signal, + kAllowedInEnvironment); AddOption("--http-parser", "Select which HTTP parser to use; either 'legacy' or 'llhttp' " "(default: llhttp).", diff --git a/src/node_options.h b/src/node_options.h index e07ee7fb35..59baea562a 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -100,6 +100,7 @@ class EnvironmentOptions : public Options { bool experimental_vm_modules = false; bool expose_internals = false; bool frozen_intrinsics = false; + std::string heap_snapshot_signal; std::string http_parser = "llhttp"; bool no_deprecation = false; bool no_force_async_hooks_checks = false; diff --git a/test/sequential/test-heapdump-flag.js b/test/sequential/test-heapdump-flag.js new file mode 100644 index 0000000000..65401b9d71 --- /dev/null +++ b/test/sequential/test-heapdump-flag.js @@ -0,0 +1,41 @@ +'use strict'; +const common = require('../common'); + +if (common.isWindows) + common.skip('test not supported on Windows'); + +const assert = require('assert'); + +if (process.argv[2] === 'child') { + const fs = require('fs'); + + assert.strictEqual(process.listenerCount('SIGUSR2'), 1); + process.kill(process.pid, 'SIGUSR2'); + process.kill(process.pid, 'SIGUSR2'); + + // Asynchronously wait for the snapshot. Use an async loop to be a bit more + // robust in case platform or machine differences throw off the timing. + (function validate() { + const files = fs.readdirSync(process.cwd()); + + if (files.length === 0) + return setImmediate(validate); + + assert.strictEqual(files.length, 2); + + for (let i = 0; i < files.length; i++) { + assert(/^Heap\..+\.heapsnapshot$/.test(files[i])); + JSON.parse(fs.readFileSync(files[i])); + } + })(); +} else { + const { spawnSync } = require('child_process'); + const tmpdir = require('../common/tmpdir'); + + tmpdir.refresh(); + const args = ['--heapsnapshot-signal', 'SIGUSR2', __filename, 'child']; + const child = spawnSync(process.execPath, args, { cwd: tmpdir.path }); + + assert.strictEqual(child.status, 0); + assert.strictEqual(child.signal, null); +} |