linux - La résolution de gettimeofday () est-elle garantie en microsecondes?

Translate

Je porte un jeu, qui a été initialement écrit pour l'API Win32, sur Linux (enfin, le portage du port OS X du port Win32 vers Linux).

J'ai implémentéQueryPerformanceCounteren donnant les uSecondes depuis le démarrage du processus:

BOOL QueryPerformanceCounter(LARGE_INTEGER* performanceCount)
{
    gettimeofday(&currentTimeVal, NULL);
    performanceCount->QuadPart = (currentTimeVal.tv_sec - startTimeVal.tv_sec);
    performanceCount->QuadPart *= (1000 * 1000);
    performanceCount->QuadPart += (currentTimeVal.tv_usec - startTimeVal.tv_usec);

    return true;
}

Ceci, couplé avecQueryPerformanceFrequency()donnant une constante 1000000 comme fréquence, fonctionne biensur ma machine, me donnant une variable 64 bits qui contientuSecondsdepuis le démarrage du programme.

Alorsest-ce portable?Je ne veux pas découvrir que cela fonctionne différemment si le noyau a été compilé d'une certaine manière ou quelque chose comme ça. Je suis d'accord avec le fait qu'il ne soit pas portable vers autre chose que Linux, cependant.

This question and all comments follow the "Attribution Required."

Toutes les réponses

Translate

Peut être. Mais vous avez de plus gros problèmes.gettimeofday()peut entraîner des timings incorrects s'il y a des processus sur votre système qui modifient la minuterie (c.-à-d. ntpd). Sur un Linux "normal", cependant, je crois que la résolution degettimeofday()est 10us. Il peut par conséquent sauter en avant et en arrière et dans le temps, en fonction des processus exécutés sur votre système. Cela rend effectivement la réponse à votre question non.

Vous devriez examinerclock_gettime(CLOCK_MONOTONIC)pour les intervalles de temps. Il souffre de plusieurs problèmes en moins en raison de choses comme les systèmes multicœurs et les paramètres d'horloge externe.

Regardez également dans leclock_getres()fonction.

La source
Translate

Haute résolution, faible temps système pour les processeurs Intel

Si vous utilisez du matériel Intel, voici comment lire le compteur d'instructions en temps réel du processeur. Il vous indiquera le nombre de cycles CPU exécutés depuis le démarrage du processeur. C'est probablement le compteur le plus fin que vous puissiez obtenir pour la mesure des performances.

Notez qu'il s'agit du nombre de cycles CPU. Sous Linux, vous pouvez obtenir la vitesse du processeur à partir de / proc / cpuinfo et la diviser pour obtenir le nombre de secondes. Le convertir en double est assez pratique.

Quand je lance ça sur ma boîte, je reçois

11867927879484732
11867927879692217
it took this long to call printf: 207485

Ici se trouve leGuide du développeur Intelcela donne des tonnes de détails.

#include <stdio.h>
#include <stdint.h>

inline uint64_t rdtsc() {
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx");
    return (uint64_t)hi << 32 | lo;
}

main()
{
    unsigned long long x;
    unsigned long long y;
    x = rdtsc();
    printf("%lld\n",x);
    y = rdtsc();
    printf("%lld\n",y);
    printf("it took this long to call printf: %lld\n",y-x);
}
La source
Translate

@Bernard:

Je dois admettre que la plupart de votre exemple est passé directement au-dessus de ma tête. Il compile et semble fonctionner, cependant. Est-ce sans danger pour les systèmes SMP ou SpeedStep?

C'est une bonne question ... Je pense que le code est correct. D'un point de vue pratique, nous l'utilisons dans mon entreprise tous les jours, et nous fonctionnons sur un assez large éventail de boîtiers, allant de 2 à 8 cœurs. Bien sûr, YMMV, etc., mais cela semble être une méthode de synchronisation fiable et à faible surcharge (car elle ne fait pas basculer le contexte dans l'espace système).

Généralement, son fonctionnement est:

  • déclarez que le bloc de code est assembleur (et volatil, donc l'optimiseur le laissera seul).
  • exécutez l'instruction CPUID. En plus d'obtenir des informations sur le processeur (avec lesquelles nous ne faisons rien), il synchronise le tampon d'exécution du processeur afin que les délais ne soient pas affectés par une exécution dans le désordre.
  • exécuter l'exécution de rdtsc (horodatage de lecture). Cela récupère le nombre de cycles machine exécutés depuis la réinitialisation du processeur. Il s'agit d'une valeur de 64 bits, donc avec les vitesses actuelles du processeur, elle s'enroulera tous les 194 ans environ. Fait intéressant, dans la référence originale du Pentium, ils notent qu'il s'enroule tous les 5800 ans environ.
  • les deux dernières lignes stockent les valeurs des registres dans les variables hi et lo, et les placent dans la valeur de retour 64 bits.

Notes spécifiques:

  • une exécution dans le désordre peut entraîner des résultats incorrects, nous exécutons donc l'instruction "cpuid" qui, en plus de vous donner des informations sur le processeur, synchronise également toute exécution d'instruction dans le désordre.

  • La plupart des systèmes d'exploitation synchronisent les compteurs sur les processeurs au démarrage, la réponse est donc bonne en quelques nanosecondes.

  • Le commentaire d'hibernation est probablement vrai, mais dans la pratique, vous ne vous souciez probablement pas des délais à travers les limites d'hibernation.

  • concernant speedstep: les nouveaux processeurs Intel compensent les changements de vitesse et renvoie un nombre ajusté. J'ai fait une analyse rapide de certaines des boîtes de notre réseau et n'ai trouvé qu'une seule boîte qui ne l'avait pas: un Pentium 3 exécutant un ancien serveur de base de données. (ce sont des boîtes Linux, j'ai donc vérifié avec: grep constant_tsc / proc / cpuinfo)

  • Je ne suis pas sûr des processeurs AMD, nous sommes principalement une boutique Intel, même si je sais que certains de nos gourous des systèmes de bas niveau ont fait une évaluation AMD.

J'espère que cela satisfait votre curiosité, c'est un domaine de programmation intéressant et (à mon humble avis) sous-étudié. Vous savez quand Jeff et Joel parlaient de savoir si un programmeur devait ou non connaître C? Je leur criais: "Hé, oubliez ce truc de haut niveau en C ... l'assembleur est ce que vous devez apprendre si vous voulez savoir ce que fait l'ordinateur!"

La source
Translate

Wine utilise en fait gettimeofday () pour implémenter QueryPerformanceCounter () et il est connu pour faire fonctionner de nombreux jeux Windows sur Linux et Mac.

Départshttp://source.winehq.org/source/dlls/kernel32/cpu.c#L312

mène àhttp://source.winehq.org/source/dlls/ntdll/time.c#L448

La source
Translate

Donc, il dit explicitement microsecondes, mais indique que la résolution de l'horloge système n'est pas spécifiée. Je suppose que la résolution dans ce contexte signifie comment le plus petit montant il sera jamais incrémenté?

La structure des données est définie comme ayant des microsecondes comme unité de mesure, mais cela ne signifie pas que l'horloge ou le système d'exploitation est réellement capable de mesurer cela finement.

Comme d'autres l'ont suggéré,gettimeofday()est mauvais car le réglage de l'heure peut provoquer un décalage de l'horloge et perturber votre calcul.clock_gettime(CLOCK_MONOTONIC)est ce que tu veux, etclock_getres()vous dira la précision de votre horloge.

La source
Translate

La résolution réelle de gettimeofday () dépend de l'architecture matérielle. Les processeurs Intel ainsi que les machines SPARC offrent des minuteries haute résolution qui mesurent les microsecondes. D'autres architectures matérielles retombent sur la minuterie du système, qui est généralement réglée sur 100 Hz. Dans de tels cas, la résolution temporelle sera moins précise.

J'ai obtenu cette réponse deMesure du temps et minuteries haute résolution, partie I

La source
Translate

Cette réponsementionne des problèmes de réglage de l'horloge. Vos problèmes de garantie des unités de graduation et les problèmes de réglage de l'heure sont résolus en C ++ 11 avec le<chrono>bibliothèque.

L'horlogestd::chrono::steady_clockest garanti de ne pas être ajusté, et en outre, il avancera à une vitesse constante par rapport au temps réel, de sorte que les technologies comme SpeedStep ne doivent pas l'affecter.

Vous pouvez obtenir des unités sécurisées en convertissantstd::chrono::durationspécialisations, telles questd::chrono::microseconds. Avec ce type, il n'y a aucune ambiguïté sur les unités utilisées par la valeur de graduation. Cependant, gardez à l'esprit que l'horloge n'a pas nécessairement cette résolution. Vous pouvez convertir une durée en attosecondes sans avoir une horloge aussi précise.

La source
Translate

D'après mon expérience et ce que j'ai lu sur Internet, la réponse est «non», ce n'est pas garanti. Cela dépend de la vitesse du processeur, du système d'exploitation, de la saveur de Linux, etc.

La source
Translate

La lecture du RDTSC n'est pas fiable dans les systèmes SMP, puisque chaque CPU maintient son propre compteur et que chaque compteur n'est pas garanti d'être synchronisé par rapport à une autre CPU.

Je pourrais suggérer d'essayerclock_gettime(CLOCK_REALTIME). Le manuel posix indique que cela doit être implémenté sur tous les systèmes conformes. Il peut fournir un nombre de nanosecondes, mais vous voudrez probablement vérifierclock_getres(CLOCK_REALTIME)sur votre système pour voir quelle est la résolution réelle.

La source