aboutsummaryrefslogtreecommitdiffstats
path: root/erts/doc/src/time_correction.xml
diff options
context:
space:
mode:
Diffstat (limited to 'erts/doc/src/time_correction.xml')
-rw-r--r--erts/doc/src/time_correction.xml1082
1 files changed, 855 insertions, 227 deletions
diff --git a/erts/doc/src/time_correction.xml b/erts/doc/src/time_correction.xml
index 7f7c28fc30..236fe679cb 100644
--- a/erts/doc/src/time_correction.xml
+++ b/erts/doc/src/time_correction.xml
@@ -4,25 +4,26 @@
<chapter>
<header>
<copyright>
- <year>1999</year><year>2014</year>
+ <year>1999</year><year>2015</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/.
+ 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
- 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.
+ 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>Patrik Nyblom</prepared>
+ <title>Time and Time Correction in Erlang</title>
+ <prepared></prepared>
<responsible></responsible>
<docno></docno>
<approved></approved>
@@ -31,244 +32,871 @@
<rev>PA1</rev>
<file>time_correction.xml</file>
</header>
+
+ <section>
+ <title>New Extended Time Functionality</title>
+ <note><p>As of OTP 18 (<c>ERTS</c> version 7.0) the time functionality of
+ Erlang has been extended. This includes a
+ <seealso marker="#The_New_Time_API">new API</seealso>
+ for time and
+ <seealso marker="#Time_Warp_Modes">time warp
+ modes</seealso> that alter the system behavior 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 still works. Thus, 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> is deprecated, as it is and
+ will be a scalability bottleneck.</p>
+
+ <p>By using the new API, you
+ automatically get scalability and performance improvements. This
+ also enables you to use the
+ <seealso marker="#Multi_Time_Warp_Mode">multi-time warp mode</seealso>
+ that improves accuracy and precision of time measurements.</p>
+ </note>
+ </section>
+
+ <section>
+ <title>Terminology</title>
+ <p>To make it easier to understand this section, some terms
+ are defined. This is a mix 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. UT1 is based on the rotation of the earth
+ and conceptually means solar time at 0° longitude.</p>
+ </section>
+
+ <marker id="UTC"/>
+ <section>
+ <title>UTC</title>
+ <p>Coordinated Universal Time. UTC almost aligns with
+ <seealso marker="#UT1">UT1</seealso>. However, UTC uses the
+ SI definition of a second, which has not exactly the same length
+ as the second used by UT1. This means that UTC slowly drifts from
+ UT1. To keep UTC relatively in sync with UT1, leap seconds
+ are inserted, and potentially also deleted. That is, an UTC day can
+ 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>,
+ 1970-01-01.
+ <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 has 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 (which has not
+ 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 distinguished
+ repeatedly and reliably when reading time values. Precision
+ is limited by the
+ <seealso marker="#Time_Resolution">resolution</seealso>, but
+ resolution and precision can 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 does 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>. To
+ retrieve it, call
+ <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.</p>
+
+ <p>To get information about the Erlang runtime
+ system's source of OS system time, call
+ <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 has a relatively steady
+ frequency although not completely correct. However, it is not
+ uncommon that OS monotonic time stops if the system is
+ suspended. This time typically increases since some
+ unspecified point in time that is not connected to
+ <seealso marker="#OS_System_Time">OS system time</seealso>.
+ This type of time is not necessarily provided by all
+ operating systems.</p>
+
+ <p>To get information about the Erlang
+ runtime system's source of OS monotonic time, call
+ <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>. To
+ retrieve it, call
+ <seealso marker="erlang#system_time/0"><c>erlang:system_time()</c></seealso>.</p>
+
+ <p>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 the
+ <seealso marker="#Time_Warp_Modes">time warp mode</seealso> used,
+ this can be achieved by letting 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. Erlang monotonic time increases since
+ some unspecified point in time. To retrieve it, call
+ <seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time()</c></seealso>.
+ </p>
+
+ <p>The <seealso marker="#Time_Accuracy">accuracy</seealso> and
+ <seealso marker="#Time_Precision">precision</seealso> of Erlang
+ monotonic time heavily depends on the following:</p>
+
+ <list type="bulleted">
+ <item>Accuracy and precision of
+ <seealso marker="#OS_Monotonic_Time">OS monotonic time</seealso>
+ </item>
+ <item>Accuracy and precision of
+ <seealso marker="#OS_System_Time">OS system time</seealso>
+ </item>
+ <item><seealso marker="#Time_Warp_Modes">time warp mode</seealso> used
+ </item>
+ </list>
+
+ <p>On a system without OS monotonic time, Erlang monotonic
+ time guarantees monotonicity, but cannot give
+ other guarantees. The frequency adjustments made to
+ Erlang monotonic time depend on the time warp mode used.</p>
+
+ <p>Internally in the runtime system, 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.</p>
+
+ <p>To retrieve current time offset, call
+ <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
+ soft real-time properties and we can express
+ time in our programs, the Virtual Machine and the language must be
+ careful about what is considered a correct time and in
how time functions behave.</p>
- <p>In the beginning, Erlang was constructed assuming that the wall
+ <p>When Erlang was designed, it was assumed 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
+ exactly the same pace as the definition of time. This more or less meant
+ that an atomic clock (or better time source) 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
+ locked away from any human tinkering forever. While this can be a
+ compelling thought, it is simply never the case.</p>
+
+ <p>A "normal" modern computer cannot keep time, not on itself and
+ not unless you have a chip-level atomic clock wired to it. Time,
+ as perceived by your computer, must normally be corrected. Hence
+ the Network Time Protocol (NTP) protocol, together with the <c>ntpd</c>
+ process, does its best to keep your computer time in sync with
+ the correct time. 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
+ <p>However, NTP is not fail-safe. The NTP server can be unavailable,
+ <c>ntp.conf</c> can be wrongly configured, or your computer may
+ sometimes be disconnected from Internet. Furthermore, you can have a
+ user (or even system administrator) who thinks the correct
+ way to handle Daylight Saving Time is to adjust the clock one
+ hour two times a year (which is the incorrect way to do it).
+ To complicate things further, this user fetched your
+ software from Internet and has not considered what
+ the correct time is as perceived by a computer. The user does
+ not care about keeping the wall clock in sync with the correct
+ time. The user expects your program to have unlimited 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>
+ they realize that the wall clock time on their workstation is off by
+ a minute. Then they set it to the correct time, but 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
+ <p>The number of problems that arise when you always expect the wall clock
+ time on the system to be correct can be immense. Erlang therefore
introduced the "corrected estimate of time", or the "time
- correction" many years ago. The time correction relies on the fact
+ 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>
+ either a real-time extension or some built-in "tick counter" that is
+ independent of the wall clock settings. This counter can have
+ microsecond resolution or much less, but it has a drift that cannot
+ be ignored.</p>
+ </section>
<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>
+ <marker id="Time_Correction"/>
+ <title>Time Correction</title>
+ <p>If time correction is enabled, the Erlang runtime system
+ makes use of both
+ <seealso marker="#OS_System_Time">OS system time</seealso>
+ and <seealso marker="#OS_Monotonic_Time">OS monotonic time</seealso>,
+ to adjust the frequency of the Erlang
+ monotonic clock. Time correction ensures that
+ <seealso marker="#Erlang_Monotonic_Time">Erlang monotonic time</seealso>
+ does not warp and that the frequency is relatively accurate.
+ The type of frequency adjustments depends on the time warp mode used.
+ Section <seealso marker="#Time_Warp_Modes">Time Warp Modes</seealso>
+ provides more details.</p>
+
+ <p>By default time correction is enabled if support for
+ it exists on the specific platform. Support for it includes
+ both OS monotonic time, provided by the OS, and an
+ implementation in the Erlang runtime system using
+ OS monotonic time. To check if your system has support
+ for OS monotonic time, call
+ <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>.
+ To check if time correction is enabled on your system, call
+ <seealso marker="erlang#system_info_time_correction"><c>erlang:system_info(time_correction)</c></seealso>.</p>
+
+ <p>To enable or disable time correction, pass command-line argument
+ <seealso marker="erl#+c"><c>+c [true|false]</c></seealso>
+ to <c>erl</c>.</p>
+
+ <p>If time correction is disabled, Erlang monotonic time
+ may warp forwards or stop, or even freeze for extended
+ periods of time. There are then 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 a performance penalty was associated with time
+ correction, but nowadays it is usually the other way around.
+ If time correction is disabled, you probably get bad scalability,
+ bad performance, and bad time measurements.</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>
+ <marker id="Time_Warp_Safe_Code"/>
+ <title>Time Warp Safe Code</title>
+ <p>Time warp safe code can 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 bad when Erlang system time warps. When Erlang
+ system time does a time warp backwards, the values returned
+ from <c>erlang:now/0</c> freeze (if you disregard the
+ microsecond increments made because of the actual call) until
+ OS system time reaches the point of the last value returned by
+ <c>erlang:now/0</c>. This freeze can continue for a long time. It
+ can take years, decades, and even longer 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
+ is 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 use of it with other functionality. For examples
+ of how to replace the use of <c>erlang:now/0</c>, see Section
+ <seealso marker="#Dos_and_Donts">How to Work with the New
+ API</seealso>.</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>
+ <title>Time Warp Modes</title>
+ <marker id="Time_Warp_Modes"/>
+ <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.</p>
+
+ <p>To set the time warp mode, pass command-line argument
+ <seealso marker="erl#+C_"><c>+C
+ [no_time_warp|single_time_warp|multi_time_warp]</c></seealso>
+ 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 does not change later. This is the default behavior, but
+ not because it is the best mode (which it is not). It is
+ default <em>only</em> because this is how the runtime system
+ behaved until <c>ERTS</c> 7.0.
+ Ensure that your Erlang code that may execute during a time
+ warp is <seealso marker="#Time_Warp_Safe_Code">time warp
+ safe</seealso> before enabling other modes.</p>
+
+ <p>As the time offset is not allowed to change, time
+ correction must adjust the frequency of the Erlang
+ monotonic clock to align Erlang system time with OS
+ system time smoothly. A significant 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 can be as large as 1%. This error will show up in all
+ time measurements in the runtime system.</p>
+
+ <p>If time correction is not enabled, Erlang monotonic
+ time freezes when OS system time leaps backwards.
+ The freeze of monotonic time continues until
+ OS system time catches up. The freeze can continue for
+ a long time. When OS system time leaps forwards,
+ Erlang monotonic time also leaps 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, not even a battery, when it is
+ shut off. The system clock on such a system is typically
+ way off when the system boots. If
+ <seealso marker="#No_Time_Warp_Mode">no time warp mode</seealso>
+ is used, and the Erlang runtime system is started before
+ OS system time has been corrected, Erlang system time
+ can be wrong for a long time, centuries or even longer.</p>
+
+ <p>If you 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 OS
+ system time has been corrected, you may want to use the single
+ time warp mode.</p>
+
+ <note><p>There are limitations to when you can
+ execute time warp unsafe code using this mode. If it is possible
+ to use time warp safe code only, it is <em>much</em> better
+ to use the <seealso marker="#Multi_Time_Warp_Mode">multi-time
+ warp mode</seealso> instead.</p></note>
+
+ <p>Using the single time warp mode, the time offset is
+ handled in two phases:</p>
+
+ <taglist>
+ <tag>Preliminary Phase</tag>
+ <item>
+ <p>This phase starts when the runtime
+ system starts. A preliminary time offset based on
+ current OS system time is determined. This offset is from
+ now on to be fixed during the whole preliminary phase.</p>
+
+ <p>If time correction is enabled, adjustments to the
+ Erlang monotonic clock are made to keep its
+ frequency as correct as possible. However, <em>no</em>
+ adjustments are made trying to align Erlang system
+ time and OS system time. That is, during the preliminary phase
+ Erlang system time and OS system time can diverge
+ from each other, and no attempt is made to prevent this.</p>
+
+ <p>If time correction is disabled, changes in OS system
+ time affects 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>This phase begins when the user finalizes 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 aligns with
+ current OS system time. As the time offset can
+ change during the finalization, Erlang system time
+ can do a time warp at this point. The time offset is
+ from now on fixed until the runtime system terminates.
+ If time correction has been enabled, the time
+ correction from now on also makes adjustments
+ 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, the user must ensure
+ that the following two requirements 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 must ensure that OS
+ system time is set to a time earlier or equal to actual
+ POSIX time before starting the Erlang runtime system.</p>
+
+ <p>If you are not sure that 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>OS system time must be correct when
+ 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 these requirements are fulfilled,
+ time correction is enabled, and that OS system time
+ is adjusted using a time adjustment protocol such as NTP,
+ only small adjustments of Erlang monotonic
+ time are needed to keep system times
+ aligned after finalization. As long as the system is not
+ suspended, the largest adjustments needed are for
+ inserted (or deleted) leap seconds.</p>
+
+ <warning><p>To use this mode, 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 executing only 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 as
+ the Erlang runtime system have better performance, scale
+ better, and behave better on almost all platforms. In
+ addition, the accuracy and precision of time measurements
+ are better. Only Erlang runtime systems executing on
+ ancient platforms 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. As we align
+ Erlang system time with 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 makes time measurements using
+ Erlang monotonic time more accurate and precise.</p>
+
+ <p>If time correction is disabled, Erlang monotonic time
+ leaps forward if OS system time leaps forward. If
+ OS system time leaps backwards, Erlang monotonic time
+ stops briefly, but it does not freeze for extended periods
+ of time. This as the time offset is changed to
+ align Erlang system time with OS system time.</p>
+
+ <warning><p>To use this mode, 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>
+
<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>
+ <title>New Time API</title>
+ <marker id="The_New_Time_API"/>
+ <p>The old time API is based on
+ <seealso marker="erlang#now/0"><c>erlang:now/0</c></seealso>.
+ <c>erlang:now/0</c> was intended to be used for many unrelated
+ things. This tied these unrelated operations together and
+ caused issues with performance, scalability, accuracy, and
+ precision for operations that did not need to have
+ such issues. To improve this, the new API spreads different
+ functionality over multiple functions.</p>
+
+ <p>To be backwards compatible, <c>erlang:now/0</c>
+ remains as is, but <em>you are strongly discouraged from using
+ it</em>. Many use cases of <c>erlang:now/0</c>
+ prevents 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 runtime
+ system. This is not a bug, but a memory use optimization.</p>
+
+ <p>The new API consists of the following 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>The new API also consists of extensions of the following 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>New Erlang Monotonic Time</title>
+ <p>Erlang monotonic time as such is new as of <c>ERTS</c> 7.0.
+ It is introduced to detach time measurements, such as elapsed
+ time from calendar time. In many use cases there is a need to
+ measure elapsed time or specify a time relative to another point
+ in time without the need to know the involved times in UTC or
+ any other globally defined time scale. By introducing a time
+ scale with a local definition of where it starts, time that do
+ not concern calendar time can be managed on that time
+ scale. Erlang monotonic time uses such a time scale with a
+ locally defined start.</p>
+
+ <p>The introduction of Erlang monotonic time allows
+ us to adjust the two Erlang times (Erlang
+ monotonic time and Erlang system time) separately. By
+ doing this, the 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 for backwards
+ compatibility reasons. When using these modes, the
+ accuracy of Erlang monotonic time suffer, as
+ the adjustments of Erlang monotonic time in these
+ modes are more or less tied to 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. As we can
+ express and measure time that is not connected to
+ calendar time by the use of Erlang monotonic time, it
+ is better to expose the change in Erlang system time
+ immediately. This as the Erlang applications
+ executing on the system can react on the change in
+ system time as soon as possible. This is also more or
+ less exactly how most operating systems 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>To be able to react to a change in Erlang
+ system time, you must 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 is 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
+ produces unique and strictly monotonically increasing
+ values. 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>How to Work with the New API</title>
+ <p>Previously <c>erlang:now/0</c> was the only option for doing
+ many things. This section deals with some things that
+ <c>erlang:now/0</c> can be used for, and how you are to
+ these 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> to retrieve current Erlang system time.
+ </p>
+ </dont>
+ <do>
+ <p>
+ Use
+ <seealso marker="erlang#system_time/1"><c>erlang:system_time/1</c></seealso>
+ 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 use
+ <seealso marker="erlang#convert_time_unit/3"><c>erlang:convert_time_unit/3</c></seealso>.
+ </p>
+
+ <p>An easier way to do this is to use
+ <seealso marker="erlang#monotonic_time/1"><c>erlang:monotonic_time/1</c></seealso>
+ with the desired time unit. However, you can then lose accuracy
+ and precision.
+ </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 occurs.
+ </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 occurs. 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 occurs.
+ </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> as follows:</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 current runtime system instance according to
+ creation time. 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 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
+ can change, and you want 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>
+ 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>
+ 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 up this section: <em>Do not use <c>erlang:now/0</c>.</em></p>
+ </section>
</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>
+ <marker id="Supporting_Both_New_and_Old_OTP_Releases"/>
+ <title>Support of Both New and Old OTP Releases</title>
+ <p>It can be required that your code must run on a variety
+ of OTP installations of different OTP releases. If so, you
+ cannot use the new API out of the box, as it will
+ not be available on old pre OTP 18 releases. The solution
+ is <em>not</em> to avoid using the new API, as your
+ code then would not benefit from the scalability
+ and accuracy improvements made. Instead, use the
+ new API when available, and fall back on <c>erlang:now/0</c>
+ when the new API is unavailable.</p>
+
+ <p>Fortunately most of the new API can easily be
+ implemented using existing primitives, except for:</p>
+
+ <list type="bulleted">
+ <item>
+ <seealso marker="erlang#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso>
+ </item>
+ <item>
+ <seealso marker="erlang#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso>
+ </item>
+ <item>
+ <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>
+ </item>
+ <item>
+ <seealso marker="erlang#system_info_os_system_time_source"><c>erlang:system_info(os_system_time_source)</c></seealso>)
+ </item>
+ </list>
+
+ <p>By wrapping the API with functions that fall back on
+ <c>erlang:now/0</c> when the new API is unavailable,
+ 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">$ERL_TOP/erts/example/time_compat.erl</url>.</p>
</section>
</chapter>
-