@@ -3,77 +3,81 @@ const common = require('../common');
3
3
const tmpdir = require ( '../common/tmpdir' ) ;
4
4
const fs = require ( 'fs' ) ;
5
5
const assert = require ( 'assert' ) ;
6
- const util = require ( 'util' ) ;
7
- const { spawnSync } = require ( 'child_process' ) ;
6
+ const { spawnSyncAndExitWithoutError } = require ( '../common/child_process' ) ;
8
7
9
8
// Test that --prof also tracks Worker threads.
10
9
// Refs: https://github.com/nodejs/node/issues/24016
11
10
12
11
if ( process . argv [ 2 ] === 'child' ) {
13
- const fs = require ( 'fs' ) ;
14
- let files = fs . readdirSync ( tmpdir . path ) ;
15
- const plog = files . filter ( ( name ) => / \. l o g $ / . test ( name ) ) [ 0 ] ;
16
- if ( plog === undefined ) {
17
- console . error ( '`--prof` did not produce a profile log for parent thread!' ) ;
18
- process . exit ( 1 ) ;
19
- }
20
- const pingpong = `
21
- let counter = 0;
22
- const fs = require('fs');
23
- const { Worker, parentPort } = require('worker_threads');
24
- parentPort.on('message', (m) => {
25
- if (counter++ === 1024)
12
+ let files = fs . readdirSync ( process . cwd ( ) ) ;
13
+ console . log ( 'files found in working directory before worker starts' , files ) ;
14
+ const parentProf = files . find ( ( name ) => name . endsWith ( '.log' ) ) ;
15
+ assert ( parentProf , '--prof did not produce a profile log for parent thread' ) ;
16
+ console . log ( 'parent prof file:' , parentProf ) ;
17
+
18
+ const { Worker } = require ( 'worker_threads' ) ;
19
+ const w = new Worker ( `
20
+ const { parentPort, workerData } = require('worker_threads');
21
+
22
+ const SPIN_MS = 1000;
23
+ const start = Date.now();
24
+ parentPort.on('message', (data) => {
25
+ if (Date.now() - start < SPIN_MS) {
26
+ parentPort.postMessage(data);
27
+ } else {
26
28
process.exit(0);
27
- parentPort.postMessage(
28
- fs.readFileSync(m.toString()).slice(0, 1024 * 1024));
29
+ }
29
30
});
30
- ` ;
31
+ ` , { eval : true } ) ;
31
32
32
- const { Worker } = require ( 'worker_threads' ) ;
33
- const w = new Worker ( pingpong , { eval : true } ) ;
34
- w . on ( 'message' , ( m ) => {
35
- w . postMessage ( __filename ) ;
33
+ let count = 1 ;
34
+ w . postMessage ( 'hello\n' ) ;
35
+ w . on ( 'message' , ( ) => {
36
+ count ++ ;
37
+ w . postMessage ( 'hello\n' ) ;
36
38
} ) ;
37
39
38
40
w . on ( 'exit' , common . mustCall ( ( ) => {
39
- files = fs . readdirSync ( tmpdir . path ) ;
40
- const wlog = files . filter ( ( name ) => / \. l o g $ / . test ( name ) && name !== plog ) [ 0 ] ;
41
- if ( wlog === undefined ) {
42
- console . error ( '`--prof` did not produce a profile log' +
43
- ' for worker thread!' ) ;
44
- process . exit ( 1 ) ;
45
- }
46
- process . exit ( 0 ) ;
41
+ console . log ( `parent posted ${ count } messages` ) ;
42
+ files = fs . readdirSync ( process . cwd ( ) ) ;
43
+ console . log ( 'files found in working directory before worker exits' , files ) ;
44
+ const workerProf = files . find ( ( name ) => name !== parentProf && name . endsWith ( '.log' ) ) ;
45
+ assert ( workerProf , '--prof did not produce a profile log for worker thread' ) ;
46
+ console . log ( 'worker prof file:' , workerProf ) ;
47
47
} ) ) ;
48
- w . postMessage ( __filename ) ;
49
48
} else {
50
49
tmpdir . refresh ( ) ;
51
- const timeout = common . platformTimeout ( 30_000 ) ;
52
- const spawnResult = spawnSync (
50
+
51
+ const workerProfRegexp = / w o r k e r p r o f f i l e : ( .+ \. l o g ) / ;
52
+ const parentProfRegexp = / p a r e n t p r o f f i l e : ( .+ \. l o g ) / ;
53
+ const { stdout } = spawnSyncAndExitWithoutError (
53
54
process . execPath , [ '--prof' , __filename , 'child' ] ,
54
- { cwd : tmpdir . path , encoding : 'utf8' , timeout } ) ;
55
- assert . strictEqual ( spawnResult . stderr . toString ( ) , '' ,
56
- `child exited with an error: \
57
- ${ util . inspect ( spawnResult ) } ` ) ;
58
- assert . strictEqual ( spawnResult . signal , null ,
59
- `child exited with signal: ${ util . inspect ( spawnResult ) } ` ) ;
60
- assert . strictEqual ( spawnResult . status , 0 ,
61
- `child exited with non-zero status: \
62
- ${ util . inspect ( spawnResult ) } ` ) ;
63
- const files = fs . readdirSync ( tmpdir . path ) ;
64
- const logfiles = files . filter ( ( name ) => / \. l o g $ / . test ( name ) ) ;
65
- assert . strictEqual ( logfiles . length , 2 ) ; // Parent thread + child thread.
55
+ { cwd : tmpdir . path , encoding : 'utf8' } , {
56
+ stdout ( output ) {
57
+ console . log ( output ) ;
58
+ assert . match ( output , workerProfRegexp ) ;
59
+ assert . match ( output , parentProfRegexp ) ;
60
+ return true ;
61
+ }
62
+ } ) ;
63
+ const workerProf = stdout . match ( workerProfRegexp ) [ 1 ] ;
64
+ const parentProf = stdout . match ( parentProfRegexp ) [ 1 ] ;
65
+
66
+ const logfiles = fs . readdirSync ( tmpdir . path ) . filter ( ( name ) => name . endsWith ( '.log' ) ) ;
67
+ assert . deepStrictEqual ( new Set ( logfiles ) , new Set ( [ workerProf , parentProf ] ) ) ;
68
+
69
+ const workerLines = fs . readFileSync ( tmpdir . resolve ( workerProf ) , 'utf8' ) . split ( '\n' ) ;
70
+ const parentLines = fs . readFileSync ( tmpdir . resolve ( parentProf ) , 'utf8' ) . split ( '\n' ) ;
66
71
67
- for ( const logfile of logfiles ) {
68
- const lines = fs . readFileSync (
69
- tmpdir . resolve ( logfile ) , 'utf8' ) . split ( '\n' ) ;
70
- const ticks = lines . filter ( ( line ) => / ^ t i c k , / . test ( line ) ) . length ;
72
+ const workerTicks = workerLines . filter ( ( line ) => line . startsWith ( 'tick' ) ) ;
73
+ const parentTicks = parentLines . filter ( ( line ) => line . startsWith ( 'tick' ) ) ;
71
74
72
- // Test that at least 15 ticks have been recorded for both parent and child
73
- // threads. When not tracking Worker threads, only 1 or 2 ticks would
74
- // have been recorded.
75
- // When running locally, this number is usually around 200
76
- // for both threads, so 15 seems like a very safe threshold.
77
- assert ( ticks >= 15 , `${ ticks } >= 15` ) ;
78
- }
75
+ console . log ( 'worker ticks' , workerTicks . length ) ;
76
+ console . log ( 'parent ticks' , parentTicks . length ) ;
77
+ // When not tracking Worker threads, only 1 or 2 ticks would
78
+ // have been recorded.
79
+ // prof_sampling_interval is by default 1 millsecond. A higher NODE_TEST_SPIN_MS
80
+ // should result in more ticks, while 15 should be safe on most machines.
81
+ assert ( workerTicks . length > 15 , `worker ticks <= 15:\n${ workerTicks . join ( '\n' ) } ` ) ;
82
+ assert ( parentTicks . length > 15 , `parent ticks <= 15:\n${ parentTicks . join ( '\n' ) } ` ) ;
79
83
}
0 commit comments