PB und MMX

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

PB und MMX

Beitrag 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
Benutzeravatar
MVXA
Beiträge: 3823
Registriert: 11.09.2004 00:45
Wohnort: Bremen, Deutschland
Kontaktdaten:

Beitrag 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 :).
Bild
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Beitrag von remi_meier »

Code: Alles auswählen

!EMMS
:)
Benutzeravatar
Deeem2031
Beiträge: 1232
Registriert: 29.08.2004 00:16
Wohnort: Vorm Computer
Kontaktdaten:

Beitrag von Deeem2031 »

Solang er keine Floats/Doubles benutzt ist doch alles ok ;)
Bild
[url=irc://irc.freenode.org/##purebasic.de]irc://irc.freenode.org/##purebasic.de[/url]
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Beitrag von remi_meier »

Schön gesagt :roll:
DarkDragon
Beiträge: 6291
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Beitrag 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
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag 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
Antworten