Forum Programmation.c difference entre mmap() et read()

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
3
23
avr.
2019

Bonjour à tous,

voila si je veux lire un fichier je peux faire :

int fd = open("fichier_a_lire.txt", O_RDONLY);

et ensuite je peux faire :
read(fd, buffer, 256);

ou faire
void* addr = mmap(NULL,length_of_fichier_a_lire,…, fd, 0);
strncpy( buffer, addr, 256);

mais c'est quoi le mieux?
dans les deux cas le fichier est chargé en RAM par le noyau via l'appel systeme open, donc pourquoi s’embêter avec mmap ?

merci de vos éclaircissements

  • # quelques pistes ...

    Posté par  . Évalué à 5. Dernière modification le 23 avril 2019 à 18:17.

    Pour un usage classique (aka lire un fichier), je suis pas sûr en effet qu'il y ai un grand intérêt: c'est à ta convenance mais aussi et surtout en fonction du système hôte car il faut se souvenir que linux tourne sur du hard embarqué avec parfois très peu de RAM: dans ce contexte, mapper l'intégralité d'un fichier en mémoire est parfois impossible.

    Pour tout les usages ou tu vas préferer utiliser un pointeur (plus souple, te permet de te ballader facilement) plutôt qu'un fd (séquentiel, rewind & co), mmap sera probablement plus adapté.

    De mémoire, mmap() peut aussi être utilisé pour de la communication interprocess… (genre j'ouvre un shm qui me donne un fd, puis je mappe ce fd à coup de mmap et hop, j'ai un pointeur partagé entre mes deux process).

    En espérant t'avoir déjà donné quelques éléments …

    • [^] # Re: quelques pistes ...

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

      En tout cas, si c'est juste pour faire une copie du mapping dans un autre buffer( ici le strncpy) , ça ne sert pas à grand chose.

    • [^] # Re: quelques pistes ...

      Posté par  . Évalué à 2.

      De mémoire, mmap() peut aussi être utilisé pour de la communication interprocess…

      read aussi, vu que les sockets AF_UNIX sont des mécanismes d'IPC.

      Bon, j'avoue, cette remarque est un prétexte pour te poser d'autres questions:

      linux tourne sur du hard embarqué avec parfois très peu de RAM: dans ce contexte, mapper l'intégralité d'un fichier en mémoire est parfois impossible.

      Donc, mmap serait moins efficace dans ces cas que read? Cela n'impliquerait-il pas d'avoir une configuration pour read adéquate?
      Je suis réellement curieux, étant à la croisée entre de vieux souvenirs de cours, ma démerde pendant une décennie, et un taf qui me demande maintenant de faire de l'IPC…

      Pour ajouter de l'eau à ton moulin, dans ton sens, si tu mappes une zone mémoire entre deux processus, il va aussi te falloir gérer les accès concurrentiels, et du coup, utiliser un socket est nettement plus simple (c'est, en gros, un pipe), mais sera effectivement plus lourd qu'un mémoire partagée entre 2 processus.

      • [^] # Re: quelques pistes ...

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

        Pour ajouter de l'eau à ton moulin, dans ton sens, si tu mappes une zone mémoire entre deux processus,
        il va aussi te falloir gérer les accès concurrentiels,
        et du coup, utiliser un socket est nettement plus simple

        Cela reste du traitement par flux.
        C'est assez peu adapté lors de gros échanges de données et lorsque que l'on doit pouvoir se positionner dans la zone (fseek/lseek). Je pense en particulier aux traitements vidéo où l'on doit entrelacer et dé-entrelacer des blocs.
        C'est là que l'on utilise mmap, associé à une mémoire partagée (shm_), par exemple.
        S'il s'agit d'un fichier, on peut aussi partager le descripteur de fichier via une socket unix.

        Bref, sans plus de détails, on ne pas dire ce qui est "mieux".


        Et si l'on cherche à atteindre ou améliorer des performances (consommation et/ou vitesse), il faut faire des mesures.

      • [^] # Re: quelques pistes ...

        Posté par  . Évalué à 3.

        read aussi, vu que les sockets AF_UNIX sont des mécanismes d'IPC.

        Yep, tout à fait.
        Après, j'imagine qu'un segment de mémoire partagé est peut être plus performant qu'une socket (mais ce n'est que présomption)

        Donc, mmap serait moins efficace dans ces cas que read? Cela n'impliquerait-il pas d'avoir une configuration pour read adéquate?

        Bein, à mon taf on a du hard avec 8MiB de RAM. Autant te dire que mapper un fichier ne serait ce que de 1 ou 2 MiB à coup de mmap() met un vilain coup au système :-)

        Pour ajouter de l'eau à ton moulin, dans ton sens, si tu mappes une zone mémoire entre deux processus, il va aussi te falloir gérer les accès concurrentiels, et du coup, utiliser un socket est nettement plus simple (c'est, en gros, un pipe), mais sera effectivement plus lourd qu'un mémoire partagée entre 2 processus.

        Bien sûr, mais disons que le segment de mémoire partagé ne t'impose pas un scénario/protocole de communication contrairement au socket (aka proc-A envoie un message X à proc-B et bloque ensuite en l'attente d'une réponse Y).
        A l'inverse, l'utilisation de sendmsg() avec un socket peut faciliter le développement (puisque les messages transmis sont directement mappable sur une structure C)… chose qui reste cependant possible avec un mmap() en utilisant un cast.

        Puisque le fond de ton message semble concerné l'IPC, je vais dériver un peu sur ce sujet.
        A mon humble opinion, il n'y a pas de solution miracle ou d'IPC à tout faire. En vrac et sans être exhaustif, je dirai que:

        • Si tu veux qu'un processus X offre un "service" à un process Y sans connaitre Y au préalable, je partirai sur des sockets unix en effet.

        • Si tu veux échanger des données que tu vas au préalable manipuler à coup de transformation de pointeur, mmap() est probablement plus adapté.

        • Si le système cible est performant (au minimum une carte avec un ARM AXX), je partirai sur un composant plus haut niveau:

          • dbus est puissant mais particulièrement pénible à utiliser.
          • LCM et ZCM sont pas mal, plutôt performant mais s'appuie sur du code généré à partir de description textuelle des messages… faut aimer.
          • ubus est un système d'ipc light: pas énormément de fonctionnalité, mais ça peut suffire.
          • … il y en a d'autres .. à toi de voir ;-)

        Pour conclure, en 2019, je m'embêterai pas à écrire moi même un système d'IPC à moins que:
        * Ce soit un délire personnel, pour le plaisir (mais faut être un peu maso ;-).
        * Le système cible soit vraiment très contraignant (peu de RAM en particulier).

  • # mmap vs malloc

    Posté par  (Mastodon) . Évalué à 4. Dernière modification le 24 avril 2019 à 08:29.

    De ce que j'ai compris, mmap sert aux gros fichiers. En effet, avec mmap tu n'as pas de mise en mémoire du fichier, il n'y a pas de malloc gigantesque. C'est le kernel qui ira lire quand il le faut les données sur le disque (par page mémoire ?), mais toi tu te contentes de gérer "comme si" tout était mis en RAM.

    Dans le cas de 256 octets que tu veux absolument mettre en RAM, aucune utilité, fais simplement un read, ne serait-ce que parce que c'est bcp plus lisible comme code.

    A vérifier, je suis pas spécialiste, mais je n'ai vu mmap utilisé que sur des gros fichiers en tous cas.

    En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

    • [^] # Re: mmap vs malloc

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

      C'est à peu près ça.

      Le problème avec open+read, c'est que tu vas typiquement faire :

      fd = open(...);
      buffer = malloc(...);
      read(fd, buffer, ...);
      

      Le contenu du fichier apparaîtra deux fois en RAM : une fois dans le cache, au niveau du kernel, et une fois dans le processus, pour la variable buffer. Avec mmap, c'est la même RAM physique qui est utilisée pour le cache pour la mémoire de travail du processus (une lecture à un endroit du fichier qui n'est pas encore chargée en RAM va déclencher un chargement dans le cache, une écriture va écrire dans le cache qui sera écrite sur disque un peu plus tard). Bien sûr, ça veut aussi dire que si on écrit dans cette zone de RAM, on écrit directement dans le fichier, donc ça n'est pas applicable si on veut faire des modifications locales non-visibles par les autres processus.

    • [^] # Re: mmap vs malloc

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

      A vérifier, je suis pas spécialiste, mais je n'ai vu mmap utilisé que sur des gros fichiers en tous cas.

      Ce n'est pas la taille qui compte.

      Ou plutôt, c'est aussi utile si l'on veut éviter de multiplier les appels à read.

Suivre le flux des commentaires

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