Journal [SSD] Mesure de la latence d'écriture aléatoire sur disque

Posté par  (site web personnel) .
Étiquettes : aucune
5
2
avr.
2009
On trouve de plus en plus de SSD sur le marché. Il annonce une bande
passante mais surtout une latence très faible.

Dans les faits, la latence d'écriture peut devenir importante, certain
SSD pouvant tomber à 2 IO/s soit une latence de 500ms ! C'est la
technologie flash avec des besoins d'effacement de secteur entier qui
pose cette limite.

Pour trouver un bon SSD, il faut donc surtout tester sa capacité à gérer
les petites écritures. On ne compte plus en bande passante mais en
latence pour gérer un petit paquet.

J'ai écrit un petit benchmark, qui génère des écritures de un octet à
des adresses aléatoires. On spécifie le nom d'un fichier et sa
taille. Cette taille doit être grande pour ne pas rester dans les
mémoire cache (typiquement 1 Go). Le bench gère les fichiers de plus
de 2Go. Le programme va générer une série de 1000 ios sur lequel il
fait une moyenne. Il maintient aussi la moyenne, le min et le max sur
toute la session de test.

L'écriture se fait sur une taille de 1 octet, vu que les clusters du
fichier font de 512 à 4K, une lecture s'effectue avant
l'écriture. N'ayant pas de contrainte d'alignement, cela pourrait aussi
arriver avec des écritures plus importantes non alignées.

J'ai mis une limite de 30 lots de 1000 ios. En effet, avec une boucle
infinie, si je tue le process, le fichier dans lequel je redirige la
sortie écran se retrouve vide.

La sortie est formaté comme un fichier csv, avec la moyenne des 1000
ios puis le minimum, la moyenne global, et le max.

Frequency of RDTSC: 2838955030 Hz
io/s means over 1000 io, min, overal means, max
93505.65, 0.09, 1005.33, 570988.54
92314.63, 0.09, 1057.63, 570988.54

Les chiffres les plus intéressants, sont la moyenne global et le
nombre minimum d'io. La moyenne local peut servir à faire de jolie courbe.

Le bench sous forme de fichier C à compiler avec un
$ gcc -O2 -o wio wio.c

http://f-cpu.seul.org/~nico/wio.c
  • # résultats bizarre sur un disque rotatif SATA :

    Posté par  . Évalué à 3.

    ./a.out 1000000000 tt

    io/s means over 1000 io min overal means max
    21246.18 615.57 21246.18 110265.64
    16874.82 62.26 18809.86 115627.99
    23070.14 62.26 20043.66 118643.06
    17840.42 62.26 19443.36 118643.06
    19275.56 62.26 19409.57 118797.94
    18703.09 62.26 19288.14 120790.57
    19980.66 62.26 19384.12 120790.57
    20039.53 62.26 19463.69 120790.57
    20909.80 62.26 19614.41 123487.72
    20805.56 62.26 19727.36 123487.72
    22679.64 62.26 19963.60 123487.72
    15101.66 62.26 19442.00 123487.72
    20529.50 62.26 19521.54 123487.72
    20776.91 62.26 19606.16 126164.79
    23366.93 62.26 19818.81 126164.79
    22083.77 62.26 19946.67 126164.79
    23606.28 62.26 20130.24 126435.71
    23297.72 62.26 20283.44 126435.71
    23631.61 62.26 20435.83 126435.71
    24039.90 62.26 20590.18 126435.71
    23733.17 62.26 20720.85 126435.71
    25495.10 62.26 20898.73 126435.71
    0.00 0.00 0.00 126435.71
    2964.02 0.00 0.00 126435.71
    20047.00 0.00 0.00 126435.71
    26890.95 0.00 0.00 126435.71
    27110.81 0.00 0.00 126435.71
    28299.50 0.00 0.00 129310.36
    27315.60 0.00 0.00 129310.36
    27930.48 0.00 0.00 129310.36

    pourquoi plein de zéros à la fin?

    ⚓ À g'Auch TOUTE! http://afdgauch.online.fr

    • [^] # Re: résultats bizarre sur un disque rotatif SATA :

      Posté par  (site web personnel) . Évalué à 3.

      Cela sent le bug. 0.0 est impossible, c'est le nombre io/s, je fais 1000 io et je divise le temps pris par la fréquence.

      En tout cas, c'est une machine de cinglé ton truc pour avoir des chiffres pareil. C'est un SSD intel ?

      "La première sécurité est la liberté"

      • [^] # Re: résultats bizarre sur un disque rotatif SATA :

        Posté par  (site web personnel) . Évalué à 2.

        Il y a une autre explication. Dans un but de clareté, j'ai coupé à 2 chiffres après la virgule.

        Si tu as un gros système RAID, les données remplissent des caches. Ensuite, il faut tout vider, ce qui peut être très long.

        Vu que cela touche le min et la moyenne, je penche pour une IO qui dure très longtemps. Genre 100s. Cela explique un chiffre comme 0.001 io/s. Et cela explique que la moyenne aussi soit touché.

        "La première sécurité est la liberté"

      • [^] # Re: résultats bizarre sur un disque rotatif SATA :

        Posté par  . Évalué à 3.

        NAN, un disque rotatif tout bête de 80 Go ;-)

        ⚓ À g'Auch TOUTE! http://afdgauch.online.fr

  • # Bug !!

    Posté par  . Évalué à 5.

    printf("%.2f, %.2f, %.2f, %.2f\n",(double)(rdtsc_freq)/((tmoy)/1000.0),
    (double)(rdtsc_freq)/(tmax),
    (double)(rdtsc_freq)/((tgmoy)/(double)ios),
    (double)(rdtsc_freq)/(tmin));

    Dus à tes parenthèses, les divisions effectué ici sont des divisions entières, car tmoy et tgmoy sont des entiers 64. Le calcul étant réalisé avec le type du membre gauche.
    • [^] # Re: Bug !!

      Posté par  . Évalué à 2.

      Autre remarque, tu mesures le temps complet de la boucle, alors que tu ne devrais mesurer que l'io. mettre un get_tick avant et après le write, et enlevé le temps moyen d'execution du get_tick.
      • [^] # Re: Bug !!

        Posté par  . Évalué à 2.

        Encore une autre :-D,
        Tu ne réinitialises que la moyenne entre deux essais, ce qui signifie que ton min et ton max sont sur l'ensemble du test, et pas que sur le test en cours. Est-ce voulu ?
      • [^] # Re: Bug !!

        Posté par  (site web personnel) . Évalué à 2.

        Non, cela serait une erreur. Les ios disques continue en arrière plan. De plus le lseek peut prendre aussi du temps. Je considère le temps passé dans les quelques calculs de la boucle sont complètement négligeable devant les IOs.

        Un get_tick doit prendre 32 cycles...

        "La première sécurité est la liberté"

    • [^] # Re: Bug !!

      Posté par  . Évalué à 2.

      Je vais encore m'auto-répondre.

      Pour tester j'ai écris ce programme.

      #include <stdio.h>

      int main(void)
      {
      int _a;
      double _r, _val, d_a;

      _a = 3;
      d_a = 3.0;
      _val = 1.5;

      _r = _a / _val;
      printf("_r = %2.5f (int) / (double)\n",_r);

      _r = d_a / _val;
      printf("_r = %2.5f (double) / (double)\n",_r);

      return 0;
      }

      D'après mon explication ci-dessus, dans le premier cas _r devrait valoir 3.0, car _a / _val est (int) / (double) donc je m'attendais à (int) / (int) or le cast de 1.5 en int donne 1, donc 3 / 1 = 3 puis cast vers double 3.0.
      Avec le gcc ici 3.3.1 il me donne 2.0 aussi.

      J'ai cherché dans la norme C, et rien trouvé d'intéressant. Il semble y avoir un flou dans le cas des opérateurs utilisés avec deux types différents. Cela dépend-il du compilateur ? Est-ce un cas indéterminé ? gcc semble utiliser le type le plus précis. Quelqu'un a t'il la possibilité de tester avec un gcc 2.95 ?

      Si quelqu'un a une réponse, je suis preneur.
    • [^] # Re: Bug !!

      Posté par  . Évalué à 5.


      printf("%.2f, %.2f, %.2f, %.2f\n",(double)(rdtsc_freq)/((tmoy)/1000.0),
      (double)(rdtsc_freq)/(tmax),
      (double)(rdtsc_freq)/((tgmoy)/(double)ios),
      (double)(rdtsc_freq)/(tmin));

      Dus à tes parenthèses, les divisions effectué ici sont des divisions entières, car tmoy et tgmoy sont des entiers 64. Le calcul étant réalisé avec le type du membre gauche.


      Pas du tout, efface. Il suffit qu'un des deux membres d'une operation soit un double pour que l'opération soit faite en double. Il n'y a que si les deux opérandes sont des entiers qu'on a affaire à une opération entière.

      Heureusement, d'ailleurs.
      • [^] # Re: Bug !!

        Posté par  . Évalué à -1.

        Ok, sur quoi tu te bases pour l'affirmer ?

        Ne me dis pas essaye, car tu prouves le comportement de tel compilateur.

        Il y a des tas de cas ou la norme est floue :

        a = 2 * b++ - --b + c --;

        maFct(fonctAApellerEnPremier(b),fonctAApellerEnDeuxieme(a));

        etc.

        Dans le premier cas, je connais plusieurs comportement, pour la deuxième sur une station SUN, la "fonctAApellerEnDeuxieme" sera en fait appeller la première.

        Dans le cas de la formule, si on met b = 2 et c = 10 alors gcc applique :
        2 * 2 - 1 + 9 = 13.
        Mais qui dis que le -- pre doit s'appliquer que à ce membre ? Et pas a toute l'expression ?
        2 * 1 - 1 + 9 = 11 ?
        • [^] # Re: Bug !!

          Posté par  . Évalué à 1.

          La norme du C dit qu'il y a promotion d'entier vers flottant si au moins l'un des opérandes en présence est lui-même un flottant. Comme en plus il n'y a pas de garantie sur l'ordre des opérations (sauf si on met des parenthèses), ça s'applique à toute l'expression.
          • [^] # Re: Bug !!

            Posté par  (site web personnel) . Évalué à 2.

            L'ordre est définit même sans parenthèse.

            a=b+c+d+e+f;

            c'est a=((((b+c)+d)+e)+f);

            "La première sécurité est la liberté"

          • [^] # Re: Bug !!

            Posté par  . Évalué à 2.

            Effectivement, le paragraphe 6.3.1.8 semble explicite. (j'utilise un des derniers draft de la norme C99) :
            Many operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. The purpose is to determine a common real type for the operands and result. For the specified operands, each operand is converted, without change of type domain, to a type whose corresponding real type is the common real type. Unless explicitly stated otherwise, the common real type is also the corresponding real type of the result, whose type domain is the type domain of the operands if they are the same, and complex otherwise.

            Je vois pourtant régulièrement des erreurs du type que j'ai décrite. Donc, je ne comprends pas. Soit le comportement dans la norme c89 est différent, soit les compilateurs sont mal écris.

            Comme en plus il n'y a pas de garantie sur l'ordre des opérations (sauf si on met des parenthèses), ...
            L'ordre des opération est parfaitement défini dans le cas d'une expression, il est indéfini uniquement dans le cas des paramètres d'une fonction.
            ex:
            if ((monPointeur != NULL) && (*monPointeur != 42)) est parfaitement valide, car la norme garanti que si la première partie est fausse, la seconde n'est pas évalué.
            • [^] # Re: Bug !!

              Posté par  (site web personnel) . Évalué à 1.

              Comme en plus il n'y a pas de garantie sur l'ordre des opérations (sauf si on met des parenthèses), ...

              L'ordre des opération est parfaitement défini dans le cas d'une expression, il est indéfini uniquement dans le cas des paramètres d'une fonction.


              Non, vous confondez plusieurs choses là

              - la construction de l'arbre d'expressions, fixée par la grammaire et sur laquelle on peut intervenir avec des parenthèses

              - l'évaluation des expressions ; l'ordre d'évaluation des sous-expressions et surtout le déroulement des effets de bords ne sont pas spécifiés, sauf pour certaines expressions contenant des points de séquencement (par ex. && || ?:)
        • [^] # Re: Bug !!

          Posté par  . Évalué à 2.

          Ok, sur quoi tu te bases pour l'affirmer ?

          Ne me dis pas essaye, car tu prouves le comportement de tel compilateur.

          Il y a des tas de cas ou la norme est floue :

          a = 2 * b++ - --b + c --;

          maFct(fonctAApellerEnPremier(b),fonctAApellerEnDeuxieme(a));


          Faux.
          La norme n'est pas floue, elle dit spécifiquement que ces cas sont "undefined", ce qui signifie que l'implémentation est libre de faire ce qu'elle veut.
          En d'autres termes
          int a = 41;
          a = a++;
          printf("%d\n", a);


          Peut aussi bien sortir "42" que "quarante deux". Ces expressions sont incorrectes.
          • [^] # Re: Bug !!

            Posté par  . Évalué à 3.

            42 ou quarante deux ? Impressionnant /o\

            Tous les nombres premiers sont impairs, sauf un. Tous les nombres premiers sont impairs, sauf deux.

  • # Intéressant

    Posté par  . Évalué à 1.

    Je trouve l'outil super intéressant.

    Mais j'ai du mal à comprendre son fonctionnement (le C n'est pas mon fort).

    Je peux l'utiliser sur un SSD qui est déjà formaté? (i.e. je ne vais pas tout perdre?)

    De plus, je suis aussi très déçu des perfs des SSD en général :/

    On nous a annoncé monts et merveilles et au final, les perfs sont hypra décevantes (de manière totalement subjectives).
    • [^] # Re: Intéressant

      Posté par  . Évalué à 1.

      Dans ton terminal, tu lances :
      $ wio leNomDeFichierQueTuVeux.avecUneExtensionSiTuVeux

      Sinon, faire des accès aléatoires de se type met à genoux n'importe quel disque. Le même test avec les fonction fread, etc. du C qui bufferise les accès donne de meilleurs résultat.

      Généralement, dans une application classique, on utilise pas le disque de cette manière, donc, c'est un bench, il n'est représentatif d'aucune application, ou d'usage normal connue d'un disque.
      • [^] # Re: Intéressant

        Posté par  (site web personnel) . Évalué à 2.

        $ wio lataillequetuveux leNomDeFichierQueTuVeux.avecUneExtensionSiTuVeux

        :)

        C'est bien un bench. A priori, un pire cas pour les SSD.

        "La première sécurité est la liberté"

    • [^] # Re: Intéressant

      Posté par  (Mastodon) . Évalué à 2.

      Pour les perfs, il y a d'énormes différences d'un modèle à l'autre. Il existe d'excellents SSD (Intel, Samsung, certains OCZ), mais à côté de ça, il y a énormément de bouses pratiquement inutilisables en raison de latence en écriture particulièrement haute (c'est justement ce qu'on essaie de mesurer ici)

      Les débits annoncés par les constructeurs et repris par la plupart des tests qu'on trouve sur le web n'ont à peu prêt aucun intérêt. Ce qui fait la puissance d'un SSD, plus que les débits, c'est avant tout une latence de l'ordre du dixième de miliseconde. Les mauvais SSD peuvent avoir des latences qui grimpent à plus d'une seconde quand il y a beaucoup d'écritures sur des petits fichiers, ce qui provoque des "freezes" du système.
      • [^] # Re: Intéressant

        Posté par  . Évalué à 2.

        En fait j'ai installé une distrib sur USB.

        Si je l'installe sur un disque dur IDE à bons vieux plateaux et un cable IDE <-> USB, j'ai des performances tout à fait correctes.

        J'ai testé sur une clé USB. Les performances sont devenues abominables. Genre j'édite un fichier sous vi, et la machine entière freeze pendant 3 à 4s.
        Firefox est inutilisable.
        Je me suis rendu compte que le défaut venait de la clé USB en elle-même: ses perfs sont catastrophiques sous linux, catastrophiques sous mac OS et excellentes sous windows (je ne comprends pas pourquoi).
        Bench, copier une image ISO sur la clé formattée en FAT32:
        linux: 20mn
        mac OS: 20mn
        windows: 1mn

        J'ai essayé avec une seconde clé USB aui a des débits corrects sous linux.
        -> Même résultats catastrophiques! Le temps de boot a été multiplié par 8 ou 10 entre cette clé et le disque IDE en USB. J'ai supprimé le journal d'ext3 et le boot en ext2 s'est accéléré, mais pas de beaucoup :/

        Je vais faire un test en jffs (ou autre chose, vous coneillez quoi comme fs autre qu'un de la série d'ext?), mais je veux savoir si j'ai des chances que ça fonctionne mieux?

        Je voulais faire un test avec cet outil sur le disque IDE en USB et sur ma clé pour voir s'il y a une grosse différence; de plus, si cet outil me permet de faire pleins de tests qui me permettront de savoir quel est le meilleur fs ET quelle est ma meilleure clé, je prends! :)
        • [^] # Re: Intéressant

          Posté par  (Mastodon) . Évalué à 3.

          Une clé USB n'est pas un bon exemple de SSD. Même si les puces de mémoire flash sont sans doute plus ou moins les mêmes, le contrôleur n'a rien à voir, et c'est à ce niveau qu'on trouve les plus grosses différences entre un bon et un mauvais SSD. Une clé USB a certainement un contrôleur extrêmement primitif, et je ne pense pas que ça soit une bonne idée de l'utiliser pour autre chose que du transport de fichiers d'une machine à l'autre.
        • [^] # Re: Intéressant

          Posté par  (Mastodon) . Évalué à 5.

          Bench, copier une image ISO sur la clé formattée en FAT32:
          linux: 20mn
          mac OS: 20mn
          windows: 1mn


          es-tu sur de ton bench ? ce n'est pas parce que windows te rend la main que la copie est finie.

          As-tu essayé de démonter la clé après 1 minute ? En général sous windows ça ne marche pas car même s'il t'a annoncé avoir copié le fichier, il est toujours en train de l'écrire.
          • [^] # Re: Intéressant

            Posté par  . Évalué à 1.

            es-tu sur de ton bench ?

            oui. J'ai fait plusieurs fois le test sur du XP et du Vista. Et le fichier est bien copié, je peux supprimer la clé (et monter l'ISO dans mon cas).

            J'ai testé différentes manières sur linux et sur Mac, mais c'est bien toujours cette durée. J'ai vérifié que c'est bien de l'USB2 (c'en est), mais pas moyen. Avec une autre clé sur le même linux, çest 20x plus rapide.

            Je n'ai pas vraiment trouvé d'explications, mais je suis super déçu de mon achat (pas de windows chez moi, que du MAC et du linux), donc bon, se retrouver avec une clé qui se traine comme une tortue rhumatisante, bof :/
  • # État du SSD ?

    Posté par  (site web personnel) . Évalué à 3.

    // The goal is to measure the worst case latency of write, this is the most demanding task
    // of an SSD.


    Certains SSD sont très sensibles à leur état : les performances peuvent énormément se dégrader s'il a été rempli ou non (et la manière dont il a été rempli peut influer aussi : écritures aléatoires ou écritures séquentielles).
    Donc les résultats obtenus avec ce bench ne seront pas forcément reproductibles sur les disques en question, et pas non plus le pire cas (c'est entre autre expliqué dans ce papier "Understanding Flash IO patterns" : http://www-db.cs.wisc.edu/cidr/cidr2009/Paper_102.pdf ).

    Et sinon, j'ai quand même un doute sur le code, vu que le cache du kernel n'est pas désactivé, et l'ordonnanceur des IO n'est pas forcé à 'noop', donc je suppose qu'il peut un peu réorganiser les IO dans l'ordre qu'il veut, ce qui doit influencer les résultats, non ?
    • [^] # Re: État du SSD ?

      Posté par  (site web personnel) . Évalué à 2.

      Le plus complexe lors de l'écriture d'un bench est de savoir très exactement ce que tu benches.

      Pour s'y retrouver et ne pas être dans un cas encore plus éloigné de la réalité, je suis rester simple : un lseek64+un write et rien d'autre.

      J'ai choisi de ne pas utiliser le fwrite() qui rajoute encore une couche de buffer.

      Toute la chaines influence les résultats : le kernel avec sa couche vfs et son cache, le scheduler io,le système de fichier, le controleur hw, et finalement la mémoire de masse.

      Si on veut des testes reproductibles, il faut spécifier l'état du système. On peut rajouter une lecture de l'état du scheduler ou le taux de remplissage du disque.

      "La première sécurité est la liberté"

      • [^] # Re: État du SSD ?

        Posté par  (site web personnel) . Évalué à 1.

        On peut rajouter une lecture de l'état du scheduler ou le taux de remplissage du disque.

        Je parlais surtout de l'état de la nand en dessous : si tu dois te farcir un copy+erase+write (de l'ordre de la ms) ou juste un write (de l'ordre du 1/10e de ms).
        • [^] # Re: État du SSD ?

          Posté par  (site web personnel) . Évalué à 2.

          Disons que c'est la personne qui test qui décide. Je voulais aussi faire un truc rapide.

          Faire une campagne de test complet demande du matos vierge, et un temps fou. Là, c'est plus rapide, mais il faut maitriser l'environnement pour comparer.

          "La première sécurité est la liberté"

  • # La lecture indispensable :

    Posté par  (site web personnel) . Évalué à 6.

    C'est ce test de Anand Lal Shimpi (merci au blog de Linus pour le lien) :
    http://www.anandtech.com/storage/showdoc.aspx?i=3531

    Après ça, on comprend tout sur le fonctionnement des SSD. Prévoyez du temps, l'article fait 31 pages mais est le meilleur sur le sujet que j'aie pu lire. Voir notamment les bench en bande passante en lecture/écriture aléatoire (voir surtout l'écriture !)
    http://www.anandtech.com/storage/showdoc.aspx?i=3531&p=2(...)

    Et pour la latence, le cas désastreux des SSD à base de contrôleur JMicron, qui peuvent atteindre 0,5s de latence en moyenne !
    http://www.anandtech.com/storage/showdoc.aspx?i=3531&p=1(...)

    Au final, pour ceux qui ont des sous, prenez du Intel X-25, et pour moitié moins cher du Go, vous avez les OCZ Vertex (moins performants mais sans les défauts rédhibitoires des JMicron).
    • [^] # Re: La lecture indispensable :

      Posté par  (site web personnel) . Évalué à 3.

      Ah, au fait, le gars précise un peu son protocole de test pour l'écriture aléatoire (blocs de 4ko) et utilise pour les mesures iometer : http://www.iometer.org/
      • [^] # Re: La lecture indispensable :

        Posté par  (site web personnel) . Évalué à 2.

        J'avais vu ce genre de test. Je voulais vraiment avoir un test avec un bloc de 1 octets seulement.

        Je suis d'accord que je teste plus que la vitesse du SSD. Mais si le sous-système disque du kernel est mauvais le SSD ne sert à rien.

        L'intéret d'utiliser un fichier de vouloir faire ce que l'on veut.

        Si on veut tester un disque en raw, on peut attaquer directement /dev/sd??

        Ou encore, on peut tester avec des remplissages progressifs du disque.

        Et surtout on peut tester, sans vider son disque actuel.

        "La première sécurité est la liberté"

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.