Retidy, removing align=left from headings and empty paragraphs

This commit is contained in:
James Gregory 2013-12-30 15:37:13 +11:00
commit a96a114403
362 changed files with 8472 additions and 5040 deletions

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="about_author.html">Previous</a></td>
<td>
<a href="about_author.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="01-02.html">Next</a></td>
<td>
<a href="01-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 align="center"><i>Part I</i></h2>
<h2 id="Heading1">Chapter 1<br />
@ -69,7 +72,7 @@
<p>&ldquo;What&rsquo;s a fast slow program?&rdquo; you ask. That&rsquo;s a good question, and a brief (true) story is perhaps the best answer.</p>
<h4 align="left" id="Heading4">When Fast Isn&rsquo;t Fast</h4>
<h4 id="Heading4">When Fast Isn&rsquo;t Fast</h4>
<p>In the early 1970s, as the first hand-held calculators were hitting the market, I knew a fellow named Irwin. He was a good student, and was planning to be an engineer. Being an engineer back then meant knowing how to use a slide rule, and Irwin could jockey a slipstick with the best of them. In fact, he was so good that he challenged a fellow with a calculator to a duel&mdash;and won, becoming a local legend in the process.</p>
@ -77,16 +80,20 @@
<p>What does all this have to do with programming? Plenty. When you spend time optimizing poorly-designed assembly code, or when you count on an optimizing compiler to make your code fast, you&rsquo;re wasting the optimization, much as Irwin did. Particularly in assembly, you&rsquo;ll find that without proper up-front design and everything else that goes into high-performance design, you&rsquo;ll waste considerable effort and time on making an inherently slow program as fast as possible&mdash;which is still slow&mdash;when you could easily have improved performance a great deal more with just a little thought. As we&rsquo;ll see, handcrafted assembly language and optimizing compilers matter, but less than you might think, in the grand scheme of things&mdash;and they scarcely matter at all unless they&rsquo;re used in the context of a good design and a thorough understanding of both the task at hand and the PC.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="about_author.html">Previous</a></td>
<td>
<a href="about_author.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="01-02.html">Next</a></td>
<td>
<a href="01-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="01-01.html">Previous</a></td>
<td>
<a href="01-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="01-03.html">Next</a></td>
<td>
<a href="01-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h3 id="Heading5">Rules for Building High-Performance Code</h3>
<p>We&rsquo;ve got the following rules for creating high-performance software:</p>
@ -52,15 +55,15 @@
<p>Making rules is easy; the hard part is figuring out how to apply them in the real world. For my money, examining some actual working code is always a good way to get a handle on programming concepts, so let&rsquo;s look at some of the performance rules in action.</p>
<h4 align="left" id="Heading6">Know Where You&rsquo;re Going</h4>
<h4 id="Heading6">Know Where You&rsquo;re Going</h4>
<p>If we&rsquo;re going to create high-performance code, first we have to know what that code is going to do. As an example, let&rsquo;s write a program that generates a 16-bit checksum of the bytes in a file. In other words, the program will add each byte in a specified file in turn into a 16-bit value. This checksum value might be used to make sure that a file hasn&rsquo;t been corrupted, as might occur during transmission over a modem or if a Trojan horse virus rears its ugly head. We&rsquo;re not going to do anything with the checksum value other than print it out, however; right now we&rsquo;re only interested in generating that checksum value as rapidly as possible.</p>
<h4 align="left" id="Heading7">Make a Big Map</h4>
<h4 id="Heading7">Make a Big Map</h4>
<p>How are we going to generate a checksum value for a specified file? The logical approach is to get the file name, open the file, read the bytes out of the file, add them together, and print the result. Most of those actions are straightforward; the only tricky part lies in reading the bytes and adding them together.</p>
<h4 align="left" id="Heading8">Make Lots of Little Maps</h4>
<h4 id="Heading8">Make Lots of Little Maps</h4>
<p>Actually, we&rsquo;re only going to make one little map, because we only have one program section that requires much thought&mdash;the section that reads the bytes and adds them up. What&rsquo;s the best way to do this?</p>
@ -128,16 +131,20 @@ main(int argc, char *argv[]) {
<p>These results make it clear that it&rsquo;s folly to rely on your compiler&rsquo;s optimization to make your programs fast. Listing 1.1 is simply poorly designed, and no amount of compiler optimization will compensate for that failing. To drive home the point, conListings 1.2 and 1.3, which together are equivalent to Listing 1.1 except that the entire checksum loop is written in tight assembly code. The assembly language implementation is indeed faster than any of the C versions, as shown in Table 1.1, but it&rsquo;s less than 10 percent faster, and it&rsquo;s still unacceptably slow.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="01-01.html">Previous</a></td>
<td>
<a href="01-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="01-03.html">Next</a></td>
<td>
<a href="01-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="01-02.html">Previous</a></td>
<td>
<a href="01-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="01-04.html">Next</a></td>
<td>
<a href="01-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<table width="100%">
<tr>
<td colspan="7">
@ -266,7 +269,7 @@ _ChecksumFileendp
<p>Well, then, how are we going to improve our design? Before we can do that, we have to understand what&rsquo;s wrong with the current design.</p>
<h4 align="left" id="Heading9">Know the Territory</h4>
<h4 id="Heading9">Know the Territory</h4>
<p>Just why is Listing 1.1 so slow? In a word: overhead. The C library implements the <b>read()</b> function by calling DOS to read the desired number of bytes. (I figured this out by watching the code execute with a debugger, but you can buy library source code from both Microsoft and Borland.) That means that Listing 1.1 (and Listing 1.3 as well) executes one DOS function per byte processed&mdash;and DOS functions, especially this one, come with a lot of overhead.</p>
@ -278,16 +281,20 @@ _ChecksumFileendp
<p>Listing 1.4 is similar to Listing 1.1, but uses <b>fopen()</b> and <b>getc()</b> (rather than <b>open()</b> and <b>read()</b>) to access the file being checksummed. The results confirm our theories splendidly, and validate our new design. As shown in Table 1.1, Listing 1.4 runs more than an order of magnitude faster than even the assembly version of Listing 1.1, <i>even though Listing 1.1 and Listing 1.4 look almost the same</i>. To the casual observer, <b>read()</b> and <b>getc()</b> would seem slightly different but pretty much interchangeable, and yet in this application the performance difference between the two is about the same as that between a 4.77 MHz PC and a 16 MHz 386.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="01-02.html">Previous</a></td>
<td>
<a href="01-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="01-04.html">Next</a></td>
<td>
<a href="01-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="01-03.html">Previous</a></td>
<td>
<a href="01-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="01-05.html">Next</a></td>
<td>
<a href="01-05.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<table width="100%">
<tr>
<td width="5%" valign="top"><img src="images/i.jpg" /></td>
@ -77,7 +80,7 @@ main(int argc, char *argv[]) {
}
</pre>
<h4 align="left" id="Heading10">Know When It Matters</h4>
<h4 id="Heading10">Know When It Matters</h4>
<p>The last section contained a particularly interesting phrase: <i>the time-critical portions of your code</i>. Time-critical portions of your code are those portions in which the speed of the code makes a significant difference in the overall performance of your program&mdash;and by &ldquo;significant,&rdquo; I don&rsquo;t mean that it makes the code 100 percent faster, or 200 percent, or any particular amount at all, but rather that it makes the program more responsive and/or usable <i>from the user&rsquo;s perspective</i>.</p>
@ -93,7 +96,7 @@ main(int argc, char *argv[]) {
<p>Besides, we don&rsquo;t want to optimize until the design is refined to our satisfaction, and that won&rsquo;t be the case until we&rsquo;ve thought about other approaches.</p>
<h4 align="left" id="Heading11">Always Consider the Alternatives</h4>
<h4 id="Heading11">Always Consider the Alternatives</h4>
<p>Listing 1.4 is good, but let&rsquo;s see if there are other&mdash;perhaps less obvious&mdash;ways to get the same results faster. Let&rsquo;s start by considering why Listing 1.4 is so much better than Listing 1.1. Like <b>read()</b>, <b>getc()</b> calls DOS to read from the file; the speed improvement of Listing 1.4 over Listing 1.1 occurs because <b>getc()</b> eads many bytes at once via DOS, then manages those bytes for us. That&rsquo;s faster than reading them one at a time using <b>read()</b>&mdash;but there&rsquo;s no reason to think that it&rsquo;s faster than having our program read and manage blocks itself. Easier, yes, but not faster.</p>
@ -115,16 +118,20 @@ main(int argc, char *argv[]) {
<p>The second reason is the hallmark of the mediocre programmer. Know when optimization matters&mdash;and then optimize when it does!</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="01-03.html">Previous</a></td>
<td>
<a href="01-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="01-05.html">Next</a></td>
<td>
<a href="01-05.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="01-04.html">Previous</a></td>
<td>
<a href="01-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="01-06.html">Next</a></td>
<td>
<a href="01-06.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>The third reason is often fallacious. C library functions are not always written in assembly, nor are they always particularly well-optimized. (In fact, they&rsquo;re often written for <i>portability</i>, which has nothing to do with optimization.) What&rsquo;s more, they&rsquo;re general-purpose functions, and often can be outperformed by well-but-not- brilliantly-written code that is well-matched to a specific task. As an example, consider Listing 1.5, which uses internal buffering to handle blocks of bytes at a time. Table 1.1 shows that Listing 1.5 is 2.5 to 4 times faster than Listing 1.4 (and as much as 49 times faster than Listing 1.1!), even though it uses no assembly at all.</p>
<table width="100%">
@ -106,7 +109,7 @@ main(int argc, char *argv[]) {
<p>At any rate, Listing 1.5 isn&rsquo;t much more complicated than Listing 1.4&mdash;and it&rsquo;s a <i>lot</i> faster. Always consider the alternatives; a bit of clever thinking and program redesign can go a long way.</p>
<h4 align="left" id="Heading12">Know How to Turn On the Juice</h4>
<h4 id="Heading12">Know How to Turn On the Juice</h4>
<p>I have said time and again that optimization is pointless until the design is settled. When that time comes, however, optimization can indeed make a significant difference. Table 1.1 indicates that the optimized version of Listing 1.5 produced by Microsoft C outperforms an unoptimized version of the same code by more than 60 percent. What&rsquo;s more, a mostly-assembly version of Listing 1.5, shown in Listings 1.6 and 1.7, outperforms even the best-optimized C version of List1.5 by 26 percent. These are considerable improvements, well worth pursuing&mdash;once the design has been maxed out.</p>
@ -167,16 +170,20 @@ main(int argc, char *argv[]) {
}
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="01-04.html">Previous</a></td>
<td>
<a href="01-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="01-06.html">Next</a></td>
<td>
<a href="01-06.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="01-05.html">Previous</a></td>
<td>
<a href="01-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="02-01.html">Next</a></td>
<td>
<a href="02-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 1.7 L1-7.ASM</b></p>
<pre>
; Assembler subroutine to perform a 16-bit checksum on a block of
@ -103,22 +106,26 @@ _ChecksumChunkendp
<p>Optimization only matters after you&rsquo;ve done your part on the program design end. Consider the ratios on the vertical axis of Table 1.1, which show that optimization is almost totally wasted in the checksumming application without an efficient design. Optimization is no panacea. Table 1.1 shows a two-times improvement from optimization&mdash;and a 50-times-plus improvement from redesign. The longstanding debate about which C compiler optimizes code best doesn&rsquo;t matter quite so much in light of Table 1.1, does it? Your organic optimizer matters much more than your compiler&rsquo;s optimizer, and there&rsquo;s always assembly for those usually small sections of code where performance really matters.</p>
<h4 align="left" id="Heading14">Where We&rsquo;re Going</h4>
<h4 id="Heading14">Where We&rsquo;re Going</h4>
<p>This chapter has presented a quick step-by-step overview of the design process. I&rsquo;m not claiming that this is the only way to create high-performance code; it&rsquo;s just an approach that works for me. Create code however you want, but never forget that design matters more than detailed optimization. Never stop looking for inventive ways to boost performance&mdash;and never waste time speeding up code that doesn&rsquo;t need to be sped up.</p>
<p>I&rsquo;m going to focus on specific ways to create high-performance code from now on. In Chapter 5, we&rsquo;ll continue to look at restartable blocks and internal buffering, in the form of a program that searches files for text strings.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="01-05.html">Previous</a></td>
<td>
<a href="01-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="02-01.html">Next</a></td>
<td>
<a href="02-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="01-06.html">Previous</a></td>
<td>
<a href="01-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="02-02.html">Next</a></td>
<td>
<a href="02-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 2<br />
A World Apart</h2>
@ -88,16 +91,20 @@ LoopTop:
<p>To understand why this is so, consider how a program gets written. A programmer examines the requirements of an application, designs a solution at some level of abstraction, and then makes that design come alive in a code implementation. If not handled properly, the transformation that takes place between conception and implementation can reduce performance tremendously; for example, a programmer who implements a routine to search a list of 100,000 sorted items with a linear rather than binary search will end up with a disappointingly slow program.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="01-06.html">Previous</a></td>
<td>
<a href="01-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="02-02.html">Next</a></td>
<td>
<a href="02-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,18 +18,22 @@
<center>
<table border="1">
<tr>
<td><a href="02-01.html">Previous</a></td>
<td>
<a href="02-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="02-03.html">Next</a></td>
<td>
<a href="02-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h4 align="left" id="Heading5">Transformation Inefficiencies</h4>
<h4 id="Heading5">Transformation Inefficiencies</h4>
<p>No matter how well an implementation is derived from the corresponding design, however, high-level languages like C/C<small>++</small> and Pascal inevitably introduce additional transformation inefficiencies, as shown in Figure 2.1.</p>
@ -50,11 +53,11 @@
<p>The key, of course, is the programmer, since in assembly the programmer must essentially perform the transformation from the application specification to machine language entirely on his or her own. (The assembler merely handles the <i>direct</i> translation from assembly to machine language.)</p>
<h4 align="left" id="Heading6">Self-Reliance</h4>
<h4 id="Heading6">Self-Reliance</h4>
<p>The first part of assembly language optimization, then, is self. An assembler is nothing more than a tool to let you design machine-language programs without having to think in hexadecimal codes. So assembly language programmers&mdash;unlike all other programmers&mdash;must take full responsibility for the quality of their code. Since assemblers provide little help at any level higher than the generation of machine language, the assembly programmer must be capable both of coding any programming construct directly and of controlling the PC at the lowest practical level&mdash;the operating system, the BIOS, even the hardware where necessary. High-level languages handle most of this transparently to the programmer, but in assembly everything is fair&mdash;and necessary&mdash;game, which brings us to another aspect of assembly optimization: knowledge.</p>
<h4 align="left" id="Heading7">Knowledge</h4>
<h4 id="Heading7">Knowledge</h4>
<p>In the PC world, you can never have enough knowledge, and every item you add to your store will make your programs better. Thorough familiarity with both the operating system APIs and BIOS interfaces is important; since those interfaces are well-documented and reasonably straightforward, my advice is to get a good book or two and bring yourself up to speed. Similarly, familiarity with the PC hardware is required. While that topic covers a lot of ground&mdash;display adapters, keyboards, serial ports, printer ports, timer and DMA channels, memory organization, and more&mdash;most of the hardware is well-documented, and articles about programming major hardware components appear frequently in the literature, so this sort of knowledge can be acquired readily enough.</p>
@ -68,16 +71,20 @@
</tr>
</table>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="02-01.html">Previous</a></td>
<td>
<a href="02-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="02-03.html">Next</a></td>
<td>
<a href="02-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="02-02.html">Previous</a></td>
<td>
<a href="02-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-01.html">Next</a></td>
<td>
<a href="03-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h3 id="Heading8">The Flexible Mind</h3>
<p>Is the never-ending collection of information all there is to the assembly optimization, then? Hardly. Knowledge is simply a necessary base on which to build. Let&rsquo;s take a moment to examine the objectives of good assembly programming, and the remainder of the forces that act on assembly optimization will fall into place.</p>
@ -58,20 +61,24 @@
<p>The gist of all this is simply that good assembly programming is done in the context of a solid overall framework unique to each program, and the flexible mind is the key to creating that framework and holding it together.</p>
<h4 align="left" id="Heading9">Where to Begin?</h4>
<h4 id="Heading9">Where to Begin?</h4>
<p>To summarize, the skill of assembly language optimization is a combination of knowledge, perspective, and a way of thought that makes possible the genesis of absolutely the fastest or the smallest code. With that in mind, what should the first step be? Development of the flexible mind is an obvious step. Still, the flexible mind is no better than the knowledge at its disposal. The first step in the journey toward mastering optimization at that exalted level, then, would seem to be learning how to learn.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="02-02.html">Previous</a></td>
<td>
<a href="02-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-01.html">Next</a></td>
<td>
<a href="03-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="02-03.html">Previous</a></td>
<td>
<a href="02-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-02.html">Next</a></td>
<td>
<a href="03-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 3<br />
Assume Nothing</h2>
@ -69,16 +72,20 @@
<p>Listing 3.1 shows 8253-based timer software, consisting of three subroutines: <b>ZTimerOn, ZTimerOff</b>, and <b>ZTimerReport</b>. For the remainder of this book, I&rsquo;ll refer to these routines collectively as the &ldquo;Zen timer.&rdquo; C-callable versions of the two precision Zen timers are presented in Chapter K on the companion CD-ROM.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="02-03.html">Previous</a></td>
<td>
<a href="02-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-02.html">Next</a></td>
<td>
<a href="03-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="03-01.html">Previous</a></td>
<td>
<a href="03-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-03.html">Next</a></td>
<td>
<a href="03-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 3.1 PZTIMER.ASM</b></p>
<pre>
; The precision Zen timer (PZTIMER.ASM)
@ -473,16 +476,20 @@ Code ends
end
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="03-01.html">Previous</a></td>
<td>
<a href="03-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-03.html">Next</a></td>
<td>
<a href="03-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,24 +18,28 @@
<center>
<table border="1">
<tr>
<td><a href="03-02.html">Previous</a></td>
<td>
<a href="03-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-04.html">Next</a></td>
<td>
<a href="03-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h4 align="left" id="Heading5">The Zen Timer Is a Means, Not an End</h4>
<h4 id="Heading5">The Zen Timer Is a Means, Not an End</h4>
<p>We&rsquo;re going to spend the rest of this chapter seeing what the Zen timer can do, examining how it works, and learning how to use it. I&rsquo;ll be using the Zen timer again and again over the course of this book, so it&rsquo;s essential that you learn what the Zen timer can do and how to use it. On the other hand, it is by no means essential that you understand exactly how the Zen timer works. (Interesting, yes; essential, no.)</p>
<p>In other words, the Zen timer isn&rsquo;t really part of the knowledge we seek; rather, it&rsquo;s one tool with which we&rsquo;ll acquire that knowledge. Consequently, you shouldn&rsquo;t worry if you don&rsquo;t fully grasp the inner workings of the Zen timer. Instead, focus on learning how to <i>use</i> it, and you&rsquo;ll be on the right road.</p>
<h4 align="left" id="Heading6">Starting the Zen Timer</h4>
<h4 id="Heading6">Starting the Zen Timer</h4>
<p><b>ZTimerOn</b> is called at the start of a segment of code to be timed. <b>ZTimerOn</b> saves the context of the calling code, disables interrupts, sets timer 0 of the 8253 to mode 2 (divide-by-N mode), sets the initial timer count to 0, restores the context of the calling code, and returns. (I&rsquo;d like to note that while Intel&rsquo;s documentation for the 8253 seems to indicate that a timer won&rsquo;t reset to 0 until it finishes counting down, in actual practice, timers seem to reset to 0 as soon as they&rsquo;re loaded.)</p>
@ -67,16 +70,20 @@
<p>Why not use timer 2 instead of timer 0 for precision timing? After all, timer 2 has a programmable gate input and isn&rsquo;t used for anything but sound generation. The problem with timer 2 is that its output can&rsquo;t generate an interrupt; in fact, timer 2 can&rsquo;t do anything but drive the speaker. We need the interrupt generated by the output of timer 0 to tell us when the count has overflowed, and we will see shortly that the timer interrupt also makes it possible to time much longer periods than the Zen timer shown in Listing 3.1 supports.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="03-02.html">Previous</a></td>
<td>
<a href="03-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-04.html">Next</a></td>
<td>
<a href="03-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="03-03.html">Previous</a></td>
<td>
<a href="03-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-05.html">Next</a></td>
<td>
<a href="03-05.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>In fact, the Zen timer shown in Listing 3.1 can only time intervals of up to about 54 ms in length, since that is the period of time that can be measured by timer 0 before its count turns over and repeats. fifty-four ms may not seem like a very long time, but even a CPU as slow as the 8088 can perform more than 1,000 divides in 54 ms, and division is the single instruction that the 8088 performs most slowly. If a measured period turns out to be longer than 54 ms (that is, if timer 0 has counted down and turned over), the Zen timer will display a message to that effect. A long-period Zen timer for use in such cases will be presented later in this chapter.</p>
<p>The Zen timer determines whether timer 0 has turned over by checking to see whether an IRQ0 interrupt is pending. (Remember, interrupts are off while the Zen timer runs, so the timer interrupt cannot be recognized until the Zen timer stops and enables interrupts.) If an IRQ0 interrupt is pending, then timer 0 has turned over and generated a timer interrupt. Recall that <b>ZTimerOn</b> initially sets timer 0 to 0, in order to allow for the longest possible period&mdash;about 54 ms&mdash;before timer 0 reaches 0 and generates the timer interrupt.</p>
@ -70,16 +73,20 @@
<p>You may well want to devise still other approaches better suited to your needs than those I&rsquo;ve presented. Go to it! I&rsquo;ve just thrown out a few possibilities to get you started.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="03-03.html">Previous</a></td>
<td>
<a href="03-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-05.html">Next</a></td>
<td>
<a href="03-05.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="03-04.html">Previous</a></td>
<td>
<a href="03-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-06.html">Next</a></td>
<td>
<a href="03-06.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h3 id="Heading10">Notes on the Zen Timer</h3>
<p>The Zen timer subroutines are designed to be near-called from assembly language code running in the public segment <b>Code</b>. The Zen timer subroutines can, however, be called from any assembly or high-level language code that generates OBJ files that are compatible with the Microsoft linker, simply by modifying the segment that the timer code runs in to match the segment used by the code being timed, or by changing the Zen timer routines to far procedures and making far calls to the Zen timer code from the code being timed, as discussed at the end of this chapter. All three subroutines preserve all registers and all flags except the interrupt flag, so calls to these routines are transparent to the calling code.</p>
@ -121,16 +124,20 @@ Skip:
<p>It&rsquo;s worth noting that Listing 3.3 begins by jumping around the memory variable <b>MemVar</b>. This approach lets us avoid reproducing Listing 3.2 in its entirety for each code fragment we want to measure; by defining any needed data right in the code segment and jumping around that data, each listing becomes self-contained and can be plugged directly into Listing 3.2 as TESTCODE. Listing 3.2 sets DS equal to CS before doing anything else precisely so that data can be embedded in code fragments being timed. Note that only after the initial jump is performed in Listing 3.3 is the Zen timer started, since we don&rsquo;t want to include the execution time of start-up code in the timing interval. That&rsquo;s why the calls to <b>ZTimerOn</b> and <b>ZTimerOff</b> are in TESTCODE, not in PZTEST.ASM; this way, we have full control over which portion of TESTCODE is timed, and we can keep set-up code and the like out of the timing interval.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="03-04.html">Previous</a></td>
<td>
<a href="03-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-06.html">Next</a></td>
<td>
<a href="03-06.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="03-05.html">Previous</a></td>
<td>
<a href="03-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-07.html">Next</a></td>
<td>
<a href="03-07.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Listing 3.3 is used by naming it TESTCODE, assembling both Listing 3.2 (which includes TESTCODE) and Listing 3.1 with TASM or MASM, and linking the two resulting OBJ files together by way of the Borland orMicrosoft linker. Listing 3.4 shows a batch file, PZTIME.BAT, which does all that; when run, this batch file generates and runs the executable file PZTEST.EXE. PZTIME.BAT (Listing 3.4) assumes that the file PZTIMER.ASM contains Listing 3.1, and the file PZTEST.ASM contains Listing 3.2. The command-line parameter to PZTIME.BAT is the name of the file to be copied to TESTCODE and included into PZTEST.ASM. (Note that Turbo Assembler can be substituted for MASM by replacing &ldquo;masm&rdquo; with &ldquo;tasm&rdquo; and &ldquo;link&rdquo; with &ldquo;tlink&rdquo; in Listing 3.4. The same is true of Listing 3.7.)</p>
<p><b>LISTING 3.4 PZTIME.BAT</b></p>
@ -123,16 +126,20 @@ pztime &lt;filename&gt;
<p>You should not use the long-period Zen timer to time code that requires interrupts to be disabled for more than 54 ms at a stretch during the timing interval, since when interrupts are disabled the long-period Zen timer is subject to the same 54 ms maximum measurement time as the precision Zen timer.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="03-05.html">Previous</a></td>
<td>
<a href="03-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-07.html">Next</a></td>
<td>
<a href="03-07.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,22 +18,26 @@
<center>
<table border="1">
<tr>
<td><a href="03-06.html">Previous</a></td>
<td>
<a href="03-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-08.html">Next</a></td>
<td>
<a href="03-08.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>While permitting the timer interrupt to occur allows long intervals to be timed, that same interrupt makes the long-period Zen timer less accurate than the precision Zen timer, since the time the BIOS spends handling timer interrupts during the timing interval is included in the time measured by the long-period timer. Likewise, any other interrupts that occur during the timing interval, most notably keyboard and mouse interrupts, will increase the measured time.</p>
<p>The long-period Zen timer has some of the same effects on the system time as does the precision Zen timer, so it&rsquo;s a good idea to reboot the system after a session with the long-period Zen timer. The long-period Zen timer does not, however, have the same potential for introducing major inaccuracy into the system clock time during a single timing run since it leaves interrupts enabled and therefore allows the system clock to update normally.</p>
<h4 align="left" id="Heading13">Stopping the Clock</h4>
<h4 id="Heading13">Stopping the Clock</h4>
<p>There&rsquo;s a potential problem with the long-period Zen timer. The problem is this: In order to measure times longer than 54 ms, we must maintain not one but two timing components, the timer 0 count and the BIOS time-of-day count. The time-of-day count measures the passage of 54.9 ms intervals, while the timer 0 count measures time within those 54.9 ms intervals. We need to read the two time components simultaneously in order to get a clean reading. Otherwise, we may read the timer count just before it turns over and generates an interrupt, then read the BIOS time-of-day count just after the interrupt has occurred and caused the time-of-day count to turn over, with a resulting 54 ms measurement inaccuracy. (The opposite sequence&mdash;reading the time-of-day count and then the timer count&mdash;can result in a 54 ms inaccuracy in the other direction.)</p>
@ -684,16 +687,20 @@ Code ends
end
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="03-06.html">Previous</a></td>
<td>
<a href="03-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-08.html">Next</a></td>
<td>
<a href="03-08.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="03-07.html">Previous</a></td>
<td>
<a href="03-07.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-09.html">Next</a></td>
<td>
<a href="03-09.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Moreover, because it uses an undocumented feature, the timer-stop approach could conceivably cause erratic 8253 operation, which could in turn seriously affect your computer&rsquo;s operation until the next reboot. In non-8253-compatible systems, I&rsquo;ve observed not only wildly incorrect timing results, but also failure of a diskette drive to operate properly after the long-period Zen timer with <b>PS2</b> set to 0 has run, so be alert for signs of trouble if you do set <b>PS2</b> to 0.</p>
<p>Rebooting should clear up any timer-related problems of the sort described above. (This gives us another reason to reboot at the end of each code-timing session.) You should <i>immediately</i> reboot and set the <b>PS2</b> equate to 1 if you get erratic or obviously incorrect results with the long-period Zen timer when <b>PS2</b> is set to 0. If you want to set <b>PS2</b> to 0, it would be a good idea to time a few of the listings in this book with <b>PS2</b> set first to 1 and then to 0, to make sure that the results match. If they&rsquo;re consistently different, you should set <b>PS2</b> to 1.</p>
@ -110,16 +113,20 @@ Code ends
<p>As with the precision Zen timer, the program in Listing 3.6 is used by naming the file containing the code to be timed TESTCODE, then assembling both Listing 3.6 and Listing 3.5 with MASM or TASM and linking the two files together by way of the Microsoft or Borland linker. Listing 3.7 shows a batch file, named LZTIME.BAT, which does all of the above, generating and running the executable file LZTEST.EXE. LZTIME.BAT assumes that the file LZTIMER.ASM contains Listing 3.5 and the file LZTEST.ASM contains Listing 3.6.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="03-07.html">Previous</a></td>
<td>
<a href="03-07.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-09.html">Next</a></td>
<td>
<a href="03-09.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="03-08.html">Previous</a></td>
<td>
<a href="03-08.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-10.html">Next</a></td>
<td>
<a href="03-10.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 3.7 LZTIME.BAT</b></p>
<pre>
echo off
@ -146,16 +149,20 @@ lztime lst3-8.asm
extern &ldquo;C&rdquo; ZTimerOn(void);
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="03-08.html">Previous</a></td>
<td>
<a href="03-08.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="03-10.html">Next</a></td>
<td>
<a href="03-10.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="03-09.html">Previous</a></td>
<td>
<a href="03-09.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-01.html">Next</a></td>
<td>
<a href="04-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>when declaring the timer routines <b>extern</b>, so that name-mangling doesn&rsquo;t occur, and the linker can find the routines&rsquo; C-style names.)</p>
<p>That&rsquo;s all it takes; after doing this, you&rsquo;ll be able to use the Zen timer from C, as, for example, in:</p>
@ -50,7 +53,7 @@ ZTimerReport();
<p>The full listings for the C-callable Zen timers are presented in Chapter K on the companion CD-ROM.</p>
<h4 align="left" id="Heading16">Watch Out for Optimizing Assemblers!</h4>
<h4 id="Heading16">Watch Out for Optimizing Assemblers!</h4>
<p>One important safety tip when modifying the Zen timer for use with large code model C code: Watch out for optimizing assemblers! TASM actually replaces</p>
<pre>
@ -76,28 +79,32 @@ call near ptr ReferenceZTimerOn
<p>I&rsquo;ve tested the changes shown in Figures 3.2 and 3.3 with TASM and Borland C<small>++</small> 4.0, and also with the latest MASM and Microsoft C/C<small>++</small> compiler.</p>
<h4 align="left" id="Heading17">Further Reading</h4>
<h4 id="Heading17">Further Reading</h4>
<p>For those of you who wish to pursue the mechanics of code measurement further, one good article about measuring code performance with the 8253 timer is &ldquo;Programming Insight: High-Performance Software Analysis on the IBM PC,&rdquo; by Byron Sheppard, which appeared in the January, 1987 issue of <i>Byte</i>. For complete if somewhat cryptic information on the 8253 timer itself, I refer you to Intel&rsquo;s <i>Microsystem Components Handbook</i>, which is also a useful reference for a number of other PC components, including the 8259 Programmable Interrupt Controller and the 8237 DMA Controller. For details about the way the 8253 is used in the PC, as well as a great deal of additional information about the PC&rsquo;s hardware and BIOS resources, I suggest you consult IBM&rsquo;s series of technical reference manuals for the PC, XT, AT, Model 30, and microchannel computers, such as the Models 50, 60, and 80.</p>
<p>For our purposes, however, it&rsquo;s not critical that you understand exactly how the Zen timer works. All you really need to know is what the Zen timer can do and how to use it, and we&rsquo;ve accomplished that in this chapter.</p>
<h4 align="left" id="Heading18">Armed with the Zen Timer, Onward and Upward</h4>
<h4 id="Heading18">Armed with the Zen Timer, Onward and Upward</h4>
<p>The Zen timer is not perfect. For one thing, the finest resolution to which it can measure an interval is at best about 1&micro;s, a period of time in which a 66 MHz Pentium computer can execute as many as 132 instructions (although an 8088-based PC would be hard-pressed to manage two instructions in a microsecond). Another problem is that the timing code itself interferes with the state of the prefetch queue and processor cache at the start of the code being timed, because the timing code is not necessarily fetched and does not necessarily access memory in exactly the same time sequence as the code immediately preceding the code under measurement normally does. This prefetch effect can introduce as much as 3 to 4 &micro; of inaccuracy. Similarly, the state of the prefetch queue at the end of the code being timed affects how long the code that stops the timer takes to execute. Consequently, the Zen timer tends to be more accurate for longer code sequences, since the relative magnitude of the inaccuracy introduced by the Zen timer becomes less over longer periods.</p>
<p>Imperfections notwithstanding, the Zen timer is a good tool for exploring C code and x86 family assembly language, and it&rsquo;s a tool we&rsquo;ll use frequently for the remainder of this book.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="03-09.html">Previous</a></td>
<td>
<a href="03-09.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-01.html">Next</a></td>
<td>
<a href="04-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="03-10.html">Previous</a></td>
<td>
<a href="03-10.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-02.html">Next</a></td>
<td>
<a href="04-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 4<br />
In the Lair of the Cycle-Eaters</h2>
@ -57,7 +60,7 @@
<p>The nature and severity of the cycle-eaters vary enormously from processor to processor, and (especially) from memory architecture to memory architecture. In order to understand them all, we need first to understand the simplest among them, those that haunted the original 8088-based IBM PC. Later on in this book, I&rsquo;ll be better able to explain the newer generation of cycle-eaters in terms of those ancestral cycle-eaters&mdash;but we have to get the groundwork down first.</p>
<h4 align="left" id="Heading5">The 8088&rsquo;s Ancestral Cycle-Eaters</h4>
<h4 id="Heading5">The 8088&rsquo;s Ancestral Cycle-Eaters</h4>
<p>Internally, the 8088 is a 16-bit processor, capable of running at full speed at all times&mdash;unless external data is required. External data must traverse the 8088&rsquo;s external data bus and the PC&rsquo;s data bus one byte at a time to and from peripherals, with cycle-eaters lurking along every step of the way. What&rsquo;s more, external data includes not only memory operands <i>but also instruction bytes,</i> so even instructions with no memory operands can suffer from cycle-eaters. Since some of the 8088&rsquo;s fastest instructions are register-only instructions, that&rsquo;s important indeed.</p>
@ -85,16 +88,20 @@
<p>The 8088 is internally a full 16-bit processor, equivalent to an 8086. (In fact, the 8086 is identical to the 8088, except that it has a full 16-bit bus. The 8088 is basically the poor man&rsquo;s 8086, because it allows a cheaper&mdash;albeit slower&mdash;system to be built, thanks to the half-sized bus.) In terms of the instruction set, the 8088 is clearly a 16-bit processor, capable of performing any given 16-bit operation&mdash;addition, subtraction, even multiplication or division&mdash;with a single instruction. Externally, however, the 8088 is unequivocally an 8-bit processor, since the external data bus is only 8 bits wide. In other words, the programming interface is 16 bits wide, but the hardware interface is only 8 bits wide, as shown in Figure 4.2. The result of this mismatch is simple: Word-sized data can be transferred between the 8088 and memory or peripherals at only one-half the maximum rate of the 8086, which is to say one-half the maximum rate for which the Execution Unit of the 8088 was designed.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="03-10.html">Previous</a></td>
<td>
<a href="03-10.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-02.html">Next</a></td>
<td>
<a href="04-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="04-01.html">Previous</a></td>
<td>
<a href="04-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-03.html">Next</a></td>
<td>
<a href="04-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><a id="Fig1"><img src="images/04-01.jpg" /><br />
<b>Figure 4.1</b></a>&nbsp;&nbsp;<i>The location of the major cycle-eaters in the IBM PC.</i></p>
@ -42,7 +45,7 @@
<p>A related cycle-eater lurks beneath the 386SX chip, which is a 32-bit processor internally with only a 16-bit path to system memory. The numbers are different, but the way the cycle-eater operates is exactly the same. AT-compatible systems have 16-bit data buses, which can access a full 16-bit word at a time. The 386SX can process 32 bits (a doubleword) at a time, however, and loses a lot of time fetching that doubleword from memory in two halves.</p>
<h4 align="left" id="Heading7">The Impact of the 8-Bit Bus Cycle-Eater</h4>
<h4 id="Heading7">The Impact of the 8-Bit Bus Cycle-Eater</h4>
<p>One obvious effect of the 8-bit bus cycle-eater is that word-sized accesses to memory operands on the 8088 take 4 cycles longer than byte-sized accesses. That&rsquo;s why the official instruction timings indicate that for code running on an 8088 an additional 4 cycles are required for every word-sized access to a memory operand. For instance,</p>
<pre>
@ -70,7 +73,7 @@ add byte ptr [MemVar],al
<p>The upshot of all this is simply that the 8088 can transfer word-sized data to and from memory at only half the speed of the 8086, which inevitably causes performance problems when coupled with an Execution Unit that can process word-sized data every bit as quickly as an 8086. These problems show up with any code that uses word-sized memory operands. More ominously, as we will see shortly, the 8-bit bus cycle-eater can cause performance problems with other sorts of code as well.</p>
<h4 align="left" id="Heading8">What to Do about the 8-Bit Bus Cycle-Eater?</h4>
<h4 id="Heading8">What to Do about the 8-Bit Bus Cycle-Eater?</h4>
<p>The obvious implication of the 8-bit bus cycle-eater is that byte-sized memory variables should be used whenever possible. After all, the 8088 performs <i>byte-sized</i> memory accesses just as quickly as the 8086. For instance, Listing 4.1, which uses a byte-sized memory variable as a loop counter, runs in 10.03 s per loop. That&rsquo;s 20 percent faster than the 12.05 &micro;s per loop execution time of Listing 4.2, which uses a word-sized counter. Why the difference in execution times? Simply because each word-sized <b>DEC</b> performs 4 byte-sized memory accesses (two to read the word-sized operand and two to write the result back to memory), while each byte-sized <b>DEC</b> performs only 2 byte-sized memory accesses in all.</p>
@ -110,16 +113,20 @@ LoopTop:
<p>I&rsquo;d like to make a brief aside concerning code optimization in the listings in this book. Throughout this book I&rsquo;ve modeled the sample code after working code so that the timing results are applicable to real-world programming. In Listings 4.1 and 4.2, for example, I could have shown a still greater advantage for byte-sized operands simply by performing 1,000 <b>DEC</b> instructions in a row, with no branching at all. However, <b>DEC</b> instructions don&rsquo;t exist in a vacuum, so in the listings I used code that both decremented the counter and tested the result. The difference is that between decrementing a memory location (simply an instruction) and using a loop counter (a functional instruction sequence). If you come across code in this book that seems less than optimal, it&rsquo;s simply due to my desire to provide code that&rsquo;s relevant to real programming problems. On the other hand, optimal code is an elusive thing indeed; by no means should you assume that the code in this book is ideal! Examine it, question it, and improve upon it, for an inquisitive, skeptical mind is an important part of the Zen of assembly optimization.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="04-01.html">Previous</a></td>
<td>
<a href="04-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-03.html">Next</a></td>
<td>
<a href="04-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="04-02.html">Previous</a></td>
<td>
<a href="04-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-04.html">Next</a></td>
<td>
<a href="04-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Back to the 8-bit bus cycle-eater. As I&rsquo;ve said, in 8088 work you should strive to use byte-sized memory variables whenever possible. That does <i>not</i> mean that you should use 2 byte-sized memory accesses to manipulate a word-sized memory variable in preference to 1 word-sized memory access, as, for instance,</p>
<pre>
mov dl,byte ptr [MemVar]
@ -105,16 +108,20 @@ shr ax,1
<p>should execute in 10 cycles, since each <b>SHR</b> takes 2 cycles to execute, according to Intel&rsquo;s specifications. Those specifications contain Intel&rsquo;s official instruction execution times, but in this case&mdash;and in many others&mdash;the specifications are drastically wrong. Why? Because they describe execution time <i>once an instruction reaches the prefetch queue.</i> They say nothing about whether a given instruction will be in the prefetch queue when it&rsquo;s time for that instruction to run, or how long it will take that instruction to reach the prefetch queue if it&rsquo;s not there already. Thanks to the low performance of the 8088&rsquo;s external data bus, that&rsquo;s a glaring omission&mdash;but, alas, an unavoidable one. Let&rsquo;s look at why the official execution times are wrong, and why that can&rsquo;t be helped.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="04-02.html">Previous</a></td>
<td>
<a href="04-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-04.html">Next</a></td>
<td>
<a href="04-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,18 +18,22 @@
<center>
<table border="1">
<tr>
<td><a href="04-03.html">Previous</a></td>
<td>
<a href="04-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-05.html">Next</a></td>
<td>
<a href="04-05.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h4 align="left" id="Heading10">Official Execution Times Are Only Part of the Story</h4>
<h4 id="Heading10">Official Execution Times Are Only Part of the Story</h4>
<p>The sequence of 5 <b>SHR</b> instructions in the last example is 10 bytes long. That means that it can never execute in less than 24 cycles even if the 4-byte prefetch queue is full when it starts, since 6 instruction bytes would still remain to be fetched, at 4 cycles per fetch. If the prefetch queue is empty at the start, the sequence <i>could</i> take 40 cycles. In short, thanks to instruction fetching, the code won&rsquo;t run at its documented speed, and could take up to four times longer than it is supposed to.</p>
@ -48,7 +51,7 @@
<p>So now you know why the official instruction execution times are often wrong, and why Intel can&rsquo;t provide better specifications. You also know now why it is that you must time your code if you want to know how fast it really is.</p>
<h4 align="left" id="Heading11">There Is No Such Beast as a True Instruction Execution Time</h4>
<h4 id="Heading11">There Is No Such Beast as a True Instruction Execution Time</h4>
<p>The effect of the code preceding an instruction on the execution time of that instruction makes the Zen timer trickier to use than you might expect, and complicates the interpretation of the results reported by the Zen timer. For one thing, the Zen timer is best used to time code sequences that are more than a few instructions long; below 10&micro;s or so, prefetch queue effects and the limited resolution of the clock driving the timer can cause problems.</p>
@ -96,16 +99,20 @@
<p>The key point is this: We&rsquo;ve seen one code sequence in which <b>SHR</b> took 8-plus cycles to execute, and another in which it took only 2 cycles. Are we talking about two different forms of <b>SHR</b> here? Of course not&mdash;the difference is purely a reflection of the differing states in which the preceding code left the prefetch queue. In Listing 4.5, each <b>SHR</b> after the first few follows a slew of other <b>SHR</b> instructions which have sucked the prefetch queue dry, so overall performance reflects instruction fetch time. By contrast, each <b>SHR</b> in Listing 4.6 follows a <b>MUL</b> instruction which leaves the prefetch queue full, so overall performance reflects Execution Unit execution time.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="04-03.html">Previous</a></td>
<td>
<a href="04-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-05.html">Next</a></td>
<td>
<a href="04-05.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="04-04.html">Previous</a></td>
<td>
<a href="04-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-06.html">Next</a></td>
<td>
<a href="04-06.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Clearly, either instruction fetch time <i>or</i> Execution Unit execution time&mdash;or even a mix of the two, if an instruction is partially prefetched&mdash;can determine code performance. Some people operate under a rule of thumb by which they assume that the execution time of each instruction is 4 cycles times the number of bytes in the instruction. While that&rsquo;s often true for register-only code, it frequently doesn&rsquo;t hold for code that accesses memory. For one thing, the rule should be 4 cycles times the number of <i>memory accesses,</i> not instruction bytes, since all accesses take 4 cycles on the 8088-based PC. For another, memory-accessing instructions often have slower Execution Unit execution times than the 4 cycles per memory access rule would dictate, because the 8088 isn&rsquo;t very fast at calculating memory addresses. Also, the 4 cycles per instruction byte rule isn&rsquo;t true for register-only instructions that are already in the prefetch queue when the preceding instruction ends.</p>
<p>The truth is that it never hurts performance to reduce either the cycle count or the byte count of a given bit of code, but there&rsquo;s no guarantee that one or the other will improve performance either. For example, consider Listing 4.7, which consists of a series of 4-cycle, 2-byte <b>MOV AL,0</b> instructions, and which executes at the rate of 1.81 &micro;s per instruction. Now consider Listing 4.8, which replaces the 4-cycle <b>MOV AL,0</b> with the 3-cycle (but still 2-byte) <b>SUB AL,AL,</b> Despite its 1-cycle-per-instruction advantage, Listing 4.8 runs at exactly the same speed as Listing 4.7. The reason: Both instructions are 2 bytes long, and in both cases it is the 8-cycle instruction fetch time, not the 3 or 4-cycle Execution Unit execution time, that limits performance.</p>
@ -79,7 +82,7 @@
<p>What we <i>really</i> want is to know how long useful working code takes to run, not how long a single instruction takes, and the Zen timer gives us the tool we need to gather that information. Granted, it would be easier if we could just add up neatly documented instruction execution times&mdash;but that&rsquo;s not going to happen. Without actually measuring the performance of a given code sequence, you simply don&rsquo;t know how fast it is. For crying out loud, even the people who <i>designed</i> the 8088 at Intel couldn&rsquo;t tell you exactly how quickly a given 8088 code sequence executes on the PC just by looking at it! Get used to the idea that execution times are only meaningful in context, learn the rules of thumb in this book, and use the Zen timer to measure your code.</p>
<h4 align="left" id="Heading12">Approximating Overall Execution Times</h4>
<h4 id="Heading12">Approximating Overall Execution Times</h4>
<p>Don&rsquo;t think that because overall instruction execution time is determined by both instruction fetch time and Execution Unit execution time, the two times should be added together when estimating performance. For example, practically speaking, each <b>SHR</b> in Listing 4.5 does not take 8 cycles of instruction fetch time plus 2 cycles of Execution Unit execution time to execute. Figure 4.3 shows that while a given <b>SHR</b> is executing, the fetch of the next <b>SHR</b> is starting, and since the two operations are overlapped for 2 cycles, there&rsquo;s no sense in charging the time to both instructions. You could think of the extra instruction fetch time for <b>SHR</b> in Listing 4.5 as being 6 cycles, which yields an overall execution time of 8 cycles when added to the 2 cycles of Execution Unit execution time.</p>
@ -87,22 +90,26 @@
<p>As a working definition, we&rsquo;ll consider the execution time of a given instruction in a particular context to start when the first byte of the instruction is sent to the Execution Unit and end when the first byte of the next instruction is sent to the EU.</p>
<h4 align="left" id="Heading13">What to Do about the Prefetch Queue Cycle-Eater?</h4>
<h4 id="Heading13">What to Do about the Prefetch Queue Cycle-Eater?</h4>
<p>Reducing the impact of the prefetch queue cycle-eater is one of the overriding principles of high-performance assembly code. How can you do this? One effective technique is to minimize access to memory operands, since such accesses compete with instruction fetching for precious memory accesses. You can also greatly reduce instruction fetch time simply by your choice of instructions: <i>Keep your instructions short.</i> Less time is required to fetch instructions that are 1 or 2 bytes long than instructions that are 5 or 6 bytes long. Reduced instruction fetching lowers minimum execution time (minimum execution time is 4 cycles times the number of instruction bytes) and often leads to faster overall execution.</p>
<p>While short instructions minimize overall prefetch time, ironically they actually often suffer more from the prefetch queue bottleneck than do long instructions. Short instructions generally have such fast execution times that they drain the prefetch queue despite their small size. For example, consider the <b>SHR</b> of Listing 4.5, which runs at only 25 percent of its Execution Unit execution time even though it&rsquo;s only 2 bytes long, thanks to the prefetch queue bottleneck. Short instructions are nonetheless generally faster than long instructions, thanks to the combination of fewer instruction bytes and faster Execution Unit execution times, and should be used as much as possible&mdash;just don&rsquo;t expect them to run at their &ldquo;official&rdquo; documented speeds.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="04-04.html">Previous</a></td>
<td>
<a href="04-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-06.html">Next</a></td>
<td>
<a href="04-06.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,22 +18,26 @@
<center>
<table border="1">
<tr>
<td><a href="04-05.html">Previous</a></td>
<td>
<a href="04-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-07.html">Next</a></td>
<td>
<a href="04-07.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>More than anything, the above rules mean using the registers as heavily as possible, both because register-only instructions are short and because they don&rsquo;t perform memory accesses to read or write operands. However, using the registers is a rule of thumb, not a commandment. In some circumstances, it may actually be <i>faster</i> to access memory. (The look-up table technique is one such case.) What&rsquo;s more, the performance of the prefetch queue (and hence the performance of each instruction) differs from one code sequence to the next, and can even differ during different executions of the <i>same</i> code sequence.</p>
<p>All in all, writing good assembler code is as much an art as a science. As a result, you should follow the rules of thumb described here&mdash;and then time your code to see how fast it really is. You should experiment freely, but always remember that actual, measured performance is the bottom line.</p>
<h4 align="left" id="Heading14">Holding Up the 8088</h4>
<h4 id="Heading14">Holding Up the 8088</h4>
<p>In this chapter I&rsquo;ve taken you further and further into the depths of the PC, telling you again and again that you must understand the computer at the lowest possible level in order to write good code. At this point, you may well wonder, &ldquo;Have we gotten low enough?&rdquo;</p>
@ -54,7 +57,7 @@
<p>All of the PC&rsquo;s system memory consists of DRAM chips. Each DRAM chip in the PC must be completely refreshed about once every four milliseconds in order to ensure the integrity of the data it stores. Obviously, it&rsquo;s highly desirable that the memory in the PC retain the correct data indefinitely, so each DRAM chip in the PC <i>must</i> always be refreshed within 4 &micro;s of the last refresh. Since there&rsquo;s no guarantee that a given program will access each and every DRAM block once every 4 &micro;s, the PC contains special circuitry and programming for providing DRAM refresh.</p>
<h4 align="left" id="Heading16">How DRAM Refresh Works in the PC</h4>
<h4 id="Heading16">How DRAM Refresh Works in the PC</h4>
<p>On the original 8088-based IBM PC, timer 1 of the 8253 timer chip is programmed at power-up to generate a signal once every 72 cycles, or once every 15.08&micro;s. That signal goes to channel 0 of the 8237 DMA controller, which requests the bus from the 8088 upon receiving the signal. (DMA stands for <i>direct memory access,</i> the ability of a device other than the 8088 to control the bus and access memory directly, without any help from the 8088.) As soon as the 8088 is between memory accesses, it gives control of the bus to the 8237, which in conjunction with special circuitry on the PC&rsquo;s motherboard then performs a single 4-cycle read access to 1 of 256 possible addresses, advancing to the next address on each successive access. (The read access is only for the purpose of refreshing the DRAM; the data that is read isn&rsquo;t used.)</p>
@ -65,16 +68,20 @@
<p><a id="Fig5"><img src="images/04-05.jpg" /><br />
<b>Figure 4.5</b></a>&nbsp;&nbsp;<i>The PC bus dynamic RAM (DRAM) refresh.</i></p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="04-05.html">Previous</a></td>
<td>
<a href="04-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-07.html">Next</a></td>
<td>
<a href="04-07.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,18 +18,22 @@
<center>
<table border="1">
<tr>
<td><a href="04-06.html">Previous</a></td>
<td>
<a href="04-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-08.html">Next</a></td>
<td>
<a href="04-08.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h4 align="left" id="Heading17">The Impact of DRAM Refresh</h4>
<h4 id="Heading17">The Impact of DRAM Refresh</h4>
<p>Let&rsquo;s look at examples from opposite ends of the spectrum in terms of the impact of DRAM refresh on code performance. First, consider the series of <b>MUL</b> instructions in Listing 4.9. Since a 16-bit <b>MUL</b> on the 8088 executes in between 118 and 133 cycles and is only 2 bytes long, there should be plenty of time for the prefetch queue to fill after each instruction, even after DRAM refresh has taken its slice of memory access time. Consequently, the prefetch queue should be able to keep the Execution Unit well-supplied with instruction bytes at all times. Since Listing 4.9 uses no memory operands, the Execution Unit should never have to wait for data from memory, and DRAM refresh should have no impact on performance. (Remember that the Execution Unit can operate normally during DRAM refreshes so long as it doesn&rsquo;t need to request a memory access from the Bus Interface Unit.)</p>
@ -72,7 +75,7 @@
<p>Which of the two cases we&rsquo;ve examined reflects reality? While either case <i>can</i> happen, the latter case&mdash;significant performance reduction, ranging as high as 8.33 percent&mdash;is far more likely to occur. This is especially true for high-performance assembly code, which uses fast instructions that tend to cause non-stop instruction fetching.</p>
<h4 align="left" id="Heading18">What to Do About the DRAM Refresh Cycle-Eater?</h4>
<h4 id="Heading18">What to Do About the DRAM Refresh Cycle-Eater?</h4>
<p><i>Hmmm.</i> When we discovered the prefetch queue cycle-eater, we learned to use short instructions. When we discovered the 8-bit bus cycle-eater, we learned to use byte-sized memory operands whenever possible, and to keep word-sized variables in registers. What can we do to work around the DRAM refresh cycle-eater?</p>
@ -88,16 +91,20 @@
<p>Wait states are cycles during which a bus access by the CPU to a device on the PC&rsquo;s bus is temporarily halted by that device while the device gets ready to complete the read or write. Wait states are well and truly the lowest level of code performance. Everything we have discussed (and will discuss)&mdash;even DMA accesses&mdash;can be affected by wait states.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="04-06.html">Previous</a></td>
<td>
<a href="04-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-08.html">Next</a></td>
<td>
<a href="04-08.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="04-07.html">Previous</a></td>
<td>
<a href="04-07.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-09.html">Next</a></td>
<td>
<a href="04-09.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Wait states exist because the CPU must to be able to coexist with any adapter, no matter how slow (within reason). The 8088 expects to be able to complete each bus access&mdash;a memory or I/O read or write&mdash;in 4 cycles, but adapters can&rsquo;t always respond that quickly for a number of reasons. For example, display adapters must split access to display memory between the CPU and the circuitry that generates the video signal based on the contents of display memory, so they often can&rsquo;t immediately fulfill a request by the CPU for a display memory read or write. To resolve this conflict, display adapters can tell the CPU to wait during bus accesses by inserting one or more wait states, as shown in Figure 4.6. The CPU simply sits and idles as long as wait states are inserted, then completes the access as soon as the display adapter indicates its readiness by no longer inserting wait states. The same would be true of any adapter that couldn&rsquo;t keep up with the CPU.</p>
<p>Mind you, this is all transparent to executing code. An instruction that encounters wait states runs exactly as if there were no wait states, only slower. Wait states are nothing more or less than wasted time as far as the CPU and your program are concerned.</p>
@ -69,16 +72,20 @@
<p>Enough said. All the memory in the PC is <i>not</i> display memory, however, and unless you&rsquo;re thickheaded enough to put code in display memory, the PC isn&rsquo;t going to run as slowly as a PC<i>jr.</i> (Putting code or other non-video data in unused areas of display memory sounds like a neat idea&mdash;until you consider the effect on instruction prefetching of cutting the 8088&rsquo;s already-poor memory access performance in half. Running your code from display memory is sort of like running on a hypothetical 8084&mdash;an 8086 with a <i>4-bit</i> bus. Not recommended!) Given that your code and data reside in normal system memory below the 640K mark, how great an impact does the display adapter cycle-eater have on performance?</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="04-07.html">Previous</a></td>
<td>
<a href="04-07.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-09.html">Next</a></td>
<td>
<a href="04-09.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,20 +18,24 @@
<center>
<table border="1">
<tr>
<td><a href="04-08.html">Previous</a></td>
<td>
<a href="04-08.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-10.html">Next</a></td>
<td>
<a href="04-10.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>The answer varies considerably depending on what display adapter and what display mode we&rsquo;re talking about. The display adapter cycle-eater is worst with the Enhanced Graphics Adapter (EGA) and the original Video Graphics Array (VGA). (Many VGAs, especially newer ones, insert many fewer wait states than IBM&rsquo;s original VGA. On the other hand, Super VGAs have more bytes of display memory to be accessed in high-resolution mode.) While the Color/Graphics Adapter (CGA), Monochrome Display Adapter (MDA), and Hercules Graphics Card (HGC) all suffer from the display adapter cycle-eater as well, they suffer to a lesser degree. Since the VGA represents the base standard for PC graphics now and for the foreseeable future, and since it is the hardest graphics adapter to wring performance from, we&rsquo;ll restrict our discussion to the VGA (and its close relative, the EGA) for the remainder of this chapter.</p>
<h4 align="left" id="Heading21">The Impact of the Display Adapter Cycle-Eater</h4>
<h4 id="Heading21">The Impact of the Display Adapter Cycle-Eater</h4>
<p>Even on the EGA and VGA, the effect of the display adapter cycle-eater depends on the display mode selected. In text mode, the display adapter cycle-eater is rarely a major factor. It&rsquo;s not that the cycle-eater isn&rsquo;t present; however, a mere 4,000 bytes control the entire text mode display, and even with the display adapter cycle-eater it just doesn&rsquo;t take that long to manipulate 4,000 bytes. Even if the display adapter cycle-eater were to cause the 8088 to take as much as 5&micro;s per display memory access&mdash;more than five times normal&mdash;it would still take only 4,000x 2x 5&micro;s, or 40 &micro;s, to read and write every byte of display memory. That&rsquo;s a lot of time as measured in 8088 cycles, but it&rsquo;s less than the blink of an eye in human time, and video performance only matters in human time. After all, the whole point of drawing graphics is to convey visual information, and if that information can be presented faster than the eye can see, that is by definition fast enough.</p>
@ -102,16 +105,20 @@
<p>Bear in mind that we&rsquo;re talking about a worst case here; the impact of the display adapter cycle-eater is proportional to the percent of time a given code sequence spends accessing display memory.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="04-08.html">Previous</a></td>
<td>
<a href="04-08.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="04-10.html">Next</a></td>
<td>
<a href="04-10.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="04-09.html">Previous</a></td>
<td>
<a href="04-09.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="05-01.html">Next</a></td>
<td>
<a href="05-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<table width="100%">
<tr>
<td align="left" valign="top" width="5%"><img src="images/i.jpg" /></td>
@ -42,7 +45,7 @@
<p>Nonetheless, the display adapter cycle-eater always takes its toll on graphics code. Interestingly, that toll becomes much higher on ATs and 80386 machines because while those computers can execute many more instructions per microsecond than can the 8088-based PC, it takes just as long to access display memory on those computers as on the 8088-based PC. Remember, the limited speed of access to a graphics adapter is an inherent characteristic of the adapter, so the fastest computer around can&rsquo;t access display memory one iota faster than the adapter will allow.</p>
<h4 align="left" id="Heading22">What to Do about the Display Adapter Cycle-Eater?</h4>
<h4 id="Heading22">What to Do about the Display Adapter Cycle-Eater?</h4>
<p>What can we do about the display adapter cycle-eater? Well, we can minimize display memory accesses whenever possible. In particular, we can try to avoid read/modify/write display memory operations of the sort used to mask individual pixels and clip images. Why? Because read/modify/write operations require two display memory accesses (one read and one write) each time display memory is manipulated. Instead, we should try to use writes of the sort that set all the pixels in a given byte of display memory at once, since such writes don&rsquo;t require accompanying read accesses. The key here is that only half as many display memory accesses are required to write a byte to display memory as are required to read a byte from display memory, mask part of it off and alter the rest, and write the byte back to display memory. Half as many display memory accesses means half as many display memory wait states.</p>
@ -60,7 +63,7 @@
<p>It would be handy to explore the display adapter cycle-eater issue in depth, with lots of example code and execution timings, but alas, I don&rsquo;t have the space for that right now. For the time being, all you really need to know about the display adapter cycle-eater is that on the 8088 you can lose more than 8 cycles of execution time on each access to display memory. For intensive access to display memory, the loss really can be as high as 8cycles (and up to 50, 100, or even more on 486s and Pentiums paired with slow VGAs), while for average graphics code the loss is closer to 4 cycles; in either case, the impact on performance is significant. There is only one way to discover just how significant the impact of the display adapter cycle-eater is for any particular graphics code, and that is of course to measure the performance of that code.</p>
<h4 align="left" id="Heading23">Cycle-Eaters: A Summary</h4>
<h4 id="Heading23">Cycle-Eaters: A Summary</h4>
<p>We&rsquo;ve covered a great deal of sophisticated material in this chapter, so don&rsquo;t feel bad if you haven&rsquo;t understood everything you&rsquo;ve read; it will all become clear from further reading, especially once you study, time, and tune code that you have written yourself. What&rsquo;s really important is that you come away from this chapter understanding that on the 8088:</p>
@ -76,20 +79,24 @@
<p>This basic knowledge about cycle-eaters puts you in a good position to understand the results reported by the Zen timer, and that means that you&rsquo;re well on your way to writing high-performance assembler code.</p>
<h4 align="left" id="Heading24">What Does It All Mean?</h4>
<h4 id="Heading24">What Does It All Mean?</h4>
<p>There you have it: life under the programming interface. It&rsquo;s not a particularly pretty picture for the inhabitants of that strange realm where hardware and software meet are little-known cycle-eaters that sap the speed from your unsuspecting code. Still, some of those cycle-eaters can be minimized by keeping instructions short, using the registers, using byte-sized memory operands, and accessing display memory as little as possible. None of the cycle-eaters can be eliminated, and dynamic RAM refresh can scarcely be addressed at all; still, aren&rsquo;t you better off knowing how fast your code <i>really</i> runs&mdash;and why&mdash;than you were reading the official execution times and guessing? And while specific cycle-eaters vary in importance on later x86-family processors, with some cycle-eaters vanishing altogether and new ones appearing, the concept that understanding these obscure gremlins is a key to performance remains unchanged, as we&rsquo;ll see again and again in later chapters.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="04-09.html">Previous</a></td>
<td>
<a href="04-09.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="05-01.html">Next</a></td>
<td>
<a href="05-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="04-10.html">Previous</a></td>
<td>
<a href="04-10.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="05-02.html">Next</a></td>
<td>
<a href="05-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 5<br />
Crossing the Border</h2>
@ -59,7 +62,7 @@
<p>And with that, let&rsquo;s look at a fairly complex application of restartable blocks.</p>
<h4 align="left" id="Heading3">Searching for Text</h4>
<h4 id="Heading3">Searching for Text</h4>
<p>The application we&rsquo;re going to examine searches a file for a specified string. We&rsquo;ll develop a program that will search the file specified on the command line for a string (also specified on the comline), then report whether the string was found or not. (Because the searched-for string is obtained via <b>argv</b>, it can&rsquo;t contain any whitespace characters.)</p>
@ -75,16 +78,20 @@
<p>The easiest approach would be to use a C/C<small>++</small> library function. The closest match to what we need is <b>strstr()</b>, which searches one string for the first occurrence of a second string. However, while <b>strstr()</b> would work, it isn&rsquo;t ideal for our purposes. The problem is this: Where we want to search a fixed-length buffer for the first occurrence of a string, <b>strstr()</b> searches a <i>string</i> for the first occurrence of another string.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="04-10.html">Previous</a></td>
<td>
<a href="04-10.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="05-02.html">Next</a></td>
<td>
<a href="05-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="05-01.html">Previous</a></td>
<td>
<a href="05-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="05-03.html">Next</a></td>
<td>
<a href="05-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>We could put a zero byte at the end of our buffer to allow <b>strstr()</b> to work, but why bother? The <b>strstr()</b> function must spend time either checking for the end of the string being searched or determining the length of that string&mdash;wasted effort given that we already know exactly how long our search buffer is. Even if a given <b>strstr()</b> implementation is well-written, its performance will suffer, at least for our application, from unnecessary overhead.</p>
<table width="100%">
@ -64,7 +67,7 @@
<p>Now that we&rsquo;ve selected a searching approach, let&rsquo;s integrate it with file handling and searching through multiple blocks. In other words, let&rsquo;s make it restartable.</p>
<h4 align="left" id="Heading7">Making a Search Restartable</h4>
<h4 id="Heading7">Making a Search Restartable</h4>
<p>As it happens, there&rsquo;s no great trick to putting the pieces of this search program together. Basically, we&rsquo;ll read in a buffer of data (we&rsquo;ll work with 16K at a time to avoid signed overflow problems with integers), search it for a match with the <b>memchr()/memcmp()</b> engine described, and exit with a &ldquo;string found&rdquo; response if the desired string is found.</p>
@ -76,16 +79,20 @@
<p>Listing 5.1 nicely illustrates the core concept of restartable blocks: Organize your program so that you can do your processing within each block as fast as you could if there were only one block&mdash;which is to say at top speed&mdash;and make your blocks as large as possible in order to minimize the overhead associated with going from one block to the next.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="05-01.html">Previous</a></td>
<td>
<a href="05-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="05-03.html">Next</a></td>
<td>
<a href="05-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="05-02.html">Previous</a></td>
<td>
<a href="05-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="05-04.html">Next</a></td>
<td>
<a href="05-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 5.1 SEARCH.C</b></p>
<pre>
/* Program to search the file specified by the first command-line
@ -199,16 +202,20 @@ main(int argc, char *argv[]) {
}
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="05-02.html">Previous</a></td>
<td>
<a href="05-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="05-04.html">Next</a></td>
<td>
<a href="05-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="05-03.html">Previous</a></td>
<td>
<a href="05-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="05-05.html">Next</a></td>
<td>
<a href="05-05.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h3 id="Heading8">Interpreting Where the Cycles Go</h3>
<p>To boost the overall performance of Listing 5.1, I would normally convert <b>SearchForString()</b> to assembly language at this point. However, I&rsquo;m not going to do that, and the reason is as important a lesson as any discussion of optimized assembly code is likely to be. Take a moment to examine some interesting performance aspects of the C implementation, and all should become much clearer.</p>
@ -46,7 +49,7 @@
<p>Not likely.</p>
<h4 align="left" id="Heading9">Knowing When Assembly Is Pointless</h4>
<h4 id="Heading9">Knowing When Assembly Is Pointless</h4>
<p>So that&rsquo;s why we&rsquo;re not going to go to assembly language in this example&mdash;which is not to say it would never be worth converting the search engine in Listing 5.1 to assembly.</p>
@ -54,16 +57,20 @@
<p>In contrast, Listing 5.1 must return from <b>memchr()</b>, set up parameters, and call <b>memcmp()</b> in order to do the same thing. Likewise, assembly can switch back to <b>REPNZ SCASB</b> after a non-match much more quickly than Listing 5.1. The switching overhead is high; when searching a file completely filled with the character z for the string &ldquo;zy,&rdquo; Listing 5.1 takes almost 1/2 minute, or nearly an order of magnitude longer than when searching a file filled with normal text.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="05-03.html">Previous</a></td>
<td>
<a href="05-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="05-05.html">Next</a></td>
<td>
<a href="05-05.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="05-04.html">Previous</a></td>
<td>
<a href="05-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="06-01.html">Next</a></td>
<td>
<a href="06-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>It might also be worth converting the search engine to assembly for searches performed entirely in memory; with the overhead of file access eliminated, improvements in search-engine performance would translate directly into significantly faster overall performance. One such application that would have much the same structure as Listing 5.1 would be searching through expanded memory buffers, and another would be searching through huge (segment-spanning) buffers.</p>
<p>And so we find, as we so often will, that optimization is definitely not a cut-and-dried matter, and that there is no such thing as a single &ldquo;best&rdquo; approach.</p>
@ -66,16 +69,20 @@
<p>Would you?</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="05-04.html">Previous</a></td>
<td>
<a href="05-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="06-01.html">Next</a></td>
<td>
<a href="06-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="05-05.html">Previous</a></td>
<td>
<a href="05-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="06-02.html">Next</a></td>
<td>
<a href="06-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 6<br />
Looking Past Face Value</h2>
@ -59,7 +62,7 @@
<p>In short, the x86 family can do much more than you think&mdash;if you&rsquo;ll use everything it has to offer. Give it a shot!</p>
<h4 align="left" id="Heading3">Memory Addressing and Arithmetic</h4>
<h4 id="Heading3">Memory Addressing and Arithmetic</h4>
<p>Years ago, I saw a clip on the David Letterman show in which Letterman walked into a store by the name of &ldquo;Just Lamps&rdquo; and asked, &ldquo;So what do you sell here?&rdquo;</p>
@ -86,16 +89,20 @@ mov al,[bx]
mov al,[bx+si]
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="05-05.html">Previous</a></td>
<td>
<a href="05-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="06-02.html">Next</a></td>
<td>
<a href="06-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="06-01.html">Previous</a></td>
<td>
<a href="06-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="07-01.html">Next</a></td>
<td>
<a href="07-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>The two approaches are functionally interchangeable but <i>not</i> equivalent from a performance standpoint, and which is better depends on the particular context. If it&rsquo;s a one-shot memory access, it&rsquo;s best to let the processor perform the addition; it&rsquo;s generally faster at doing this than a separate <b>ADD</b> instruction would be. If it&rsquo;s a memory access within a loop, however, it&rsquo;s advantageous on the 8088 CPU to perform the addition outside the loop, if possible, reducing effective address calculation time inside the loop, as in the following:</p>
<pre>
add bx,si
@ -83,7 +86,7 @@ lea di,[si+2]
<p><a id="Fig1"><img src="images/06-01.jpg" /><br />
<b>Figure 6.1</b></a>&nbsp;&nbsp;<i>Operation of ADD Reg,Reg vs. LEA Reg,{Addr}.</i></p>
<h4 align="left" id="Heading5">The Wonders of LEA on the 386</h4>
<h4 id="Heading5">The Wonders of LEA on the 386</h4>
<p><b>LEA</b> really comes into its own as a &ldquo;super-ADD&rdquo; instruction on the 386, 486, and Pentium, where it can take advantage of the enhanced memory addressing modes of those processors. (The 486 and Pentium offer the same modes as the 386, so I&rsquo;ll refer only to the 386 from now on.) The 386 can do two very interesting things: It can use <i>any</i> 32-bit register (EAX, EBX, and so on) as the memory addressing base register and/or the memory addressing index register, and it can multiply any 32-bit register used as an index by two, four, or eight in the process of calculating a memory address, as shown in Figure 6.2. Let&rsquo;s see what that&rsquo;s good for.</p>
@ -137,16 +140,20 @@ add ebx,edx
<p>I&rsquo;d like to extend my thanks to Duane Strong of Metagraphics for his help in brainstorming uses for the 386 version of <b>LEA</b> and for pointing out the complications of 486 instruction timings.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="06-01.html">Previous</a></td>
<td>
<a href="06-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="07-01.html">Next</a></td>
<td>
<a href="07-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="06-02.html">Previous</a></td>
<td>
<a href="06-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="07-02.html">Next</a></td>
<td>
<a href="07-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 7<br />
Local Optimization</h2>
@ -67,7 +70,7 @@
<p>And yes, in case you&rsquo;re wondering, the above story is indeed true. Was I there? Let me put it this way: If I were, I&rsquo;d never admit it!</p>
<h4 align="left" id="Heading3">When LOOP Is a Bad Idea</h4>
<h4 id="Heading3">When LOOP Is a Bad Idea</h4>
<p>Let&rsquo;s examine first an instruction that is less than it appears to be: <b>LOOP</b>. There&rsquo;s no mystery about what <b>LOOP</b> does; it decrements CX and branches if CX doesn&rsquo;t decrement to zero. It&rsquo;s so beautifully suited to the task of counting down loops that any experienced x86 programmer instinctively stuffs the loop count in CX and reaches for <b>LOOP</b> when setting up a loop. That&rsquo;s fine&mdash;<b>LOOP</b> does, of course, work as advertised&mdash;but there is one problem:</p>
@ -89,16 +92,20 @@
</tr>
</table>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="06-02.html">Previous</a></td>
<td>
<a href="06-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="07-02.html">Next</a></td>
<td>
<a href="07-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="07-01.html">Previous</a></td>
<td>
<a href="07-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="07-03.html">Next</a></td>
<td>
<a href="07-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>By the way, don&rsquo;t fall victim to the lures of <b>JCXZ</b> and do something like this:</p>
<pre>
and cx,ofh ;Isolate the desired field
@ -50,7 +53,7 @@ jz SkipLoop ;If field is 0, don&rsquo;t bother
<p>In particular, if you&rsquo;re going to write 386 protected mode code, which will run only on the 386, 486, and Pentium, you&rsquo;d be well advised to rethink your use of the more esoteric members of the x86 instruction set. <b>LOOP, JCXZ,</b> the various accumulator-specific instructions, and even the string instructions in many circumstances no longer offer the advantages they did on the 8088. Sometimes they&rsquo;re just not any faster than more general instructions, so they&rsquo;re not worth going out of your way to use; sometimes, as with <b>LOOP,</b> they&rsquo;re actually slower, and you&rsquo;d do well to avoid them altogether in the 386/486 world. Reviewing the instruction cycle times in the MASM or TASM manuals, or looking over the cycle times in Intel&rsquo;s literature, is a good place to start; published cycle times are closer to actual execution times on the 386 and 486 than on the 8088, and are reasonably reliable indicators of the relative performance levels of x86 instructions.</p>
<h4 align="left" id="Heading5">Avoiding LOOPS of Any Stripe</h4>
<h4 id="Heading5">Avoiding LOOPS of Any Stripe</h4>
<p>Cycle counting and directly substituting instructions (<b>DEC CX/JNZ</b> for <b>LOOP,</b> for example) are techniques that belong at the lowest level of optimization. It&rsquo;s an important level, but it&rsquo;s fairly mechanical; once you&rsquo;ve learned the capabilities and relative performance levels of the various instructions, you should be able to select the best instructions fairly easily. What&rsquo;s more, this is a task at which compilers excel. What I&rsquo;m saying is that you shouldn&rsquo;t get too caught up in counting cycles because that&rsquo;s a small (albeit important) part of the optimization picture, and not the area in which your greatest advantage lies.</p>
@ -74,16 +77,20 @@ jz SkipLoop ;If field is 0, don&rsquo;t bother
<p>When the <b>LOOP</b> in Listing 7.1 is replaced with <b>DEC CX/JNZ,</b> performance improves to 168 &micro;s, less than 2 percent faster than Listing 7.1. Actually, instruction fetching, instruction alignment, cache characteristics, or something similar is affecting these results; I&rsquo;d expect a slightly larger improvement&mdash;around 7 percent&mdash;but that&rsquo;s the most that counting cycles could buy us in this case. (All right, already; <b>LOOPNZ</b> could be used at the bottom of the loop, and other optimizations are surely possible, but all that won&rsquo;t add up to anywhere near the benefits we&rsquo;re about to see from local optimization, and that&rsquo;s the whole point.)</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="07-01.html">Previous</a></td>
<td>
<a href="07-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="07-03.html">Next</a></td>
<td>
<a href="07-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="07-02.html">Previous</a></td>
<td>
<a href="07-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="07-04.html">Next</a></td>
<td>
<a href="07-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 7.1 L7-1.ASM</b></p>
<pre>
; Program to illustrate searching through a buffer of a specified
@ -128,16 +131,20 @@ SearchMaxLengthendp
<p>Listing 7.2 takes a different tack, unrolling the loop so that four bytes are checked for each <b>LOOP</b> performed. The same instructions are used inside the loop in each listing, but Listing 7.2 is arranged so that three-quarters of the <b>LOOP</b>s are eliminated. Listings 7.1 and 7.2 perform exactly the same task, and they use the same instructions in the loop&mdash;the searching algorithm hasn&rsquo;t changed in any way&mdash;but we have sequenced the instructions differently in Listing 7.2, and that makes all the difference.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="07-02.html">Previous</a></td>
<td>
<a href="07-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="07-04.html">Next</a></td>
<td>
<a href="07-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="07-03.html">Previous</a></td>
<td>
<a href="07-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="07-05.html">Next</a></td>
<td>
<a href="07-05.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 7.2 L7-2.ASM</b></p>
<pre>
; Program to illustrate searching through a buffer of a specified
@ -172,16 +175,20 @@ SearchMaxLengthendp
</tr>
</table>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="07-03.html">Previous</a></td>
<td>
<a href="07-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="07-05.html">Next</a></td>
<td>
<a href="07-05.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,18 +18,22 @@
<center>
<table border="1">
<tr>
<td><a href="07-04.html">Previous</a></td>
<td>
<a href="07-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="08-01.html">Next</a></td>
<td>
<a href="08-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h4 align="left" id="Heading8">Rotating and Shifting with Tables</h4>
<h4 id="Heading8">Rotating and Shifting with Tables</h4>
<p>As another example of local optimization, consider the matter of rotating or shifting a mask into position. First, let&rsquo;s look at the simple task of setting bit N of AX to 1.</p>
@ -80,7 +83,7 @@ BIT_PATTERN=BIT_PATTERN SHL 1
</tr>
</table>
<h4 align="left" id="Heading9">NOT Flips Bits&mdash;Not Flags</h4>
<h4 id="Heading9">NOT Flips Bits&mdash;Not Flags</h4>
<p>The <b>NOT</b> instruction flips all the bits in the operand, from 0 to 1 or from 1 to 0. That&rsquo;s as simple as could be, but <b>NOT</b> nonetheless has a minor but interesting talent: It doesn&rsquo;t affect the flags. That can be irritating; I once spent a good hour tracking down a bug caused by my unconscious assumption that <b>NOT</b> does set the flags. After all, every other arithmetic and logical instruction sets the flags; why not <b>NOT</b>? Probably because <b>NOT</b> isn&rsquo;t considered to be an arithmetic or logical instruction at all; rather, it&rsquo;s a data manipulation instruction, like <b>MOV</b> and the various rotates. (These are <b>RCR, RCL, ROR,</b> and <b>ROL,</b> which affect only the Carry and Overflow flags.) NOT is often used for tasks, such as flipping masks, where there&rsquo;s no reason to test the state of the result, and in that context it can be handy to keep the flags unmodified for later testing.</p>
@ -94,7 +97,7 @@ BIT_PATTERN=BIT_PATTERN SHL 1
<p>The x86 instruction set offers many ways to accomplish almost any task. Understanding the subtle distinctions between the instructions&mdash;whether and which flags are set, for example&mdash;can be critical when you&rsquo;re trying to optimize a code sequence and you&rsquo;re running out of registers, or when you&rsquo;re trying to minimize branching.</p>
<h4 align="left" id="Heading10">Incrementing with and without Carry</h4>
<h4 id="Heading10">Incrementing with and without Carry</h4>
<p>Another case in which there are two slightly different ways to perform a task involves adding 1 to an operand. You can do this with <b>INC,</b> as in <b>INC AX,</b> or you can do it with <b>ADD,</b> as in <b>ADD AX,1.</b> What&rsquo;s the difference? The obvious difference is that <b>INC</b> is usually a byte or two shorter (the exception being <b>ADD AL,1,</b> which at two bytes is the same length as <b>INC AL</b>), and is faster on some processors. Less obvious, but no less important, is that <b>ADD</b> sets the Carry flag while <b>INC</b> leaves the Carry flag untouched.</p>
@ -158,16 +161,20 @@ ADC DX,0
<p>As always, pay attention!</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="07-04.html">Previous</a></td>
<td>
<a href="07-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="08-01.html">Next</a></td>
<td>
<a href="08-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="07-05.html">Previous</a></td>
<td>
<a href="07-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="08-02.html">Next</a></td>
<td>
<a href="08-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 8<br />
Speeding Up C with Assembly Language</h2>
@ -55,7 +58,7 @@
<p>Apropos of which, when was the last time you heard of Terry Jacks?</p>
<h4 align="left" id="Heading3">Billy, Don&rsquo;t Be a Compiler</h4>
<h4 id="Heading3">Billy, Don&rsquo;t Be a Compiler</h4>
<p>The key to optimizing C programs with assembly language is, as always, writing good assembly language code, but with an added twist. Rule 1 when converting C code to assembly is this: <i>Don&rsquo;t think like a compiler.</i> That&rsquo;s more easily said than done, especially when the C code you&rsquo;re converting is readily available as a model and the assembly code that the compiler generates is available as well. Nevertheless, the principle of not thinking like a compiler is essential, and is, in one form or another, the basis for all that I&rsquo;ll discuss below.</p>
@ -81,16 +84,20 @@
<p>What this means is that when you want to speed up a portion of a C program, you should identify the entire critical portion and move <i>all</i> of that critical portion into an assembly language function. You don&rsquo;t want to move a part of the inner loop into assembly language and then call it from C every time through the loop; the function call and return overhead would be unacceptable. Carve out the critical code <i>en masse</i> and move it into assembly, and try to avoid calls and returns even in your assembly code. True, in assembly you can pass parameters in registers, but the calls and returns themselves are still slow; if the extra cycles they take don&rsquo;t affect performance, then the code they&rsquo;re in probably isn&rsquo;t critical, and perhaps you&rsquo;ve chosen to convert too much code to assembly, eh?</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="07-05.html">Previous</a></td>
<td>
<a href="07-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="08-02.html">Next</a></td>
<td>
<a href="08-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="08-01.html">Previous</a></td>
<td>
<a href="08-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="08-03.html">Next</a></td>
<td>
<a href="08-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h3 id="Heading5">Stack Frames Slow So Much</h3>
<p>C compilers work within the stack frame model, whereby variables reside in a block of stack memory and are accessed via offsets from BP. Compilers may store a couple of variables in registers and may briefly keep other variables in registers when they&rsquo;re used repeatedly, but the stack frame is the underlying architecture. It&rsquo;s a nice architecture; it&rsquo;s flexible, convenient, easy to program, and makes for fairly compact code. However, stack frames have a few drawbacks. They must be constructed and destroyed, which takes both time and code. They are so easy to use that they tend to bias the assembly language programmer in favor of accessing memory variables more often than might be necessary. Finally, you cannot use BP as a general-purpose register if you intend to access a stack frame, and having that seventh register available is sometimes useful indeed.</p>
@ -50,7 +53,7 @@
<p>In assembly language you have full control over segments. Use it, and, if necessary, reorganize your code to minimize segment loading.</p>
<h4 align="left" id="Heading7">Why Speeding Up Is Hard to Do</h4>
<h4 id="Heading7">Why Speeding Up Is Hard to Do</h4>
<p>You might think that the most obvious advantage assembly language has over C is that it allows the use of all forms of instructions and all registers in all ways, whereas C compilers tend to use a subset of registers and instructions in a limited number of ways. Yes and no. It&rsquo;s true that C compilers typically don&rsquo;t generate instructions such as <b>XLAT,</b> rotates, or the string instructions. On the other hand, <b>XLAT</b> and rotates are useful in a limited set of circumstances, and string instructions <i>are</i> used in the C library functions. In fact, C library code is likely to be carefully optimized by experts, and may be much better than equivalent code you&rsquo;d produce yourself.</p>
@ -113,20 +116,24 @@ jz Match
<p>That said, let me show some of these precepts in action.</p>
<h4 align="left" id="Heading9">A C-to-Assembly Case Study</h4>
<h4 id="Heading9">A C-to-Assembly Case Study</h4>
<p>Listing 8.1 is the sample C application I&rsquo;m going to use to examine optimization in action. Listing 8.1 isn&rsquo;t really complete&mdash;it doesn&rsquo;t handle the &ldquo;no-matches&rdquo; case well, and it assumes that the sum of all matches will fit into an <b>int&mdash;</b>but it will do just fine as an optimization example.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="08-01.html">Previous</a></td>
<td>
<a href="08-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="08-03.html">Next</a></td>
<td>
<a href="08-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="08-02.html">Previous</a></td>
<td>
<a href="08-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="08-04.html">Next</a></td>
<td>
<a href="08-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 8.1 L8-1.C</b></p>
<pre>
/* Program to search an array spanning a linked list of variable-
@ -193,16 +196,20 @@ $I265:
$FB264:
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="08-02.html">Previous</a></td>
<td>
<a href="08-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="08-04.html">Next</a></td>
<td>
<a href="08-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="08-03.html">Previous</a></td>
<td>
<a href="08-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="08-05.html">Next</a></td>
<td>
<a href="08-05.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>It&rsquo;s hard to squeeze much more performance from this code by tweaking it, as exemplified by Listing 8.3, a fine-tuned assembly version of <b>FindIDAverage</b> that was produced by looking at the assembly output of MS C/C<small>++</small> and tightening it. Listing 8.3 eliminates all stack frame access in the inner loop, but that&rsquo;s about all the tightening there is to do. The result, as shown in Table 8.1, is that Listing 8.3 runs a modest 11 percent faster than Listing 8.1 on a 386. The results could vary considerably, depending on the nature of the data set searched through (average block size and frequency of matches). But, then, understanding the typical and worst case conditions is part of optimization, isn&rsquo;t it?</p>
<p><b>LISTING 8.3 L8-3.ASM</b></p>
@ -290,16 +293,20 @@ _FindIDAverage ENDP
end
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="08-03.html">Previous</a></td>
<td>
<a href="08-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="08-05.html">Next</a></td>
<td>
<a href="08-05.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="08-04.html">Previous</a></td>
<td>
<a href="08-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="09-01.html">Next</a></td>
<td>
<a href="09-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Listings 8.5 and 8.6 together go the final step and change the rules in favor of assembly language. Listing 8.5 creates the same list of linked blocks as Listing 8.1. However, instead of storing an array of structures within each block, it stores <i>two</i> arrays in each block, one consisting of ID numbers and the other consisting of the corresponding values, as shown in Figure 8.3. No information is lost; the data is merely rearranged.</p>
<p><b>LISTING 8.5 L8-5.C</b></p>
@ -186,16 +189,20 @@ _FindIDAverage2 ENDP
<p>I trust you get the picture. The sort of instruction-by-instruction optimization that so many of us love to do as a kind of puzzle is fun, but compilers can do it nearly as well as you can, and in the future will surely do it better. What a compiler <i>can&rsquo;t</i> do is tie together the needs of the program specification on the high end and the processor on the low end, resulting in critical code that runs just about as fast as the hardware permits. The only software that can do that is located north of your sternum and slightly aft of your nose. Dust it off and put it to work&mdash;and your code will never again be confused with anything by Hamilton, Joe, Frank, eynolds or Bo Donaldson and the Heywoods.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="08-04.html">Previous</a></td>
<td>
<a href="08-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="09-01.html">Next</a></td>
<td>
<a href="09-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="08-05.html">Previous</a></td>
<td>
<a href="08-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="09-02.html">Next</a></td>
<td>
<a href="09-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 9<br />
Hints My Readers Gave Me</h2>
@ -64,7 +67,7 @@ X - 1 = 0
<p>I like to think I know more about performance programming than Barry knew about math. Nonetheless, I always welcome good ideas and comments, and many readers have sent me a slew of those over the years. So in this chapter, I think I&rsquo;ll return the favor by devoting a chapter to reader feedback.</p>
<h4 align="left" id="Heading3">Another Look at LEA</h4>
<h4 id="Heading3">Another Look at LEA</h4>
<p>Several people have pointed out that while <b>LEA</b> is great for performing certain additions (see Chapter 6), it isn&rsquo;t a perfect replacement for <b>ADD</b>. What&rsquo;s the difference? <b>LEA</b>, an addressing instruction by trade, doesn&rsquo;t affect the flags, while the arithmetic <b>ADD</b> instruction most certainly does. This is no problem when performing additions that involve only quantities that fit in one machine word (32 bits in 386 protected mode, 16 bits otherwise), but it renders <b>LEA</b> useless for multiword operations, which use the Carry flag to tie together partial results. For example, these instructions</p>
<pre>
@ -100,7 +103,7 @@ ADDLOOP:
<p>But there sure are a lot of interesting options, aren&rsquo;t there?</p>
<h4 align="left" id="Heading4">The Kennedy Portfolio</h4>
<h4 id="Heading4">The Kennedy Portfolio</h4>
<p>Reader John Kennedy regularly passes along intriguing assembly programming tricks, many of which I&rsquo;ve never seen mentioned anywhere else. John likes to optimize for size, whereas I lean more toward speed, but many of his optimizations are good for both purposes. Here are a few of my favorites:</p>
@ -140,16 +143,20 @@ REP MOVSB ;copy any odd byte
CopyDone:
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="08-05.html">Previous</a></td>
<td>
<a href="08-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="09-02.html">Next</a></td>
<td>
<a href="09-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="09-01.html">Previous</a></td>
<td>
<a href="09-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="09-03.html">Next</a></td>
<td>
<a href="09-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>However, it generally is. Sure, if the length is odd, John&rsquo;s approach incurs a penalty approximately equal to the <b>REP</b> startup time for <b>MOVSB</b>. However, if the length is even, John&rsquo;s approach doesn&rsquo;t branch, saving cycles and not emptying the prefetch queue. If copy lengths are evenly distributed between even and odd, John&rsquo;s approach is faster in most x86 systems. (Not on the 486, though.)</p>
<p>John also points out that on the 386, multiple <b>LEA</b>s can be combined to perform multiplications that can&rsquo;t be handled by a single <b>LEA</b>, much as multiple shifts and adds can be used for multiplication, only faster. <b>LEA</b> can be used to multiply in a single instruction on the 386, but only by the values 2, 3, 4, 5, 8, and 9; several <b>LEA</b>s strung together can handle a much wider range of values. For example, video programmers are undoubtedly familiar with the following code to multiply AX times 80 (the width in bytes of the bitmap in most PC display modes):</p>
@ -66,7 +69,7 @@ SHL AX,2 ;*64
ADD AX,BX ;*80
</pre>
<h4 align="left" id="Heading5">Speeding Up Multiplication</h4>
<h4 id="Heading5">Speeding Up Multiplication</h4>
<p>That brings us to multiplication, one of the slowest of x86 operations and one that allows for considerable optimization. One way to speed up multiplication is to use shift and add, <b>LEA</b>, or a lookup table to hard-code a multiplication operation for a fixed multiplier, as shown above. Another is to take advantage of the early-out feature of the 386 (and the 486, but in the interests of brevity I&rsquo;ll just say &ldquo;386&rdquo; from now on) by arranging your operands so that the multiplier (always the rightmost operand following <b>MUL</b> or <b>IMUL</b>) is no larger than the other operand.</p>
@ -96,7 +99,7 @@ ADD AX,BX ;*80
<p>That doesn&rsquo;t mean that your code should test and swap operands to make sure the smaller one is the multiplier; that rarely pays off. I&rsquo;m speaking more of the case where you&rsquo;re scaling an array up by a value that&rsquo;s always in the range of, say, 2 to 10; because the scale value will always be small and the array elements may have any value, the scale value is the logical choice for the multiplier.</p>
<h4 align="left" id="Heading6">Optimizing Optimized Searching</h4>
<h4 id="Heading6">Optimizing Optimized Searching</h4>
<p>Rob Williams writes with a wonderful optimization to the <b>REPNZ SCASB-</b>based optimized searching routine I discussed in Chapter 5. As a quick refresher, I described searching a buffer for a text string as follows: Scan for the first byte of the text string with <b>REPNZ SCASB</b>, then use <b>REPZ CMPS</b> to check for a full match whenever <b>REPNZ SCASB</b> finds a match for the first character, as shown in Figure 9.1. The principle is that most buffer characters won&rsquo;t match the first character of any given string, so <b>REPNZ SCASB</b>, by far the fastest way to search on the PC, can be used to eliminate most potential matches; each remaining potential match can then be checked in its entirety with <b>REPZ CMPS</b>.</p>
@ -115,16 +118,20 @@ ADD AX,BX ;*80
<p>Imagine, if you will, that you&rsquo;re searching for the string &ldquo;EQUAL.&rdquo; By my approach, you&rsquo;d use <b>REPNZ SCASB</b> to scan for each occurrence of &ldquo;E,&rdquo; which crops up quite often in normal text. Rob points out that it would make more sense to scan for &ldquo;Q,&rdquo; then back up one character and check the whole string when a &ldquo;Q&rdquo; is found, as shown in Figure 9.2. &ldquo;Q&rdquo; is likely to occur much less often, resulting in many fewer whole-string checks and much faster processing.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="09-01.html">Previous</a></td>
<td>
<a href="09-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="09-03.html">Next</a></td>
<td>
<a href="09-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="09-02.html">Previous</a></td>
<td>
<a href="09-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="09-04.html">Next</a></td>
<td>
<a href="09-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Listing 9.1 implements the scan-on-first-character approach. Listing 9.2 scans for whatever character the caller specifies. Listing 9.3 is a test program used to compare the two approaches. How much difference does Rob&rsquo;s revelation make? Plenty. Even when the entire C function call to <b>FindString</b> is timed&mdash;<b>strlen</b> calls, parameter pushing, calling, setup, and all&mdash;the version of <b>FindString</b> in Listing 9.2, which is directed by Listing 9.3 to scan for the infrequently-occurring &ldquo;Q,&rdquo; is about 40 percent faster on a 20 MHz cached 386 for the test search of Listing 9.3 than is the version of <b>FindString</b> in Listing 9.1, which always scans for the first character, in this case &ldquo;E.&rdquo; However, when only the search loops (the code that actually does the searching) in the two versions of <b>FindString</b> are compared, Listing 9.2 is more than <i>twice</i> as fast as Listing 9.1&mdash;a remarkable improvement over code that already uses <b>REPNZ SCASB</b> and <b>REPZ CMPS</b>.</p>
<p>What I like so much about Rob&rsquo;s approach is that it demonstrates that optimization involves much more than instruction selection and cycle counting. Listings 9.1 and 9.2 use pretty much the same instructions, and even use the same approach of scanning with <b>REPNZ SCASB</b> and using <b>REPZ CMPS</b> to check scanning matches.</p>
@ -140,16 +143,20 @@ _FindStringendp
end
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="09-02.html">Previous</a></td>
<td>
<a href="09-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="09-04.html">Next</a></td>
<td>
<a href="09-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="09-03.html">Previous</a></td>
<td>
<a href="09-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="09-05.html">Next</a></td>
<td>
<a href="09-05.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 9.2 L9-2.ASM</b></p>
<pre>
; Searches a text buffer for a text string. Uses REPNZ SCASB to scan
@ -166,16 +169,20 @@ void main() {
}
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="09-03.html">Previous</a></td>
<td>
<a href="09-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="09-05.html">Next</a></td>
<td>
<a href="09-05.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,22 +18,26 @@
<center>
<table border="1">
<tr>
<td><a href="09-04.html">Previous</a></td>
<td>
<a href="09-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="09-06.html">Next</a></td>
<td>
<a href="09-06.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>You&rsquo;ll notice that in Listing 9.2 I didn&rsquo;t use a table of character frequencies in English text to determine the character for which to scan, but rather let the caller make that choice. Each buffer of bytes has unique characteristics, and English-letter frequency could well be inappropriate. What if the buffer is filled with French text? Cyrillic? What if it isn&rsquo;t text that&rsquo;s being searched? It might be worthwhile for an application to build a dynamic frequency table for each buffer so that the best scan character could be chosen for each search. Or perhaps not, if the search isn&rsquo;t time-critical or the buffer is small.</p>
<p>The point is that you can improve performance dramatically by understanding the nature of the data with which you work. (This is equally true for high-level language programming, by the way.) Listing 9.2 is very similar to and only slightly more complex than Listing 9.1; the difference lies not in elbow grease or cycle counting but in the organic integrating optimizer technology we all carry around in our heads.</p>
<h4 align="left" id="Heading7">Short Sorts</h4>
<h4 id="Heading7">Short Sorts</h4>
<p>David Stafford (recently of Borland and Borland Japan) who happens to be one of the best assembly language programmers I&rsquo;ve ever met, has written a C-callable routine that sorts an array of integers in ascending order. That wouldn&rsquo;t be particularly noteworthy, except that David&rsquo;s routine, shown in Listing 9.4, is exactly <i>25 bytes</i> long. Look at the code; you&rsquo;ll keep saying to yourself, &ldquo;But this doesn&rsquo;t work...oh, yes, I guess it does.&rdquo; As they say in the Prego spaghetti sauce ads, <i>it&rsquo;s in there</i>&mdash;and what a job of packing. Anyway, David says that a 24-byte sort routine eludes him, and he&rsquo;d like to know if anyone can come up with one.</p>
@ -74,7 +77,7 @@ _sort: pop dx ;get return address (entry point)
end
</pre>
<h4 align="left" id="Heading8">Full 32-Bit Division</h4>
<h4 id="Heading8">Full 32-Bit Division</h4>
<p>One of the most annoying limitations of the x86 is that while the dividend operand to the <b>DIV</b> instruction can be 32 bits in size, both the divisor and the result must be 16 bits. That&rsquo;s particularly annoying in regards to the result because sometimes you just don&rsquo;t know whether the ratio of the dividend to the divisor is greater than 64K-1 or not&mdash;and if you guess wrong, you get that godawful Divide By Zero interrupt. So, what is one to do when the result might not fit in 16 bits, or when the dividend is larger than 32 bits? Fall back to a software division approach? That will work&mdash;but oh so slowly.</p>
@ -87,16 +90,20 @@ _sort: pop dx ;get return address (entry point)
<p>As for handling signed division with arbitrarily large dividends, that can be done easily enough by remembering the signs of the dividend and divisor, dividing the absolute value of the dividend by the absolute value of the divisor, and applying the stored signs to set the proper signs for the quotient and remainder. There may be more clever ways to produce the same result, by using <b>IDIV</b>, for example; if you know of one, drop me a line c/o Coriolis Group Books.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="09-04.html">Previous</a></td>
<td>
<a href="09-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="09-06.html">Next</a></td>
<td>
<a href="09-06.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="09-05.html">Previous</a></td>
<td>
<a href="09-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="09-07.html">Next</a></td>
<td>
<a href="09-07.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 9.5 L9-5.ASM</b></p>
<pre>
; Divides an arbitrarily long unsigned dividend by a 16-bit unsigned
@ -120,7 +123,7 @@ main() {
}
</pre>
<h4 align="left" id="Heading9">Sweet Spot Revisited</h4>
<h4 id="Heading9">Sweet Spot Revisited</h4>
<p>Way back in Volume 1, Number 1 of <i>PC TECHNIQUES</i>, (April/May 1990) I wrote the very first of that magazine&rsquo;s HAX (#1), which extolled the virtues of placing your most commonly-used automatic (stack-based) variables within the stack&rsquo;s &ldquo;sweet spot,&rdquo; the area between +127 to -128 bytes away from BP, the stack frame pointer. The reason was that the 8088 can store addressing displacements that fall within that range in a single byte; larger displacements require a full word of storage, increasing code size by a byte per instruction, and thereby slowing down performance due to increased instruction fetching time.</p>
@ -138,16 +141,20 @@ main() {
<p>In assembly, it&rsquo;s easy to control the organization of your stack frame. In C, however, you&rsquo;ll have to figure out the allocation scheme your compiler uses to allocate automatic variables, and declare automatics appropriately to produce the desired effect. It can be done: I did it in Turbo C some years back, and trimmed the size of a program (admittedly, a large one) by several K&mdash;not bad, when you consider that the &ldquo;sweet spot&rdquo; optimization is essentially free, with no code reorganization, change in logic, or heavy thinking involved.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="09-05.html">Previous</a></td>
<td>
<a href="09-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="09-07.html">Next</a></td>
<td>
<a href="09-07.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,18 +18,22 @@
<center>
<table border="1">
<tr>
<td><a href="09-06.html">Previous</a></td>
<td>
<a href="09-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="10-01.html">Next</a></td>
<td>
<a href="10-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h4 align="left" id="Heading10">Hard-Core Cycle Counting</h4>
<h4 id="Heading10">Hard-Core Cycle Counting</h4>
<p>Next, we come to an item that cycle counters will love, especially since it involves apparently incorrect documentation on Intel&rsquo;s part. According to Intel&rsquo;s documents, all <b>RCR</b> and <b>RCL</b> instructions, which perform rotations through the Carry flag, as shown in Figure 9.4, take 9 cycles on the 386 when working with a register operand. My measurements indicate that the 9-cycle execution time almost holds true for <i>multibit</i> rotate-through-carries, which I&rsquo;ve timed at 8 cycles apiece; for example, <b>RCR AX,CL</b> takes 8 cycles on <i>my</i> 386, as does <b>RCL DX,2</b>. Contrast that with <b>ROR</b> and <b>ROL</b>, which can rotate the contents of a register any number of bits in just 3 cycles.</p>
@ -43,7 +46,7 @@
<p>No great lesson here, just a caution to be leery of multibit <b>RCR</b> and <b>RCL</b> when performance matters&mdash;and to take cycle-time documentation with a grain of salt.</p>
<h4 align="left" id="Heading11">Hardwired Far Jumps</h4>
<h4 id="Heading11">Hardwired Far Jumps</h4>
<p>Did you ever wonder how to code a far jump to an absolute address in assembly language? Probably not, but if you ever do, you&rsquo;re going to be glad for this next item, because the obvious solution doesn&rsquo;t work. You might think all it would take to jump to, say, 1000:5 would be <b>JMP FAR PTR 1000:5</b>, but you&rsquo;d be wrong. That won&rsquo;t even assemble. You might then think to construct in memory a far pointer containing 1000:5, as in the following:</p>
<pre>
@ -84,7 +87,7 @@ start:
<p>If the obvious doesn&rsquo;t work (and it usually doesn&rsquo;t), just try everything you can think of, no matter how ridiculous, until you find something that does&mdash;a rule with plenty of history on its side.</p>
<h4 align="left" id="Heading12">Setting 32-Bit Registers: Time versus Space</h4>
<h4 id="Heading12">Setting 32-Bit Registers: Time versus Space</h4>
<p>To finish up this chapter, consider these two items. First, in 32-bit protected mode,</p>
<pre>
@ -111,16 +114,20 @@ move bx,-1
<p>Be warned, though, that I&rsquo;ve found <b>OR, AND, ADD</b>, and the like to be a cycle slower than <b>MOV</b> when working with immediate operands on the 386 under some circumstances, for reasons that thus far escape me. This just reinforces the first rule of optimization: Measure your code in action, and place not your trust in documented cycle times.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="09-06.html">Previous</a></td>
<td>
<a href="09-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="10-01.html">Next</a></td>
<td>
<a href="10-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="09-07.html">Previous</a></td>
<td>
<a href="09-07.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="10-02.html">Next</a></td>
<td>
<a href="10-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 10<br />
Patient Coding, Faster Code</h2>
@ -57,7 +60,7 @@
<p>In this chapter, I&rsquo;m going to walk you through a simple but illustrative case history that nicely points up the wisdom of delaying gratification when faced with programming problems, so that your mind has time to chew on the problems from other angles. The alternative solutions you find by doing this may seem obvious, once you&rsquo;ve come up with them. They may not even differ greatly from your initial solutions. Often, however, they will be much better&mdash;and you&rsquo;ll never even have the chance to decide whether they&rsquo;re better or not if you take the first thing that comes into your head and run with it.</p>
<h4 align="left" id="Heading3">The Case for Delayed Gratification</h4>
<h4 id="Heading3">The Case for Delayed Gratification</h4>
<p>Once upon a time, I set out to read <i>Algorithms</i>, by Robert Sedgewick (Addison-Wesley), which turned out to be a wonderful, stimulating, and most useful book, one that I recommend highly. My story, however, involves only what happened in the first 12 pages, for it was in those pages that Sedgewick discussed Euclid&rsquo;s algorithm.</p>
@ -71,16 +74,20 @@
<p>You see, I fell victim to a common programming pitfall, the &ldquo;brute-force&rdquo; syndrome. The basis of this syndrome is that there are many problems that have obvious, brute-force solutions&mdash;with one small drawback. The drawback is that if you were to try to apply a brute-force solution by hand&mdash;that is, work a single problem out with pencil and paper or a calculator&mdash;it would generally require that you have the patience and discipline to work on the problem for approximately seven hundred years, not counting eating and sleeping, in order to get an answer. Finding all the prime numbers less than 1,000,000 is a good example; just divide each number up to 1,000,000 by every lesser number, and see what&rsquo;s left standing. For most of the history of humankind, people were forced to think of cleverer solutions, such as the Sieve of Eratosthenes (we&rsquo;d have been in big trouble if the ancient Greeks had had computers), mainly because after about five minutes of brute force-type work, people&rsquo;s attention gets diverted to other important matters, such as how far a paper airplane will fly from a second-story window.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="09-07.html">Previous</a></td>
<td>
<a href="09-07.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="10-02.html">Next</a></td>
<td>
<a href="10-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="10-01.html">Previous</a></td>
<td>
<a href="10-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="10-03.html">Next</a></td>
<td>
<a href="10-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Not so nowadays, though. Computers love boring work; they&rsquo;re very patient and disciplined, and, besides, one human year = seven dog years = two zillion computer years. So when we&rsquo;re faced with a problem that has an obvious but exceedingly lengthy solution, we&rsquo;re apt to say, &ldquo;Ah, let the computer do that, it&rsquo;s fast,&rdquo; and go back to making paper airplanes. Unfortunately, brute-force solutions tend to be slow even when performed by modern-day microcomputers, which are capable of several MIPS except when I&rsquo;m late for an appointment and want to finish a compile and run just one more test before I leave, in which case the crystal in my computer is apparently designed to automatically revert to 1 Hz.)</p>
<p>The solution that I instantly came up with to finding the GCD is about as brute- force as you can get: Divide both the larger integer (iL) and the smaller integer (iS) by every integer equal to or less than the smaller integer, until a number is found that divides both evenly, as shown in Figure 10.1. This works, but it&rsquo;s a lousy solution, requiring as many as iS*2 divisions; <i>very</i> expensive, especially for large values of iS. For example, finding the GCD of 30,001 and 30,002 would require 60,002 divisions, which alone, disregarding tests and branches, would take about 2 seconds on an 8088, and more than 50 milliseconds even on a 25 MHz 486&mdash;a <i>very</i> long time in computer years, and not insignificant in human years either.</p>
@ -240,7 +243,7 @@ unsigned int gcd(unsigned int int1, unsigned int int2) {
}
</pre>
<h4 align="left" id="Heading5">Wasted Breakthroughs</h4>
<h4 id="Heading5">Wasted Breakthroughs</h4>
<p>Sedgewick&rsquo;s first solution to the GCD problem was pretty much the one I came up with. He then pointed out that the GCD of iL and iS is the same as the GCD of iL-iS and iS. This was obvious (once Sedgewick pointed it out); by the very nature of division, any number that divides iL evenly nL times and iS evenly nS times must divide iL-iS evenly nL-nS times. Given that insight, I immediately designed a new, faster approach, shown in Listing 10.2.</p>
@ -277,16 +280,20 @@ unsigned int gcd(unsigned int int1, unsigned int int2) {
}
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="10-01.html">Previous</a></td>
<td>
<a href="10-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="10-03.html">Next</a></td>
<td>
<a href="10-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="10-02.html">Previous</a></td>
<td>
<a href="10-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="10-04.html">Next</a></td>
<td>
<a href="10-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Listing 10.2 repeatedly subtracts iS from iL until iL becomes less than or equal to iS. If iL becomes equal to iS, then that&rsquo;s the GCD; alternatively, if iL becomes <i>less</i> than iS, iL and iS switch values, and the process is repeated, as shown in Figure 10.2. The number of iterations this approach requires relative to Listing 10.1 depends heavily on the values of iL and iS, so it&rsquo;s not always faster, but, as Table 10.1 indicates, Listing 10.2 is generally much better code.</p>
<p><a id="Fig2"><img src="images/10-02.jpg" /><br />
@ -141,20 +144,24 @@ unsigned int gcd(unsigned int int1, unsigned int int2) {
}
</pre>
<h4 align="left" id="Heading7">Patient Optimization</h4>
<h4 id="Heading7">Patient Optimization</h4>
<p>At long last, we&rsquo;re ready to optimize GCD determination in the classic sense. Table 10.1 shows the performance of Listing 10.4 with and without Microsoft C/C<small>++</small>&rsquo;s maximum optimization, and also shows the performance of Listing 10.5, an assembly language version of Listing 10.4. Sure, the optimized versions are faster than the unoptimized version of Listing 10.4&mdash;but the gains are small compared to those realized from the higher-level optimizations in Listings 10.2 through 10.4.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="10-02.html">Previous</a></td>
<td>
<a href="10-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="10-04.html">Next</a></td>
<td>
<a href="10-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="10-03.html">Previous</a></td>
<td>
<a href="10-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-01.html">Next</a></td>
<td>
<a href="11-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 10.5 L10-5.ASM</b></p>
<pre>
; Finds and returns the greatest common divisor of two integers.
@ -139,16 +142,20 @@ _gcd endp
<p>And think what you could do with all those extra computer years!</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="10-03.html">Previous</a></td>
<td>
<a href="10-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-01.html">Next</a></td>
<td>
<a href="11-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="10-04.html">Previous</a></td>
<td>
<a href="10-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-02.html">Next</a></td>
<td>
<a href="11-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 11<br />
Pushing the 286 and 386</h2>
@ -39,7 +42,7 @@
<p>This chapter provides an interesting look at the evolution of the x86 architecture, to a greater degree than you might expect, for the x86 family came into full maturity with the 386; the 486 and the Pentium are really nothing more than faster 386s, with very little in the way of new functionality. In contrast, the 286 added a number of instructions, respectable performance, and protected mode to the 8088&rsquo;s capabilities, and the 386 added more instructions and a whole new set of addressing modes, and brought the x86 family into the 32-bit world that represents the future (and, increasingly, the present) of personal computing. This chapter also provides insight into the effects on optimization of the variations in processors and memory architectures that are common in the PC world. So, although the 286 and 386 no longer represent the mainstream of computing, this chapter is a useful mix of history lesson, x86 overview, and details on two workhorse processors that are still in wide use.</p>
<h4 align="left" id="Heading3">Family Matters</h4>
<h4 id="Heading3">Family Matters</h4>
<p>While the x86 family is a large one, only a few members of the family&mdash;which includes the 8088, 8086, 80188, 80186, 286, 386SX, 386DX, numerous permutations of the 486, and now the Pentium&mdash;really matter.</p>
@ -53,7 +56,7 @@
<p>This leaves us with just two processors: the 286 and the 386. Each was <i>the</i> PC standard in its day. The 286 is no longer used in new systems, but there are millions of 286-based systems still in daily use. The 386 is still being used in new systems, although it&rsquo;s on the downhill leg of its lifespan, and it is in even wider use than the 286. The future clearly belongs to the 486 and Pentium, but the 286 and 386 are still very much a part of the present-day landscape.</p>
<h4 align="left" id="Heading4">Crossing the Gulf to the 286 and the 386</h4>
<h4 id="Heading4">Crossing the Gulf to the 286 and the 386</h4>
<p>Apart from vastly improved performance, the biggest difference between the 8088 and the 286 and 386 (as well as the later Intel CPUs) is that the 286 introduced protected mode, and the 386 greatly expanded the capabilities of protected mode. We&rsquo;re only going to talk about real-mode operation of the 286 and 386 in this book, however. Protected mode offers a whole new memory management scheme, one that isn&rsquo;t supported by the 8088. Only code specifically written for protected mode can run in that mode; it&rsquo;s an alien and hostile environment for MS-DOS programs.</p>
@ -75,22 +78,26 @@ mov dx,word ptr [LongVar+2]
<p>In short, taken as a whole, protected mode programming is a different kettle of fish altogether from what I&rsquo;ve been describing in this book. There&rsquo;s certainly a knack to optimizing specifically for protected mode under a given operating system...but it&rsquo;s not what we&rsquo;ve been learning, and now is not the time to pursue it further. In general, though, the optimization strategies discussed in this book still hold true in protected mode; it&rsquo;s just issues specific to protected mode or a particular operating system that we won&rsquo;t discuss.</p>
<h4 align="left" id="Heading5">In the Lair of the Cycle-Eaters, Part II</h4>
<h4 id="Heading5">In the Lair of the Cycle-Eaters, Part II</h4>
<p>Under the programming interface, the 286 and 386 differ considerably from the 8088. Nonetheless, with one exception and one addition, the cycle-eaters remain much the same on computers built around the 286 and 386. Next, we&rsquo;ll review each of the familiar cycle-eaters I covered in Chapter 4 as they apply to the 286 and 386, and we&rsquo;ll look at the new member of the gang, the data alignment cycle-eater.</p>
<p>The one cycle-eater that vanishes on the 286 and 386 is the 8-bit bus cycle-eater. The 286 is a 16-bit processor both internally and externally, and the 386 is a 32-bit processor both internally and externally, so the Execution Unit/Bus Interface Unit size mismatch that plagues the 8088 is eliminated. Consequently, there&rsquo;s no longer any need to use byte-sized memory variables in preference to word-sized variables, at least so long as word-sized variables start at even addresses, as we&rsquo;ll see shortly. On the other hand, access to byte-sized variables still isn&rsquo;t any <i>slower</i> than access to word-sized variables, so you can use whichever size suits a given task best.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="10-04.html">Previous</a></td>
<td>
<a href="10-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-02.html">Next</a></td>
<td>
<a href="11-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="11-01.html">Previous</a></td>
<td>
<a href="11-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-03.html">Next</a></td>
<td>
<a href="11-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>You might think that the elimination of the 8-bit bus cycle-eater would mean that the prefetch queue cycle-eater would also vanish, since on the 8088 the prefetch queue cycle-eater is a side effect of the 8-bit bus. That would seem all the more likely given that both the 286 and the 386 have larger prefetch queues than the 8088 (6 bytes for the 286, 16 bytes for the 386) and can perform memory accesses, including instruction fetches, in far fewer cycles than the 8088.</p>
<p>However, the prefetch queue cycle-eater <i>doesn&rsquo;t</i> vanish on either the 286 or the 386, for several reasons. For one thing, branching instructions still empty the prefetch queue, so instruction fetching still slows things down after most branches; when the prefetch queue is empty, it doesn&rsquo;t much matter how big it is. (Even apart from emptying the prefetch queue, branches aren&rsquo;t particularly fast on the 286 or the 386, at a minimum of seven-plus cycles apiece. Avoid branching whenever possible.)</p>
@ -89,16 +92,20 @@ Skip:
<p>What does this mean? It means that, practically speaking, the 286 as used in the AT doesn&rsquo;t have a 16-bit bus. From a performance perspective, the 286 in an AT has two-thirds of a 16-bit bus (a 10.7-bit bus?), since every bus access on an AT takes 50 percent longer than it should. A 286 running at 10 MHz <i>should</i> be able to access memory at a maximum rate of 1 word every 200 ns; in a 10 MHz AT, however, that rate is reduced to 1 word every 300 ns by the one-wait-state memory.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="11-01.html">Previous</a></td>
<td>
<a href="11-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-03.html">Next</a></td>
<td>
<a href="11-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="11-02.html">Previous</a></td>
<td>
<a href="11-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-04.html">Next</a></td>
<td>
<a href="11-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>In short, a close relative of our old friend the 8-bit bus cycle-eater&mdash;the system memory wait state cycle-eater&mdash;haunts us still on all but zero-wait-state 286 and 386 computers, and that means that the prefetch queue cycle-eater is alive and well. (The system memory wait state cycle-eater isn&rsquo;t really a new cycle-eater, but rather a variant of the general wait state cycle-eater, of which the display adapter cycle-eater is yet another variant.) While the 286 in the AT can fetch instructions much faster than can the 8088 in the PC, it can execute those instructions faster still.</p>
<p>The picture is less clear in the 386 world since there are so many different memory architectures, but similar problems can occur in any computer built around a 286 or 386. The prefetch queue cycle-eater is even a factor&mdash;albeit a lesser one&mdash;on zero-wait-state machines, both because branching empties the queue and because some instructions can outrun even zero&mdash;5 cycles longer than the official execution time.)</p>
@ -128,22 +131,26 @@ Skip:
<p>The data alignment cycle-eater has intriguing implications for speeding up 286/386 code. The expenditure of a little care and a few bytes to make sure that word-sized variables and memory blocks are word-aligned can literally double the performance of certain code running on the 286. Even if it doesn&rsquo;t double performance, word alignment usually helps and never hurts.</p>
<h4 align="left" id="Heading8">Code Alignment</h4>
<h4 id="Heading8">Code Alignment</h4>
<p>Lack of word alignment can also interfere with instruction fetching on the 286, although not to the extent that it interferes with access to word-sized memory variables. The 286 prefetches instructions a word at a time; even if a given instruction doesn&rsquo;t begin at an even address, the 286 simply fetches the first byte of that instruction at the same time that it fetches the last byte of the previous instruction, as shown in Figure 11.2, then separates the bytes internally. That means that in most cases, instructions run just as fast whether they&rsquo;re word-aligned or not.</p>
<p>There is, however, a non-word-alignment penalty on <i>branches</i> to odd addresses. On a branch to an odd address, the 286 is only able to fetch 1 useful byte with the first instruction fetch following the branch, as shown in Figure 11.3. In other words, lack of word alignment of the target instruction for any branch effectively cuts the instruction-fetching power of the 286 in half for the first instruction fetch after that branch. While that may not sound like much, you&rsquo;d be surprised at what it can do to tight loops; in fact, a brief story is in order.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="11-02.html">Previous</a></td>
<td>
<a href="11-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-04.html">Next</a></td>
<td>
<a href="11-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="11-03.html">Previous</a></td>
<td>
<a href="11-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-05.html">Next</a></td>
<td>
<a href="11-05.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>When I was developing the Zen timer, I used my trusty 10 MHz 286-based AT clone to verify the basic functionality of the timer by measuring the performance of simple instruction sequences. I was cruising along with no problems until I timed the following code:</p>
<pre>
@ -115,16 +118,20 @@ FindChar proc near
<p>The two ways of looking at the display adapter cycle-eater on 286/386 computers are actually the same. As you&rsquo;ll recall from my earlier discussion of the matter in Chapter 4, display adapters offer only a limited number of accesses to display memory during any given period of time. The 8088 is capable of making use of most but not all of those slots with <b>REP MOVSW</b>, so the number of memory accesses allowed by a display adapter such as a standard VGA is reasonably well-matched to an 8088&rsquo;s memory access speed. Granted, access to a VGA slows the 8088 down considerably&mdash;but, as we&rsquo;re about to find out, &ldquo;considerably&rdquo; is a relative term. What a VGA does to PC performance is nothing compared to what it does to faster computers.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="11-03.html">Previous</a></td>
<td>
<a href="11-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-05.html">Next</a></td>
<td>
<a href="11-05.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="11-04.html">Previous</a></td>
<td>
<a href="11-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-06.html">Next</a></td>
<td>
<a href="11-06.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Under ideal conditions, a 286 can access memory much, much faster than an 8088. A 10 MHz 286 is capable of accessing a word of system memory every 0.20 ms with <b>REP MOVSW</b>, dwarfing the 1 byte every 1.31 &micro;s that the 8088 in a PC can manage. However, access to display memory is anything but ideal for a 286. For one thing, most display adapters are 8-bit devices, although newer adapters are 16-bit in nature. One consequence of that is that only 1 byte can be read or written per access to display memory; word-sized accesses to 8-bit devices are automatically split into 2 separate byte-sized accesses by the AT&rsquo;s bus. Another consequence is that accesses are simply slower; the AT&rsquo;s bus inserts additional wait states on accesses to 8-bit devices since it must assume that such devices were designed for PCs and may not run reliably at AT speeds.</p>
<p>However, the 8-bit size of most display adapters is but one of the two factors that reduce the speed with which the 286 can access display memory. Far more cycles are eaten by the inherent memory-access limitations of display adapters&mdash;that is, the limited number of display memory accesses that display adapters make available to the 286. Look at it this way: If <b>REP MOVSW</b> on a PC can use more than half of all available accesses to display memory, then how much faster can code running on a 286 or 386 possibly run when accessing display memory?</p>
@ -54,7 +57,7 @@
<p>What can we do about this new, more virulent form of the display adapter cycle-eater? The workaround is the same as it was on the PC: Access display memory as little as you possibly can.</p>
<h4 align="left" id="Heading13">New Instructions and Features: The 286</h4>
<h4 id="Heading13">New Instructions and Features: The 286</h4>
<p>The 286 and 386 offer a number of new instructions. The 286 has a relatively small number of instructions that the 8088 lacks, while the 386 has those instructions and quite a few more, along with new addressing modes and data sizes. We&rsquo;ll discuss the 286 and the 386 separately in this regard.</p>
@ -64,7 +67,7 @@
<p>A couple of old instructions gain new features on the 286. For one, the 286 version of <b>PUSH</b> is capable of pushing a constant on the stack. For another, the 286 allows all shifts and rotates to be performed for not just 1 bit or the number of bits specified by CL, but for <i>any</i> constant number of bits.</p>
<h4 align="left" id="Heading14">New Instructions and Features: The 386</h4>
<h4 id="Heading14">New Instructions and Features: The 386</h4>
<p>The 386 is somewhat more complex than the 286 regarding new features. Once again, we won&rsquo;t discuss protected mode, which on the 386 comes with the ability to address up to 4 gigabytes per segment and 64 terabytes in all. In real mode (and in virtual-86 mode, which allows the 386 to multitask MS-DOS applications, and which is identical to real mode so far as MS-DOS programs are concerned), programs running on the 386 are still limited to 1 MB of addressable memory and 64K per segment.</p>
@ -74,16 +77,20 @@
<p>The 386 also comes with a slew of new real-mode instructions beyond those supported by the 8088 and 286. These instructions can scan data on a bit-by-bit basis, set the Carry flag to the value of a specified bit, sign-extend or zero-extend data as it&rsquo;s moved, set a register or memory variable to 1 or 0 on the basis of any of the conditions that can be tested with conditional jumps, and more. (Again, beware: Many of these complex 386-specific instructions are slower than equivalent sequences of simple instructions on the 486 and especially on the Pentium.) What&rsquo;s more, both old and new instructions support 32-bit operations on the 386. For example, it&rsquo;s relatively simple to copy data in chunks of 4 bytes on a 386, even in real mode, by using the <b>MOVSD</b> (&ldquo;move string double&rdquo;) instruction, or to negate a 32-bit value with <b>NEG eax</b>.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="11-04.html">Previous</a></td>
<td>
<a href="11-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-06.html">Next</a></td>
<td>
<a href="11-06.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="11-05.html">Previous</a></td>
<td>
<a href="11-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-07.html">Next</a></td>
<td>
<a href="11-07.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Finally, it&rsquo;s possible in real mode to use the 386&rsquo;s new addressing modes, in which <i>any</i> 32-bit general-purpose register or pair of registers can be used to address memory. What&rsquo;s more, multiplication of memory-addressing registers by 2, 4, or 8 for look-ups in word, doubleword, or quadword tables can be built right into the memory addressing mode. (The 32-bit addressing modes are discussed further in later chapters.) In protected mode, these new addressing modes allow you to address a full 4 gigabytes per segment, but in real mode you&rsquo;re still limited to 64K, even with 32-bit registers and the new addressing modes, unless you play some unorthodox tricks with the segment registers.</p>
<table width="100%">
@ -80,16 +83,20 @@
call ZTimerOff
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="11-05.html">Previous</a></td>
<td>
<a href="11-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-07.html">Next</a></td>
<td>
<a href="11-07.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="11-06.html">Previous</a></td>
<td>
<a href="11-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-08.html">Next</a></td>
<td>
<a href="11-08.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 11.5 L11-5.ASM</b></p>
<pre>
;
@ -61,7 +64,7 @@ Skip:
<p>The more things change, the more they remain the same....</p>
<h4 align="left" id="Heading17">POPF and the 286</h4>
<h4 id="Heading17">POPF and the 286</h4>
<p>We&rsquo;ve one final 286-related item to discuss: the hardware malfunction of <b>POPF</b> under certain circumstances on the 286.</p>
@ -73,16 +76,20 @@ Skip:
<p>All <b>POPF</b> does is pop the word on top of the stack into the FLAGS register, as shown in Figure 11.4. How can we do that without <b>POPF</b>? Of course, the 286&rsquo;s designers intended us to use <b>POPF</b> for this purpose, and didn&rsquo;t intentionally provide any alternative approach, so we&rsquo;ll have to devise an alternative approach of our own. To do that, we&rsquo;ll have to search for instructions that contain some of the same functionality as <b>POPF</b>, in the hope that one of those instructions can be used in some way to replace <b>POPF</b>.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="11-06.html">Previous</a></td>
<td>
<a href="11-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="11-08.html">Next</a></td>
<td>
<a href="11-08.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="11-07.html">Previous</a></td>
<td>
<a href="11-07.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="12-01.html">Next</a></td>
<td>
<a href="12-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Well, there&rsquo;s only one instruction other than <b>POPF</b> that loads the FLAGS register directly from the stack, and that&rsquo;s <b>IRET</b>, which loads the FLAGS register from the stack as it branches, as shown in Figure 11.5. iret has no known bugs of the sort that plague <b>POPF</b>, so it&rsquo;s certainly a candidate to replace popf in non-interruptible applications. Unfortunately, <b>IRET</b> loads the FLAGS register with the <i>third</i> word down on the stack, not the word on top of the stack, as is the case with <b>POPF</b>; the far return address that <b>IRET</b> pops into CS:IP lies between the top of the stack and the word popped into the FLAGS register.</p>
<p>Obviously, the segment:offset that <b>IRET</b> expects to find on the stack above the pushed flags isn&rsquo;t present when the stack is set up for <b>POPF</b>, so we&rsquo;ll have to adjust the stack a bit before we can substitute <b>IRET</b> for <b>POPF</b>. What we&rsquo;ll have to do is push the segment:offset of the instruction after our workaround code onto the stack right above the pushed flags. <b>IRET</b> will then branch to that address and pop the flags, ending up at the instruction after the workaround code with the flags popped. That&rsquo;s just the result that would have occurred had we executed <b>POPF</b>&mdash;WITH the bonus that no interrupts can accidentally occur when the Interrupt flag is 0 both before and after the pop.</p>
@ -103,16 +106,20 @@ EMULATE_POPFmacro
<p>And now you know the nature of and the workaround for the <b>POPF</b> bug. Whether you ever need the workaround or not, it&rsquo;s a neatly packaged example of the tremendous flexibility of the x86 instruction set.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="11-07.html">Previous</a></td>
<td>
<a href="11-07.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="12-01.html">Next</a></td>
<td>
<a href="12-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="11-08.html">Previous</a></td>
<td>
<a href="11-08.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="12-02.html">Next</a></td>
<td>
<a href="12-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 12<br />
Pushing the 486</h2>
@ -45,7 +48,7 @@
<p>Substitute &ldquo;processor&rdquo; for the various digging implements, and you get an idea of just how different the optimization rules for the 486 are from what you&rsquo;re used to. Okay, it&rsquo;s not quite <i>that</i> bad&mdash;but upon encountering a processor where string instructions are often to be avoided and memory-to-register <b>MOV</b>s are frequently as fast as register-to-register <b>MOV</b>s, Dorothy was heard to exclaim (before she sank out of sight in a swirl of hopelessly mixed metaphors), &ldquo;I don&rsquo;t think we&rsquo;re in Kansas anymore, Toto.&rdquo;</p>
<h4 align="left" id="Heading3">Enter the 486</h4>
<h4 id="Heading3">Enter the 486</h4>
<p>No chip that is a direct, fully compatible descendant of the 8088, 286, and 386 could ever be called a RISC chip, but the 486 certainly contains RISC elements, and it&rsquo;s those elements that are most responsible for making 486 optimization unique. Simple, common instructions are executed in a single cycle by a RISC-like core processor, but other instructions are executed pretty much as they were on the 386, where every instruction takes at least 2 cycles. For example, <b>MOV AL, [TestChar]</b> takes only 1 cycle on the 486, assuming both instruction and data are in the cache&mdash;3 cycles faster than the 386&mdash;but <b>STOSB</b> takes 5 cycles, 1 cycle <i>slower</i> than on the 386. The floating-point execution unit inside the 486 is also much faster than the 387 math coprocessor, largely because, being in the same silicon as the CPU (the 486 has a math coprocessor built in), it is more tightly coupled. The results are sometimes startling: <b>FMUL</b> (floating point multiply) is usually faster on the 486 than <b>IMUL</b> (integer multiply)!</p>
@ -65,7 +68,7 @@
<p>In other words, for cached code (which time-critical code almost always is), performance is predictable and can be calculated with good precision, and those calculations will apply on any 486. However, &ldquo;predictable&rdquo; doesn&rsquo;t mean &ldquo;trivial&rdquo;; the cycle times printed for the various instructions are not the whole story. You must be aware of all the rules, documented and undocumented, that go into calculating actual execution times&mdash;and uncovering some of those rules is exactly what this chapter is about.</p>
<h4 align="left" id="Heading5">The Hazards of Indexed Addressing</h4>
<h4 id="Heading5">The Hazards of Indexed Addressing</h4>
<p>Rule #1: Avoid indexed addressing (that is, try not to use either two registers or scaled addressing to point to memory).</p>
@ -101,16 +104,20 @@ LoopTop:
sub si,bx
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="11-08.html">Previous</a></td>
<td>
<a href="11-08.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="12-02.html">Next</a></td>
<td>
<a href="12-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="12-01.html">Previous</a></td>
<td>
<a href="12-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="12-03.html">Next</a></td>
<td>
<a href="12-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>which calculates the same sum and leaves the registers in the same state as the first example, but avoids indexed addressing.</p>
<p>In protected mode, the definition of indexed addressing is a tad more complex. The use of two registers to address memory, as in <b>MOV EAX, [EDX+EDI]</b>, still qualifies for the one-cycle penalty. In addition, the use of 386/486 scaled addressing, as in <b>MOV [ECX*2],EAX</b>, also constitutes indexed addressing, even if only one register is used to point to memory.</p>
@ -40,7 +43,7 @@
<p>In a key loop on the 486, 1 cycle can indeed matter.</p>
<h4 align="left" id="Heading6">Calculate Memory Pointers Ahead of Time</h4>
<h4 id="Heading6">Calculate Memory Pointers Ahead of Time</h4>
<p>Rule #2: Don&rsquo;t use a register as a memory pointer during the next two cycles after loading it.</p>
@ -125,16 +128,20 @@ jnz LoopTop
<p>A caution: I&rsquo;m quite certain that the 2-cycle-ahead addressing pipeline interruption penalty I&rsquo;ve described exists in the two 486s I&rsquo;ve tested. However, there&rsquo;s no guarantee that Intel won&rsquo;t change this aspect of the 486 in the future, especially given that the documentation indicates otherwise. Perhaps the 2-cycle penalty is the result of a bug in the initial steps of the 486, and will revert to the documented 1-cycle penalty someday; likewise for the undocumented optimizations I&rsquo;ll describe below. Nonetheless, none of the optimizations I suggest would hurt performance even if the undocumented performance characteristics of the 486 were to vanish, and they certainly will help performance on at least some 486s right now, so I feel they&rsquo;re well worth using.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="12-01.html">Previous</a></td>
<td>
<a href="12-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="12-03.html">Next</a></td>
<td>
<a href="12-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,20 +18,24 @@
<center>
<table border="1">
<tr>
<td><a href="12-02.html">Previous</a></td>
<td>
<a href="12-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="12-04.html">Next</a></td>
<td>
<a href="12-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>There is, of course, no guarantee that I&rsquo;m entirely correct about the optimizations discussed in this chapter. Without knowing the internals of the 486, all I can do is time code and make inferences from the results; I invite you to deduce your own rules and cross-check them against mine. Also, most likely there are other optimizations that I&rsquo;m unaware of. If you have further information on these or any other undocumented optimizations, please write and let me know. And, of course, if anyone from Intel is reading this and wants to give us the gospel truth, please do!</p>
<h4 align="left" id="Heading8">Stack Addressing and Address Pipelining</h4>
<h4 id="Heading8">Stack Addressing and Address Pipelining</h4>
<p>Rule #2A: Rule #2 sometimes, but not always, applies to the stack pointer when it is implicitly used to point to memory.</p>
@ -74,7 +77,7 @@ pop ax
<p>I certainly haven&rsquo;t tried all possible combinations, but the results so far indicate that the stack pointer incurs the addressing pipeline penalty only if (E)SP is the <i>explicit</i> destination of one instruction and is then used by one of the two following instructions to address memory. So, for instance, SP isn&rsquo;t the explicit operand of <b>POP AX&mdash;</b>AX is&mdash;and no cycles are lost if <b>POP AX</b> is followed by <b>POP</b> or <b>RET</b>. Happily, then, we need not worry about the sequence in which we use <b>PUSH</b> and <b>POP</b>. However, adding to, moving to, or subtracting from the stack pointer should ideally be done at least two cycles before <b>PUSH</b>, <b>POP</b>, <b>RET</b>, or any other instruction that uses the stack pointer to address memory.</p>
<h4 align="left" id="Heading9">Problems with Byte Registers</h4>
<h4 id="Heading9">Problems with Byte Registers</h4>
<p>There are two ways to lose cycles by using byte registers, and neither of them is documented by Intel, so far as I know. Let&rsquo;s start with the lesser and simpler of the two.</p>
@ -120,16 +123,20 @@ xlat
<p>In general, penalties for interrupting the 486&rsquo;s pipeline apply primarily to the fast core instructions of the 486, most notably register-only instructions and <b>MOV</b>, although arithmetic and logical operations that access memory are also often affected. I don&rsquo;t know all the performance dependencies, and I don&rsquo;t plan to; figuring all of them out would be a big, boring job of little value. Basically, on the 486 you should concentrate on using those fast core instructions when performance matters, and all the rules I&rsquo;ll discuss do indeed apply to those instructions.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="12-02.html">Previous</a></td>
<td>
<a href="12-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="12-04.html">Next</a></td>
<td>
<a href="12-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,20 +18,24 @@
<center>
<table border="1">
<tr>
<td><a href="12-03.html">Previous</a></td>
<td>
<a href="12-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="13-01.html">Next</a></td>
<td>
<a href="13-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>You don&rsquo;t need to understand every corner of the 486 universe unless you&rsquo;re a diehard ASMhead who does this stuff for fun. Just learn enough to be able to speed up the key portions of your programs, and spend the rest of your time on a fast design and overall implementation.</p>
<h4 align="left" id="Heading10">More Fun with Byte Registers</h4>
<h4 id="Heading10">More Fun with Byte Registers</h4>
<p>Rule #4: Don&rsquo;t load <i>any</i> byte register exactly 2 cycles before using <i>any</i> register to address memory.</p>
@ -78,7 +81,7 @@ mov ax,[bx]
</tr>
</table>
<h4 align="left" id="Heading11">Timing Your Own 486 Code</h4>
<h4 id="Heading11">Timing Your Own 486 Code</h4>
<p>In case you want to do some 486 performance analysis of your own, let me show you how I arrived at one of the above conclusions; at the same time, I can warn you of the timing hazards of the cache. Listings 12.1 and 12.2 show the code I ran through the Zen timer in order to establish the effects of loading a byte register before using a register to address memory. Listing 12.1 ran in 120 &micro;s on a 33 MHz 486, or 4 cycles per repetition (120 &micro;s/1000 repetitions = 120 ns per repetition; 120 ns per repetition/30 ns per cycle = 4 cycles per repetition); Listing 12.2 ran in 90 &micro;s, or 3 cycles, establishing that loading a byte register costs a cycle only when it&rsquo;s performed exactly 2 cycles before addressing memory.</p>
@ -140,16 +143,20 @@ Done:
<p>Sometimes it <i>is</i> hard to believe we&rsquo;re still in Kansas!</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="12-03.html">Previous</a></td>
<td>
<a href="12-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="13-01.html">Next</a></td>
<td>
<a href="13-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="12-04.html">Previous</a></td>
<td>
<a href="12-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="13-02.html">Next</a></td>
<td>
<a href="13-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 13<br />
Aiming the 486</h2>
@ -43,7 +46,7 @@
<p>For example, consider how Terje Mathisen doubled the speed of his word-counting program on a 486 simply by shuffling a couple of instructions.</p>
<h4 align="left" id="Heading3">486 Pipeline Optimization</h4>
<h4 id="Heading3">486 Pipeline Optimization</h4>
<p>I&rsquo;ve mentioned Terje Mathisen in my writings before. Terje is an assembly language programmer extraordinaire, and author of the incredibly fast public-domain word-counting program WC (which comes complete with source code; well worth a look, if you want to see what <i>really</i> fast code looks like). Terje&rsquo;s a regular participant in the ibm.pc/fast.code topic on Bix. In a thread titled &ldquo;486 Pipeline Optimization, or TANSTATFC (There Ain&rsquo;t No Such Thing As The Fastest Code),&rdquo; he detailed the following optimization to WC, perhaps the best example of 486 pipeline optimization I&rsquo;ve yet seen.</p>
@ -82,16 +85,20 @@ add dx,[bx+8000h] ;increment word and line count
<p>At this point, Terje had nearly doubled the performance of this code simply by moving one instruction. (Note that swapping the instructions also made it necessary to preload DI at the start of the loop; Listing 13.2 is not exactly equivalent to Listing 13.1.) I&rsquo;ll let Terje describe his next optimization in his own words:</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="12-04.html">Previous</a></td>
<td>
<a href="12-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="13-02.html">Next</a></td>
<td>
<a href="13-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="13-01.html">Previous</a></td>
<td>
<a href="13-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="13-03.html">Next</a></td>
<td>
<a href="13-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>&ldquo;When I looked closely as this, I realized that the two cycles for the final <b>ADD</b> is just the sum of 1 cycle to load the data from memory, and 1 cycle to add it to DX, so the code could just as well have been written as shown in Listing 13.3. The final breakthrough came when I realized that by initializing AX to zero outside the loop, I could rearrange it as shown in Listing 13.4 and do the final <b>ADD DX,AX</b> after the loop. This way there are two single-cycle instructions between the first and the fourth line, avoiding all pipeline stalls, for a total throughput of two cycles/char.&rdquo;</p>
<p><b>LISTING 13.3 L13-3.ASM</b></p>
@ -88,16 +91,20 @@ looptop:
<p>Not necessarily. Shifts and rotates are among the worst performing instructions of the 486, taking 2 to 3 cycles to execute. Thus, it takes 2 cycles to rotate the skip value into CX in Listing 13.5, and 2 more cycles to rotate it back to the upper half of ECX. I&rsquo;d say four cycles is a pretty steep price to pay, especially considering that a <b>MOV</b> to or from memory takes only one cycle. Basically, using <b>ROR</b> to access a 16-bit value in the upper half of a 16-bit register is a pretty marginal technique, unless for some reason you can&rsquo;t access memory at all (for example, if you&rsquo;re using BP as a working register, temporarily making the stack frame inaccessible).</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="13-01.html">Previous</a></td>
<td>
<a href="13-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="13-03.html">Next</a></td>
<td>
<a href="13-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="13-02.html">Previous</a></td>
<td>
<a href="13-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="13-04.html">Next</a></td>
<td>
<a href="13-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>On the 386, <b>ROR</b> was the only way to split a 32-bit register into two 16-bit registers. On the 486, however, <b>BSWAP</b> can not only do the job, but can do it better, because <b>BSWAP</b> executes in just one cycle. <b>BSWAP</b> has the added benefit of not affecting any flags, unlike <b>ROR</b>. With <b>BSWAP</b>-based code like that in Listing 13.6, the upper 16 bits of a register can be accessed with only 2 cycles of overhead and without altering any flags, making the technique of packing two 16-bit registers into one 32-bit register much more useful.</p>
<p><b>LISTING 13.6 L13-6.ASM</b></p>
@ -89,16 +92,20 @@ mov dx,ax
<p>Again, this technique is advantageous <i>only</i> on a 486. It also doesn&rsquo;t apply to <b>RCL</b> and <b>RCR,</b> where you definitely want to use the 1-bit versions whenever you can, because the n-bit versions are horrendously slow. But if you&rsquo;re optimizing for the 486, these tidbits can save a few critical cycles&mdash;and Lord knows that if you&rsquo;re optimizing for the 486&mdash;that is, if you need even more performance than you get from unoptimized code on a 486&mdash;you almost certainly need all the speed you can get.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="13-02.html">Previous</a></td>
<td>
<a href="13-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="13-04.html">Next</a></td>
<td>
<a href="13-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="13-03.html">Previous</a></td>
<td>
<a href="13-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="14-01.html">Next</a></td>
<td>
<a href="14-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h3 id="Heading7">32-Bit Addressing Modes</h3>
<p>The 386 and 486 both support 32-bit addressing modes, in which any register may serve as the base memory addressing register, and almost any register may serve as the potentially scaled index register. For example,</p>
@ -77,16 +80,20 @@ LoopTop:
<p>Lastly, as I mentioned, ESP cannot be scaled. In fact, ESP cannot be an index register; it must be a base register. Ironically, however, ESP is the one register that cannot be used to address memory without the presence of an SIB byte, even if it&rsquo;s used without an index register. This is an outcome of the way in which the SIB byte extends the capabilities of the Mod-R/M byte, and there&rsquo;s nothing to be done about it, but it&rsquo;s at least worth noting that ESP-based, non-indexed addressing makes for instructions that are a byte larger than other non-indexed addressing (but not any slower; there&rsquo;s no 1-cycle penalty for using ESP as a base register) on the 486.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="13-03.html">Previous</a></td>
<td>
<a href="13-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="14-01.html">Next</a></td>
<td>
<a href="14-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="13-04.html">Previous</a></td>
<td>
<a href="13-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="14-02.html">Next</a></td>
<td>
<a href="14-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 14<br />
Boyer-Moore String Searching</h2>
@ -77,16 +80,20 @@
<p>Actually, yes, we can.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="13-04.html">Previous</a></td>
<td>
<a href="13-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="14-02.html">Next</a></td>
<td>
<a href="14-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="14-01.html">Previous</a></td>
<td>
<a href="14-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="14-03.html">Next</a></td>
<td>
<a href="14-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h3 id="Heading4">The Boyer-Moore Algorithm</h3>
<p>All our <i>a priori</i> knowledge of string searching is stated above, but there&rsquo;s another sort of knowledge&mdash;knowledge that&rsquo;s generated dynamically. As we search through the buffer, we acquire information each time we check for a match. One sort of information that we acquire is based on partial matches; we can often skip ahead after partial matches because (take a deep breath!) by partially matching, we have already implicitly done a comparison of the partially matched buffer characters with all possible pattern start locations that overlap those partially-matched bytes.</p>
@ -71,16 +74,20 @@
<p>The best case for Boyer-Moore is good indeed: About N/M comparisons are required, where N is the buffer length and M is the pattern length. This reflects the ability of Boyer-Moore to skip ahead by a full pattern length on a complete mismatch.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="14-01.html">Previous</a></td>
<td>
<a href="14-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="14-03.html">Next</a></td>
<td>
<a href="14-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="14-02.html">Previous</a></td>
<td>
<a href="14-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="14-04.html">Next</a></td>
<td>
<a href="14-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>How fast <i>is</i> Boyer-Moore? Listing 14.1 is a C implementation of Boyer-Moore searching; Listing 14.2 is a test-bed program that searches up to the first 32K of a file for a pattern. Table 14.1 (all times measured with Turbo Profiler on a 20 MHz cached 386, searching a modified version of the text of this chapter) shows that this implementation is generally much slower than <b>REPNZ SCASB,</b> although it does come close when searching for long patterns. Listing 14.1 is designed primarily to make later assembly implemenmore comprehensible, rather than faster; Sedge&rsquo;s implementation uses arrays rather than pointers, is a great deal more compact and very clever, and may be somewhat faster. Regardless, the far superior performance of <b>REPNZ SCASB</b> clearly indicates that assembly language is in order at this point.</p>
<table width="100%">
@ -197,16 +200,20 @@
<p>The entry &ldquo;Standard Boyer-Moore in ASM&rdquo; in Table 14.1 refers to straight-forward hand optimization of Listing 14.1, code that is not included in this chapter for the perfectly good reason that it is slower in most cases than <b>REPNZ SCASB.</b> I say this casually now, but not so yesterday, when I had all but concluded that Boyer-Moore was simply inferior on the x86, due to two architectural quirks: the string instructions and slow branch. I had even coined a neat phrase for it: Architecture is destiny. Has a nice ring, doesn&rsquo;t it?</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="14-02.html">Previous</a></td>
<td>
<a href="14-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="14-04.html">Next</a></td>
<td>
<a href="14-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="14-03.html">Previous</a></td>
<td>
<a href="14-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="14-05.html">Next</a></td>
<td>
<a href="14-05.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 14.1 L14-1.C</b></p>
<pre>
/* Searches a buffer for a specified pattern. In case of a mismatch,
@ -179,16 +182,20 @@ void main() {
<p>Well, architecture carries a lot of weight, but it sure as heck isn&rsquo;t destiny. I had simply fallen into the trap of figuring that the algorithm was so clever that I didn&rsquo;t have to do any thinking myself. The path leading to <b>REPNZ SCASB</b> from the original brute-force approach of <b>REPZ CMPSB</b> at every location had been based on my observation that the first character comparison at each buffer location usually fails. Why not apply the same concept to Boyer-Moore? Listing 14.3 is just like the standard implementation&mdash;except that it&rsquo;s optimized to handle a first-comparison mismatch as quickly as possible in the loop at <b>QuickSearchLoop</b>, much as <b>REPNZ SCASB</b> optimizes first-comparison mismatches for the brute-force approach. The results in Table 14.1 speak for themselves; Listing 14.3 is more than twice as fast as what I assure you was already a nice, tight assembly implementation (and unrolling <b>QuickSearchLoop</b> could boost performance by up to 10 percent more). Listing 14.3 is also <i>four times</i> faster than <b>REPNZ SCASB</b> in one case.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="14-03.html">Previous</a></td>
<td>
<a href="14-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="14-05.html">Next</a></td>
<td>
<a href="14-05.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="14-04.html">Previous</a></td>
<td>
<a href="14-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="14-06.html">Next</a></td>
<td>
<a href="14-06.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 14.3 L14-3.ASM</b></p>
<pre>
; Searches a buffer for a specified pattern. In case of a mismatch,
@ -194,16 +197,20 @@ _FindString endp
end
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="14-04.html">Previous</a></td>
<td>
<a href="14-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="14-06.html">Next</a></td>
<td>
<a href="14-06.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="14-05.html">Previous</a></td>
<td>
<a href="14-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="15-01.html">Next</a></td>
<td>
<a href="15-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Table 14.1 represents a limited and decidedly unscientific comparison of searching techniques. Nonetheless, the overall trend is clear: For all but the shortest patterns, well-implemented Boyer-Moore is generally as good as or better than&mdash;sometimes <i>much</i> better than&mdash;brute-force searching. (For short patterns, you might want to use <b>REPNZ SCASB,</b> thereby getting the best of both worlds.)</p>
<p>Know your data and use your smarts. Don&rsquo;t stop thinking just because you&rsquo;re implementing a big-name algorithm; you know more than it does.</p>
@ -196,16 +199,20 @@ _FindString endp
<p>As Yogi Berra might put it, &ldquo;You don&rsquo;t know what you know until you know it.&rdquo;</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="14-05.html">Previous</a></td>
<td>
<a href="14-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="15-01.html">Next</a></td>
<td>
<a href="15-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="14-06.html">Previous</a></td>
<td>
<a href="14-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="15-02.html">Next</a></td>
<td>
<a href="15-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 15<br />
Linked Lists and plain Unintended Challenges</h2>
@ -70,16 +73,20 @@
<p><a id="Fig1"><img src="images/15-01.jpg" /><br />
<b>Figure 15.1</b></a>&nbsp;&nbsp;<i>The basic concept of a linked list.</i></p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="14-06.html">Previous</a></td>
<td>
<a href="14-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="15-02.html">Next</a></td>
<td>
<a href="15-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="15-01.html">Previous</a></td>
<td>
<a href="15-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="15-03.html">Next</a></td>
<td>
<a href="15-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 15.1 L15-1.C</b></p>
<pre>
/* Deletes the node in a linked list that follows the indicated node.
@ -143,16 +146,20 @@ struct LinkNode *FindNodeBeforeValueNotLess(
<p><a id="Fig3"><img src="images/15-03.jpg" /><br />
<b>Figure 15.3</b></a>&nbsp;&nbsp;<i>Representing an empty list.</i></p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="15-01.html">Previous</a></td>
<td>
<a href="15-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="15-03.html">Next</a></td>
<td>
<a href="15-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="15-02.html">Previous</a></td>
<td>
<a href="15-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="15-04.html">Next</a></td>
<td>
<a href="15-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 15.5 L15-5.C</b></p>
<pre>
/* Finds the first node in a value-sorted linked list that
@ -142,16 +145,20 @@ struct LinkNode *InsertNodeSorted(struct LinkNode *HeadOfListNode,
}
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="15-02.html">Previous</a></td>
<td>
<a href="15-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="15-04.html">Next</a></td>
<td>
<a href="15-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="15-03.html">Previous</a></td>
<td>
<a href="15-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-01.html">Next</a></td>
<td>
<a href="16-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 15.7 L15-7.ASM</b></p>
<pre>
; C near-callable assembly function for inserting a new node in a
@ -221,16 +224,20 @@ around: ja save
<p>Before I end this chapter, let me say that I get a lot of feedback from my readers, and it&rsquo;s much appreciated. Keep those cards, letters, and email messages coming. And if any of you know Jeannie Schweigert, have her drop me a line and let me know how she&rsquo;s doing these days....</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="15-03.html">Previous</a></td>
<td>
<a href="15-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-01.html">Next</a></td>
<td>
<a href="16-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="15-04.html">Previous</a></td>
<td>
<a href="15-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-02.html">Next</a></td>
<td>
<a href="16-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 16<br />
There Ain&rsquo;t No Such Thing as the Fastest Code</h2>
@ -198,16 +201,20 @@
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="15-04.html">Previous</a></td>
<td>
<a href="15-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-02.html">Next</a></td>
<td>
<a href="16-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="16-01.html">Previous</a></td>
<td>
<a href="16-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-03.html">Next</a></td>
<td>
<a href="16-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Listing 16.2 is Listing 16.1 modified to call a function that scans each block for words, and Listing 16.3 contains an assembly function that counts words. Used together, Listings 16.2 and 16.3 are just about twice as fast as Listing 16.1, a good return for a little assembly language. Listing 16.3 is a pretty straightforward translation from C to assembly; the new code makes good use of registers, but the key code&mdash;determining whether each byte is a character or not&mdash;is still done with the same multiple-sequential-tests approach used by the code that the C compiler generates.</p>
<p><b>LISTING 16.2 L16-2.C</b></p>
@ -178,20 +181,24 @@
end
</pre>
<h4 align="left" id="Heading4">Which Way to Go from Here?</h4>
<h4 id="Heading4">Which Way to Go from Here?</h4>
<p>We could rearrange the tests in light of the nature of the data being scanned; for example, we could perform the tests more efficiently by taking advantage of the knowledge that if a byte is less than &lsquo;0,&rsquo; it&rsquo;s either an apostrophe or not a character at all. However, that sort of fine-tuning is typically good for speedups of only 10 to 20 percent, and I&rsquo;ve intentionally refrained from implementing this in Listing 16.3 to avoid pointing you down the wrong path; what we need is a different tack altogether. Ponder this. What we <i>really</i> want to know is nothing more than whether a byte is a character, not what sort of character it is. For each byte value, we want a yes/no status, and nothing else&mdash;and that description practically begs for a lookup table. Listing 16.4 uses a lookup table approach to boost performance another 50 percent, to three times the performance of the original C code. On a 20 MHz 386, this represents a change from 4.6 to 1.6 seconds, which could be significant&mdash;who likes to wait? On an 8088, the improvement in word-counting a large file could easily be 10 or 20 seconds, which is <i>definitely</i> significant.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="16-01.html">Previous</a></td>
<td>
<a href="16-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-03.html">Next</a></td>
<td>
<a href="16-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="16-02.html">Previous</a></td>
<td>
<a href="16-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-04.html">Next</a></td>
<td>
<a href="16-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 16.4 L16-4.ASM</b></p>
<pre>
; Assembly subroutine for Listing 16.2. Scans through Buffer, of
@ -147,16 +150,20 @@
<p>So how did the entrants in this particular challenge stack up? More than one claimed a speed-up over my assembly word-counting code of more than three times. On top of the three-times speedup over the original C code that I had already realized, we&rsquo;re almost up to an order of magnitude faster. You are, of course, entitled to your own opinion, but <i>I</i> consider an order of magnitude to be significant.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="16-02.html">Previous</a></td>
<td>
<a href="16-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-04.html">Next</a></td>
<td>
<a href="16-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,20 +18,24 @@
<center>
<table border="1">
<tr>
<td><a href="16-03.html">Previous</a></td>
<td>
<a href="16-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-05.html">Next</a></td>
<td>
<a href="16-05.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Truth to tell, I didn&rsquo;t expect a three-times speedup; around two times was what I had in mind. Which just goes to show that any code can be made faster than you&rsquo;d expect, if you think about it long enough and from many different perspectives. (The most potent word-counting technique seems to be a 64K lookup table that allows handling two bytes simultaneously. This is not the sort of technique one comes up with by brute-force optimization.) Thinking (or, worse yet, boasting) that your code is the fastest possible is rollescating on a tightrope in a hurricane; you&rsquo;re due for a fall, if you catch my drift. Case in point: Terje Mathisen&rsquo;s word-counting program.</p>
<h4 align="left" id="Heading6">Blinding Yourself to a Better Approach</h4>
<h4 id="Heading6">Blinding Yourself to a Better Approach</h4>
<p>Not so long ago, Terje Mathisen, who I introduced earlier in this book, wrote a very fast word-counting program, and posted it on Bix. When I say it was fast, I mean <i>fast;</i> this code was optimized like nobody&rsquo;s business. We&rsquo;re talking top-quality code here.</p>
@ -57,7 +60,7 @@
<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&rsquo;re both the same on the 8088; in this case, though, the code was specific to the 386. In case you&rsquo;re curious, both forms take 2 cycles on the 486; quite a lot faster, eh?)</p>
<h4 align="left" id="Heading7">Watch Out for Luggable Assumptions!</h4>
<h4 id="Heading7">Watch Out for Luggable Assumptions!</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&rsquo;ve slaved over your code for a while, you&rsquo;re in no shape to see its flaws, or to be able to get the new perspectives needed to speed it up. I&rsquo;ll bet Terje looked at that <b>[EBX+EAX]</b> addressing a hundred times while trying to speed up his code, but he didn&rsquo;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>
@ -81,16 +84,20 @@
<p>The winner was David Stafford, who at the time was working for Borland International; his entry is shown in Listing 16.5. Dave Methvin, whom some of you may recall as a tech editor of the late, lamented <i>PC Tech Journal,</i> was a close second, and Mick Brown, about whom I know nothing more than that he is obviously an extremely good assembly language programmer, was a close third, as shown in Table 16.2, which precedes Listing 16.5. Those three were out ahead of the pack; the fourth-place entry, good as it was (twice as fast as my original code), was twice as slow as David&rsquo;s winning entry, so you can see that David, Dave, and Mick attained a rarefied level of optimization indeed.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="16-03.html">Previous</a></td>
<td>
<a href="16-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-05.html">Next</a></td>
<td>
<a href="16-05.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="16-04.html">Previous</a></td>
<td>
<a href="16-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-06.html">Next</a></td>
<td>
<a href="16-06.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>Table 16.2 has two times for each entry listed: the first value is the overall counting time, including time spent in the main program, disk I/O, and everything else; the second value is the time actually spent counting words, the time spent in <b>ScanBuffer</b> . The first value is the time perceived by the user, but the second value best reflects the quality of the optimization in each entry, since the rest of the overall execution time is fixed.</p>
<table width="85%">
@ -340,16 +343,20 @@ jumping.
end
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="16-04.html">Previous</a></td>
<td>
<a href="16-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-06.html">Next</a></td>
<td>
<a href="16-06.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="16-05.html">Previous</a></td>
<td>
<a href="16-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-07.html">Next</a></td>
<td>
<a href="16-07.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h3 id="Heading9">Levels of Optimization</h3>
<p>Three levels of optimization were evident in the word-counting entries I received in response to my challenge. I&rsquo;d briefly describe them as &ldquo;fine-tuning,&rdquo; &ldquo;new perspective,&rdquo; and &ldquo;table-driven state machine.&rdquo; The latter categories produce faster code, but, by the same token, they are harder to design, harder to implement, and more difficult to understand, so they&rsquo;re suitable for only the most demanding applications. (Heck, I don&rsquo;t even guarantee that David Stafford&rsquo;s entry works perfectly, although, knowing him, it probably does; the more complex and cryptic the code, the greater the chance for obscure bugs.)</p>
@ -42,7 +45,7 @@
</tr>
</table>
<h4 align="left" id="Heading10">Optimization Level 1: Good Code</h4>
<h4 id="Heading10">Optimization Level 1: Good Code</h4>
<p>The first level of optimization involves fine-tuning and clever use of the instruction set. The basic framework is still the same as my code (which in turn is basically the same as that of the original C code), but that framework is implemented more efficiently.</p>
@ -56,16 +59,20 @@
<p>Listing 16.6, contributed by Willem Clements, of Granada, Spain, illustrates a variety of level 1 optimizations: the two-loop approach, the use of a 16- rather than 32-bit counter, and the use of <b>LODSW</b> . Together, these optimizations made Willem&rsquo;s code nearly twice as fast as mine in Listing 16.4. A few details could stand improvement; for example, <b>AND AX,AX</b> is a shorter way to test for zero than <b>CMP AX,0</b> , and <b>ALIGN 2</b> could be used. Nonetheless, this is good code, and it&rsquo;s also fairly compact and reasonably easy to understand. In short, this is an excellent example of how an hour or so of hand-optimization might accomplish significantly improved performance at a reasonable cost in complexity and time. This level of optimization is adequate for most purposes (and, in truth, is beyond the abilities of most programmers).</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="16-05.html">Previous</a></td>
<td>
<a href="16-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-07.html">Next</a></td>
<td>
<a href="16-07.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="16-06.html">Previous</a></td>
<td>
<a href="16-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-08.html">Next</a></td>
<td>
<a href="16-08.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>Listing 16.6 OPT2.ASM</b></p>
<pre>
;
@ -152,16 +155,20 @@
<p><i>&ldquo;My next shot was to get rid of all the branches in the loop. To do that, I reached back to my college hardware courses. I noticed that we were really looking at an edge triggered device we want to count each time the I&rsquo;m a character state goes from one to zero. Remembering that XOR on two single-bit values will always return whether the bits are different or the same, I implemented a transition counter. The counter triggers every time a word begins or ends.&rdquo;</i></p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="16-06.html">Previous</a></td>
<td>
<a href="16-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="16-08.html">Next</a></td>
<td>
<a href="16-08.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="16-07.html">Previous</a></td>
<td>
<a href="16-07.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-01.html">Next</a></td>
<td>
<a href="17-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>Listing 16.7 L16-7.ASM</b></p>
<pre>
ScanLoop:
@ -52,7 +55,7 @@
<p>John&rsquo;s approach makes it clear that word-counting is nothing more than a fairly simple state machine. The interesting part, of course, is building the fastest state machine.</p>
<h4 align="left" id="Heading12">Level 3: Breakthrough</h4>
<h4 id="Heading12">Level 3: Breakthrough</h4>
<p>The boundaries between the levels of optimization are not sharply defined. In a sense, level 3 optimization is just like levels 1 and 2, but more so. At level 3, one takes whatever level 2 perspective seems most promising, and implements it as efficiently as possible on the x86. Even more than at level 2, at level 3 this means breaking out of familiar patterns of thinking.</p>
@ -113,22 +116,26 @@
<p>Enough said, I trust.</p>
<h4 align="left" id="Heading13">Enough Word Counting Already!</h4>
<h4 id="Heading13">Enough Word Counting Already!</h4>
<p>Before I finish up this chapter, I&rsquo;d like to mention that Terje Mathisen&rsquo;s WC word-counting program, which I&rsquo;ve mentioned previously and which is available, with source, on Bix, is in the ballpark with David&rsquo;s code for performance. What&rsquo;s more, Terje&rsquo;s program handles 8-bit ASCII, counts lines as well as words, and supports user-definable separator sets. It&rsquo;s wonderful code, well worth a look; it also happens to be a great word-counting utility. By the way, Terje builds his 64K table on the fly, at program initialization; this allows for customized tables, shrinks the size of the EXE, and, according to Terje&rsquo;s calculations, takes less time than loading the table off disk as part of the EXE.</p>
<p>So, has David written the fastest possible word-counting code? Well, maybe&mdash;but I have a letter from Terry Holmes, of San Rafael, California, that calculates the theoretical maximum performance of native 386 word-counting code at 5.5 cycles/byte, which would be significantly faster than David&rsquo;s code. Terry, alas, didn&rsquo;t bother to implement his design, but maybe I&rsquo;ll take a shot at it someday. It&rsquo;d be fun, for sure&mdash;but jeez, I&rsquo;ve got <i>real</i> work to do!</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="16-07.html">Previous</a></td>
<td>
<a href="16-07.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-01.html">Next</a></td>
<td>
<a href="17-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="16-08.html">Previous</a></td>
<td>
<a href="16-08.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-02.html">Next</a></td>
<td>
<a href="17-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 17<br />
The Game of Life</h2>
@ -47,7 +50,7 @@
<p>First, I&rsquo;ll describe the ground rules of Life, implement a very straightforward version in C<small>++</small>, and then speed that version up by about eight times without using any drastically different approaches or any assembly. This may be a little tame for some of you, but be patient; for after that, we&rsquo;ll haul out the big guns and move into the 30 to 40 times speed-up range. Then in the next chapter, I&rsquo;ll show you how several programmers <i>really</i> floored it in taking me up on my second Optimization Challenge, which involved the Game of Life.</p>
<h4 align="left" id="Heading4">The Rules of the Game</h4>
<h4 id="Heading4">The Rules of the Game</h4>
<p>The Game of Life is ridiculously simple. There is a cellmap, consisting of a rectangular matrix of cells, each of which may initially be either on or off. Each cell has eight neighbors: two horizontally, two vertically, and four diagonally. For each succeeding generation of cells, the game logic determines whether each cell will be on or off according to the following rules:</p>
@ -61,16 +64,20 @@
<p>All in all, Listing 17.1 is a clean, compact, and elegant implementation of the Game of Life. Were it not that the code is as slow as molasses, we could stop right here.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="16-08.html">Previous</a></td>
<td>
<a href="16-08.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-02.html">Next</a></td>
<td>
<a href="17-02.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="17-01.html">Previous</a></td>
<td>
<a href="17-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-03.html">Next</a></td>
<td>
<a href="17-03.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 17.1 L17-1.CPP</b></p>
<pre>
/* C++ Game of Life implementation for any mode for which mode set
@ -288,16 +291,20 @@ void show_text(int x, int y, char *text)
}
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="17-01.html">Previous</a></td>
<td>
<a href="17-01.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-03.html">Next</a></td>
<td>
<a href="17-03.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="17-02.html">Previous</a></td>
<td>
<a href="17-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-04.html">Next</a></td>
<td>
<a href="17-04.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h3 id="Heading5">Where Does the Time Go?</h3>
<p>How slow is Listing 17.1? Table 17.1 shows that even on a 486, Listing 17.1 does fewer than three 96x96 generations per second. (The times in Table 17.1 are for 1,000 generations of a 96x96 cell map with <b>seed=1, LIMIT_18_HZ=0, WRAP_EDGES=1,</b> and <b>magnifier=2,</b> running on a 33 MHz 486.) Since my target is 18 generations per second with a 200x200 cellmap on a 20 MHz 386, Listing 17.1 is too slow by a rather wide margin&mdash;75 times too slow, in fact. You might say we have a little optimizing to do.</p>
@ -182,16 +185,20 @@
<p>Having said that, let me hasten to add that algorithmic improvements can make a big difference even when working at a purely abstract level. For a large unordered data set, a high-level Quicksort will beat the pants off the best-implemented insertion sort you can imagine. Still, you can optimize your algorithm from here &rsquo;til doomsday, and if you have a fast algorithm running on top of a highly abstract programming model, you&rsquo;ll almost certainly end up with a slow program. In Listing 17.1, the abstraction that&rsquo;s killing us is that of looking at the eight neighbors with eight completely independent operations, requiring eight calls to <b>cell_state()</b> and eight calculations of cell address and cell mask. In fact, given the nature of cell storage, the eight neighbors are in a fixed relationship to one another, and the addresses and masks of all eight can generally be found very easily via hard-wired offsets and shifts once the address and mask of any one is known.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="17-02.html">Previous</a></td>
<td>
<a href="17-02.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-04.html">Next</a></td>
<td>
<a href="17-04.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="17-03.html">Previous</a></td>
<td>
<a href="17-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-05.html">Next</a></td>
<td>
<a href="17-05.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>There&rsquo;s a kicker here, though, and that&rsquo;s the counting of neighbors for cells at the edge of the cellmap. When cellmap wrapping is enabled (so that the cellmap becomes essentially a toroid, with each edge joined seamlessly to the opposite edge, as opposed to having a border of off-cells), neighbors that reside on the other edge of the cellmap can&rsquo;t be accessed by the standard fixed offset, as shown in Figure 17.1. So, in general, we could improve performance by hard-wiring our neighbor-counting for the bit-per-cell cellmap format, but it seems we&rsquo;d need a lot of conditional code to handle wrapping, and that would slow things back down again.</p>
<p><a id="Fig1"><img src="images/17-01.jpg" /><br />
@ -207,16 +210,20 @@ void cellmap::next_generation(cellmap&amp; next_map)
}
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="17-03.html">Previous</a></td>
<td>
<a href="17-03.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-05.html">Next</a></td>
<td>
<a href="17-05.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="17-04.html">Previous</a></td>
<td>
<a href="17-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-06.html">Next</a></td>
<td>
<a href="17-06.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>In Listing 17.3, note the padded cellmap edges, and the alteration of the member functions to compensate for the padding. Also note that the width now has to be a multiple of eight, to facilitate the process of copying the edges to the opposite padding bytes. We have decreased the generality of our Game of Life implementation in exchange for better performance. That&rsquo;s a very common trade-off, as common as trading memory for performance. As a rule, the more general a program is, the slower it is. A corollary is that often (not always, but often), the more heavily optimized a program is, the more complex and the more difficult to implement it is. You can often improve performance a good deal by implementing only the level of generality you need, but at the same time decreased generality makes it more difficult to change or port the program at some later date. A Game of Life implementation, such as Listing 17.1, that&rsquo;s built on <b>set_cell()</b>, <b>clear_cell()</b>, and <b>get_cell()</b> is completely general; you can change the cell storage format simply by changing the constructor and those three functions. Listing 17.3 is harder to change because <b>count_neighbors()</b> would also have to be altered, and it&rsquo;s more complex than any of the other functions.</p>
<p>So, in Listing 17.3, we&rsquo;ve gotten under the hood and changed the cellmap format a little, and gotten impressive results. But now <b>count_neighbors()</b> is hard-wired for optimized counting, and it&rsquo;s still taking up more than half the time. Maybe now it&rsquo;s time to go to assembly?</p>
@ -140,16 +143,20 @@ neighbor_count++;
</tr>
</table>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="17-04.html">Previous</a></td>
<td>
<a href="17-04.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-06.html">Next</a></td>
<td>
<a href="17-06.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="17-05.html">Previous</a></td>
<td>
<a href="17-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-07.html">Next</a></td>
<td>
<a href="17-07.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>We&rsquo;re still not ready for assembly, though; what we need is a new perspective that lends itself to vastly better performance in C<small>++</small>. The Life program in the next section is <i>three to seven times</i> faster than Listing 17.4&mdash;and it&rsquo;s still in C<small>++</small>.</p>
<p>How is this possible? Here are some hints:</p>
@ -50,7 +53,7 @@
<p>I have two objectives to achieve in the remainder of this chapter. First, I want to show that optimization consists of many levels, from assembly language up to conceptual design, and that assembly language kicks in pretty late in the optimization process. Second, I want to encourage you to saturate your brain with everything you know about any particular optimization problem, then make space for your right brain to solve the problem.</p>
<h4 align="left" id="Heading9">Re-Examining the Task</h4>
<h4 id="Heading9">Re-Examining the Task</h4>
<p>Earlier in this chapter, we looked at a straightforward Game of Life implementation, then increased performance considerably by making the implementation a little less abstract and a little less general. We made a small change to the cellmap format, adding padding bytes off the edges so that pointer arithmetic would always work, but the major optimizations were moving the critical code into a single loop and using pointers rather than member functions whenever possible. In other words, we took what we already knew and made it more efficient.</p>
@ -75,22 +78,26 @@
<p><a id="Fig3"><img src="images/17-03.jpg" /><br />
<b>Figure 17.3</b></a>&nbsp;&nbsp;<i>New cell format.</i></p>
<h4 align="left" id="Heading10">Acting on What We Know</h4>
<h4 id="Heading10">Acting on What We Know</h4>
<p>Once we&rsquo;ve changed the cellmap format to store neighbor counts as well as states, with a byte for each cell, we can get another performance boost by again examining what we know about our data. I said earlier that most cells are off during any given generation. This means that most cells have no neighbors that are on. Since the cell map representation for an off-cell that has no neighbors is a zero byte, we can skip over scads of unchanged cells at a pop simply by scanning for non-zero bytes. This is much faster than explicitly testing cell states and neighbor counts, and lends itself beautifully to assembly language implementation as <b>REPZ SCASB</b> or (with a little cleverness) <b>REPZ SCASW.</b> (Unfortunately, there&rsquo;s no C library function that can scan memory for the next byte that&rsquo;s non-zero.)</p>
<p>Listing 17.5 is a Game of Life implementation that uses the neighbor-count cell map format and scans for non-zero bytes. On a 20 MHz 386, Listing 17.5 is about 4.5 times faster at calculating generations (that is, the generation engine is 4.5 times faster; I&rsquo;m ignoring the time consumed by drawing and text display) than Listing 17.4, which is no slouch. On a 33 MHz 486, Listing 17.5 is about 3.5 times faster than Listing 17.4. This is true even though Listing 17.5 must be compiled using the large model. Imagine that&mdash;getting a four times speed-up while switching from the small model to the large model!</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="17-05.html">Previous</a></td>
<td>
<a href="17-05.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-07.html">Next</a></td>
<td>
<a href="17-07.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="17-06.html">Previous</a></td>
<td>
<a href="17-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-08.html">Next</a></td>
<td>
<a href="17-08.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p><b>LISTING 17.5 L17-5.CPP</b></p>
<pre>
/* C++ Game of Life implementation for any mode for which mode set
@ -307,16 +310,20 @@ void cellmap::init()
}
</pre>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="17-06.html">Previous</a></td>
<td>
<a href="17-06.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="17-08.html">Next</a></td>
<td>
<a href="17-08.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="17-07.html">Previous</a></td>
<td>
<a href="17-07.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="18-01.html">Next</a></td>
<td>
<a href="18-01.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<p>The large model is actually not necessary for the 96x96 cellmap in Listing 17.5. However, I was actually more interested in seeing a fast 200x200 cellmap, and two 200x200 cellmaps can&rsquo;t fit in a single segment. (This can easily be worked around in assembly language for cellmaps up to a segment in size; beyond that size, cellmap scanning becomes pretty complex, although it can still be efficiently implemented with some clever programming.)</p>
<p>Anyway, using the large model helps illustrate that it&rsquo;s the data representation and the data processing approach you choose that matter most. Optimization details like memory models and segments and in-line functions and assembly language are important but secondary. Let your mind roam creatively before you start coding. Otherwise, you may find you&rsquo;re writing well-tuned slow code, which is by no means the same thing as fast code.</p>
@ -48,7 +51,7 @@
<p>No doubt we could get another two to five times improvement with good assembly code&mdash;but that&rsquo;s dwarfed by a 30-times improvement, so optimization at a conceptual level <i>must</i> come first.</p>
<h4 align="left" id="Heading11">The Challenge That Ate My Life</h4>
<h4 id="Heading11">The Challenge That Ate My Life</h4>
<p>The most recent optimization challenge I laid my community of readers was to write the fastest possible Game of Life generation engine. By &ldquo;engine&rdquo; I meant that I didn&rsquo;t care about time spent in input or output, only time consumed by the call to <b>next-generation.</b> The time spent updating the cellmap was what I wanted people to concentrate on.</p>
@ -72,16 +75,20 @@
<p>Who won? What did I learn? To find out, read on.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="17-07.html">Previous</a></td>
<td>
<a href="17-07.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="18-01.html">Next</a></td>
<td>
<a href="18-01.html">Next</a>
</td>
</tr>
</table>
</center>

View file

@ -1,5 +1,4 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@ -19,17 +18,21 @@
<center>
<table border="1">
<tr>
<td><a href="17-08.html">Previous</a></td>
<td>
<a href="17-08.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="18-02.html">Next</a></td>
<td>
<a href="18-02.html">Next</a>
</td>
</tr>
</table>
</center>
<p><br /></p>
<h2 id="Heading1">Chapter 18<br />
It&rsquo;s a plain Wonderful Life</h2>
@ -63,16 +66,20 @@
<p>Onward to the code.</p>
<p><br /></p>
<center>
<table border="1">
<tr>
<td><a href="17-08.html">Previous</a></td>
<td>
<a href="17-08.html">Previous</a>
</td>
<td><a href="index.html">Table of Contents</a></td>
<td>
<a href="index.html">Table of Contents</a>
</td>
<td><a href="18-02.html">Next</a></td>
<td>
<a href="18-02.html">Next</a>
</td>
</tr>
</table>
</center>

Some files were not shown because too many files have changed in this diff Show more