Sous Linux, l'horodatage d'un fichier est un peu dépassé.

(L'environnement d'exécution du texte ci-dessous est ubuntu 18.04. Le code source fait référence à la version amont de git, qui est la même version que le package ubuntu 18.04, pour la liaison.)

Déclencheur

Si vous regardez les horodatages après la mise à jour du fichier, il se peut qu'il soit légèrement passé.

$ 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

Puisque vous touchez le fichier entre 1 et 2, l'horodatage 3 doit être une heure entre 1 et 2, mais si vous regardez de près, 3 est environ 2 ms avant 1.

Examinez la date (1) et touchez (1)

La commande date n'émet pas d'appel système pour obtenir l'heure même si strace est appliqué. C'est parce que le temps est calculé sans appeler le noyau par un mécanisme appelé vsyscall, donc on peut considérer que l'appel système clock_gettime (2) est effectivement utilisé. Code source de la commande de dateQue,

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

gettime () est [défini] dans gnulib (Bibliothèque de portabilité GNU) (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
}

# if adopte la ligne du milieu clock_gettime.

D'un autre côté, le toucher peut prendre du rythme normalement.

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

J'utilise un appel système appelé ʻutimensat (2) `.

Examiner le noyau

ʻUtimensat (2) est [défini] dans le fichier 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)
{
Abréviation
}

A partir de maintenant, depuis do_utimes () → ʻutimes_common () , notify_change () ʻin fs / attr.c est [appelé](https://git.kernel.org/pub/scm/linux/kernel/ git / torvalds / linux.git / tree / fs / attr.c? h = v4.15 & id = d8a5b80568a9cb66810e75b182018e9edb68e8ff # n205).

Lors du réglage à l'heure actuelleattr->ia_validEstATTR_CTIME | ATTR_MTIME | ATTR_ATIME | ATTR_TOUCHIl est devenu.notify_change()Estファイルの各種属性の変更をする関数だが、属性変更時はctime、mtime、atimeを現在時刻に変更する普通であるので、そのような処理Il est devenu.

L'heure actuelle est [obtenue] par la fonction 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 () est défini dans fs / inode.c et [does](https: //) pour arrondir le résultat de current_kernel_time () à la précision de l'horodatage dépendant du système de fichiers. git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/inode.c?h=v4.15&id=d8a5b80568a9cb66810e75b182018e9edb68e8ff#n2116). Dans ext4, l'horodatage peut être conservé en unités ns, il ne sera donc pas arrondi ici.

current_kernel_time () passe par quelques fonctions wrapper et enfin les fonctions suivantes /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;
}

Extension de la fonction en ligne 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;
}

La boucle de read_seqcount_begin () à read_seqcount_retry () est une sorte de cliché pour vous empêcher de récupérer des données à moitié finies lors de la mise à jour.

Ensuite, pour 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). C'est enfin Ce qui suit [__getnstimeofday64](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/time/timekeeping.c?h=v4.15&id=d8a5b80568a9cb66810e75b182018e9edb Venez au 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;
}

En comparant les deux, vous pouvez voir qu'il y a une différence dans la partie tv_nsec. La commande tactile ʻutimensat () traite la variable tk-> tkr_mono.xtime_nsec, tandis que la commande de date clock_gettime (CLOCK_REALTIME) utilise le résultat de timekeeping_get_ns ()et déborde. Si c'est le cas, je fais quelque chose comme la modification de tv_sec. Lorsque vous appeleztimekeeping_get_ns ()`, vous appelez clocksource.

La différence essentielle est

Les horodatages sont uniquement des variables. L'appel horloger (matériel) est utilisé pour obtenir l'heure. C'est la différence essentielle.

Les variables référencées lors du changement d'horodatage sont mises à jour avec une coche, c'est-à-dire (en principe) un processus planifié toutes les 1 seconde de HZ. Par conséquent, l'horodatage est une unité de graduation, et puisque HZ = 250 dans ubuntu 18.04 générique, il représente l'heure passée jusqu'à 1/250 seconde = 4 millisecondes. Puisqu'il n'accède pas au matériel, l'heure peut être obtenue à grande vitesse avec n'importe quelle architecture.

Lors de l'obtention de l'heure actuelle avec la commande date, en plus de cette variable, se référer au matériel de la source d'horloge (normalement CPU TSC: compteur d'horodatage dans le x86 actuel).

TSC se trouve être rapidement accessible, mais les sources d'horloges d'autres architectures ne sont pas toujours rapidement accessibles, donc chaque fois qu'un fichier est mis à jour, ce qui est censé être fait plus souvent que d'obtenir l'heure actuelle avec une commande de date, etc. Il n'est pas rationnel d'accéder à la source d'horloge.

CLOCK_REALTIME_COARSE

En fait, vous pouvez également obtenir cette heure, qui est utilisée lors du changement de l'horodatage, clock_gettime (2). À ce stade, spécifiez CLOCK_REALTIME_COARSE comme premier argument.

Appelez alternativement CLOCK_REALTIME et CLOCK_REALTIME_COARSE, c'est-à-dire

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

Lorsque vous le faites, ts2 et ts4 auront la même valeur avec une probabilité relativement élevée, mais ts1, ts2 et ts3 n'auront jamais la même valeur (au moins tant que la source d'horloge est tsc).

Recommended Posts

Sous Linux, l'horodatage d'un fichier est un peu dépassé.
J'ai essayé de mesurer le temps d'attente de la file d'attente d'exécution d'un processus sous Linux
Le problème Zip 4 Gbyte est une histoire du passé
# La commande pour vérifier le codage du fichier texte (ISO-2022-JP, Shift_JIS, EUC-JP, UTF-8 ou UTF-16) sous Linux est nkf --guess (oubliez à chaque fois)
Créez un environnement Selenium sur Amazon Linux 2 dans les plus brefs délais
Comment afficher le résultat de sortie de la commande man Linux dans un fichier
Renommer en fonction de l'heure de modification du fichier (Linux)
[python] [meta] Le type de python est-il un type?
Quel est le fichier XX à la racine d'un projet Python populaire?
[Linux] Une commande pour obtenir une liste des commandes exécutées dans le passé
[Java] [Linux] Etude de la manière dont l'implémentation des processus enfants Java sous Linux est réalisée
Afficher le chemin complet (chemin absolu) d'un fichier dans un répertoire sous Linux Bash
Une note sur les fonctions de la bibliothèque Linux standard qui gère le temps
Découvrez où se trouve l'entité Java sur Linux (CentOS cette fois)
L'origine de Manjaro Linux est "Mount Kirimandjaro"
[2020July] Vérifiez l'UDID de l'iPad sous Linux
Calculer la probabilité de valeurs aberrantes sur les moustaches de la boîte
C'est un Mac. Qu'est-ce que la commande Linux Linux?
Au moment de la mise à jour de python avec ubuntu
J'ai fait un peu de recherche sur la classe
[Linux] Différence d'informations temporelles en fonction de l'ID d'horloge de la fonction clock_gettime ()
Lorsqu'un fichier est placé dans le dossier partagé de Raspberry Pi, le processus est exécuté.
Spécifiez le volume sous Linux et jouez le son
Créez un code QR pour l'URL sous Linux
Faites de votre curseur une photo de votre choix sous Linux
Vérifiez si le câble LAN est déconnecté sous Linux
L'émulateur Linux "iSH" qui fonctionne sur iPad est un sujet brûlant en moi
Une réflexion sur la visualisation du champ d'application du modèle de prédiction
Qu'est-ce qu'un moteur de recommandation? Résumé des types
Décompressez un fichier ZIP de plus de 4 Go sous Linux.
Afficher le résultat de sortie de sklearn.metrics.classification_report sous forme de fichier CSV
Créer une liste lorsque la nomenclature est pour une certaine période de temps
Annonce de la disponibilité de Java 11 LTS sur Amazon Linux 2
J'ai réfléchi un peu car Trace Plot du paramètre de stan est difficile à voir
Comment afficher une ligne spécifiée d'un fichier ou d'un résultat de commande sous Linux (sed, awk)
Mettez la dernière version de Python dans Linux (Debian) du Chromebook
Remarque sur le comportement par défaut de collate_fn dans PyTorch
Exécutons la commande à temps avec le bot discord
[Note] Importation de fichiers dans le répertoire parent en Python
Un résumé approximatif des différences entre Windows et Linux
J'ai essayé un peu le comportement de la fonction zip
Installez la dernière version de Git sur votre serveur Linux
Y a-t-il un secret dans la fréquence des nombres de rapport de circonférence?
Obtenez le nom d'hôte du PC hôte avec Docker sous Linux
Installez JDK sur Linux
Un bref résumé de Linux
Collez le lien sous Linux
L'image est Namekuji
Publiez le script shell créé pour réduire les problèmes de création de LiveUSB sous Linux
L'histoire de la sortie d'un outil de vérification de texte créé par Python sur GitHub x CircleCI pour la première fois
Une petite histoire addictive avec les permissions du répertoire spécifié par expdp (pour les débutants)
Il est étonnamment difficile d'obtenir une liste de la dernière date et heure de connexion des espaces de travail