Page 1 sur 2
Optimiser un code
Publié : mer. 16/févr./2005 12:31
par Le Soldat Inconnu
Bon, j'ouvre ce sujet pour papoter un peu de truc permettant d'optimiser un code.
tout d'abbod, voici un code qui permet de faire des test de rapidité, ça permettra de donner les résultats de l'optimisation en pourcentage rapidement.
Code : Tout sélectionner
#nb = 100000000
Temps1 = ElapsedMilliseconds()
For n = 1 To #nb
; mettre ici votre code 1
Next
Temps2 = ElapsedMilliseconds()
For n = 1 To #nb
; mettre ici votre code 2
Next
Temps3 = ElapsedMilliseconds()
MessageRequester("Test rapidité", "Solution 1 : " + Str(Temps2 - Temps1) + " ; Solution 2 : " + Str(Temps3 - Temps2) + Chr(10) + "Ratio = 1 / " + StrF((Temps2 - Temps1) / (Temps3 - Temps2)), 0)
Le cas du Int()
j'ai comparé ceci :
Y.l = Int(X.f) sachant que ceci tronque la valeur (1.7 devient 1 et 1.3 devient 1 par exemple)
avec
Y.l = X.f sachant que ceci arrondi la valeur (1.7 devient 2 et 1.3 devient 1 par exemple)
Le résultat est que le code sans Int() va 5 fois plus vite chez moi
Code : Tout sélectionner
#nb = 100000000
X.f = Cos(1)
Temps1 = ElapsedMilliseconds()
For n = 1 To #nb
Y.l = Int(X.f)
Next
Temps2 = ElapsedMilliseconds()
For n = 1 To #nb
Y.l = X.f
Next
Temps3 = ElapsedMilliseconds()
MessageRequester("Test rapidité", "Solution 1 : " + Str(Temps2 - Temps1) + " ; Solution 2 : " + Str(Temps3 - Temps2) + Chr(10) + "Ratio = 1 / " + StrF((Temps2 - Temps1) / (Temps3 - Temps2)), 0)
Multiplication
Multiplié par une valeur 2^n par exemple 2, 4, 8, 16, 32, etc ...
est plus rapide qu'une multiplication par un autres chiffres. (ente 1.2 et 1.5 fois)
Pas forcément facile à appliquer, je le reconnais
Code : Tout sélectionner
#nb = 100000000
X = 1524
Temps1 = ElapsedMilliseconds()
For n = 1 To #nb
Y = X * 100
Next
Temps2 = ElapsedMilliseconds()
For n = 1 To #nb
Y = X * 128
Next
Temps3 = ElapsedMilliseconds()
MessageRequester("Test rapidité", "Solution 1 : " + Str(Temps2 - Temps1) + " ; Solution 2 : " + Str(Temps3 - Temps2) + Chr(10) + "Ratio = 1 / " + StrF((Temps2 - Temps1) / (Temps3 - Temps2)), 0)
Si vous avez d'autres truc utile du genre

Publié : mer. 16/févr./2005 15:22
par comtois
le temps est le même , mais c'est toujours bon de savoir que
y = x * 128
peut s'écrire aussi
y = x << 7
________________________________________
Le truc qui suit est de Fweil , on en avait parlé dans un autre post , mais puisque l'objet de celui ci c'est de regrouper tous les trucs pour optimiser , je remets ici le passage qui en parlait :
Fweil a écrit :Je pense que plutôt que de faire :
PokeW(Addresse, B1)
PokeW(Adresse + 2, B2)
il est sûrement plus rapide de faire un :
PokeL(Adresse, B2 << 16 + B1)
D'ailleurs je m'absente trois minutes pour vérifier ...
Voila, les 3 minutes sont écoulées ...
Code : Tout sélectionner
b1.w = 123
b2.w = 456
l.l
OpenConsole()
;
; pour vérifier que je ne dis pas d'ânerie
;
PokeL(@l, b2 << 16 + b1)
PrintN(Str(l))
PokeW(@l, b1)
PokeW(@l + 2, b2)
PrintN(Str(l))
;
; Les deux résultats sont bien identiques !
Count = 100000000
tz = ElapsedMilliseconds() : For i = 1 To Count
PokeW(@l, b1)
PokeW(@l + 2, b2)
Next : PrintN(Str(ElapsedMilliseconds() - tz))
tz = ElapsedMilliseconds() : For i = 1 To Count
PokeL(@l, b2 << 16 + b1)
Next : PrintN(Str(ElapsedMilliseconds() - tz))
While Inkey() = "" : Wend
CloseConsole()
end
Ca donne 1.6s pour le double PokeW et 1.1s pour le simple PokeL sur mon 1,2GHz !
CQFD. Ce genre de petit détail peut changer la vie.
Publié : mer. 16/févr./2005 18:40
par djes
Dans le cas des multiplications par multiples, ne pas oublier qu'une addition est plus rapide qu'un décalage.
Ex :
est plus rapide que
ou que
Ensuite, pour le int, j'ai parfois remarqué que le résultat était différent quand on convertissait un flottant directement, comme le fait le soldat ci-dessus. Je ne pense pas que ce soit normal!
Publié : mer. 16/févr./2005 18:48
par Fred
A noter que PureBasic fait deja les optimisations sur les multiplications comme un grand

. Pour le PokeW/PokeL, le moyen encore plus rapide est d'utiliser un pointer sur un long: *Pointer.Long = @l : *Pointer\l = b2 << 16 + b1
On economize l'appel de la fonction ce qui n'est pas négligeable.
Publié : mer. 16/févr./2005 19:33
par djes
Cool!!!
Fred, peux-tu m'éclairer sur un point? Pourquoi y'a-t-il une différence de résultat entre
et

Merci d'avance!
Publié : mer. 16/févr./2005 22:28
par comtois
j'ai modifié le test
Code : Tout sélectionner
b1.w = 123
b2.w = 456
l.l
OpenConsole()
;
; pour vérifier que je ne dis pas d'ânerie
;
PokeL(@l, b2 << 16 + b1)
PrintN(Str(l))
PokeW(@l, b1)
PokeW(@l + 2, b2)
PrintN(Str(l))
*Pointer.LONG = @l
*Pointer\l = b2 << 16 + b1
PrintN(Str(l))
;
; Les deux résultats sont bien identiques !
Count = 100000000
Tz = ElapsedMilliseconds() : For i = 1 To Count
PokeW(@l, b1)
PokeW(@l + 2, b2)
Next : PrintN(Str(ElapsedMilliseconds() - Tz))
Tz = ElapsedMilliseconds() : For i = 1 To Count
PokeL(@l, b2 << 16 + b1)
Next : PrintN(Str(ElapsedMilliseconds() - Tz))
Tz = ElapsedMilliseconds() : For i = 1 To Count
*Pointer\l = b2 << 16 + b1
Next : PrintN(Str(ElapsedMilliseconds() - Tz))
While Inkey() = "" : Wend
CloseConsole()
End
Est-ce qu'il y a une erreur ?
chez moi c'est toujours le pokeL le vainqueur .
Publié : mer. 16/févr./2005 23:01
par Le Soldat Inconnu
idem chez moi, passez par les pointeurs est un poil plus lent que passez par un PokeL
Publié : mer. 16/févr./2005 23:12
par Torp
Ben chez c'est le contraire :
PokeW : 672
PokeL : 500
Pointeur : 422
Publié : mer. 16/févr./2005 23:13
par djes
Peux-tu essayer en changeant la valeur de l'align, avant dd:? Merci! Plusieurs compilations à chaque fois, si possible!
Code : Tout sélectionner
b1.w = 123
b2.w = 456
l.l
OpenConsole()
;
; pour vérifier que je ne dis pas d'ânerie
;
PokeL(@l, b2 << 16 + b1)
PrintN(Str(l))
PokeW(@l, b1)
PokeW(@l + 2, b2)
PrintN(Str(l))
*Pointer.LONG = @l
*Pointer\l = b2 << 16 + b1
PrintN(Str(l))
;
; Les deux résultats sont bien identiques !
Count = 100000000
Tz = ElapsedMilliseconds() : For i = 1 To Count
PokeW(@l, b1)
PokeW(@l + 2, b2)
Next : PrintN(Str(ElapsedMilliseconds() - Tz))
Tz = ElapsedMilliseconds() : For i = 1 To Count
PokeL(@l, b2 << 16 + b1)
Next : PrintN(Str(ElapsedMilliseconds() - Tz))
Goto dd
!section 'test' code executable align 256
DD:
Tz = ElapsedMilliseconds() : For i = 1 To Count
*Pointer\l = b2 << 16 + b1
Next : PrintN(Str(ElapsedMilliseconds() - Tz))
While Inkey() = "" : Wend
CloseConsole()
End
Publié : mer. 16/févr./2005 23:39
par comtois
ça correspond à quoi cette valeur d'align ? il faut mettre quoi pour tester ?
bon , j'ai essayé quand même en mettant 128 , 256 , et ça ne change rien .
C'est toujours PokeL qui gagne.
Publié : jeu. 17/févr./2005 0:10
par Fred
C'est bizarre. Ici c'est les pointeurs qui sont plus rapides. ..
Publié : jeu. 17/févr./2005 0:51
par djes
comtois a écrit :ça correspond à quoi cette valeur d'align ? il faut mettre quoi pour tester ?
bon , j'ai essayé quand même en mettant 128 , 256 , et ça ne change rien .
C'est toujours PokeL qui gagne.
C'est l'alignement du code dans la mémoire. Il se peut que du code soit mal aligné (voire des données), càd que par exemple un long (4 octets) se retrouve sur une adresse mémoire impaire, ce qui cause une pénalité lors d'un accès. En outre, le cache lit les données en rafale, il faut donc que le code se trouve aligné sur un multiple de la taille d'une rafale (là j'ai mis 256), et y tienne en entier (ce n'est pas le cas ici, trop long).
L'align ici correspond à l'alignement de la section de code (enfin je crois). Par contre les données (les variables) ne sont peut-être pas alignées. Je regarderai demain, pour l'instant je tâtonne. En plus tout ça n'est pas évident car on est tributaire du système; lors d'une compil ça va aller, la suivante, rien du tout. Je ne sais pas si quelqu'un sait comment résoudre tout ça?
Publié : jeu. 17/févr./2005 0:53
par Le Soldat Inconnu
Code : Tout sélectionner
#nb = 300000000
f1.f = 103.2
f2.f = 215.45
l1= 103
l2 = 215
Temps1 = ElapsedMilliseconds()
For n = 1 To #nb
; mettre ici votre code 1
f3.f = f1 * f2
Next
Temps2 = ElapsedMilliseconds()
For n = 1 To #nb
; mettre ici votre code 2
l3 = l1 * l2
Next
Temps3 = ElapsedMilliseconds()
MessageRequester("Test rapidité", "Solution 1 : " + Str(Temps2 - Temps1) + " ; Solution 2 : " + Str(Temps3 - Temps2) + Chr(10) + "Ratio = 1 / " + StrF((Temps2 - Temps1) / (Temps3 - Temps2)), 0)
c'est marrant, sur mon AMD Athlon, j'ai pas de différence entre les float et les long

moi qui pensait que les float était plus lent, en fait ça change rien
Ca donne quoi sur un pentium ?
Publié : jeu. 17/févr./2005 1:11
par djes
sur mon xp1800 le calcul en entiers est plus lent... 329 contre 437!
Publié : jeu. 17/févr./2005 12:02
par djes
Bon voilà j'ai expérimenté un peu, et voilà ce qu'il faut pour que le test se fasse dans de bonnes conditions d'alignement (en tout cas sur un pentium xeon).
Ne pas oublier d'activer l'assembleur en ligne dans les options!
Code : Tout sélectionner
#nb = 300000000
f1.f = 103.2
f2.f = 215.45
l1.l = 103
l2.l = 215
;****************************************************************
Goto f
!SECTION '.testf' CODE READABLE EXECUTABLE ALIGN 4096
f:
Temps1 = ElapsedMilliseconds()
!ALIGN 4
For n = 1 To #nb
; mettre ici votre code 1
f3.f = f1 * f2
Next
Temps2 = ElapsedMilliseconds()
;****************************************************************
Goto i
!SECTION '.testi' CODE READABLE EXECUTABLE ALIGN 4096
i:
Temps3 = ElapsedMilliseconds()
!ALIGN 4
For n = 1 To #nb
; mettre ici votre code 2
l3 = l1 * l2
Next
Temps4 = ElapsedMilliseconds()
;****************************************************************
MessageRequester("Test rapidité", "Solution 1 : " + Str(Temps2 - Temps1) + " ; Solution 2 : " + Str(Temps4 - Temps3) + Chr(10) + "Ratio = 1 / " + StrF((Temps2 - Temps1) / (Temps4 - Temps3)), 0)
Donnez vos résultats et vos configs svp!
