L'importance de l'optimisation dans la copie des données [memcpy] - C++ - Programmation
Marsh Posté le 11-07-2004 à 11:53:42
La suite... Pour ce test, on essaye de ne pas utiliser le cache (flush).
<Erreur dans le graphe, voir plus bas>
Marsh Posté le 11-07-2004 à 11:57:56
Ces tests confirment largement la supériorité de la copy SSE avec movaps/movntps quand il s'agit de traîter des zones ne se trouvant pas dans le cache.
Attention toutefois, on effectue une copie ! Cet à dire que l'on lit puis on écrit. Certains logiciels affichent des résultats doubles.
En accès RAM, le débit entrant/sortant est de 3238Mo/s et le global de 1619Mo/s.
Le processeur ayant un bus de 180,409MHz soit un vitesse DDR de 360,818MHz. A chaque front, on peut transmettre 64 bits. Soit un débit théorique entrant ou sortant de 23092MBits/s soit 2886Mo/s. Alors pourquoi je suis à 3238Mo/s ? A mon avis, le Write-Back y est pour quelque chose.
Pour illustrer un processeur AthlonXP Barton, un test fait HFR.
Attention, pour ce test, la mémoire est en 2-2-2-6 d'où les résultats élevés. Sandra ne dit pas si les débits sont doublés ou pas.
Une autre test à 200MHz avec différents timings
Marsh Posté le 11-07-2004 à 13:15:14
Enfin OUF !
J'ai compris. Il y avait un soucis dans ma routine.
J'atteind donc un débit crête de 1377Mo/s contre 1343Mo/s pour la routine d'AMD. Soit mon gain initial de 2,5% pour le débit en mode DDR.
Marsh Posté le 11-07-2004 à 13:28:30
oui mais est-ce que tu as fait des mesures applicatives réelles, je veux dire, faire des memcpy en boucles, d'accord, mais dans une application de calcul (ou bien un tri, ça peut être très bien) pour évaluer ça en condition réelles, voir comment ça souille le cache ou bien les temps de bascule selon les routines. tu peux faire ça, un tri générique en C avec des memcpy, avec des tailles de données différentes ?
Marsh Posté le 11-07-2004 à 13:43:48
Le but final est de fournir plusieurs routines memcpy dont une permettant de faire une liste de memcpy.
Toutes ces routines utiliseront la meilleure routine selon les besoins.
Marsh Posté le 11-07-2004 à 13:47:45
oui, mais pour pouvoir déterminer qui réponds le mieux à quoi ...
Marsh Posté le 11-07-2004 à 13:50:48
Taz> C'est l'intérêt de fournir plusieurs routines au programmeur qui au final font la même chose mais de façon différentes.
Up> Je travaille surtout sur les problèmes d'alignement 8/16 octets.
Marsh Posté le 11-07-2004 à 17:07:16
Taz> De toute façon, t'es tout le temps en train de critiquer. Si le monde t'écoutait, on serait pas prêt d'évoluer.
Une routine relativement générique qui permet de gagner un peu de vitesse est toujours bonne à prendre.
Marsh Posté le 11-07-2004 à 17:52:45
mais putain, tu comprends rien !
t'auras beau montrer que l'avion va 4 fois plus vite que le train, il faut bien 2H pour embarquer/débarquer dans un voil, donc sur énormément de distances, le train est, de manière pratique, plus rapide que l'avion.
Marsh Posté le 11-07-2004 à 18:26:51
Si je te suis dans ton raisonnement, il faut laisser tomber l'avion...
PS: ça sert à rien de jurer.
Marsh Posté le 11-07-2004 à 18:58:05
non, d'apres son raisonnement, il faut prendre l'avion sur des grandes distances peu frequemment et le train sur des petites distances frequemment, et jpense qu'il associe ton memcpy a l'avion et celui de l'os (vu qu'il parle de cache) au train.
Marsh Posté le 11-07-2004 à 19:06:49
vous me sidérez : exercice pratique. La voiture va bien plus vite que la marche (on va dire 130km/h contre 4km/h). Votre boulangerie est au coin de la rue. Allez-y a pied. Allez-y en voiture. Vous allez voir ...
Marsh Posté le 11-07-2004 à 19:09:19
et j'associe rien du tout : je demande un benchmark applicatif pour justement savoir qui est plus efficace.
Marsh Posté le 11-07-2004 à 19:29:02
On est d'accord Taz, c'est clair, n'empêche que ce genre de bench/test est intéressant à mon avis, on s'est déjà posé le problème ( K!TV pour ne pas le nommer), on a fait un paquet de tests ( c'est pas moi qui m'en suis occuppé ...), sans vraiment arriver à qq chose de top, faut dire qu'il y a plusieurs cas, copie de mémoire à mémoire ( pour les plugins), et copie de mémoire dans l'overlay à la fin; et là c'est clairement différent car on tape dans la vidéo ...
Mais bon, on s'égarre ...
Marsh Posté le 11-07-2004 à 19:51:31
Et indique la source/destination, car comme déjà dit de mémoire à overlay ça n'est pas du tout pareil, enfin je pense que tes tests sont de mémoire à mémoire.
Marsh Posté le 11-07-2004 à 20:57:15
Mes tests ont un seul but : Fournir au programmeur plusieurs routines de copy adaptées à ses besoins.
Il y a plus d'un millier de tests qui sont effectués au démarrage de l'application pour choisir les meilleurs compromis (vitesse, taille, overlap, alignement) pour les routines :
- Copie en considérant que les données sont probalement dans le cache L1, L2 ou la mémoire
- Idem mais uniquement pour le L2 et la mémoire
- Idem mais uniquement pour la mémoire
- Copie en effectuant le meilleur compromis taille/vitesse (même si on perd des performances sur le L1).
- Et puis surtout la copie listée...
L'intérêt c'est bien de fournir les routines les plus rapides quel que soit l'os, le CPU, le cache ou la mémoire.
C'est pour cela que mes fonctions testent le processeur (CPUID), la vitesse et la taille des caches ainsi que la vitesse de la mémoire.
Marsh Posté le 12-07-2004 à 07:51:19
« Fournir au programmeur plusieurs routines de copy adaptées à ses besoins. »
Ariane va à 28.800km/h, mais elle est loin d'être adaptée à mes besoins
Marsh Posté le 12-07-2004 à 09:02:52
Bah, joelf fait bien le meme genre d'optimisations avec son altivec, non ?
C'est clair que dans la plupart des applis lambda, c'est inutile voire deconseille, mais il se peut tjrs que dans qq cas particuliers (genre K!TV, avec lequel je regarde la tele d'ailleurs, merci CriCri ), ca serve.
Marsh Posté le 12-07-2004 à 09:13:33
non, il fait pas du tout la même chose, lui il fait du SIMD, pas de la branlette qui accélère l'internet
Marsh Posté le 12-07-2004 à 09:18:56
Taz a écrit : non, il fait pas du tout la même chose, lui il fait du SIMD, pas de la branlette qui accélère l'internet |
c'est bien Taz ça
Marsh Posté le 12-07-2004 à 09:39:53
Taz a écrit : non, il fait pas du tout la même chose, lui il fait du SIMD, pas de la branlette qui accélère l'internet |
Signe Taz !
En fait, son truc, je pense que ca peut marcher seulement si le jeu de tests au demarrage est suffisamment bien selectionne pour evaluer correctement l'utilisation de la memoire cache dans l'appli, ce qui est loin d'etre evident (il faut essayer dans de nombreuses appli differentes, gros calcul, video, quicksort par exemple), mais certainement instructif, sinon ca peut faire une excellente librairie memoire.
Marsh Posté le 12-07-2004 à 12:42:55
Je deviens fous !
Etant donné que j'ai besoin de mesurer la taille des caches, j'ai donc fait plusieurs routines pour cela. Et dans la dernière, j'ai des résultats ahurissants : (j'ai converti pour les vrai Mo - 1Mo = 1048576 octets et non 1000000)
L1 = 28455Mo/s
L2 = 11884Mo/s
DDR = 2752Mo/s
Processeur AthlonXP 2164,91MHz (Diviseur /12)
Bus à 180,4092MHz
Débit DDR max = 23093MBits/s soit 2753Mo/s
Voici ma routine de test de lecture (via le CPU uniquement)
(c) 2004 Christophe Gossa, Tous droits réservés.
A noter que je ne mesure pas la latence de RDTSC/MOV EBX,EAX/RDTSC, et que la routine travaille sur 5 passes.
#define PROCESSORTESTREAD_MOV256RD64(x) __asm mov eax, [esi+ecx+ 4+x] \ |
Je vous fait une petite routine d'appel simple
Code :
|
L'avantage de la routine : Vitesse maximale avec une ligne de cache de 32 ou 64 octets.
Marsh Posté le 12-07-2004 à 13:00:43
Je viens de faire un test sur un PIII-866 (133*6.5)
Débit mémoire plafonnant à plus de 1Go/s (débit également théorique).
Pour l'instant, je considère que le test est concluant et que ma routine est fiable.
Up: Sur un PIV (un serveur pas top à 2,66GHz pour 1Go de ram), j'obtiens 3616Mo/s. CPU-Z m'apprend :
- L1 Cache : 8Ko (de la daube !)
- L2 Cache : 512Ko
- FSB 133
- Bus 533
- Mémoire : 2/3/3/6
Marsh Posté le 12-07-2004 à 13:23:37
En comparant d'Athlon et le P4:
L1 = 28455 contre 17337
L2 = 11884 contre 14539
RAM = 2752 contre 3616
Je comprend mieux pourquoi le P4 se prend des claques de la part de l'athlon. On se demande d'ailleurs à quoi sert le cache L1 chez intel... Faudrait qu'ils pensent à le passer à 32Ko.
Marsh Posté le 12-07-2004 à 15:32:48
christophe_d13 a écrit : En comparant d'Athlon et le P4: |
Oui, c'est bizarre que les bursts du cache L1 soient inférieurs à ceux du L2.
Sinon, ton code, tu peux le faire "portable" (Linux/FreeBSD inside) ?
Marsh Posté le 12-07-2004 à 16:24:45
Erreur de ma part en écrivant les chiffres. Mais je confirme le peu d'importance (en cas de linear-read) du cache L1.
Pour le porter sous Linux, il faut tout passer en mode AT&T et j'ai pas trop le temps pour cela : "mov eax, ebx" => "movl %ebx, %eax"
Marsh Posté le 12-07-2004 à 21:06:49
Petite mise à jour.
En tout, j'ai calculé 1856 combinaisons pour :
- Type de routine (L1, L2, RAM ou compromis)
- Taille de l'overlap
- Alignement
- Taille du transfert
Marsh Posté le 13-07-2004 à 00:59:09
Je propose une fonction de copie nécessitant un CPU supportant SSE ou 3DNow!
Comparativement à la fonction de copie livrée avec visual C :
Sur le cache L1 : +112%
Sur le cache L2 : +41%
Sur la mémoire : +6%
Cette routine n'est pas la plus performante, mais elle est assez simple à comprendre.
Code :
|
Voici une autre fonction plus tordue (qui n'apporte pas grand chose) mais qui, sur les cpu avec une FPU lente (6x86) permet de gratter un peu (très peu en fait 5-15%):
Code :
|
Par rapport à une fonction de copie plus classique par 'mov reg,mem' puis 'mov mem,reg' :
- Sur le cache L1 : +15%
- Sur le cache L2 : +6%
- Sur la mémoire : +2%
En comparant avec la classique memcpy de visual
- Sur le cache L1 : +18%
- Sur le cache L2 : +15%
- Sur la mémoire : +4%
Codes (c) 2004 Christophe Gossa
Marsh Posté le 13-07-2004 à 08:39:02
Histoire de se prendre le choux encore un peu...
Une variante de la copie 'mov reg/mem,reg/mem' précédente :
Comparaison avec la précédente version
- Cache L1 : +5%
- Cache L2 : +2%
- Mémoire : 0%
Code :
|
Code (c) 2004 Christophe Gossa
Marsh Posté le 13-07-2004 à 08:56:21
christophe_d13 a écrit : Erreur de ma part en écrivant les chiffres. Mais je confirme le peu d'importance (en cas de linear-read) du cache L1. |
Demande à Taz, je suis sûr que ça l'intéresse.
Mais pour cela, il faut que tu passes ta librairie en LGPL.
Marsh Posté le 13-07-2004 à 09:00:05
christophe_d13 a écrit : |
Marsh Posté le 13-07-2004 à 09:00:27
Taz a écrit : non, il fait pas du tout la même chose, lui il fait du SIMD, pas de la branlette qui accélère l'internet |
LMAO ^^ je quote
Marsh Posté le 13-07-2004 à 09:01:10
el muchacho a écrit : Bah, joelf fait bien le meme genre d'optimisations avec son altivec, non ? |
Ouais sauf que c'est pas des copies mémoires que j'optimise ^^
Marsh Posté le 13-07-2004 à 10:11:48
Après avoir testé sur plusieurs plateformes (PII, PIII, P4, AthlonXP) une trentaine de fonctions, j'en ai retenue que 13. Les autres n'apportent jamais rien et ralentissent la procédure de test :
- les classiques MOVSB et MOVSD
- 2 routines "mov reg/mem, reg/mem"
- 2 routines utilisant la FPU (pratique sur les vieilles bécanes)
- 1 routine MMX
- 2 routines SSE
- 4 routines MMX/SSE compatibles MMX/3DNow! (utilisation prefetch)
Marsh Posté le 15-07-2004 à 00:26:11
ça avance encore.
J'ai terminé la phase de sélection du compromis.
Il ne me reste qu'à faire la routine de copie à proprement parlé qui sélectionnera la meilleure routine.
Je vais également inclure un test de performance pour comparer le memcpy de visual c avec ma routine.
Hélas je ne pourrait comparer avec celle de AMD, car elle ne supporte pas l'overlap inférieur à 8.
Le grand intérêt de ma routine c'est que chacun peu ajouter son code et le programme choisira toujours parmis le meilleur.
Actuellement, j'ai 152 tests pour chacune des 13 routines soit 3780 tests allant de 128 octets à 2Mo.
Au final, j'ai réussi à réduire le nombre de combinaisons à 928.
Marsh Posté le 11-07-2004 à 11:26:17
Je travaille actuellement sur memcpy (ré-écriture).
En effet, j'ai découvert que les routines officielles (intel et AMD) n'étaient pas aussi performantes que ces fondeurs pouvaient le laisser croire.
Pour illustrer mes propos, voici un graphe utilisant plusieurs routines SSE et/ou MMX, j'ai enlever les routines CPU et FPU car elles n'apportent rien de plus (et polluent le graphe)
<Erreur dans le graphe, voir plus bas>
Message édité par christophe_d13 le 11-07-2004 à 13:15:57