Asm Geschwindigkeit
Asm Geschwindigkeit
Habe mal wieder eine Frage zu ASM:
Wie kriege ich raus welche ASM-Codes schnell sind? Des öfteren hat man ja verschiedene Möglichkeiten wie man etwas implementieren kann.
Muss ich da performance-tests machen (die dann nur für meine CPU zutreffend sind) oder gibt es da eventuell Möglichkeiten irgendwas über Taktzyklen usw. festzustellen?
Wie kriege ich raus welche ASM-Codes schnell sind? Des öfteren hat man ja verschiedene Möglichkeiten wie man etwas implementieren kann.
Muss ich da performance-tests machen (die dann nur für meine CPU zutreffend sind) oder gibt es da eventuell Möglichkeiten irgendwas über Taktzyklen usw. festzustellen?
Re: Asm Geschwindigkeit
Dafür brauchst du aber eine recht moderne CPU: http://www.purebasic.fr/german/viewtopi ... 2&p=257579
Und die Messung ist immer spezifisch zu deiner CPU, egal wie du misst. Gleiche Instruktionen können auf unterschiedlichen CPU's unterschiedlich viele Zyklen benötigen.
Es gibt ein paar Grundregeln an die man sich halten kann: http://www.intel.com/Assets/PDF/manual/248966.pdf
Und die Messung ist immer spezifisch zu deiner CPU, egal wie du misst. Gleiche Instruktionen können auf unterschiedlichen CPU's unterschiedlich viele Zyklen benötigen.
Es gibt ein paar Grundregeln an die man sich halten kann: http://www.intel.com/Assets/PDF/manual/248966.pdf
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.
Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke!
Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke!

Re: Asm Geschwindigkeit
Gibts da nicht auch Programme, die einen kurzen Bytefetzen anaylsieren können und schätzen, wie lange das dauert?
Frag mich gerade, was du in der heutigen Zeit so kritisches Programmierst? Auf Konsolen etc. würde es ja noch Sinn machen, weil da die Hardware relativ fest ist - aber bei PCs?
Eine solche Extreme Optimierung ist ja kaum noch nötig, oder?
Frag mich gerade, was du in der heutigen Zeit so kritisches Programmierst? Auf Konsolen etc. würde es ja noch Sinn machen, weil da die Hardware relativ fest ist - aber bei PCs?
Eine solche Extreme Optimierung ist ja kaum noch nötig, oder?
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Re: Asm Geschwindigkeit
Naja, für mein jetztiges Programm habe ich es zum ersten mal verwendet. Ich muss halt Pixeldaten von mehreren (unter Umständen 1080p-) Bildern verarbeiten. Da ist es schon angenehmer, wenn da nicht nur alle 2-3 Sekunden eine Aktualisierung erfolgt, wie als ich das mit einer Doppelschleife und Peek / Poke gemacht habe. Alleine die Schleifen (Peek und Poke ersetzen bin ich dann schnell drauf gekommen) waren so langsam, das es praktisch nicht möglich ist die zu benutzen. Inzwischen bin ich dazu übergegangen diesen ganzen Teil in ASM zu schreiben, sodass ich nichtmal mehr Variablen für die Counter usw verwende sondern nur Register. Problem ist halt nur zu wissen, was da denn nun schnell ist. Wenn man sich schon die Arbeit macht das in ASM zu schreiben, dann doch wenigstens vernünftig.GPI hat geschrieben:Gibts da nicht auch Programme, die einen kurzen Bytefetzen anaylsieren können und schätzen, wie lange das dauert?
Frag mich gerade, was du in der heutigen Zeit so kritisches Programmierst? Auf Konsolen etc. würde es ja noch Sinn machen, weil da die Hardware relativ fest ist - aber bei PCs?
Eine solche Extreme Optimierung ist ja kaum noch nötig, oder?
Dazu auch Danke an Thorium für die Links.

Ansonsten reicht mir normalerweise Purebasic von der Geschwindigkeit völlig aus.
Re: Asm Geschwindigkeit
Das kann man nicht pauschal beantworten. Kommt halt immer drauf an was man machen möchte. Optimierung macht Sinn, wenn große Datenmengen in möglichst geringer Zeit verarbeitet werden müssen.GPI hat geschrieben: Eine solche Extreme Optimierung ist ja kaum noch nötig, oder?
Als Beispiel ein Filter für Bilddaten, den ich mal geschrieben habe, hat mit reinem PB-Code ca. 200MB/s durchgeackert. Die Assemblerimplementation hat dann ca 500MB/s durchgeackert und die SSE2-Implementation ca 11GB/s.
Das heisst eine Geschwindigkeitszuwachs von 550% durch Assembleroptimierung mit SSE2.
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.
Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke!
Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke!

Re: Asm Geschwindigkeit
Kleines MIssverständis. Dachte mehr so dran, das man mit den Befehl 2 Taktcyclen weniger braucht und solche Scherze.
Sowas war beim C64 notwendig, weil man da wirklich alles gebrauchen konnte, was man bekommen konnte. Aber bei den heutigen PCs auf einen Prozessor überoptimieren ist etwas übertrieben.
Sowas war beim C64 notwendig, weil man da wirklich alles gebrauchen konnte, was man bekommen konnte. Aber bei den heutigen PCs auf einen Prozessor überoptimieren ist etwas übertrieben.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Re: Asm Geschwindigkeit
Das ist heute recht ähnlich. Wenn du in einer Schleife 2 Taktzyklen sparen kannst, macht sich das natürlich stark bemerkbar, wenn die Schleife ne milliarde mal durchgeackert wird. Dann spart zu nämlich 2 milliarden Taktzyklen.GPI hat geschrieben:Kleines MIssverständis. Dachte mehr so dran, das man mit den Befehl 2 Taktcyclen weniger braucht und solche Scherze.
Sowas war beim C64 notwendig, weil man da wirklich alles gebrauchen konnte, was man bekommen konnte. Aber bei den heutigen PCs auf einen Prozessor überoptimieren ist etwas übertrieben.
Das Problem ist nur das es sich halt von CPU zu CPU unterscheiden kann. Was sich aber immer lohnt ist es SIMD Instruktionen zu verwenden, wo immer es möglich ist, also MMX, SSE, etc.
SIMD steht für Single Instruction Multiple Data. Bei x86 CPU's benötigen SIMD Instuktionen, die nicht auf den Speicher zugreifen, immer nur einen Taktzyklus. Dabei verarbeiten sie aber bis zu 16 Datensätze.
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.
Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke!
Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke!

Re: Asm Geschwindigkeit
Ja, dahin geht ja auch mein Projekt. Ist dein Assemblercode zu diesem Filter irgendwo verfügbar? Ist ja vielleicht ganz interessant wie das so implementiert ist.Thorium hat geschrieben:Als Beispiel ein Filter für Bilddaten, den ich mal geschrieben habe, hat mit reinem PB-Code ca. 200MB/s durchgeackert. Die Assemblerimplementation hat dann ca 500MB/s durchgeackert und die SSE2-Implementation ca 11GB/s.
Das heisst eine Geschwindigkeitszuwachs von 550% durch Assembleroptimierung mit SSE2.
Auf jeden Fall werde ich mir mal was zu SSE angucken, wenn das doch so viel rausholen kann, würde sich das ja lohnen, sich damit mal zu beschäftigen.
Re: Asm Geschwindigkeit
Ich hab die PNG Filter für mein Bildformat implementiert.Batze hat geschrieben: Ist dein Assemblercode zu diesem Filter irgendwo verfügbar? Ist ja vielleicht ganz interessant wie das so implementiert ist.
Auf jeden Fall werde ich mir mal was zu SSE angucken, wenn das doch so viel rausholen kann, würde sich das ja lohnen, sich damit mal zu beschäftigen.
Hier der Up Filter:
PB-Implementation
Code: Alles auswählen
Protected.i X, ByteSize
Protected *ActualChannel.Tsi_Pixel_Channel
Protected *PriorChannel.Tsi_Pixel_Channel
*PriorChannel = *ImageData
*ActualChannel = *ImageData + Width * 4
Height - 1
ByteSize = Width * Height * 4
For X = 1 To ByteSize
*ActualChannel\Channel = *ActualChannel\Channel + *PriorChannel\Channel
*ActualChannel + 1
*PriorChannel + 1
Next
Code: Alles auswählen
!push esi
!push edi
!mov eax,[p.v_Height+8]
!dec eax
!mul dword[p.v_Width+8]
!mov ecx,eax
!mov edi,[p.p_ImageData+8]
!mov esi,edi
!mov edx,[p.v_Width+8]
!shl edx,2
!add edi,edx
!align 4
!Tsi_UnFilterUp_LoopStart:
!mov al,[edi]
!add al,[esi]
!mov [edi],al
!mov al,[edi+1]
!add al,[esi+1]
!mov [edi+1],al
!mov al,[edi+2]
!add al,[esi+2]
!mov [edi+2],al
!mov al,[edi+3]
!add al,[esi+3]
!mov [edi+3],al
!add esi,4
!add edi,4
!dec ecx
!jne Tsi_UnFilterUp_LoopStart
!pop edi
!pop esi
Code: Alles auswählen
;save registers
!push esi
!push edi
;calculate the counters
!mov eax,[p.v_Height+8]
!dec eax
!mul dword[p.v_Width+8]
!mov ecx,eax
!shr ecx,4
!and eax,15
;calculate the pointers
!mov edi,[p.p_ImageData+8]
!mov esi,edi
!mov edx,[p.v_Width+8]
!shl edx,2
!add edi,edx
;process a part of the data to cut the length to a multiple of 64
!test eax,eax
!je Tsi_UnFilterUp_MmxCutLengthEnd
!align 4
!Tsi_UnFilterUp_MmxCutLengthStart:
!movd mm0,[esi]
!movd mm1,[edi]
!paddb mm0,mm1
!movd [edi],mm0
!add esi,4
!add edi,4
!dec eax
!jne Tsi_UnFilterUp_MmxCutLengthStart
!align 4
!Tsi_UnFilterUp_MmxCutLengthEnd:
;process the rest of the data
!test ecx,ecx
!je Tsi_UnFilterUp_MmxLoopEnd
!align 4
!Tsi_UnFilterUp_MmxLoopStart:
!movq mm0,[esi]
!movq mm1,[esi+8]
!movq mm2,[esi+16]
!movq mm3,[esi+24]
!movq mm4,[esi+32]
!movq mm5,[esi+40]
!movq mm6,[esi+48]
!movq mm7,[esi+56]
!paddb mm0,[edi]
!paddb mm1,[edi+8]
!paddb mm2,[edi+16]
!paddb mm3,[edi+24]
!paddb mm4,[edi+32]
!paddb mm5,[edi+40]
!paddb mm6,[edi+48]
!paddb mm7,[edi+56]
!movq [edi],mm0
!movq [edi+8],mm1
!movq [edi+16],mm2
!movq [edi+24],mm3
!movq [edi+32],mm4
!movq [edi+40],mm5
!movq [edi+48],mm6
!movq [edi+56],mm7
!add esi,64
!add edi,64
!dec ecx
!jne Tsi_UnFilterUp_MmxLoopStart
!align 4
!Tsi_UnFilterUp_MmxLoopEnd:
;restore the registers
!pop edi
!pop esi
;end MMX state
!emms
Code: Alles auswählen
;save registers
!push esi
!push edi
;calculate the counters
!mov eax,[p.v_Height+8]
!dec eax
!mul dword[p.v_Width+8]
!mov ecx,eax
!shr ecx,5
!and eax,31
;calculate the pointers
!mov edi,[p.p_ImageData+8]
!mov esi,edi
!mov edx,[p.v_Width+8]
!shl edx,2
!add edi,edx
;process a part of the data to cut the length to a multiple of 128
!test eax,eax
!je Tsi_UnFilterUp_Sse2CutLengthEnd
!align 4
!Tsi_UnFilterUp_Sse2CutLengthStart:
!movd mm0,[esi]
!movd mm1,[edi]
!paddb mm0,mm1
!movd [edi],mm0
!add esi,4
!add edi,4
!dec eax
!jne Tsi_UnFilterUp_Sse2CutLengthStart
!align 4
!Tsi_UnFilterUp_Sse2CutLengthEnd:
;process the rest of the data
!test ecx,ecx
!je Tsi_UnFilterUp_Sse2LoopEnd
!align 4
!Tsi_UnFilterUp_Sse2LoopStart:
!movdqu xmm0,[esi]
!movdqu xmm1,[esi+16]
!movdqu xmm2,[esi+32]
!movdqu xmm3,[esi+48]
!movdqu xmm4,[esi+64]
!movdqu xmm5,[esi+80]
!movdqu xmm6,[esi+96]
!movdqu xmm7,[esi+112]
!paddb xmm0,[edi]
!paddb xmm1,[edi+16]
!paddb xmm2,[edi+32]
!paddb xmm3,[edi+48]
!paddb xmm4,[edi+64]
!paddb xmm5,[edi+80]
!paddb xmm6,[edi+96]
!paddb xmm7,[edi+112]
!movdqu [edi],xmm0
!movdqu [edi+16],xmm1
!movdqu [edi+32],xmm2
!movdqu [edi+48],xmm3
!movdqu [edi+64],xmm4
!movdqu [edi+80],xmm5
!movdqu [edi+96],xmm6
!movdqu [edi+112],xmm7
!add esi,128
!add edi,128
!dec ecx
!jne Tsi_UnFilterUp_Sse2LoopStart
!align 4
!Tsi_UnFilterUp_Sse2LoopEnd:
;restore the registers
!pop edi
!pop esi
;end MMX state
!emms
Der Trick dabei ist halt das man Instruktionen hat, die eine Operation auf mehrere Daten anwenden in nur einem Tacktzyklus: das SIMD Prinzip.
Dafür hast du bei MMX die 64bit breiten MMX-Register und bei SSE die 128bit breiten XMM-Register. Das kommende AVX wird die 256bit breiten YMM-Register einführen.
Nun das ganze funktioniert so indem man mit sogenannten gepackten Daten arbeitet. Damit ist gemeint das ein Register mehrere Daten enthalten kann. Ein MMX-Register kann 8 Bytes oder 4 Words oder 2 DoubleWords oder 2 Floats enthalten. Nun liefert MMX dir Instruktionen, welche die MMX-Register miteinander verrechnen können und dabei die einzelnen Daten beachten anstatt das komplette Register.
z.b. paddb steht für "Packed Addition Byte"
Das heisst mit der Instruktion: paddb mm0,mm1
Werden die einzelnen Bytes des mm0 Registers mit den einzelnen Bytes des mm1 Registers Addiert und im mm0 Register abgelegt.
Das heisst es werden 8 Additionen auf einen Schlag ausgeführt.
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.
Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke!
Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke!

Re: Asm Geschwindigkeit
Vielen Dank, das ist wirklich sehr hilfreich.
Mit MMX oder noch besser SSE2 sollte sich da ja bei Bilddatenverarbeiten wirklich unglaublich viel sparen lassen.
Gibt es einen Grund, dass du in einem Durchgang 128 Bytes nacheinander verarbeitest? Um Sprünge zu sparen, oder alles hintereinander einzulessen, oder so ähnlich?

Mit MMX oder noch besser SSE2 sollte sich da ja bei Bilddatenverarbeiten wirklich unglaublich viel sparen lassen.
Gibt es einen Grund, dass du in einem Durchgang 128 Bytes nacheinander verarbeitest? Um Sprünge zu sparen, oder alles hintereinander einzulessen, oder so ähnlich?