Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add test for Linux perf #20783

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@ test-with-async-hooks:
.PHONY: test-v8-all
.PHONY: test-v8-benchmarks
.PHONY: test-v8-intl
.PHONY: test-v8-updates
ifneq ("","$(wildcard deps/v8/tools/run-tests.py)")
# Related CI job: node-test-commit-v8-linux
test-v8: v8 ## Runs the V8 test suite on deps/v8.
Expand All @@ -580,7 +581,10 @@ test-v8-benchmarks: v8
benchmarks \
$(TAP_V8_BENCHMARKS)

test-v8-all: test-v8 test-v8-intl test-v8-benchmarks
test-v8-updates:
$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) v8-updates

test-v8-all: test-v8 test-v8-intl test-v8-benchmarks test-v8-updates
# runs all v8 tests
else
test-v8 test-v8-intl test-v8-benchmarks test-v8-all:
Expand Down
26 changes: 26 additions & 0 deletions test/fixtures/linux-perf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use strict';

const crypto = require('crypto');

// Functions should be complex enough for V8 to run them a few times before
// compiling, but not complex enough to always stay in interpreted mode. They
// should also take some time to run, otherwise Linux perf might miss them
// entirely even when sampling at a high frequency.
function functionOne(i) {
for (let j=i; j > 0; j--) {
crypto.createHash('md5').update(functionTwo(i, j)).digest("hex");
}
}

function functionTwo(x, y) {
let data = ((((x * y) + (x / y)) * y) ** (x + 1)).toString();
if (x % 2 == 0) {
return crypto.createHash('md5').update(data.repeat((x % 100) + 1)).digest("hex");
} else {
return crypto.createHash('md5').update(data.repeat((y % 100) + 1)).digest("hex");
}
}

for (let i = 0; i < 1000; i++) {
functionOne(i);
}
2 changes: 0 additions & 2 deletions test/parallel/parallel.status
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ prefix parallel
# sample-test : PASS,FLAKY

[true] # This section applies to all platforms
# Postmortem debugging data is prone to accidental removal during V8 updates.
test-postmortem-metadata: PASS,FLAKY

[$system==win32]
test-child-process-fork-net: PASS,FLAKY
Expand Down
81 changes: 81 additions & 0 deletions test/v8-updates/test-linux-perf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
'use strict';

// This test verifies that JavaScript functions are being correctly sampled by
// Linux perf. The test runs a JavaScript script, sampling the execution with
// Linux perf. It then uses `perf script` to generate a human-readable output,
// and uses regular expressions to find samples of the functions defined in
// `fixtures/linux-perf.js`.

// NOTE (mmarchini): this test is meant to run only on Linux machines with Linux
// perf installed. It will skip if those criteria are not met.

const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const assert = require('assert');
const { spawnSync } = require('child_process');
const fixtures = require('../common/fixtures');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();

if (process.config.variables.node_shared)
common.skip("can't test Linux perf with shared libraries yet");

const perfArgs = [
'record',
'-F500',
'-g',
'--',
process.execPath,
'--perf-basic-prof',
'--interpreted-frames-native-stack',
'--no-turbo-inlining', // Otherwise simple functions might get inlined.
fixtures.path('linux-perf.js'),
];

const perfScriptArgs = [
'script',
];

const options = {
cwd: tmpdir.path,
encoding: 'utf-8',
};

if (!common.isLinux)
common.skip('only testing Linux for now');

const perf = spawnSync('perf', perfArgs, options);

if (perf.error && perf.error.errno === 'ENOENT')
common.skip('perf not found on system');

if (perf.status !== 0) {
common.skip(`Failed to execute perf: ${perf.stderr}`);
}

const perfScript = spawnSync('perf', perfScriptArgs, options);

if (perf.error)
common.skip(`perf script aborted: ${perf.error.errno}`);

if (perfScript.status !== 0) {
common.skip(`Failed to execute perf script: ${perfScript.stderr}`);
}

const interpretedFunctionOneRe = /InterpretedFunction:functionOne/;
const compiledFunctionOneRe = /LazyCompile:\*functionOne/;
const interpretedFunctionTwoRe = /InterpretedFunction:functionTwo/;
const compiledFunctionTwoRe = /LazyCompile:\*functionTwo/;

const output = perfScript.stdout;

assert.ok(output.match(interpretedFunctionOneRe),
"Couldn't find interpreted functionOne()");
assert.ok(output.match(compiledFunctionOneRe),
"Couldn't find compiled functionOne()");
assert.ok(output.match(interpretedFunctionTwoRe),
"Couldn't find interpreted functionTwo()");
assert.ok(output.match(compiledFunctionTwoRe),
"Couldn't find compiled functionTwo");
6 changes: 6 additions & 0 deletions test/v8-updates/testcfg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import testpy

def GetConfiguration(context, root):
return testpy.ParallelTestConfiguration(context, root, 'v8-updates')
21 changes: 21 additions & 0 deletions test/v8-updates/v8-updates.status
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
prefix v8-updates

# To mark a test as flaky, list the test name in the appropriate section
# below, without ".js", followed by ": PASS,FLAKY". Example:
# sample-test : PASS,FLAKY

[true] # This section applies to all platforms

[$system==win32]

[$system==linux]

[$system==macos]

[$arch==arm || $arch==arm64]

[$system==solaris] # Also applies to SmartOS

[$system==freebsd]

[$system==aix]
3 changes: 2 additions & 1 deletion tools/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1553,7 +1553,8 @@ def PrintCrashed(code):
'pummel',
'test-known-issues',
'tick-processor',
'timers'
'timers',
'v8-updates'
]


Expand Down