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
|
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
<year>1999</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
</legalnotice>
<title>Time and Time Correction in Erlang</title>
<prepared></prepared>
<responsible></responsible>
<docno></docno>
<approved></approved>
<checked></checked>
<date>2013-08-28</date>
<rev>PA1</rev>
<file>time_correction.xml</file>
</header>
<section>
<title>New Extended Time Functionality</title>
<note><p>As of OTP 18 (ERTS version 7.0) the time functionality of
Erlang has been extended. This both includes a
<seealso marker="#The_New_Time_API">new API</seealso>
for time, as well as
<seealso marker="#Time_Warp_Modes">time warp
modes</seealso> which alters the behavior of the system when
system time changes.</p>
<p>The <seealso marker="#No_Time_Warp_Mode">default
time warp mode</seealso> has the same behavior as before, and the
old API will still work, so you are not required to change
anything unless you want to. However, <em>you are strongly
encouraged to use the new API</em> instead of the old API based
on <seealso marker="erlang#now/0"><c>erlang:now/0</c></seealso>.
<c>erlang:now/0</c> has been deprecated since it is and forever
will be a scalability bottleneck. By using the new API you will
automatically get scalability and performance improvements. This
will also enable you to use the
<seealso marker="#Multi_Time_Warp_Mode">multi time warp mode</seealso>
which improves accuracy, and precision of time measurements.</p></note>
</section>
<section>
<title>Some Terminology</title>
<p>In order to make it easier to understand this document we first
define some terminology. This is a mixture of our own terminology
(Erlang/OS system time, Erlang/OS monotonic time, time warp)
and globally accepted terminology.</p>
<marker id="Monotonically_Increasing"/>
<section>
<title>Monotonically Increasing</title>
<p>In a monotonically increasing sequence of values, all values
that have a predecessor are either larger than, or equal to its
predecessor.</p>
</section>
<marker id="Strictly_Monotonically_Increasing"/>
<section>
<title>Strictly Monotonically Increasing</title>
<p>In a strictly monotonically increasing sequence of values,
all values that have a predecessor are larger than its
predecessor.</p>
</section>
<marker id="UT1"/>
<section>
<title>UT1</title>
<p>Universal Time. Based on the rotation of the earth. Conceptually
mean solar time at 0° longitude.</p>
</section>
<marker id="UTC"/>
<section>
<title>UTC</title>
<p>Coordinated Universal Time. UTC almost align with
<seealso marker="#UT1">UT1</seealso>, however, UTC uses the
SI definition of a second which is not exactly of the same length
as the second used by UT1. This means that UTC slowly drifts from
UT1. In order to keep UTC relatively in sync with UT1, leap seconds
are inserted, and potentially also deleted. That is, an UTC day may
be 86400, 86401, or 86399 seconds long.</p>
</section>
<marker id="POSIX_Time"/>
<section>
<title>POSIX Time</title>
<p>Time since
<url href="http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap03.html#tag_21_03_00_17">Epoch</url>.
Epoch is defined to be 00:00:00 <seealso marker="#UTC">UTC</seealso>,
January 1, 1970.
<url href="http://pubs.opengroup.org/onlinepubs/009604499/basedefs/xbd_chap04.html#tag_04_14">A day in POSIX time</url>
is defined to be exactly 86400 seconds long. Strangely enough
Epoch is defined to be a time in UTC, and UTC have another
definition of how long a day is. Quoting the Open Group
<url href="http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_15">"POSIX time is therefore not necessarily UTC, despite its appearance"</url>. The effect of this is that when an UTC leap second is
inserted, POSIX time either stops for a second, or repeats the
last second. If an UTC leap second would be deleted (has never
happened yet), POSIX time would make a one second leap forward.</p>
</section>
<marker id="Time_Resolution"/>
<section>
<title>Time Resolution</title>
<p>The shortest time interval that can be distinguished when
reading time values.</p>
</section>
<marker id="Time_Precision"/>
<section>
<title>Time Precision</title>
<p>The shortest time interval that can be be distinguished
repeatedly and reliably when reading time values. Precision
is limited by the
<seealso marker="#Time_Resolution">resolution</seealso>, but
resolution and precision might differ significantly.</p>
</section>
<marker id="Time_Accuracy"/>
<section>
<title>Time Accuracy</title>
<p>The correctness of time values.</p>
</section>
<marker id="Time_Warp"/>
<section>
<title>Time Warp</title>
<p>A time warp is a leap forwards or backwards in time. That
is, the difference of time values taken before and after the
time warp will not correspond to the actual elapsed time.</p>
</section>
<marker id="OS_System_Time"/>
<section>
<title>OS System Time</title>
<p>The operating systems view of
<seealso marker="#POSIX_Time">POSIX time</seealso>. It can be
retrieved by calling
<seealso marker="kernel:os#system_time/0"><c>os:system_time()</c></seealso>.
This may or may not be an accurate view of POSIX time. This time
may typically be adjusted both backwards and forwards without
limitation. That is, <seealso marker="#Time_Warp">time warps</seealso>
may be observed. You can get information about the Erlang runtime
system's source of OS system time by calling
<seealso marker="erlang#system_info_os_system_time_source"><c>erlang:system_info(os_system_time_source)</c></seealso>.</p>
</section>
<marker id="OS_Monotonic_Time"/>
<section>
<title>OS Monotonic Time</title>
<p>A monotonically increasing time provided by the operating
system. This time does not leap and have a relatively steady
frequency although not completely correct. However, it is not
uncommon that the OS monotonic time stops if the system is
suspended. This time typically increase since some
unspecified point in time that is not connected to
<seealso marker="#OS_System_Time">OS system time</seealso>. Note
that this type of time is not necessarily provided by all
operating systems. You can get information about the Erlang
runtime system's source of OS monotonic time by calling
<seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>.</p>
</section>
<marker id="Erlang_System_Time"/>
<section>
<title>Erlang System Time</title>
<p>The Erlang runtime systems view of
<seealso marker="#POSIX_Time">POSIX time</seealso>. It can be
retrieved by calling
<seealso marker="erlang#system_time/0"><c>erlang:system_time()</c></seealso>.
This time may or may not be an accurate view of POSIX time, and may
or may not align with <seealso marker="#OS_System_Time">OS system
time</seealso>. The runtime system works towards aligning the two
system times. Depending on <seealso marker="#Time_Warp_Modes">time
warp mode</seealso> used, this may be achieved by letting the Erlang
system time perform a <seealso marker="#Time_Warp">time
warp</seealso>.</p>
</section>
<marker id="Erlang_Monotonic_Time"/>
<section>
<title>Erlang Monotonic Time</title>
<p>A monotonically increasing time provided by the
Erlang runtime system. The Erlang monotonic time increase since
some unspecified point in time. It can be retrieved by calling
<seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time()</c></seealso>.
The
<seealso marker="#Time_Accuracy">accuracy</seealso>, and
<seealso marker="#Time_Precision">precision</seealso> of Erlang
monotonic time heavily depends on the accuracy and precision of
<seealso marker="#OS_Monotonic_Time">OS monotonic time</seealso>,
the accuracy and precision of
<seealso marker="#OS_System_Time">OS system time</seealso> as well
as on the
<seealso marker="#Time_Warp_Modes">time warp mode</seealso>
used. On a system that is lacking OS monotonic time, the Erlang
monotonic time can only guarantee monotonicity and can more or less
not give any other guarantees. The frequency adjustments made to
the Erlang monotonic time depends on the time warp mode
used.</p>
<p>Internally in the runtime system the Erlang monotonic
time is the "time engine" that is used for more or less
everything that has anything to do with time. All timers
regardless of it is a <c>receive ... after</c> timer, BIF timer,
or a timer in the <c>timer</c> module are triggered
relative Erlang monotonic time. Even
<seealso marker="#Erlang_System_Time">Erlang system
time</seealso> is based on Erlang monotonic time.
By adding current Erlang monotonic time with current time
offset you get current Erlang system time. Current time
offset can be retrieved by calling
<seealso marker="erlang#time_offset/0"><c>erlang:time_offset/0</c></seealso>.
</p>
</section>
</section>
<section>
<title>Introduction</title>
<p>Time is vital to an Erlang program and, more importantly, <em>correct</em>
time is vital to an Erlang program. As Erlang is a language with
soft real time properties and we have the possibility to express
time in our programs, the Virtual Machine and the language has to be
very careful about what is considered a correct point in time and in
how time functions behave.</p>
<p>In the beginning, Erlang was constructed assuming that the wall
clock time in the system showed a monotonic time moving forward at
exactly the same pace as the definition of time. That more or less
meant that an atomic clock (or better) was expected to be attached
to your hardware and that the hardware was then expected to be
locked away from any human (or unearthly) tinkering for all
eternity. While this might be a compelling thought, it's simply
never the case.</p>
<p>A "normal" modern computer can not keep time. Not on itself and
not unless you actually have a chip level atomic clock wired to
it. Time, as perceived by your computer, will normally need to be
corrected. Hence the NTP protocol that together with the ntpd
process will do it's best to keep your computers time in sync with
the "real" time in the universe. Between NTP corrections, usually a
less potent time-keeper than an atomic clock is used.</p>
<p>But NTP is not fail safe. The NTP server can be unavailable, the
ntp.conf can be wrongly configured or your computer may from time to
time be disconnected from the internet. Furthermore you can have a
user (or even system administrator) on your system that thinks the
right way to handle daylight saving time is to adjust the clock one
hour two times a year (a tip, that is not the right way to do
it...). To further complicate things, this user fetched your
software from the internet and has never ever thought about what's
the correct time as perceived by a computer. The user simply does
not care about keeping the wall clock in sync with the rest of the
universe. The user expects your program to have omnipotent knowledge
about the time.</p>
<p>Most programmers also expect time to be reliable, at least until
they realize that the wall clock time on their workstation is of by
a minute. Then they simply set it to the correct time, maybe or
maybe not in a smooth way. Most probably not in a smooth way.</p>
<p>The amount of problems that arise when you expect the wall clock
time on the system to always be correct may be immense. Therefore Erlang
introduced the "corrected estimate of time", or the "time
correction" many years ago. The time correction relies on the fact
that most operating systems have some kind of monotonic clock,
either a real time extension or some built in "tick counter" that is
independent of the wall clock settings. This counter may have
microsecond resolution or much less, but generally it has a drift
that is not to be ignored.</p>
</section>
<marker id="Time_Correction"/>
<section>
<title>Time Correction</title>
<p>If time correction is enabled, the Erlang runtime system
will make use of both
<seealso marker="#OS_System_Time">OS system time</seealso>
and <seealso marker="#OS_Monotonic_Time">OS monotonic time</seealso>,
in order to make adjustments of the frequency of the Erlang
monotonic clock. Time correction will ensure that
<seealso marker="#Erlang_Monotonic_Time">Erlang monotonic time</seealso>
will not warp, and that the frequency is relatively accurate.
The type of adjustments made to the frequency depends on the
time warp mode used. This will be discussed in more details in
the <seealso marker="#Time_Warp_Modes">time warp modes</seealso>
section below.</p>
<p>By default time correction will be enabled if support for
it on the specific platform exist. Support for it includes
both an OS monotonic time provided by the OS, and an
implementation in the Erlang runtime system utilizing the
OS monotonic time. You can check if your system has support
for OS monotonic time by calling
<seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>,
and you can check if time correction is enabled on your
system by calling
<seealso marker="erlang#system_info_time_correction"><c>erlang:system_info(time_correction)</c></seealso>.</p>
<p>Time correction is enabled or disabled by passing the
<seealso marker="erl#+c"><c>+c [true|false]</c></seealso>
command line argument to <c>erl</c>.</p>
<p>If time correction is disabled, Erlang monotonic time
may warp forwards, it may stop and even freeze for extended
periods of time, and there are no guarantees that the frequency
of the Erlang monotonic clock is accurate or stable.</p>
<p><em>You typically never want to disable time correction</em>.
Previously there was a performance penalty associated with time
correction, but nowadays it is most often the other way around.
By disabling time correction you are likely to get bad scalability,
bad performance, and bad time measurements.</p>
</section>
<marker id="Time_Warp_Safe_Code"/>
<section>
<title>Time Warp Safe Code</title>
<p>Time warp safe code is code that is able to handle
a <seealso marker="#Time_Warp">time warp</seealso> of
<seealso marker="#Erlang_System_Time">Erlang system time</seealso>.
</p>
<p><seealso marker="erlang#now/0"><c>erlang:now/0</c></seealso>
behaves very bad when Erlang system time warps. When Erlang
system time do a time warp backwards, the values returned
from <c>erlang:now/0</c> will freeze (if you disregard the
micro second increments made due to the actual call) until
OS system time reach the point of the last value returned by
<c>erlang:now/0</c>. This freeze might continue for very
long periods of time. It might take years, decades,
and even longer than this until the freeze stops.</p>
<p>All uses of <c>erlang:now/0</c> are not necessarily
time warp unsafe. If you do not use it to get time, it
will be time warp safe. However <em>all uses of
<c>erlang:now/0</c> are suboptimal</em> from a performance
and scalability perspective. So you really want to replace
the usage of it with other functionality. For examples
of how to replace the usage of <c>erlang:now/0</c>,
see the <seealso marker="#Dos_and_Donts">Dos and Donts</seealso>
section.</p>
</section>
<marker id="Time_Warp_Modes"/>
<section>
<title>Time Warp Modes</title>
<p>Current <seealso marker="#Erlang_System_Time">Erlang system
time</seealso> is determined by adding current
<seealso marker="erlang#monotonic_time/0">Erlang monotonic time</seealso>
with current
<seealso marker="erlang#time_offset/0">time offset</seealso>. The
time offset is managed differently depending on which time
warp mode you use. The time warp mode is set by passing the
<seealso marker="erl#+C_"><c>+C
[no_time_warp|single_time_warp|multi_time_warp]</c></seealso>
command line argument to <c>erl</c>.</p>
<marker id="No_Time_Warp_Mode"/>
<section>
<title>No Time Warp Mode</title>
<p>The time offset is determined at runtime system start
and will after this not change. This is the default behavior.
Not because it is the best mode (which it isn't). It is
default <em>only</em> because this is how the runtime system
always has behaved up until ERTS version 7.0, and you have to
ensure that your Erlang code that may execute during a time
warp is <seealso marker="#Time_Warp_Safe_Code">time warp
safe</seealso> before you can enable other modes.</p>
<p>Since the time offset is not allowed to change, time
correction needs to adjust the frequency of the Erlang
monotonic clock in order to smoothly align Erlang system
time with OS system time. A big downside of this approach
is that we on purpose will use a faulty frequency on the
Erlang monotonic clock if adjustments are needed. This
error may be as big as 1%. This error will show up in all
time measurements in the runtime system.</p>
<p>If time correction is not enabled, the Erlang monotonic
time will freeze when the OS system time leap backwards.
The freeze of the monotonic time will continue until
OS system time catch up. The freeze may continue for
a very long time. When OS system time leaps forwards,
Erlang monotonic time will also leap forward.</p>
</section>
<marker id="Single_Time_Warp_Mode"/>
<section>
<title>Single Time Warp Mode</title>
<p>This mode is more or less a backwards compatibility mode
as of its introduction.</p>
<p>On an embedded system it is not uncommon that the system
has no power supply at all, not even a battery, when it is
shut off. The system clock on such a system will typically
be way off when the system boots. If the
<seealso marker="#No_Time_Warp_Mode">no time warp mode</seealso>
is used, and the Erlang runtime system is started before
the OS system time has been corrected, the Erlang system
time may be wrong for a very long time, even centuries or
more.</p>
<p>If you for some reason need to use Erlang code that
is not
<seealso marker="#Time_Warp_Safe_Code">time warp safe</seealso>,
and you need to start the Erlang runtime system before the OS
system time has been corrected, you may want to use the single
time warp mode. Note that there are limitations to when you can
execute time warp unsafe code using this mode. If it is possible
to only utilize time warp safe code, it is <em>much</em> better
to use the <seealso marker="#Multi_Time_Warp_Mode">multi time
warp mode</seealso> instead.
</p>
<p>Using the single time warp mode, the time offset is
handled in two phases:</p>
<taglist>
<tag>Preliminary Phase</tag>
<item>
<p>The preliminary phase starts when the runtime
system starts. A preliminary time offset based on
current OS system time is determined. This offset will
from now on be fixed during the whole preliminary phase.</p>
<p>If time correction is enabled, adjustments to the
Erlang monotonic clock will be made to keep its
frequency as correct as possible, but <em>no</em>
adjustments will be made trying to align Erlang system
time and OS system time. That is, during the preliminary
Erlang system time and OS system time might diverge
from each other, and no attempt to prevent this will
be made.</p>
<p>If time correction is disabled, changes in OS system
time will effect the monotonic clock the same way as
when the <seealso marker="#No_Time_Warp_Mode">no time warp
mode</seealso> is used.</p>
</item>
<tag>Final Phase</tag>
<item>
<p>The final phase begin when the user finalize the time
offset by calling
<seealso marker="erlang#system_flag_time_offset"><c>erlang:system_flag(time_offset, finalize)</c></seealso>.
The finalization can only be performed once.
</p>
<p>During finalization, the time offset is adjusted and
fixated so that current Erlang system time align with
current OS system time. Since the time offset may
change during the finalization, the Erlang system time
may do a time warp at this point. The time offset will
from now on be fixed until the runtime system terminates.
If time correction has been enabled, the time
correction will from now on also make adjustments
in order to align Erlang system time with OS system
time. When the system is in the final phase it behaves
exactly as in the <seealso marker="#No_Time_Warp_Mode">no
time warp mode</seealso>.</p>
</item>
</taglist>
<p>In order for this to work properly there are two
requirements that the user needs to ensure are
satisfied:</p>
<taglist>
<tag>Forward Time Warp</tag>
<item><p>The time warp made when finalizing the time offset
can only be done forwards without encountering problems.
This implies that the user has to ensure that the OS
system time is set to a time earlier or equal to actual
POSIX time before starting the Erlang runtime system. If
you are not completely sure the OS system time is correct,
set it to a time that is guaranteed to be earlier than
actual POSIX time before starting the Erlang runtime
system just to be safe.</p></item>
<tag>Finalize Correct OS System Time</tag>
<item><p>The OS system time needs to be correct when the
the user finalizes the time offset.</p></item>
</taglist>
<p>If these requirements are not fulfilled, the system
may behave very bad.
</p>
<p>Assuming that the requirements above are fulfilled,
time correction is enabled, and that the OS system time
is adjusted using some time adjustment protocol like NTP
or similar, only small adjustments of the Erlang monotonic
time should be needed in order to keep system times
aligned after finilization. As long as the system is not
suspended, the largest adjustments needed should be for
inserted (or deleted) leap seconds.</p>
<warning><p>In order to be able to use this mode you have
to ensure that all Erlang code that will execute in
both phases are
<seealso marker="#Time_Warp_Safe_Code">time warp
safe</seealso>.</p>
<p>Code that only execute in the final phase does not have
to be able to cope with the time warp.</p></warning>
</section>
<marker id="Multi_Time_Warp_Mode"/>
<section>
<title>Multi Time Warp Mode</title>
<p><em>Multi time warp mode in combination with time
correction is the preferred configuration</em>. This since,
on almost all platforms, the Erlang runtime system will have
better performance, will scale better, will behave better,
and since the accuracy, and precision of time measurements
will be better. Only Erlang runtime systems executing on
ancient platforms will benefit from another configuration.</p>
<p>The time offset may change at any time without limitations.
That is, Erlang system time may perform time warps both
forwards and backwards at <em>any</em> time. Since we align
the Erlang system time with the OS system time by changing
the time offset, we can enable a time correction that tries
to adjust the frequency of the Erlang monotonic clock to be as
correct as possible. This will make time measurements using
the Erlang monotonic time more accurate and precise.</p>
<p>If time correction is disabled, Erlang monotonic time
will leap forward if OS system time leaps forward. If the
OS system time leaps backwards, Erlang monotonic time will
stop briefly but it does not freeze for extended periods
of time. This since the time offset is changed in order to
align Erlang system time with OS system time.</p>
<warning><p>In order to be able to use this mode you have
to ensure that all Erlang code that will execute on the
runtime system is
<seealso marker="#Time_Warp_Safe_Code">time warp
safe</seealso>.</p></warning>
</section>
</section>
<marker id="The_New_Time_API"/>
<section>
<title>The New Time API</title>
<p>The old time API is based on
<seealso marker="erlang#now/0"><c>erlang:now/0</c></seealso>.
The major issue with <c>erlang:now/0</c> is that it was
intended to be used for so many unrelated things. This
tied these unrelated operations together and unnecessarily
caused performance, scalability as well as accuracy, and
precision issues for operations that do not need to have
such issues. The new API spreads different functionality
over multiple functions in order to improve on this.</p>
<p>In order to be backwards compatible <c>erlang:now/0</c> will
remain as is, but <em>you are strongly discouraged from using
it</em>. A lot of uses of <c>erlang:now/0</c> will also
prevent you from using the new
<seealso marker="#Multi_Time_Warp_Mode">multi time warp
mode</seealso> which is an important part of this
new time functionality improvement.</p>
<p>Some of the new BIFs on some systems, perhaps surprisingly,
return negative integer values on a newly started run time
system. This is not a bug, but a memory usage optimization.</p>
<p>The new API consists of a number of new BIFs:</p>
<list>
<item><p><seealso marker="erlang#convert_time_unit/3"><c>erlang:convert_time_unit/3</c></seealso></p></item>
<item><p><seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time/0</c></seealso></p></item>
<item><p><seealso marker="erlang#monotonic_time/1"><c>erlang:monotonic_time/1</c></seealso></p></item>
<item><p><seealso marker="erlang#system_time/0"><c>erlang:system_time/0</c></seealso></p></item>
<item><p><seealso marker="erlang#system_time/1"><c>erlang:system_time/1</c></seealso></p></item>
<item><p><seealso marker="erlang#time_offset/0"><c>erlang:time_offset/0</c></seealso></p></item>
<item><p><seealso marker="erlang#time_offset/1"><c>erlang:time_offset/1</c></seealso></p></item>
<item><p><seealso marker="erlang#timestamp/0"><c>erlang:timestamp/0</c></seealso></p></item>
<item><p><seealso marker="erlang#unique_integer/0"><c>erlang:unique_integer/0</c></seealso></p></item>
<item><p><seealso marker="erlang#unique_integer/1"><c>erlang:unique_integer/1</c></seealso></p></item>
<item><p><seealso marker="kernel:os#system_time/0"><c>os:system_time/0</c></seealso></p></item>
<item><p><seealso marker="kernel:os#system_time/1"><c>os:system_time/1</c></seealso></p></item>
</list>
<p>and a number of extensions of existing BIFs:</p>
<list>
<item><p><seealso marker="erlang#monitor/2"><c>erlang:monitor(time_offset, clock_service)</c></seealso></p></item>
<item><p><seealso marker="erlang#system_flag_time_offset"><c>erlang:system_flag(time_offset, finalize)</c></seealso></p></item>
<item><p><seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso></p></item>
<item><p><seealso marker="erlang#system_info_os_system_time_source"><c>erlang:system_info(os_system_time_source)</c></seealso></p></item>
<item><p><seealso marker="erlang#system_info_time_offset"><c>erlang:system_info(time_offset)</c></seealso></p></item>
<item><p><seealso marker="erlang#system_info_time_warp_mode"><c>erlang:system_info(time_warp_mode)</c></seealso></p></item>
<item><p><seealso marker="erlang#system_info_time_correction"><c>erlang:system_info(time_correction)</c></seealso></p></item>
<item><p><seealso marker="erlang#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso></p></item>
<item><p><seealso marker="erlang#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso></p></item>
</list>
<marker id="The_New_Erlang_Monotonic_Time"/>
<section>
<title>The New Erlang Monotonic Time</title>
<p>The Erlang monotonic time as such is new as of ERTS
version 7.0. It has been introduced in order to be able
to detach time measurements such as elapsed time from
calender time. It is very common that one is interested
in measuring elapsed time or specifying a time relative
to another point in time without having any need to know
what the involved times are in UTC or any other
globally defined time scale. By introducing a time scale
that has a local definition of where it starts, it is
possible to manage time that do not concern calender
time on that time scale. Erlang monotonic time use
such a time scale with a locally defined start.</p>
<p>The introduction of Erlang monotonic time gives us
the possibility to adjust the two Erlang times (Erlang
monotonic time and Erlang system time) separately. By
doing this, accuracy of elapsed time does not have to
suffer just because the system time happened to be
wrong at some point in time. Separate adjustments
of the two times are only performed in the time warp
modes, and only fully separated in the
<seealso marker="#Multi_Time_Warp_Mode">multi
time warp mode</seealso>. All other modes than the
multi time warp mode are there for backwards
compatibility reasons, and when using these the
accuracy of Erlang monotonic time suffer since
the adjustments of Erlang monotonic time in these
modes are more or less tied to the Erlang system
time.</p>
<p>The adjustment of system time could have been made
smother than using a time warp approach, but we think
that would be a bad choice. Since we are able to
express and measure time that aren't connected to
calender time by the use of Erlang monotonic time, it
is better to expose the change in Erlang system time
immediately. This since it makes it possible for the
Erlang applications executing on the system to react
on the change in system time as soon as possible. This
is also more or less exactly how most OSes handle this
(OS monotonic time and OS system time). By adjusting
system time smoothly we would just hide the fact that
system time changed and make it harder for the Erlang
applications to react to the change in a sensible way.</p>
<p>In order to be able to react to a change in Erlang
system time you have to be able to detect that it
happened. The change in Erlang system time occurs when
current time offset is changed. We have therefore
introduced the possibility to monitor the time offset
using
<seealso marker="erlang#monitor/2"><c>erlang:monitor(time_offset, clock_service)</c></seealso>. A process monitoring the time
offset will be sent a message on the following format
when the time offset is changed:</p>
<code type="none">{'CHANGE', MonitorReference, time_offset, clock_service, NewTimeOffset}</code>
</section>
<marker id="Unique_Values"/>
<section>
<title>Unique Values</title>
<p>Besides reporting time <c>erlang:now/0</c> also
produce unique and strictly monotonically increasing
values. In order to detach this functionality from
time measurements we have introduced
<seealso marker="erlang#unique_integer/1"><c>erlang:unique_integer()</c></seealso>.
</p>
</section>
<marker id="Dos_and_Donts"/>
<section>
<title>Dos and Don'ts</title>
<p>Previously <c>erlang:now/0</c> was the only option for doing
quite a lot of things. We will look at a few different things
<c>erlang:now/0</c> could be used for, and how you want to do
this using the new API:</p>
<marker id="Dos_and_Donts_Retrieve_Erlang_System_Time"/>
<section>
<title>Retrieve Erlang System Time</title>
<dont>
<p>
use <c>erlang:now/0</c> in order to retrieve current Erlang
system time.
</p>
</dont>
<do>
<p>
use
<seealso marker="erlang#system_time/1"><c>erlang:system_time/1</c></seealso>
in order to retrieve current Erlang system time on the
<seealso marker="erlang#type_time_unit">time unit</seealso>
of your choice.</p>
<p>If you want the same format as returned by <c>erlang:now/0</c>, use
<seealso marker="erlang#timestamp/0"><c>erlang:timestamp/0</c></seealso>.
</p>
</do>
</section>
<marker id="Dos_and_Donts_Measure_Elapsed_Time"/>
<section>
<title>Measure Elapsed Time</title>
<dont>
<p>
take timestamps with <c>erlang:now/0</c> and calculate
the difference in time with
<seealso marker="stdlib:timer#now_diff/2"><c>timer:now_diff/2</c></seealso>.
</p>
</dont>
<do>
<p>
take timestamps with
<seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time/0</c></seealso>
and calculate the time difference using ordinary subtraction.
The result will be in <c>native</c>
<seealso marker="erlang#type_time_unit">time unit</seealso>.
If you want to convert the
result to another time unit you can do this using
<seealso marker="erlang#convert_time_unit/3"><c>erlang:convert_time_unit/3</c></seealso>.
</p>
<p>Another easier way of doing this is to use
<seealso marker="erlang#monotonic_time/1"><c>erlang:monotonic_time/1</c></seealso>
with desired time unit. However, you may lose accuracy,
and precision this way.
</p>
</do>
</section>
<marker id="Dos_and_Donts_Determine_Order_of_Events"/>
<section>
<title>Determine Order of Events</title>
<dont>
<p>
determine the order of events by saving a timestamp
with <c>erlang:now/0</c> when the event happens.
</p>
</dont>
<do>
<p>
determine the order of events by saving the integer
returned by
<seealso marker="erlang#unique_integer/1"><c>erlang:unique_integer([monotonic])</c></seealso>
when the event happens. These integers will be strictly
monotonically ordered on current runtime system instance
corresponding to creation time.
</p>
</do>
</section>
<marker id="Dos_and_Donts_Determine_Order_of_Events_With_Time_of_the_Event"/>
<section>
<title>Determine Order of Events With Time of the Event</title>
<dont>
<p>
determine the order of events by saving a timestamp
with <c>erlang:now/0</c> when the event happens.
</p>
</dont>
<do>
<p>
determine the order of events by saving a tuple
containing
<seealso marker="erlang#monotonic_time/0">monotonic time</seealso>
and a <seealso marker="erlang#unique_integer/1">strictly
monotonically increasing integer</seealso> like this:</p>
<code type="none">
Time = erlang:monotonic_time(),
UMI = erlang:unique_integer([monotonic]),
EventTag = {Time, UMI}</code>
<p>These tuples will be strictly monotonically ordered
on the current runtime system instance according to
creation time. Note that it is important that the
monotonic time is in the first element (the most
significant element when comparing 2-tuples). Using
the monotonic time in the tuples, you can calculate time
between events.</p>
<p>If you are interested in the Erlang system time at the
time when the event occurred you can also save the time
offset before or after saving the events using
<seealso marker="erlang#time_offset/0"><c>erlang:time_offset/0</c></seealso>.
Erlang monotonic time added with the time
offset corresponds to Erlang system time.</p>
<p>If you are executing in a mode where time offset
may change and you want to be able to get the actual
Erlang system time when the event occurred you can
save the time offset as a third element in the tuple
(the least significant element when comparing 3-tuples).</p>
</do>
</section>
<marker id="Dos_and_Donts_Create_a_Unique_Name"/>
<section>
<title>Create a Unique Name</title>
<dont>
<p>
use the values returned from <c>erlang:now/0</c>
in order to create a name unique on the current
runtime system instance.
</p>
</dont>
<do>
<p>
use the value returned from
<seealso marker="erlang#unique_integer/0"><c>erlang:unique_integer/0</c></seealso>
in order to create a name unique on the current runtime system
instance. If you only want positive integers, you can use
<seealso marker="erlang#unique_integer/1"><c>erlang:unique_integer([positive])</c></seealso>.
</p>
</do>
</section>
<marker id="Dos_and_Donts_Seed_Random_Number_Generation_With_a_Unique_Value"/>
<section>
<title>Seed Random Number Generation With a Unique Value</title>
<dont>
<p>
seed random number generation using <c>erlang:now()</c>.
</p>
</dont>
<do>
<p>
seed random number generation using a combination of
<seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time()</c></seealso>,
<seealso marker="erlang#time_offset/0"><c>erlang:time_offset()</c></seealso>,
<seealso marker="erlang#unique_integer/0"><c>erlang:unique_integer()</c></seealso>, and other functionality.
</p>
</do>
</section>
<p>To sum this section up: <em>Don't use <c>erlang:now/0</c>!</em></p>
</section>
</section>
<marker id="Supporting_Both_New_and_Old_OTP_Releases"/>
<section>
<title>Supporting Both New and Old OTP Releases</title>
<p>Your code may be required to be able to run on a variety
of OTP installations of different OTP releases. If so, you
can not just use the new API out of the box, since it will
not be available on old pre OTP 18 releases. The solution
is <em>not</em> to avoid using the new API, since your
code then won't be able to benefit from the scalability
and accuracy improvements made. Instead you want to use the
new API when available, and fall back on <c>erlang:now/0</c>
when it is not available. Fortunately almost all of the new
API can easily be implemented using existing primitives
(except for
<seealso marker="erlang#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso>,
<seealso marker="erlang#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso>,
<seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>, and
<seealso marker="erlang#system_info_os_system_time_source"><c>erlang:system_info(os_system_time_source)</c></seealso>).
By wrapping the API with functions that fall back on
<c>erlang:now/0</c> when the new API is not available,
and using these wrappers instead of using the API directly
the problem is solved. These wrappers can for example
be implemented as in
<url href="time_compat.erl"><c>$ERL_TOP/erts/example/time_compat.erl</c></url>.</p>
</section>
</chapter>
|