Benchs avec fio, comprendre (un peu) certaines options et les I/O sous Linux

5 réponses
Avatar
Francois Lafont
Bonjour à tous,

J'ai un laptop sous Debian Stretch avec un disque Samsung SSD
2.5" MZ-7TE2560 de 256GB monté en EXT4 avec l'option noatime.
Je tente actuellement des benchs du disque avec fio. Ce n'est
pas vraiment pour chercher à optimiser les perfs (je suis plutôt
satisfait à l'usage) mais c'est surtout pour tenter d'apprendre
à me servir de fio et aussi de comprendre un (petit peu) mieux
le mécanisme des I/O sous Linux.

Voici les options de base que j'utilise sur mes 3 tests :

alias my_fio='fio --name myjob --numjobs=3 --size=1G \
--time_based --runtime=60 --group_reporting \
--rw=randwrite --ioengine=libaio --iodepth=8 --bs=4k'


1. Mon premier test est : my_fio --direct=1

Si je comprends bien, avec --direct=1, fio utilise le flag
O_DIRECT au niveau de l'appel système open() ce qui oblige
le noyau Linux à ne pas utiliser son cache.

J'ai bon ?

Avec ce test, j'obtiens environ 48 000 iops.


2. Ensuite, je tente : my_fio --direct=1 --sync=1

Là aussi, je comprends que --sync=1 fait en sorte que le
flag O_SYNC est utilisé de sorte que les écritures sont
synchrones et qu'en gros (si je comprends bien) le kernel
ne passe de l'écriture N à la N+1 que lorsqu'il a la
« garantie » que les données de l'écriture N ont été
transférées au niveau du disque (je mets des guillemets
ici car le disque peut lui-même avoir son cache et le
noyau peut estimer que les données sont écrites sur le
disque alors que ce n'est pas encore le cas en réalité).

Et là j'ai bon ?

Avec ce deuxième test, j'ai environ 1 500 iops et je trouve
donc logique que l'ajout de --sync=1 fasse baisser les perfs.


3. Enfin je teste : my_fio --direct=1 --fsync=1

La page man de fio est claire, avec cette option --fsync=1
tous les « 1 » I/O un appel de fsync() est fait ce qui (plus
on avance moins je suis sûr de moi) provoque un flush des
data au niveau du disque.

Si je regarde la page man open(2) je vois ceci :

O_SYNC
Write operations on the file will complete according to
the requirements of synchronized I/O file integrity
completion (by contrast with the synchronized I/O
data integrity completion provided by O_DSYNC.)

By the time write(2) (and similar) return, the output
data and associated file metadata have been transferred
to the underlying hardware (i.e., as though each write(2)
was followed by a call to fsync(2)).

C'est la dernière phrase entre parenthèses qui me laisse penser
que O_SYNC revient à faire un fsync() lors de chaque écriture.
Du coup, naïvement, je me dis que ce bench numéro 3 devrait
être équivalent au second (celui avec --sync=1 ie avec O_SYNC)
puisque, apparemment, O_SYNC revient à faire un fsync() à chaque
écriture.

Et bien non, le bench numéro 3 est nettement plus « mauvais »
que le second car je tombe à environ 300 iops.

Pourquoi est-ce

a) my_fio --direct=1 --sync=1
b) my_fio --direct=1 --fsync=1

ne sont pas (du tout) équivalent ?


Voilà. J'ai bien conscience que les I/O sous Linux c'est vraiment
compliqué mais j'apprécierais toutes aides, liens etc. qui pourraient
m'aider à acquérir quelques éléments de compréhension sur ces
questions.

Merci d'avance pour votre aide.

--
François Lafont

5 réponses

Avatar
Marc SCHAEFER
Francois Lafont wrote:
ici car le disque peut lui-même avoir son cache et le
noyau peut estimer que les données sont écrites sur le
disque alors que ce n'est pas encore le cas en réalité).

Une référence un peu ancienne, mais qui donne quelques
pistes:
http://milek.blogspot.ch/2010/12/linux-osync-and-write-barriers.html
On y apprend notamment que normalement, la synchro va y.c
sur les caches des disques, mais pas toujours.
On y lit aussi que fsync() devrait être bien plus rapide
que O_SYNC, vu que fsync() sur ext3 semble ne faire de
commit de journal qu'une fois par seconde.
La recommandation semble être d'utiliser fdatasync()
aux points de synchronisation indispensables.
Le brouillard n'est donc pas vraiment dissipé.
Avatar
Francois Lafont
Bonjour,
On 05/28/2018 02:48 PM, Marc SCHAEFER wrote:
Une référence un peu ancienne, mais qui donne quelques
pistes:
http://milek.blogspot.ch/2010/12/linux-osync-and-write-barriers.html

Merci pour le lien.
On y apprend notamment que normalement, la synchro va y.c
sur les caches des disques, mais pas toujours.

Heu... ça veut dire quoi "y.c" ?
On y lit aussi que fsync() devrait être bien plus rapide que O_SYNC,

Et bien on dirait que c'est le contraire sur mes tests fio où
j'ai l'option --fsync=1 qui me plombe les perfs par rapport à
"--direct=1 --sync=1". Et je ne comprends pas pourquoi car pour
moi cela devrait être équivalent (étant donné que je lis dans
les pages man qu'avec O_SYNC tout se passe comme si un fsync()
était exécuté).
vu que fsync() sur ext3 semble ne faire de
commit de journal qu'une fois par seconde.

Perso, si je lis man fsync(2), on dirait bien que ça flush les
data et les metadata et qu'il y a fdatasync(), apparemment, pour
flusher uniquement les data (si j'ai bien compris).
La recommandation semble être d'utiliser fdatasync()
aux points de synchronisation indispensables.
Le brouillard n'est donc pas vraiment dissipé.

Arf... non pas encore mais merci beaucoup pour ces éléments.
Au passage, j'ai lu ici ou là que O_DIRECT ne donnerait qu'une
« indication » au noyau en lui signalant qu'il n'est pas nécessaire
de cacher la data mais que le noyau peut parfaitement ne pas
respecter cette indication.
À+
--
François Lafont
Avatar
Marc SCHAEFER
In article <5b0d1e51$0$31623$ you wrote:
Heu... ça veut dire quoi "y.c" ?

y compris?
Et bien on dirait que c'est le contraire sur mes tests fio où
j'ai l'option --fsync=1 qui me plombe les perfs par rapport à
"--direct=1 --sync=1". Et je ne comprends pas pourquoi car pour
moi cela devrait être équivalent (étant donné que je lis dans
les pages man qu'avec O_SYNC tout se passe comme si un fsync()
était exécuté).

Ni moi.
Perso, si je lis man fsync(2), on dirait bien que ça flush les
data et les metadata et qu'il y a fdatasync(), apparemment, pour
flusher uniquement les data (si j'ai bien compris).

Et les métadata directement liées (data blocks).
Au passage, j'ai lu ici ou là que O_DIRECT ne donnerait qu'une
« indication » au noyau en lui signalant qu'il n'est pas nécessaire
de cacher la data mais que le noyau peut parfaitement ne pas
respecter cette indication.

De mes vieux souvenirs d'avoir joué avec le buffer cache ~1999,
dans tous les cas il y a caching, la différence de O_SYNC c'est
qu'il y a écriture des blocs correspondants, et O_DIRECT n'est
pas forcément implémenté par l'ensemble des couches: VFS,
fs spécifique, block device.
Mais je dois dire que mes souvenirs sont vieux et pas à jour.
(pour la petite histoire j'avais écrit du code pour exporter
des raw devices ou des fichiers sous forme d'un LUN d'un
device SCSI ou fibre channel, et ça marchait, même: un peu
ce que le target subsystem fait je crois, aujourd'hui)
Avatar
Francois Lafont
On 05/29/2018 07:22 PM, Marc SCHAEFER wrote:
In article <5b0d1e51$0$31623$ you wrote:
Heu... ça veut dire quoi "y.c" ?

y compris?

Ah ok. :)
Et bien on dirait que c'est le contraire sur mes tests fio où
j'ai l'option --fsync=1 qui me plombe les perfs par rapport à
"--direct=1 --sync=1". Et je ne comprends pas pourquoi car pour
moi cela devrait être équivalent (étant donné que je lis dans
les pages man qu'avec O_SYNC tout se passe comme si un fsync()
était exécuté).

Ni moi.

Et j'en profite pour (re)dire que je serais vraiment très intéressé
d'avoir des éléments de réponses sur ce point.
Perso, si je lis man fsync(2), on dirait bien que ça flush les
data et les metadata et qu'il y a fdatasync(), apparemment, pour
flusher uniquement les data (si j'ai bien compris).

Et les métadata directement liées (data blocks).

Moi je lis : « but does not flush modified metadata unless that
metadata is needed in order to allow subsequent data retrieval
to be correctly handled. »
Au passage, j'ai lu ici ou là que O_DIRECT ne donnerait qu'une
« indication » au noyau en lui signalant qu'il n'est pas nécessaire
de cacher la data mais que le noyau peut parfaitement ne pas
respecter cette indication.

De mes vieux souvenirs d'avoir joué avec le buffer cache ~1999,
dans tous les cas il y a caching, la différence de O_SYNC c'est
qu'il y a écriture des blocs correspondants, et O_DIRECT n'est
pas forcément implémenté par l'ensemble des couches: VFS,
fs spécifique, block device.
Mais je dois dire que mes souvenirs sont vieux et pas à jour.

Dommage qu'on ait pas eu cette discussion en 1999. :p
(pour la petite histoire j'avais écrit du code pour exporter
des raw devices ou des fichiers sous forme d'un LUN d'un
device SCSI ou fibre channel, et ça marchait, même: un peu
ce que le target subsystem fait je crois, aujourd'hui)

Ah oui et maintenant c'est fini, tu ne codes plus ce genre de
choses ? Tu es devenu chef et c'est toi qui demandes aux autres
de coder. :p
Merci de ton aide.
--
François Lafont
Avatar
Marc SCHAEFER
Francois Lafont wrote:
Ah oui et maintenant c'est fini, tu ne codes plus ce genre de
choses ? Tu es devenu chef et c'est toi qui demandes aux autres
de coder. :p

Ca m'arrive de coder, mais c'est plutôt du perl et du bash
ces temps :) Et pour le reste, c'est un peu ce que tu dis!