GNU/Linux >> Tutoriels Linux >  >> Linux

Pourquoi cette boucle de retard commence-t-elle à s'exécuter plus rapidement après plusieurs itérations sans sommeil ?

Après 26 itérations, Linux augmente la vitesse du processeur jusqu'à la vitesse d'horloge maximale, car votre processus utilise sa tranche de temps plein plusieurs fois de suite.

Si vous vérifiiez avec des compteurs de performances au lieu de l'horloge murale, vous verriez que les cycles d'horloge de base par boucle de retard sont restés constants, confirmant qu'il s'agit simplement d'un effet de DVFS (que tous les processeurs modernes utilisent pour fonctionner à une énergie plus élevée). fréquence et tension efficaces la plupart du temps).

Si vous testiez sur un Skylake avec la prise en charge du noyau pour le nouveau mode de gestion de l'alimentation (où le matériel prend le contrôle total de la vitesse d'horloge), la montée en puissance se produirait beaucoup plus rapidement.

Si vous le laissez fonctionner pendant un certain temps sur un processeur Intel avec Turbo, vous verrez probablement le temps par itération augmenter à nouveau légèrement une fois que les limites thermiques obligeront la vitesse d'horloge à revenir à la fréquence maximale soutenue. (Consultez Pourquoi mon CPU ne peut-il pas maintenir des performances optimales dans HPC pour en savoir plus sur Turbo permettant au CPU de fonctionner plus vite qu'il ne peut le supporter pour des charges de travail à haute puissance.)

Présentation d'un usleep empêche le régulateur de fréquence du processeur de Linux d'augmenter la vitesse d'horloge, car le processus ne génère pas une charge de 100 % même à la fréquence minimale. (C'est-à-dire que l'heuristique du noyau décide que le processeur fonctionne assez rapidement pour la charge de travail qui s'exécute dessus.)

commentaires sur d'autres théories :

re :La théorie de David selon laquelle un changement de contexte potentiel de usleep pourrait polluer les caches :ce n'est pas une mauvaise idée en général, mais cela n'aide pas à expliquer ce code.

La pollution du cache/TLB n'est pas du tout importante pour cette expérience . Il n'y a pratiquement rien à l'intérieur de la fenêtre de synchronisation qui touche la mémoire autre que la fin de la pile. La plupart du temps est passé dans une petite boucle (1 ligne de cache d'instructions) qui ne touche qu'un int de mémoire de pile. Toute pollution potentielle du cache pendant usleep est une infime fraction du temps pour ce code (le vrai code sera différent) !

Plus en détail pour x86 :

L'appel au clock() elle-même peut manquer de cache, mais une erreur de cache de récupération de code retarde la mesure de l'heure de démarrage, plutôt que de faire partie de ce qui est mesuré. Le deuxième appel au clock() ne sera presque jamais retardé, car il devrait encore être chaud dans le cache.

Le run la fonction peut être dans une ligne de cache différente de main (puisque gcc marque main comme "froid", il est donc moins optimisé et placé avec d'autres fonctions/données froides). Nous pouvons nous attendre à un ou deux échecs du cache d'instructions. Ils sont probablement toujours dans la même page 4k, donc main aura déclenché l'échec potentiel du TLB avant d'entrer dans la région chronométrée du programme.

gcc -O0 compilera le code de l'OP en quelque chose comme ceci (l'explorateur Godbolt Compiler) :garder le compteur de boucle en mémoire sur la pile.

La boucle vide conserve le compteur de boucle dans la mémoire de la pile, donc sur un processeur Intel x86 typique, la boucle s'exécute à une itération par ~ 6 cycles sur le processeur IvyBridge de l'OP, grâce à la latence de transfert de magasin qui fait partie de add avec une destination mémoire (lecture-modification-écriture). 100k iterations * 6 cycles/iteration est de 600 000 cycles, ce qui domine la contribution d'au plus quelques échecs de cache (~ 200 cycles chacun pour les échecs de récupération de code qui empêchent d'autres instructions d'être émises jusqu'à ce qu'elles soient résolues).

L'exécution dans le désordre et la redirection de magasin devraient principalement masquer le manque potentiel de cache lors de l'accès à la pile (dans le cadre du call instructions).

Même si le compteur de boucles était conservé dans un registre, 100 000 cycles, c'est beaucoup.


Un appel au usleep peut entraîner ou non un changement de contexte. Si c'est le cas, cela prendra plus de temps que si ce n'est pas le cas.


Linux
  1. Pourquoi ce pipeline shell sort-il ?

  2. Pourquoi Tomcat fonctionne-t-il avec le port 8080 mais pas 80 ?

  3. Pourquoi ce code plante-t-il avec la randomisation d'adresse activée ?

  4. Pourquoi cette regex ne fonctionne-t-elle pas sous Linux ?

  5. Comment exécuter une commande en arrière-plan avec un délai ?

Pourquoi la machine virtuelle Windows 10 affiche-t-elle toujours une utilisation du processeur à 100 % sur QEMU-KVM ?

Linux - Comment la charge moyenne fonctionne-t-elle avec les processeurs modernes ?

Pourquoi Bash ne stocke-t-il pas les commandes commençant par des espaces ?

Pourquoi Htop Meter affiche-t-il> 90 % alors que le tableau est à 0,0 % ?

Pourquoi cette commande ldapadd se termine-t-elle avec une erreur de syntaxe non valide ?

Pourquoi me manque-t-il /var/run/sshd après chaque démarrage ?