Skip to content

Commit a4ad989

Browse files
Matheus Marchinitargos
authored andcommitted
test: add test for Linux perf
This commit adds a test to validate if Linux perf is working correctly on Node.js. The test is marked as flaky because its intention is to let us know when changes on V8 potentially broke Linux perf, so we can fix it before a new version of V8 lands on Node.js master. PR-URL: #20783 Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
1 parent e16036c commit a4ad989

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

‎test/fixtures/linux-perf.js‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use strict';
2+
3+
constcrypto=require('crypto');
4+
5+
// Functions should be complex enough for V8 to run them a few times before
6+
// compiling, but not complex enough to always stay in interpreted mode. They
7+
// should also take some time to run, otherwise Linux perf might miss them
8+
// entirely even when sampling at a high frequency.
9+
functionfunctionOne(i){
10+
for(letj=i;j>0;j--){
11+
crypto.createHash('md5').update(functionTwo(i,j)).digest("hex");
12+
}
13+
}
14+
15+
functionfunctionTwo(x,y){
16+
letdata=((((x*y)+(x/y))*y)**(x+1)).toString();
17+
if(x%2==0){
18+
returncrypto.createHash('md5').update(data.repeat((x%100)+1)).digest("hex");
19+
}else{
20+
returncrypto.createHash('md5').update(data.repeat((y%100)+1)).digest("hex");
21+
}
22+
}
23+
24+
for(leti=0;i<1000;i++){
25+
functionOne(i);
26+
}

‎test/v8-updates/test-linux-perf.js‎

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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+
constcommon=require('../common');
13+
if(!common.hasCrypto)
14+
common.skip('missing crypto');
15+
16+
constassert=require('assert');
17+
const{ spawnSync }=require('child_process');
18+
constfixtures=require('../common/fixtures');
19+
consttmpdir=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+
constperfArgs=[
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+
constperfScriptArgs=[
38+
'script',
39+
];
40+
41+
constoptions={
42+
cwd: tmpdir.path,
43+
encoding: 'utf-8',
44+
};
45+
46+
if(!common.isLinux)
47+
common.skip('only testing Linux for now');
48+
49+
constperf=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+
constperfScript=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+
constinterpretedFunctionOneRe=/InterpretedFunction:functionOne/;
68+
constcompiledFunctionOneRe=/LazyCompile:\*functionOne/;
69+
constinterpretedFunctionTwoRe=/InterpretedFunction:functionTwo/;
70+
constcompiledFunctionTwoRe=/LazyCompile:\*functionTwo/;
71+
72+
constoutput=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");

0 commit comments

Comments
(0)