Skip to content

Commit b5901a0

Browse files
joyeecheungjuanarbol
authored andcommittedOct 11, 2022
test: split heap prof tests
The original heap prof tests can take too long to complete on azure Windows machines, resulting in timeouts. Split them into smaller tests and move them into the parallel directory to speed up the execution. PR-URL: #44388 Refs: nodejs/reliability#356 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent a139f5d commit b5901a0

13 files changed

+592
-375
lines changed
 

‎test/common/prof.js

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const fs = require('fs');
5+
const path = require('path');
6+
7+
function getHeapProfiles(dir) {
8+
const list = fs.readdirSync(dir);
9+
return list
10+
.filter((file) => file.endsWith('.heapprofile'))
11+
.map((file) => path.join(dir, file));
12+
}
13+
14+
function findFirstFrameInNode(root, func) {
15+
const first = root.children.find(
16+
(child) => child.callFrame.functionName === func
17+
);
18+
if (first) {
19+
return first;
20+
}
21+
for (const child of root.children) {
22+
const first = findFirstFrameInNode(child, func);
23+
if (first) {
24+
return first;
25+
}
26+
}
27+
return undefined;
28+
}
29+
30+
function findFirstFrame(file, func) {
31+
const data = fs.readFileSync(file, 'utf8');
32+
const profile = JSON.parse(data);
33+
const first = findFirstFrameInNode(profile.head, func);
34+
return { frame: first, roots: profile.head.children };
35+
}
36+
37+
function verifyFrames(output, file, func) {
38+
const { frame, roots } = findFirstFrame(file, func);
39+
if (!frame) {
40+
// Show native debug output and the profile for debugging.
41+
console.log(output.stderr.toString());
42+
console.log(roots);
43+
}
44+
assert.notStrictEqual(frame, undefined);
45+
}
46+
47+
// We need to set --heap-prof-interval to a small enough value to make
48+
// sure we can find our workload in the samples, so we need to set
49+
// TEST_ALLOCATION > kHeapProfInterval.
50+
const kHeapProfInterval = 128;
51+
const TEST_ALLOCATION = kHeapProfInterval * 2;
52+
53+
const env = {
54+
...process.env,
55+
TEST_ALLOCATION,
56+
NODE_DEBUG_NATIVE: 'INSPECTOR_PROFILER'
57+
};
58+
59+
// TODO(joyeecheung): share the fixutres with v8 coverage tests
60+
module.exports = {
61+
getHeapProfiles,
62+
verifyFrames,
63+
findFirstFrame,
64+
kHeapProfInterval,
65+
TEST_ALLOCATION,
66+
env
67+
};

‎test/parallel/test-heap-prof-basic.js

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict';
2+
3+
// Tests --heap-prof without --heap-prof-interval. Here we just verify that
4+
// we manage to generate a profile.
5+
6+
const common = require('../common');
7+
8+
const fixtures = require('../common/fixtures');
9+
common.skipIfInspectorDisabled();
10+
11+
const assert = require('assert');
12+
const { spawnSync } = require('child_process');
13+
14+
const tmpdir = require('../common/tmpdir');
15+
16+
const {
17+
getHeapProfiles,
18+
env
19+
} = require('../common/prof');
20+
21+
{
22+
tmpdir.refresh();
23+
const output = spawnSync(process.execPath, [
24+
'--heap-prof',
25+
fixtures.path('workload', 'allocation.js'),
26+
], {
27+
cwd: tmpdir.path,
28+
env
29+
});
30+
if (output.status !== 0) {
31+
console.log(output.stderr.toString());
32+
console.log(output);
33+
}
34+
assert.strictEqual(output.status, 0);
35+
const profiles = getHeapProfiles(tmpdir.path);
36+
assert.strictEqual(profiles.length, 1);
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict';
2+
3+
// This tests that --heap-prof, --heap-prof-dir and --heap-prof-name works.
4+
5+
const common = require('../common');
6+
7+
const fixtures = require('../common/fixtures');
8+
common.skipIfInspectorDisabled();
9+
10+
const assert = require('assert');
11+
const fs = require('fs');
12+
const path = require('path');
13+
const { spawnSync } = require('child_process');
14+
15+
const tmpdir = require('../common/tmpdir');
16+
17+
const {
18+
getHeapProfiles,
19+
verifyFrames,
20+
kHeapProfInterval,
21+
env
22+
} = require('../common/prof');
23+
24+
// Tests absolute --heap-prof-dir
25+
{
26+
tmpdir.refresh();
27+
const dir = path.join(tmpdir.path, 'prof');
28+
const output = spawnSync(process.execPath, [
29+
'--heap-prof',
30+
'--heap-prof-dir',
31+
dir,
32+
'--heap-prof-interval',
33+
kHeapProfInterval,
34+
fixtures.path('workload', 'allocation.js'),
35+
], {
36+
cwd: tmpdir.path,
37+
env
38+
});
39+
if (output.status !== 0) {
40+
console.log(output.stderr.toString());
41+
}
42+
assert.strictEqual(output.status, 0);
43+
assert(fs.existsSync(dir));
44+
const profiles = getHeapProfiles(dir);
45+
assert.strictEqual(profiles.length, 1);
46+
verifyFrames(output, profiles[0], 'runAllocation');
47+
}
+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
3+
// Tests --heap-prof-dir and --heap-prof-name work together.
4+
5+
const common = require('../common');
6+
7+
const fixtures = require('../common/fixtures');
8+
common.skipIfInspectorDisabled();
9+
10+
const assert = require('assert');
11+
const fs = require('fs');
12+
const path = require('path');
13+
const { spawnSync } = require('child_process');
14+
15+
const tmpdir = require('../common/tmpdir');
16+
17+
const {
18+
getHeapProfiles,
19+
verifyFrames,
20+
kHeapProfInterval,
21+
env
22+
} = require('../common/prof');
23+
24+
{
25+
tmpdir.refresh();
26+
const dir = path.join(tmpdir.path, 'prof');
27+
const file = path.join(dir, 'test.heapprofile');
28+
const output = spawnSync(process.execPath, [
29+
'--heap-prof',
30+
'--heap-prof-name',
31+
'test.heapprofile',
32+
'--heap-prof-dir',
33+
dir,
34+
'--heap-prof-interval',
35+
kHeapProfInterval,
36+
fixtures.path('workload', 'allocation.js'),
37+
], {
38+
cwd: tmpdir.path,
39+
env
40+
});
41+
if (output.status !== 0) {
42+
console.log(output.stderr.toString());
43+
}
44+
assert.strictEqual(output.status, 0);
45+
assert(fs.existsSync(dir));
46+
const profiles = getHeapProfiles(dir);
47+
assert.deepStrictEqual(profiles, [file]);
48+
verifyFrames(output, file, 'runAllocation');
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use strict';
2+
3+
// Tests relative --heap-prof-dir works.
4+
5+
const common = require('../common');
6+
7+
const fixtures = require('../common/fixtures');
8+
common.skipIfInspectorDisabled();
9+
10+
const assert = require('assert');
11+
const fs = require('fs');
12+
const path = require('path');
13+
const { spawnSync } = require('child_process');
14+
15+
const tmpdir = require('../common/tmpdir');
16+
17+
const {
18+
getHeapProfiles,
19+
verifyFrames,
20+
kHeapProfInterval,
21+
env
22+
} = require('../common/prof');
23+
24+
{
25+
tmpdir.refresh();
26+
const output = spawnSync(process.execPath, [
27+
'--heap-prof',
28+
'--heap-prof-dir',
29+
'prof',
30+
'--heap-prof-interval',
31+
kHeapProfInterval,
32+
fixtures.path('workload', 'allocation.js'),
33+
], {
34+
cwd: tmpdir.path,
35+
env
36+
});
37+
if (output.status !== 0) {
38+
console.log(output.stderr.toString());
39+
}
40+
assert.strictEqual(output.status, 0);
41+
const dir = path.join(tmpdir.path, 'prof');
42+
assert(fs.existsSync(dir));
43+
const profiles = getHeapProfiles(dir);
44+
assert.strictEqual(profiles.length, 1);
45+
verifyFrames(output, profiles[0], 'runAllocation');
46+
}
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict';
2+
3+
// Tests --heap-prof generates a heap profile from worker
4+
// when execArgv is set.
5+
6+
const common = require('../common');
7+
8+
const fixtures = require('../common/fixtures');
9+
common.skipIfInspectorDisabled();
10+
11+
const assert = require('assert');
12+
const { spawnSync } = require('child_process');
13+
14+
const tmpdir = require('../common/tmpdir');
15+
16+
const {
17+
getHeapProfiles,
18+
verifyFrames,
19+
} = require('../common/prof');
20+
21+
{
22+
tmpdir.refresh();
23+
const output = spawnSync(process.execPath, [
24+
fixtures.path('workload', 'allocation-worker-argv.js'),
25+
], {
26+
cwd: tmpdir.path,
27+
env: {
28+
...process.env,
29+
HEAP_PROF_INTERVAL: '128'
30+
}
31+
});
32+
if (output.status !== 0) {
33+
console.log(output.stderr.toString());
34+
}
35+
assert.strictEqual(output.status, 0);
36+
const profiles = getHeapProfiles(tmpdir.path);
37+
assert.strictEqual(profiles.length, 1);
38+
verifyFrames(output, profiles[0], 'runAllocation');
39+
}

‎test/parallel/test-heap-prof-exit.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
'use strict';
2+
3+
// Tests --heap-prof generates a heap profile when process.exit(55) exits
4+
// process.
5+
6+
const common = require('../common');
7+
8+
const fixtures = require('../common/fixtures');
9+
common.skipIfInspectorDisabled();
10+
11+
const assert = require('assert');
12+
const { spawnSync } = require('child_process');
13+
14+
const tmpdir = require('../common/tmpdir');
15+
16+
const {
17+
getHeapProfiles,
18+
verifyFrames,
19+
kHeapProfInterval,
20+
env
21+
} = require('../common/prof');
22+
23+
{
24+
tmpdir.refresh();
25+
const output = spawnSync(process.execPath, [
26+
'--heap-prof',
27+
'--heap-prof-interval',
28+
kHeapProfInterval,
29+
fixtures.path('workload', 'allocation-exit.js'),
30+
], {
31+
cwd: tmpdir.path,
32+
env
33+
});
34+
if (output.status !== 55) {
35+
console.log(output.stderr.toString());
36+
}
37+
assert.strictEqual(output.status, 55);
38+
const profiles = getHeapProfiles(tmpdir.path);
39+
assert.strictEqual(profiles.length, 1);
40+
verifyFrames(output, profiles[0], 'runAllocation');
41+
}
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
'use strict';
2+
3+
// Tests multiple profiles generated by --heap-prof-interval are valid.
4+
5+
const common = require('../common');
6+
7+
const fixtures = require('../common/fixtures');
8+
common.skipIfInspectorDisabled();
9+
10+
const assert = require('assert');
11+
const fs = require('fs');
12+
const path = require('path');
13+
const { spawnSync } = require('child_process');
14+
15+
const tmpdir = require('../common/tmpdir');
16+
17+
const {
18+
getHeapProfiles,
19+
findFirstFrame,
20+
kHeapProfInterval,
21+
env
22+
} = require('../common/prof');
23+
24+
{
25+
tmpdir.refresh();
26+
const output = spawnSync(process.execPath, [
27+
'--heap-prof-interval',
28+
kHeapProfInterval,
29+
'--heap-prof-dir',
30+
'prof',
31+
'--heap-prof',
32+
fixtures.path('workload', 'allocation-worker.js'),
33+
], {
34+
cwd: tmpdir.path,
35+
env
36+
});
37+
if (output.status !== 0) {
38+
console.log(output.stderr.toString());
39+
}
40+
assert.strictEqual(output.status, 0);
41+
const dir = path.join(tmpdir.path, 'prof');
42+
assert(fs.existsSync(dir));
43+
const profiles = getHeapProfiles(dir);
44+
assert.strictEqual(profiles.length, 2);
45+
const profile1 = findFirstFrame(profiles[0], 'runAllocation');
46+
const profile2 = findFirstFrame(profiles[1], 'runAllocation');
47+
if (!profile1.frame && !profile2.frame) {
48+
// Show native debug output and the profile for debugging.
49+
console.log(output.stderr.toString());
50+
console.log('heap path: ', profiles[0]);
51+
console.log(profile1.roots);
52+
console.log('heap path: ', profiles[1]);
53+
console.log(profile2.roots);
54+
}
55+
assert(profile1.frame || profile2.frame);
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
'use strict';
2+
3+
// Tests invalid --heap-prof CLI arguments.
4+
5+
const common = require('../common');
6+
7+
const fixtures = require('../common/fixtures');
8+
common.skipIfInspectorDisabled();
9+
10+
const assert = require('assert');
11+
const { spawnSync } = require('child_process');
12+
13+
const tmpdir = require('../common/tmpdir');
14+
15+
const {
16+
kHeapProfInterval,
17+
env
18+
} = require('../common/prof');
19+
20+
// Tests --heap-prof-name without --heap-prof.
21+
{
22+
tmpdir.refresh();
23+
const output = spawnSync(process.execPath, [
24+
'--heap-prof-name',
25+
'test.heapprofile',
26+
fixtures.path('workload', 'allocation.js'),
27+
], {
28+
cwd: tmpdir.path,
29+
env
30+
});
31+
const stderr = output.stderr.toString().trim();
32+
if (output.status !== 9) {
33+
console.log(stderr);
34+
}
35+
assert.strictEqual(output.status, 9);
36+
assert.strictEqual(
37+
stderr,
38+
`${process.execPath}: --heap-prof-name must be used with --heap-prof`);
39+
}
40+
41+
// Tests --heap-prof-dir without --heap-prof.
42+
{
43+
tmpdir.refresh();
44+
const output = spawnSync(process.execPath, [
45+
'--heap-prof-dir',
46+
'prof',
47+
fixtures.path('workload', 'allocation.js'),
48+
], {
49+
cwd: tmpdir.path,
50+
env
51+
});
52+
const stderr = output.stderr.toString().trim();
53+
if (output.status !== 9) {
54+
console.log(stderr);
55+
}
56+
assert.strictEqual(output.status, 9);
57+
assert.strictEqual(
58+
stderr,
59+
`${process.execPath}: --heap-prof-dir must be used with --heap-prof`);
60+
}
61+
62+
// Tests --heap-prof-interval without --heap-prof.
63+
{
64+
tmpdir.refresh();
65+
const output = spawnSync(process.execPath, [
66+
'--heap-prof-interval',
67+
kHeapProfInterval,
68+
fixtures.path('workload', 'allocation.js'),
69+
], {
70+
cwd: tmpdir.path,
71+
env
72+
});
73+
const stderr = output.stderr.toString().trim();
74+
if (output.status !== 9) {
75+
console.log(stderr);
76+
}
77+
assert.strictEqual(output.status, 9);
78+
assert.strictEqual(
79+
stderr,
80+
`${process.execPath}: ` +
81+
'--heap-prof-interval must be used with --heap-prof');
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
'use strict';
2+
3+
// Tests that --heap-prof outputs heap profile when event loop is drained.
4+
5+
const common = require('../common');
6+
7+
const fixtures = require('../common/fixtures');
8+
common.skipIfInspectorDisabled();
9+
10+
const assert = require('assert');
11+
const { spawnSync } = require('child_process');
12+
13+
const tmpdir = require('../common/tmpdir');
14+
15+
const {
16+
getHeapProfiles,
17+
verifyFrames,
18+
kHeapProfInterval,
19+
env,
20+
} = require('../common/prof');
21+
22+
{
23+
tmpdir.refresh();
24+
const output = spawnSync(process.execPath, [
25+
'--heap-prof',
26+
'--heap-prof-interval',
27+
kHeapProfInterval,
28+
fixtures.path('workload', 'allocation.js'),
29+
], {
30+
cwd: tmpdir.path,
31+
env
32+
});
33+
if (output.status !== 0) {
34+
console.log(output.stderr.toString());
35+
console.log(output);
36+
}
37+
assert.strictEqual(output.status, 0);
38+
const profiles = getHeapProfiles(tmpdir.path);
39+
assert.strictEqual(profiles.length, 1);
40+
verifyFrames(output, profiles[0], 'runAllocation');
41+
}

‎test/parallel/test-heap-prof-name.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
'use strict';
2+
3+
// Tests --heap-prof-name works.
4+
5+
const common = require('../common');
6+
7+
const fixtures = require('../common/fixtures');
8+
common.skipIfInspectorDisabled();
9+
10+
const assert = require('assert');
11+
const path = require('path');
12+
const { spawnSync } = require('child_process');
13+
14+
const tmpdir = require('../common/tmpdir');
15+
16+
const {
17+
getHeapProfiles,
18+
verifyFrames,
19+
kHeapProfInterval,
20+
env
21+
} = require('../common/prof');
22+
23+
{
24+
tmpdir.refresh();
25+
const file = path.join(tmpdir.path, 'test.heapprofile');
26+
const output = spawnSync(process.execPath, [
27+
'--heap-prof',
28+
'--heap-prof-name',
29+
'test.heapprofile',
30+
'--heap-prof-interval',
31+
kHeapProfInterval,
32+
fixtures.path('workload', 'allocation.js'),
33+
], {
34+
cwd: tmpdir.path,
35+
env
36+
});
37+
if (output.status !== 0) {
38+
console.log(output.stderr.toString());
39+
}
40+
assert.strictEqual(output.status, 0);
41+
const profiles = getHeapProfiles(tmpdir.path);
42+
assert.deepStrictEqual(profiles, [file]);
43+
verifyFrames(output, file, 'runAllocation');
44+
}
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use strict';
2+
3+
// Tests --heap-prof generates a heap profile when
4+
// process.kill(process.pid, "SIGINT"); exits process.
5+
6+
const common = require('../common');
7+
8+
const fixtures = require('../common/fixtures');
9+
common.skipIfInspectorDisabled();
10+
11+
const assert = require('assert');
12+
const { spawnSync } = require('child_process');
13+
14+
const tmpdir = require('../common/tmpdir');
15+
16+
const {
17+
getHeapProfiles,
18+
verifyFrames,
19+
kHeapProfInterval,
20+
env
21+
} = require('../common/prof');
22+
23+
{
24+
tmpdir.refresh();
25+
const output = spawnSync(process.execPath, [
26+
'--heap-prof',
27+
'--heap-prof-interval',
28+
kHeapProfInterval,
29+
fixtures.path('workload', 'allocation-sigint.js'),
30+
], {
31+
cwd: tmpdir.path,
32+
env
33+
});
34+
if (!common.isWindows) {
35+
if (output.signal !== 'SIGINT') {
36+
console.log(output.stderr.toString());
37+
}
38+
assert.strictEqual(output.signal, 'SIGINT');
39+
}
40+
const profiles = getHeapProfiles(tmpdir.path);
41+
assert.strictEqual(profiles.length, 1);
42+
verifyFrames(output, profiles[0], 'runAllocation');
43+
}

‎test/sequential/test-heap-prof.js

-375
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.