[RUBY] The story around the time acquisition API in programming languages

Synopsis: When I was investigating the handling of the argument of clock_gettime (2) in each language, I found such a strange sentence. Because of that, there is no description related to Windows. I may add it later.

clock_gettime

clock_gettime (2) is an API for time acquisition standardized by the Single Unix Specification v2. For clock_gettime (2), the semantics and precision of time acquisition change depending on the constant passed to clock_id.

To quote an example from a Linux man,

- CLOCK_REALTIME
A system-wide unique time that measures real time. Appropriate privileges are required to set this clock. This clock is a discontinuous change in system time(For example, if the system administrator manually changes the system time.)It is affected by the gradual adjustments made by, adjtime, and NTP.
CLOCK_REALTIME_COARSE (Linux 2.6.32 or later;Linux specific)
Fast but low accuracy CLOCK_REAL TIME. It is recommended to use when speed is very necessary and high-precision time stamp is not required.
CLOCK_MONOTONIC
A clock that cannot be set and is represented by a monotonically increasing time from a certain start point.(It is not specified when the start time will be).. This clock has discontinuous changes in system time(For example, if the system administrator manually changes the system time.)Not affected by, but adjtime(3)And are affected by the gradual adjustments made by NTP.
CLOCK_MONOTONIC_COARSE (Linux 2.6.32 or later;Linux specific)
Fast but low accuracy CLOCK_MONOTONIC. It is recommended to use when speed is very necessary and high-precision time stamp is not required.
CLOCK_MONOTONIC_RAW (Linux 2.6.28 or later;Linux specific)
CLOCK_Similar to MONOTONIC, but with NTP adjustments and adjtime(3)Provides hardware access to the raw time, unaffected by the gradual adjustments made by.
CLOCK_BOOTTIME (Linux 2.6.39 or later;Linux specific)
CLOCK_Same as MONOTONIC, except that it includes the time the system is suspended. With it, the application can also handle suspended states"monotonic"Clock can be obtained. Moreover, CLOCK_There is no need to perform complicated processing in REALTIME. CLOCK_In REALTIME, settimeofday(2)This is because if you change the time using, the time will change discontinuously.

a. This constant varies depending on the OS. Others, like sierra, have added a special API called clock_gettime_nsec_np.

In this blog, the quoted part of the implementation was helpful. http://d.hatena.ne.jp/yohei-a/20140913/1410628229

Ruby

Process.clock_gettime

Ruby provides an API that calls clock_gettime (2) directly. Specify clock_id as an argument of Process.clock_gettime.

According to process.c, the following constants can be specified. It also describes which version was added properly, which is very wonderful. There was no specification for CLOCK_HIGHRES on Solaris. Also, Dragonfly BSD should be able to use the same options as FreeBSD, at least in the latest version, but wasn't mentioned.

 *  [CLOCK_REALTIME] SUSv2 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1, macOS 10.12
 *  [CLOCK_MONOTONIC] SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12
 *  [CLOCK_PROCESS_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, OpenBSD 5.4, macOS 10.12
 *  [CLOCK_THREAD_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12
 *  [CLOCK_VIRTUAL] FreeBSD 3.0, OpenBSD 2.1
 *  [CLOCK_PROF] FreeBSD 3.0, OpenBSD 2.1
 *  [CLOCK_REALTIME_FAST] FreeBSD 8.1
 *  [CLOCK_REALTIME_PRECISE] FreeBSD 8.1
 *  [CLOCK_REALTIME_COARSE] Linux 2.6.32
 *  [CLOCK_REALTIME_ALARM] Linux 3.0
 *  [CLOCK_MONOTONIC_FAST] FreeBSD 8.1
 *  [CLOCK_MONOTONIC_PRECISE] FreeBSD 8.1
 *  [CLOCK_MONOTONIC_COARSE] Linux 2.6.32
 *  [CLOCK_MONOTONIC_RAW] Linux 2.6.28, macOS 10.12
 *  [CLOCK_MONOTONIC_RAW_APPROX] macOS 10.12
 *  [CLOCK_BOOTTIME] Linux 2.6.39
 *  [CLOCK_BOOTTIME_ALARM] Linux 3.0
 *  [CLOCK_UPTIME] FreeBSD 7.0, OpenBSD 5.5
 *  [CLOCK_UPTIME_FAST] FreeBSD 8.1
 *  [CLOCK_UPTIME_RAW] macOS 10.12
 *  [CLOCK_UPTIME_RAW_APPROX] macOS 10.12
 *  [CLOCK_UPTIME_PRECISE] FreeBSD 8.1
 *  [CLOCK_SECOND] FreeBSD 8.1

Time.now

The most commonly used current time, which is called Time.now or Time # initialize, is fixed to CLOCK_REALTIME if clock_gettime is defined. If not, I'm using gettimeofday (macOS, etc.).

Although it is not written in Document, if clock_gettime / gettimeofday fails internally, rb_sys_fail Throw an exception with .

Python3 (3.3 or later)

time.clock_gettime

In Python 3.3 and later, you can call clock_gettime (2) directly with time.clock_gettime (clock_id) like Ruby. However, what can be passed to clock_id is and documented, and apparently constants such as CLOCK_MONOTONIC_COARSE cannot be passed (as of 3.6.0). In the first place, Python doesn't seem to provide an API that uses CLOCK_MONOTONIC_COARSE internally or passes it from the outside.

Looking at pytime.c, the pymonotonic function is fixed to CLOCK_MONOTONIC, and the pygettimeofday function is used to fix CLOCK_REALTIME. In pymonotonic, mach_absolute_time is passed for macOS and CLOCK_HIGHRES is passed for Solaris.

time.time

The most commonly used time.time () internally calls the pygetimeofday function, which is equivalent totime.clock_gettime (CLOCK_REALTIME). Like Time.now in Ruby, gettimeofday (2) is used as the fallback destination.

If the system call call fails, it returns NULL internally, but I'm not sure.

pep418

This is the clock-based proposal PEP newly added to the time module in Python 3.3 https://www.python.org/dev/peps/pep-0418/

Perl5

Is it attached to the main body? The Time :: HiRes module that is doing seems to be the de facto.

clock_gettime

You can pass CLOCK_MONOTONIC or CLOCK_REALTIME to clock_gettime. Like Ruby and Python, clock_gettime does not grow if it is not defined on the OS side, so there is no mechanism to fall back to gettimofday (2). At the moment, it does not support the API newly created in the latest macOS Sierra, but FreeBSD's CLOCK_MONOTONIC_FAST etc. are defined as constants.

time

The time function internally calls gettimeofday (2). It seems to return -1.0 if the call to gettimeofday (2) fails. When I wondered what this meant, I wondered if the failure status of the system call was expressed as a float. There are no direct sum types, direct product types, or exceptions in Perl, so it would be better to express the return values in a mixed manner.

It became annoying, so it became messy.

C++

Look at std :: chrono (libstdc ++-v3 / src / c ++ 11 / chrono.cc) in STL.

std::chrono::system_clock::now

  1. Use CLOCK_REALTIME if you have clock_gettime (2)
  2. If not, use gettimeofday (2)
  3. If not, use time (2)

std::chrono::steady_clock::now

  1. Use CLOCK_MONOTONIC if you have clock_gettime (2)
  2. If not, use std :: chrono :: system_clock to find the difference

It has become.

Go

Many platforms (Linux, FreeBSD, OpenBSD) use CLOCK_REALTIME to implement now and CLOCK_MONOTONIC to implement nanotime for each architecture. For NetBSD and Solaris, CLOCK_REALTIME is also used to implement nanotime, but I'm not sure. I'm not sure about Plan9.

The situation is complicated on macOS, probably because it is a statically linked binary. But I'm not sure. Keep only the URL that was referenced. https://opensource.apple.com/source/xnu/xnu-1699.26.8/osfmk/i386/cpu_capabilities.h

FreeBSD says that you can use CLOCK_MONOTONIC_FAST if you turn off 8-STABLE support, but Linux does not say that you can use CLOCK_MONOTONIC_COARSE if you turn off support before 2.6.32.

// func now() (sec int64, nsec int32)
TEXT time·now(SB), NOSPLIT, $32
	MOVL	$232, AX // clock_gettime
	MOVQ	$0, DI		// CLOCK_REALTIME
	LEAQ	8(SP), SI
	SYSCALL
	MOVQ	8(SP), AX	// sec
	MOVQ	16(SP), DX	// nsec

	// sec is in AX, nsec in DX
	MOVQ	AX, sec+0(FP)
	MOVL	DX, nsec+8(FP)
	RET

TEXT runtime·nanotime(SB), NOSPLIT, $32
	MOVL	$232, AX
	// We can use CLOCK_MONOTONIC_FAST here when we drop
	// support for FreeBSD 8-STABLE.
	MOVQ	$4, DI		// CLOCK_MONOTONIC
	LEAQ	8(SP), SI
	SYSCALL
	MOVQ	8(SP), AX	// sec
	MOVQ	16(SP), DX	// nsec

	// sec is in AX, nsec in DX
	// return nsec in AX
	IMULQ	$1000000000, AX
	ADDQ	DX, AX
	MOVQ	AX, ret+0(FP)
	RET

Rust

In the standard library std :: time, ʻInstant :: now is fixed to CLOCK_MONOTONICandSystemTime :: now is fixed to CLOCK_REALTIMEon many platforms. For macOS, we usemach_absolute_time / gettimeofdayrespectively. From the comments in the Ruby source,CLOCK_MONOTONIC` should work fine on Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4 (and for some unknown reason, the recent Dragonfly BSD). Panic if system call call fails.

Instant::now

SystemTime::now

rust-coarsetime crate

If you want speed over accuracy, you can use rust-coarsetime. rust-coarsetime uses CLOCK_MONOTONIC_COARSE / CLOCK_MONOTONIC_RAW_APPROX / CLOCK_MONOTONIC_FAST on Linux / OSX / FreeBSD (DragonflyBSD) respectively.

D language

There is Clock.currTime / Clock.currStdTime in std.datetime of the standard library Phobos as API of time acquisition, and ClockType can be specified. Both internally call the currStdTime function. Throws a TimeException exception if the system call call fails.

The implementation of currStdTime by specifying ClockType for each OS is summarized in the table below. OSs that don't have Sierra's new API support or aren't on the branch here (eg OpenBSD) die as Unsupported OS at compile time.

Here, time (2) / gettimeofday (2) each represent a system call, and the constant-like one is the constant passed to the argument of clock_gettime (2).

Recommended Posts

The story around the time acquisition API in programming languages
10 Most Popular Programming Languages in 2020
The popularity of programming languages
Programming to fight in the world ~ 5-1
Programming to fight in the world 5-3
Getting the arXiv API in Python
Activity record in the programming circle
The story of participating in AtCoder
Programming to fight in the world-Chapter 4
The story of the "hole" in the file
Access the Twitter API in Python
Code tests around time in Python
Programming to fight in the world ~ 5-2
If you are a beginner in programming, why not make a "game" for the time being? The story
Trends in programming languages from the perspective of GitHub (updated semi-annual changes)
The most sought after programming language in 2020
Try using the Wunderlist API in Python
The story of an error in PyOCR
Try using the Kraken API in Python
Tweet using the Twitter API in Python
MongoDB for the first time in Python
RICOH THETA S API in several languages.
Draw graphs in the programming language Julia
Try hitting the YouTube API in Python
Try hitting the Spotify API in Django.
Write classes (or class-like) in various programming languages
Try using the BitFlyer Ligntning API in Python
Transition animation of the most popular programming languages (#programming languages #popular)
I tried python programming for the first time.
Tips for hitting the ATND API in Python
The story of finding the optimal n in N fist
The story of reading HSPICE data in Python
Loop variables at the same time in the template
The story of viewing media files in Django
Hit the Firebase Dynamic Links API in Python
Try using the DropBox Core API in Python
The story that fits in with pip installation