Page 1 sur 1

for ... next : rapidité !

Publié : dim. 29/avr./2007 13:09
par jerexgrz
Je suis surpris, j'ai fait ce petit prog pour voir le temps que prenait un : for... next :

Code : Tout sélectionner

InitKeyboard()
InitSprite()

Structure uni
X.l
y.l
EndStructure

Global Dim unite.uni (999)

unite(1)\x = 304
unite(1)\y = 304

OpenScreen(640,480,16,"")

Procedure evenement1(nbx.l)
cx = 16 : cy = 16

For tt=1 To nbx

      If unite(quan)\x % 32 > 0 
         a = Round((unite(quan)\x+cx)/32,0)
     
         If a*32 <= unite(quan)\x+cx And (a*32)+32 >= unite(quan)\x+cx
            posx = a
      
         ElseIf (a-1)*32 <= unite(quan)\x+cx And (a-1)*32+32 >= unite(quan)\x+cx
            posx = a-1
      
         ElseIf (a+1)*32 <= unite(quan)\x+cx And (a+1)*32+32 >= unite(quan)\x+cx
            posx = a+1      
   
         EndIf

       ElseIf unite(quan)\x % 32 = 0
          posx = (unite(quan)\x) /32
   
       EndIf

       If unite(quan)\y % 32 > 0 
          b = Round((unite(quan)\y+cy)/32,0)
       
          If b*32 <= unite(quan)\y+cy And (b*32)+32 >= unite(quan)\y+cy
             posy = b
      
          ElseIf (b-1)*32 <= unite(quan)\y+cy And (b-1)*32+32 >= unite(quan)\y+cy
             posy = b-1
      
          ElseIf (b+1)*32 <= unite(quan)\y+cy And (b+1)*32+32 >= unite(quan)\y+cy
             posy = b+1
   
          EndIf

       ElseIf unite(quan)\y % 32 =0
          posy = (unite(quan)\y) /32
      
       EndIf

Next tt

EndProcedure

Procedure evenement2(nbx.l)
cx = 16 : cy = 16
coef.l
position.l
reX.l
reY.l

For tt=1 To nbx

    For u = 1 To 2  
      
          If u = 1 
             position = unite(quan)\x
             coef = cx         
      
          ElseIf u = 2 
             position = unite(quan)\y
             coef = cy              
     
          EndIf
            
            If position % 32 > 0 
               a = Round((position+coef)/32,0)
     
               If a*32 <= position+coef And (a*32)+32 >= position+coef
                  posx = a
      
               ElseIf (a-1)*32 <= position+coef And (a-1)*32+32 >= position+coef
                  posx = a-1
      
               ElseIf (a+1)*32 <= position+coef And (a+1)*32+32 >= position+coef
                  posx = a+1      
   
               EndIf

            ElseIf position % 32 = 0
              If u = 1 : rex = (position /32) : EndIf
              If u = 2 : rey = (position /32) : EndIf
   
            EndIf
       
    Next u  

Next tt

EndProcedure

Repeat
timer1.f = ElapsedMilliseconds()
        
  evenement1(1000000)

timer2.f =  ElapsedMilliseconds() - timer1

Debug timer2

ExamineKeyboard()
FlipBuffers()

Until KeyboardPushed(#PB_Key_Escape)
Avec le 1er evenement, je suis à environ 297 ms alors que le 2eme evenement est à 812ms voire 828ms !! 8O
C'est ahurissant, le temps d'execution que prend un for ... next (surtout pour faire 1 à 2 !!!)

J'ai peut-etre mal programmé, mais apparement c'est très lent un for... next (quelque soit le nombre).

Publié : dim. 29/avr./2007 13:19
par Flype
mouais, faire un test de rapidité en mode Debugger n'est pas du tout objectif.

Publié : dim. 29/avr./2007 14:01
par wolfjeremy
Tout dépend de ton pc en même temps, moi je tourne plus dans les 400 avec le debugger. Sans le debugger je suis a ~105 pour le premier et ~90 pour les suivant.

Publié : dim. 29/avr./2007 23:52
par Backup
j'avais fait des test a une epoque qui montraient qu'un For-next
etait plus rapide qu'un While-wend , faudrai le refaire pour voir si cela a changer avec la V4.xx :D

Publié : lun. 30/avr./2007 8:48
par erix14
Tu aurais dû utiliser ma librairie ITest pour faire tes tests, elle est très précise. Tu aurais vu que les résultats sont très proche, et en regardant le code, on voit bien qu'il y a plus de conditions "If" à exécuter dans ta deuxième procédure. C'est la faute à tes : If u = 1 / If u = 2

Code : Tout sélectionner

Structure uni
	X.l
	y.l
EndStructure

Global Dim unite.uni (999)

unite(1)\X = 304
unite(1)\y = 304

Procedure evenement1(nbx.l)
	cx = 16 : cy = 16
	For tt=1 To nbx
		If unite(quan)\X % 32 > 0
			a = Round((unite(quan)\X+cx)/32,0)
			If a*32 <= unite(quan)\X+cx And (a*32)+32 >= unite(quan)\X+cx
				posx = a
			ElseIf (a-1)*32 <= unite(quan)\X+cx And (a-1)*32+32 >= unite(quan)\X+cx
				posx = a-1
			ElseIf (a+1)*32 <= unite(quan)\X+cx And (a+1)*32+32 >= unite(quan)\X+cx
				posx = a+1     
			EndIf
		ElseIf unite(quan)\X % 32 = 0
			posx = (unite(quan)\X) /32
		EndIf
		If unite(quan)\y % 32 > 0
			b = Round((unite(quan)\y+cy)/32,0)
			If b*32 <= unite(quan)\y+cy And (b*32)+32 >= unite(quan)\y+cy
				posy = b
			ElseIf (b-1)*32 <= unite(quan)\y+cy And (b-1)*32+32 >= unite(quan)\y+cy
				posy = b-1
			ElseIf (b+1)*32 <= unite(quan)\y+cy And (b+1)*32+32 >= unite(quan)\y+cy
				posy = b+1
			EndIf
		ElseIf unite(quan)\y % 32 =0
			posy = (unite(quan)\y) /32
		EndIf
	Next tt
EndProcedure

Procedure evenement2(nbx.l)
	cx = 16 : cy = 16
	coef.l
	Position.l
	reX.l
	reY.l
	For tt=1 To nbx
		For u = 1 To 2 
			If u = 1
				Position = unite(quan)\X
				coef = cx         
			ElseIf u = 2
				Position = unite(quan)\y
				coef = cy             
			EndIf
			If Position % 32 > 0
				a = Round((Position+coef)/32,0)
				If a*32 <= Position+coef And (a*32)+32 >= Position+coef
					posx = a
				ElseIf (a-1)*32 <= Position+coef And (a-1)*32+32 >= Position+coef
					posx = a-1
				ElseIf (a+1)*32 <= Position+coef And (a+1)*32+32 >= Position+coef
					posx = a+1     
				EndIf
			ElseIf Position % 32 = 0
				If u = 1 : reX = (Position /32) : EndIf
				If u = 2 : reY = (Position /32) : EndIf
			EndIf
		Next u 
	Next tt
EndProcedure

*Test.ITest = New_Test(0)
For t=0 To #ITest
	*Test\Start(1)
	evenement1(10000)
	*Test\Stop(1)
Next
*Test\SetTitle(1, "evenement1")

For t=0 To #ITest
	*Test\Start(2)
	evenement2(10000)
	*Test\Stop(2)
Next
*Test\SetTitle(2, "evenement2")

For t=0 To #ITest
   *Test\Start(3)
   ; à vide
   *Test\Stop(3)
Next
*Test\SetTitle(3, "Test à vide")

*Test\Display(2) 
Intel(R) Pentium(R) 4 CPU 2.40GHz
2.52 GHz, 768Mo de RAM
NVIDIA GeForce4 Ti 4800 SE - 128Mo
Microsoft Windows XP Professionnel Service Pack 2
-----------------------------------
evenement1
1110452 cycles CPU (minimum)
1116171 cycles en moyenne
X 1.02
-----------------------------------
evenement2
1130536 cycles CPU (minimum)
1139030 cycles en moyenne
X 1.00
-----------------------------------
Test à vide
296 cycles CPU (minimum)
313 cycles en moyenne
X 3819.38
-----------------------------------

Publié : lun. 30/avr./2007 14:52
par jerexgrz
Je viens de télécharger et d'installer ta lib test, c du bon travail (tres propre, tres professionnel, precis aussi !! :o ).
Concernant l'evenement 1 :
je suis à 7 320 085 mini, -722388 moy et le X 2.92

pour l'evenement 2:
je suis à 21 340 976 mini, - 3513423 moy et le X 1 8O 8O 8O

a vide:
279 mini, 299 moy et X 76490.95

Il y a donc une enorme difference entre le code pas trop optimisé que j'ai fait avec le calcul des X en 1er et le calcul des Y en 2nd. Et l'utilisation, d'une boucle pour eviter de réécrire 2X la meme chose !!!

Publié : lun. 30/avr./2007 15:12
par erix14
Tu sais, le résultat du test est copié automatiquement dans le presse-papier, c'est pour éviter de les entrer à la main sur le forum. :wink:
Voici mes résultats avec le Debogueur :
Intel(R) Pentium(R) 4 CPU 2.40GHz
2.52 GHz, 768Mo de RAM
NVIDIA GeForce4 Ti 4800 SE - 128Mo
Microsoft Windows XP Professionnel Service Pack 2
-----------------------------------
evenement1
13656360 cycles CPU (minimum)
-2937086 cycles en moyenne
X 2.99
-----------------------------------
evenement2
40884432 cycles CPU (minimum)
-374451 cycles en moyenne
X 1.00
-----------------------------------
Test à vide
464 cycles CPU (minimum)
544 cycles en moyenne
X 88113.00
-----------------------------------
On ne fait jamais de test de vitesse avec le débogueur sur ON, les résultats ne veulent rien dire!

Publié : mar. 01/mai/2007 11:59
par jerexgrz
oui, il y a une grosse difference quand le debuggeur est activé !
j'avais pris le bloc note traditionnel au lieu d'utiliser wordpad ...
AMD Athlon(tm) 64 X2 Dual Core Processor 5200+
2.61 GHz, 2048Mo de RAM (par contre moi c'est 4go et non 2go !!)
NVIDIA GeForce 7950 GT - 512Mo
Microsoft Windows XP Professionnel Service Pack 2
-----------------------------------
evenement1
1160172 cycles CPU (minimum)
1177879 cycles en moyenne
X 1.10
-----------------------------------
evenement2
1280284 cycles CPU (minimum)
1298296 cycles en moyenne
X 1.00
-----------------------------------
Test à vide
95 cycles CPU (minimum)
117 cycles en moyenne
X 13476.67
-----------------------------------
Mais, l'evenement 1 est toujours + rapide que l'evenement 2 : grosso modo c'est de l'ordre de 10% (quand meme une difference avec avant de l'ordre de 290%).

Publié : mar. 01/mai/2007 12:30
par erix14
Oui, une différence tout à fait normale en raison des conditions supplémentaires que l'événement 2 doit exécuter. Pour conclure, la boucle For en PureBasic est tout ce qu'il y a de plus normal :
Code PureBasic :

Code : Tout sélectionner

For t=0 To 9
	; Code
Next
Code ASM :

Code : Tout sélectionner

; For t=0 To 9
	MOV	 dword [v_t],0
_For1:
	MOV	 eax,9
	CMP	 eax,dword [v_t]
	JL	 _Next2
; Code
; Next
_NextContinue2:
	INC	 dword [v_t]
	JMP	 _For1
_Next2:

Publié : mar. 01/mai/2007 12:46
par jerexgrz
Procedure evenement2(nbx.l)
cx = 16 : cy = 16
Position.l
reX.l
reY.l
posu.l

For tt=1 To nbx

For u = 1 To 2
If u = 1
Position = unite(quan)\X
posu = unite(quan)\x + cx

ElseIf u = 2
Position = unite(quan)\y
posu = unite(quan)\y + cy

EndIf

If Position % 32 > 0
a = Round((Posu)/32,0)
b = a*32

If b <= Posu And b+32 >= Posu
posx = a
ElseIf b-32 <= Posu And b >= Posu
posx = a-1
ElseIf b+32 <= Posu And b+64 >= Posu
posx = a+1
EndIf
ElseIf Position % 32 = 0
If u = 1 : reX = (Position /32) : EndIf
If u = 2 : reY = (Position /32) : EndIf

EndIf
Next u

Next tt
EndProcedure
C'est hyper surprenant, j'ai amélioré la boucle pour qu'elle prenne - de temps, et resultat c'est le contraire ! Aussi, une multiplication est vraiment tres gourmande en cycle : mieux vaut faire : a*32+32 que (a+1)*32 !! 8O

Publié : mar. 01/mai/2007 13:28
par erix14
Comme tu travailles avec des nombres entiers, voilà comment on optimise avec des entiers :

Code : Tout sélectionner

Structure uni
   x.l
   y.l
EndStructure

Global Dim unite.uni (999)

unite(1)\x = 304
unite(1)\y = 304

Procedure evenement2(nbx.l)
   cx = 16 : cy = 16
   coef.l
   Position.l
   reX.l
   reY.l
   For tt=1 To nbx
      For u = 1 To 2
         If u = 1
            Position = unite(quan)\x
            coef = cx         
         ElseIf u = 2
            Position = unite(quan)\y
            coef = cy             
         EndIf
         If Position % 32 > 0
            a = Round((Position+coef)/32,0)
            If a*32 <= Position+coef And (a*32)+32 >= Position+coef
               posx = a
            ElseIf (a-1)*32 <= Position+coef And (a-1)*32+32 >= Position+coef
               posx = a-1
            ElseIf (a+1)*32 <= Position+coef And (a+1)*32+32 >= Position+coef
               posx = a+1     
            EndIf
         ElseIf Position % 32 = 0
            If u = 1 : reX = (Position /32) : EndIf
            If u = 2 : reY = (Position /32) : EndIf
         EndIf
      Next u
   Next tt
EndProcedure
Procedure evenement2_RX(nbx.l)
	cx = 16 : cy = 16
	Position.l
	reX.l
	reY.l
	posu.l
	
	For tt=1 To nbx
		
		For u = 1 To 2
			If u = 1
				Position = unite(quan)\x
				posu = unite(quan)\x + cx
				
			ElseIf u = 2
				Position = unite(quan)\y
				posu = unite(quan)\y + cy
				
			EndIf
			
			If Position & $1F ; Position % 32 > 0
				a = posu >> 5  ;Round((posu)/32,0)
				b = a << 5 ;*32
				
				If b <= posu And b+32 >= posu
					posx = a
				ElseIf b-32 <= posu And b >= posu
					posx = a-1
				ElseIf b+32 <= posu And b+64 >= posu
					posx = a+1
				EndIf
			ElseIf Position & $1F = 0 ;Position % 32 = 0
				If u = 1 : reX = Position >> 5 : EndIf;(Position /32) : EndIf
				If u = 2 : reY = Position >> 5 : EndIf;(Position /32) : EndIf
				
			EndIf
		Next u
		
	Next tt
EndProcedure 

*Test.ITest = New_Test(0)

For t=0 To #ITest
   *Test\Start(1)
   evenement2(10000)
   *Test\Stop(1)
Next
*Test\SetTitle(1, "evenement2")

For t=0 To #ITest
   *Test\Start(2)
   evenement2_RX(10000)
   *Test\Stop(2)
Next
*Test\SetTitle(2, "evenement2_RX")

For t=0 To #ITest
   *Test\Start(3)
   ; à vide
   *Test\Stop(3)
Next
*Test\SetTitle(3, "Test à vide")

*Test\Display(1)
Intel(R) Pentium(R) 4 CPU 2.40GHz
2.52 GHz, 768Mo de RAM
NVIDIA GeForce4 Ti 4800 SE - 128Mo
Microsoft Windows XP Professionnel Service Pack 2
-----------------------------------
evenement2
1130488 cycles CPU (minimum)
1142284 cycles en moyenne
X 1.00
-----------------------------------
evenement2_RX
460680 cycles CPU (minimum)
466956 cycles en moyenne
X 2.45
-----------------------------------
Test à vide
284 cycles CPU (minimum)
327 cycles en moyenne
X 3980.59
-----------------------------------

Publié : mar. 01/mai/2007 13:51
par jerexgrz
:lol: Merci, Merci, pour la version optimisé ! En faite, je travaille dans un monde 3D iso, mais il faut un maximum de precision !
Ce sont de nouvelles fonctions que je viens d'apprendre ! Par contre, c comme meme bizarre, que lorsque les calculs sont faits, ca prends plus de temps ???