Skip to content

Commit 28880cf

Browse files
TimothyGuMylesBorins
authored andcommitted
perf_hooks: fix timing
Fixes: #17892Fixes: #17893Fixes: #18992 PR-URL: #18993 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
1 parent cc52dae commit 28880cf

6 files changed

Lines changed: 182 additions & 52 deletions

File tree

‎doc/api/perf_hooks.md‎

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ added: v8.5.0
181181

182182
* Returns: {number}
183183

184-
Returns the current high resolution millisecond timestamp.
184+
Returns the current high resolution millisecond timestamp, where 0 represents
185+
the start of the current `node` process.
185186

186187
### performance.timeOrigin
187188
<!-- YAML
@@ -190,8 +191,8 @@ added: v8.5.0
190191

191192
* {number}
192193

193-
The [`timeOrigin`][] specifies the high resolution millisecond timestamp from
194-
which all performance metric durations are measured.
194+
The [`timeOrigin`][] specifies the high resolution millisecond timestamp at
195+
which the current `node` process began, measured in Unix time.
195196

196197
### performance.timerify(fn)
197198
<!-- YAML
@@ -302,7 +303,8 @@ added: v8.5.0
302303
* {number}
303304

304305
The high resolution millisecond timestamp at which the Node.js process
305-
completed bootstrap.
306+
completed bootstrapping. If bootstrapping has not yet finished, the property
307+
has the value of -1.
306308

307309
### performanceNodeTiming.clusterSetupEnd
308310
<!-- YAML
@@ -311,7 +313,8 @@ added: v8.5.0
311313

312314
* {number}
313315

314-
The high resolution millisecond timestamp at which cluster processing ended.
316+
The high resolution millisecond timestamp at which cluster processing ended. If
317+
cluster processing has not yet ended, the property has the value of -1.
315318

316319
### performanceNodeTiming.clusterSetupStart
317320
<!-- YAML
@@ -321,6 +324,7 @@ added: v8.5.0
321324
* {number}
322325

323326
The high resolution millisecond timestamp at which cluster processing started.
327+
If cluster processing has not yet started, the property has the value of -1.
324328

325329
### performanceNodeTiming.loopExit
326330
<!-- YAML
@@ -330,7 +334,8 @@ added: v8.5.0
330334
* {number}
331335

332336
The high resolution millisecond timestamp at which the Node.js event loop
333-
exited.
337+
exited. If the event loop has not yet exited, the property has the value of -1.
338+
It can only have a value of not -1 in a handler of the [`'exit'`][] event.
334339

335340
### performanceNodeTiming.loopStart
336341
<!-- YAML
@@ -340,7 +345,8 @@ added: v8.5.0
340345
* {number}
341346

342347
The high resolution millisecond timestamp at which the Node.js event loop
343-
started.
348+
started. If the event loop has not yet started (e.g., in the first tick of the
349+
main script), the property has the value of -1.
344350

345351
### performanceNodeTiming.moduleLoadEnd
346352
<!-- YAML
@@ -395,8 +401,9 @@ added: v8.5.0
395401

396402
* {number}
397403

398-
The high resolution millisecond timestamp at which third_party_main processing
399-
ended.
404+
The high resolution millisecond timestamp at which third\_party\_main
405+
processing ended. If third\_party\_main processing has not yet ended, the
406+
property has the value of -1.
400407

401408
### performanceNodeTiming.thirdPartyMainStart
402409
<!-- YAML
@@ -405,8 +412,9 @@ added: v8.5.0
405412

406413
* {number}
407414

408-
The high resolution millisecond timestamp at which third_party_main processing
409-
started.
415+
The high resolution millisecond timestamp at which third\_party\_main
416+
processing started. If third\_party\_main processing has not yet started, the
417+
property has the value of -1.
410418

411419
### performanceNodeTiming.v8Start
412420
<!-- YAML
@@ -642,6 +650,7 @@ obs.observe({ entryTypes: ['function'], buffered: true });
642650
require('some-module');
643651
```
644652

653+
[`'exit'`]: process.html#process_event_exit
645654
[`timeOrigin`]: https://w3c.github.io/hr-time/#dom-performance-timeorigin
646655
[Async Hooks]: async_hooks.html
647656
[W3C Performance Timeline]: https://w3c.github.io/performance-timeline/

‎lib/perf_hooks.js‎

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const {
88
observerCounts,
99
setupObservers,
1010
timeOrigin,
11+
timeOriginTimestamp,
1112
timerify,
1213
constants
1314
}=process.binding('performance');
@@ -145,6 +146,13 @@ function now() {
145146
returnhr[0]*1000+hr[1]/1e6;
146147
}
147148

149+
functiongetMilestoneTimestamp(milestoneIdx){
150+
constns=milestones[milestoneIdx];
151+
if(ns===-1)
152+
returnns;
153+
returnns/1e6-timeOrigin;
154+
}
155+
148156
classPerformanceNodeTiming{
149157
constructor(){}
150158

@@ -157,67 +165,72 @@ class PerformanceNodeTiming {
157165
}
158166

159167
getstartTime(){
160-
returntimeOrigin;
168+
return0;
161169
}
162170

163171
getduration(){
164172
returnnow()-timeOrigin;
165173
}
166174

167175
getnodeStart(){
168-
returnmilestones[NODE_PERFORMANCE_MILESTONE_NODE_START];
176+
returngetMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_NODE_START);
169177
}
170178

171179
getv8Start(){
172-
returnmilestones[NODE_PERFORMANCE_MILESTONE_V8_START];
180+
returngetMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_V8_START);
173181
}
174182

175183
getenvironment(){
176-
returnmilestones[NODE_PERFORMANCE_MILESTONE_ENVIRONMENT];
184+
returngetMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_ENVIRONMENT);
177185
}
178186

179187
getloopStart(){
180-
returnmilestones[NODE_PERFORMANCE_MILESTONE_LOOP_START];
188+
returngetMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_LOOP_START);
181189
}
182190

183191
getloopExit(){
184-
returnmilestones[NODE_PERFORMANCE_MILESTONE_LOOP_EXIT];
192+
returngetMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
185193
}
186194

187195
getbootstrapComplete(){
188-
returnmilestones[NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE];
196+
returngetMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
189197
}
190198

191199
getthirdPartyMainStart(){
192-
returnmilestones[NODE_PERFORMANCE_MILESTONE_THIRD_PARTY_MAIN_START];
200+
returngetMilestoneTimestamp(
201+
NODE_PERFORMANCE_MILESTONE_THIRD_PARTY_MAIN_START);
193202
}
194203

195204
getthirdPartyMainEnd(){
196-
returnmilestones[NODE_PERFORMANCE_MILESTONE_THIRD_PARTY_MAIN_END];
205+
returngetMilestoneTimestamp(
206+
NODE_PERFORMANCE_MILESTONE_THIRD_PARTY_MAIN_END);
197207
}
198208

199209
getclusterSetupStart(){
200-
returnmilestones[NODE_PERFORMANCE_MILESTONE_CLUSTER_SETUP_START];
210+
returngetMilestoneTimestamp(
211+
NODE_PERFORMANCE_MILESTONE_CLUSTER_SETUP_START);
201212
}
202213

203214
getclusterSetupEnd(){
204-
returnmilestones[NODE_PERFORMANCE_MILESTONE_CLUSTER_SETUP_END];
215+
returngetMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_CLUSTER_SETUP_END);
205216
}
206217

207218
getmoduleLoadStart(){
208-
returnmilestones[NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_START];
219+
returngetMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_START);
209220
}
210221

211222
getmoduleLoadEnd(){
212-
returnmilestones[NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_END];
223+
returngetMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_END);
213224
}
214225

215226
getpreloadModuleLoadStart(){
216-
returnmilestones[NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_START];
227+
returngetMilestoneTimestamp(
228+
NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_START);
217229
}
218230

219231
getpreloadModuleLoadEnd(){
220-
returnmilestones[NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_END];
232+
returngetMilestoneTimestamp(
233+
NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_END);
221234
}
222235

223236
[kInspect](){
@@ -466,11 +479,11 @@ class Performance extends PerformanceObserverEntryList {
466479
}
467480

468481
gettimeOrigin(){
469-
returntimeOrigin;
482+
returntimeOriginTimestamp;
470483
}
471484

472485
now(){
473-
returnnow();
486+
returnnow()-timeOrigin;
474487
}
475488

476489
mark(name){
@@ -549,8 +562,9 @@ class Performance extends PerformanceObserverEntryList {
549562

550563
[kInspect](){
551564
return{
552-
timeOrigin,
553-
nodeTiming
565+
maxEntries: this.maxEntries,
566+
nodeTiming: this.nodeTiming,
567+
timeOrigin: this.timeOrigin
554568
};
555569
}
556570
}

‎src/node_perf.cc‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
#include<vector>
55

6+
#ifdef __POSIX__
7+
#include<sys/time.h>// gettimeofday
8+
#endif
9+
610
namespacenode {
711
namespaceperformance {
812

@@ -21,13 +25,38 @@ using v8::Object;
2125
using v8::String;
2226
using v8::Value;
2327

28+
// Microseconds in a second, as a float.
29+
#defineMICROS_PER_SEC1e6
30+
// Microseconds in a millisecond, as a float.
31+
#defineMICROS_PER_MILLIS1e3
32+
33+
// https://w3c.github.io/hr-time/#dfn-time-origin
2434
constuint64_t timeOrigin = PERFORMANCE_NOW();
35+
// https://w3c.github.io/hr-time/#dfn-time-origin-timestamp
36+
constdouble timeOriginTimestamp = GetCurrentTimeInMicroseconds();
2537
uint64_t performance_node_start;
2638
uint64_t performance_v8_start;
2739

2840
uint64_t performance_last_gc_start_mark_ = 0;
2941
v8::GCType performance_last_gc_type_ = v8::GCType::kGCTypeAll;
3042

43+
doubleGetCurrentTimeInMicroseconds() {
44+
#ifdef _WIN32
45+
// The difference between the Unix Epoch and the Windows Epoch in 100-ns ticks.
46+
#defineTICKS_TO_UNIX_EPOCH116444736000000000LL
47+
FILETIME ft;
48+
GetSystemTimeAsFileTime(&ft);
49+
uint64_t filetime_int = static_cast<uint64_t>(ft.dwHighDateTime) << 32 |
50+
ft.dwLowDateTime;
51+
// FILETIME is measured in terms of 100 ns. Convert that to 1 us (1000 ns).
52+
return (filetime_int - TICKS_TO_UNIX_EPOCH) / 10.;
53+
#else
54+
structtimeval tp;
55+
gettimeofday(&tp, nullptr);
56+
returnMICROS_PER_SEC * tp.tv_sec + tp.tv_usec;
57+
#endif
58+
}
59+
3160
// Initialize the performance entry object properties
3261
inlinevoidInitObject(const PerformanceEntry& entry, Local<Object> obj) {
3362
Environment* env = entry.env();
@@ -372,6 +401,12 @@ void Init(Local<Object> target,
372401
v8::Number::New(isolate, timeOrigin / 1e6),
373402
attr).ToChecked();
374403

404+
target->DefineOwnProperty(
405+
context,
406+
FIXED_ONE_BYTE_STRING(isolate, "timeOriginTimestamp"),
407+
v8::Number::New(isolate, timeOriginTimestamp / MICROS_PER_MILLIS),
408+
attr).ToChecked();
409+
375410
target->DefineOwnProperty(context,
376411
env->constants_string(),
377412
constants,

‎src/node_perf.h‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ using v8::Local;
2222
using v8::Object;
2323
using v8::Value;
2424

25+
externconstuint64_t timeOrigin;
26+
27+
doubleGetCurrentTimeInMicroseconds();
28+
2529
staticinline PerformanceMilestone ToPerformanceMilestoneEnum(constchar* str) {
2630
#defineV(name, label) \
2731
if (strcmp(str, label) == 0) returnNODE_PERFORMANCE_MILESTONE_##name;
@@ -77,11 +81,11 @@ class PerformanceEntry {
7781
returnToPerformanceEntryTypeEnum(type().c_str());
7882
}
7983

80-
doublestartTime() const { returnstartTime_ / 1e6; }
84+
doublestartTime() const { returnstartTimeNano() / 1e6; }
8185

8286
doubleduration() const { returndurationNano() / 1e6; }
8387

84-
uint64_tstartTimeNano() const { return startTime_; }
88+
uint64_tstartTimeNano() const { return startTime_ - timeOrigin; }
8589

8690
uint64_tdurationNano() const { return endTime_ - startTime_; }
8791

‎src/node_perf_common.h‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include"node.h"
55
#include"v8.h"
66

7+
#include<algorithm>
78
#include<map>
89
#include<string>
910

@@ -76,7 +77,10 @@ class performance_state {
7677
isolate,
7778
offsetof(performance_state_internal, observers),
7879
NODE_PERFORMANCE_ENTRY_TYPE_INVALID,
79-
root) {}
80+
root) {
81+
for (size_t i = 0; i < milestones.Length(); i++)
82+
milestones[i] = -1.;
83+
}
8084

8185
AliasedBuffer<uint8_t, v8::Uint8Array> root;
8286
AliasedBuffer<double, v8::Float64Array> milestones;

0 commit comments

Comments
 (0)