Mesurer le temps sous Linux - temps vs horloge vs getrusage vs clock_gettime vs gettimeofday vs timespec_get?

148

Parmi les fonctions de synchronisation, time, clock getrusage, clock_gettime, gettimeofdayet timespec_get, je veux bien comprendre comment ils sont mis en œuvre et quelles sont leurs valeurs de retour afin de savoir dans quelle situation je dois les utiliser.

Nous devons d'abord classer les fonctions retournant des valeurs d'horloge murale par rapport aux fonctions retournant des valeurs de processus ou de threads . gettimeofdayretours valeur d'horloge de mur, clock_gettimerenvoie la valeur d'horloge de mur ou de processus ou des valeurs de fils en fonction du Clockparamètre qui lui est passé. getrusageet clockrenvoyer les valeurs de processus.

Ensuite, la deuxième question concerne la mise en œuvre de ces fonctions et par conséquent leur exactitude. Quel mécanisme matériel ou logiciel ces fonctions utilisent-elles?

Il semble qu'il getrusagen'utilise que le tick du noyau (généralement 1 ms de long) et par conséquent ne peut pas être plus précis que le ms. Est ce juste? Ensuite, la getimeofdayfonction semble utiliser le matériel sous-jacent le plus précis disponible. En conséquence, sa précision est généralement de la microseconde (ne peut pas être plus à cause de l'API) sur du matériel récent. Qu'en est-il clock, la page de manuel parle d '"approximation", qu'est-ce que cela signifie? Qu'en est-il clock_gettime, l'API est en nanoseconde, cela signifie-t-il qu'elle peut être si précise si le matériel sous-jacent le permet? Qu'en est-il de la monotonie?

Y a-t-il d'autres fonctions?

Manuel Selva
la source

Réponses:

198

Le problème est qu'il existe plusieurs fonctions de temps différentes disponibles en C et C ++, et certaines d'entre elles varient en comportement entre les implémentations. Il y a aussi beaucoup de demi-réponses qui circulent. Compiler une liste de fonctions d'horloge avec leurs propriétés répondrait correctement à la question. Pour commencer, demandons quelles sont les propriétés pertinentes que nous recherchons. En regardant votre message, je suggère:

  • Quelle heure est mesurée par l'horloge? (réel, utilisateur, système ou, espérons-le pas, horloge murale?)
  • Quelle est la précision de l'horloge? (s, ms, µs ou plus rapide?)
  • Après combien de temps l'horloge tourne-t-elle? Ou existe-t-il un mécanisme pour éviter cela?
  • L'horloge est-elle monotone ou changera-t-elle avec les changements d'heure système (via NTP, fuseau horaire, heure d'été, par l'utilisateur, etc.)?
  • Comment les éléments ci-dessus varient-ils entre les implémentations?
  • La fonction spécifique est-elle obsolète, non standard, etc.?

Avant de commencer la liste, je voudrais souligner que l'heure de l'horloge murale est rarement le bon moment à utiliser, alors qu'elle change avec les changements de fuseau horaire, les changements d'heure d'été ou si l'horloge murale est synchronisée par NTP. Aucune de ces choses n'est bonne si vous utilisez le temps pour planifier des événements ou pour évaluer les performances. Ce n'est vraiment bon que pour ce que son nom dit, une horloge sur le mur (ou sur le bureau).

Voici ce que j'ai trouvé jusqu'à présent pour les horloges sous Linux et OS X:

  • time() renvoie l'heure de l'horloge murale du système d'exploitation, avec une précision en secondes.
  • clock()semble renvoyer la somme du temps utilisateur et système. Il est présent dans C89 et plus tard. À un moment donné, cela était censé être le temps CPU en cycles, mais les normes modernes comme POSIX exigent que CLOCKS_PER_SEC soit 1000000, ce qui donne une précision maximale possible de 1 µs. La précision sur mon système est en effet de 1 µs. Cette horloge s'enroule une fois qu'elle atteint son maximum (cela se produit généralement après ~ 2 ^ 32 ticks, ce qui n'est pas très long pour une horloge de 1 MHz). man clockdit que depuis la glibc 2.18, il est implémenté clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...)sous Linux.
  • clock_gettime(CLOCK_MONOTONIC, ...)fournit une résolution nanoseconde, est monotone. Je crois que les «secondes» et les «nanosecondes» sont stockées séparément, chacune dans des compteurs 32 bits. Ainsi, tout bouclage se produirait après plusieurs dizaines d'années de disponibilité. Cela ressemble à une très bonne horloge, mais malheureusement, elle n'est pas encore disponible sur OS X. POSIX 7 décrit CLOCK_MONOTONICcomme une extension facultative .
  • getrusage()s'est avéré être le meilleur choix pour ma situation. Il rapporte les heures de l'utilisateur et du système séparément et ne se déroule pas. La précision sur mon système est de 1 µs, mais je l'ai également testé sur un système Linux (Red Hat 4.1.2-48 avec GCC 4.1.2) et là, la précision n'était que de 1 ms.
  • gettimeofday()renvoie l'heure de l'horloge murale avec une précision (nominalement) de µs. Sur mon système, cette horloge semble avoir une précision de µs, mais ce n'est pas garanti, car "la résolution de l'horloge système dépend du matériel" . POSIX.1-2008 le dit . "Les applications doivent utiliser la clock_gettime()fonction au lieu de la gettimeofday()fonction obsolescente ", vous devez donc vous en tenir à l'écart. Linux x86 et l'implémente en tant qu'appel système .
  • mach_absolute_time()est une option pour la synchronisation à très haute résolution (ns) sur OS X. Sur mon système, cela donne en effet une résolution ns. En principe, cette horloge tourne autour, mais elle stocke ns en utilisant un entier 64 bits non signé, donc le bouclage ne devrait pas être un problème en pratique. La portabilité est discutable.
  • J'ai écrit une fonction hybride basée sur cet extrait de code qui utilise clock_gettime lorsqu'elle est compilée sous Linux, ou une minuterie Mach lorsqu'elle est compilée sur OS X, afin d'obtenir une précision ns sur Linux et OS X.

Tout ce qui précède existe sous Linux et OS X, sauf indication contraire. "Mon système" dans ce qui précède est un Apple exécutant OS X 10.8.3 avec GCC 4.7.2 de MacPorts.

Enfin, voici une liste de références que j'ai trouvées utiles en plus des liens ci-dessus:


Mise à jour : pour OS X, clock_gettimea été implémentée à partir du 10.12 (Sierra). De plus, les plates-formes basées sur POSIX et BSD (comme OS X) partagent le rusage.ru_utimechamp struct.

Douglas B. Staple
la source
Mac OS X n'a ​​pas clock_gettime, d'où l'utilité d' gettimeofday()être un peu plus polyvalent queclock_gettime()
bobobobo
1
Vous n'avez pas mentionné times()(avec un s), qui existe dans POSIX depuis le numéro 1. Concernant GNU / Linux: Selon la page de manuel clock (3), clock()de la glibc 2.17 et versions antérieures a été implémentée par-dessus, mais pour une amélioration précision, il est maintenant implémenté par-dessus clock_gettime(CLOCK_PROCESS_CPUTIME_ID,...), ce qui est également spécifié dans POSIX mais est facultatif.
vinc17 le
2
@starflyer La précision de l'horloge est en partie limitée par le temps nécessaire pour interroger l'horloge. C'est parce que, si j'appelle l'horloge et qu'il faut 1 µs pour revenir, alors l'heure à laquelle l'horloge rapporte sera "off" de 1 µs du point de vue de l'appelant. Cela signifie qu'une horloge très précise doit également être à faible latence. Donc, généralement, on n'aura pas le compromis dont vous parlez: les horloges les moins chères seront également les plus précises.
Douglas B.Staple
3
De plus, la plupart des horloges ne se soucient pas de l'heure d'été / des fuseaux horaires, même si elles sont considérées comme des horloges murales . Les deux timeet gettimeofdayretournent, au moins de nos jours, secondes depuis l'époque (c'est-à-dire horodatages unix). Ceci est indépendant des fuseaux horaires / heure d'été. Les secondes
intercalaires
2
Pour les utilisateurs d'Android, l'utilisation de CLOCK_MONOTONIC peut être problématique car l'application peut être suspendue, ainsi que l'horloge. Pour cela, Android a ajouté le minuteur ANDROID_ALARM_ELAPSED_REALTIME accessible via ioctl. des informations sur ces informations et d'autres informations relatives à la suspension peuvent être trouvées ici
Itay Bianco
17

C11 timespec_get

Exemple d'utilisation sur: https://stackoverflow.com/a/36095407/895245

La précision maximale possible renvoyée est de nanosecondes, mais la précision réelle est définie par l'implémentation et peut être plus petite.

Il renvoie l'heure du mur, pas l'utilisation du processeur.

la glibc 2.21 l'implémente sous sysdeps/posix/timespec_get.cet la transmet directement à:

clock_gettime (CLOCK_REALTIME, ts) < 0)

clock_gettimeet CLOCK_REALTIMEsont POSIX http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html , et man clock_gettimeindique que cette mesure peut avoir des discontinuités si vous modifiez certains paramètres de l'heure du système pendant que votre programme s'exécute.

Chrono C ++ 11

Puisque nous y sommes, couvrons-les également: http://en.cppreference.com/w/cpp/chrono

GCC 5.3.0 (C ++ stdlib est dans la source GCC):

  • high_resolution_clock est un alias pour system_clock
  • system_clock transfère au premier des éléments suivants disponibles:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock transfère au premier des éléments suivants disponibles:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

Question posée à: Différence entre std :: system_clock et std :: regular_clock?

CLOCK_REALTIMEvs CLOCK_MONOTONIC: Différence entre CLOCK_REALTIME et CLOCK_MONOTONIC?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
1
Excellente réponse qui démystifie les implémentations typiques. C'est ce que les gens ont vraiment besoin de savoir.
Celess