Tracepoints

A la fin de la partie sur perf list, nous avons évoqué comment perf stat nous permettait d’aller au-delà des appels système et de compter divers événements internes au noyau Linux, via des tracepoints (points de code instrumentés) que nous pouvons énumérer avec perf list tracepoint.

Avec perf trace, nous avons accès à des informations supplémentaires sur ces tracepoints :

  • Nous pouvons observer le déroulé temporel des passages à ces endroits du noyau
  • Nous pouvons y connaître certaines informations choisies par l’auteur du tracepoint

Considérons, par exemple, la commande dd suivante, qui écrit quelques kilo-octets de données aléatoires dans un fichier du disque dur SATA du serveur d’une façon fabuleusement inefficace :

dd if=/dev/urandom of=/hdd/${USER}/randomness.bin bs=42 count=123 oflag=sync

En examinant les appels système qu’elle fait, on n’apprendrait pas grand-chose :

srun --pty \
    perf trace -s \
    dd if=/dev/urandom of=/hdd/${USER}/randomness.bin bs=42 count=123 oflag=sync

Sommaire perf trace de l’exécution de dd

En revanche, on peut en apprendre davantage en étudiant l’activité des tracepoints associés à différentes parties du noyau Linux impliquées dans l’écriture de données sur le disque :

  • Le système de fichier utilisé sur /hdd (ext4, comme vous le dira mount)
  • Le périphérique bloc sous-jacent (/dev/sda1 pour les intimes)
  • Le cache disque qui s’intercale grosso modo entre les deux

Utiliser perf stat avec ces tracepoints nous permet déjà de formuler quelques hypothèses :

srun --pty \
    perf stat -e 'block:*,ext4:*,writeback:*' \
    dd if=/dev/urandom of=/hdd/${USER}/randomness.bin bs=42 count=123 oflag=sync
Sortie de perf stat

On constate ainsi que certaines parties du noyau semblent traversées une fois par bloc, d’autres plusieurs fois par bloc (le nombre de fois où elles sont traversées est approximativement multiple du nombre de blocs), et d’autres plus rarement, ce qui suggère qu’elle sont appelées une fois tous les quelques blocs ou bien durant les phases d’initialisation et de finalisation du programme.

Et, bien sûr, on voit aussi que certaines parties du noyau ne sont pas traversées, ce qui peut dans certain cas être une information tout aussi importante.

Mais le niveau de détail accessible via perf trace n’est tout simplement pas comparable :

srun --pty \
    perf trace -e 'block:*,ext4:*,writeback:*' \
    dd if=/dev/urandom of=/hdd/${USER}/randomness.bin bs=42 count=123 oflag=sync
Sortie de perf trace

Avec ce nouvel outil, on commence vraiment à voir assez précisément qu’est-ce que fait le noyau Linux des requêtes d’écriture disque qu’on lui envoie, quelles parties du noyau sont sollicitées, quels ordres sont envoyés au matériel sous-jacent… et ce niveau de détail peut faire la différence quand on essaie de démêler pourquoi une application relativement complexe est loin d’atteindre les performances d’E/S théoriquement permises par le périphérique de stockage qu’elle utilise.

Exercice : Répétez cette analyse en remplaçant oflag=sync par conv=fsync, puis en supprimant carrément cette option. Qu’est-ce que ça change au niveau de l’activité noyau ?