Page 2 sur 2

Publié : dim. 16/avr./2006 14:32
par erix14
Je viens de faire des tests : PureBasic / GCC
voici le code GCC :

Code : Tout sélectionner

			int i,a,b,c,d;
			float e,f;
			LARGE_INTEGER t1,t2;
  			QueryPerformanceCounter(&t2);
  			 
			for (i = 0; i <= 10000; i++){
			 	 a++;
			 	 b = a * 2;
			 	 c = b * a;
			 	 d = (c + b)/a;
				 e = sin(50.0)+d;
                 f = e*e+sqrt(e);
    		 }
    		 
  	 	   	 QueryPerformanceCounter(&t1);
			 CHAR Texte[128];
			 sprintf(Texte, "f = %f / Intervalle : %d",f, t1.LowPart - t2.LowPart);
			 MessageBox(0,Texte,"Test",MB_OK);
voici le code PureBasic :

Code : Tout sélectionner

               i.l:a.l:b.l:c.l:d.l
               e.f:f.f
               t1.LARGE_INTEGER:t2.LARGE_INTEGER
               QueryPerformanceCounter_(t2)
               
               For i = 0 To 10000
                    a+1
                    b = a * 2
                    c = b * a
                    d = (c + b)/a
                    e = Sin(50.0)+d
                    f = e*e+Sqr(e)
               Next
               
               QueryPerformanceCounter_(t1)
               MessageRequester("Test","f = "+StrF(f)+" / Intervalle : "+Str(t1\lowpart - t2\lowpart))
Les résultats des calculs sont les mêmes, mais GCC se prend une grosse déculottée par PureBasic :lol:
En calcul pur, PureBasic est légèrement meilleur et en rajoutant sin et sqrt, GCC est complètement à la ramasse..., au lieu d'intégrer directement la fonction assembleur FSIN il doit certainement appeler une fonction... :lol: :lol: :lol:
Voici les résultats d'une série de 5 tests:
GCC => 18179 / 19603 / 18617 / 18636 / 18570
PureBasic => 4698 / 4648 / 5993 / 4645 / 5143

Publié : dim. 16/avr./2006 15:18
par Flype
Ah ouai quand meme. faut que je test avec mon DevC++.

toute petite remarque, pour coller au plus près du C tu peux écrire les définitions de tes variables comme çà:

Code : Tout sélectionner

int i,a,b,c,d;
float e,f; 
LARGE_INTEGER t1,t2;

Code : Tout sélectionner

Define.l i,a,b,c,d
Define.f e,f
Define.LARGE_INTEGER t1,t2

Publié : dim. 16/avr./2006 16:08
par comtois
Avec Dev-C++ et cette fonction , j'obtiens un gain de 50% par rapport à la fonction PureBasic !!

Code : Tout sélectionner

#include <stdio.h>

double puis(double x, int n){
       double res = 1;
       while (n > 0) {
             if (n % 2 != 0) 
                   res = res * x;
             x = x * x;
             n = n / 2;
       }
       return res;
}

Code : Tout sélectionner

ImportC "StaticLibrary.lib"
 
  puis.d(x.d, n.l)
  TestPuissance.d(x.d, n.l) As "_puis@12"
                                                
EndImport

Procedure.d puisPB(x.d, n.l)
  Define.d res 
  res = 1
  While n > 0
    If (n % 2) <> 0 
      res * x
    EndIf  
    x * x
    n / 2
  Wend  
  ProcedureReturn res
EndProcedure

Max = 1000000
Dim a.d(Max)
Dim v.l(Max)

For i = 0 To Max
a(i)=Random(100)
v(i)=Random(20)
Next i

Tps = ElapsedMilliseconds()
For i = 0 To Max
  puis(a(i), v(i))
Next i
Total1 = ElapsedMilliseconds()-Tps
  
Tps = ElapsedMilliseconds()
For i = 0 To Max
  puisPB(a(i), v(i))
Next i
Total2 = ElapsedMilliseconds()-Tps

MessageRequester("test",Str(Total1) + " / " + Str(Total2) , 0)

Publié : dim. 16/avr./2006 21:58
par erix14
Je viens de faire générer le fichier ASM de ta fonction par GCC pour comparer avec celui de PureBasic. C'est vrai que sur ce coup là GCC a mieux assuré. Comme par exemple ceci :
PureBasic :

Code : Tout sélectionner

; res = 1
	FLD	 qword [D1]
GCC :

Code : Tout sélectionner

	fld1
Ben alors Fred ! qu'est-ce que tu fous ! :mad:
Par compte je maintiens ce que je dis, sur les codes utilisant des cos,sin,sqrt,... Je le prouve :
PureBasic :

Code : Tout sélectionner

; f.f = Sin(12.0)
	FLD	 dword [F1]
	FSIN
	FSTP	 dword [v_f]
GCC :

Code : Tout sélectionner

	fldl	LC1
	fstpl	(%esp)
	call	_sin
	fstps	-12(%ebp)
La honte!!! :lol: :lol: :lol:
Conclusion : il y a des avantages et des inconvénients dans ces deux langages. Si vous avez des calculs avec des racines carrées, des sinus, etc. mieux vaut rester avec PureBasic...

Publié : dim. 16/avr./2006 22:05
par comtois
Je n'ai que deux Sqr() dans mes calculs , pour le reste je crois que ce n'est que des additions , des divisions , des multiplications et des soustractions, ça vaut le coup de tenter l'aventure si je gagne 50% :)

Publié : lun. 17/avr./2006 7:25
par erix14
L'écart est important parce que ta procédure est petite, ce qui a surtout fait perdre du temps à PureBasic c'est l'entrée et la sortie de la procédure.
Entrée PureBasic :

Code : Tout sélectionner

_Procedure0:
	PUSH	 ebx
PS0=16
	XOR	 eax,eax
	PUSH	 eax
	PUSH	 eax                                                                                                                                                                                                        
Entrée GCC :

Code : Tout sélectionner

__Z4puisdi:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
Sortie PureBasic :

Code : Tout sélectionner

_Wend1:
;jfhsdkfhkjk:
; ProcedureReturn res
	FLD	 qword [esp]
	MOVSX	 eax,ax
	JMP	 _EndProcedure1
; EndProcedure
	FLDZ
_EndProcedure1:
	ADD	 esp,8
	POP	 ebx
	RET	 12
Sortie GCC :

Code : Tout sélectionner

L3:
	fldl	-8(%ebp)
	leave
	ret
Si les procédures sont plus grandes, il n'est pas garanti que GCC soit plus rapide, PureBasic peut combler son retard :D
D'autre part, je ne comprends pas pourquoi tu fais une procédure pour ces quelques lignes, fait plutôt une macro. Quand on veut de la puissance, il faut éviter toutes les procédures inutiles, quitte à ce que le programme soit plus grand...

Publié : lun. 17/avr./2006 8:11
par comtois
Euh là c'était juste pour faire un test, je n'utilise pas cette fonction :)

J'ai un maximum de macros dans ma gestion des collisions.

J'utilise les procédures quand j'ai besoin de récursivité. Il reste peut-être quelques procédures que je pourrais passer en macro, il faut que je regarde ça.

Je me doute bien que sur l'ensemble de mes fonctions je ne vais pas gagner 50%, mais je suis curieux de connaître l'écart :)

Publié : lun. 17/avr./2006 15:57
par comtois
et bien je dirais que les débuts sont encourageants :)

j'ai testé la fonction suivante :
MaLib.h

Code : Tout sélectionner

struct VECTOR
{
  float x;
  float y;
  float z;
}; 

union floatlong
{
  float f;
  int   l;
};
      
typedef struct VECTOR s_vecteur;
typedef union floatlong s_floatlong;
typedef unsigned int uint32;

#define PRODUIT_SCALAIRE(V1, V2) (V1.x * V2.x + V1.y * V2.y + V1.z * V2.z)
#define in(a)((uint32) a)
Test.c

Code : Tout sélectionner

int TestPointDansTriangle(s_vecteur *point, s_vecteur *pa, s_vecteur *pb, s_vecteur *pc){
   float a, b, c, d, e; 
   s_vecteur e10, e20, vp;
   s_floatlong x, y, z;
   
   e10.x = pb->x - pa->x;
   e10.y = pb->y - pa->y;
   e10.z = pb->z - pa->z;

   e20.x = pc->x - pa->x;
   e20.y = pc->y - pa->y;
   e20.z = pc->z - pa->z;
   
   a = (e10.x * e10.x + e10.y * e10.y + e10.z * e10.z);
   b = (e10.x * e20.x + e10.y * e20.y + e10.z * e20.z);
   c = (e20.x * e20.x + e20.y * e20.y + e20.z * e20.z);

   vp.x = point->x - pa->x;
   vp.y = point->y - pa->y;
   vp.z = point->z - pa->z;
   
   d = (vp.x * e10.x + vp.y * e10.y + vp.z * e10.z);
   e = (vp.x * e20.x + vp.y * e20.y + vp.z * e20.z);
      
   x.f = (d * c) - (e * b);
   y.f = (e * a) - (d * b);
   z.f = x.f + y.f - (a * c) + (b * b);
   
   return ((z.l & ~(x.l | y.l)) & 0x80000000);

  // return ((in(z)& ~(in(x)|in(y))) & 0x80000000);
}
Elle est 50% plus rapide que ma fonction PureBasic, et apparemment plus précise, là je ne comprends pas pourquoi !

Pourquoi je dis plus précise ? j'ai fait un triangle sur le plan XY , et en mettant sa composante z à 0. autrement dit , dès qu'un point a une composante z différente de 0, il devrait se trouver en dehors du triangle, ben la fonction en C le détecte, et pas celle en PureBasic !

voila le code PB

Code : Tout sélectionner

Structure s_Vecteur
   x.f
   y.f
   z.f
EndStructure

ImportC "StaticLibrary.lib"
 
  TestPointDansTriangle.l(*point.s_Vecteur, *pa.s_Vecteur, *pb.s_Vecteur, *pc.s_Vecteur)
                                                
EndImport

#Epsilon=0.0001

Structure FloatLong
  StructureUnion
    f.f
    l.l
  EndStructureUnion
EndStructure

Macro SOUSTRACTION_VECTEUR(V, V1, V2)
   V\x = V1\x - V2\x
  	V\y = V1\y - V2\y
  	V\z = V1\z - V2\z
EndMacro 

Macro PRODUIT_SCALAIRE(V1, V2)
  	(V1\x * V2\x + V1\y * V2\y + V1\z * V2\z) 
EndMacro

;La procédure d'erix14
Procedure TestPointDansTriangleErix14(*point.s_Vecteur, *pa.s_Vecteur, *pb.s_Vecteur, *pc.s_Vecteur)
   Define.s_Vecteur e10, e20, vp
   Define.f a, b, c, d, e
   Define.FloatLong x, y, z
   
   SOUSTRACTION_VECTEUR(e10, *pb, *pa)
   SOUSTRACTION_VECTEUR(e20, *pc, *pa)
   
   a = PRODUIT_SCALAIRE(e10, e10)
   b = PRODUIT_SCALAIRE(e10, e20)
   c = PRODUIT_SCALAIRE(e20, e20)
   SOUSTRACTION_VECTEUR(vp, *point, *pa)
   d = PRODUIT_SCALAIRE(vp, e10)
   e = PRODUIT_SCALAIRE(vp, e20)
   x\f = (d * c) - (e * b)
   y\f = (e * a) - (d * b)
   z\f = x\f + y\f - (a * c) + (b * b)
   
   ProcedureReturn ((z\l & ~(x\l | y\l)) & $80000000)
EndProcedure


Define.s_Vecteur P, T1, T2, T3

;Le triangle
T1\x = 0.0
T1\y = 0.0
T1\z = 0.0

T2\x = 300.0
T2\y = 0.0
T2\z = 0.0

T3\x = 300.0
T3\y = 300.0
T3\z = 0.0


#Max = 100000

Dim Points.s_Vecteur(#Max)
For i = 1 To #Max
  Points(i)\x = Random(600) - 300
  Points(i)\y = Random(600) - 300
  Points(i)\z = Random(600) - 300
Next i

 For i = 1 To #Max 
  a = TestPointDansTriangleErix14(Points(i), @T1, @T2, @T3)
  b = TestPointDansTriangle(Points(i), @T1, @T2, @T3)
  If a <> b
  Debug a
  Debug b
  Debug Points(i)\x
  Debug Points(i)\y
  Debug Points(i)\z
  Debug "*********"
  EndIf
 Next i   
Debug "fini"
End
  
Tps = ElapsedMilliseconds()
For j = 1 To 100
For i = 1 To #Max 
  TestPointDansTriangleErix14(Points(i), @T1, @T2, @T3)
Next i
Next j
Total1 = ElapsedMilliseconds()-Tps

Tps = ElapsedMilliseconds()
For j = 1 To 100
For i = 1 To #Max 
  TestPointDansTriangle(Points(i), @T1, @T2, @T3)
Next i
Next j
Total2 = ElapsedMilliseconds()-Tps


MessageRequester("test",Str(total1) + " / " + Str(Total2) ,0)

Publié : lun. 17/avr./2006 16:46
par djes
Essaye de traiter plusieurs points dans la même boucle ;)

Publié : lun. 17/avr./2006 16:51
par comtois
djes a écrit :Essaye de traiter plusieurs points dans la même boucle ;)
C'est à dire ?

j'ai créé un tableau de points pour tester les procédures dans les mêmes conditions.

Code : Tout sélectionner

Dim Points.s_Vecteur(#Max)
For i = 1 To #Max
  Points(i)\x = Random(600) - 300
  Points(i)\y = Random(600) - 300
  Points(i)\z = Random(600) - 300
Next i 
Je ne vois pas ce que tu veux dire , tu peux me montrer un exemple ?

[EDIT]

Il y a quand même des choses étranges, parfois les deux procédures détectent un point dans le triangle avec que la composante en z du point n'est pas zéro :?

Je vais comparer avec un autre algo.

Publié : lun. 17/avr./2006 18:53
par djes
Je veux dire que tu fais appel x fois à la procédure. Rien que le fait d'appeler cette procédure et d'en revenir fait perdre beaucoup de temps (purebasic n'est pas bien optimisé là dessus, il sauve les paramètres sur la pile et les dépile en sortant, il fait un jmp, etc.; c'est très long). Essaye d'intégrer ta procédure dans la boucle et tu verras la différence.

Ensuite, si tu veux vraiment optimiser, il faut que tu essayes de mettre un maximum d'instructions dans le cache, et donc au lieu de faire une boucle qui va de 1 à n et qui appelle n fois la procédure, tu fais une boucle qui va de 1 à n/2, et tu intégres deux fois la procédure, ou alors de 1 à n/4 et tu l'intégres quatre fois, etc.

Publié : mar. 18/avr./2006 7:33
par comtois
Si je te comprends bien , je devrais éviter d'utiliser les procédures et faire un programme d'un seul bloc ? Déjà que je suis bordélique, mais alors là si je fais ça...bonjour la maintenance du code :P

Trêve de plaisanterie, j'ai essayé par curiosité de supprimer la procédure, et j'ai placé son code directement dans la boucle.

Avant avec la procédure j'avais :
Environ 120 pour PB
et environ 47 pour la fonction en C.

En supprimant la procédure :
PB = 94
C = 47

Effectivement je gagne un peu, mais la fonction en C garde l'avantage.

Publié : mar. 18/avr./2006 18:28
par erix14
Je viens de trouver le problème, effectivement il vaut mieux que tu continues avec des fonctions en C...
Dans mon premier test, PureBasic était supérieur à GCC, car je n'utilisais pas de procédure et de structure. Or il s'avère que PureBasic gère très mal les entrées sorties de procédures comme on l'a vu précédemment. Et avec ton programme tu viens de mettre à jour un autre très gros problème de PureBasic qui son les structures.
Code PureBasic :

Code : Tout sélectionner

; V1\x = 1.0
	LEA	 ebp,[v_V1]
	MOV	 dword [ebp],1065353216
; V1\y = 2.0
	MOV	 dword [ebp+4],1073741824
; V1\z = 3.0
	MOV	 dword [ebp+8],1077936128
; 
; V2\x = 4.0
	LEA	 ebp,[v_V2]
	MOV	 dword [ebp],1082130432
; V2\y = 5.0
	MOV	 dword [ebp+4],1084227584
; V2\z = 6.0
	MOV	 dword [ebp+8],1086324736
; 
; V\x = V1\x - V2\x
	LEA	 ebp,[v_V1]
	FLD	 dword [ebp]
	LEA	 ebp,[v_V2]
	FSUB	 dword [ebp]
	FADD	 dword [F1]
	LEA	 ebp,[v_V]
	FSTP	 dword [ebp]
; V\y = V1\y - V2\y
	LEA	 ebp,[v_V1]
	FLD	 dword [ebp+4]
	LEA	 ebp,[v_V2]
	FSUB	 dword [ebp+4]
	FADD	 dword [F1]
	LEA	 ebp,[v_V]
	FSTP	 dword [ebp+4]
; V\z = V1\z - V2\z
	LEA	 ebp,[v_V1]
	FLD	 dword [ebp+8]
	LEA	 ebp,[v_V2]
	FSUB	 dword [ebp+8]
	FADD	 dword [F1]
	LEA	 ebp,[v_V]
	FSTP	 dword [ebp+8]
Code GCC :

Code : Tout sélectionner

	movl	$0x3f800000, %eax
	movl	%eax, -40(%ebp)
    
	movl	$0x40000000, %eax
	movl	%eax, -36(%ebp)
    
	movl	$0x40400000, %eax
	movl	%eax, -32(%ebp)
    
	movl	$0x40800000, %eax
	movl	%eax, -56(%ebp)
    
	movl	$0x40a00000, %eax
	movl	%eax, -52(%ebp)
    
	movl	$0x40c00000, %eax
	movl	%eax, -48(%ebp)
    
	flds	-40(%ebp)
	fsubs	-56(%ebp)
	fstps	-24(%ebp)
    
	flds	-36(%ebp)
	fsubs	-52(%ebp)
	fstps	-20(%ebp)
    
	flds	-32(%ebp)
	fsubs	-48(%ebp)
	fstps	-16(%ebp)
Il va falloir absolument que Fred fasse quelque chose, car là c'est quand même très grave. Je suis vraiment très déçu :(
Pour ceux qui n'aurait pas trouvé le problème, compter le nombre de LEA...

Publié : mar. 18/avr./2006 19:06
par djes
comtois a écrit :Si je te comprends bien , je devrais éviter d'utiliser les procédures et faire un programme d'un seul bloc ? Déjà que je suis bordélique, mais alors là si je fais ça...bonjour la maintenance du code :P

Trêve de plaisanterie, j'ai essayé par curiosité de supprimer la procédure, et j'ai placé son code directement dans la boucle.

Avant avec la procédure j'avais :
Environ 120 pour PB
et environ 47 pour la fonction en C.

En supprimant la procédure :
PB = 94
C = 47

Effectivement je gagne un peu, mais la fonction en C garde l'avantage.
J'ai bien parlé d'optimisation extrême! Personne ne fait ça s'il veut pouvoir lire correctement son code! Sinon, c'est à la dernière minute qu'on fait ça. Un peu comme une image dont on garde l'original et dont on diffuse les jpeg sur les sites web.

J'avais aussi remarqué que Pure gère assez lentement les listes chainées et les structures. Il faudrait revoir une bonne partie de ce code; on pourrait le faire avec des macros, mais après pareil, c'est plus difficile à maintenir.