14 Apr 2025, 00:00

Tester les I/O sous Linux avec fio

Flexible I/O tester, soit fio, sert à spécifier des charges de travail précises à faire exécuter par des supports de stockage.

sudo apt install fio

Liens :
https://fio.readthedocs.io/en/latest/fio_doc.html
https://linux.die.net/man/1/fio
https://askubuntu.com/questions/87035/how-to-check-hard-disk-performance
https://arstechnica.com/gadgets/2020/02/how-fast-are-your-disks-find-out-the-open-source-way-with-fio/
https://www.virtono.com/community/tutorial-how-to/fio-basics/

Paramètres obligatoires :
--name : le nom du job
--size : la taille du fichier ; obligatoire s’il n’existe pas déjà un fichier ou périphérique à l’emplacement de “filename” ; on peut toutefois une taille inférieure à l’objet existant, et seule cette zone sera utilisée pour le test

Par défaut, c’est un test en lecture seule sur un fichier de 4G.
Attention, si la taille est élevée, elle peut mener à une consommation de RAM élevée par job qui utilise des accès random (randread, randwrite et randrw) ! Dans le cas d’un RAID de 40 To, chaque job consommait environ 1.3 Go de RAM. Si on multiplie les jobs, cela peut mener à l’OOM.
Je suppose que c’est lié au fait qu’il va essayer de répartir les tests sur l’intégralité de la surface du périphérique, qu’il doit donc “mapper”.
Si on spécifie une taille sensiblement plus petite, alors ce problème ne se manifeste pas. Mais cela ne teste le support de stockage que sur une plus petite surface (donc moins de mouvement mécanique, et des résultats plus élevés que des accès sur toutes la surface).
io_size n’a pas d’effet dessus ; c’est size qui importe.

Autres paramètres :

--filename : le fichier (ou bloc ! ) sur lequel sera réalisé le test ; par défaut, c’est ./${jobname} (la valeur de –name) si un seul job, ou jobname.jobnumber.filenumber si plusieurs jobs
--filename_format : permet de personnaliser la génération de filename

--readonly pour de la lecture seule
--readwrite (ou –rw) : définit le type d’opération : read (séquentiel) , write (séquentiel) , randread (aléatoire) , randwrite (aléatoire) , rw (50/50 séquentiel) , randrw (50/50 aléatoire)
--opendir : ouvre séquentiellement tous les fichiers sous le répertoire passé en argument

--io_size : définit la quantité de données à traiter avant d’arrêter fio. Par défaut c’est équivalent à size, mais peut être différent (par exemple pour lire uniquement 5G de données malgré une taille de fichier de 20G, ou à l’inverse lire un total de 10G malgré une taile de fichier de 500m ; en cas il boucle)
--blocksize : par défaut 4096
--ioengine : le moteur d’I/O à utiliser ; par défaut psync ; voir les descriptions ; beaucoup d’exemples semblent utiliser libaio
--fsync= : pour forcer une sync (écriture réelle sur le périphérique) après X écritures
--end_fsync=1 : pour que le timer continue jusqu’à ce que l’OS rapporte que les écritures ont réellement été réalisées
--direct : force la non-utilisation d’un buffer disque ; recommandé de toujours mettre 1 (true)
--refill-buffers : pour forcer le renouvellement des données aléatoires utilisées pour le test

--gtod_reduce=1 : semble réduire les requêtes pour connaître l’heure et améliorer les perfs
--eta-newline : force l’affichage d’une nouvelle ligne après X secondes

En cas de lecture seule, le fichier de test doit être au moins aussi gros que la taille de blocs par défaut (soit 4K).

Job files

Syntaxe

; -- start job file --
[global]
rw=randread
size=128m

[job1]

[job2]

; -- end job file --

Chaque jobfile peut contenir 1 ou plusieurs jobs. Si plusieurs présents, il sont parallélisés.
On peut éviter cette parallélisation avec l’option stonewall (ou wait_for_previous) : un job qui possède cette option attendra la fin du/des jobs précédents avant de démarrer. Ce job (et les suivants) feront aussi partie d’un nouveau groupe de rapport.

Chaque job peut également paralléliser des IO (via iodepth ou numjobs).
On peut également fournir plusieurs jobfiles en ligne de commandes, et ils seront exécutés à la suite.

–section
possible de mettre des variables

Utilisation

Pour tester un disque en tant que bloc :
fio --filename=/dev/sdX ./jobfile.txt
Pour écrire le log dans un fichier :
fio --filename=/dev/sdX --output=mydisk.log ./jobfile.txt

Output

https://fio.readthedocs.io/en/latest/fio_doc.html#interpreting-the-output

Au début, le nom de tous les jobs qui seront lancés, avec leurs options.

seqread: (g=0): rw=read, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
randread: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
randwrite: (g=1): rw=randwrite, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1

g= : leur groupe d’appartenance (je suppose) ; (R) (W) (T) : read write trim

Pendant le test, Une ligne de type :
Jobs: 1 (f=1): [_(1),r(1),P(1)][45.4%][r=20.9MiB/s][r=5350 IOPS][eta 00m:53s]
Jobs: 1 (f=1) : le nombre jobs en cours dans le groupe (f=nombre de fichiers ouverts)
[_(1),r(1),P(1)] : l’état de l’ensemble des jobs prévus ; voir table dans la doc pour + de détails ;
les principaux états : _ = correctement fini ; rwmdRWMD : read/write/mixed/trim (MAJ=seq,min=rand) ;
P = job planifié pour plus tard ; X = erreurs ; K = interrompu
Puis pour chaque test (ou groupe si group_reporting) :

  • des infos test1: (groupid=0, jobs=1): err= 0: pid=1519610: Sun Feb 25 11:25:53 2024
  • des valeurs de latences (slat = submission latency, clat = completion latency, lat = total latency)
  • des valeurs de bande passante et d’IOPS
  • statistiques sur la latence, les IOPS, la bande passante etc

bench-fio et fio-plot

Un programme existe, fio-plot, qui permet de faire des graphs en utilisant les résultats de fio comme source de données.
Git : https://github.com/louwrentius/fio-plot qd Il est nécessaire que les données soient au format JSON, et que l’arborescence suive une formé précise.

Le + simple pour les créer semble être d’utiliser le script bench-fio fourni avec fio-plot.

Installation

Ne semble pas dispo dans les dépôts Debian.
Les instructions disent d’utiliser pip3 pour l’installer, mais Debian (trixie) m’informe que c’est mieux avec pipx. Donc on y va :
pipx install fio-plot

Les binaires se trouvent dans ${HOME}/.local/bin/ , et sont en fait des liens vers ${HOME}/.local/share/pipx/vens/fio-plot/. On y trouve notamment bench-fio et fio-plot.

Le chemin devrait être dans le ${PATH}, mais si besoin de lancer en root, il faudra sûrement donner le chemin complet.

Utilisation

bench-fio est un wrapper autour de fio. Il utilise un fichier INI qui définit les combinaisons à tester pour une même cible (fichier, périphérique etc…).

Dans le cas d’un RAID, en RAW (attention destruction de données), ce fichier INI pourrait être :

[benchfio]
target = /dev/md0
output = results
type = device
mode = read,randread,write,randwrite
size = 5G
iodepth = 1,2,4,8,16,32,64
numjobs = 1,2,4,8,16,32,64
direct = 1
engine = libaio
precondition = False
precondition_repeat = False
runtime = 30
destructive = True
block_size = 4k

type doit nécessairement être défini. Il peut s’agir, entre autres, de directory, device, file ou rbd (lié à Ceph).

Certaines valeurs sont définies par défaut ; notamment le runtime, qui si non spécifié, est de 60 secondes, soit 1 minute max par test ; je l’ai baissé ici à 30s.
Chaque test se finit dès que la taille spécifiée est traitée OU que le temps de runtime s’est écoulé.

Le paramètre “invalidate” de fio est par défaut à 1, c’est-à-dire que le cache est invalidé avant chaque test. Mais pour ceci, si la cible est de type “device”, il est nécessaire d’être root pour pouvoir invalider le cache.

Pour lancer le bench, il suffit de faire bench-fio ./bench.ini.
Ceci va nous créer (dans le dossier actuel) un dossier ${output}/${target}/${block_size} ; donc ici results/md0/4k , qui contiendra des fichiers JSON de type $mode-$iodepth-$numjob , par exemple “read-16-32.json”, ainsi qu’un fichier .log pour chaque job de chaque test ! Ça peut donc vite se compter en 10aines de milliers si on met beaucoup de combinaisons.

Génération des graphs

Une fois que le benchmark est fini, on peut genérer un graph avec fio-plot .
La syntaxe minimale doit inclure le dossier ou chercher les résultats (source des graphs) avec -i, le titre du graph avec -T, la mesure (read, randwrite etc) à laquelle on s’intéresse avec -r et le type de graph ; par exemple :
fio-plot -i results/md0/4k -T MONSUPERGRAPH -r read -l
En l’absence de précisions, il va chercher les valeurs pour les queue depths 1 2 4 8 16 32 64 et uniquement 1 en numjob.
Si une de ces combinaison est manquante dans les les données, la création de l’image échouera. On peut alors préciser ces valeurs avec -d pour depth et -n ; selon le type de graph, il peut être possible de séparer plusieurs valeurs par des espaces ; par exemple :
-d 1 4 16 64 -n 2 16 32

Les types de graph sont :

  • -l pour un graph 2D avec des barres représentant les IOPS et la latency, selon la queue depth (1 seul numjob par graph)
  • -N pour un graph 2D avec des barres représentant les IOPS et la latency, selon le numjob (1 seul queue depth par graph)
  • -L pour un graph 3D avec des barres représentant, au choix grace à l’option -t, les IOPS, ou la latence (lat, slat, clat) ou le débit ; les valeurs possibles sont bw,iops,lat,slat,clat ; on peut cumuler les valeurs de queue depth et numjob
  • -H pour un histogramme (quel pourcentage des valeurs est contenu dans chaque tranche de valeur) de la latence ; 1 depth et 1 numjob par graph (si on en spécifie plusieurs, seule la première valeur est prise en compte)
  • -g pour des courbes en fonction du temps ; on choisit une métrique avec -t (parmi bw,iops,lat,slat,clat) et autant de numjobs et qd que souhaité ; on aura 1 courbe par combinaison de qd et nj

À ma connaissance, seuls les graph -L et -g permettent de voir la bande passante en MO/s.

09 Nov 2020, 00:00

Monitoring du réseau sous Linux

Un peu de lecture ici.

nethogs

sudo apt install nethogs
sudo nethogs