|
1 | 1 | 'use strict'; |
2 | 2 |
|
3 | 3 | constcommon=require('../common'); |
4 | | -constassert=require('assert'); |
5 | 4 | const{ performance }=require('perf_hooks'); |
| 5 | +// Get the start time as soon as possible. |
| 6 | +consttestStartTime=performance.now(); |
| 7 | +constassert=require('assert'); |
| 8 | +const{ writeSync }=require('fs'); |
6 | 9 |
|
7 | | -if(!common.isMainThread) |
8 | | -common.skip('bootstrapping workers works differently'); |
| 10 | +// Use writeSync to stdout to avoid disturbing the loop. |
| 11 | +functionlog(str){ |
| 12 | +writeSync(1,str+'\n'); |
| 13 | +} |
9 | 14 |
|
10 | 15 | assert(performance); |
11 | 16 | assert(performance.nodeTiming); |
12 | 17 | assert.strictEqual(typeofperformance.timeOrigin,'number'); |
| 18 | + |
| 19 | +assert(testStartTime>0,`${testStartTime} <= 0`); |
13 | 20 | // Use a fairly large epsilon value, since we can only guarantee that the node |
14 | 21 | // process started up in 15 seconds. |
15 | | -assert(Math.abs(performance.timeOrigin-Date.now())<15000); |
| 22 | +assert(testStartTime<15000,`${testStartTime} >= 15000`); |
16 | 23 |
|
17 | | -constinited=performance.now(); |
18 | | -assert(inited<15000); |
| 24 | +// Use different ways to calculate process uptime to check that |
| 25 | +// performance.timeOrigin and performance.now() are in reasonable range. |
| 26 | +constepsilon=50; |
| 27 | +{ |
| 28 | +constuptime1=Date.now()-performance.timeOrigin; |
| 29 | +constuptime2=performance.now(); |
| 30 | +constuptime3=process.uptime()*1000; |
| 31 | +assert(Math.abs(uptime1-uptime2)<epsilon, |
| 32 | +`Date.now() - performance.timeOrigin (${uptime1}) - `+ |
| 33 | +`performance.now() (${uptime2}) = `+ |
| 34 | +`${uptime1-uptime2} >= +- ${epsilon}`); |
| 35 | +assert(Math.abs(uptime1-uptime3)<epsilon, |
| 36 | +`Date.now() - performance.timeOrigin (${uptime1}) - `+ |
| 37 | +`process.uptime() * 1000 (${uptime3}) = `+ |
| 38 | +`${uptime1-uptime3} >= +- ${epsilon}`); |
| 39 | +} |
19 | 40 |
|
20 | 41 | assert.strictEqual(performance.nodeTiming.name,'node'); |
21 | 42 | assert.strictEqual(performance.nodeTiming.entryType,'node'); |
22 | 43 |
|
23 | | -constdelay=250; |
24 | | -functioncheckNodeTiming(props){ |
25 | | -console.log(props); |
26 | | - |
27 | | -for(constpropofObject.keys(props)){ |
28 | | -if(props[prop].around!==undefined){ |
29 | | -assert.strictEqual(typeofperformance.nodeTiming[prop],'number'); |
30 | | -constdelta=performance.nodeTiming[prop]-props[prop].around; |
31 | | -assert( |
32 | | -Math.abs(delta)<(props[prop].delay||delay), |
33 | | -`${prop}: ${Math.abs(delta)} >= ${props[prop].delay||delay}` |
34 | | -); |
35 | | -}else{ |
36 | | -assert.strictEqual(performance.nodeTiming[prop],props[prop], |
37 | | -`mismatch for performance property ${prop}: `+ |
38 | | -`${performance.nodeTiming[prop]} vs ${props[prop]}`); |
39 | | -} |
40 | | -} |
| 44 | +// Copy all the values from the getters. |
| 45 | +constinitialTiming={ ...performance.nodeTiming}; |
| 46 | + |
| 47 | +{ |
| 48 | +const{ |
| 49 | + startTime, |
| 50 | + nodeStart, |
| 51 | + v8Start, |
| 52 | + environment, |
| 53 | + bootstrapComplete, |
| 54 | +}=initialTiming; |
| 55 | + |
| 56 | +assert.strictEqual(startTime,0); |
| 57 | +assert.strictEqual(typeofnodeStart,'number'); |
| 58 | +assert(nodeStart>0,`nodeStart ${nodeStart} <= 0`); |
| 59 | +// The whole process starts before this test starts. |
| 60 | +assert(nodeStart<testStartTime, |
| 61 | +`nodeStart ${nodeStart} >= ${testStartTime}`); |
| 62 | + |
| 63 | +assert.strictEqual(typeofv8Start,'number'); |
| 64 | +assert(v8Start>0,`v8Start ${v8Start} <= 0`); |
| 65 | +// V8 starts after the process starts. |
| 66 | +assert(v8Start>nodeStart,`v8Start ${v8Start} <= ${nodeStart}`); |
| 67 | +// V8 starts before this test starts. |
| 68 | +assert(v8Start<testStartTime, |
| 69 | +`v8Start ${v8Start} >= ${testStartTime}`); |
| 70 | + |
| 71 | +assert.strictEqual(typeofenvironment,'number'); |
| 72 | +assert(environment>0,`environment ${environment} <= 0`); |
| 73 | +// Environment starts after V8 starts. |
| 74 | +assert(environment>v8Start, |
| 75 | +`environment ${environment} <= ${v8Start}`); |
| 76 | +// Environment starts before this test starts. |
| 77 | +assert(environment<testStartTime, |
| 78 | +`environment ${environment} >= ${testStartTime}`); |
| 79 | + |
| 80 | +assert.strictEqual(typeofbootstrapComplete,'number'); |
| 81 | +assert(bootstrapComplete>0,`bootstrapComplete ${bootstrapComplete} <= 0`); |
| 82 | +// Bootstrap completes after environment starts. |
| 83 | +assert(bootstrapComplete>environment, |
| 84 | +`bootstrapComplete ${bootstrapComplete} <= ${environment}`); |
| 85 | +// Bootstrap completes before this test starts. |
| 86 | +assert(bootstrapComplete<testStartTime, |
| 87 | +`bootstrapComplete ${bootstrapComplete} >= ${testStartTime}`); |
41 | 88 | } |
42 | 89 |
|
43 | | -checkNodeTiming({ |
44 | | -name: 'node', |
45 | | -entryType: 'node', |
46 | | -startTime: 0, |
47 | | -duration: {around: performance.now()}, |
48 | | -nodeStart: {around: 0}, |
49 | | -v8Start: {around: 0}, |
50 | | -bootstrapComplete: {around: inited,delay: 2500}, |
51 | | -environment: {around: 0}, |
52 | | -loopStart: -1, |
53 | | -loopExit: -1 |
54 | | -}); |
| 90 | +functioncheckNodeTiming(timing){ |
| 91 | +// Calculate the difference between now() and duration as soon as possible. |
| 92 | +constnow=performance.now(); |
| 93 | +constdelta=Math.abs(now-timing.duration); |
| 94 | + |
| 95 | +log(JSON.stringify(timing,null,2)); |
| 96 | +// Check that the properties are still reasonable. |
| 97 | +assert.strictEqual(timing.name,'node'); |
| 98 | +assert.strictEqual(timing.entryType,'node'); |
| 99 | + |
| 100 | +// Check that duration is positive and practically the same as |
| 101 | +// performance.now() i.e. measures Node.js instance up time. |
| 102 | +assert.strictEqual(typeoftiming.duration,'number'); |
| 103 | +assert(timing.duration>0,`timing.duration ${timing.duration} <= 0`); |
| 104 | +assert(delta<10, |
| 105 | +`now (${now}) - timing.duration (${timing.duration}) = ${delta} >= 10`); |
| 106 | + |
| 107 | +// Check that the following fields do not change. |
| 108 | +assert.strictEqual(timing.startTime,initialTiming.startTime); |
| 109 | +assert.strictEqual(timing.nodeStart,initialTiming.nodeStart); |
| 110 | +assert.strictEqual(timing.v8Start,initialTiming.v8Start); |
| 111 | +assert.strictEqual(timing.environment,initialTiming.environment); |
| 112 | +assert.strictEqual(timing.bootstrapComplete,initialTiming.bootstrapComplete); |
| 113 | + |
| 114 | +assert.strictEqual(typeoftiming.loopStart,'number'); |
| 115 | +assert.strictEqual(typeoftiming.loopExit,'number'); |
| 116 | +} |
| 117 | + |
| 118 | +log('check initial nodeTiming'); |
| 119 | +checkNodeTiming(initialTiming); |
| 120 | +assert.strictEqual(initialTiming.loopExit,-1); |
55 | 121 |
|
56 | | -setTimeout(()=>{ |
57 | | -checkNodeTiming({ |
58 | | -name: 'node', |
59 | | -entryType: 'node', |
60 | | -startTime: 0, |
61 | | -duration: {around: performance.now()}, |
62 | | -nodeStart: {around: 0}, |
63 | | -v8Start: {around: 0}, |
64 | | -bootstrapComplete: {around: inited,delay: 2500}, |
65 | | -environment: {around: 0}, |
66 | | -loopStart: {around: inited,delay: 2500}, |
67 | | -loopExit: -1 |
68 | | -}); |
69 | | -},1000); |
| 122 | +functioncheckValue(timing,name,min,max){ |
| 123 | +constvalue=timing[name]; |
| 124 | +assert(value>0,`${name}${value} <= 0`); |
| 125 | +// Loop starts after bootstrap completes. |
| 126 | +assert(value>min, |
| 127 | +`${name}${value} <= ${min}`); |
| 128 | +assert(value<max,`${name}${value} >= ${max}`); |
| 129 | +} |
| 130 | + |
| 131 | +letloopStart=initialTiming.loopStart; |
| 132 | +if(common.isMainThread){ |
| 133 | +// In the main thread, the loop does not start until we start an operation |
| 134 | +// that requires it, e.g. setTimeout(). |
| 135 | +assert.strictEqual(initialTiming.loopStart,-1); |
| 136 | +log('Start timer'); |
| 137 | +setTimeout(()=>{ |
| 138 | +log('Check nodeTiming in timer'); |
| 139 | +consttiming={ ...performance.nodeTiming}; |
| 140 | +checkNodeTiming(timing); |
| 141 | +// Loop should start after we fire the timeout, and before we call |
| 142 | +// performance.now() here. |
| 143 | +loopStart=timing.loopStart; |
| 144 | +checkValue(timing,'loopStart',initialTiming.duration,performance.now()); |
| 145 | +},1000); |
| 146 | +}else{ |
| 147 | +// In the worker, the loop always starts before the user code is evaluated, |
| 148 | +// and after bootstrap completes. |
| 149 | +checkValue(initialTiming, |
| 150 | +'loopStart', |
| 151 | +initialTiming.bootstrapComplete, |
| 152 | +testStartTime); |
| 153 | +} |
70 | 154 |
|
71 | 155 | process.on('exit',()=>{ |
72 | | -checkNodeTiming({ |
73 | | -name: 'node', |
74 | | -entryType: 'node', |
75 | | -startTime: 0, |
76 | | -duration: {around: performance.now()}, |
77 | | -nodeStart: {around: 0}, |
78 | | -v8Start: {around: 0}, |
79 | | -bootstrapComplete: {around: inited,delay: 2500}, |
80 | | -environment: {around: 0}, |
81 | | -loopStart: {around: inited,delay: 2500}, |
82 | | -loopExit: {around: performance.now()} |
83 | | -}); |
| 156 | +log('Check nodeTiming in process exit event'); |
| 157 | +consttiming={ ...performance.nodeTiming}; |
| 158 | +checkNodeTiming(timing); |
| 159 | +// Check that loopStart does not change. |
| 160 | +assert.strictEqual(timing.loopStart,loopStart); |
| 161 | +checkValue(timing, |
| 162 | +'loopExit', |
| 163 | +loopStart, |
| 164 | +performance.now()); |
84 | 165 | }); |
0 commit comments