On Linux, the time stamp of a file is a little past.

(The execution environment of the following text is ubuntu 18.04. The source code refers to the upstream version of git which is the same version as the ubuntu 18.04 package for linking.)

Trigger

If you look at the timestamp after updating the file, it may be slightly past.

$ date +%H:%M:%S.%N ; touch file ; date +%H:%M:%S.%N ; stat --printf="%y\n" file
XX:46:44.546008239			← 1
XX:46:44.550890822			← 2
20XX-XX-XX XX:46:44.543994035 +0900	← 3

Since you are touching the file between 1 and 2, timestamp 3 must be the time between 1 and 2, but if you look closely, 3 is about 2ms before 1.

Examine date (1) and touch (1)

The date command does not issue a system call to get the time even if strace is applied. This is because the time is calculated without calling the kernel by a mechanism called vsyscall, so it can be considered that the system call clock_gettime (2) is actually used. Source code of date commandThan,

              /* Prepare to print the current date/time.  */
              gettime (&when);

gettime () is [defined] in gnulib (GNU Portability Library) (http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob;f=lib/gettime .c; h = 4ae313e78ea5b90475fa7ab1fd0c2479a3410d09; hb = a20922f10).

void
gettime (struct timespec *ts)
{
#if HAVE_NANOTIME
  nanotime (ts);
#else

# if defined CLOCK_REALTIME && HAVE_CLOCK_GETTIME
  if (clock_gettime (CLOCK_REALTIME, ts) == 0)
    return;
# endif

  {
    struct timeval tv;
    gettimeofday (&tv, NULL);
    ts->tv_sec = tv.tv_sec;
    ts->tv_nsec = tv.tv_usec * 1000;
  }

#endif
}

With #if, the middle clock_gettime line is adopted.

On the other hand, touch can take strace normally.

$ strace touch file
...
openat(AT_FDCWD, "file", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = 3
dup2(3, 0)                              = 0
close(3)                                = 0
utimensat(0, NULL, NULL, 0)             = 0
close(0)                                = 0
...

I am using a system call called ʻutimensat (2)`.

Examine the kernel

ʻUtimensat (2)is [defined] in the filefs / utimes.c` (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git /tree/fs/utimes.c?h=v4.15&id=d8a5b80568a9cb66810e75b182018e9edb68e8ff#n168).

SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename,
		struct timespec __user *, utimes, int, flags)
{
Abbreviation
}

From now on, from do_utimes () → ʻutimes_common () , notify_change () `in fs / attr.c is [called](https://git.kernel.org/pub/scm/linux/kernel/ git / torvalds / linux.git/tree/fs/attr.c?h=v4.15&id=d8a5b80568a9cb66810e75b182018e9edb68e8ff#n205).

When setting to the current timeattr->ia_validIsATTR_CTIME | ATTR_MTIME | ATTR_ATIME | ATTR_TOUCHIt has become.notify_change()Isファイルの各種属性の変更をする関数だが、属性変更時はctime、mtime、atimeを現在時刻に変更する普通であるので、そのような処理It has become.

The current time is [obtained] by a function called current_time () (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/attr) .c? h = v4.15 & id = d8a5b80568a9cb66810e75b182018e9edb68e8ff # n242).

current_time () is defined in fs / inode.c and [does](https: //) rounds the result of current_kernel_time () to filesystem dependent timestamp precision. git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/inode.c?h=v4.15&id=d8a5b80568a9cb66810e75b182018e9edb68e8ff#n2116). In ext4, the time stamp can be retained in ns units, so it will not be rounded here.

current_kernel_time () goes through some wrapper functions and finally the following functions /tree/kernel/time/timekeeping.c?h=v4.15&id=d8a5b80568a9cb66810e75b182018e9edb68e8ff#n2190).

struct timespec64 current_kernel_time64(void)
{
	struct timekeeper *tk = &tk_core.timekeeper;
	struct timespec64 now;
	unsigned long seq;

	do {
		seq = read_seqcount_begin(&tk_core.seq);

		now = tk_xtime(tk);
	} while (read_seqcount_retry(&tk_core.seq, seq));

	return now;
}

Expanding the inline function tk_xtime ()

struct timespec64 current_kernel_time64(void)
{
	struct timekeeper *tk = &tk_core.timekeeper;
	struct timespec64 now;
	unsigned long seq;

	do {
		seq = read_seqcount_begin(&tk_core.seq);

		now.tv_sec = tk->xtime_sec;
		now.tv_nsec = (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift);
	} while (read_seqcount_retry(&tk_core.seq, seq));

	return now;
}

The loop of read_seqcount_begin () ~ read_seqcount_retry () is a kind of cliché to prevent you from catching half-finished data during the update.

Next, for clock_gettime (), [kernel / time / posix-stubs.c](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ It is located at tree / kernel / time / posix-stubs.c? H = v4.15 & id = d8a5b80568a9cb66810e75b182018e9edb68e8ff # n82). This is finally The following [__getnstimeofday64](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/time/timekeeping.c?h=v4.15&id=d8a5b80568a9cb66810e75b182018e9edb68e8ff# Come to n713).

int __getnstimeofday64(struct timespec64 *ts)
{
	struct timekeeper *tk = &tk_core.timekeeper;
	unsigned long seq;
	u64 nsecs;

	do {
		seq = read_seqcount_begin(&tk_core.seq);

		ts->tv_sec = tk->xtime_sec;
		nsecs = timekeeping_get_ns(&tk->tkr_mono);

	} while (read_seqcount_retry(&tk_core.seq, seq));

	ts->tv_nsec = 0;
	timespec64_add_ns(ts, nsecs);

	/*
	 * Do not bail out early, in case there were callers still using
	 * the value, even in the face of the WARN_ON.
	 */
	if (unlikely(timekeeping_suspended))
		return -EAGAIN;
	return 0;
}

Comparing the two, you can see that there is a difference in the tv_nsec part. While the touch command ʻutimensat ()processes the variabletk-> tkr_mono.xtime_nsec, the date command clock_gettime (CLOCK_REALTIME) uses the result of timekeeping_get_ns () and overflows. If so, I am doing something like modifying tv_sec. When you call timekeeping_get_ns ()`, you are calling clocksource.

The essential difference is

Timestamp is variable only. The clocksource (hardware) call is used to get the time. This is the essential difference.

The variables referenced when changing the timestamp are updated with a tick, that is, (in principle) a scheduled process every 1 second of HZ. Therefore, the time stamp is a tick unit, and since HZ = 250 in ubuntu 18.04 generic, it represents the past time up to 1/250 second = 4 milliseconds. Since it does not access the hardware, the time can be obtained at high speed on any architecture.

When getting the current time with the date command, in addition to this variable, refer to the clocksource hardware (usually CPU TSC: time stamp counter on current x86).

TSC happens to be fast accessible, but clocksources from other architectures are not always fast accessible, so every time a file is updated, which is thought to be done more often than getting the current time with a date command etc. It is not rational to access the clocksource.

CLOCK_REALTIME_COARSE

Actually, you can also get this time, clock_gettime (2), which is used when changing the time stamp. At this time, specify CLOCK_REALTIME_COARSE as the first argument.

Call CLOCK_REALTIME and CLOCK_REALTIME_COARSE alternately, that is,

	clock_gettime(CLOCK_REALTIME, &ts1);
	clock_gettime(CLOCK_REALTIME_COARSE, &ts2);
	clock_gettime(CLOCK_REALTIME, &ts3);
	clock_gettime(CLOCK_REALTIME_COARSE, &ts4);

When you do, ts2 and ts4 have the same value with a relatively high probability, but ts1, ts2, and ts3 do not have the same value (at least as long as the clock source is tsc).

Recommended Posts

On Linux, the time stamp of a file is a little past.
I measured the run queue wait time of a process on Linux
Zip 4 Gbyte problem is a story of the past
#The command to check the encoding of a text file (ISO-2022-JP, Shift_JIS, EUC-JP, UTF-8 or UTF-16) on Linux is nkf --guess (forget every time)
Build a Selenium environment on Amazon Linux 2 in the shortest time
How to output the output result of the Linux man command to a file
A quick overview of the Linux kernel
Rename based on file modification time (Linux)
[python] [meta] Is the type of python a type?
Randomly play the movie on ChromeCast for a certain period of time
What is the XX file at the root of a popular Python project?
[Linux] Command to get a list of commands executed in the past
[Java] [Linux] Investigating how the implementation of Java child processes on Linux is realized
View the full path (absolute path) of a file in a directory in Linux Bash
A note about the functions of the Linux standard library that handles time
Find out where the java entity is on Linux (CentOS this time)
The origin of Manjaro Linux is "Mount Kilimanjaro"
[2020July] Check the UDID of the iPad on Linux
Calculate the probability of outliers on a boxplot
It's a Mac. What is the Linux command Linux?
The .pyd file is the DLL itself on Windows
At the time of python update on ubuntu
I did a little research on the class
[Linux] Difference in time information depending on the clock ID of the clock_gettime () function
How to access the contents of a Linux disk on a Mac (but read-only)
A record of the time it took to deploy mysql on Cloud9 + Rails
When a file is placed in the shared folder of Raspberry Pi, the process is executed.
Specify the volume on linux and make a sound
Create a QR code for the URL on Linux
Make your cursor a photo of your choice on Linux
Check if the LAN cable is disconnected on Linux
The Linux emulator "iSH" that runs on the iPad is a hot topic in me
A Study on Visualization of the Scope of Prediction Models
What is a recommend engine? Summary of the types
Unzip a ZIP file larger than 4GB on Linux.
Output the output result of sklearn.metrics.classification_report as a CSV file
Creating a list when the nomenclature is a fixed time
Create a shape on the trajectory of an object
Announcing the availability of Java 11 LTS on Amazon Linux 2
I thought a little because the Trace Plot of the stan parameter is hard to see.
How to display a specified line of a file or command result on Linux (sed, awk)
Make a Linux version of OpenSiv3D with find_package a little easier
Put the latest version of Python on linux (Debian) on Chromebook
A note on the default behavior of collate_fn in PyTorch
I just changed the sample source of Python a little.
Let's execute the command on time with the bot of discord
[Note] Import of a file in the parent directory in Python
A rough summary of the differences between Windows and Linux
I tried a little bit of the behavior of the zip function
Install the latest version of Git on your Linux server
Is there a secret to the frequency of pi numbers?
Get the host name of the host PC with Docker on Linux
What is the Linux kernel?
Install the JDK on Linux
A brief summary of Linux
Paste the link on linux
The image is a slug
I will publish a shell script created to reduce the trouble of creating LiveUSB on Linux
The story of releasing a Python text check tool on GitHub x CircleCI for the first time
A story that is a little addicted to the authority of the directory specified by expdp (for beginners)
It is surprisingly troublesome to get a list of the last login date and time of Workspaces