Forum Programmation.c++ DMA en C++ ?

Posté par  .
Étiquettes : aucune
0
30
juin
2008
Bonjour,
Je travaille sur un logiciel qui va devoir copier des données de la mémoire vers le disque dur. Mettons des blocks de 200 Mega-octets.

Je me dis: mmm, je devrais utiliser un mécanisme de Direct Memory Access (DMA). Mais je n'ai aucune idées. Une recherche sur internet me donne surtout des posts traitant de problèmes de lenteurs de disque-dur, mais pas trop sur la manière de coder ça.

J'imagine que c'est un controlleur DMA qui s'occupe de ça. Comment lui "parler" pour lui faire envoyer des choses vers le disque ?

Merci!
  • # Euh ...

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

    Laisse le noyau se demerder lui meme avec le DMA, c'est déjà assez compliqué comme ca, et il le fait tres bien tout seul.

    Mais tu peux utiliser mmap(2), c'est beaucoup plus simple et je doute que niveau perf ce soit radicalement différent, et accessoirement t'as pas à gérer toi meme le systeme de fichier.
  • # File mapping

    Posté par  . Évalué à 3.

    Le contrôleur DMA relève du système d'exploitation, et est fortement lié à la gestion interne du filesystem, etc. Bref, c'est beaucoup plus que d'écrire un pilote, ce qui n'est déjà pas trivial. Si tu utilises de l'IDE, utilises hdparm pour voir si tes disques l'utilisent par défaut.

    Ensuite, tu peux faire du raw device. Avant, ça se fait en associant un /dev/raw/rawX à ton périphérique. Maintenant, c'est en passant l'option O_DIRECT à open().

    Par contre, d'après ce que je lis, il semblerait que ce qu'il te faille, c'est du file mapping. Vois du coté de $ man mmap. C'est un appel système, donc en C, aisément encastrable dans du code en C++.

    Bon courage.
    • [^] # Re: File mapping

      Posté par  . Évalué à 1.

      Merci pour vos reponses !
      Je ne sais pas trop si ce que je dois faire c'est du file mapping ou autre. En fait je fais cela:

      Je reçois des paquets UDP, je prend le payload et je rajoute un timstamp (l'heure) et l'adresse IP/port d'origine.

      Je stocke le tout en mémoire, et quand j'en ai suffisamment, je l'envois vers le disque.

      Le tout dans un thread, et il y a plusieurs threads qui font la même chose, avec bien sur un mecanisme pour qu'un seul thread a la fois ecrive sur le disque.
      • [^] # Re: File mapping

        Posté par  . Évalué à 1.

        mmm; apres avoir lu ces 2 liens en anglais:
        http://en.wikipedia.org/wiki/Mmap
        http://en.wikipedia.org/wiki/Raw_device

        Je pense aussi que je suis plus proche du file mapping (mmap) que du raw device...
      • [^] # Re: File mapping

        Posté par  . Évalué à 2.

        Tout dépend de ta charge réseau. À priori, un bête fopen de débutant doit suffire à tout faire puisque les fichiers ainsi ouverts sont dotés d'un tampon, vidés à intervalles définis par le système, et qui peuvent être flushés sur commande avec sync.

        Après, si tu reçois des milliers de paquets à la seconde, tu peux peut-être envisager autre chose.
        • [^] # Re: File mapping

          Posté par  . Évalué à 1.

          oui, je vais recevoir beaucoup de paquets: le debit est d'environ 20 Megabit/s, et ce, sur une dizaine de port different. Donc ça fait quand même 200 Mb/s. C'est pourquoi je dois les stocker en mémoire avant d'écrire, histoire de pas pourrir les perfs sur le disque: un seul fichier ouvert en même temps, puis on le referme.

          Je precise que ce sera une machine de guerre, comme PC. Un truc super puissant.
          • [^] # Re: File mapping

            Posté par  . Évalué à 2.

            Le mieux dans ces cas-là c'est du faire du multithread. : 1 thread par client, qui remplissent un buffer, et un thread qui s'occupe de vider le buffer dans le fichier. Ainsi si ponctuellement le disque "ralentit" (vis-à-vis du process), la RAM est mise à contribution, puis se vide quand le débit du disque remonte, si c'est le débit d'entrée qui diminue le buffer sera tout le temps vide - tant mieux. Si tu satures la RAM et que le disque ne suit pas, c'est pas la peine de chercher à optimiser le process (l'OS sait mieux que toi quelle resource est dispo à un moment donné), il faut changer le hard : passer sur plusieurs machines, mettre des disques plus rapides. etc...
            • [^] # Re: File mapping

              Posté par  . Évalué à 1.

              ah, pas mal comme idée ! Je pensais effectivement faire plusieurs thread, un par client, mais que ce soit eux qui vident leur memoire vers le disque.

              Ta solution de passer par un autre thread intermediaire qui pourrait faire tampon est une bonne idée! Un peu comme un graveur de CD.
              • [^] # Re: File mapping

                Posté par  . Évalué à 2.

                Exactement. Surtout que faire à la fois lire le flux et écrire sur disque dans le même thread est dangereux : si l'écriture disque prend trop de temps, les buffers de la couche réseau vont se remplir et provoquer des soucis en cascade aux niveaux des clients. Alors qu'en découplant les accés lecture/écriture, il est plus simple d'identifier et d'isoler le goulot d'étranglement.
                • [^] # Re: File mapping

                  Posté par  . Évalué à 2.

                  N'oubliez pas qu'au final, tous ces threads vont tourner sur la même machine et engendrer beaucoup d'overhead système ! Le multi-processus, c'est bien quand on fait du SMP. Pour le reste, ce n'est certainement pas une manière d'accélérer le travail en le distribuant, sauf en cas d'appel bloquant.

                  Étant donné que les machines récentes sont toutes hyper-threadées, je ferais exactement deux processus, qui partagent un buffer circulaire (le fameux graveur de CD). L'une en charge du disque, qui peut se permettre de l'attendre, et l'autre qui remplit le tampon.

                  Par contre, je pense quand même que la charge sera moins lourde si un seul processus lit tous les ports. Il y a un seul noyau et surtout, c'est la même carte réseau derrière pour tout le monde.
                  • [^] # Re: File mapping

                    Posté par  . Évalué à 1.

                    Addendum :

                    J'ajoute que si tu en es là, et que l'opération à faire sur les paquets est fort simple, largue le C++ et code directement en C. Tu économiseras beaucoup de ressources.
                    • [^] # Re: File mapping

                      Posté par  . Évalué à 1.

                      Pour ce qui est du C++, je serais assez tenté de passer en C comme tu le conseille.
                      Je fais des essais avec la librairie GNU Common C++, et je n'arrive même pas a compiler les fichiers exemples...

                      Mais bon, je suis au boulot, et je n'ai pas trop le choix.
                    • [^] # Re: File mapping

                      Posté par  . Évalué à 1.

                      L'économie de ressources, c'est de la poudre aux yeux à mon avis.

                      Pas de raison qu'un code aussi simple soit plus lent en C++ qu'en C.

                      C'est l'architecture du programme qui va déterminer son efficience.

                      Ici, en C ou en C++, c'est l'algorithme qui va jouer ...

                      De toute manière, je ne pense pas que tu t'y prennes correctement. Fais déjà un soft qui fonctionne avant de passer à son optimisation, pas l'inverse.

                      Par contre, pour l'architecture, évite d'utiliser du polymorphisme dynamique, car c'est d'ici que viendrait une éventuelle baisse de perf par rapport à un code en C. Mais de toute manière le sujet ne s'y prête peu.
        • [^] # Re: File mapping

          Posté par  . Évalué à 2.

          Justement, il ne faut pas tamponner dans ce cas, mais opérer directement avec les appels système open / write (puisqu'on dispose déjà d'une grande quantité de données).
          L'utilisation de open(O_DIRECT) a de multiples contraintes, mais pourrait être envisageable (à voir, économise une copie mémoire...).

          Pour "flusher" un fichier ouvert avec fopen(), c'est plutôt fflush() que sync. flush() envoie les données de l'espace utilisateur vers le noyau.

          "sync" n'est pas flush : sync écrit les données encore en RAM sur le support physique, pour TOUS les systèmes de fichiers : c'est très lourd (il existe fsync() pour faire cela par fichier). En l'occurrence, je ne sais pas si c'est ce que cherche à faire fabricius ?

          Deux threads suffisent : un premier qui fait select() ou epoll() sur les sockets + remplit la ram, et un second qui vide la ram sur le disque (modèle classique producteur / consommateur).
          Sauf architecture SMP, je ne pense pas que davantage de threads permettent de gagner en performance...
          • [^] # Re: File mapping

            Posté par  . Évalué à 1.

            Bon, apres une reunion hier, j'ai plus d'info. En fait j'aurais une dizaine de fichier d'ouvert, et j'y mettrais les données. Le but est de ne pas avoir a modifier la TOC en ouvrant pleins de fichiers. Donc au debut j'ouvre les fichiers (un par socket ecoutée) et ensuite je les remplis. Ca fera des gros fichiers a la fin mais ce n'est pas grave.

            Pour les 2 threads, effectivement, ca devrait suffire. Et ça evitera les changement de contexte, donc on devrait gagner en performance.
            • [^] # Re: File mapping

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

              Utilises write et read plutot que fread et fwrite qui bufferise en espace utilisateur par contre n'utilise surtout pas O_direct qui est fait pour faire sa propre couche de cache.

              Utilises des gros write (genre >> 1 Mo). Si tu maitrises ton systeme de fichier privilegies, utilises des gros cluster, ils sont plus rapide que les petits si tu as des gros fichiers.

              Logiquement, il sera plus rapide d'ouvrir une seul fichier que plusieurs, la tête du disque n'aura pas a bouger.

              Oublies mmap() qui ne permet pas de faire grossir un fichier.

              Fais gaffe que fseek utilise un entier 32 bits, cela peut poser des ennuis sur un fichier de plus de 2 Go.

              Le top des perfs devrait etre obtenu avec un thread lecteur qui utilise select() ou un equivalent (poll ?) et un thread d'ecriture.

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

              • [^] # Re: File mapping

                Posté par  . Évalué à 1.

                ah, je ne savais pas pour mmap !
                Effectivement, je maitrise mon systeme de fichier: c'est quelqu'un de mon equipe qui va s'occuper de l'installation de la distrib, une debian. Je vais lui demander d'adapter la taille des clusters pour que ça soit plus adapté aux gros fichiers.
                • [^] # Re: File mapping

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

                  Si tu as un disque et un contrôleur disque dédié pour le fichier, c'est encore mieux.

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

                • [^] # Re: File mapping

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

                  En fait, il y a bien une option pour ca.

                  Mais mmap se comporte toujours mal, si le fichier devient plus gros que la RAM par exemple.

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

              • [^] # Re: File mapping

                Posté par  . Évalué à 1.


                Logiquement, il sera plus rapide d'ouvrir une seul fichier que plusieurs, la tête du disque n'aura pas a bouger.


                C'est pas faux, mais la fragmentation peut réduire le bénéfice à 0. Difficile à "prédire" dans plus de précisions.
  • # splice ?

    Posté par  . Évalué à 1.

    Bonjour,

    Je me demande si ce genre de cas ne pourrait pas profiter de l'appel système "splice" qui permet de balancer des données d'un file descriptor (dans ton cas, ça serait ton socket) vers un autre file descriptor (le fichier sur disque), sans avoir besoin de recopier des données entre userland et kernel.

    http://en.wikipedia.org/wiki/Splice_(system_call)

    J'avoue que je n'ai jamais utilisé, et ça ne marche que si tu veux recopier de la donnée "brute".
    • [^] # Re: splice ?

      Posté par  . Évalué à 1.

      merci pour cette info, mais ca n'ira pas, je ne veux pas recopier de la données brute.
      • [^] # Re: splice ?

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

        Cela peut être intéressant si tu copie les donnes en brut et qui te créer un fichier d'index avec les meta données a coté.

        Si tu as 2 systèmes de fichiers (2 disques, 2 controleurs), un pour les donnes et un pour l'index, cela permet de gagner en perf brut.

        "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.