Optimiser un code

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Optimiser un code

Message 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 :wink:

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 :D
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message 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.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Message par djes »

Dans le cas des multiplications par multiples, ne pas oublier qu'une addition est plus rapide qu'un décalage.

Ex :

Code : Tout sélectionner

a.l=10
a+a
est plus rapide que

Code : Tout sélectionner

a.l=10
a*2
ou que

Code : Tout sélectionner

a.l=10
a<<1
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!
Fred
Site Admin
Messages : 2808
Inscription : mer. 21/janv./2004 11:03

Message 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.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Message par djes »

Cool!!! :P

Fred, peux-tu m'éclairer sur un point? Pourquoi y'a-t-il une différence de résultat entre

Code : Tout sélectionner

x2.l=Int(x1.f)
et

Code : Tout sélectionner

x2.l=x1.f
:?: Merci d'avance!
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message 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 .
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message par Le Soldat Inconnu »

idem chez moi, passez par les pointeurs est un poil plus lent que passez par un PokeL
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Torp
Messages : 360
Inscription : lun. 22/nov./2004 13:05

Message par Torp »

Ben chez c'est le contraire :

PokeW : 672
PokeL : 500
Pointeur : 422
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Message 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
Dernière modification par djes le jeu. 17/févr./2005 0:41, modifié 1 fois.
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message 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.
Fred
Site Admin
Messages : 2808
Inscription : mer. 21/janv./2004 11:03

Message par Fred »

C'est bizarre. Ici c'est les pointeurs qui sont plus rapides. ..
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Message 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?
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message 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 :roll: moi qui pensait que les float était plus lent, en fait ça change rien

Ca donne quoi sur un pentium ?
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Message par djes »

sur mon xp1800 le calcul en entiers est plus lent... 329 contre 437!
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Message 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! :o
Répondre