diff options
author | Sverker Eriksson <[email protected]> | 2017-08-30 20:55:08 +0200 |
---|---|---|
committer | Sverker Eriksson <[email protected]> | 2017-08-30 20:55:08 +0200 |
commit | 7c67bbddb53c364086f66260701bc54a61c9659c (patch) | |
tree | 92ab0d4b91d5e2f6e7a3f9d61ea25089e8a71fe0 /erts/doc/src/time_correction.xml | |
parent | 97dc5e7f396129222419811c173edc7fa767b0f8 (diff) | |
parent | 3b7a6ffddc819bf305353a593904cea9e932e7dc (diff) | |
download | otp-7c67bbddb53c364086f66260701bc54a61c9659c.tar.gz otp-7c67bbddb53c364086f66260701bc54a61c9659c.tar.bz2 otp-7c67bbddb53c364086f66260701bc54a61c9659c.zip |
Merge tag 'OTP-19.0' into sverker/19/binary_to_atom-utf8-crash/ERL-474/OTP-14590
Diffstat (limited to 'erts/doc/src/time_correction.xml')
-rw-r--r-- | erts/doc/src/time_correction.xml | 902 |
1 files changed, 902 insertions, 0 deletions
diff --git a/erts/doc/src/time_correction.xml b/erts/doc/src/time_correction.xml new file mode 100644 index 0000000000..236fe679cb --- /dev/null +++ b/erts/doc/src/time_correction.xml @@ -0,0 +1,902 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1999</year><year>2015</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 (<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 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>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. 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 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>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 off by + a minute. Then they set it to the correct time, but most probably + not in a smooth way.</p> + + <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 + 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 can have + microsecond resolution or much less, but it has a drift that cannot + be ignored.</p> + </section> + + <section> + <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> + <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>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>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> + <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> |