Deduped images

This commit is contained in:
James Gregory 2013-12-30 12:25:34 +11:00
commit 9e52de9586
233 changed files with 128 additions and 128 deletions

View file

@ -50,14 +50,14 @@
</PRE>
<!-- END CODE SNIP //-->
<P>Harmless enough, save for two things. First, EBX happened to be zero at this point (a leftover from an earlier version of the code, as it turned out), so it was superfluous as a memory-addressing component; this made it possible to use base-only addressing (<B>[EAX]</B>) rather than base&#43;index addressing (<B>[EBX&#43;EAX]</B>), which saves a cycle on the 386. Second: Changing the instruction to <B>CMP [EAX],DH</B> saved 2 cycles&#151;just enough, by good fortune, to speed up the whole program by 5 percent.</P>
<TABLE WIDTH="100%"><TD ALIGN="LEFT" VALIGN="TOP" WIDTH="5%"><IMG SRC="images/16-02i.jpg"><TD ALIGN="LEFT" VALIGN="TOP" WIDTH="95%"><SMALL><I><B>CMP reg,[mem]</B> takes 6 cycles on the 386, but <B>CMP [ mem ],reg</B> takes only 5 cycles; you should always perform<B>CMP</B> with the memory operand on the left on the 386.</I></SMALL>
<TABLE WIDTH="100%"><TD ALIGN="LEFT" VALIGN="TOP" WIDTH="5%"><IMG SRC="images/i.jpg"><TD ALIGN="LEFT" VALIGN="TOP" WIDTH="95%"><SMALL><I><B>CMP reg,[mem]</B> takes 6 cycles on the 386, but <B>CMP [ mem ],reg</B> takes only 5 cycles; you should always perform<B>CMP</B> with the memory operand on the left on the 386.</I></SMALL>
</TABLE>
<P>(Granted, <B>CMP [<I>mem</I>],<I>reg</I></B> is 1 cycle slower than <B>CMP <I>reg</I>,[<I>mem</I>]</B> on the 286, and they&#146;re both the same on the 8088; in this case, though, the code was specific to the 386. In case you&#146;re curious, both forms take 2 cycles on the 486; quite a lot faster, eh?)</P>
<H4 ALIGN="LEFT"><A NAME="Heading7"></A><FONT COLOR="#000077">Watch Out for Luggable Assumptions!</FONT></H4>
<P>The first lesson to be learned here is not to lug assumptions that may no longer be valid from the 8088/286 world into the wonderful new world of 386 native-mode programming. The second lesson is that after you&#146;ve slaved over your code for a while, you&#146;re in no shape to see its flaws, or to be able to get the new perspectives needed to speed it up. I&#146;ll bet Terje looked at that <B>[EBX&#43;EAX]</B> addressing a hundred times while trying to speed up his code, but he didn&#146;t really see what it did; instead, he saw what it was supposed to do. Mental shortcuts like this are what enable us to deal with the complexities of assembly language without overloading after about 20 instructions, but they can be a major problem when looking over familiar code.</P>
<P>The third, and most interesting, lesson is that a far more fruitful optimization came of all this, one that nicely illustrates that cycle counting is not the key to happiness, riches, and wondrous performance. After getting my 5 percent speedup, I mentioned to Terje the possibility of using a 64K lookup table. (This predated the arrival of entries for the optimization contest.) He said that he had considered it, but it didn&#146;t seem to him to be worthwhile. He couldn&#146;t shake the thought, though, and started to poke around, and one day, <I>voila,</I> he posted a new version of his word count program, WC50, that was <I>much</I> faster than the old version. I don&#146;t have exact numbers, but Terje&#146;s preliminary estimate was 80 percent faster, and word counting&#151;<I>including</I> disk cache access time&#151;proceeds at more than 3 MB per second on a 33 MHz 486. Even allowing for the speed of the 486, those are very impressive numbers indeed.</P>
<P>The point I want to make, though, is that the biggest optimization barrier that Terje faced was that he <I>thought</I> he had the fastest code possible. Once he opened up the possibility that there were faster approaches, and looked beyond the specific approach that he had so carefully optimized, he was able to come up with code that was a <I>lot</I> faster. Consider the incongruity of Terje&#146;s willingness to consider a 5 percent speedup significant in light of his later near-doubling of performance.</P>
<TABLE WIDTH="100%"><TD ALIGN="LEFT" VALIGN="TOP" WIDTH="5%"><IMG SRC="images/16-03i.jpg"><TD ALIGN="LEFT" VALIGN="TOP" WIDTH="95%"><SMALL><I>Don&#146;t get stuck in the rut of instruction-by-instruction optimization. It&#146;s useful in key loops, but very often, a change in approach will work far greater wonders than any amount of cycle counting can.</I></SMALL>
<TABLE WIDTH="100%"><TD ALIGN="LEFT" VALIGN="TOP" WIDTH="5%"><IMG SRC="images/i.jpg"><TD ALIGN="LEFT" VALIGN="TOP" WIDTH="95%"><SMALL><I>Don&#146;t get stuck in the rut of instruction-by-instruction optimization. It&#146;s useful in key loops, but very often, a change in approach will work far greater wonders than any amount of cycle counting can.</I></SMALL>
</TABLE>
<P>By the way, Terje&#146;s WC50 program is a full-fledged counting program; it counts characters, words, and lines, can handle multiple files, and lets you specify the characters that separate words, should you so desire. Source code is provided as part of the archive WC50 comes in. All in all, it&#146;s a nice piece of work, and you might want to take a look at it if you&#146;re interested in really fast assembly code. I wouldn&#146;t call it the <I>fastest</I> word-counting code, though, because I would of course never be so foolish as to call <I>anything</I> the fastest.</P>
<H3><A NAME="Heading8"></A><FONT COLOR="#000077">The Astonishment of Right-Brain Optimization</FONT></H3>