Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib,src,doc: add --heapsnapshot-signal CLI flag #27133

Merged
merged 1 commit into from
Apr 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
cjihrig marked this conversation as resolved.
Show resolved Hide resolved
<!-- 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
Expand Down Expand Up @@ -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`
Expand Down
3 changes: 3 additions & 0 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions lib/internal/bootstrap/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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, () => {
cjihrig marked this conversation as resolved.
Show resolved Hide resolved
writeHeapSnapshot();
});
}

function setupTraceCategoryState() {
const { isTraceCategoryEnabled } = internalBinding('trace_events');
const { toggleTraceCategoryState } = require('internal/process/per_thread');
Expand Down
4 changes: 4 additions & 0 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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).",
Expand Down
1 change: 1 addition & 0 deletions src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
41 changes: 41 additions & 0 deletions test/sequential/test-heapdump-flag.js
Original file line number Diff line number Diff line change
@@ -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);
}