URL: https://linuxfr.org/forums/programmation-c--2/posts/performances-de-memcpy Title: Performances de memcpy ??? Authors: khivapia Date: 2010年02月08日T23:23:10+01:00 Tags: debian Score: 8 Bonjour chers lecteurs du forum, Une petite question me tarabuste : je viens de découvrir le benchmark tout simple mbw (pour memory bandwith) qui teste les performance de la machine pour ce qui est de la mémoire. Il est disponible sous debian testing ou à l'adresse [http://linux.softpedia.com/progDownload/MBW-Download-12167.h(...)](http://linux.softpedia.com/progDownload/MBW-Download-12167.html) il n'y a pas plus simple : un simple fichier C à compiler). Il s'agit d'allouer un tableau d'entiers, et de le copier le plus vite possible vers un autre tableau. Le test mesure la vitesse de copie. De manière basique on précise simplement la quantité (en Mo) de mémoire à utiliser pour le test, par exemple 200: ./mbw 200 (utilisera au total 400 Mo, hé oui si vous avez suivi il faut 200 Mo pour l'original et 200Mo pour la copie). Essentiellement 3 tests sont disponibles * le premier, un memcpy tout bête, source -> destination pour la quantité donnée initialement * le deuxième, une copie _a la mano_ du type for (...) { dest[i] = src[i] } * le dernier, un memcpy par blocs de taille prédéfinie (quelques dizaines de Ko). Les résultats (sur différentes machines, architectures variées 64 et 32 bits, amd et intel, datant des années 2003 à aujourd'hui, distributions variées avec une dominante debian) sont éloquents: Dans tous les cas, le memcpy tout seul est le plus mauvais. La copie naïve met entre 1,5 et 2.5 fois moins de temps que memcpy (suivant les architectures). Le memcpy par blocs de quelques ko est infiniment plus rapide que les autres (de l'ordre de 8 fois plus rapide que le memcpy standard, surtout si on tune la taille du bloc). Alors on pense immédiatement à des effets de cache, ce qui se conçoit pour le memcpy par blocs (quelques dizaines de ko = taille du cache L1 par exemple). Ce que confirme valgrind --tool=cachegrind par exemple (même en tunant les paramètres pour le faire ressembler aux machines à ma disposition, x86info --cache est votre ami). Les optimisations du compilateur n'entrent pas en jeu (en -O0 comme en -O3 comme avec -march=native ou non ne change pas grand-chose). J'exclus également les mécanismes de prefetch hardware qui pour les données n'existent que depuis peu (pas vraiment sur les anciens processeurs en tous cas). En revanche, rien ne m'explique pourquoi la copie naïve est plus rapide que le memcpy. Les résultats de cachegrind ne font pas apparaître de différences flagrantes dans l'utilisation du cache, pourtant la différence est réelle... C'est pourquoi je vous pose la question ! D'ailleurs memcpy ne devrait-il pas (ou le compilateur quand il compile memcpy) faire attention au cache en choisissant une taille de copie convenable ? pas forcément optimale mais convenant à une majorité de processeurs actuels, et l'utiliser comme le fait la version par blocs de la copie, un peu comme fait gparted quand on copie des partitions, pour ce qui est de la taille de bloc à prendre. Notons que ce benchmark est assez spécifique bien entendu. Dans d'autres applications plus orientées calcul j'ai déjà vu memcpy faire gagner pas mal de temps. Mais là j'ai vraiment du mal à m'expliquer le résultat, même en ayant relu [http://people.redhat.com/drepper/cpumemory.pdf](http://people.redhat.com/drepper/cpumemory.pdf) En résumé deux choses sont étonnantes de mon point de vue : 1) le manque de tenue de memcpy par rapport à la copie naïve. On mesure quand même bien l'appel le plus simple qui peut être fait de ces fonctions ! Et la différence est significative. Alors certes il ne s'agit que de copier des entiers et pas des structures compliquées, mais tout de même. 2) pourquoi memcpy ne fait pas par défaut une copie par taille de quelques ko. Les processeurs ont tous depuis plusieurs années un cache L1 qui fait au moins 32Ko, on pourrait décider que memcpy copie par bloc de 16Ko par exemple. PS : si quelqu'un pouvait faire tourner ce bench sur quelques archis intel type core i* avec DDR3 et poster les chiffres des lignes AVG, je l'en remercie d'avance. PS : je vais recompiler en utilisant les options de la branche graphite de gcc-4.4 qui est censée bien gérer la gestion du cache dans les boucles, voir la dépêche [https://linuxfr.org//2009/04/21/24809.html](https://linuxfr.org//2009/04/21/24809.html) J'ose espérer que la boucles si simple de la méthode naïve pourra être optimisée sans trop de difficultés par le compilateur, sinon il faudra voir ce que donne un découpage à la main.