• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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