Unter Linux ist der Zeitstempel einer Datei etwas vorbei.

(Die Ausführungsumgebung des folgenden Textes ist Ubuntu 18.04. Der Quellcode bezieht sich zum Verknüpfen auf die Upstream-Version von git, die dieselbe Version wie das Ubuntu 18.04-Paket ist.)

Auslösen

Wenn Sie sich die Zeitstempel nach dem Aktualisieren der Datei ansehen, ist sie möglicherweise etwas vergangen.

$ 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

Da Sie die Datei zwischen 1 und 2 berühren, muss der Zeitstempel 3 eine Zeit zwischen 1 und 2 sein. Wenn Sie jedoch genau hinschauen, liegt 3 etwa 2 ms vor 1.

Untersuche Datum (1) und berühre (1)

Der Befehl date gibt keinen Systemaufruf aus, um die Uhrzeit abzurufen, selbst wenn strace angewendet wird. Dies liegt daran, dass die Zeit berechnet wird, ohne den Kernel durch einen Mechanismus namens vsyscall aufzurufen. Daher kann davon ausgegangen werden, dass der Systemaufruf "clock_gettime (2)" tatsächlich verwendet wird. Befehl für den Quellcode des DatumsAls,

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

gettime () ist [definiert] 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
}

In # if wird die mittlere clock_gettime Zeile übernommen.

Auf der anderen Seite kann die Berührung normal sein.

$ 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
...

Ich verwende einen Systemaufruf namens "utimensat (2)".

Untersuche den Kernel

utimensat (2) ist [definiert] in einer Datei namens fs / 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)
{
Abkürzung
}

Von nun an wird ab do_utimes ()utimes_common () notify_change () in fs / attr.c aufgerufen. git / torvalds / linux.git / tree / fs / attr.c? h = v4.15 & id = d8a5b80568a9cb66810e75b182018e9edb68e8ff # n205).

Bei Einstellung auf die aktuelle Zeitattr->ia_validIstATTR_CTIME | ATTR_MTIME | ATTR_ATIME | ATTR_TOUCHEs ist geworden.notify_change()Istファイルの各種属性の変更をする関数だが、属性変更時はctime、mtime、atimeを現在時刻に変更する普通であるので、そのような処理Es ist geworden.

Die aktuelle Zeit wird durch die Funktion current_time () (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/attr] erhalten .c? h = v4.15 & id = d8a5b80568a9cb66810e75b182018e9edb68e8ff # n242).

current_time () ist in fs / inode.c und [does](https: //) definiert, um das Ergebnis von current_kernel_time () auf die dateisystemabhängige Zeitstempelgenauigkeit zu runden. git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/inode.c?h=v4.15&id=d8a5b80568a9cb66810e75b182018e9edb68e8ff#n2116). In ext4 kann der Zeitstempel in ns-Einheiten beibehalten werden, sodass er hier nicht gerundet wird.

current_kernel_time () durchläuft einige Wrapper-Funktionen und schließlich die folgenden Funktionen /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;
}

Erweiterung der Inline-Funktion 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;
}

Die Schleife von "read_seqcount_begin ()" zu "read_seqcount_retry ()" ist eine Art Klischee, um zu verhindern, dass Sie während des Updates halbfertige Daten abfangen.

Als nächstes für clock_gettime () [kernel / time / posix-stubs.c](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ tree / kernel / time / posix-stubs.c? h = v4.15 & id = d8a5b80568a9cb66810e75b182018e9edb68e8ff # n82). Das ist endlich Die folgenden [__getnstimeofday64](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/time/timekeeping.c?h=v4.15&id=d8a5b80568a9cb66810e75b182018e9 Komm zu 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;
}

Wenn Sie die beiden vergleichen, sehen Sie, dass es einen Unterschied im Teil tv_nsec gibt. Der Berührungsbefehl utimensat () verarbeitet die Variable tk-> tkr_mono.xtime_nsec, während der Datumsbefehlclock_gettime (CLOCK_REALTIME)das Ergebnis von timekeeping_get_ns () verwendet und überläuft. Wenn ja, mache ich so etwas wie das Ändern von tv_sec. Wenn Sie "timekeeping_get_ns ()" aufrufen, rufen Sie clocksource auf.

Der wesentliche Unterschied ist

Zeitstempel sind nur Variablen. Der Clocksource-Aufruf (Hardware-Aufruf) wird verwendet, um die Zeit abzurufen. Dies ist der wesentliche Unterschied.

Die Variablen, auf die beim Ändern des Zeitstempels verwiesen wird, werden mit einem Häkchen aktualisiert, dh (im Prinzip) einem geplanten Prozess alle 1 Sekunde von HZ. Daher ist der Zeitstempel eine Tick-Einheit, und da HZ = 250 in Ubuntu 18.04 generisch ist, repräsentiert er die vergangene Zeit bis zu 1/250 Sekunde = 4 Millisekunden. Da nicht auf die Hardware zugegriffen wird, kann die Zeit mit jeder Architektur mit hoher Geschwindigkeit abgerufen werden.

Wenn Sie die aktuelle Uhrzeit mit dem Datumsbefehl abrufen, beziehen Sie sich zusätzlich zu dieser Variablen auf die Hardware der Taktquelle (normalerweise CPU TSC: Zeitstempelzähler im aktuellen x86).

TSC ist zwar schnell zugänglich, aber Taktquellen von anderen Architekturen sind nicht immer schnell zugänglich. Daher wird jedes Mal, wenn eine Datei aktualisiert wird, davon ausgegangen, dass dies häufiger erfolgt als das Abrufen der aktuellen Uhrzeit mit einem Datumsbefehl usw. Es ist nicht rational, auf die Uhrenquelle zuzugreifen.

CLOCK_REALTIME_COARSE

Tatsächlich können Sie auch diese Zeit "clock_gettime (2)" abrufen, die beim Ändern des Zeitstempels verwendet wird. Geben Sie zu diesem Zeitpunkt CLOCK_REALTIME_COARSE als erstes Argument an.

Rufen Sie abwechselnd CLOCK_REALTIME und CLOCK_REALTIME_COARSE auf.

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

Wenn Sie dies tun, haben ts2 und ts4 mit relativ hoher Wahrscheinlichkeit denselben Wert, aber ts1, ts2 und ts3 haben niemals denselben Wert (zumindest solange die Taktquelle tsc ist).

Recommended Posts

Unter Linux ist der Zeitstempel einer Datei etwas vorbei.
Ich habe versucht, die Wartezeit der Ausführungswarteschlange eines Prozesses unter Linux zu messen
Zip 4 Gbyte Problem ist eine Geschichte der Vergangenheit
#Der Befehl zum Nachschlagen der Codierung der Textdatei (ISO-2022-JP, Shift_JIS, EUC-JP, UTF-8 oder UTF-16) unter Linux lautet nkf --guess (jedes Mal vergessen)
Erstellen Sie in kürzester Zeit eine Selenium-Umgebung unter Amazon Linux 2
So geben Sie das Ausgabeergebnis des Linux-Befehls man in eine Datei aus
Umbenennen basierend auf der Änderungszeit der Datei (Linux)
[Python] [Meta] Ist der Python-Typ ein Typ?
Was ist die XX-Datei im Stammverzeichnis eines beliebten Python-Projekts?
[Linux] Ein Befehl zum Abrufen einer Liste der in der Vergangenheit ausgeführten Befehle
[Java] [Linux] Untersuchen, wie die Implementierung von untergeordneten Java-Prozessen unter Linux realisiert wird
Zeigen Sie den vollständigen Pfad (absoluten Pfad) einer Datei in einem Verzeichnis in Linux Bash an
Ein Hinweis zu den Funktionen der Standard-Linux-Bibliothek, die sich mit Zeit befasst
Finden Sie heraus, wo sich die Java-Entität unter Linux befindet (diesmal CentOS).
Der Ursprung von Manjaro Linux ist "Mount Kirimanjaro"
[2020Juli] Überprüfen Sie die UDID des iPad unter Linux
Berechnen Sie die Wahrscheinlichkeit von Ausreißern auf den Box-Whiskern
Es ist ein Mac. Was ist der Linux-Befehl Linux?
Zum Zeitpunkt des Python-Updates mit Ubuntu
Ich habe ein wenig über die Klasse recherchiert
[Linux] Unterschied in den Zeitinformationen in Abhängigkeit von der Uhr-ID der Funktion clock_gettime ()
Wenn eine Datei im freigegebenen Ordner von Raspberry Pi abgelegt wird, wird der Vorgang ausgeführt.
Geben Sie die Lautstärke unter Linux an und spielen Sie den Sound ab
Erstellen Sie unter Linux einen QR-Code für die URL
Machen Sie Ihren Cursor unter Linux zu einem Foto Ihrer Wahl
Überprüfen Sie, ob das LAN-Kabel unter Linux nicht angeschlossen ist
Der Linux-Emulator "iSH", der auf dem iPad läuft, ist ein heißes Thema in mir
Eine Überlegung zur Visualisierung des Anwendungsbereichs des Vorhersagemodells
Was ist ein empfohlener Motor? Zusammenfassung der Typen
Entpacken Sie eine ZIP-Datei mit mehr als 4 GB unter Linux.
Geben Sie das Ausgabeergebnis von sklearn.metrics.classification_report als CSV-Datei aus
Erstellen einer Liste, wenn die Nomenklatur für einen bestimmten Zeitraum gültig ist
Ankündigung der Verfügbarkeit von Java 11 LTS unter Amazon Linux 2
Ich dachte ein wenig nach, weil Trace Plot von Stan's Parameter schwer zu sehen ist
So zeigen Sie eine bestimmte Zeile einer Datei oder ein Befehlsergebnis unter Linux an (sed, awk)
Stellen Sie die neueste Version von Python in Linux (Debian) von Chromebook
Hinweis zum Standardverhalten von collate_fn in PyTorch
Lassen Sie uns den Befehl pünktlich mit dem Bot der Zwietracht ausführen
[Hinweis] Import von Dateien in das übergeordnete Verzeichnis in Python
Eine grobe Zusammenfassung der Unterschiede zwischen Windows und Linux
Ich habe ein wenig versucht, das Verhalten der Zip-Funktion
Installieren Sie die neueste Version von Git auf Ihrem Linux-Server
Gibt es ein Geheimnis in der Häufigkeit der Umfangszahlen?
Rufen Sie den Hostnamen des Host-PCs mit Docker unter Linux ab
Installieren Sie JDK unter Linux
Eine kurze Zusammenfassung von Linux
Fügen Sie den Link unter Linux ein
Das Bild ist Namekuji
Veröffentlichen Sie das erstellte Shell-Skript, um die Probleme beim Erstellen von LiveUSB unter Linux zu verringern
Zum ersten Mal veröffentlichte GitHub x Circle CI ein Textüberprüfungstool von Python
Eine kleine süchtig machende Geschichte mit den Berechtigungen des von expdp angegebenen Verzeichnisses (für Anfänger)
Es ist überraschend mühsam, eine Liste mit dem Datum und der Uhrzeit der letzten Anmeldung von Arbeitsbereichen abzurufen