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 12const common = require('../common'); 13if (!common.hasCrypto) 14 common.skip('missing crypto'); 15 16const assert = require('assert'); 17const { spawnSync } = require('child_process'); 18const fixtures = require('../common/fixtures'); 19const tmpdir = require('../common/tmpdir'); 20tmpdir.refresh(); 21 22if (process.config.variables.node_shared) 23 common.skip("can't test Linux perf with shared libraries yet"); 24 25if (!common.isLinux) 26 common.skip('only testing Linux for now'); 27 28const frequency = 99; 29 30const repeat = 5; 31 32// Expected number of samples we'll capture per repeat 33const sampleCount = 10; 34const sleepTime = sampleCount * (1.0 / frequency); 35 36const perfFlags = [ 37 'record', 38 `-F${frequency}`, 39 '-g', 40]; 41 42const nodeCommonFlags = [ 43 '--perf-basic-prof', 44 '--interpreted-frames-native-stack', 45 '--no-turbo-inlining', // Otherwise simple functions might get inlined. 46]; 47 48const perfInterpretedFramesArgs = [ 49 ...perfFlags, 50 '--', 51 process.execPath, 52 ...nodeCommonFlags, 53 '--no-opt', 54 fixtures.path('linux-perf.js'), 55 `${sleepTime}`, 56 `${repeat}`, 57]; 58 59const perfCompiledFramesArgs = [ 60 ...perfFlags, 61 '--', 62 process.execPath, 63 ...nodeCommonFlags, 64 '--always-opt', 65 fixtures.path('linux-perf.js'), 66 `${sleepTime}`, 67 `${repeat}`, 68]; 69 70const perfArgsList = [ 71 perfInterpretedFramesArgs, perfCompiledFramesArgs, 72]; 73 74const perfScriptArgs = [ 75 'script', 76]; 77 78const options = { 79 cwd: tmpdir.path, 80 encoding: 'utf-8', 81}; 82 83let output = ''; 84 85for (const perfArgs of perfArgsList) { 86 const perf = spawnSync('perf', perfArgs, options); 87 assert.ifError(perf.error); 88 if (perf.status !== 0) 89 throw new Error(`Failed to execute 'perf': ${perf.stderr}`); 90 91 const perfScript = spawnSync('perf', perfScriptArgs, options); 92 assert.ifError(perfScript.error); 93 if (perfScript.status !== 0) 94 throw new Error(`Failed to execute perf script: ${perfScript.stderr}`); 95 96 output += perfScript.stdout; 97} 98 99const interpretedFunctionOneRe = /InterpretedFunction:functionOne/; 100const compiledFunctionOneRe = /LazyCompile:\*functionOne/; 101const interpretedFunctionTwoRe = /InterpretedFunction:functionTwo/; 102const compiledFunctionTwoRe = /LazyCompile:\*functionTwo/; 103 104 105assert.ok(output.match(interpretedFunctionOneRe), 106 "Couldn't find interpreted functionOne()"); 107assert.ok(output.match(compiledFunctionOneRe), 108 "Couldn't find compiled functionOne()"); 109assert.ok(output.match(interpretedFunctionTwoRe), 110 "Couldn't find interpreted functionTwo()"); 111assert.ok(output.match(compiledFunctionTwoRe), 112 "Couldn't find compiled functionTwo"); 113