Salut !
Un petit topic pour se renseigner au sujet des optimisations :
le processeur calcule certaines opérations plus vite que d´autres.
Par exemple, la racine carré est un algo X fois plus lent qu´une simple multiplication.
Ma premiere question, que vaut X ?
Et plus généralement, une addition est elle plus rapide qu´une multiplication, qu´une division, quelle facteur de temps ?
Quelle facteur de temps entre les 2 syntaxes suivantes :
p = ma_struct->truc->bidule->chose->machin;
et
p2 = ma_struct->truc;
p3 = p2->bidule;
p4 = p3->chose;
p = p4->machin;
Bref, voici un topic pour parler d´optimisations processeur, et surtout de facteur de temps entre une opération et une autre...
En php, pour savoir quelle strcture de langage est plus rapide ou nom, on fait tout simplement des tests (1000, 10000) aevc le temps d´execution (microtime fin du script - microtime debut du script)
Bonjour,
J´avais effectué des recherches sur le sujet il y a quelques temps. Se que j´ai appris, pour faire simple, c´est que ta premiere question a autant de réponses que d´architecture de processeur. Ta seconde question a autant de réponse que de compilateur.
Pour parler d´optimisation processeur il faut spécifier la famille de processeur visée. Chaqu´une a ses jeux d´instruction permettant d´accélérer les calculs. MMX, 3DNOW, SS& et 2...
Ces nouvelle collection d´instruction oblige le developpeur a concevoir son code de facon a les utiliser le mieux possible. Pour avoir une vitesse d´execution maximum dans tout les cas il n´est commun de compiler le meme code autant de fois qu´il y a de famille de prosseur, le choix de l´implémentation étant faite par le programme en late-binding.
Je me suis fait un petit fichier de Bench qui illustre pas mal de choses.
http://rafb.net/p/u9ERMZ36.html
Mes résultats sont en dessous.
(CPU : Athlon T-bird, Visual C++ 6.0)
1) A ceux qui veulent essayer, avez vous globalement les memes resultats ? (ordre de facteur)
(essayez bien en release, et non en debug !! )
Mes remarques et questions :
pourquoi une telle différence quand je cast un int en (double), et en (double&).
Les opérateurs trigo internes sont de vraies saletés...
La racine carrée est moins craignos que je le pensais, mais reste 6 fois plus lente que la multiplication...
"
Quelle facteur de temps entre les 2 syntaxes suivantes :
p = ma_struct->truc->bidule->chose->machin;
et
p2 = ma_struct->truc;
p3 = p2->bidule;
p4 = p3->chose;
p = p4->machin;
"
en principe c´est exactement pareil! Sauf si ton compilo est débile bien sur.
"le processeur calcule certaines opérations plus vite que d´autres.
Par exemple, la racine carré est un algo X fois plus lent qu´une simple multiplication.
Ma premiere question, que vaut X ?"
1/ Ca dépend complètement des processeurs et des algorithmes.
2/ ce n´est pas forcément linéaire. Parceque certaines fonctions sont calculées a partir de developpement limite. l´algorithme s´arrete quand l´erreur commise est inférieur au standard IEEE. et selon les algorithmes et les valeurs cela peut changer fortement
J´ai également fait tourner le test sur ma machine. C´est un Athlon 2000+. Rien de lourd (mis a par KDE) ne tournait sur ma machine lors du test. Les résultats sont a la fin des sources que j´ai modifiées pour fonctionner sous linux avec GCC 4.1.
http://rafb.net/p/XScgnj35.html
On ne peux pas dire que ce soit trés parlant comme résultats. Il serait interressant de comparer les instructions classiques et les vectioriels sur un meme processeur. La il y aurait des résultats plus interressant.
En optimisant violemment :
g++ essai.cpp -O3 -march=nocona -mfpmath=sse
je trouve 0 pour presque tout les tests sauf ceux qui suivent :
1M malloc(100), 1M free : 96 millisecondes
1M calloc(100,0), 1M free : 40 millisecondes
1M new char[100], 1M delete : 74 millisecondes
1M malloc(100), 1M free, 1M creation var interne : 64 millisecondes
100M += et 100M sqrt et 100M cast double: 2439 millisecondes
si ça ce trouve, il ne génère pas de code pour le reste car ça ne sers à rien. Mais je ne sais pas comment on regarde le code assembleur généré avec gcc donc je ne peut pas vérifier.
Il faut noter que les sin, cos, etc. sont des fonctions de lamachine (au moins pour le fpu x87) donc ne prennent à lalimite qu´une seule instruction, et il doit être facile au compilo de savoir qu´il faut les éliminer si on jette leur résultat. Pour la racine, je ne crois pas qu´il y ai d´instruction directement (je regarderais dans la doc intel).
J´ai testé aussi sur une grosse station de travail Sun, mais là, je trouve rigoureusement 0 milliseconde partout, même sans optimisation, je crois que c´est le GetTimeOfDay qui déconne dessus.
Je regarderais demain sous windows avec les compilo MS et Intel.
A partir de l´option -O1 la majeur partie des tests ne sont pas compilés.
Pour optenir le code ASM il suffit de compiler avec l´option -S.
Pour ce qui est des résultat sur la station Sun, cela dépend du compilateur (vérififier avec -S) et de la puissance du proc.
GetTimeOfDay renvoi des nanoseconde, pour un résultat plus précis tu peux utiliser la ligne suivante pour la fonction timeGetTime :
return ((unsigned long long)(tv1.tv_sec) *1000000) + (unsigned long long)(tv1.tv_usec);
j´ai un peu modifié le code pour que le tout soit toujours compilé (globalement, je récupère le résultat du calcul), car sous VS2005, dès qu´on est en release, il ne compilaitplus rien du tout (sauf malloc et Cie).
le code et les résultats sont là, avec la version VC++ sans vectorisation (ou pas trop en tout cas), et celle de ICC.
http://repository.sectionpc.info/C/bench.cpp
Là, je tourne en 32 bits. Mais dès qu´on manipule des float et des double, il peut être interessant de comparer surla même machine, le résultat en 64 bit (mais si possible avec le même compilo, hors je n´arrive pas à faire tourner icc sous linux) vu que là, les double en 80 bits tiennent dans un registre, ce qui améliore les choses.
a mon tour:
proc: P4 HT Ghz en 64 bit (os et binaire)
Les résultats des test sont en fin de post.
chez moi, -O1 -O2 -O3 ca ne change rien. En tout cas, tant que l´on ne vise pas le bon processeur.
Parcontre cibler le bon processeur, ca change tout! avec -O3 et -O2 on obtient une bonne proportion de 0ms. en -01, le compilo semble faire tout betement snas optimisation.
Au chapitre des curiosités...
dans l´assembleur les lignes d´initialisations sont différente en -02 et -O3 (avec processeur ciblé au moins)
movl $0, %eax (en -O1)
xorl %eax, %eax (en -O2)
plutot que de faire a=0; il fait a= a XOR a; ce qui en effet fait 0 aussi.
ceci semble etre la différence majeure entre les deux code binaire.
je fournit un diff des code en fin de post.
-------------------------------------
g++ /tmp/toto.cpp -o /tmp/toto (donc -O1)
100M += : 293 millisecondes
100M += ; 100M appels de fonction inline: 503 millisecondes
100M += ; 100M appels de fonction: 516 millisecondes
100M *= : 502 millisecondes
100M += et 100M + : 307 millisecondes
100M += et 100M * : 344 millisecondes
100M += float : 871 millisecondes
100M += double : 869 millisecondes
100M += float+cast : 870 millisecondes
100M += double+cast : 870 millisecondes
100M += float, 200M cast, 100M * : 875 millisecondes
100M += double, 200M cast, 100M * : 871 millisecondes
100M += float, 100M cast, 100M var temp, 100 * : 1506 millisecondes
100M += float, 100M cast, 100M var temp, 100 * : 1537 millisecondes
100M += float+cast& : 3075 millisecondes
100M += double+cast& : 2175 millisecondes
1M malloc(100), 1M free : 99 millisecondes
1M calloc(100,0), 1M free : 54 millisecondes
1M new char[100], 1M delete : 115 millisecondes
1K malloc(100000), 1M free : 0 millisecondes
1K new char[100000], 1M delete : 0 millisecondes
1M malloc(100), 1M free, 1M creation var interne : 102 millisecondes
100M 10 indirections : 1259 millisecondes
100M 2*5 indirections : 1427 millisecondes
100M += et 100M sqrt et 100M cast double: 3175 millisecondes
100M += et 100M sin et 100M cast double: 10876 millisecondes
100M += et 100M cos et 100M cast double: 10753 millisecondes
100M += et 100M tan et 100M cast double: 16911 millisecondes
les meme en -02:
godrik@skynet-ubuntu:~$ g++ -O2 /tmp/toto.cpp -o /tmp/tot
godrik@skynet-ubuntu:~$ /tmp/toto
100M += : 293 millisecondes
100M += ; 100M appels de fonction inline: 508 millisecondes
100M += ; 100M appels de fonction: 507 millisecondes
100M *= : 503 millisecondes
100M += et 100M + : 309 millisecondes
100M += et 100M * : 337 millisecondes
100M += float : 872 millisecondes
100M += double : 872 millisecondes
100M += float+cast : 874 millisecondes
100M += double+cast : 872 millisecondes
100M += float, 200M cast, 100M * : 880 millisecondes
100M += double, 200M cast, 100M * : 876 millisecondes
100M += float, 100M cast, 100M var temp, 100 * : 1509 millisecondes
100M += float, 100M cast, 100M var temp, 100 * : 1541 millisecondes
100M += float+cast& : 3058 millisecondes
100M += double+cast& : 2180 millisecondes
1M malloc(100), 1M free : 100 millisecondes
1M calloc(100,0), 1M free : 54 millisecondes
1M new char[100], 1M delete : 115 millisecondes
1K malloc(100000), 1M free : 1 millisecondes
1K new char[100000], 1M delete : 0 millisecondes
1M malloc(100), 1M free, 1M creation var interne : 103 millisecondes
100M 10 indirections : 1348 millisecondes
100M 2*5 indirections : 1534 millisecondes
100M += et 100M sqrt et 100M cast double: 3413 millisecondes
100M += et 100M sin et 100M cast double: 10970 millisecondes
100M += et 100M cos et 100M cast double: 10756 millisecondes
100M += et 100M tan et 100M cast double: 16891 millisecondes
puis en -O3:
godrik@skynet-ubuntu:~$ g++ -O3 /tmp/toto.cpp -o /tmp/tot
godrik@skynet-ubuntu:~$ /tmp/toto
100M += : 288 millisecondes
100M += ; 100M appels de fonction inline: 505 millisecondes
100M += ; 100M appels de fonction: 501 millisecondes
100M *= : 505 millisecondes
100M += et 100M + : 309 millisecondes
100M += et 100M * : 337 millisecondes
100M += float : 874 millisecondes
100M += double : 872 millisecondes
100M += float+cast : 873 millisecondes
100M += double+cast : 872 millisecondes
100M += float, 200M cast, 100M * : 881 millisecondes
100M += double, 200M cast, 100M * : 885 millisecondes
100M += float, 100M cast, 100M var temp, 100 * : 1505 millisecondes
100M += float, 100M cast, 100M var temp, 100 * : 1536 millisecondes
100M += float+cast& : 3072 millisecondes
100M += double+cast& : 2173 millisecondes
1M malloc(100), 1M free : 98 millisecondes
1M calloc(100,0), 1M free : 54 millisecondes
1M new char[100], 1M delete : 112 millisecondes
1K malloc(100000), 1M free : 0 millisecondes
1K new char[100000], 1M delete : 0 millisecondes
1M malloc(100), 1M free, 1M creation var interne : 98 millisecondes
100M 10 indirections : 1260 millisecondes
100M 2*5 indirections : 1427 millisecondes
100M += et 100M sqrt et 100M cast double: 3173 millisecondes
100M += et 100M sin et 100M cast double: 10885 millisecondes
100M += et 100M cos et 100M cast double: 10754 millisecondes
100M += et 100M tan et 100M cast double: 16888 millisecondes
et avec l´optimisation pour le processeur comme il faut:
godrik@skynet-ubuntu:~$ g++ -O3 -mtune=nocona /tmp/toto.cpp -o /tmp/toto
godrik@skynet-ubuntu:~$ /tmp/toto
100M += : 0 millisecondes
100M += ; 100M appels de fonction inline: 0 millisecondes
100M += ; 100M appels de fonction: 0 millisecondes
100M *= : 0 millisecondes
100M += et 100M + : 0 millisecondes
100M += et 100M * : 0 millisecondes
100M += float : 0 millisecondes
100M += double : 0 millisecondes
100M += float+cast : 0 millisecondes
100M += double+cast : 0 millisecondes
100M += float, 200M cast, 100M * : 0 millisecondes
100M += double, 200M cast, 100M * : 0 millisecondes
100M += float, 100M cast, 100M var temp, 100 * : 0 millisecondes
100M += float, 100M cast, 100M var temp, 100 * : 0 millisecondes
100M += float+cast& : 0 millisecondes
100M += double+cast& : 0 millisecondes
1M malloc(100), 1M free : 105 millisecondes
1M calloc(100,0), 1M free : 56 millisecondes
1M new char[100], 1M delete : 128 millisecondes
1K malloc(100000), 1M free : 0 millisecondes
1K new char[100000], 1M delete : 0 millisecondes
1M malloc(100), 1M free, 1M creation var interne : 98 millisecondes
100M 10 indirections : 0 millisecondes
100M 2*5 indirections : 0 millisecondes
100M += et 100M sqrt et 100M cast double: 1374 millisecondes
100M += et 100M sin et 100M cast double: 0 millisecondes
100M += et 100M cos et 100M cast double: 0 millisecondes
100M += et 100M tan et 100M cast double: 0 millisecondes
godrik@skynet-ubuntu:~$ g++ -mtune=nocona /tmp/toto.cpp -o /tmp/toto
godrik@skynet-ubuntu:~$ /tmp/toto
100M += : 292 millisecondes
100M += ; 100M appels de fonction inline: 469 millisecondes
100M += ; 100M appels de fonction: 471 millisecondes
100M *= : 502 millisecondes
100M += et 100M + : 312 millisecondes
100M += et 100M * : 338 millisecondes
100M += float : 869 millisecondes
100M += double : 871 millisecondes
100M += float+cast : 869 millisecondes
100M += double+cast : 869 millisecondes
100M += float, 200M cast, 100M * : 881 millisecondes
100M += double, 200M cast, 100M * : 871 millisecondes
100M += float, 100M cast, 100M var temp, 100 * : 1553 millisecondes
100M += float, 100M cast, 100M var temp, 100 * : 1568 millisecondes
100M += float+cast& : 3144 millisecondes
100M += double+cast& : 2246 millisecondes
1M malloc(100), 1M free : 101 millisecondes
1M calloc(100,0), 1M free : 55 millisecondes
1M new char[100], 1M delete : 122 millisecondes
1K malloc(100000), 1M free : 0 millisecondes
1K new char[100000], 1M delete : 0 millisecondes
1M malloc(100), 1M free, 1M creation var interne : 107 millisecondes
100M 10 indirections : 1345 millisecondes
100M 2*5 indirections : 1448 millisecondes
100M += et 100M sqrt et 100M cast double: 3173 millisecondes
100M += et 100M sin et 100M cast double: 10920 millisecondes
100M += et 100M cos et 100M cast double: 10915 millisecondes
100M += et 100M tan et 100M cast double: 16926 millisecondes
godrik@skynet-ubuntu:~$ g++ -mtune=nocona -O2 /tmp/toto.cpp -o /tmp/toto
godrik@skynet-ubuntu:~$ /tmp/toto
100M += : 0 millisecondes
100M += ; 100M appels de fonction inline: 0 millisecondes
100M += ; 100M appels de fonction: 0 millisecondes
100M *= : 0 millisecondes
100M += et 100M + : 0 millisecondes
100M += et 100M * : 0 millisecondes
100M += float : 0 millisecondes
100M += double : 0 millisecondes
100M += float+cast : 0 millisecondes
100M += double+cast : 0 millisecondes
100M += float, 200M cast, 100M * : 0 millisecondes
100M += double, 200M cast, 100M * : 0 millisecondes
100M += float, 100M cast, 100M var temp, 100 * : 0 millisecondes
100M += float, 100M cast, 100M var temp, 100 * : 0 millisecondes
100M += float+cast& : 0 millisecondes
100M += double+cast& : 0 millisecondes
1M malloc(100), 1M free : 106 millisecondes
1M calloc(100,0), 1M free : 57 millisecondes
1M new char[100], 1M delete : 119 millisecondes
1K malloc(100000), 1M free : 0 millisecondes
1K new char[100000], 1M delete : 0 millisecondes
1M malloc(100), 1M free, 1M creation var interne : 98 millisecondes
100M 10 indirections : 0 millisecondes
100M 2*5 indirections : 0 millisecondes
100M += et 100M sqrt et 100M cast double: 1376 millisecondes
100M += et 100M sin et 100M cast double: 0 millisecondes
100M += et 100M cos et 100M cast double: 0 millisecondes
100M += et 100M tan et 100M cast double: 0 millisecondes
godrik@skynet-ubuntu:~$ g++ -mtune=nocona -S -O2 /tmp/toto.cpp -o /tmp/toto.o2.s
godrik@skynet-ubuntu:~$ g++ -mtune=nocona -S -O1 /tmp/toto.cpp -o /tmp/toto.o1.s
godrik@skynet-ubuntu:~$ diff /tmp/toto.o{1,2}.s
154,155d153
< pushq %r13
< .LCFI3:
157c155
< .LCFI4:
---
.LCFI3:
159c157
< .LCFI5:
---
.LCFI4:
161,163c159
< .LCFI6:
< subq $8, %rsp
< .LCFI7:
---
.LCFI5:
168c164
< movl $0, %eax
---
xorl %eax, %eax
174c170
< movl $0, %eax
---
xorl %eax, %eax
180c176
< movl $0, %eax
---
xorl %eax, %eax
186c182
< movl $0, %eax
---
xorl %eax, %eax
192c188
< movl $0, %eax
---
xorl %eax, %eax
198c194
< movl $0, %eax
---
xorl %eax, %eax
204c200
< movl $0, %eax
---
xorl %eax, %eax
210c206
< movl $0, %eax
---
xorl %eax, %eax
216c212
< movl $0, %eax
---
xorl %eax, %eax
222c218
< movl $0, %eax
---
xorl %eax, %eax
228c224
< movl $0, %eax
---
xorl %eax, %eax
234c230
< movl $0, %eax
---
xorl %eax, %eax
240c236
< movl $0, %eax
---
xorl %eax, %eax
246c242
< movl $0, %eax
---
xorl %eax, %eax
252c248
< movl $0, %eax
---
xorl %eax, %eax
258c254
< movl $0, %eax
---
xorl %eax, %eax
261c257
< movl $0, %ebx
---
xorl %ebx, %ebx
273c269
< movl $0, %eax
---
xorl %eax, %eax
276c272
< movl $0, %ebx
---
xorl %ebx, %ebx
278c274
< movl $0, %esi
---
xorl %esi, %esi
289c285
< movl $0, %eax
---
xorl %eax, %eax
292c288
< movl $0, %ebx
---
xorl %ebx, %ebx
307c303
< movl $0, %eax
---
xorl %eax, %eax
310c306
< movl $0, %ebx
---
xorl %ebx, %ebx
322c318
< movl $0, %eax
---
xorl %eax, %eax
325c321
< movw $0, %bx
---
xorw %bx, %bx
340c336
< movl $0, %eax
---
xorl %eax, %eax
343c339
< movw $0, %bx
---
xorw %bx, %bx
355c351
< movl $0, %eax
---
xorl %eax, %eax
360d355
< movq %rax, %r13
362,363c357,362
< movl $0, %ebp
< movl $0, %eax
---
xorl %ebp, %ebp
xorl %eax, %eax
jmp .L26
.L53:
movq %rax, %rbx
movl %ebp, %eax
372,376c371
< je .L27
< movq %rax, %rbx
< movl %ebp, %eax
< jmp .L26
< .L27:
---
jne .L53
381c376
< movl $0, %eax
---
xorl %eax, %eax
387c382
< movl $0, %eax
---
xorl %eax, %eax
389c384
< testq %r13, %r13
---
testq %r12, %r12
400,401c395,399
< movl $0, %ebx
< movl $0, %eax
---
xorl %ebx, %ebx
xorl %ebx, %ebx
xorl %eax, %eax
jmp .L32
.L54:
movl %ebx, %eax
415,419c413
< je .L34
< movl %ebx, %eax
< jmp .L32
< .L34:
< .p2align 4,,5
---
jne .L54
423c417
< movl $0, %eax
---
xorl %eax, %eax
429c423
< movl $0, %eax
---
xorl %eax, %eax
435c429
< movl $0, %eax
---
xorl %eax, %eax
441c435
< movl $0, %eax
---
xorl %eax, %eax
443,444c437
< movl $0, %eax
< addq $8, %rsp
---
xorl %eax, %eax
448d440
< popq %r13
547,554d538
< .byte 0x4
< .long .LCFI6-.LCFI5
< .byte 0xe
< .uleb128 0x28
< .byte 0x4
< .long .LCFI7-.LCFI6
< .byte 0xe
< .uleb128 0x30
556,557d539
< .uleb128 0x5
< .byte 0x86
559c541
< .byte 0x8c
---
.byte 0x86
561c543
< .byte 0x8d
---
.byte 0x8c
mea culpa. Quand on ne met pas de´option d´optimisation, c´est du -O0 et pas du -O1.
a partir de -O1, le compilo dégage la plus part du code.
On le voit d´ailleurs dans l´assembleur, ceci est le code de la premiere boucle. Aucun calcul n´est fait, parcontre le compilo ne pourrait pas les supprimer si on affichait le résultat.
.loc 1 83 0
call _Z12ReInitChronov
.loc 1 86 0
call _Z9GetChronov
movq %rax, %rsi
movl $.LC0, %edi
xorl %eax, %eax
call printf
Par contre, j´ai plus de mal a analyser les appels a sqrt et a sin
en -O1, il fait les appels a sqrt mais pas a sin
alors qu´en -O0 il fait les deux. Je ne comprends pas bien pourquoi en -O1 il n´arrive pas a supprimer les appels a sqrt...
Intéressant
Pour les tests a 0 millisecondes, pour voir si ils ont été purement supprimés, il faut augmenter les itérations.
Avec un int (signed), on peut monter jusqu´a 2 milliards d´itérations. Si la, ça fait toujours 0 ms, c´est qu´il y a soucis.
C´est ce que j´avais quand je ne mettais pas de :
tmp+= _letest
car le compilo detectait que le resultat de _letest n´allait nulle part, donc le virait carrément. Avec le +=, il est obligé d´accumuler pour mettre la variable tmp a jour.
Peut etre que carrément, d´autres compilos plus malins detectent que je ne me sers pas de tmp par la suite, donc zappent quand meme les tests.
J´ai un moyen infaillible pour l´obliger a calculer malgré tout : un bete printf("%d",tmp);
Au moins, la, il est obligé de faire les calculs
Sinon, Dnob, tu parles des instructions sinus, cosinus, tangeante, qui seraient directement une instruction machine (sur les CISC du coup non ?)
Si c´est le cas, il doit y avoir moyen d´avoir de tres bons résultats pour les tests trigos, si je peux avoir ça, je suis intéressé.
A defaut, je pense que je programmerai des fonctions trigo a moi, qui auront en interne une table statique (comme dans nos livres de maths au lycée !) , comme ça, un résultat arrondi (un peu moins juste mais suffisant pour pas mal de cas) en temps rapide.
je rajoute qq elements :
specs Intel IA32 (ou autres..) avec SSEx ; ca donne tous les details, au niveau des instructions meme. Impossible de dire "une / est X fois plus lent qu´une *" ; ca depend de bcp de choses : vectorisation ? types a traiter ? type des operandes ? leur place dans le cache 1st level ? etc.
connaitre son compilo et l´implemention de choses cruciales comme les tables de virtualite
jeter un oeila "C++ Performance Draft" pour des idees sur des concepts plus generiques
faire des tests et regarder le code ASM *optimise* (avec un BON compilo, comme VC2005 ou ICC ; oubliez gcc)
connaitre qq astuces comme par ex remplacer des virtual calls par des templates specilizations, histoire de virer le virtual overhead de dereferecement non trivial des donnees membres
"Peut etre que carrément, d´autres compilos plus malins detectent que je ne me sers pas de tmp par la suite, donc zappent quand meme les tests."
clairement, oui..
"J´ai un moyen infaillible pour l´obliger a calculer malgré tout : un bete printf("%d",tmp)"
a faire en dehors des timers, vu que ca coute un max de temps, ce genre de traitement de chaine. A noter que la encore, un compilo a qui on fait faire 2 milliards de fois une operation qui produit un resultat "predictable" (pas forcement similaire, mais qu´il peut predire), va grandement simplifier le probleme
"Sinon, Dnob, tu parles des instructions sinus, cosinus, tangeante, qui seraient directement une instruction machine (sur les CISC du coup non ?)
Si c´est le cas, il doit y avoir moyen d´avoir de tres bons résultats pour les tests trigos, si je peux avoir ça, je suis intéressé."
toutes les fonctions trigo sont effectivement cablees en dur, avec des mnemoniques associees. Ca ne coute plus "rien" ajd.
"A defaut, je pense que je programmerai des fonctions trigo a moi, qui auront en interne une table statique (comme dans nos livres de maths au lycée !) , comme ça, un résultat arrondi (un peu moins juste mais suffisant pour pas mal de cas) en temps rapide."
ca marchait bien a l´epoque des 3/486 et P1, ou les calculs trigo etaient couteux. Ajd c´est souvent contre-performant d´utiliser son propre mecanisme : le cout des dereferencement (souvent vers une table static, sympa pour le cache..) et d´interpolation a l´arrache sont bien plus eleves qu´utiliser les mnemoniques du CPU.
oui, dans la version du code que j´ai reposté, j´utilise le résultat des boucles pour l´obliger à les calculer, sinon effectivement, il zappe les boucles.
Par contre, même si le résultat d´une boucle est complétement prévisible, je ne crois pas qu´un compilo va faire le calcul à la compilation pour optimiser le tout, c´est a priori une optimisation trop complexe qu´un compilo ne sait pas faire, on touche là à la limite de l´analyse statique.
dnob700 >
J´ai essayé de lancer le programme avec visual 2005, les fonctions trigo restent toujours relativement lentes.
Faut il une config spéciale du projet pour utiliser les fonctions en hardware ?
Comment configurer le projet ?
Tu arrives, toi, a faire utiliser les fonctions trigo en interne ?
j´ai beau activer toute les options d´optimisation, je continu de voir un ´call sin´ dans le code assembleur.
options du compilo
optimization
optim > max speed
intrinsic > yes
favor fast code
code generation
floating model > fast
instruction set > SOIT mettre sur "not set", soit faire mumuse avec le SSEx mais la faut aussi tripoter le linker pour faire apparaitre directement le code SSE dans l´asm
teste a l´instant sous VC++ 2005 Express