11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci// This test verifies that JavaScript functions are being correctly sampled by
41cb0ef41Sopenharmony_ci// Linux perf. The test runs a JavaScript script, sampling the execution with
51cb0ef41Sopenharmony_ci// Linux perf. It then uses `perf script` to generate a human-readable output,
61cb0ef41Sopenharmony_ci// and uses regular expressions to find samples of the functions defined in
71cb0ef41Sopenharmony_ci// `fixtures/linux-perf.js`.
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci// NOTE (mmarchini): this test is meant to run only on Linux machines with Linux
101cb0ef41Sopenharmony_ci// perf installed. It will skip if those criteria are not met.
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ciconst common = require('../common');
131cb0ef41Sopenharmony_ciif (!common.hasCrypto)
141cb0ef41Sopenharmony_ci  common.skip('missing crypto');
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ciconst assert = require('assert');
171cb0ef41Sopenharmony_ciconst { spawnSync } = require('child_process');
181cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures');
191cb0ef41Sopenharmony_ciconst tmpdir = require('../common/tmpdir');
201cb0ef41Sopenharmony_citmpdir.refresh();
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ciif (process.config.variables.node_shared)
231cb0ef41Sopenharmony_ci  common.skip("can't test Linux perf with shared libraries yet");
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ciif (!common.isLinux)
261cb0ef41Sopenharmony_ci  common.skip('only testing Linux for now');
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ciconst frequency = 99;
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ciconst repeat = 5;
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci// Expected number of samples we'll capture per repeat
331cb0ef41Sopenharmony_ciconst sampleCount = 10;
341cb0ef41Sopenharmony_ciconst sleepTime = sampleCount * (1.0 / frequency);
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ciconst perfFlags = [
371cb0ef41Sopenharmony_ci  'record',
381cb0ef41Sopenharmony_ci  `-F${frequency}`,
391cb0ef41Sopenharmony_ci  '-g',
401cb0ef41Sopenharmony_ci];
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ciconst nodeCommonFlags = [
431cb0ef41Sopenharmony_ci  '--perf-basic-prof',
441cb0ef41Sopenharmony_ci  '--interpreted-frames-native-stack',
451cb0ef41Sopenharmony_ci  '--no-turbo-inlining',  // Otherwise simple functions might get inlined.
461cb0ef41Sopenharmony_ci];
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ciconst perfInterpretedFramesArgs = [
491cb0ef41Sopenharmony_ci  ...perfFlags,
501cb0ef41Sopenharmony_ci  '--',
511cb0ef41Sopenharmony_ci  process.execPath,
521cb0ef41Sopenharmony_ci  ...nodeCommonFlags,
531cb0ef41Sopenharmony_ci  '--no-opt',
541cb0ef41Sopenharmony_ci  fixtures.path('linux-perf.js'),
551cb0ef41Sopenharmony_ci  `${sleepTime}`,
561cb0ef41Sopenharmony_ci  `${repeat}`,
571cb0ef41Sopenharmony_ci];
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ciconst perfCompiledFramesArgs = [
601cb0ef41Sopenharmony_ci  ...perfFlags,
611cb0ef41Sopenharmony_ci  '--',
621cb0ef41Sopenharmony_ci  process.execPath,
631cb0ef41Sopenharmony_ci  ...nodeCommonFlags,
641cb0ef41Sopenharmony_ci  '--always-opt',
651cb0ef41Sopenharmony_ci  fixtures.path('linux-perf.js'),
661cb0ef41Sopenharmony_ci  `${sleepTime}`,
671cb0ef41Sopenharmony_ci  `${repeat}`,
681cb0ef41Sopenharmony_ci];
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ciconst perfArgsList = [
711cb0ef41Sopenharmony_ci  perfInterpretedFramesArgs, perfCompiledFramesArgs,
721cb0ef41Sopenharmony_ci];
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ciconst perfScriptArgs = [
751cb0ef41Sopenharmony_ci  'script',
761cb0ef41Sopenharmony_ci];
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ciconst options = {
791cb0ef41Sopenharmony_ci  cwd: tmpdir.path,
801cb0ef41Sopenharmony_ci  encoding: 'utf-8',
811cb0ef41Sopenharmony_ci};
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_cilet output = '';
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_cifor (const perfArgs of perfArgsList) {
861cb0ef41Sopenharmony_ci  const perf = spawnSync('perf', perfArgs, options);
871cb0ef41Sopenharmony_ci  assert.ifError(perf.error);
881cb0ef41Sopenharmony_ci  if (perf.status !== 0)
891cb0ef41Sopenharmony_ci    throw new Error(`Failed to execute 'perf': ${perf.stderr}`);
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci  const perfScript = spawnSync('perf', perfScriptArgs, options);
921cb0ef41Sopenharmony_ci  assert.ifError(perfScript.error);
931cb0ef41Sopenharmony_ci  if (perfScript.status !== 0)
941cb0ef41Sopenharmony_ci    throw new Error(`Failed to execute perf script: ${perfScript.stderr}`);
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci  output += perfScript.stdout;
971cb0ef41Sopenharmony_ci}
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ciconst interpretedFunctionOneRe = /~functionOne/;
1001cb0ef41Sopenharmony_ciconst compiledFunctionOneRe = /\*functionOne/;
1011cb0ef41Sopenharmony_ciconst interpretedFunctionTwoRe = /~functionTwo/;
1021cb0ef41Sopenharmony_ciconst compiledFunctionTwoRe = /\*functionTwo/;
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_cifunction makeAssertMessage(message) {
1051cb0ef41Sopenharmony_ci  return message + '\nPerf output:\n\n' + output;
1061cb0ef41Sopenharmony_ci}
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ciassert.ok(output.match(interpretedFunctionOneRe),
1091cb0ef41Sopenharmony_ci          makeAssertMessage("Couldn't find interpreted functionOne()"));
1101cb0ef41Sopenharmony_ciassert.ok(output.match(compiledFunctionOneRe),
1111cb0ef41Sopenharmony_ci          makeAssertMessage("Couldn't find compiled functionOne()"));
1121cb0ef41Sopenharmony_ciassert.ok(output.match(interpretedFunctionTwoRe),
1131cb0ef41Sopenharmony_ci          makeAssertMessage("Couldn't find interpreted functionTwo()"));
1141cb0ef41Sopenharmony_ciassert.ok(output.match(compiledFunctionTwoRe),
1151cb0ef41Sopenharmony_ci          makeAssertMessage("Couldn't find compiled functionTwo"));
116