le compilateur manque de performances dans les boucles !

Programmation d'applications complexes
Avatar de l’utilisateur
Ganagyre
Messages : 67
Inscription : jeu. 09/nov./2006 13:41
Localisation : PACA

Un Test Suplemetaire .

Message par Ganagyre »

Rajout de While Wend.

Code : Tout sélectionner

;==========================
;      Test by Mytic
;==========================
;
DisableDebugger
; !!! désactivez le débogueur avant !!!
max = 999999999

;=================================(ASM)============================
Delay(1000)
t.d = ElapsedMilliseconds()
a.l = 0
!PUSH Eax
!PUSH Ebx
!MOV Eax,[v_a]
!MOV Ebx,[v_max]
!LP1:
!INC Eax
!CMP Eax,Ebx
!JNE LP1
!MOV [v_a],Eax
!POP Ebx
!POP Eax
S1.d = ElapsedMilliseconds()-t
;MessageRequester("ASM",StrD(S1))


;=================================(Semi ASM/PB!)============================
Delay(1000)
t.d = ElapsedMilliseconds()
a.l = 0
!PUSH Eax
!MOV Eax,[v_a]
Repeat
    !INC Eax
    !MOV [v_a],Eax
Until(a=max)
!POP Eax
S2.d = ElapsedMilliseconds()-t
;MessageRequester("Semi ASM/PB!",StrD(S2))
;=================================(PB REPEAT UNTIL!)========================
Delay(1000)
t.d = ElapsedMilliseconds()
a.l = 0
Repeat
    a+1
Until(a=max)
S3.d = ElapsedMilliseconds()-t
;MessageRequester("PB!",StrD(S3))
;=================================(PB FOR NEXT!)============================
Delay(1000)
t.d = ElapsedMilliseconds()
a=0
For a=1 To max
Next a
S4.d = ElapsedMilliseconds()-t
;MessageRequester("PB!",StrD(S3))
;=================================(PB WHILE WEND!)==========================
Delay(1000)
t.d = ElapsedMilliseconds()
a = 0
While Not (a=max) 
 a+1 
Wend
S5.d = ElapsedMilliseconds()-t

;============================( Conclusion )
R$ = "ASM                =  " + Str(S1) + #CRLF$ + "ASM Repeat    =  " + Str(S2) + #CRLF$ + "Repeat Until     =  " + Str(S3) +#CRLF$ + "For Next          =  " + Str(S4) +#CRLF$ + "While Wend      =  " + Str(S5)
MessageRequester("Comparaison",R$)

; IDE Options = PureBasic 4.30 (Windows - x86)
; CursorPosition = 46
; FirstLine = 29


Ce qui donne :

Configuration

XP
Intel Core Duo E6850 3.00 Ghz
4 Go de Ram
(36 Processus en cours et 430 mo de pris)

;====================
; ASM = 328
; ASM Repeat = 1 472
; REPEAT = 2 344
; FOR NEXT = 1 937
; WHILE WEND = 1 922
;====================

Je réitére ma demande sur comment utiliser la code ASM pour incremeter une variable pendant la boucle ?

Il serait ainsi pratique de comparer les boucles avec un petit calcul ensuite .

+
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Le test While...Wend est faussé par l'ajout de l'instruction Not.

(Not (a=b) ) == (a <> b)

En théorie, tu peux insérer ton code PB au sein d'un code ASM, mais dans la pratique, ça n'est pas possible à cause des modifs de registres qu'effectuent tes instructions PB. En gros, certaines instructions vont être ok (ex: calcul très spécifiques) si tu vérifies que l'équivalent ASM de l'instruction PB ne vient pas foirer ton/tes registre(s) de comptage. (paramètre /COMMENTED de PBCompiler.EXE pour vérifier le fichier ASM). Les autres instructions qui sont des macros de l'ensemble des fonctions dispo peuvent apporter à des foirages chaotiques, car il est impossible de vérifier l'ensemble des routines pré-compilées par Fred pour voir si elle vont foirer le(s) registre(s) de comptage utilisé(s). Pour réussir à insérer un code PB dans un code ASM, il faut procéder à une sauvegarde de registres.



Schéma:
![Début de 1ère partie de code ASM]
![Fin de 1ère partie de code ASM avec sauvegarde des registres]

[Début de code PB]
[Fin de code PB]

![Début de 2nde partie de code ASM avec restauration des registres]
![Fin de 2nde partie de code ASM]



Or, c'est ce que Fred a mis en place dans chacune de ses instructions de boucle: une sécurisation de registre, qui prend un temps non négligeable.
C'est ce laps de temps-là qui vous fait halluciner et penser que Fred a merdé. Pourtant, il n'a sûrement pas merdé. Seulement, l'ASM c'est tout sauf quelquechose de souple. Il n'y a que des types de boucles très spécifiques qui peuvent subir une absence de sécurisation des registres, notamment certains calculs (une addition, une soustraction, un swap ou une opération logique) ou l'utilisation des instructions XMM (mais là, on reste dans l'ASM et non dans les instructions PB). Pour tout le reste, il est impensable d'optimiser les boucles mieux que ce qu'elles sont déjà.

L'ASM ça n'est vraiment pas le truc souple!

Exemple:
Pour les petites boucles, il vaut mieux utiliser une étiquette, décrémenter le registre de comptage (1ère instruction) et répéter si non zéro (2nde instruction). (donc 2 instructions pour la totalité, c'est ça l'essentiel d'une boucle d'ailleurs)
Alors que pour les grosses boucles, il vaudrait mieux utiliser une étiquette, et "LOOPer" (1 seule instruction).
Problème: L'instruction n'est valable qu'à partir d'un seuil tellement arbitraire selon les CPUs qu'elle est inutilisable. Il faudrait que l'exécutable démarre en mesurant ce seuil et recompile les instructions machine pour y insérer les instructions Loop là où elles sont valables. Et il faudrait que les boucles concernées aient une très grande itération FIXE, ce qui est rarement le cas. A mon avis, on doit retrouver des instructions LOOP dans un missile à tête chercheuse. Ailleurs, je ne vois pas trop où ça pourrait être utile...

Mais bon, pour les hardis crasher, je vous ai rajouté une boucle ASM0 (faut bien qu'on rigole un peu): il n'y a juste que 2 instructions tout simplement, comme expliqué plus haut:

Code : Tout sélectionner

;==========================
;      Test by Mytic
;==========================
;
DisableDebugger
; !!! désactivez le débogueur avant !!!
max = 999999999
;=================================(ASM0)============================
;(Ollivier)
Delay(1000)
t.d = ElapsedMilliseconds()
!PUSH Ecx
!MOV Ecx,[v_max]
!LP0:     ; Etiquette de départ

          ; Ici, c'est l'intérieur de la boucle
          ; Dès qu'on insère une instruction PB,
          ; il faut absolument rajouter !PUSH Ecx
          ; avant et !POP Ecx après, ce qui revient
          ; aux même timings que FOR...NEXT
          ; ou REPEAT...UNTIL 

!DEC Ecx  ; Equivalent de Next, 1ère instruction
!JNE LP0  ; Equivalent de Next, 2nde instruction

!POP Ecx
S0.d = ElapsedMilliseconds()-t
;MessageRequester(Str(max), "")
;End
;=================================(ASM)============================
Delay(1000)
t.d = ElapsedMilliseconds()
a.l = 0
!PUSH Eax
!PUSH Ebx
!MOV Eax,[v_a]
!MOV Ebx,[v_max]
!LP1:
!INC Eax
!CMP Eax,Ebx
!JNE LP1
!MOV [v_a],Eax
!POP Ebx
!POP Eax
S1.d = ElapsedMilliseconds()-t
;MessageRequester("ASM",StrD(S1))


;=================================(Semi ASM/PB!)============================
Delay(1000)
t.d = ElapsedMilliseconds()
a.l = 0
!PUSH Eax
!MOV Eax,[v_a]
Repeat
    !INC Eax
    !MOV [v_a],Eax
Until(a=max)
!POP Eax
S2.d = ElapsedMilliseconds()-t
;MessageRequester("Semi ASM/PB!",StrD(S2))
;=================================(PB REPEAT UNTIL!)========================
Delay(1000)
t.d = ElapsedMilliseconds()
a.l = 0
Repeat
    a+1
Until(a=max)
S3.d = ElapsedMilliseconds()-t
;MessageRequester("PB!",StrD(S3))
;=================================(PB FOR NEXT!)============================
Delay(1000)
t.d = ElapsedMilliseconds()
a=0
For a=1 To max
Next a
S4.d = ElapsedMilliseconds()-t
;MessageRequester("PB!",StrD(S3))
;=================================(PB WHILE WEND!)==========================
Delay(1000)
t.d = ElapsedMilliseconds()
a = 0
While (a<>max) ; Ici j'ai viré Not (instruction inutile en plus! Olliv)
 a+1
Wend
S5.d = ElapsedMilliseconds()-t

;============================( Conclusion )
R$ = "ASM Version perso  =  " + Str(S0) + #CRLF$ + "ASM                =  " + Str(S1) + #CRLF$ + "ASM Repeat    =  " + Str(S2) + #CRLF$ + "Repeat Until     =  " + Str(S3) +#CRLF$ + "For Next          =  " + Str(S4) +#CRLF$ + "While Wend      =  " + Str(S5)
MessageRequester("Comparaison",R$)

Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Conclusion:

Le compilateur ne manque pas de performance dans les boucles!!!
kwandjeen
Messages : 204
Inscription : dim. 16/juil./2006 21:44

Message par kwandjeen »

J'avais remarqué que sur des exemples comme les votre assez simple il y a une différence notable.

Mais dès que l'on ajoute du code tout s'égalise. Je pense que cela tiens de l'optimisation à la compilation et purebasic gère ça très bien.
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Oui, et c'est très bien que l'on fasse des tests ainsi. ça permet à ceux qui découvrent ou veulent découvrir l'application de l'ASM de se faire la main contre des idées reçues. Par contre, le titre n'est pas adapté. Il insinue que PB a des lacunes alors que Fred s'est fait chier à tester sur 4 OS + créer une version 64 bits pour continuer à rester dans la haute performance (et c'est le cas!).
kwandjeen
Messages : 204
Inscription : dim. 16/juil./2006 21:44

Message par kwandjeen »

Tout à fait d'accord avec toi ollivier.

Dans mon entourage j'ai fait connaitre purebasic à quelques informaticiens et ils ont bien accroché et trouve que purebasic n'est pas assez répandu.

De l'avis de certain il n'a rien à envier a des language tel que le C.
Répondre