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
|
<?xml version="1.0" encoding="utf8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
<year>1999</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
The contents of this file are subject to the Erlang Public License,
Version 1.1, (the "License"); you may not use this file except in
compliance with the License. You should have received a copy of the
Erlang Public License along with this software. If not, it can be
retrieved online at http://www.erlang.org/.
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
the License for the specific language governing rights and limitations
under the License.
</legalnotice>
<title>Time and time correction in Erlang</title>
<prepared>Patrik Nyblom</prepared>
<responsible></responsible>
<docno></docno>
<approved></approved>
<checked></checked>
<date>2013-08-28</date>
<rev>PA1</rev>
<file>time_correction.xml</file>
</header>
<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>
<p>So we have this monotonic ticking and we have the wall clock
time. Two unreliable times that together can give us an estimate of
an actual wall clock time that does not jump around and that
monotonically moves forward. If the tick counter has a high
resolution, this is fairly easy to do, if the counter has a low
resolution, it's more expensive, but still doable down to
frequencies of 50-60 Hz (of the tick counter).</p>
<p>So the corrected time is the nearest approximation of an atomic
clock that is available on the computer. We want it to have the
following properties:</p>
<taglist>
<tag>Monotonic</tag>
<item>The clock should not move backwards</item>
<tag>Intervals should be near the truth</tag>
<item>We want the actual time (as measured by an atomic clock or
an astronomer) that passes between two time stamps, T1 and T2, to be as
near to T2 - T1 as possible.</item>
<tag>Tight coupling to the wall clock</tag>
<item>We want a timer that is to be fired when the wall clock
reaches a time in the future, to fire as near to that point in
time as possible</item>
</taglist>
<p>To meet all the criteria, we have to utilize both times in such a
way that Erlangs "corrected time" moves slightly slower or slightly
faster than the wall clock to get in sync with it. The word
"slightly" means a maximum of 1% difference to the wall clock time,
meaning that a sudden change in the wall clock of one minute, takes
100 minutes to fix, by letting all "corrected time" move 1% slower
or faster.</p>
<p>Needless to say, correcting for a faulty handling of daylight
saving time may be disturbing to a user comparing wall clock
time to for example calendar:now_to_local_time(erlang:now()). But
calendar:now_to_local_time/1 is not supposed to be used for presenting wall
clock time to the user.</p>
<p>Time correction is not perfect, but it saves you from the havoc
of clocks jumping around, which would make timers in your program
fire far to late or far to early and could bring your whole system
to it's knees (or worse) just because someone detected a small error
in the wall clock time of the server where your program runs. So
while it might be confusing, it is still a really good feature of
Erlang and you should not throw it away using time functions which
may give you higher benchmark results, not unless you really know
what you're doing.</p>
<section>
<title>What does time correction mean in my system?</title>
<p>Time correction means that Erlang estimates a time from current
and previous settings of the wall clock, and it uses a fairly
exact tick counter to detect when the wall clock time has jumped
for some reason, slowly adjusting to the new value.</p>
<p>In practice, this means that the difference between two calls
to time corrected functions, like erlang:now(), might differ up to
one percent from the corresponding calls to non time corrected
functions (like os:timestamp()). Furthermore, if comparing
calendar:local_time/0 to calendar:now_to_local_time(erlang:now()),
you might temporarily see a difference, depending on how well kept your
system is.</p>
<p>It is important to understand that it is (to the program)
always unknown if it is the wall clock time that moves in the
wrong pace or the Erlang corrected time. The only way to determine
that, is to have an external source of universally correct time. If
some such source is available, the wall clock time can be kept
nearly perfect at all times, and no significant difference will be
detected between erlang:now/0's pace and the wall clock's.</p>
<p>Still, the time correction will mean that your system keeps
it's real time characteristics very well, even when the wall clock
is unreliable.</p>
</section>
<section>
<title>Where does Erlang use corrected time?</title>
<p>For all functionality where real time characteristics are
desirable, time correction is used. This basically means:</p>
<taglist>
<tag>erlang:now/0</tag>
<item>The infamous erlang:now/0 function uses time correction so
that differences between two "now-timestamps" will correspond to
other timeouts in the system. erlang:now/0 also holds other
properties, discussed later.</item>
<tag>receive ... after</tag>
<item>Timeouts on receive uses time correction to determine a
stable timeout interval.</item>
<tag>The timer module</tag>
<item>As the timer module uses other built in functions which
deliver corrected time, the timer module itself works with
corrected time.</item>
<tag>erlang:start_timer/3 and erlang:send_after/3</tag>
<item>The timer BIF's work with corrected time, so that they
will not fire prematurely or too late due to changes in the wall
clock time.</item>
</taglist>
<p>All other functionality in the system where erlang:now/0 or any
other time corrected functionality is used, will of course
automatically benefit from it, as long as it's not "optimized" to
use some other time stamp function (like os:timestamp/0).</p>
<p>Modules like calendar and functions like erlang:localtime/0 use
the wall clock time as it is currently set on the system. They
will not use corrected time. However, if you use a now-value and
convert it to local time, you will get a corrected local time
value, which may or may not be what you want. Typically older code
tend to use erlang:now/0 as a wall clock time, which is usually
correct (at least when testing), but might surprise you when
compared to other times in the system.</p>
</section>
<section>
<title>What is erlang:now/0 really?</title>
<p>erlang:now/0 is a function designed to serve multiple purposes
(or a multi-headed beast if you're a VM designer). It is expected
to hold the following properties:</p>
<taglist>
<tag>Monotonic</tag>
<item>erlang:now() never jumps backwards - it always moves
forward</item>
<tag>Interval correct</tag>
<item>The interval between two erlang:now() calls is expected to
correspond to the correct time in real life (as defined by an
atomic clock, or better)</item>
<tag>Absolute correctness</tag>
<item>The erlang:now/0 value should be possible to convert to an
absolute and correct date-time, corresponding to the real world
date and time (the wall clock)</item>
<tag>System correspondence</tag>
<item>The erlang:now/0 value converted to a date-time is
expected to correspond to times given by other programs on the
system (or by functions like os:timestamp/0)</item>
<tag>Unique</tag>
<item>No two calls to erlang:now on one Erlang node should
return the same value</item>
</taglist>
<p>All these requirements are possible to uphold at the same
time if (and only if):</p>
<taglist>
<tag>The wall clock time of the system is perfect</tag>
<item>The system (Operating System) time needs to be perfectly
in sync with the actual time as defined by an atomic clock or
a better time source. A good installation using NTP, and that is
up to date before Erlang starts, will have properties that for
most users and programs will be near indistinguishable from the
perfect time. Note that any larger corrections to the time done
by hand, or after Erlang has started, will partly (or
temporarily) invalidate some of the properties, as the time is
no longer perfect.</item>
<tag>Less than one call per microsecond to erlang:now/0 is
done</tag>
<item>This means that at <em>any</em> microsecond interval in
time, there can be no more than one call to erlang:now/0 in the
system. However, for the system not to loose it's properties
completely, it's enough that it on average is no more than one
call per microsecond (in one Erlang node).</item>
</taglist>
<p>The uniqueness property of erlang:now/0 is the most limiting
property. It means that erlang:now() maintains a global state and
that there is a hard-to-check property of the system that needs to
be maintained. For most applications this is still not a problem,
but a future system might very well manage to violate the
frequency limit on the calls globally. The uniqueness property is
also quite useless, as there are globally unique references that
provide a much better unique value to programs. However the
property will need to be maintained unless a really subtle
backward compatibility issue is to be introduced.</p>
</section>
<section>
<title>Should I use erlang:now/0 or os:timestamp/0</title>
<p>The simple answer is to use erlang:now/0 for everything where
you want to keep real time characteristics, but use os:timestamp
for things like logs, user communication and debugging (typically
timer:ts uses os:timestamp, as it is a test tool, not a real world
application API). The benefit of using os:timestamp/0 is that it's
faster and does not involve any global state (unless the operating
system has one). The downside is that it will be vulnerable to wall
clock time changes.</p>
</section>
<section>
<title>Turning off time correction</title>
<p>If, for some reason, time correction causes trouble and you are
absolutely confident that the wall clock on the system is nearly
perfect, you can turn off time correction completely by giving the
<c>+c</c> option to <c>erl</c>. The probability for this being a
good idea, is very low.</p>
</section>
</chapter>
|