forked from w3c/hr-time
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
955 lines (949 loc) · 40.4 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>
High Resolution Time
</title>
<script src="https://www.w3.org/Tools/respec/respec-w3c" async class=
"remove"></script>
<script class="remove">
var respecConfig = {
shortName: "hr-time-3",
specStatus: "ED",
editors: [
{
company: "Google LLC",
companyURL: "https://google.com/",
name: "Yoav Weiss",
url: "https://blog.yoav.ws/",
w3cid: "58673",
},
],
formerEditors: [
{
company: "Google LLC",
name: "Ilya Grigorik",
retiredDate: "2021-03-01",
url: "mailto:[email protected]",
w3cid: "56102",
},
{
company: "Google LLC",
name: "James Simonsen",
retiredDate: "2015-01-01",
url: "mailto:[email protected]",
w3cid: "45726",
},
{
company: "Microsoft Corp.",
name: "Jatinder Mann",
retiredDate: "2014-02-01",
url: "mailto:[email protected]",
w3cid: "44357",
},
],
github: "w3c/hr-time",
caniuse: "high-resolution-time",
testSuiteURI: "https://wpt.live/hr-time/",
implementationReportURI: "https://wpt.fyi/hr-time/",
group: "webperf",
xref: "web-platform",
mdn: "hr-time",
highlightVars: true,
localBiblio: {
"Temporal": {
href: "https://tc39.es/proposal-temporal/",
title: "Temporal",
status: "Stage 3 Proposal",
publisher: "ECMA TC39",
},
},
};
</script>
</head>
<body>
<section id="abstract">
<p>
This specification defines an API that provides the time origin, and
current time in sub-millisecond resolution, such that it is not subject
to system clock skew or adjustments.
</p>
</section>
<section id="sotd"></section>
<section id="introduction" class="informative">
<h2>
Introduction
</h2>
<p>
The ECMAScript Language specification [[ECMA-262]] defines the
<code><dfn data-no-export="" data-cite=
"ECMA-262#sec-date-objects">Date</dfn></code> object as a time value
representing time in milliseconds since 01 January, 1970 UTC. For most
purposes, this definition of time is sufficient as these values
represent time to millisecond precision for any moment that is within
approximately 285,616 years from 01 January, 1970 UTC.
</p>
<p>
In practice, these definitions of time are subject to both clock skew
and adjustment of the system clock. The value of time may not always be
monotonically increasing and subsequent values may either decrease or
remain the same.
</p>
<p>
For example, the following script may record a positive number,
negative number, or zero for computed <code>duration</code>:
</p>
<pre class="example js">
var mark_start = Date.now();
doTask(); // Some task
var duration = Date.now() - mark_start;
</pre>
<p>
For certain tasks this definition of time may not be sufficient as it:
</p>
<ul>
<li>Does not have a stable monotonic clock, and as a result, it is
subject to system clock skew.
</li>
<li>Does not provide sub-millisecond time resolution.
</li>
</ul>
<p>
This specification does not propose changing the behavior of
<code><dfn data-no-export="" data-cite=
"ecma-262#sec-date.now">Date.now()</dfn></code> [[ECMA-262]] as it is
genuinely useful in determining the current value of the calendar time
and has a long history of usage. The {{DOMHighResTimeStamp}} type,
{{Performance}}.{{Performance/now()}} method, and
{{Performance}}.{{Performance/timeOrigin}} attributes of the
{{Performance}} interface resolve the above issues by providing
monotonically increasing time values with sub-millisecond resolution.
</p>
<p class="note">
Providing sub-millisecond resolution is not a mandatory part of this
specification. Implementations may choose to limit the timer resolution
they expose for privacy and security reasons, and not expose
sub-millisecond timers. Use-cases that rely on sub-millisecond
resolution may not be satisfied when that happens.
</p>
<section id="use-cases" class="informative">
<h3>
Use-cases
</h3>
<p>
This specification defines a few different capabilities: it provides
timestamps based on a stable, monotonic clock, comparable across
contexts, with potential sub-millisecond resolution.
</p>
<p>
The need for a stable monotonic clock when talking about performance
measurements stems from the fact that unrelated clock skew can
distort measurements and render them useless. For example, when
attempting to accurately measure the elapsed time of navigating to a
Document, fetching of resources or execution of script, a
monotonically increasing clock with sub-millisecond resolution is
desired.
</p>
<p>
Comparing timestamps between contexts is essential e.g. when
synchronizing work between a {{Worker}} and the main thread or when
instrumenting such work in order to create a unified view of the
event timeline.
</p>
<p>
Finally, the need for sub-millisecond timers revolves around the
following use-cases:
</p>
<ul>
<li>Ability to schedule work in sub-millisecond intervals. That is
particularly important on the main thread, where work can interfere
with frame rendering which needs to happen in short and regular
intervals, to avoid user-visible jank.
</li>
<li>When calculating the frame rate of a script-based animation,
developers will need sub-millisecond resolution in order to determine
if an animation is drawing at 60 FPS. Without sub-millisecond
resolution, a developer can only determine if an animation is drawing
at 58.8 FPS (1000ms / 16) or 62.5 FPS (1000ms / 17).
</li>
<li>When collecting in-the-wild measurements of JS code (e.g. using
User-Timing), developers may be interested in gathering
sub-milliseconds timing of their functions, to catch regressions
early.
</li>
<li>When attempting to cue audio to a specific point in an animation
or ensure that the audio and animation are perfectly synchronized,
developers will need to accurately measure the amount of time
elapsed.
</li>
</ul>
</section>
<section id="examples" class="informative">
<h3>
Examples
</h3>
<p>
A developer may wish to construct a timeline of their entire
application, including events from {{Worker}} or {{SharedWorker}},
which have different [=environment settings object/time origins=]. To
display such events on the same timeline, the application can
translate the {{DOMHighResTimeStamp}}s with the help of the
{{Performance}}.{{Performance/timeOrigin}} attribute.
</p>
<pre class="example js">
// ---- worker.js -----------------------------
// Shared worker script
onconnect = function(e) {
var port = e.ports[0];
port.onmessage = function(e) {
// Time execution in worker
var task_start = performance.now();
result = runSomeWorkerTask();
var task_end = performance.now();
}
// Send results and epoch-relative timestamps to another context
port.postMessage({
'task': 'Some worker task',
'start_time': task_start + performance.timeOrigin,
'end_time': task_end + performance.timeOrigin,
'result': result
});
}
// ---- application.js ------------------------
// Timing tasks in the document
var task_start = performance.now();
runSomeApplicationTask();
var task_end = performance.now();
// developer provided method to upload runtime performance data
reportEventToAnalytics({
'task': 'Some document task',
'start_time': task_start,
'duration': task_end - task_start
});
// Translating worker timestamps into document's time origin
var worker = new SharedWorker('worker.js');
worker.port.onmessage = function (event) {
var msg = event.data;
// translate epoch-relative timestamps into document's time origin
msg.start_time = msg.start_time - performance.timeOrigin;
msg.end_time = msg.end_time - performance.timeOrigin;
reportEventToAnalytics(msg);
}
</pre>
</section>
</section>
<section id="sec-concepts">
<h3>
Time Concepts
</h3>
<section id="sec-clocks">
<h4>
Clocks
</h4>
<p>
A <dfn>clock</dfn> tracks the passage of time and can report the
<dfn>unsafe current time</dfn> that an algorithm step is executing.
There are many kinds of clocks. All clocks on the web platform
attempt to count 1 millisecond of clock time per 1 millisecond of
real-world time, but they differ in how they handle cases where they
can't be exactly correct.
</p>
<ul>
<li>The <dfn data-export="">wall clock</dfn>'s <dfn data-dfn-for=
"wall clock" data-export="" id=
"wall-clock-unsafe-current-time">unsafe current time</dfn> is always
as close as possible to a user's notion of time. Since a computer
sometimes runs slow or fast or loses track of time, its [=wall
clock=] sometimes needs to be adjusted, which means the [=wall
clock/unsafe current time=] can decrease, making it unreliable for
performance measurement or recording the orders of events. The web
platform shares a [=wall clock=] with [[ECMA-262]]
<dfn data-no-export="" data-cite=
"ECMA-262#sec-time-values-and-time-range">time</dfn>.
</li>
<li>
<p>
The <dfn data-export="">monotonic clock</dfn>'s <dfn data-export=
"" data-dfn-for="monotonic clock" id=
"monotonic-clock-unsafe-current-time">unsafe current time</dfn>
never decreases, so it can't be changed by system clock
adjustments. The [=monotonic clock=] only exists within a single
execution of the [=user agent=], so it can't be used to compare
events that might happen in different executions.
</p>
<p class="note">
Since the [=monotonic clock=] can't be adjusted to match the
user's notion of time, it should be used for measurement, rather
than user-visible times. For any time communication with the
user, use the wall clock.
</p>
<p class="note">
The user agent can pick a new [=estimated monotonic time of the
Unix epoch=] when the browser restarts, when it starts an
isolated browsing session—e.g. incognito or a similar browsing
mode—or when it creates an [=environment settings object=] that
can't communicate with any existing settings objects. As a
result, developers should not use shared timestamps as absolute
time that holds its monotonic properties across all past,
present, and future contexts; in practice, the monotonic
properties only apply for contexts that can reach each other by
exchanging messages via one of the provided messaging mechanisms
- e.g. {{Window/postMessage(message, options)}},
{{BroadcastChannel}}, etc.
</p>
<p class="note">
In certain scenarios (e.g. when a tab is backgrounded), the user
agent may choose to throttle timers and periodic callbacks run in
that context or even freeze them entirely. Any such throttling
should not affect the resolution or accuracy of the time returned
by the monotonic clock.
</p>
</li>
</ul>
</section>
<section>
<h4>
Moments and Durations
</h4>
<p>
Each [=clock=]'s [=unsafe current time=] returns an <dfn>unsafe
moment</dfn>. [=Coarsen time=] converts these [=unsafe moments=] to
<dfn data-export="" data-lt="moment">coarsened moments</dfn> or just
[=moments=]. [=Unsafe moments=] and [=moments=] from different clocks
are not comparable.
</p>
<p class="note">
[=Moments=] and [=unsafe moments=] represent points in time, which
means they can't be directly stored as numbers. Implementations will
usually represent a [=moment=] as a [=duration=] from some other
fixed point in time, but specifications ought to deal in the
[=moments=] themselves.
</p>
<p>
A <dfn data-export="">duration</dfn> is the distance from one
[=moment=] to another from the same [=clock=]. Neither endpoint can
be an [=unsafe moment=] so that both [=durations=] and differences of
[=durations=] mitigate the concerns in [[[#clock-resolution]]].
[=Durations=] are measured in milliseconds, seconds, etc. Since all
[=clocks=] attempt to count at the same rate, [=durations=] don't
have an associated [=clock=], and a [=duration=] calculated from two
[=moments=] on one clock can be added to a [=moment=] from a second
[=clock=], to produce another [=moment=] on that second [=clock=].
</p>
<p>
The <dfn data-export="">duration from</dfn> |a:moment| to |b:moment|
is the result of the following algorithm:
</p>
<ol class="algorithm">
<li>Assert: |a| was created by the same [=clock=] as |b|.
</li>
<li>Assert: Both |a| and |b| are [=coarsened moments=].
</li>
<li>Return the amount of time from |a| to |b| as a [=duration=]. If
|b| came before |a|, this will be a negative [=duration=].
</li>
</ol>
<p>
[=Durations=] can be used implicitly as {{DOMHighResTimeStamp}}s. To
<dfn>implicitly convert a duration to a timestamp</dfn>, given a
[=duration=] |d:duration|, return the number of milliseconds in |d|.
</p>
</section>
</section>
<section id="sec-tools">
<h3>
Tools for Specification Authors
</h3>
<p>
For measuring time within a single page (within the context of a single
[=environment settings object=]), use the |settingsObject:environment
settings object|'s <dfn data-export="" data-dfn-for=
"environment settings object">current relative timestamp</dfn>, defined
as the [=duration from=] |settingsObject|'s [=environment settings
object/time origin=] to the |settingsObject|'s [=environment settings
object/current monotonic time=]. This value can be exposed directly to
JavaScript using the [=duration=]'s [=implicitly convert a duration to
a timestamp|implicit conversion=] to {{DOMHighResTimeStamp}}.
</p>
<p>
For measuring time within a single UA execution when an [=environment
settings object=]'s [=environment settings object/time origin=] isn't
an appropriate base for comparison, create [=moments=] using an
[=environment settings object=]'s [=environment settings object/current
monotonic time=]. An [=environment settings object=]
|settingsObject:environment settings object|'s <dfn data-export=""
data-dfn-for="environment settings object">current monotonic time</dfn>
is the result of the following steps:
</p>
<ol>
<li>Let |unsafeMonotonicTime:unsafe moment on the monotonic clock| be
the [=monotonic clock=]'s [=monotonic clock/unsafe current time=].
</li>
<li>Return the result of calling [=coarsen time=] with
|unsafeMonotonicTime| and |settingsObject|'s [=environment settings
object/cross-origin isolated capability=].
</li>
</ol>
<p>
[=Moments=] from the [=monotonic clock=] can't be directly represented
in JavaScript or HTTP. Instead, expose a [=duration=] between two such
[=moments=].
</p>
<p>
For measuring time across multiple UA executions, create [=moments=]
using the [=current wall time=] or (if you need higher precision in
[=environment settings object/cross-origin isolated
capability|cross-origin-isolated contexts=]) an [=environment settings
object=]'s [=environment settings object/current wall time=]. The
<dfn data-export="" id="dfn-current-wall-time">current wall time</dfn>
is the result of calling [=coarsen time=] with the [=wall clock=]'s
[=wall clock/unsafe current time=].
</p>
<p>
An [=environment settings object=] |settingsObject:environment settings
object|'s <dfn data-export="" data-dfn-for=
"environment settings object" id="dfn-eso-current-wall-time">current
wall time</dfn> is the result of the following steps:
</p>
<ol>
<li>Let |unsafeWallTime:unsafe moment on the wall clock| be the [=wall
clock=]'s [=wall clock/unsafe current time=].
</li>
<li>Return the result of calling [=coarsen time=] with |unsafeWallTime|
and |settingsObject|'s [=environment settings object/cross-origin
isolated capability=].
</li>
</ol>
<p class="advisement">
When using [=moments=] from the [=wall clock=], be sure that your
design accounts for situations when the user adjusts their clock either
forward or backward.
</p>
<p>
[=Moments=] from the [=wall clock=] can be represented in JavaScript by
passing the number of milliseconds from the [=Unix epoch=] to that
[=moment=] into the {{Date}} constructor, or by passing the number of
nanoseconds from the [=Unix epoch=] to that [=moment=] into the
<a data-link-type="idl" data-cite=
"Temporal#sec-temporal-instant-constructor">Temporal.Instant</a>
constructor.
</p>
<p class="advisement tracking-vector">
Avoid sending similar representations between computers, as doing so
will expose the user's clock skew, which is a [=tracking vector=].
Instead, use an approach similar to [=monotonic clock=] [=moments=] of
sending a duration between two [=moments=].
</p>
<section id="sec-tools-examples">
<h3>
Examples
</h3>
<div class="example" id="example-current-relative-timestamp">
<p>
The time a DOM event happens can be reported using:
</p>
<ol start="7">
<li>Initialize |event|'s {{Event/timeStamp}} attribute to
[=this=]'s [=relevant settings object=]'s [=environment settings
object/current relative timestamp=].
</li>
</ol>
</div>
<div class="example" id="example-current-monotonic-time">
<p>
The age of an error report can be computed using:
</p>
<ol start="7">
<li>Initialize |report|'s <a data-cite=
"reporting#report-timestamp">generation time</a> to |settings|'
[=environment settings object/current monotonic time=].
</li>
</ol>
<p>
Later:
</p>
<ol start="2">
<li>Let |data| be a map with the following key/value pairs:
<dl>
<dt>
age
</dt>
<dd>
The number of milliseconds between |report|'s <a data-cite=
"reporting#report-timestamp">generation time</a> and
|context|'s [=relevant settings object=]'s [=environment
settings object/current monotonic time=], rounded to the
nearest integer.
</dd>
<dd>
...
</dd>
</dl>
</li>
</ol>
</div>
<div class="example" id="example-current-wall-time">
<p>
Multi-day attribution report expirations can be handled as:
</p>
<ol start="2">
<li>Let |source| be a new attribution source struct whose items
are:
<dl>
<dt>
...
</dt>
<dt>
source time
</dt>
<dd>
|context|'s [=environment settings object/current wall time=]
</dd>
<dt>
expiry
</dt>
<dd>
<a data-cite="html#parse-a-duration-string">parse a duration
string</a> from <code>|value|["expiry"]</code>
</dd>
</dl>
</li>
</ol>
<p>
Days later:
</p>
<ol start="2">
<li>If |context|'s [=environment settings object/current wall
time=] is less than |source|'s source time + |source|'s expiry,
send a report.
</li>
</ol>
</div>
</section>
</section>
<section id="sec-time-origin">
<h3>
Time Origin
</h3>
<p>
The <dfn data-export="">Unix epoch</dfn> is the [=moment=] on the
[=wall clock=] corresponding to 1 January 1970 00:00:00 UTC.
</p>
<p>
Each group of [=environment settings objects=] that could possibly
communicate in any way has an <dfn>estimated monotonic time of the Unix
epoch</dfn>, a [=moment=] on the [=monotonic clock=], whose value is
initialized by the following steps:
</p>
<ol data-algorithm=
"initialize the estimated monotonic time of the Unix epoch">
<li>Let |wall time:unsafe moment on the wall clock| be the [=wall
clock=]'s [=wall clock/unsafe current time=].
</li>
<li>Let |monotonic time:unsafe moment on the monotonic clock| be the
[=monotonic clock=]'s [=monotonic clock/unsafe current time=].
</li>
<li>Let |epoch time:unsafe moment on the monotonic clock| be
<code>|monotonic time| - (|wall time| - [=Unix epoch=])</code>
</li>
<li>Initialize the [=estimated monotonic time of the Unix epoch=] to
the result of calling [=coarsen time=] with |epoch time|.
</li>
</ol>
<div class="issue">
The above set of settings-objects-that-could-possibly-communicate needs
to be specified better. It's similar to <a data-cite=
"html/browsers.html#familiar-with">familiar with</a> but includes
{{Worker}}s.
</div>
<p>
Performance measurements report a [=duration=] from a [=moment=] early
in the initialization of a relevant [=environment settings object=].
That [=moment=] is stored in that settings object's [=environment
settings object/time origin=].
</p>
<p>
To <dfn>get time origin timestamp</dfn>, given a [=/global object=]
|global:global object|, run the following steps, which return a
[=duration=]:
</p>
<ol>
<li>
<p>
Let |timeOrigin:moment on the monotonic clock| be |global|'s
[=relevant settings object=]'s [=environment settings object/time
origin=].
</p>
<p class="note">
In {{Window}} contexts, this value represents the time when
[=navigate|navigation has started=]. In {{Worker}} and
{{ServiceWorker}} contents, this value represent the time when the
[=run a worker|worker is run=]. [[service-workers]]
</p>
</li>
<li>Return the [=duration from=] the [=estimated monotonic time of the
Unix epoch=] to |timeOrigin|.
</li>
</ol>
<p class="note">
The value returned by [=get time origin timestamp=] is approximately
the time after the [=Unix epoch=] that |global|'s [=environment
settings object/time origin=] happened. It may differ from the value
returned by <a>Date.now()</a> executed at the time origin, because the
former is recorded with respect to a <a>monotonic clock</a> that is not
subject to system and user clock adjustments, clock skew, and so on.
</p>
<div data-algorithm="coarsen time">
The <dfn data-export="">coarsen time</dfn> algorithm, given an [=unsafe
moment=] |timestamp:unsafe moment| on some [=clock=] and an optional
boolean |crossOriginIsolatedCapability:boolean| (default false), runs
the following steps:
<ol>
<li>Let |time resolution:duration| be 100 microseconds, or a higher
<a>implementation-defined</a> value.
</li>
<li>If |crossOriginIsolatedCapability| is true, set |time resolution|
to be 5 microseconds, or a higher <a>implementation-defined</a>
value.
</li>
<li>In an <a>implementation-defined</a> manner, coarsen and
potentially jitter |timestamp| such that its resolution will not
exceed |time resolution|.
</li>
<li>Return |timestamp| as a [=moment=].
</li>
</ol>
</div>
<div data-algorithm="relative high resolution time">
The <dfn data-export="">relative high resolution time</dfn> given an
[=unsafe moment=] from the [=monotonic clock=] |time:unsafe moment on
the monotonic clock| and a [=Realm/global object=] |global:global
object|, is the [=duration=] returned from the following steps:
<ol>
<li>Let |coarse time:moment on the monotonic clock| be the result of
calling [=coarsen time=] with |time| and |global|'s [=relevant
settings object=]'s [=environment settings object/cross-origin
isolated capability=].
</li>
<li>Return the [=relative high resolution coarse time=] for |coarse
time| and |global|.
</li>
</ol>The <dfn data-export="">relative high resolution coarse time</dfn>
given a [=moment=] from the [=monotonic clock=] |coarseTime:moment on
the monotonic clock| and a [=Realm/global object=] |global:global
object|, is the [=duration from=] |global|'s [=relevant settings
object=]'s [=environment settings object/time origin=] to |coarseTime|.
</div>
<p>
The <dfn data-export="">current high resolution time</dfn> given a
[=/global object=] |current global:global object| must return the
result of [=relative high resolution time=] given [=unsafe shared
current time=] and |current global|.
</p>
<p>
The <dfn data-export="">coarsened shared current time</dfn> given an
optional boolean |crossOriginIsolatedCapability:boolean| (default
false), must return the result of calling [=coarsen time=] with the
[=unsafe shared current time=] and |crossOriginIsolatedCapability|.
</p>
<p>
The <dfn data-export="">unsafe shared current time</dfn> must return
the [=monotonic clock/unsafe current time=] of the <a>monotonic
clock</a>.
</p>
</section>
<section id="sec-domhighrestimestamp">
<h3>
The <dfn data-export="">DOMHighResTimeStamp</dfn> typedef
</h3>
<p>
The {{DOMHighResTimeStamp}} type is used to store a [=duration=] in
milliseconds. Depending on its context, it may represent the [=moment=]
that is this [=duration=] after a base [=moment=] like a [=environment
settings object/time origin=] or the [=Unix epoch=].
</p>
<pre class="idl">
typedef double DOMHighResTimeStamp;
</pre>
<p>
A {{DOMHighResTimeStamp}} SHOULD represent a time in milliseconds
accurate enough to allow measurement while preventing timing attacks -
see <a href="#clock-resolution"></a> for additional considerations.
</p>
<p class="note">
A {{DOMHighResTimeStamp}} is a {{double}}, so it can only represent an
epoch-relative time—the number of milliseconds from the [=Unix epoch=]
to a [=moment=]—to a finite resolution. For [=moments=] in 2023, that
resolution is approximately 0.2 microseconds.
</p>
</section>
<section>
<h3>
The <dfn>EpochTimeStamp</dfn> typedef
</h3>
<pre class="idl">
typedef unsigned long long EpochTimeStamp;
</pre>
<aside class="note" title="Legacy platform feature">
<p>
The use of `EpochTimeStamp`, known previously as `DOMTimeStamp`, is
discouraged. Wherever possible use {{DOMHighResTimeStamp}} instead.
</p>
</aside>
<p>
A {{EpochTimeStamp}} represents an integral number of milliseconds from
the [=Unix epoch=] to a given [=moment=] on the [=wall clock=],
excluding leap seconds. Specifications that use this type define how
the number of milliseconds are interpreted.
</p>
</section>
<section id="sec-performance" data-dfn-for="Performance">
<h3>
The <dfn>Performance</dfn> interface
</h3>
<pre class="idl">
[Exposed=(Window,Worker)]
interface Performance : EventTarget {
DOMHighResTimeStamp now();
readonly attribute DOMHighResTimeStamp timeOrigin;
[Default] object toJSON();
};
</pre>
<section>
<h3>
`now()` method
</h3>
<p data-tests="basic.any.html, basic.any.worker.html">
The <dfn>now()</dfn> method MUST return the number of milliseconds in
the <a>current high resolution time</a> given [=this=]'s [=relevant
global object=] (a [=duration=]).
</p>
<p data-tests=
"monotonic-clock.any.html, monotonic-clock.any.worker.html">
The time values returned when calling the {{Performance/now()}}
method on {{Performance}} objects with the same [=environment
settings object/time origin=] MUST use the same [=monotonic clock=].
The difference between any two chronologically recorded time values
returned from the {{Performance/now()}} method MUST never be negative
if the two time values have the same [=environment settings
object/time origin=].
</p>
</section>
<section>
<h3>
`timeOrigin` attribute
</h3>
<p data-tests="timeOrigin.html, window-worker-timeOrigin.window.html">
The <dfn>timeOrigin</dfn> attribute MUST return the number of
milliseconds in the [=duration=] returned by [=get time origin
timestamp=] for the <a>relevant global object</a> of [=this=].
</p>
<p data-tests="test_cross_frame_start.html">
The time values returned when getting
{{Performance}}.{{Performance/timeOrigin}} MUST use the same
[=monotonic clock=] that is shared by [=environment settings
object/time origins=], and whose reference point is the [[ECMA-262]]
<a data-cite="ECMA-262#sec-time-values-and-time-range">time</a>
definition - see [[[#sec-security]]].
</p>
</section>
<section>
<h3>
`toJSON()` method
</h3>
<p data-tests="performance-tojson.html">
When <dfn>toJSON()</dfn> is called, run [[WEBIDL]]'s <a>default
toJSON steps</a>.
</p>
</section>
</section>
<section>
<h2>
Extensions to `WindowOrWorkerGlobalScope` mixin
</h2>
<section data-dfn-for="WindowOrWorkerGlobalScope">
<h3>
The <code>performance</code> attribute
</h3>
<p>
The <dfn>performance</dfn> attribute on the interface mixin
{{WindowOrWorkerGlobalScope}} allows access to performance related
attributes and methods from the [=Realm/global object=].
</p>
<pre class="idl">
partial interface mixin WindowOrWorkerGlobalScope {
[Replaceable] readonly attribute Performance performance;
};
</pre>
</section>
</section>
<section id="sec-security">
<h3>
Security Considerations
</h3>
<section>
<h3>
Clock resolution
</h3>
<p>
Access to accurate timing information, both for measurement and
scheduling purposes, is a common requirement for many applications.
For example, coordinating animations, sound, and other activity on
the page requires access to high-resolution time to provide a good
user experience. Similarly, measurement enables developers to track
the performance of critical code components, detect regressions, and
so on.
</p>
<p>
However, access to the same accurate timing information can sometimes
be also used for malicious purposes by an attacker to guess and infer
data that they can't see or access otherwise. For example, cache
attacks, statistical fingerprinting and micro-architectural attacks
are a privacy and security concern where a malicious web site may use
high resolution timing data of various browser or
application-initiated operations to differentiate between subset of
users, identify a particular user or reveal unrelated but
same-process user data - see [[?CACHE-ATTACKS]] and [[SPECTRE]] for
more background.
</p>
<p data-tests="timing-attack.html">
This specification defines an API that provides sub-millisecond time
resolution, which is more accurate than the previously available
millisecond resolution exposed by {{EpochTimeStamp}}. However, even
without this new API an attacker may be able to obtain
high-resolution estimates through repeat execution and statistical
analysis.
</p>
<p>
To ensure that the new API does not significantly improve the
accuracy or speed of such attacks, the minimum resolution of the
{{DOMHighResTimeStamp}} type should be inaccurate enough to prevent
attacks.
</p>
<p>
Where necessary, the user agent should set higher resolution values
to |time resolution| in [=coarsen time=]'s processing model, to
address privacy and security concerns due to architecture or software
constraints, or other considerations.
</p>
<p>
In order to mitigate such attacks user agents may deploy any
technique they deem necessary. Deployment of those techniques may
vary based on the browser's architecture, the user's device, the
content and its ability to maliciously read cross-origin data, or
other practical considerations.
</p>
<p>
These techniques may include:
</p>
<ul>
<li>Resolution reduction.
</li>
<li>Added jitter.
</li>
<li>Abuse detection and/or API call throttling.
</li>
</ul>
<p>
Mitigating such timing side-channel attacks entirely is practically
impossible: either all operations would have to execute in a time
that does not vary based on the value of any confidential
information, or the application would need to be isolated from any
time-related primitives (clock, timers, counters, etc). Neither is
practical due to the associated complexity for the browser and
application developers and the associated negative effects on
performance and responsiveness of applications.
</p>
<div class="note">
Clock resolution is an unsolved and evolving area of research, with
no existing industry consensus or definitive set of recommendations
that applies to all browsers. To track the discussion, refer to
<a href="https://github.com/w3c/hr-time/issues/79">Issue 79</a>.
</div>
</section>
<section>
<h3>
Clock drift
</h3>
<p>
This specification also defines an API that provides sub-millisecond
time resolution of the zero time of the time origin, which requires
and exposes a <a>monotonic clock</a> to the application, and that
must be shared across all the browser contexts. The <a>monotonic
clock</a> does not need to be tied to physical time, but is
recommended to be set with respect to the [[ECMA-262]] definition of
<a>time</a> to avoid exposing new fingerprint entropy about the user
— e.g. this time can already be easily obtained by the application,
whereas exposing a new logical clock provides new information.
</p>
<p>
However, even with the above mechanism in place, the <a>monotonic
clock</a> may provide additional <a href=
"https://en.wikipedia.org/wiki/Clock_drift">clock drift</a>
resolution. Today, the application can timestamp the time-of-day and
monotonic time values (via <a>Date.now()</a> and
{{Performance/now()}}) at multiple points within the same context and
observe drift between them—e.g. due to automatic or user clock
adjustments. With the {{Performance/timeOrigin}} attribute, the
attacker can also compare the [=environment settings object/time
origin=], as reported by the <a>monotonic clock</a>, against the
current time-of-day estimate of the [=environment settings
object/time origin=] (i.e. the difference between
`performance.timeOrigin` and `Date.now() - performance.now()`) and
potentially observe clock drift between these clocks over a longer
time period.
</p>
<p>
In practice, the same time drift can be observed by an application
across multiple navigations: the application can record the logical
time in each context and use a client or server time synchronization
mechanism to infer changes in the user's clock. Similarly,
lower-layer mechanisms such as TCP timestamps may reveal the same
high-resolution information to the server without the need for
multiple visits. As such, the information provided by this API should
not expose any significant or previously unavailable entropy about
the user.
</p>
</section>
</section>
<section id="sec-privacy">
<h3>
Privacy Considerations
</h3>
<p>
The current definition of [=environment settings object/time origin=]
for a {{Document}} exposes the total time of cross-origin redirects
prior to the request arriving at the document's origin. This exposes
cross-origin information, however it's not yet decided how to mitigate
this without causing major breakages to performance metrics.
</p>
<p>
To track the discussion, refer to <a href=
"https://github.com/w3c/navigation-timing/issues/160">Navigation Timing
Issue 160</a>.
</p>
</section>
<section id="conformance">
<p>
Some conformance requirements are phrased as requirements on
attributes, methods or objects. Such requirements are to be interpreted
as requirements on user agents.
</p>
</section>
<section id="index"></section>
<section id="idl-index"></section>
<section class="appendix">
<h2>
Acknowledgments
</h2>
<p>
Thanks to Arvind Jain, Angelos D. Keromytis, Boris Zbarsky, Jason
Weber, Karen Anderson, Nat Duca, Philippe Le Hegaret, Ryosuke Niwa,
Simha Sethumadhavan, Todd Reifsteck, Tony Gentilcore, Vasileios P.
Kemerlis, Yoav Weiss, and Yossef Oren for their contributions to this
work.
</p>
</section>
</body>
</html>