-
Notifications
You must be signed in to change notification settings - Fork 30.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
inspector: implement --cpu-prof[-path]
This patch introduces a CLI flag --cpu-prof that starts the V8 CPU profiler on start up, and ends the profiler then writes the CPU profile before the Node.js instance (on the main thread or the worker thread) exits. By default the profile is written to `${cwd}/CPU.${yyyymmdd}.${hhmmss}.${pid}.${tid}.${seq}.cpuprofile`. The patch also introduces a --cpu-prof-path flag for the user to specify the path the profile will be written to. Refs: #26878 PR-URL: #27147 Reviewed-By: Anna Henningsen <[email protected]>
- v23.9.0
- v23.8.0
- v23.7.0
- v23.6.1
- v23.6.0
- v23.5.0
- v23.4.0
- v23.3.0
- v23.2.0
- v23.1.0
- v23.0.0
- v22.14.0
- v22.13.1
- v22.13.0
- v22.12.0
- v22.11.0
- v22.10.0
- v22.9.0
- v22.8.0
- v22.7.0
- v22.6.0
- v22.5.1
- v22.5.0
- v22.4.1
- v22.4.0
- v22.3.0
- v22.2.0
- v22.1.0
- v22.0.0
- v21.7.3
- v21.7.2
- v21.7.1
- v21.7.0
- v21.6.2
- v21.6.1
- v21.6.0
- v21.5.0
- v21.4.0
- v21.3.0
- v21.2.0
- v21.1.0
- v21.0.0
- v20.18.3
- v20.18.2
- v20.18.1
- v20.18.0
- v20.17.0
- v20.16.0
- v20.15.1
- v20.15.0
- v20.14.0
- v20.13.1
- v20.13.0
- v20.12.2
- v20.12.1
- v20.12.0
- v20.11.1
- v20.11.0
- v20.10.0
- v20.9.0
- v20.8.1
- v20.8.0
- v20.7.0
- v20.6.1
- v20.6.0
- v20.5.1
- v20.5.0
- v20.4.0
- v20.3.1
- v20.3.0
- v20.2.0
- v20.1.0
- v20.0.0
- v19.9.0
- v19.8.1
- v19.8.0
- v19.7.0
- v19.6.1
- v19.6.0
- v19.5.0
- v19.4.0
- v19.3.0
- v19.2.0
- v19.1.0
- v19.0.1
- v19.0.0
- v18.20.7
- v18.20.6
- v18.20.5
- v18.20.4
- v18.20.3
- v18.20.2
- v18.20.1
- v18.20.0
- v18.19.1
- v18.19.0
- v18.18.2
- v18.18.1
- v18.18.0
- v18.17.1
- v18.17.0
- v18.16.1
- v18.16.0
- v18.15.0
- v18.14.2
- v18.14.1
- v18.14.0
- v18.13.0
- v18.12.1
- v18.12.0
- v18.11.0
- v18.10.0
- v18.9.1
- v18.9.0
- v18.8.0
- v18.7.0
- v18.6.0
- v18.5.0
- v18.4.0
- v18.3.0
- v18.2.0
- v18.1.0
- v18.0.0
- v17.9.1
- v17.9.0
- v17.8.0
- v17.7.2
- v17.7.1
- v17.7.0
- v17.6.0
- v17.5.0
- v17.4.0
- v17.3.1
- v17.3.0
- v17.2.0
- v17.1.0
- v17.0.1
- v17.0.0
- v16.20.2
- v16.20.1
- v16.20.0
- v16.19.1
- v16.19.0
- v16.18.1
- v16.18.0
- v16.17.1
- v16.17.0
- v16.16.0
- v16.15.1
- v16.15.0
- v16.14.2
- v16.14.1
- v16.14.0
- v16.13.2
- v16.13.1
- v16.13.0
- v16.12.0
- v16.11.1
- v16.11.0
- v16.10.0
- v16.9.1
- v16.9.0
- v16.8.0
- v16.7.0
- v16.6.2
- v16.6.1
- v16.6.0
- v16.5.0
- v16.4.2
- v16.4.1
- v16.4.0
- v16.3.0
- v16.2.0
- v16.1.0
- v16.0.0
- v15.14.0
- v15.13.0
- v15.12.0
- v15.11.0
- v15.10.0
- v15.9.0
- v15.8.0
- v15.7.0
- v15.6.0
- v15.5.1
- v15.5.0
- v15.4.0
- v15.3.0
- v15.2.1
- v15.2.0
- v15.1.0
- v15.0.1
- v15.0.0
- v14.21.3
- v14.21.2
- v14.21.1
- v14.21.0
- v14.20.1
- v14.20.0
- v14.19.3
- v14.19.2
- v14.19.1
- v14.19.0
- v14.18.3
- v14.18.2
- v14.18.1
- v14.18.0
- v14.17.6
- v14.17.5
- v14.17.4
- v14.17.3
- v14.17.2
- v14.17.1
- v14.17.0
- v14.16.1
- v14.16.0
- v14.15.5
- v14.15.4
- v14.15.3
- v14.15.2
- v14.15.1
- v14.15.0
- v14.14.0
- v14.13.1
- v14.13.0
- v14.12.0
- v14.11.0
- v14.10.1
- v14.10.0
- v14.9.0
- v14.8.0
- v14.7.0
- v14.6.0
- v14.5.0
- v14.4.0
- v14.3.0
- v14.2.0
- v14.1.0
- v14.0.0
- v13.14.0
- v13.13.0
- v13.12.0
- v13.11.0
- v13.10.1
- v13.10.0
- v13.9.0
- v13.8.0
- v13.7.0
- v13.6.0
- v13.5.0
- v13.4.0
- v13.3.0
- v13.2.0
- v13.1.0
- v13.0.1
- v13.0.0
- v12.22.12
- v12.22.11
- v12.22.10
- v12.22.9
- v12.22.8
- v12.22.7
- v12.22.6
- v12.22.5
- v12.22.4
- v12.22.3
- v12.22.2
- v12.22.1
- v12.22.0
- v12.21.0
- v12.20.2
- v12.20.1
- v12.20.0
- v12.19.1
- v12.19.0
- v12.18.4
- v12.18.3
- v12.18.2
- v12.18.1
- v12.18.0
- v12.17.0
- v12.16.3
- v12.16.2
- v12.16.1
- v12.16.0
- v12.15.0
- v12.14.1
- v12.14.0
- v12.13.1
- v12.13.0
- v12.12.0
- v12.11.1
- v12.11.0
- v12.10.0
- v12.9.1
- v12.9.0
- v12.8.1
- v12.8.0
- v12.7.0
- v12.6.0
- v12.5.0
- v12.4.0
- v12.3.1
- v12.3.0
- v12.2.0
- v12.1.0
- v12.0.0
1 parent
57ab3b5
commit e0e3084
Showing
15 changed files
with
480 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'use strict'; | ||
function fib(n) { | ||
if (n === 0 || n === 1) return n; | ||
return fib(n - 1) + fib(n - 2); | ||
} | ||
fib(parseInt(process.argv[2]) || 35); | ||
process.exit(55); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'use strict'; | ||
function fib(n) { | ||
if (n === 0 || n === 1) return n; | ||
return fib(n - 1) + fib(n - 2); | ||
} | ||
fib(parseInt(process.argv[2]) || 35); | ||
process.kill(process.pid, "SIGINT"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'use strict'; | ||
|
||
const { Worker } = require('worker_threads'); | ||
const path = require('path'); | ||
new Worker(path.join(__dirname, 'fibonacci.js'), { | ||
execArgv: ['--cpu-prof'] | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
'use strict'; | ||
function fib(n) { | ||
if (n === 0 || n === 1) return n; | ||
return fib(n - 1) + fib(n - 2); | ||
} | ||
|
||
const n = parseInt(process.env.FIB) || 35; | ||
process.stdout.write(`${fib(n)}\n`); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
'use strict'; | ||
|
||
// This tests that --cpu-prof and --cpu-prof-path works. | ||
|
||
const common = require('../common'); | ||
const fixtures = require('../common/fixtures'); | ||
common.skipIfInspectorDisabled(); | ||
|
||
const assert = require('assert'); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const { spawnSync } = require('child_process'); | ||
|
||
const tmpdir = require('../common/tmpdir'); | ||
|
||
function getCpuProfiles(dir) { | ||
const list = fs.readdirSync(dir); | ||
return list | ||
.filter((file) => file.endsWith('.cpuprofile')) | ||
.map((file) => path.join(dir, file)); | ||
} | ||
|
||
function verifyFrames(output, file, suffix) { | ||
const data = fs.readFileSync(file, 'utf8'); | ||
const profile = JSON.parse(data); | ||
const frames = profile.nodes.filter((i) => { | ||
const frame = i.callFrame; | ||
return frame.url.endsWith(suffix); | ||
}); | ||
if (frames.length === 0) { | ||
// Show native debug output and the profile for debugging. | ||
console.log(output.stderr.toString()); | ||
console.log(profile.nodes); | ||
} | ||
assert.notDeepStrictEqual(frames, []); | ||
} | ||
|
||
let FIB = 30; | ||
// This is based on emperial values - in the CI, on Windows the program | ||
// tend to finish too fast then we won't be able to see the profiled script | ||
// in the samples, so we need to bump the values a bit. On slower platforms | ||
// like the Pis it could take more time to complete, we need to use a | ||
// smaller value so the test would not time out. | ||
if (common.isWindows) { | ||
FIB = 40; | ||
} | ||
|
||
const env = { | ||
...process.env, | ||
FIB, | ||
NODE_DEBUG_NATIVE: 'INSPECTOR_PROFILER' | ||
}; | ||
|
||
// Outputs CPU profile when event loop is drained. | ||
// TODO(joyeecheung): share the fixutres with v8 coverage tests | ||
{ | ||
tmpdir.refresh(); | ||
const output = spawnSync(process.execPath, [ | ||
'--cpu-prof', | ||
fixtures.path('workload', 'fibonacci.js'), | ||
], { | ||
cwd: tmpdir.path, | ||
env | ||
}); | ||
if (output.status !== 0) { | ||
console.log(output.stderr.toString()); | ||
} | ||
assert.strictEqual(output.status, 0); | ||
const profiles = getCpuProfiles(tmpdir.path); | ||
assert.strictEqual(profiles.length, 1); | ||
verifyFrames(output, profiles[0], 'fibonacci.js'); | ||
} | ||
|
||
// Outputs CPU profile when process.exit(55) exits process. | ||
{ | ||
tmpdir.refresh(); | ||
const output = spawnSync(process.execPath, [ | ||
'--cpu-prof', | ||
fixtures.path('workload', 'fibonacci-exit.js'), | ||
], { | ||
cwd: tmpdir.path, | ||
env | ||
}); | ||
if (output.status !== 55) { | ||
console.log(output.stderr.toString()); | ||
} | ||
assert.strictEqual(output.status, 55); | ||
const profiles = getCpuProfiles(tmpdir.path); | ||
assert.strictEqual(profiles.length, 1); | ||
verifyFrames(output, profiles[0], 'fibonacci-exit.js'); | ||
} | ||
|
||
// Outputs CPU profile when process.kill(process.pid, "SIGINT"); exits process. | ||
{ | ||
tmpdir.refresh(); | ||
const output = spawnSync(process.execPath, [ | ||
'--cpu-prof', | ||
fixtures.path('workload', 'fibonacci-sigint.js'), | ||
], { | ||
cwd: tmpdir.path, | ||
env | ||
}); | ||
if (!common.isWindows) { | ||
if (output.signal !== 'SIGINT') { | ||
console.log(output.stderr.toString()); | ||
} | ||
assert.strictEqual(output.signal, 'SIGINT'); | ||
} | ||
const profiles = getCpuProfiles(tmpdir.path); | ||
assert.strictEqual(profiles.length, 1); | ||
verifyFrames(output, profiles[0], 'fibonacci-sigint.js'); | ||
} | ||
|
||
// Outputs CPU profile from worker. | ||
{ | ||
tmpdir.refresh(); | ||
const output = spawnSync(process.execPath, [ | ||
fixtures.path('workload', 'fibonacci-worker.js'), | ||
], { | ||
cwd: tmpdir.path, | ||
env | ||
}); | ||
if (output.status !== 0) { | ||
console.log(output.stderr.toString()); | ||
} | ||
assert.strictEqual(output.status, 0); | ||
const profiles = getCpuProfiles(tmpdir.path); | ||
assert.strictEqual(profiles.length, 1); | ||
verifyFrames(output, profiles[0], 'fibonacci.js'); | ||
} | ||
|
||
// Output to specified --cpu-prof-path without --cpu-prof | ||
{ | ||
tmpdir.refresh(); | ||
const file = path.join(tmpdir.path, 'test.cpuprofile'); | ||
const output = spawnSync(process.execPath, [ | ||
'--cpu-prof-path', | ||
file, | ||
fixtures.path('workload', 'fibonacci.js'), | ||
], { | ||
cwd: tmpdir.path, | ||
env | ||
}); | ||
if (output.status !== 0) { | ||
console.log(output.stderr.toString()); | ||
} | ||
assert.strictEqual(output.status, 0); | ||
const profiles = getCpuProfiles(tmpdir.path); | ||
assert.deepStrictEqual(profiles, [file]); | ||
verifyFrames(output, file, 'fibonacci.js'); | ||
} | ||
|
||
// Output to specified --cpu-prof-path with --cpu-prof | ||
{ | ||
tmpdir.refresh(); | ||
const file = path.join(tmpdir.path, 'test.cpuprofile'); | ||
const output = spawnSync(process.execPath, [ | ||
'--cpu-prof', | ||
'--cpu-prof-path', | ||
file, | ||
fixtures.path('workload', 'fibonacci.js'), | ||
], { | ||
cwd: tmpdir.path, | ||
env | ||
}); | ||
if (output.status !== 0) { | ||
console.log(output.stderr.toString()); | ||
} | ||
assert.strictEqual(output.status, 0); | ||
const profiles = getCpuProfiles(tmpdir.path); | ||
assert.deepStrictEqual(profiles, [file]); | ||
verifyFrames(output, file, 'fibonacci.js'); | ||
} | ||
|
||
// Output to specified --cpu-prof-path when it's not absolute | ||
{ | ||
tmpdir.refresh(); | ||
const file = path.join(tmpdir.path, 'test.cpuprofile'); | ||
const output = spawnSync(process.execPath, [ | ||
'--cpu-prof', | ||
'--cpu-prof-path', | ||
'test.cpuprofile', | ||
fixtures.path('workload', 'fibonacci.js'), | ||
], { | ||
cwd: tmpdir.path, | ||
env | ||
}); | ||
if (output.status !== 0) { | ||
console.log(output.stderr.toString()); | ||
} | ||
assert.strictEqual(output.status, 0); | ||
const profiles = getCpuProfiles(tmpdir.path); | ||
assert.deepStrictEqual(profiles, [file]); | ||
verifyFrames(output, file, 'fibonacci.js'); | ||
} |