::PtInRect(): 0.987226s
Lesbare Version: 0.32199s
Jörgs Version: 0.375697s
Soo, der Reihe nach: Danke, Helmut, dass du mich auf
::PtInRect() aufmerksam gemacht hast. Irgendwo
musste ja ein Makro oder eine Funktion existieren, das/die diese Aufgabe erledigt – der kryptische Name hatte mir die Suche aber vermasselt …
… mit der Funktion gibt es drei Probleme: Zum einen verrät mir die Disassembly, dass sie die logischen ANDs und damit drei Sprünge benutzt. Zum Anderen weigert sich VC, sie zu inlinen. Zu guter Letzt benutzt sie
BOOL statt
bool und VC wirft deswegen schon im Voraus eine Performance-Warnung.
Die Disassembly meiner Funktion (inline, für einen einzelnen Schleifendurchgang):
Code: Alles auswählen
mov eax,dword ptr [ebp+54h]
mov edi,dword ptr [ebp+64h]
xor esi,esi
add eax,4
mov dword ptr [ebp+54h],eax
lea esp,[esp]
mov edx,dword ptr [edi+4]
cmp edx,dword ptr [eax+8]
mov ecx,dword ptr [edi]
setl dl
cmp ecx,dword ptr [eax-4]
setge bl
and dl,bl
cmp ecx,dword ptr [eax+4]
setl cl
and dl,cl
mov ecx,dword ptr [edi+4]
cmp ecx,dword ptr [eax]
setge cl
and dl,cl
mov ecx,dword ptr [ebp+50h]
mov byte ptr [esi+ecx],dl
Die Kürze gestern lag also tatsächlich daran, dass ich die Schleife zu Viererblöcken abgerollt hatte.
Jörg, was deine neue Funktion angeht (ich habe wieder die zwei Dekrementierungen ergänzt), das hier ist ihre Disassembly (für einen einzelnen Schleifendurchgang):
Code: Alles auswählen
mov eax,dword ptr [ebp+64h]
mov ecx,dword ptr [eax]
mov eax,dword ptr [eax+4]
mov esi,dword ptr [edx]
sub esi,eax
mov edi,eax
mov eax,dword ptr [edx-4]
sub edi,dword ptr [edx+8]
sub eax,ecx
sub ecx,dword ptr [edx+4]
dec eax
dec esi
or eax,esi
not eax
or ecx,eax
or ecx,edi
mov ecx,dword ptr [ebp+50h]
setl al
add dword ptr [ebp+64h],8
mov byte ptr [ebx+ecx],al
Sie ist zwei Anweisungen kürzer, aber trotzdem langsamer (auch dann noch, wenn ich die Ausführungsreihenfolge mit der lesbaren Version vertausche).
@Sprünge: Selbst, wenn der erste Sprung die restlichen drei Vergleiche überspringen kann ist die Performance immernoch schlechter, weil der dann auszuführende Code nicht bereit in der Pipeline liegt. Die Sprungvorhersage einer CPU kann noch so effizient arbeiten, wenn der Sprung (wie hier) auf einer direkt zuvor ausgeführten Vergleichsoperation beruht, kann man das garnicht out-of-order genug ausführen, um
nicht zu verlieren. Natürlichen können Sprünge große Brocken Ausführungszeit abfangen und ich will nicht verallgemeinern, dass sprungfreier Code schneller wäre – aber diese Mini-Funktion hier wird nunmal mehr als doppelt so schnell (und, wie Helmut richtig bemerkte, ein wenig kleiner), sobald man ihre Sprünge weglässt. Kannst das ja gerne testen, ich bitte dich sogar darum, schließlich haben wir hier immernoch keine Ergebnisse von anderen CPUs als meinem Core 2 Quad.