test: add test for Linux perf · nodejs/node@a4ad989
1+'use strict';
2+3+// This test verifies that JavaScript functions are being correctly sampled by
4+// Linux perf. The test runs a JavaScript script, sampling the execution with
5+// Linux perf. It then uses `perf script` to generate a human-readable output,
6+// and uses regular expressions to find samples of the functions defined in
7+// `fixtures/linux-perf.js`.
8+9+// NOTE (mmarchini): this test is meant to run only on Linux machines with Linux
10+// perf installed. It will skip if those criteria are not met.
11+12+const common = require('../common');
13+if (!common.hasCrypto)
14+common.skip('missing crypto');
15+16+const assert = require('assert');
17+const { spawnSync } = require('child_process');
18+const fixtures = require('../common/fixtures');
19+const tmpdir = require('../common/tmpdir');
20+tmpdir.refresh();
21+22+if (process.config.variables.node_shared)
23+common.skip("can't test Linux perf with shared libraries yet");
24+25+const perfArgs = [
26+'record',
27+'-F500',
28+'-g',
29+'--',
30+process.execPath,
31+'--perf-basic-prof',
32+'--interpreted-frames-native-stack',
33+'--no-turbo-inlining', // Otherwise simple functions might get inlined.
34+fixtures.path('linux-perf.js'),
35+];
36+37+const perfScriptArgs = [
38+'script',
39+];
40+41+const options = {
42+cwd: tmpdir.path,
43+encoding: 'utf-8',
44+};
45+46+if (!common.isLinux)
47+common.skip('only testing Linux for now');
48+49+const perf = spawnSync('perf', perfArgs, options);
50+51+if (perf.error && perf.error.errno === 'ENOENT')
52+common.skip('perf not found on system');
53+54+if (perf.status !== 0) {
55+common.skip(`Failed to execute perf: ${perf.stderr}`);
56+}
57+58+const perfScript = spawnSync('perf', perfScriptArgs, options);
59+60+if (perf.error)
61+common.skip(`perf script aborted: ${perf.error.errno}`);
62+63+if (perfScript.status !== 0) {
64+common.skip(`Failed to execute perf script: ${perfScript.stderr}`);
65+}
66+67+const interpretedFunctionOneRe = /InterpretedFunction:functionOne/;
68+const compiledFunctionOneRe = /LazyCompile:\*functionOne/;
69+const interpretedFunctionTwoRe = /InterpretedFunction:functionTwo/;
70+const compiledFunctionTwoRe = /LazyCompile:\*functionTwo/;
71+72+const output = perfScript.stdout;
73+74+assert.ok(output.match(interpretedFunctionOneRe),
75+"Couldn't find interpreted functionOne()");
76+assert.ok(output.match(compiledFunctionOneRe),
77+"Couldn't find compiled functionOne()");
78+assert.ok(output.match(interpretedFunctionTwoRe),
79+"Couldn't find interpreted functionTwo()");
80+assert.ok(output.match(compiledFunctionTwoRe),
81+"Couldn't find compiled functionTwo");