Entwickler-Ecke
Algorithmen, Optimierung und Assembler - [ASM] Bitmap + Scanline
user32 - Mo 09.05.11 02:52
Titel: [ASM] Bitmap + Scanline
Also, es geht hier um Optimierung einer Bitmap + Scanline Routine. Das Ganze hat weniger einen praktischen Zweck sondern ist eher zum Lernzweck für mich, da ich noch relativer Newbie bin in Assembler.
Also... Im Moment dauert es 5,8 ms um ein 1100x800 Bild mit gelb-rotem Rauschen zu füllen. Noch wichtiger: Die Funktion braucht knapp 10,7 Mio Takte (gemessen). Also 12 Takte/Pixel.. naja. Immerhin 40% schneller als nur mit Delphi. Aber das reicht mir noch nicht ;)
Ich hab schon soweit ich konnte versucht zu optimieren, aber ich denke mal da geht noch was. Sind doch gradmal <1Mio Pixel :)
Vielleicht hat ja jemand ne Idee.
Evtl. irgendwelche Opcodes die weniger Takte brauchen...?
Thx! ;)
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38:
| p := _image.ScanLine[height-1]; asm push EBX push ECX push EDX
rdtsc mov DWORD PTR[time1+$4],EDX mov DWORD PTR[time1+$0],EAX mov EAX,width mov ECX,height imul ECX,EAX xor EAX,EAX mov EDX,[p] imul EBX,ECX,3
@@again: sub EBX,3
call RandX mov BYTE PTR[EDX+EBX+$00],$00 mov BYTE PTR[EDX+EBX+$01],AL mov BYTE PTR[EDX+EBX+$02],AH loop @@again
rdtsc mov DWORD PTR[time2+$4],EDX mov DWORD PTR[time2+$0],EAX
pop EDX pop ECX pop EBX end; |
Gammatester - Mo 09.05.11 11:27
user32 hat folgendes geschrieben : |
Also... Im Moment dauert es 5,8 ms um ein 1100x800 Bild mit gelb-rotem Rauschen zu füllen. Noch wichtiger: Die Funktion braucht knapp 10,7 Mio Takte (gemessen). Also 12 Takte/Pixel.. naja. Immerhin 40% schneller als nur mit Delphi. Aber das reicht mir noch nicht ;)
Ich hab schon soweit ich konnte versucht zu optimieren, aber ich denke mal da geht noch was. Sind doch gradmal <1Mio Pixel :)
Vielleicht hat ja jemand ne Idee.
|
Wenn man sich die Schleife ansieht, wird doch wohl die meiste Zeit mit
call RandX verbraucht!? Wie sind denn die Werte, wenn diese Anweisung auskommentiert wird?
Selbst wenn es eigentlich wenig sinnvoll ist, Pseudo-Zufallsrauschen zu malen, kann man auf jedenfall Zyklen sparen, wenn der Code für RandX direkt in die Schleife eingebaut wird (selbst wenn RandX 100% optimiert ist - was auch immer das bedeutet). Ein zweiter Ansatz wäre Loop-Unrolling. Eventuell ist auch (je nach Prozessor)
sub ecx,1 / jnz @@again schneller als
loop @@again.
bummi - Mo 09.05.11 12:59
hat zwar mit ASM nicht zu tun, aber wenn Du statt für jede Zeile Scanline abzufragen direkt über die letzte Scanline mit berectneten Offsets über Höhe und Breite zugreifst kannst nochmals ordentlich Performance rausholen, Anhang ist zwar Delphi, aber das Zugriffsprinzip beleibt das gleiche
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
| Procedure FastPixel(BMP:TBitmap;LastScanLine:PCArray;x,y:Integer;Farbe:TColor); begin LastScanLine[(Bmp.Height - y) * Bmp.Width + x]:= Color2RGB(Farbe); end; procedure TForm2.Button4Click(Sender: TObject);
var x,y,w:Integer; tc:Cardinal; CArray,CArray2:PCArray; begin tc := GetTickCount; image1.Canvas.FillRect(image1.clientRect); image1.picture.Bitmap.PixelFormat := pf32bit; w := Image1.Picture.Bitmap.Width; CArray := Image1.Picture.Bitmap.ScanLine[Image1.Height - 1];
for y := 1 to image1.picture.Bitmap.Height -1 do begin for x := 0 to image1.picture.Bitmap.Width -1 do begin FastPixel(image1.picture.Bitmap,CArray,x,y,clBlue); end; end; Caption := IntToStr(GetTickCount-tc); end; |
jaenicke - Mo 09.05.11 15:18
bummi hat folgendes geschrieben : |
hat zwar mit ASM nicht zu tun, aber wenn Du statt für jede Zeile Scanline abzufragen direkt über die letzte Scanline mit berectneten Offsets über Höhe und Breite zugreifst kannst nochmals ordentlich Performance rausholen |
Deine Version ist langsamer als seine. Denn er rechnet gar nichts, sondern geht immer nur ein Pixel weiter. ScanLine wird nur am Anfang einmal aufgerufen. Du jedoch rechnest jedesmal beim Pixelzugriff, das sollte deutlich langsamer sein. ;-)
user32 - Mo 09.05.11 15:29
Hi,
bummi hat folgendes geschrieben : |
hat zwar mit ASM nicht zu tun, aber wenn Du statt für jede Zeile Scanline abzufragen direkt über die letzte Scanline mit berectneten Offsets über Höhe und Breite zugreifst kannst nochmals ordentlich Performance rausholen, Anhang ist zwar Delphi, aber das Zugriffsprinzip beleibt das gleiche
|
Ich greife doch nur einmal drauf zu! Oder meinst du Scanline VORHER abzufragen und in einer globalen Variable speichern?
Gammatester hat folgendes geschrieben : |
Wenn man sich die Schleife ansieht, wird doch wohl die meiste Zeit mit call RandX verbraucht!? Wie sind denn die Werte, wenn diese Anweisung auskommentiert wird?
Selbst wenn es eigentlich wenig sinnvoll ist, Pseudo-Zufallsrauschen zu malen, kann man auf jedenfall Zyklen sparen, wenn der Code für RandX direkt in die Schleife eingebaut wird (selbst wenn RandX 100% optimiert ist - was auch immer das bedeutet). |
Das ist eine gute Idee!
RandX wird noch von anderen Prozeduren gebraucht, deswegen hab ich garnicht dran gedacht sie hier in den Code einzugliedern! Also RandX sieht bis jetzt so aus:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| function RandX:DWORD; asm push EDX push ECX
mov EAX,RandSeed mov ECX,RandSeed imul EDX,ECX,87654321h mov RandSeed,EDX mul EDX mov EAX,EDX
pop ECX pop EDX end; |
Ich werd sie gleich mal in den Loop integrieren. Vielleicht kann ich ja die Pushs und Pops loswerden.
Gammatester hat folgendes geschrieben : |
Ein zweiter Ansatz wäre Loop-Unrolling. Eventuell ist auch (je nach Prozessor) sub ecx,1 / jnz @@again schneller als loop @@again. |
Jnz hab ich schon probiert. War ganze 10ms langsamer...warum auch immer. :crying:
Ich werds mir gleich mal angucken!
Mfg
---
Moderiert von
Narses: Beiträge zusammengefasst---
4,5 Millisek bzw. 7,1 Millionen clock cycles.
Hm ja, mit dem LFSR bin ich mir nicht sicher, ob ich es richtig gemacht habe. Sieht jedenfalls ziemlich zufällig aus.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50:
| p := _image.ScanLine[height-1]; asm push EBX push ECX push EDX push ESI push EDI
rdtsc mov DWORD PTR[time1+$4],EDX mov DWORD PTR[time1+$0],EAX
mov EAX,width mov ECX,height imul ECX,EAX mov EDX,[p] imul EBX,ECX,3 mov ESI,EDX
@@again: sub EBX,3 mov EAX,RandSeed mov EDI,$409 xor EAX,EDI rol EAX,1 INC EAX mov RandSeed,EAX mul EDI mov BYTE PTR[ESI+EBX+$00],$00 mov BYTE PTR[ESI+EBX+$01],AL mov BYTE PTR[ESI+EBX+$02],AH loop @@again
rdtsc mov DWORD PTR[time2+$4],EDX mov DWORD PTR[time2+$0],EAX
pop EDI pop ESI pop EDX pop ECX pop EBX end; |
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!