Skip to content

Commit 9256dbb

Browse files
TimothyGujasnell
authored andcommitted
perf_hooks: fix timing
Fixes: #17892 Fixes: #17893 Fixes: #18992 PR-URL: #18993 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Anatoli Papirovski <[email protected]>
1 parent ad72142 commit 9256dbb

File tree

6 files changed

+182
-52
lines changed

6 files changed

+182
-52
lines changed

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');
@@ -146,6 +147,13 @@ function now() {
146147
return hr[0] * 1000 + hr[1] / 1e6;
147148
}
148149

150+
function getMilestoneTimestamp(milestoneIdx) {
151+
const ns = milestones[milestoneIdx];
152+
if (ns === -1)
153+
return ns;
154+
return ns / 1e6 - timeOrigin;
155+
}
156+
149157
class PerformanceNodeTiming {
150158
constructor() {}
151159

@@ -158,67 +166,72 @@ class PerformanceNodeTiming {
158166
}
159167

160168
get startTime() {
161-
return timeOrigin;
169+
return 0;
162170
}
163171

164172
get duration() {
165173
return now() - timeOrigin;
166174
}
167175

168176
get nodeStart() {
169-
return milestones[NODE_PERFORMANCE_MILESTONE_NODE_START];
177+
return getMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_NODE_START);
170178
}
171179

172180
get v8Start() {
173-
return milestones[NODE_PERFORMANCE_MILESTONE_V8_START];
181+
return getMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_V8_START);
174182
}
175183

176184
get environment() {
177-
return milestones[NODE_PERFORMANCE_MILESTONE_ENVIRONMENT];
185+
return getMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_ENVIRONMENT);
178186
}
179187

180188
get loopStart() {
181-
return milestones[NODE_PERFORMANCE_MILESTONE_LOOP_START];
189+
return getMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_LOOP_START);
182190
}
183191

184192
get loopExit() {
185-
return milestones[NODE_PERFORMANCE_MILESTONE_LOOP_EXIT];
193+
return getMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
186194
}
187195

188196
get bootstrapComplete() {
189-
return milestones[NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE];
197+
return getMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
190198
}
191199

192200
get thirdPartyMainStart() {
193-
return milestones[NODE_PERFORMANCE_MILESTONE_THIRD_PARTY_MAIN_START];
201+
return getMilestoneTimestamp(
202+
NODE_PERFORMANCE_MILESTONE_THIRD_PARTY_MAIN_START);
194203
}
195204

196205
get thirdPartyMainEnd() {
197-
return milestones[NODE_PERFORMANCE_MILESTONE_THIRD_PARTY_MAIN_END];
206+
return getMilestoneTimestamp(
207+
NODE_PERFORMANCE_MILESTONE_THIRD_PARTY_MAIN_END);
198208
}
199209

200210
get clusterSetupStart() {
201-
return milestones[NODE_PERFORMANCE_MILESTONE_CLUSTER_SETUP_START];
211+
return getMilestoneTimestamp(
212+
NODE_PERFORMANCE_MILESTONE_CLUSTER_SETUP_START);
202213
}
203214

204215
get clusterSetupEnd() {
205-
return milestones[NODE_PERFORMANCE_MILESTONE_CLUSTER_SETUP_END];
216+
return getMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_CLUSTER_SETUP_END);
206217
}
207218

208219
get moduleLoadStart() {
209-
return milestones[NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_START];
220+
return getMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_START);
210221
}
211222

212223
get moduleLoadEnd() {
213-
return milestones[NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_END];
224+
return getMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_MODULE_LOAD_END);
214225
}
215226

216227
get preloadModuleLoadStart() {
217-
return milestones[NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_START];
228+
return getMilestoneTimestamp(
229+
NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_START);
218230
}
219231

220232
get preloadModuleLoadEnd() {
221-
return milestones[NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_END];
233+
return getMilestoneTimestamp(
234+
NODE_PERFORMANCE_MILESTONE_PRELOAD_MODULE_LOAD_END);
222235
}
223236

224237
[kInspect]() {
@@ -467,11 +480,11 @@ class Performance extends PerformanceObserverEntryList {
467480
}
468481

469482
get timeOrigin() {
470-
return timeOrigin;
483+
return timeOriginTimestamp;
471484
}
472485

473486
now() {
474-
return now();
487+
return now() - timeOrigin;
475488
}
476489

477490
mark(name) {
@@ -550,8 +563,9 @@ class Performance extends PerformanceObserverEntryList {
550563

551564
[kInspect]() {
552565
return {
553-
timeOrigin,
554-
nodeTiming
566+
maxEntries: this.maxEntries,
567+
nodeTiming: this.nodeTiming,
568+
timeOrigin: this.timeOrigin
555569
};
556570
}
557571
}

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
namespace node {
711
namespace performance {
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+
#define MICROS_PER_SEC 1e6
30+
// Microseconds in a millisecond, as a float.
31+
#define MICROS_PER_MILLIS 1e3
32+
33+
// https://w3c.github.io/hr-time/#dfn-time-origin
2434
const uint64_t timeOrigin = PERFORMANCE_NOW();
35+
// https://w3c.github.io/hr-time/#dfn-time-origin-timestamp
36+
const double 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+
double GetCurrentTimeInMicroseconds() {
44+
#ifdef _WIN32
45+
// The difference between the Unix Epoch and the Windows Epoch in 100-ns ticks.
46+
#define TICKS_TO_UNIX_EPOCH 116444736000000000LL
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+
struct timeval tp;
55+
gettimeofday(&tp, nullptr);
56+
return MICROS_PER_SEC * tp.tv_sec + tp.tv_usec;
57+
#endif
58+
}
59+
3160
// Initialize the performance entry object properties
3261
inline void InitObject(const PerformanceEntry& entry, Local<Object> obj) {
3362
Environment* env = entry.env();
@@ -384,6 +413,12 @@ void Init(Local<Object> target,
384413
v8::Number::New(isolate, timeOrigin / 1e6),
385414
attr).ToChecked();
386415

416+
target->DefineOwnProperty(
417+
context,
418+
FIXED_ONE_BYTE_STRING(isolate, "timeOriginTimestamp"),
419+
v8::Number::New(isolate, timeOriginTimestamp / MICROS_PER_MILLIS),
420+
attr).ToChecked();
421+
387422
target->DefineOwnProperty(context,
388423
env->constants_string(),
389424
constants,

src/node_perf.h

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

26+
extern const uint64_t timeOrigin;
27+
28+
double GetCurrentTimeInMicroseconds();
29+
2630
static inline PerformanceMilestone ToPerformanceMilestoneEnum(const char* str) {
2731
#define V(name, label) \
2832
if (strcmp(str, label) == 0) return NODE_PERFORMANCE_MILESTONE_##name;
@@ -78,11 +82,11 @@ class PerformanceEntry {
7882
return ToPerformanceEntryTypeEnum(type().c_str());
7983
}
8084

81-
double startTime() const { return startTime_ / 1e6; }
85+
double startTime() const { return startTimeNano() / 1e6; }
8286

8387
double duration() const { return durationNano() / 1e6; }
8488

85-
uint64_t startTimeNano() const { return startTime_; }
89+
uint64_t startTimeNano() const { return startTime_ - timeOrigin; }
8690

8791
uint64_t durationNano() const { return endTime_ - startTime_; }
8892

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)