Latence des process et kernel timing
Contents
Software version | Kernel 2.6.32+ |
---|---|
Operating System | Red Hat 6.3 Debian 7 |
Website | Kernel Website |
Last Update | 05/01/2014 |
Others |
1 Les horloges
Il existe plusieurs horloges qui permettent d'obtenir ou de manipuler des opérations de temps :
- RTC (Real Time Clock) : c'est la pile du BIOS qui permet de maintenir la date et l'heure sur une machine lorsque celle ci est éteint. Vous pouvez récupérer des informations sur celle ici dans le fichier /proc/driver/rtc.
- TSC (Time Stamp Counter) : c'est un compteur qui est mis à la même fréquence que celle du CPU, même si celui ci oscille. Le kernel utilise le TSC avec le RTC pour calculer la date et l'heure
- PIC (Programmable Interrupt Counter) : aussi connu sous le nom de PIT (Programmable Interval Timer) qui permet d'envoyer des interruptions au kernel après un certain temps passé. Il est généralement utilisé pour les process schedule.
- APIC (Advanced Programmable Interrupt Controller) : Il se cale également sur l'horloge CPU et permet de tracer les process en cours d'exécution et envoie les interruptions locales à ce processeur.
Sur un kernel 2.6, la fréquence du PIC est de 1MHz ou d'1 tick/ms (appelé aussi jiffy). Cet interval peut être ajusté lors de la compilation kernel ou bien en paramètre de boot (pour certaines distributions). Une valeur de tick plus courte donnera des temps de résolution meilleurs, cependant, les applications risquent de tourner de façon légèrement plus ralenti.
Le paramètre de boot est :
/etc/default/grub |
GRUB_CMDLINE_LINUX_DEFAULT="quiet tick_divider=<value>" |
Les valeurs intéressantes sont :
- 2 = 500 Hz
- 4 = 250 Hz
- 5 = 200 Hz
- 8 = 125 Hz
- 10 = 100 Hz
L'avantage est la réduction d'Overhead CPU, mais le scheduler est moins fair avec les processus interactifs.
2 Gérer la vitesse CPU
Il existe sous Red Hat un outil permettant de controler la vitesse de l'horloge CPU. Pour cela il faut installer le démon "cpuspeed" et le configurer dans /etc/sysconfig/cpuspeed :
Vous pouvez récupérer les informations actuelles comme ceci :
cpuspeed |
cpuspeed ---help 2>&1 | more |
Il est possible de voir les valeurs assignables possible :
cat |
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies 3166000 2667000 2333000 2000000 |
Donc 3.16Ghz, 2.66Ghz, 2.33Ghz ou 2Ghz.
Et enfin le gouvernor permet de voir l'algorithme utilisé. Par exemple ici c'est le "on demand", ce qui modifie a la volée la vitesse du processeur en fonction de la demande :
cat |
> cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors ondemand performance |
Si vous souhaitez les meilleures performances, désactivez ce démon. L'inconvénient est biensure la consommation électrique (pensez à l'environnement).
Sachez que si vous avez besoin de très faibles latences, il est fortement conseillé de désactiver ce démon.
3 Le balancing IRQ
Assurez vous que ces informations sont bien compilées dans le kernel :
grep |
> grep -e VOLUNTARY -e BKL /boot/config-2.6.32-279.2.1.el6.x86_64 | grep -v '#' CONFIG_PREEMPT_VOLUNTARY=y CONFIG_BKL=y |
Ces options sont faites pour que le kernel puisse préempter et planifier certains process. Le gain se fera sentir au niveau de la latence (surtout réseaux). Par exemple, le kernel peut gérer des opérations IO disque et recevoir en même temps des interruptions de la part de la carte réseau. Le handler qui fait les IO disques peut être préempté en faveur de l'interruption de la carte réseau ce qui améliorerait la latence réseau.
Il est néanmoins possible de désactiver l'IRQ balancing via un paramètre de boot :
/etc/default/grub |
GRUB_CMDLINE_LINUX_DEFAULT="quiet noapic" |
Si les IRQ sont inégalement réparties sur le CPU, le résultat peut être un incohérence des performances lorsque les gestionnaires d'interruption feront préempter les processus qui sont sur le CPU.
Pour voir les interruptions sur les interruptions :
Les interceptions permettent d'exploiter l'affinité des caches pour CPU et l'égalisation du nombre de visites CPU. Pour donner une affinité IRQ à un CPU afin d'améliorer les performances en exploitant au mieux l'affinité du cache, il faut spécifier le bitmap d'un core en hexadécimal. Par exemple :
echo |
echo <cpu_mask> > /proc/irq/<interrupt_number>/smp_affinity |
Cela permettra de placer cet IRQ en tête de l'active queue et de préserver certains CPU d'être utiliser pour les assignations IRQ. Il est possible de configurer sur Red Hat de façon permanente dans /etc/sysconfig/irqbalance. Pour ceux qui le souhaites, il est possible de désactiver l'IRQ balancing :
chkconfig |
chkconfig irqbalance off |
Pour plus d'infos sur les affinités IRQ : http://kernel.org/doc/Documentation/IRQ-affinity.txt[1]
4 Activer/Désactiver des CPU à chaud
Il est possible d'activer ou désactiver des CPU à chaud ! C'est d'ailleurs très facile. Vérifiez dans un premier temps que votre kernel permet ce genre de choses :
/boot/config-`uname -r` |
CONFIG_HOTPLUG CONFIG_SMP CONFIG_HOTPLUG_CPU CONFIG_ACPI_HOTPLUG_CPU |
Récupérez la liste des processeurs :
grep |
> grep processor /proc/cpuinfo processor : 0 processor : 1 |
Vérifiez ensuite vos interruptions :
Pour désactiver le CPU 1 :
echo |
echo 0 > /sys/devices/system/cpu/cpu1/online |
On peut voir qu'il n'y a plus que le CPU 0 :
On réactive ensuite le CPU 1 :
echo |
echo 1 > /sys/devices/system/cpu/cpu1/online |
Et tout le monde se replace correctement :-). Il faut savoir que certains CPU ne peuvent pas être désactivé comme le CPU de boot.
5 Egaliser l'utilisation des CPUs
Chaque core a sa propre run queue. Pour les processeurs HyperThreadés, le processeur logique utilise la même run queue que le core physique. Par défaut, il existe une certaine affinité et les tâches qui se produisent sur un CPU reviennent dessus plus ou moins automatiquement si d'autres associées se trouvaient à aller voir un autre CPU. Sachant que chaque CPU a son propre cache, c'est mieux comme cela. Cependant, si un core est plus chargé qu'un autre, le scheduleur regarde les run queues toutes les 100ms (ou 1ms sur le core ne fait rien) et décide de rééquilibrer la charge . Le problème se situe dans le cas ou ce système de balancing se fait trop souvent, on peut se prendre de la latence pour éviter des caches miss (tout dépends des applicatifs) ! Il faut alors choisir ce que l'on souhaites le plus. Pour voir la liste des programmes ainsi que leur core associés :
Vous pouvez voir également un processus se balader d'un core à un autre :
watch |
watch -n2 'ps axo comm,pid,psr | grep <process>' |
5.1 taskset
Si l'on souhaites assigner à certains process des CPU en particulier, c'est possible ! La première étape est de connaitre le bitmap CPU. Pour vous donner une idée de comment les récupérer :
Ensuite nous utiliserons la commande taskset pour assigner à un CPU en particulier un PID :
taskset |
taskset -p 0x00000001 <PID> |
Il faut savoir que les processeurs Numa ont la mémoire RAM directement mappées avec les CPU pour augmenter les performances. Cela ne change en rien que les autres processeurs peuvent utiliser de la mémoire qui ne leur est pas associée. Voici un petit aperçu de Numa :
Vous pouvez également spécifier les paramètres au niveau du grub pour isoler des CPU (isolcpus) :
Il est maintenant possible de faire du CPU pinning sur ce CPU. On aura donc une run queue plus petite et des temps de réponses améliorés pour les taches assignées à ce CPU.
Pour plus d'informations : http://kernel.org/doc/Documentation/kernel-parameters.txt[3]
5.2 cpuset/cgroup
cpuset est une version plus avancée de taskset qui permet d'avoir une méthode plus élégante, flexible et évolutive pour controler les runqueues ainsi que la latence sur les taches. Un cpuset est un groupe de CPU (scheduler domain/cgroups) sur lequel nous allons pouvoir y balanm cer des taches :
Pour s'assurer que ces fonctionnalités sont bien présentes dans le kernel :
grep |
> grep -i cpuset /proc/filesystems /boot/config-`uname -r` /proc/filesystems:nodev cpuset /boot/config-3.2.0-3-amd64:CONFIG_CPUSETS=y /boot/config-3.2.0-3-amd64:CONFIG_PROC_PID_CPUSET=y |
L'implémentation de cpuset dans le kernel est toute petite et n'a pas d'impacts sur le scheduler de process. Ca utilise un nouveau VFS qui n'introduit pas les nouveaux appels systèmes. Ce VFS cpuset peut être monté n'importe ou sur le système. Nous allons par exemple monter ceci dans /mnt/cpuserts. Il suffit de créer des dossier pour faire des assignations à d'autres CPU. Un CPU peut appartenir à plusieurs cpusets.
5.2.1 Prérequis
Mettre le montage des cgroups au boot :
/etc/fstab |
cgroup /sys/fs/cgroup cgroup defaults 0 0 |
Afin d'avoir toutes les options activés, il faut également modifier les options de Grub :
/etc/default/grub |
GRUB_CMDLINE_LINUX_DEFAULT="quiet cgroup_enable=memory swapaccount=1" |
Puis mettre à jour Grub :
update-grub |
update-grub |
Rebootez ensuite.
5.2.2 Création
Pour créer un cgroup c'est très simple :
mkdir |
mkdir /sys/fs/cgroup/mycgroup1 |
5.2.3 Assigner un cpu et sa mémoire à un cgroup
Nous allons assigner un CPU et sa mémoire à notre nouveau cgroup (ici, le CPU 0) :
echo |
echo 0 > /sys/fs/cgroup/mycgroup1/cpuset.cpus echo 0 > /sys/fs/cgroup/mycgroup1/cpuset.mems |
Vous pouvez envoyer plusieurs processeurs en les séparant par des virgules, le tout encadré par des quotes.
5.2.4 Dédier un CPU à un cgroup
Pour dédier un CPU uniquement à certains processus :
echo |
echo 0 > /sys/fs/cgroup/mycgroup1/cpuset.cpus |
5.2.5 Ajouter un processus à un cgroup
Pour ajouter un processus, c'est très simple, il suffit d'envoyer son PID dans le fichier tasks :
echo |
echo <PID> > /sys/fs/cgroup/mycgroup1/cpuset.tasks |
Ou si vous avez plusieurs processus du même nom :
for pid in $(pidof apache2); do echo $pid > /sys/fs/cgroup/mycgroup1/cpuset.tasks done |
5.2.6 Détacher un processus d'un cgroup
Il est possible de faire un détachement en rattachant un processus à un autre cgroup ou celui de la machine :
echo |
echo <PID> > /sys/fs/cgroup/tasks |
5.2.7 Supprimer un cgroup
Pour supprimer un cgroup c'est très simple, supprimez simplement le dossier en question :
rm |
rm -Rf /sys/fs/cgroup/mycgroup1/cpuset. |
5.2.8 Monitorer la pression sur un cpuset
Il est possible de monitorer la pression sur les cpusets en activant comme ceci :
echo |
echo 1 > /sys/fs/cgroup/memory_pressure_enabled |
Avec cette option, le kernel commencera à traquer l'utilisation mémoire des cpusets. Vous pourrez ensuite récupérer les statistiques dans chaque cgroup :
catcat /sys/fs/cgroup/<cgroup>/memory_pressure |
Vous retrouverez une moyenne d'exécution ou la vitesse a laquelle les pages frames se libères.
5.2.9 Divers
Voici divers astuces :
- Pour connaitre a quel cgroup le PID est attaché :
cat |
cat /proc/<pid>/cpuset |
- Pour savoir a quelle ressource un PID peut être planifié :
cat /proc/<pid>/status | grep allowed |
- Pour savoir si un CPU peut appartenir à plusieurs cgroups :
cat |
> cat /sys/fs/cgroup/cpu_exclusive 1 |
- Suppression automatique du cgroup lorsque aucune tache n'est active dessus :
echo |
echo 1 > /sys/fs/cgroup/mycgroup1/cpuset.notify_on_release |
5.3 Cgroups with cgconfig
To have cgroups working with cgconfig, be sure you've enabled cgroups in your fstab. Then install the daemon :
aptitude |
aptitude install cgroup-bin daemon |
It will checks all new running process and affect them to a correct cgroup if a rule exist.
Unfortunately, it's not well packaged yet on Debian so we need to adjust some things :
You now have your configuration files and all services installed correctly. Edit the configuration file :
Here is an example for tomcat user, where I want to have 2 dedicated CPU. Then you need to change the cgrules config :
/etc/cgrules.conf |
tomcat cpu tomcat_cgroup/ |
This indicates that tomcat user will change cpu settings and the cgroup folder is tomcat_cgroup (/sys/fs/cgroup/tomcat_cgroup). Now restart it :
Restart your tomcat service and it will automatically be placed in the cgroup :-)