Seite 1 von 1

PB und MMX

Verfasst: 06.07.2006 17:02
von Helle
Hier ein kleines Beispiel für die Verwendung von MMX-Befehlen in PB.
Es werden 8 Bytes gleichzeitig verändert, ohne das ein Byte das andere beeinflusst oder "überläuft". Ein möglicher Einsatzzweck wären Helligkeits-oder Farbänderungen in Bildern usw.

Code: Alles auswählen

;-------- Beispiel für MMX-Addition (Saturationstest)
;-------- Byte-weise Addition ohne Überlauf und mit Rückgabe des Maximal-Wertes FFh (Saturation)
;-------- "Helle" Klaus Helbing 06.07.2006 PB4.0 
;-------- Inline-Asm einschalten!!!
;-------- Test auf Verfügbarkeit von MMX geschenkt! Ebenso die Sicherung der FPU-Register-Werte

Global X.l = 0
Global Y.q = 0
Global summand1.q = $ff1111aa111111ee  ;irgendwelche Beispiel-Werte
Global summand2.q = $22667788224433cc

 *MemoryID = AllocateMemory(8)         ;hier nur mal 8 Bytes für einen Quad-Wert reservieren
 MOV esi,*MemoryID                     ;damit kann FAsm so nichts anfangen, deshalb Inline-Asm einschalten!
 
 X = @summand1
 MOV ebx,[v_X]
!movq mm0,[ebx]                        ;mit MMX-Befehlen kann PB nichts anfangen

 X = @summand2
 MOV ebx,[v_X]
!movq mm1,[ebx]

!paddusb mm0,mm1
!movq [esi],mm0

 Y = PeekQ(*MemoryID)
MessageRequester("MMX-Addition (Saturation)",HexQ(Y))

End
Gruss
Helle

Verfasst: 06.07.2006 17:07
von MVXA
Danke. Ich habe schon mal versucht mit MMX rum zu spielen aber die
Ergebnisse waren alles andere als befriedigend. Zum Beispiel hat es
zu viel Zeit gekostet für die rechnungen.

Ich schau mir deins sofort an :).

Verfasst: 07.07.2006 12:10
von remi_meier

Code: Alles auswählen

!EMMS
:)

Verfasst: 07.07.2006 12:16
von Deeem2031
Solang er keine Floats/Doubles benutzt ist doch alles ok ;)

Verfasst: 07.07.2006 13:06
von remi_meier
Schön gesagt :roll:

Verfasst: 29.07.2006 16:04
von DarkDragon
Sorry, dass ich das Thema nochmal raufhol, aber ich habe mich ein wenig mit MMX/3DNow beschäftigt und folgendes kam dabei heraus:

Code: Alles auswählen

#COUNT = 25000000

SetPriorityClass_(GetCurrentProcess_(), #REALTIME_PRIORITY_CLASS)

Dim Value1.f(2)
Dim Value2.f(2)
Dim Result.f(2)

Value1(0) = 1.5
Value1(1) = 2.0

Value2(0) = 3.0
Value2(1) = 4.0

Result(0) = 0.0
Result(1) = 0.0

k.l = 0
Timer.l = 0
Time1.l = 0
Time2.l = 0

Timer = ElapsedMilliseconds()
For k=0 To #COUNT
  !femms
  
  !mov esi, [a_Value2]
  !mov ebx, [a_Value1]
  !mov edi, [a_Result]
  
  !movq mm1, [esi]
  !movq mm0, [ebx]
  
  !pfadd mm0, mm1
  
  !movq [edi], mm0
  
  !femms
Next
Time1 = ElapsedMilliseconds()-Timer

MessageRequester("Added with 3DNow/MMX", "X/Y: "+StrF(Result(0), 2) + "/" + StrF(Result(1), 2))

Timer = ElapsedMilliseconds()
For k=0 To #COUNT
  Result(0) = Value1(0) + Value2(0)
  Result(1) = Value1(1) + Value2(1)
Next
Time2 = ElapsedMilliseconds()-Timer

MessageRequester("Added without 3DNow/MMX", "X/Y: "+StrF(Result(0), 2) + "/" + StrF(Result(1), 2))
MessageRequester("Timer", "Time with 3DNow/MMX: " + Str(Time1) + Chr(10) + "Time without 3DNow/MMX: " + Str(Time2))
End

Verfasst: 30.07.2006 20:12
von Helle
Hallo DarkDragon,
da Du in Deinem Beispiel 3DNow!-Befehle (femms und pfadd) benutzt, funktioniert das Ganze nur auf AMD-Kisten. mit Intel crasht es.
Deshalb hier ein Beispiel mit SSE anstelle von 3DNow!, so das AMD- und Intel-Besitzer sehen können, was Du meinst:

Code: Alles auswählen

#COUNT = 25000000 

SetPriorityClass_(GetCurrentProcess_(), #REALTIME_PRIORITY_CLASS) 

Dim Value1.f(2) 
Dim Value2.f(2) 
Dim Result.f(2) 

Value1(0) = 1.5 
Value1(1) = 2.0 

Value2(0) = 3.0 
Value2(1) = 4.0 

Result(0) = 0.0 
Result(1) = 0.0 

k.l = 0 
Timer.l = 0 
Time1.l = 0 
Time2.l = 0 

Timer = ElapsedMilliseconds() 

SSESich.l = AllocateMemory(512)        ;Zur Sicherung der SSE-Umgebung werden 512 Bytes benötigt
  !MOV edx,[v_SSESich]
  !fxsave [edx]                        ;Sichert unter anderem die SSE-Umgebung  
For k=0 To #COUNT 
  !mov esi, [a_Value2] 
  !mov ebx, [a_Value1] 
  !mov edi, [a_Result] 
  
  !movq xmm1, [esi] 
  !movq xmm0, [ebx] 
  
  !addps xmm0, xmm1                    ;Hier werden nur 2 der 4 möglichen Floats genutzt - da steckt noch
                                       ;viel Reserve drin! Aber SSE ist schon wieder ein anderes Thema!  
  !movq [edi], xmm0 
Next 
  !fxrstor [edx]                       ;"Alte" SSE-Umgebung zurückholen 

Time1 = ElapsedMilliseconds()-Timer 

MessageRequester("Added with SSE/MMX", "X/Y: "+StrF(Result(0), 2) + "/" + StrF(Result(1), 2)) 

Timer = ElapsedMilliseconds() 
For k=0 To #COUNT 
  Result(0) = Value1(0) + Value2(0) 
  Result(1) = Value1(1) + Value2(1) 
Next 
Time2 = ElapsedMilliseconds()-Timer 

MessageRequester("Added without SSE/MMX", "X/Y: "+StrF(Result(0), 2) + "/" + StrF(Result(1), 2)) 
MessageRequester("Timer", "Time with SSE/MMX: " + Str(Time1) + Chr(10) + "Time without SSE/MMX: " + Str(Time2)) 
End
Die Sicherung der SSE-Umgebung habe ich aus der Schleife rausgenommen, sonst bricht die Performance drastisch ein. Es soll aus meiner Sicht ja ein Lehr-Beispiel sein :D .

Gruss
Helle