• # Nanosecondes

    Posté par (site web personnel) . En réponse au journal En évoquant Facebook. Évalué à 10.

    Je bosse sur le projet Python qui manipule des durées dans des tas de format différents : time_t (secondes), timespec (secondes et nanosecondes), timeval (secondes et microsecondes), nombre de millisecondes (pour appeler poll()), etc. J'ai choisi d'utiliser le type C int64_t (appelé _PyTime_t dans pytime.c ci-dessous) avec une unité d'une nanoseconde (note : cette unité ne fait pas partie de l'API publique, c'est censé être interne).

    pytime.c:
    https://github.com/python/cpython/blob/a5293b4ff2c1b5446947b4986f98ecf5d52432d4/Python/pytime.c

    Les systèmes d'exploitation aiment la diversité. Windows fournit QueryPerformanceCounter() : nombre à diviser par QueryPerformanceFrequency() pour obtenir des secondes. En utilisant des nombres flottants, la division est facile à réaliser. Mais en utilisant des nombres entiers (_PyTime_t), euh, c'est plus difficile, surtout pour éviter un integer overflow (dépassement de capacité du type int64_t provoquant des erreurs de calcul). J'ai notamment écrit _PyTime_MulDiv() pour QueryPerformanceCounter() :
    https://github.com/python/cpython/blob/a5293b4ff2c1b5446947b4986f98ecf5d52432d4/Python/pytime.c#L46-L61

    Avec un peu de mathématique, on évite l'integer overflow en pratique :

    (ticks * mul) / div == (ticks / div) * mul + (ticks % div) * mul / div
    Le code gère 4 modes d'arrondi (_PyTime_ROUND_HALF_EVEN, _PyTime_ROUND_CEILING, _PyTime_ROUND_FLOOR, _PyTime_ROUND_UP) car en plus, selon le besoin, il faut arrondir différemment... Depuis 2012, j'ai du corriger 4x les arrondis...
    https://vstinner.github.io/pytime.html
    (cet article date de février 2016, il ne mentionne pas le dernier correctif de 2017)

    En utilisant l'Epoch Unix (1er janvier 1970) comme référence, ce type permet de stocker des dates de l'année 1678 à l'année 2262. Vous me direz que c'est largement suffisant. Sauf que Python fournit le module datetime qui gère des dates de l'année 1 à 9999. Pour ce module, il faut conserver le type time_t (qui peut être en 32-bit ou 64-bit selon la plateforme) pour gérer des dates "extrêmes". Bien sûr, jouer avec de telles dates provoque des soucis sur certaines plateformes comme Windows, AIX ou Solaris.

    Le noyau Linux a un type opaque ktime_t https://lwn.net/Articles/167897/ mais ce type n'est pas (forcément) un entier, et on ne peut pas écrire t1 + t2 ou t2 - t1, contrairement au type _PyTime_t.

    This type, found in , is meant to be used as an opaque structure. And, interestingly, its definition changes depending on the underlying architecture. On 64-bit systems, a ktime_t is really just a 64-bit integer value in nanoseconds. On 32-bit machines, however, it is a two-field structure: one 32-bit value holds the number of seconds, and the other holds nanoseconds.

    Gérer le temps, c'est simple ! Bon, maintenant on va parler des timezones et de changement d'heure d'été ...