151 lines
7.3 KiB
HTML
151 lines
7.3 KiB
HTML
<HTML>
|
|
<HEAD>
|
|
<META name=vsisbn content="1576101746">
|
|
<META name=vstitle content="Michael Abrash's Graphics Programming Black Book, Special Edition">
|
|
<META name=vsauthor content="Michael Abrash">
|
|
<META name=vspublisher content="The Coriolis Group">
|
|
<META name=vspubdate content="07/01/97">
|
|
<META name=vscategory content="Web and Software Development: Game Development,Web and Software Development: Graphics and Multimedia Development">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<TITLE>Michael Abrash's Graphics Programming Black Book Special Edition: Unleashing the Pentium's</TITLE>
|
|
|
|
<!-- HEADER -->
|
|
<!-- Empty Reference Subhead -->
|
|
|
|
<!--ISBN=1576101746//-->
|
|
<!--TITLE=Michael Abrash's Graphics Programming Black Book Special Edition//-->
|
|
<!--AUTHOR=Michael Abrash//-->
|
|
<!--PUBLISHER=The Coriolis Group, Inc.//-->
|
|
<!--CHAPTER=21//-->
|
|
<!--PAGES=409-411//-->
|
|
<!--UNASSIGNED1//-->
|
|
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
|
|
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="21-04.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="22-01.html">Next</A></TD>
|
|
</TR>
|
|
</TABLE>
|
|
</CENTER>
|
|
<P><BR></P>
|
|
<P><B>LISTING 21.4 L21-4.ASM</B></P>
|
|
<!-- CODE //-->
|
|
<PRE>
|
|
; Calculates TCP/IP (16-bit carry-wrapping) checksum for buffer
|
|
; starting at ESI, of length ECX words.
|
|
; Returns checksum in AX.
|
|
; High word of EAX, ECX, EDX, and ESI destroyed.
|
|
; All cycle counts assume 32-bit protected mode.
|
|
; Assumes buffer starts on a dword boundary, is a dword multiple
|
|
; in length, and length > 0.
|
|
|
|
sub eax,eax ;initialize the checksum
|
|
shr ecx,1 ;we’ll do two words per loop
|
|
mov edx,[esi] ;preload the first dword
|
|
add esi,4 ;point to the next dword
|
|
dec ecx ;we’ll do 1 checksum outside the loop
|
|
jz short ckloopend ;only 1 checksum to do
|
|
|
|
ckloop:
|
|
add eax,edx ;cycle 1 U-pipe
|
|
mov edx,[esi] ;cycle 1 V-pipe
|
|
adc eax,0 ;cycle 2 U-pipe
|
|
add esi,4 ;cycle 2 V-pipe
|
|
dec ecx ;cycle 3 U-pipe
|
|
jnz ckloop ;cycle 3 V-pipe
|
|
|
|
ckloopend:
|
|
add eax,edx ;checksum the last dword
|
|
adc eax,0
|
|
mov edx,eax ;compress the 32-bit checksum
|
|
shr edx,16 ; into a 16-bit checksum
|
|
add ax,dx
|
|
adc eax,0
|
|
</PRE>
|
|
<!-- END CODE //-->
|
|
<P>Listing 21.5 improves upon Listing 21.4 by processing 2 dwords per loop, thereby bringing the time per checksummed word down to exactly 1 cycle. Listing 21.5 basically does nothing but unroll Listing 21.4’s loop one time, demonstrating that the venerable optimization technique of loop unrolling still has some life left in it on the Pentium. The cost for this is, as usual, increased code size and complexity, and the use of more registers.
|
|
</P>
|
|
<P><B>LISTING 21.5 L21-5.ASM</B></P>
|
|
<!-- CODE //-->
|
|
<PRE>
|
|
; Calculates TCP/IP (16-bit carry-wrapping) checksum for buffer
|
|
; starting at ESI, of length ECX words.
|
|
; Returns checksum in AX.
|
|
; High word of EAX, EBX, ECX, EDX, and ESI destroyed.
|
|
; All cycle counts assume 32-bit protected mode.
|
|
; Assumes buffer starts on a dword boundary, is a dword multiple
|
|
; in length, and length > 0.
|
|
|
|
sub eax,eax ;initialize the checksum
|
|
shr ecx,2 ;we’ll do two dwords per loop
|
|
jnc short noodddword ;is there an odd dword in buffer?
|
|
mov eax,[esi] ;checksum the odd dword
|
|
jz short ckloopdone ;no, done
|
|
add esi,4 ;point to the next dword
|
|
noodddword:
|
|
mov edx,[esi] ;preload the first dword
|
|
mov ebx,[esi+4] ;preload the second dword
|
|
dec ecx ;we’ll do 1 checksum outside the loop
|
|
jz short ckloopend ;only 1 checksum to do
|
|
add esi,8 ;point to the next dword
|
|
|
|
ckloop:
|
|
add eax,edx ;cycle 1 U-pipe
|
|
mov edx,[esi] ;cycle 1 V-pipe
|
|
adc eax,ebx ;cycle 2 U-pipe
|
|
mov ebx,[esi+4] ;cycle 2 V-pipe
|
|
adc eax,0 ;cycle 3 U-pipe
|
|
add esi,8 ;cycle 3 V-pipe
|
|
dec ecx ;cycle 4 U-pipe
|
|
jnz ckloop ;cycle 4 V-pipe
|
|
|
|
ckloopend:
|
|
add eax,edx ;checksum the last two dwords
|
|
adc eax,ebx
|
|
adc eax,0
|
|
ckloopdone:
|
|
mov edx,eax ;compress the 32-bit checksum
|
|
shr edx,16 ; into a 16-bit checksum
|
|
add ax,dx
|
|
adc eax,0
|
|
</PRE>
|
|
<!-- END CODE //-->
|
|
<P>Listing 21.5 is undeniably intricate code, and not the sort of thing one would choose to write as a matter of course. On the other hand, it’s five times as fast as the tight, seemingly-speedy loop in Listing 21.1 (and six times as fast as Listing 21.1 would have been if the prefix byte had behaved as expected). That’s an awful lot of speed to wring out of a five-instruction loop, and the TCP/IP checksum is, in fact, used by network software, an area in which a five-times speedup might make a significant difference in overall system performance.
|
|
</P>
|
|
<P>I don’t claim that Listing 21.5 is the fastest possible way to do a TCP/IP checksum on a Pentium; in fact, it isn’t. Unrolling the loop one more time, together with a trick of Terje’s that uses <B>LEA</B> to advance ESI (neither <B>LEA</B> nor <B>DEC</B> affects the carry flag, allowing Terje to add the carry from the previous loop iteration into the next iteration’s checksum via <B>ADC</B>), produces a version that’s a full 33 percent faster. Nonetheless, Listings 21.1 through 21.5 illustrate many of the techniques and considerations in Pentium optimization. Hand-optimization for the Pentium isn’t simple, and requires careful measurement to check the efficacy of your optimizations, so reserve it for when you really, really need it—but when you need it, you need it <I>bad</I>.</P>
|
|
<H4 ALIGN="LEFT"><A NAME="Heading8"></A><FONT COLOR="#000077">A Quick Note on the 386 and 486</FONT></H4>
|
|
<P>I’ve mentioned that Pentium-optimized code does fine on the 486, but not always so well on the 386. On a 486, Listing 21.1 runs at 9 cycles per checksummed word, and Listing 21.5 runs at 2.5 cycles per checksummed word, a healthy 3.6-times speedup. On a 386, Listing 21.1 runs at 22 cycles per word; Listing 21.5 runs at 7 cycles per word, a 3.1-times speedup. As is often the case, Pentium optimization helped the other processors, but not as much as it helped the Pentium, and less on the 386 than on the 486.
|
|
</P><P><BR></P>
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="21-04.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="22-01.html">Next</A></TD>
|
|
</TR>
|
|
</TABLE>
|
|
</CENTER>
|
|
|
|
<hr width="90%" size="1" noshade>
|
|
<div align="center">
|
|
<font face="Verdana,sans-serif" size="1">Graphics Programming Black Book © 2001 Michael Abrash</font>
|
|
</div>
|
|
<!-- all of the reference materials (books) have the footer and subfoot reveresed -->
|
|
<!-- reference_subfoot = footer -->
|
|
<!-- reference_footer = subfoot -->
|
|
|
|
<!-- BEGIN SUB FOOTER -->
|
|
</BODY>
|
|
</HTML>
|
|
|
|
<!-- END FOOTER -->
|
|
|
|
|