Skip to content

Commit b2f74c8

Browse files
committed
test: enable trace_events tests with perfetto
Signed-off-by: Chengzhong Wu <cwu631@bloomberg.net>
1 parent efc612d commit b2f74c8

41 files changed

Lines changed: 594 additions & 364 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/test-linux-perfetto.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ jobs:
6262
- name: Build
6363
working-directory: node
6464
run: make build-ci -j4 V=1 CONFIG_FLAGS="--error-on-warn --v8-enable-temporal-support --with-perfetto"
65+
- name: Get trace_processor
66+
working-directory: node
67+
run: make trace_processor
6568
- name: Test
6669
working-directory: node
6770
run: make test-ci -j1 V=1 TEST_CI_ARGS="-p actions --measure-flakiness 9"

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ tools/*/*.i.tmp
116116
/tools/eslint/node_modules
117117
/tools/lint-md/node_modules
118118

119+
# === Rules for tools/perfetto ===
120+
/tools/perfetto/trace_processor_shell
121+
/tools/perfetto/.version
122+
119123
# === Rules for test artifacts ===
120124
/*.tap
121125
/*.xml

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ distclean: ## Remove all build and test artifacts.
235235
$(RM) -r node_modules
236236
$(RM) -r deps/icu
237237
$(RM) -r deps/icu4c*.tgz deps/icu4c*.zip deps/icu-tmp
238+
$(RM) tools/perfetto/trace_processor_shell tools/perfetto/.version
238239
$(RM) $(BINARYTAR).* $(TARBALL).*
239240

240241
.PHONY: check
@@ -338,6 +339,10 @@ coverage-run-js: ## Run JavaScript tests with coverage.
338339
TEST_CI_ARGS="$(TEST_CI_ARGS) --type=coverage" $(MAKE) jstest
339340
$(MAKE) coverage-report-js
340341

342+
.PHONY: trace-processor
343+
trace-processor: ## Download perfetto's trace_processor_shell.
344+
@tools/perfetto/get_trace_processor
345+
341346
.PHONY: test
342347
# This does not run tests of third-party libraries inside deps.
343348
test: all ## Run default tests and build docs.

test/common/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,7 @@ const common = {
10291029
hasSQLite,
10301030
hasFFI,
10311031
hasLocalStorage,
1032+
hasPerfetto,
10321033
invalidArgTypeHelper,
10331034
isAlive,
10341035
isASan,

test/common/trace_events.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
'use strict';
2+
3+
// Reads back the trace file a Node.js process wrote, whichever tracing backend
4+
// produced it. Legacy builds write the Chrome JSON trace format directly.
5+
// Perfetto builds write a binary protobuf trace, which perfetto's
6+
// `trace_processor_shell` converts to the same format. Run `make trace-processor`
7+
// to download it.
8+
9+
const assert = require('assert');
10+
const { spawnSync } = require('child_process');
11+
const fs = require('fs');
12+
const path = require('path');
13+
const common = require('./');
14+
15+
const traceProcessor = path.resolve(
16+
__dirname, '..', '..', 'tools', 'perfetto', 'trace_processor_shell');
17+
18+
// The JSON form of a trace runs about three times the size of the trace it was
19+
// converted from, and the traces these tests produce are a few hundred KiB at
20+
// most. This is an assumed MAX size of a JSON conversion size limit for tests.
21+
const kMaxTraceJsonBytes = 64 * 1024 * 1024;
22+
23+
// Perfetto builds default the file pattern to a .pftrace extension.
24+
const defaultTraceFileName = common.hasPerfetto ? 'node_trace.1.pftrace' :
25+
'node_trace.1.log';
26+
27+
// Only perfetto traces need converting, so a missing trace_processor_shell
28+
// does not stop anything on a legacy build.
29+
function skipIfTraceReaderMissing() {
30+
if (common.hasPerfetto && !fs.existsSync(traceProcessor)) {
31+
common.skip('trace_processor_shell is missing, ' +
32+
'run `make trace-processor` to download it');
33+
}
34+
}
35+
36+
function readTraceEvents(file) {
37+
if (!common.hasPerfetto) {
38+
return JSON.parse(fs.readFileSync(file, 'utf8')).traceEvents;
39+
}
40+
41+
const converted = spawnSync(traceProcessor, ['convert', 'json', file],
42+
{ maxBuffer: kMaxTraceJsonBytes });
43+
assert.ifError(converted.error);
44+
assert.strictEqual(
45+
converted.status, 0,
46+
`trace_processor_shell failed: ${converted.stderr}`);
47+
return JSON.parse(converted.stdout.toString()).traceEvents;
48+
}
49+
50+
// A perfetto trace event carries the single category it was emitted with. The
51+
// legacy backend instead groups it with every ancestor category, so
52+
// `node.net.native` is recorded as `node,node.net,node.net.native`.
53+
function traceCategory(name) {
54+
if (common.hasPerfetto) {
55+
return name;
56+
}
57+
const parts = name.split('.');
58+
return parts.map((_, i) => parts.slice(0, i + 1).join('.')).join(',');
59+
}
60+
61+
module.exports = {
62+
defaultTraceFileName,
63+
readTraceEvents,
64+
skipIfTraceReaderMissing,
65+
traceCategory,
66+
};

test/parallel/test-inspector-tracing-domain.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
const common = require('../common');
44

55
common.skipIfInspectorDisabled();
6+
// The inspector NodeTracing domain is not wired up on a perfetto build, see
7+
// src/inspector_agent.cc, so every command here fails with
8+
// ERR_INSPECTOR_COMMAND.
69
common.skipIfPerfettoEnabled();
710

811
const { isMainThread } = require('worker_threads');

test/parallel/test-module-print-timing.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import tmpdir from '../common/tmpdir.js';
77
import { spawnSyncAndAssert } from '../common/child_process.js';
88
import fixtures from '../common/fixtures.js';
99

10+
// The dynamic tracing case below records nothing on a perfetto build: a
11+
// category enabled after the tracing session started stays off.
1012
skipIfPerfettoEnabled();
1113
tmpdir.refresh();
1214

test/parallel/test-permission-fs-write-trace-events.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
// Flags: --expose-internals
21
'use strict';
32

43
const common = require('../common');
54
const { spawnSyncAndExitWithoutError } = require('../common/child_process');
65
const { isMainThread } = require('worker_threads');
76

8-
common.skipIfPerfettoEnabled();
97
if (!isMainThread) {
108
common.skip('This test only works on a main thread');
119
}
1210

1311
const assert = require('assert');
1412
const fs = require('fs');
1513
const tmpdir = require('../common/tmpdir');
14+
const { defaultTraceFileName } = require('../common/trace_events');
1615

1716
try {
1817
require('trace_events');
@@ -56,7 +55,7 @@ assert.throws(() => {
5655
}, common.expectsError({
5756
code: 'ERR_ACCESS_DENIED',
5857
permission: 'FileSystemWrite',
59-
resource: 'node_trace.1.log',
58+
resource: defaultTraceFileName,
6059
}));
6160

62-
assert.strictEqual(fs.existsSync('node_trace.1.log'), false);
61+
assert.strictEqual(fs.existsSync(defaultTraceFileName), false);

test/parallel/test-trace-events-all.js

Lines changed: 0 additions & 57 deletions
This file was deleted.

test/parallel/test-trace-events-async-hooks-dynamic.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ try {
1010
common.skip('missing trace events');
1111
}
1212

13+
// Perfetto records nothing for a category enabled after the tracing session
14+
// started, so there is no dynamic enabling to test there yet.
1315
common.skipIfPerfettoEnabled();
1416

1517
const assert = require('assert');

0 commit comments

Comments
 (0)