web-dev-qa-db-fra.com

Le contexte bascule beaucoup plus lentement dans les nouveaux noyaux Linux

Nous cherchons à mettre à niveau le système d'exploitation de nos serveurs d'Ubuntu 10.04 LTS vers Ubuntu 12.04 LTS. Malheureusement, il semble que la latence d'exécution d'un thread devenu exécutable ait considérablement augmenté du noyau 2.6 au noyau 3.2. En fait, les chiffres de latence que nous obtenons sont difficiles à croire.

Permettez-moi d'être plus précis sur le test. Nous avons un programme qui exécute deux threads. Le premier thread obtient l'heure actuelle (en ticks avec RDTSC), puis signale une variable de condition une fois par seconde. Le deuxième thread attend la variable de condition et se réveille quand elle est signalée. Il obtient alors l'heure actuelle (en ticks avec RDTSC). La différence entre l'heure du second thread et celle du premier thread est calculée et affichée sur la console. Après cela, le deuxième thread attend la variable de condition une fois de plus. Il sera à nouveau signalé par le premier thread après environ une seconde passe.

Donc, en résumé, nous obtenons une thread à thread la communication via la variable de condition mesure de latence une fois par seconde.

Dans le noyau 2.6.32, cette latence est de l’ordre de 2,8-3,5 us, ce qui est raisonnable. Dans le noyau 3.2.0, cette latence a augmenté de 40 à 100 us environ. J'ai exclu toute différence matérielle entre les deux hôtes. Ils fonctionnent sur un matériel identique (processeurs X5687 {Westmere-EP} à double socket fonctionnant à 3,6 GHz avec hyperthreading, speedstep et tous les états C désactivés). L'application de test modifie l'affinité des threads pour les exécuter sur des cœurs physiques indépendants du même socket (c'est-à-dire, le premier thread est exécuté sur le coeur 0 et le second thread est exécuté sur le core 1). Il n'y a donc pas de rebondissement noyaux ou rebondir/communication entre les sockets.

La seule différence entre les deux hôtes est qu’un exécute Ubuntu 10.04 LTS avec le noyau 2.6.32-28 (la boîte de commutation de contexte rapide) et l’autre exécute le dernier Ubuntu 12.04 LTS avec le noyau 3.2.0-23 (le contexte lent boîte de commutation). Tous les paramètres et le matériel du BIOS sont identiques.

Y a-t-il eu des changements dans le noyau qui pourraient expliquer ce ralentissement ridicule du temps nécessaire à l'exécution d'un thread?

Mise à jour: Si vous souhaitez exécuter le test sur votre version de l'hôte et de Linux, j'ai posté le code dans Pastebin pour votre lecture. Compiler avec:

g++ -O3 -o test_latency test_latency.cpp -lpthread

Exécutez avec (en supposant que vous avez au moins une boîte dual-core):

./test_latency 0 1 # Thread 1 on Core 0 and Thread 2 on Core 1

Mise à jour 2 : Après de nombreuses recherches dans les paramètres du noyau, des publications sur les modifications du noyau et des recherches personnelles, j'ai découvert le problème et posté la solution. une réponse à cette question.

96
Michael Goldshteyn

La solution au problème de performance de réveil de threads dans les noyaux récents concerne le passage au pilote intel_idle De cpuidle à partir de acpi_idle, Le pilote utilisé dans les noyaux plus anciens. Malheureusement, le pilote intel_idle Ignore la configuration du BIOS de l'utilisateur pour les états C et danse à son rythme . En d’autres termes, même si vous désactivez complètement tous les états C dans le BIOS de votre PC (ou de votre serveur), ce pilote les forcera toujours pendant les périodes de brève inactivité, qui surviennent presque toujours sauf si un test de synthèse synthétique tout à fait consommateur (par exemple, ) est en cours d'exécution. Vous pouvez surveiller les transitions d'état C, ainsi que d'autres informations utiles relatives aux fréquences du processeur, en utilisant le merveilleux Google outil i7z sur la plupart des matériels compatibles.

Pour voir quel pilote cpuidle est actuellement actif dans votre configuration, il suffit de lire le fichier current_driver Dans la section cpuidle de /sys/devices/system/cpu Comme suit:

cat /sys/devices/system/cpu/cpuidle/current_driver

Si vous souhaitez que votre système d'exploitation Linux moderne ait la latence de commutation de contexte la plus faible possible, ajoutez les paramètres de démarrage du noyau suivants pour désactiver toutes ces fonctionnalités d'économie d'énergie:

Pour cela, vous pouvez le faire en les ajoutant à l'entrée GRUB_CMDLINE_LINUX_DEFAULT Dans /etc/default/grub, Puis en exécutant update-grub. Les paramètres de démarrage à ajouter sont:

intel_idle.max_cstate=0 processor.max_cstate=0 idle=poll

Voici les détails sanglants sur ce que font les trois options de démarrage:

Régler intel_idle.max_cstate Sur zéro rétablira votre pilote cpuidle sur acpi_idle (Du moins selon la documentation de l'option) ou le désactivera complètement. Sur ma boîte, il est complètement désactivé (c’est-à-dire que l’affichage du fichier current_driver Dans /sys/devices/system/cpu/cpuidle Produit une sortie de none). Dans ce cas, la deuxième option de démarrage, processor.max_cstate=0 N'est pas nécessaire. Toutefois, la documentation indique que la définition de max_cstate sur zéro pour le pilote intel_idle Devrait rétablir le système d'exploitation sur le pilote acpi_idle. Par conséquent, je mets dans la deuxième option de démarrage juste au cas où.

L'option processor.max_cstate Définit l'état C maximal du pilote acpi_idle À zéro et le désactive également. Je n'ai pas de système sur lequel tester cela, car intel_idle.max_cstate=0 Désactive complètement le pilote cpuidle sur tout le matériel disponible. Cependant, si votre installation vous fait passer de intel_idle À acpi_idle Avec seulement la première option de démarrage, merci de me faire savoir si la deuxième option, processor.max_cstate A fait ce pour quoi elle a été documentée faire dans les commentaires afin que je puisse mettre à jour cette réponse.

Enfin, le dernier des trois paramètres, idle=poll Est un véritable bourreau de pouvoir. Il désactivera C1/C1E, ce qui supprimera le dernier bit de latence au détriment d'une consommation d'énergie beaucoup plus importante. N'utilisez donc celui-ci que lorsque c'est vraiment nécessaire. Pour la plupart, ce sera exagéré, car la latence C1 * n’est pas très importante. En utilisant mon application de test fonctionnant sur le matériel que j'ai décrit dans la question initiale, le temps de latence est passé de 9 à 3 personnes. C’est certainement une réduction significative pour les applications très sensibles au temps de latence (par exemple, les opérations financières, la télémétrie/suivi de haute précision, l’acquisition de données haute fréquence, etc.), mais elle peut ne pas valoir le coup de puissance électrique subi par la grande majorité des utilisateurs. applications de bureau. La seule façon de savoir avec certitude consiste à décrire l'amélioration des performances de votre application par rapport à l'augmentation réelle de la consommation d'énergie/de la chaleur de votre matériel et à peser les compromis.

Mise à jour:

Après des tests supplémentaires avec différents paramètres idle=*, J'ai découvert que définir idle sur mwait s'il était pris en charge par votre matériel était une bien meilleure idée. Il semble que l’utilisation des instructions MWAIT/MONITOR Autorise la CPU à entrer en C1E sans qu’une latence notable ne soit ajoutée à l’heure de réveil du thread. Avec idle=mwait, Vous obtiendrez des températures du processeur plus basses (comparées à idle=poll), Consommerez moins d'énergie et conserverez les excellentes latences d'une boucle inactive en relève. Par conséquent, mon ensemble de paramètres de démarrage recommandé mis à jour pour la latence de réactivation des threads de processeur faible basé sur ces constatations est le suivant:

intel_idle.max_cstate=0 processor.max_cstate=0 idle=mwait

L'utilisation de idle=mwait Au lieu de idle=poll Peut également aider à lancer Turbo Boost (en aidant le processeur à rester en dessous de son TDP [Thermal Design Power]) et de l'hyperthreading (pour lequel MWAIT est l'idéal mécanisme permettant de ne pas consommer tout un noyau physique tout en évitant les états C plus élevés). Cela reste cependant à prouver lors des tests, ce que je continuerai de faire.

Mise à jour 2:

L'option mwait inactive a été supprimée des nouveaux noyaux 3.x (grâce à l'utilisateur ck_ pour la mise à jour). Cela nous laisse deux options:

idle=halt - Devrait fonctionner aussi bien que mwait, mais testez pour vous assurer que c'est bien le cas avec votre matériel. L’instruction HLT est presque équivalente à un MWAIT avec l’indicateur d’état 0. Le problème réside dans le fait qu’une interruption est nécessaire pour sortir d’un état HLT, alors qu’une écriture en mémoire (ou une interruption) est nécessaire. ) peut être utilisé pour sortir de l'état MWAIT. En fonction de ce que le noyau Linux utilise dans sa boucle inactive, cela peut rendre MWAIT potentiellement plus efficace. Donc, comme je l'ai dit test/profile et voir si cela répond à vos besoins en latence ...

et

idle=poll - L'option la plus performante au détriment de l'énergie et de la chaleur.

93
Michael Goldshteyn

Peut-être que ce qui est devenu plus lent est le futex, le bloc de construction des variables de condition. Cela nous éclairera un peu:

strace -r ./test_latency 0 1 &> test_latency_strace & sleep 8 && killall test_latency

puis

for i in futex nanosleep rt_sig;do echo $i;grep $i test_latency_strace | sort -rn;done

qui affichera les microsecondes pris pour les appels système intéressants, triés par heure.

Sur le noyau 2.6.32

$ for i in futex nanosleep rt_sig;do echo $i;grep $i test_latency_strace | sort -rn;done
futex
 1.000140 futex(0x601ac4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601ac0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000129 futex(0x601ac4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601ac0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000124 futex(0x601ac4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601ac0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000119 futex(0x601ac4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601ac0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000106 futex(0x601ac4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601ac0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000103 futex(0x601ac4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601ac0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000102 futex(0x601ac4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601ac0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 0.000125 futex(0x7f98ce4c0b88, FUTEX_WAKE_PRIVATE, 2147483647) = 0
 0.000042 futex(0x601b00, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000038 futex(0x601b00, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000037 futex(0x601b00, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000030 futex(0x601b00, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000029 futex(0x601b00, FUTEX_WAKE_PRIVATE, 1) = 0
 0.000028 futex(0x601b00, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000027 futex(0x601b00, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000018 futex(0x7fff82f0ec3c, FUTEX_WAKE_PRIVATE, 1) = 0
nanosleep
 0.000027 nanosleep({1, 0}, {1, 0}) = 0
 0.000019 nanosleep({1, 0}, {1, 0}) = 0
 0.000019 nanosleep({1, 0}, {1, 0}) = 0
 0.000018 nanosleep({1, 0}, {1, 0}) = 0
 0.000018 nanosleep({1, 0}, {1, 0}) = 0
 0.000018 nanosleep({1, 0}, {1, 0}) = 0
 0.000018 nanosleep({1, 0}, 0x7fff82f0eb40) = ? ERESTART_RESTARTBLOCK (To be restarted)
 0.000017 nanosleep({1, 0}, {1, 0}) = 0
rt_sig
 0.000045 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000040 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000038 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000035 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000034 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000033 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000032 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000032 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000031 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000031 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000028 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000028 rt_sigaction(SIGRT_1, {0x37f8c052b0, [], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x37f8c0e4c0}, NULL, 8) = 0
 0.000027 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000027 rt_sigaction(SIGRTMIN, {0x37f8c05370, [], SA_RESTORER|SA_SIGINFO, 0x37f8c0e4c0}, NULL, 8) = 0
 0.000027 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000025 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000025 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000023 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000023 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000022 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
 0.000022 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000021 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000021 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000021 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000021 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000021 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000019 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0

Sur le noyau 3.1.9

$ for i in futex nanosleep rt_sig;do echo $i;grep $i test_latency_strace | sort -rn;done
futex
 1.000129 futex(0x601764, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601760, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000126 futex(0x601764, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601760, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000122 futex(0x601764, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601760, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000115 futex(0x601764, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601760, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000114 futex(0x601764, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601760, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000112 futex(0x601764, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601760, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000109 futex(0x601764, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601760, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 0.000139 futex(0x3f8b8f2fb0, FUTEX_WAKE_PRIVATE, 2147483647) = 0
 0.000043 futex(0x601720, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000041 futex(0x601720, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000037 futex(0x601720, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000036 futex(0x601720, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000034 futex(0x601720, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000034 futex(0x601720, FUTEX_WAKE_PRIVATE, 1) = 1
nanosleep
 0.000025 nanosleep({1, 0}, 0x7fff70091d00) = 0
 0.000022 nanosleep({1, 0}, {0, 3925413}) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
 0.000021 nanosleep({1, 0}, 0x7fff70091d00) = 0
 0.000017 nanosleep({1, 0}, 0x7fff70091d00) = 0
 0.000017 nanosleep({1, 0}, 0x7fff70091d00) = 0
 0.000017 nanosleep({1, 0}, 0x7fff70091d00) = 0
 0.000017 nanosleep({1, 0}, 0x7fff70091d00) = 0
 0.000017 nanosleep({1, 0}, 0x7fff70091d00) = 0
rt_sig
 0.000045 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000044 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000043 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000040 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000038 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000037 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000036 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000036 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000035 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000035 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000035 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000035 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000034 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000031 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000027 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000027 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000027 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000027 rt_sigaction(SIGRT_1, {0x3f892067b0, [], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x3f8920f500}, NULL, 8) = 0
 0.000026 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000026 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000025 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000024 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000023 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
 0.000023 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000022 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000021 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000019 rt_sigaction(SIGRTMIN, {0x3f89206720, [], SA_RESTORER|SA_SIGINFO, 0x3f8920f500}, NULL, 8) = 0

J'ai trouvé ceci rapport de bogue vieux de 5 ans qui contient un test de performance "ping pong" qui compare

  1. mutex libpthread à un seul thread
  2. variable de condition libpthread
  3. vieux signaux Unix simples

Je devais ajouter

#include <stdint.h>

afin de compiler, ce que j'ai fait avec cette commande

g++ -O3 -o condvar-perf condvar-perf.cpp -lpthread -lrt

Sur le noyau 2.6.32

$ ./condvar-perf 1000000
NPTL
mutex                 elapsed:    29085 us; per iteration:   29 ns / 9.4e-05 context switches.
c.v. ping-pong test   elapsed:  4771993 us; per iteration: 4771 ns / 4.03 context switches.
signal ping-pong test elapsed:  8685423 us; per iteration: 8685 ns / 4.05 context switches.

Sur le noyau 3.1.9

$ ./condvar-perf 1000000
NPTL
mutex                 elapsed:    26811 us; per iteration:   26 ns / 8e-06 context switches.
c.v. ping-pong test   elapsed: 10930794 us; per iteration: 10930 ns / 4.01 context switches.
signal ping-pong test elapsed: 10949670 us; per iteration: 10949 ns / 4.01 context switches.

J'en conclus qu'entre les noyaux 2.6.32 et 3.1.9, le changement de contexte s'est effectivement ralenti, mais pas autant que ce que vous observez dans le noyau 3.2. Je réalise que cela ne répond pas encore à votre question, je vais continuer à creuser.

Edit: j'ai constaté que le fait de changer la priorité temps réel du processus (les deux threads) améliore les performances sur 3.1.9 pour correspondre à 2.6.32. Cependant, définir la même priorité sur 2.6.32 le ralentit ... allez comprendre - je vais regarder plus en détail.

Voici mes résultats maintenant:

Sur le noyau 2.6.32

$ ./condvar-perf 1000000
NPTL
mutex                 elapsed:    29629 us; per iteration:   29 ns / 0.000418 context switches.
c.v. ping-pong test   elapsed:  6225637 us; per iteration: 6225 ns / 4.1 context switches.
signal ping-pong test elapsed:  5602248 us; per iteration: 5602 ns / 4.09 context switches.
$ chrt -f 1 ./condvar-perf 1000000
NPTL
mutex                 elapsed:    29049 us; per iteration:   29 ns / 0.000407 context switches.
c.v. ping-pong test   elapsed: 16131360 us; per iteration: 16131 ns / 4.29 context switches.
signal ping-pong test elapsed: 11817819 us; per iteration: 11817 ns / 4.16 context switches.
$ 

Sur le noyau 3.1.9

$ ./condvar-perf 1000000
NPTL
mutex                 elapsed:    26830 us; per iteration:   26 ns / 5.7e-05 context switches.
c.v. ping-pong test   elapsed: 12812788 us; per iteration: 12812 ns / 4.01 context switches.
signal ping-pong test elapsed: 13126865 us; per iteration: 13126 ns / 4.01 context switches.
$ chrt -f 1 ./condvar-perf 1000000
NPTL
mutex                 elapsed:    27025 us; per iteration:   27 ns / 3.7e-05 context switches.
c.v. ping-pong test   elapsed:  5099885 us; per iteration: 5099 ns / 4 context switches.
signal ping-pong test elapsed:  5508227 us; per iteration: 5508 ns / 4 context switches.
$ 
8
amdn

Vous pouvez également voir les processeurs cliquer dans les processus les plus récents et les noyaux Linux en raison du pilote pstate qui est distinct de c-state. Donc, en plus, pour désactiver ceci, vous utilisez le paramètre de noyau suivant:

intel_pstate=disable

0
Kyle Brandt