perf iostat

Toutes les commandes perf que nous avons étudiées jusqu’à présent ont pour fonction d’étudier le comportement du CPU ou du code qui s’y exécute. Mais perf iostat, elle, étudie le volume des échanges entre le CPU et les périphériques (stockage, GPU, réseau…) via le bus PCI-express (PCIe).

C’est donc par exemple un outil approprié pour savoir si une interconnexion CPU-périphérique est saturée, pour peu que l’on sache quel est le débit crète attendu (ex : PCIe 3.0 x16 = 16 Go/s).

Tout d’abord, on peut obtenir une liste des ports PCIe racine que perf iostat peut interroger :

perf iostat list

Ports PCIe racine

Pour savoir quels périphériques sont raccordés à ces ports, on peut utiliser la commande /sbin/lspci -D. Le résultat contiendra un grand nombre de “périphériques” qui sont en réalité des composants internes du CPU, voici un affichage simplifié qui ne les inclut pas pour plus de clarté :

/sbin/lspci -D | grep -v 'Intel Corporation Sky Lake-E'

Liste de périphériques PCIe

L’adressage PCIe est construit de telle sorte que le numéro de bus (la 1ère paire de chiffres hexadécimaux dans l’adresse) d’un enfant est compris entre celui du port racine auquel il est raccordé et celui du port racine suivant, donc…

  • La carte graphique est raccordée au port racine 0000:20.
  • Le SSD système est raccordé au port racine 0000:2c.
  • Les autres périphériques (USB, SATA, réseau, audio…) sont raccordés au port racine 0000:00.
  • Le port racine 0000:14 n’est connecté qu’à des ressources internes au CPU.

Pour illustrer cela, commençons par écrire 1 Gio de zéros sur le SSD par blocs de 4 Mio en surveillant l’ensemble des ports PCIe racine :

srun --pty --exclusive \
    perf iostat \
    dd if=/dev/zero of=~/.Private/test.dump \
       bs=4M count=256 oflag=direct \
; rm ~/.Private/test.dump

Suivi d’une commande dd écrivant sur le SSD

On voit dans le rapport produit par perf iostat qu’aucun des ports PCIe racine n’a été sollicité de façon significative à l’exception de celui connecté au SSD.

Sur celui-ci, 1026 Mio de données ont été lus par le SSD depuis la RAM (ces données ayant été préalablement préparées par le CPU). On observe donc un petit surcroît de trafic lié au protocole de communication CPU-SSD, mais qui reste très modeste ici.

On voit aussi que les transferts de données utilisent la technique du DMA (Direct Memory Access), où c’est le périphérique de stockage qui fait l’essentiel du travail pour transférer les données. C’est le cas général sur un système moderne.

Pour ce qui concerne le débit, dans le cas présent, l’utilitaire dd le calcule pour nous. Mais un intérêt de perf iostat est que cet utilitaire est utilisable même sur des programmes qui ne sont pas instrumentés pour mesurer leur volume de données, en divisant le volume de données transféré par la durée de la mesure.

On voit en tout cas que le débit est de 2 Go/s, ce qui pourrait saturer l’interconnexion sur certaines carte mères (ports PCIe 3.0 x2), mais pas toutes (certaines ont des ports x4). Il faudrait donc avoir les spécifications de la carte mère et du SSD pour conclure, mais celles-ci n’ont malheureusement pas été fournies par HP pour srv-calcul-ambulant.

En revanche, si on fait la même expérience avec le disque dur…

srun --pty --exclusive \
    perf iostat \
    dd if=/dev/zero of=hdd/$USER/test.dump \
       bs=4M count=256 oflag=direct \
; rm /hdd/$USER/test.dump

Suivi d’une commande dd écrivant sur le disque dur

…on voit qu’on est très loin d’atteindre le débit minimal d’un port PCIe pour la génération 3.0, qui est de 1 Go/s (canal 1x). On peut donc conclure sans spécifications supplémentaires que c’est le disque dur qui limite les performances d’écriture ici, et pas l’interconnexion.

Mentionnons pour conclure que sur des systèmes où il y a beaucoup de ports PCIe racine (c’est le cas des système en rack, surtout quand ils sont multi-CPU), il peut être intéressant de n’en surveiller et n’en afficher que quelques uns. C’est possible de le faire en passant les numéros de port racine à perf iostat, avant la commande à surveiller, sous forme de liste séparée par des virgules (ex : perf iostat 0000:2c,0000:20 <commande>).

Exercice : En vous inspirant des commandes dd ci-dessus, créez une charge de travail qui copie 1 Gio de données du SSD au disque dur et surveillez-la avec perf iostat en restreignant l’affichage aux ports PCIe auxquels le SSD et le disque dur sont connectés. Pour plus de réalisme, vous pouvez générer des données aléatoires en utilisant /dev/random comme source plutôt que /dev/zero.