Remove navigation and footer from each page

This commit is contained in:
James Gregory 2013-12-30 20:26:41 +11:00
commit efd73dca38
362 changed files with 80 additions and 4419 deletions

View file

@ -1,7 +1,3 @@
------------------------------- --------------------------------- --------------------
[Previous](about_author.html) [Table of Contents](index.html) [Next](01-02.html)
------------------------------- --------------------------------- --------------------
*Part I* {align="center"}
--------
@ -114,12 +110,4 @@ with just a little thought. As we'll see, handcrafted assembly language
and optimizing compilers matter, but less than you might think, in the
grand scheme of things—and they scarcely matter at all unless they're
used in the context of a good design and a thorough understanding of
both the task at hand and the PC.
------------------------------- --------------------------------- --------------------
[Previous](about_author.html) [Table of Contents](index.html) [Next](01-02.html)
------------------------------- --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
both the task at hand and the PC.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](01-01.html) [Table of Contents](index.html) [Next](01-03.html)
------------------------ --------------------------------- --------------------
### Rules for Building High-Performance Code {#Heading5}
We've got the following rules for creating high-performance software:
@ -135,12 +131,4 @@ 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's less than 10 percent faster, and it's still
unacceptably slow.
------------------------ --------------------------------- --------------------
[Previous](01-01.html) [Table of Contents](index.html) [Next](01-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
unacceptably slow.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](01-02.html) [Table of Contents](index.html) [Next](01-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Listing
@ -251,12 +247,4 @@ Listing 1.1, *even though Listing 1.1 and Listing 1.4 look almost the
same*. To the casual observer, **read()** and **getc()** 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.
------------------------ --------------------------------- --------------------
[Previous](01-02.html) [Table of Contents](index.html) [Next](01-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
as that between a 4.77 MHz PC and a 16 MHz 386.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](01-03.html) [Table of Contents](index.html) [Next](01-05.html)
------------------------ --------------------------------- --------------------
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *Make sure you understand what really goes on when you insert a seemingly-innocuous function call into the time-critical portions of your code.*
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------
@ -116,12 +112,4 @@ does *not* run fast enough—13 seconds is a long time. (Stop and wait for
long it is.)
The second reason is the hallmark of the mediocre programmer. Know when
optimization matters—and then optimize when it does!
------------------------ --------------------------------- --------------------
[Previous](01-03.html) [Table of Contents](index.html) [Next](01-05.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
optimization matters—and then optimize when it does!

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](01-04.html) [Table of Contents](index.html) [Next](01-06.html)
------------------------ --------------------------------- --------------------
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're often written for *portability*, which has nothing to
@ -164,11 +160,3 @@ the design has been maxed out.
printf("The checksum is: %u\n", Checksum);
exit(0);
}
------------------------ --------------------------------- --------------------
[Previous](01-04.html) [Table of Contents](index.html) [Next](01-06.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](01-05.html) [Table of Contents](index.html) [Next](02-01.html)
------------------------ --------------------------------- --------------------
**LISTING 1.7 L1-7.ASM**
; Assembler subroutine to perform a 16-bit checksum on a block of
@ -110,12 +106,4 @@ be sped up.
I'm going to focus on specific ways to create high-performance code from
now on. In Chapter 5, we'll continue to look at restartable blocks and
internal buffering, in the form of a program that searches files for
text strings.
------------------------ --------------------------------- --------------------
[Previous](01-05.html) [Table of Contents](index.html) [Next](02-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
text strings.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](01-06.html) [Table of Contents](index.html) [Next](02-02.html)
------------------------ --------------------------------- --------------------
Chapter 2\
A World Apart {#Heading1}
--------------
@ -102,12 +98,4 @@ 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.
------------------------ --------------------------------- --------------------
[Previous](01-06.html) [Table of Contents](index.html) [Next](02-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
program.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](02-01.html) [Table of Contents](index.html) [Next](02-03.html)
------------------------ --------------------------------- --------------------
#### Transformation Inefficiencies {#Heading5}
No matter how well an implementation is derived from the corresponding
@ -101,12 +97,4 @@ out such knowledge.
------------------- ------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *Be forewarned, though: No matter how much you learn about programming the PC in assembly, there's always more to discover.*
------------------- ------------------------------------------------------------------------------------------------------------------------------
------------------------ --------------------------------- --------------------
[Previous](02-01.html) [Table of Contents](index.html) [Next](02-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
------------------- ------------------------------------------------------------------------------------------------------------------------------

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](02-02.html) [Table of Contents](index.html) [Next](03-01.html)
------------------------ --------------------------------- --------------------
### The Flexible Mind {#Heading8}
Is the never-ending collection of information all there is to the
@ -110,12 +106,4 @@ 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.
------------------------ --------------------------------- --------------------
[Previous](02-02.html) [Table of Contents](index.html) [Next](03-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
learning how to learn.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](02-03.html) [Table of Contents](index.html) [Next](03-02.html)
------------------------ --------------------------------- --------------------
Chapter 3\
Assume Nothing {#Heading1}
---------------
@ -101,12 +97,4 @@ Listing 3.1 shows 8253-based timer software, consisting of three
subroutines: **ZTimerOn, ZTimerOff**, and **ZTimerReport**. For the
remainder of this book, I'll refer to these routines collectively as the
"Zen timer." C-callable versions of the two precision Zen timers are
presented in Chapter K on the companion CD-ROM.
------------------------ --------------------------------- --------------------
[Previous](02-03.html) [Table of Contents](index.html) [Next](03-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
presented in Chapter K on the companion CD-ROM.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](03-01.html) [Table of Contents](index.html) [Next](03-03.html)
------------------------ --------------------------------- --------------------
**LISTING 3.1 PZTIMER.ASM**
; The precision Zen timer (PZTIMER.ASM)
@ -443,11 +439,3 @@
Code ends
end
------------------------ --------------------------------- --------------------
[Previous](03-01.html) [Table of Contents](index.html) [Next](03-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](03-02.html) [Table of Contents](index.html) [Next](03-04.html)
------------------------ --------------------------------- --------------------
#### The Zen Timer Is a Means, Not an End {#Heading5}
We're going to spend the rest of this chapter seeing what the Zen timer
@ -127,12 +123,4 @@ generate an interrupt; in fact, timer 2 can'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.
------------------------ --------------------------------- --------------------
[Previous](03-02.html) [Table of Contents](index.html) [Next](03-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
the Zen timer shown in Listing 3.1 supports.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](03-03.html) [Table of Contents](index.html) [Next](03-05.html)
------------------------ --------------------------------- --------------------
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.
@ -145,12 +141,4 @@ David Miller for passing the idea on to me.)
You may well want to devise still other approaches better suited to your
needs than those I've presented. Go to it! I've just thrown out a few
possibilities to get you started.
------------------------ --------------------------------- --------------------
[Previous](03-03.html) [Table of Contents](index.html) [Next](03-05.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
possibilities to get you started.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](03-04.html) [Table of Contents](index.html) [Next](03-06.html)
------------------------ --------------------------------- --------------------
### Notes on the Zen Timer {#Heading10}
The Zen timer subroutines are designed to be near-called from assembly
@ -160,12 +156,4 @@ execution time of start-up code in the timing interval. That's why the
calls to **ZTimerOn** and **ZTimerOff** 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.
------------------------ --------------------------------- --------------------
[Previous](03-04.html) [Table of Contents](index.html) [Next](03-06.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
timing interval.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](03-05.html) [Table of Contents](index.html) [Next](03-07.html)
------------------------ --------------------------------- --------------------
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
@ -156,12 +152,4 @@ 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.
------------------------ --------------------------------- --------------------
[Previous](03-05.html) [Table of Contents](index.html) [Next](03-07.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
precision Zen timer.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](03-06.html) [Table of Contents](index.html) [Next](03-08.html)
------------------------ --------------------------------- --------------------
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
@ -704,11 +700,3 @@ computers.
Code ends
end
------------------------ --------------------------------- --------------------
[Previous](03-06.html) [Table of Contents](index.html) [Next](03-08.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](03-07.html) [Table of Contents](index.html) [Next](03-09.html)
------------------------ --------------------------------- --------------------
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's operation until the next reboot.
@ -128,12 +124,4 @@ 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.
------------------------ --------------------------------- --------------------
[Previous](03-07.html) [Table of Contents](index.html) [Next](03-09.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
the file LZTEST.ASM contains Listing 3.6.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](03-08.html) [Table of Contents](index.html) [Next](03-10.html)
------------------------ --------------------------------- --------------------
**LISTING 3.7 LZTIME.BAT**
echo off
@ -140,11 +136,3 @@ code to use C-style external label names and the small model C code
segment. (In C++, use the "C" specifier, as in
extern "C" ZTimerOn(void);
------------------------ --------------------------------- --------------------
[Previous](03-08.html) [Table of Contents](index.html) [Next](03-10.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](03-09.html) [Table of Contents](index.html) [Next](04-01.html)
------------------------ --------------------------------- --------------------
when declaring the timer routines **extern**, so that name-mangling
doesn't occur, and the linker can find the routines' C-style names.)
@ -124,12 +120,4 @@ periods.
Imperfections notwithstanding, the Zen timer is a good tool for
exploring C code and x86 family assembly language, and it's a tool we'll
use frequently for the remainder of this book.
------------------------ --------------------------------- --------------------
[Previous](03-09.html) [Table of Contents](index.html) [Next](04-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
use frequently for the remainder of this book.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](03-10.html) [Table of Contents](index.html) [Next](04-02.html)
------------------------ --------------------------------- --------------------
Chapter 4\
In the Lair of the Cycle-Eaters {#Heading1}
--------------------------------
@ -150,12 +146,4 @@ 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.
------------------------ --------------------------------- --------------------
[Previous](03-10.html) [Table of Contents](index.html) [Next](04-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
8088 was designed.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](04-01.html) [Table of Contents](index.html) [Next](04-03.html)
------------------------ --------------------------------- --------------------
![](images/04-01.jpg)\
**Figure 4.1**  *The location of the major cycle-eaters in the IBM PC.*
@ -154,12 +150,4 @@ 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.
------------------------ --------------------------------- --------------------
[Previous](04-01.html) [Table of Contents](index.html) [Next](04-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
assembly optimization.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](04-02.html) [Table of Contents](index.html) [Next](04-04.html)
------------------------ --------------------------------- --------------------
Back to the 8-bit bus cycle-eater. As I've said, in 8088 work you should
strive to use byte-sized memory variables whenever possible. That does
*not* mean that you should use 2 byte-sized memory accesses to
@ -157,12 +153,4 @@ how long it will take that instruction to reach the prefetch queue if
it's not there already. Thanks to the low performance of the 8088's
external data bus, that's a glaring omission—but, alas, an unavoidable
one. Let's look at why the official execution times are wrong, and why
that can't be helped.
------------------------ --------------------------------- --------------------
[Previous](04-02.html) [Table of Contents](index.html) [Next](04-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
that can't be helped.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](04-03.html) [Table of Contents](index.html) [Next](04-05.html)
------------------------ --------------------------------- --------------------
#### Official Execution Times Are Only Part of the Story {#Heading10}
The sequence of 5 **SHR** instructions in the last example is 10 bytes
@ -147,12 +143,4 @@ instructions which have sucked the prefetch queue dry, so overall
performance reflects instruction fetch time. By contrast, each **SHR**
in Listing 4.6 follows a **MUL** instruction which leaves the prefetch
queue full, so overall performance reflects Execution Unit execution
time.
------------------------ --------------------------------- --------------------
[Previous](04-03.html) [Table of Contents](index.html) [Next](04-05.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
time.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](04-04.html) [Table of Contents](index.html) [Next](04-06.html)
------------------------ --------------------------------- --------------------
Clearly, either instruction fetch time *or* Execution Unit execution
time—or even a mix of the two, if an instruction is partially
prefetched—can determine code performance. Some people operate under a
@ -145,12 +141,4 @@ 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—just don't
expect them to run at their "official" documented speeds.
------------------------ --------------------------------- --------------------
[Previous](04-04.html) [Table of Contents](index.html) [Next](04-06.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
expect them to run at their "official" documented speeds.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](04-05.html) [Table of Contents](index.html) [Next](04-07.html)
------------------------ --------------------------------- --------------------
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't perform memory accesses to read or write operands.
@ -128,12 +124,4 @@ occupies cycles during which the 8088 would otherwise be accessing
memory.
![](images/04-05.jpg)\
**Figure 4.5**  *The PC bus dynamic RAM (DRAM) refresh.*
------------------------ --------------------------------- --------------------
[Previous](04-05.html) [Table of Contents](index.html) [Next](04-07.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
**Figure 4.5**  *The PC bus dynamic RAM (DRAM) refresh.*

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](04-06.html) [Table of Contents](index.html) [Next](04-08.html)
------------------------ --------------------------------- --------------------
#### The Impact of DRAM Refresh {#Heading17}
Let's look at examples from opposite ends of the spectrum in terms of
@ -143,12 +139,4 @@ Wait states are cycles during which a bus access by the CPU to a device
on the PC'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)—even DMA accesses—can be affected by wait states.
------------------------ --------------------------------- --------------------
[Previous](04-06.html) [Table of Contents](index.html) [Next](04-08.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
will discuss)—even DMA accesses—can be affected by wait states.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](04-07.html) [Table of Contents](index.html) [Next](04-09.html)
------------------------ --------------------------------- --------------------
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—a memory or I/O read or write—in 4 cycles,
@ -134,12 +130,4 @@ the 8088's already-poor memory access performance in half. Running your
code from display memory is sort of like running on a hypothetical
8084—an 8086 with a *4-bit* 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?
------------------------ --------------------------------- --------------------
[Previous](04-07.html) [Table of Contents](index.html) [Next](04-09.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
an impact does the display adapter cycle-eater have on performance?

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](04-08.html) [Table of Contents](index.html) [Next](04-10.html)
------------------------ --------------------------------- --------------------
The answer varies considerably depending on what display adapter and
what display mode we're talking about. The display adapter cycle-eater
is worst with the Enhanced Graphics Adapter (EGA) and the original Video
@ -138,12 +134,4 @@ cycle-eater can *more than double* the execution time of 8088 code!
Bear in mind that we'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.
------------------------ --------------------------------- --------------------
[Previous](04-08.html) [Table of Contents](index.html) [Next](04-10.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
given code sequence spends accessing display memory.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](04-09.html) [Table of Contents](index.html) [Next](05-01.html)
------------------------ --------------------------------- --------------------
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *A line-drawing subroutine, which executes perhaps a dozen instructions for each display memory access, generally loses less performance to the display adapter cycle-eater than does a block-copy or scrolling subroutine that uses **REP MOVS** instructions. Scaled and three-dimensional graphics, which spend a great deal of time performing calculations (often using very slow floating-point arithmetic), tend to suffer less.*
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -118,12 +114,4 @@ 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'll see again and again in later
chapters.
------------------------ --------------------------------- --------------------
[Previous](04-09.html) [Table of Contents](index.html) [Next](05-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
chapters.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](04-10.html) [Table of Contents](index.html) [Next](05-02.html)
------------------------ --------------------------------- --------------------
Chapter 5\
Crossing the Border {#Heading1}
--------------------
@ -112,12 +108,4 @@ for the first occurrence of a second string. However, while **strstr()**
would work, it isn'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, **strstr()** searches a *string* for the first occurrence of
another string.
------------------------ --------------------------------- --------------------
[Previous](04-10.html) [Table of Contents](index.html) [Next](05-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
another string.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](05-01.html) [Table of Contents](index.html) [Next](05-03.html)
------------------------ --------------------------------- --------------------
We could put a zero byte at the end of our buffer to allow **strstr()**
to work, but why bother? The **strstr()** function must spend time
either checking for the end of the string being searched or determining
@ -115,12 +111,4 @@ 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—which is to say
at top speed—and make your blocks as large as possible in order to
minimize the overhead associated with going from one block to the next.
------------------------ --------------------------------- --------------------
[Previous](05-01.html) [Table of Contents](index.html) [Next](05-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
minimize the overhead associated with going from one block to the next.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](05-02.html) [Table of Contents](index.html) [Next](05-04.html)
------------------------ --------------------------------- --------------------
**LISTING 5.1 SEARCH.C**
/* Program to search the file specified by the first command-line
@ -169,11 +165,3 @@
exit(Found); /* Return the found/not found status as the
DOS errorlevel */
}
------------------------ --------------------------------- --------------------
[Previous](05-02.html) [Table of Contents](index.html) [Next](05-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](05-03.html) [Table of Contents](index.html) [Next](05-05.html)
------------------------ --------------------------------- --------------------
### Interpreting Where the Cycles Go {#Heading8}
To boost the overall performance of Listing 5.1, I would normally
@ -76,12 +72,4 @@ Likewise, assembly can switch back to **REPNZ SCASB** 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
"zy," Listing 5.1 takes almost 1/2 minute, or nearly an order of
magnitude longer than when searching a file filled with normal text.
------------------------ --------------------------------- --------------------
[Previous](05-03.html) [Table of Contents](index.html) [Next](05-05.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
magnitude longer than when searching a file filled with normal text.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](05-04.html) [Table of Contents](index.html) [Next](06-01.html)
------------------------ --------------------------------- --------------------
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
@ -67,12 +63,4 @@ itself with greatly improved performance. And when speed is *not* an
issue, of course, or in code that's not time-critical, you wouldn't
dream of wasting your time on optimization.
Would you?
------------------------ --------------------------------- --------------------
[Previous](05-04.html) [Table of Contents](index.html) [Next](06-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
Would you?

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](05-05.html) [Table of Contents](index.html) [Next](06-02.html)
------------------------ --------------------------------- --------------------
Chapter 6\
Looking Past Face Value {#Heading1}
------------------------
@ -120,11 +116,3 @@ Or you could let the processor do the arithmetic for you in a single
instruction:
mov al,[bx+si]
------------------------ --------------------------------- --------------------
[Previous](05-05.html) [Table of Contents](index.html) [Next](06-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](06-01.html) [Table of Contents](index.html) [Next](07-01.html)
------------------------ --------------------------------- --------------------
The two approaches are functionally interchangeable but *not* equivalent
from a performance standpoint, and which is better depends on the
particular context. If it's a one-shot memory access, it's best to let
@ -173,12 +169,4 @@ cycles is a pretty neat trick, even though it works only on a 386 or
I'd like to extend my thanks to Duane Strong of Metagraphics for his
help in brainstorming uses for the 386 version of **LEA** and for
pointing out the complications of 486 instruction timings.
------------------------ --------------------------------- --------------------
[Previous](06-01.html) [Table of Contents](index.html) [Next](07-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
pointing out the complications of 486 instruction timings.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](06-02.html) [Table of Contents](index.html) [Next](07-02.html)
------------------------ --------------------------------- --------------------
Chapter 7\
Local Optimization {#Heading1}
-------------------
@ -111,12 +107,4 @@ the relative performances of **LOOP** and **DEC CX/JNZ** on a cached
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *Things are stranger still for **LOOP**'s relative **JCXZ,** which branches if and only if CX is zero. **JCXZ** is faster than **AND CX,CX/JZ** on the 8088 and 80286, and equivalent on the 80386—but is about twice as slow on the 486!*
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------ --------------------------------- --------------------
[Previous](06-02.html) [Table of Contents](index.html) [Next](07-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](07-01.html) [Table of Contents](index.html) [Next](07-03.html)
------------------------ --------------------------------- --------------------
By the way, don't fall victim to the lures of **JCXZ** and do something
like this:
@ -99,12 +95,4 @@ most that counting cycles could buy us in this case. (All right,
already; **LOOPNZ** could be used at the bottom of the loop, and other
optimizations are surely possible, but all that won't add up to anywhere
near the benefits we're about to see from local optimization, and that's
the whole point.)
------------------------ --------------------------------- --------------------
[Previous](07-01.html) [Table of Contents](index.html) [Next](07-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
the whole point.)

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](07-02.html) [Table of Contents](index.html) [Next](07-04.html)
------------------------ --------------------------------- --------------------
**LISTING 7.1 L7-1.ASM**
; Program to illustrate searching through a buffer of a specified
@ -104,12 +100,4 @@ that three-quarters of the **LOOP**s are eliminated. Listings 7.1 and
7.2 perform exactly the same task, and they use the same instructions in
the loop—the searching algorithm hasn't changed in any way—but we have
sequenced the instructions differently in Listing 7.2, and that makes
all the difference.
------------------------ --------------------------------- --------------------
[Previous](07-02.html) [Table of Contents](index.html) [Next](07-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
all the difference.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](07-03.html) [Table of Contents](index.html) [Next](07-05.html)
------------------------ --------------------------------- --------------------
**LISTING 7.2 L7-2.ASM**
; Program to illustrate searching through a buffer of a specified
@ -145,12 +141,4 @@ avenues.
------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *The point is simply this: You can gain far more by stepping back a bit and thinking of the fastest overall way for the CPU to perform a task than you can by saving a cycle here or there using different instructions. Try to think at the level of sequences of instructions rather than individual instructions, and learn to treat x86 instructions as building blocks with unique characteristics rather than as instructions dedicated to specific tasks.*
------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------ --------------------------------- --------------------
[Previous](07-03.html) [Table of Contents](index.html) [Next](07-05.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](07-04.html) [Table of Contents](index.html) [Next](08-01.html)
------------------------ --------------------------------- --------------------
#### Rotating and Shifting with Tables {#Heading8}
As another example of local optimization, consider the matter of
@ -175,12 +171,4 @@ the following:
ADD AX,1
ADC DX,0
As always, pay attention!
------------------------ --------------------------------- --------------------
[Previous](07-04.html) [Table of Contents](index.html) [Next](08-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
As always, pay attention!

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](07-05.html) [Table of Contents](index.html) [Next](08-02.html)
------------------------ --------------------------------- --------------------
Chapter 8\
Speeding Up C with Assembly Language {#Heading1}
-------------------------------------
@ -114,12 +110,4 @@ 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't affect performance, then the code they're
in probably isn't critical, and perhaps you've chosen to convert too
much code to assembly, eh?
------------------------ --------------------------------- --------------------
[Previous](07-05.html) [Table of Contents](index.html) [Next](08-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
much code to assembly, eh?

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](08-01.html) [Table of Contents](index.html) [Next](08-03.html)
------------------------ --------------------------------- --------------------
### Stack Frames Slow So Much {#Heading5}
C compilers work within the stack frame model, whereby variables reside
@ -130,12 +126,4 @@ Listing 8.1 is the sample C application I'm going to use to examine
optimization in action. Listing 8.1 isn't really complete—it doesn't
handle the "no-matches" case well, and it assumes that the sum of all
matches will fit into an **int—**but it will do just fine as an
optimization example.
------------------------ --------------------------------- --------------------
[Previous](08-01.html) [Table of Contents](index.html) [Next](08-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
optimization example.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](08-02.html) [Table of Contents](index.html) [Next](08-04.html)
------------------------ --------------------------------- --------------------
**LISTING 8.1 L8-1.C**
/* Program to search an array spanning a linked list of variable-
@ -176,11 +172,3 @@ instruction can be used.
mov WORD PTR [bp-2],di ;IDMatchSum
mov WORD PTR [bp-4],dx ;IDMatchCount
$FB264:
------------------------ --------------------------------- --------------------
[Previous](08-02.html) [Table of Contents](index.html) [Next](08-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](08-03.html) [Table of Contents](index.html) [Next](08-05.html)
------------------------ --------------------------------- --------------------
It'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
**FindIDAverage** that was produced by looking at the assembly output of
@ -219,11 +215,3 @@ but not a tremendous return for the optimization effort invested.
ret
_FindIDAverage ENDP
end
------------------------ --------------------------------- --------------------
[Previous](08-03.html) [Table of Contents](index.html) [Next](08-05.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](08-04.html) [Table of Contents](index.html) [Next](09-01.html)
------------------------ --------------------------------- --------------------
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
@ -173,12 +169,4 @@ 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—and your code will never again be confused with anything by
Hamilton, Joe, Frank, eynolds or Bo Donaldson and the Heywoods.
------------------------ --------------------------------- --------------------
[Previous](08-04.html) [Table of Contents](index.html) [Next](09-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
Hamilton, Joe, Frank, eynolds or Bo Donaldson and the Heywoods.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](08-05.html) [Table of Contents](index.html) [Next](09-02.html)
------------------------ --------------------------------- --------------------
Chapter 9\
Hints My Readers Gave Me {#Heading1}
-------------------------
@ -171,11 +167,3 @@ above is faster than this:
JNC CopyDone ;done if even copy length
MOVSB ;copy the odd byte
CopyDone:
------------------------ --------------------------------- --------------------
[Previous](08-05.html) [Table of Contents](index.html) [Next](09-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](09-01.html) [Table of Contents](index.html) [Next](09-03.html)
------------------------ --------------------------------- --------------------
However, it generally is. Sure, if the length is odd, John's approach
incurs a penalty approximately equal to the **REP** startup time for
**MOVSB**. However, if the length is even, John's approach doesn't
@ -130,12 +126,4 @@ my approach, you'd use **REPNZ SCASB** to scan for each occurrence of
would make more sense to scan for "Q," then back up one character and
check the whole string when a "Q" is found, as shown in Figure 9.2. "Q"
is likely to occur much less often, resulting in many fewer whole-string
checks and much faster processing.
------------------------ --------------------------------- --------------------
[Previous](09-01.html) [Table of Contents](index.html) [Next](09-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
checks and much faster processing.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](09-02.html) [Table of Contents](index.html) [Next](09-04.html)
------------------------ --------------------------------- --------------------
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
@ -123,11 +119,3 @@ using **REPZ CMPS** to check scanning matches.
ret
_FindStringendp
end
------------------------ --------------------------------- --------------------
[Previous](09-02.html) [Table of Contents](index.html) [Next](09-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](09-03.html) [Table of Contents](index.html) [Next](09-05.html)
------------------------ --------------------------------- --------------------
**LISTING 9.2 L9-2.ASM**
; Searches a text buffer for a text string. Uses REPNZ SCASB to scan
@ -135,11 +131,3 @@
strncpy(TempBuffer, MatchPtr, DISPLAY_LENGTH));
}
}
------------------------ --------------------------------- --------------------
[Previous](09-03.html) [Table of Contents](index.html) [Next](09-05.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](09-04.html) [Table of Contents](index.html) [Next](09-06.html)
------------------------ --------------------------------- --------------------
You'll notice that in Listing 9.2 I didn'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
@ -111,12 +107,4 @@ 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 **IDIV**, for example; if you know of
one, drop me a line c/o Coriolis Group Books.
------------------------ --------------------------------- --------------------
[Previous](09-04.html) [Table of Contents](index.html) [Next](09-06.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
one, drop me a line c/o Coriolis Group Books.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](09-05.html) [Table of Contents](index.html) [Next](09-07.html)
------------------------ --------------------------------- --------------------
**LISTING 9.5 L9-5.ASM**
; Divides an arbitrarily long unsigned dividend by a 16-bit unsigned
@ -130,12 +126,4 @@ 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—not bad, when you consider that the "sweet
spot" optimization is essentially free, with no code reorganization,
change in logic, or heavy thinking involved.
------------------------ --------------------------------- --------------------
[Previous](09-05.html) [Table of Contents](index.html) [Next](09-07.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
change in logic, or heavy thinking involved.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](09-06.html) [Table of Contents](index.html) [Next](10-01.html)
------------------------ --------------------------------- --------------------
#### Hard-Core Cycle Counting {#Heading10}
Next, we come to an item that cycle counters will love, especially since
@ -140,12 +136,4 @@ Be warned, though, that I've found **OR, AND, ADD**, and the like to be
a cycle slower than **MOV** 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.
------------------------ --------------------------------- --------------------
[Previous](09-06.html) [Table of Contents](index.html) [Next](10-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
action, and place not your trust in documented cycle times.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](09-07.html) [Table of Contents](index.html) [Next](10-02.html)
------------------------ --------------------------------- --------------------
Chapter 10\
Patient Coding, Faster Code {#Heading1}
----------------------------
@ -126,12 +122,4 @@ Eratosthenes (we'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's attention gets diverted to other important
matters, such as how far a paper airplane will fly from a second-story
window.
------------------------ --------------------------------- --------------------
[Previous](09-07.html) [Table of Contents](index.html) [Next](10-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
window.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](10-01.html) [Table of Contents](index.html) [Next](10-03.html)
------------------------ --------------------------------- --------------------
Not so nowadays, though. Computers love boring work; they're very
patient and disciplined, and, besides, one human year = seven dog years
= two zillion computer years. So when we're faced with a problem that
@ -239,11 +235,3 @@ in Listing 10.2.
/* Now recursively call this function to continue the process */
return(gcd(int1, int2));
}
------------------------ --------------------------------- --------------------
[Previous](10-01.html) [Table of Contents](index.html) [Next](10-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](10-02.html) [Table of Contents](index.html) [Next](10-04.html)
------------------------ --------------------------------- --------------------
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's the GCD;
alternatively, if iL becomes *less* than iS, iL and iS switch values,
@ -160,12 +156,4 @@ Microsoft C/C++'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—but the gains are small compared to those realized from the
higher-level optimizations in Listings 10.2 through 10.4.
------------------------ --------------------------------- --------------------
[Previous](10-02.html) [Table of Contents](index.html) [Next](10-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
higher-level optimizations in Listings 10.2 through 10.4.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](10-03.html) [Table of Contents](index.html) [Next](11-01.html)
------------------------ --------------------------------- --------------------
**LISTING 10.5 L10-5.ASM**
; Finds and returns the greatest common divisor of two integers.
@ -129,12 +125,4 @@ breakthroughs. Stop, look, listen—and think. Not only will you find that
it's a more productive and creative way to program—but you'll also find
that it's more fun.
And think what you could do with all those extra computer years!
------------------------ --------------------------------- --------------------
[Previous](10-03.html) [Table of Contents](index.html) [Next](11-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
And think what you could do with all those extra computer years!

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](10-04.html) [Table of Contents](index.html) [Next](11-02.html)
------------------------ --------------------------------- --------------------
Chapter 11\
Pushing the 286 and 386 {#Heading1}
------------------------
@ -142,12 +138,4 @@ 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'll see shortly. On the other hand, access to byte-sized
variables still isn't any *slower* than access to word-sized variables,
so you can use whichever size suits a given task best.
------------------------ --------------------------------- --------------------
[Previous](10-04.html) [Table of Contents](index.html) [Next](11-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
so you can use whichever size suits a given task best.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](11-01.html) [Table of Contents](index.html) [Next](11-03.html)
------------------------ --------------------------------- --------------------
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.
@ -142,12 +138,4 @@ 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 *should* 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.
------------------------ --------------------------------- --------------------
[Previous](11-01.html) [Table of Contents](index.html) [Next](11-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
is reduced to 1 word every 300 ns by the one-wait-state memory.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](11-02.html) [Table of Contents](index.html) [Next](11-04.html)
------------------------ --------------------------------- --------------------
In short, a close relative of our old friend the 8-bit bus
cycle-eater—the system memory wait state cycle-eater—haunts us still on
all but zero-wait-state 286 and 386 computers, and that means that the
@ -165,12 +161,4 @@ 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'd be
surprised at what it can do to tight loops; in fact, a brief story is in
order.
------------------------ --------------------------------- --------------------
[Previous](11-02.html) [Table of Contents](index.html) [Next](11-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
order.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](11-03.html) [Table of Contents](index.html) [Next](11-05.html)
------------------------ --------------------------------- --------------------
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
@ -158,12 +154,4 @@ display adapter such as a standard VGA is reasonably well-matched to an
8088's memory access speed. Granted, access to a VGA slows the 8088 down
considerably—but, as we're about to find out, "considerably" is a
relative term. What a VGA does to PC performance is nothing compared to
what it does to faster computers.
------------------------ --------------------------------- --------------------
[Previous](11-03.html) [Table of Contents](index.html) [Next](11-05.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
what it does to faster computers.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](11-04.html) [Table of Contents](index.html) [Next](11-06.html)
------------------------ --------------------------------- --------------------
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 **REP MOVSW**, dwarfing the 1 byte every 1.31 µs that
@ -133,12 +129,4 @@ of simple instructions on the 486 and especially on the Pentium.) What's
more, both old and new instructions support 32-bit operations on the
386. For example, it's relatively simple to copy data in chunks of 4
bytes on a 386, even in real mode, by using the **MOVSD** ("move string
double") instruction, or to negate a 32-bit value with **NEG eax**.
------------------------ --------------------------------- --------------------
[Previous](11-04.html) [Table of Contents](index.html) [Next](11-06.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
double") instruction, or to negate a 32-bit value with **NEG eax**.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](11-05.html) [Table of Contents](index.html) [Next](11-07.html)
------------------------ --------------------------------- --------------------
Finally, it's possible in real mode to use the 386's new addressing
modes, in which *any* 32-bit general-purpose register or pair of
registers can be used to address memory. What's more, multiplication of
@ -116,11 +112,3 @@ Theory confirmed.
add dx,100h
endm
call ZTimerOff
------------------------ --------------------------------- --------------------
[Previous](11-05.html) [Table of Contents](index.html) [Next](11-07.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](11-06.html) [Table of Contents](index.html) [Next](11-08.html)
------------------------ --------------------------------- --------------------
**LISTING 11.5 L11-5.ASM**
;
@ -100,12 +96,4 @@ purpose, and didn't intentionally provide any alternative approach, so
we'll have to devise an alternative approach of our own. To do that,
we'll have to search for instructions that contain some of the same
functionality as **POPF**, in the hope that one of those instructions
can be used in some way to replace **POPF**.
------------------------ --------------------------------- --------------------
[Previous](11-06.html) [Table of Contents](index.html) [Next](11-08.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
can be used in some way to replace **POPF**.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](11-07.html) [Table of Contents](index.html) [Next](12-01.html)
------------------------ --------------------------------- --------------------
Well, there's only one instruction other than **POPF** that loads the
FLAGS register directly from the stack, and that's **IRET**, which loads
the FLAGS register from the stack as it branches, as shown in Figure
@ -112,12 +108,4 @@ it occurs.)
And now you know the nature of and the workaround for the **POPF** bug.
Whether you ever need the workaround or not, it's a neatly packaged
example of the tremendous flexibility of the x86 instruction set.
------------------------ --------------------------------- --------------------
[Previous](11-07.html) [Table of Contents](index.html) [Next](12-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
example of the tremendous flexibility of the x86 instruction set.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](11-08.html) [Table of Contents](index.html) [Next](12-02.html)
------------------------ --------------------------------- --------------------
Chapter 12\
Pushing the 486 {#Heading1}
----------------
@ -129,11 +125,3 @@ with this
dec cx
jnz LoopTop
sub si,bx
------------------------ --------------------------------- --------------------
[Previous](11-08.html) [Table of Contents](index.html) [Next](12-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](12-01.html) [Table of Contents](index.html) [Next](12-03.html)
------------------------ --------------------------------- --------------------
which calculates the same sum and leaves the registers in the same state
as the first example, but avoids indexed addressing.
@ -150,12 +146,4 @@ penalty someday; likewise for the undocumented optimizations I'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're well worth using.
------------------------ --------------------------------- --------------------
[Previous](12-01.html) [Table of Contents](index.html) [Next](12-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
least some 486s right now, so I feel they're well worth using.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](12-02.html) [Table of Contents](index.html) [Next](12-04.html)
------------------------ --------------------------------- --------------------
There is, of course, no guarantee that I'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
@ -150,12 +146,4 @@ the performance dependencies, and I don'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'll discuss do indeed apply to
those instructions.
------------------------ --------------------------------- --------------------
[Previous](12-02.html) [Table of Contents](index.html) [Next](12-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
those instructions.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](12-03.html) [Table of Contents](index.html) [Next](13-01.html)
------------------------ --------------------------------- --------------------
You don't need to understand every corner of the 486 universe unless
you'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
@ -153,12 +149,4 @@ staggeringly fast that carefully crafted 486 code can do more than twice
as much per cycle as the best 386 code—which makes it perhaps 50 times
as fast as optimized code for the original PC.
Sometimes it *is* hard to believe we're still in Kansas!
------------------------ --------------------------------- --------------------
[Previous](12-03.html) [Table of Contents](index.html) [Next](13-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
Sometimes it *is* hard to believe we're still in Kansas!

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](12-04.html) [Table of Contents](index.html) [Next](13-02.html)
------------------------ --------------------------------- --------------------
Chapter 13\
Aiming the 486 {#Heading1}
---------------
@ -115,12 +111,4 @@ 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'll let Terje describe
his next optimization in his own words:
------------------------ --------------------------------- --------------------
[Previous](12-04.html) [Table of Contents](index.html) [Next](13-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
his next optimization in his own words:

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](13-01.html) [Table of Contents](index.html) [Next](13-03.html)
------------------------ --------------------------------- --------------------
"When I looked closely as this, I realized that the two cycles for the
final **ADD** 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
@ -108,12 +104,4 @@ or from memory takes only one cycle. Basically, using **ROR** 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't access memory at
all (for example, if you're using BP as a working register, temporarily
making the stack frame inaccessible).
------------------------ --------------------------------- --------------------
[Previous](13-01.html) [Table of Contents](index.html) [Next](13-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
making the stack frame inaccessible).

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](13-02.html) [Table of Contents](index.html) [Next](13-04.html)
------------------------ --------------------------------- --------------------
On the 386, **ROR** was the only way to split a 32-bit register into two
16-bit registers. On the 486, however, **BSWAP** can not only do the
job, but can do it better, because **BSWAP** executes in just one cycle.
@ -102,12 +98,4 @@ slow. But if you're optimizing for the 486, these tidbits can save a few
critical cycles—and Lord knows that if you're optimizing for the
486—that is, if you need even more performance than you get from
unoptimized code on a 486—you almost certainly need all the speed you
can get.
------------------------ --------------------------------- --------------------
[Previous](13-02.html) [Table of Contents](index.html) [Next](13-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
can get.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](13-03.html) [Table of Contents](index.html) [Next](14-01.html)
------------------------ --------------------------------- --------------------
### 32-Bit Addressing Modes {#Heading7}
The 386 and 486 both support 32-bit addressing modes, in which any
@ -103,12 +99,4 @@ capabilities of the Mod-R/M byte, and there's nothing to be done about
it, but it'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's no 1-cycle penalty
for using ESP as a base register) on the 486.
------------------------ --------------------------------- --------------------
[Previous](13-03.html) [Table of Contents](index.html) [Next](14-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
for using ESP as a base register) on the 486.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](13-04.html) [Table of Contents](index.html) [Next](14-02.html)
------------------------ --------------------------------- --------------------
Chapter 14\
Boyer-Moore String Searching {#Heading1}
-----------------------------
@ -122,12 +118,4 @@ character in turn. In order to get any faster, we'd have to check fewer
characters—but we can't do that and still be sure of finding all
matches. Can we?
Actually, yes, we can.
------------------------ --------------------------------- --------------------
[Previous](13-04.html) [Table of Contents](index.html) [Next](14-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
Actually, yes, we can.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](14-01.html) [Table of Contents](index.html) [Next](14-03.html)
------------------------ --------------------------------- --------------------
### The Boyer-Moore Algorithm {#Heading4}
All our *a priori* knowledge of string searching is stated above, but
@ -117,12 +113,4 @@ skip ahead on all the possible mismatch values.
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.
------------------------ --------------------------------- --------------------
[Previous](14-01.html) [Table of Contents](index.html) [Next](14-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
length on a complete mismatch.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](14-02.html) [Table of Contents](index.html) [Next](14-04.html)
------------------------ --------------------------------- --------------------
How fast *is* 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
@ -147,12 +143,4 @@ in most cases than **REPNZ SCASB.** 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't it?
------------------------ --------------------------------- --------------------
[Previous](14-02.html) [Table of Contents](index.html) [Next](14-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
Architecture is destiny. Has a nice ring, doesn't it?

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](14-03.html) [Table of Contents](index.html) [Next](14-05.html)
------------------------ --------------------------------- --------------------
**LISTING 14.1 L14-1.C**
/* Searches a buffer for a specified pattern. In case of a mismatch,
@ -162,12 +158,4 @@ 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 **QuickSearchLoop** could boost performance by up to 10
percent more). Listing 14.3 is also *four times* faster than **REPNZ
SCASB** in one case.
------------------------ --------------------------------- --------------------
[Previous](14-03.html) [Table of Contents](index.html) [Next](14-05.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
SCASB** in one case.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](14-04.html) [Table of Contents](index.html) [Next](14-06.html)
------------------------ --------------------------------- --------------------
**LISTING 14.3 L14-3.ASM**
; Searches a buffer for a specified pattern. In case of a mismatch,
@ -164,11 +160,3 @@
ret
_FindString endp
end
------------------------ --------------------------------- --------------------
[Previous](14-04.html) [Table of Contents](index.html) [Next](14-06.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](14-05.html) [Table of Contents](index.html) [Next](15-01.html)
------------------------ --------------------------------- --------------------
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
@ -190,12 +186,4 @@ Everything we needed was sitting there all along; we just needed to
think to look at it.
As Yogi Berra might put it, "You don't know what you know until you know
it."
------------------------ --------------------------------- --------------------
[Previous](14-05.html) [Table of Contents](index.html) [Next](15-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
it."

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](14-06.html) [Table of Contents](index.html) [Next](15-02.html)
------------------------ --------------------------------- --------------------
Chapter 15\
Linked Lists and plain Unintended Challenges {#Heading1}
---------------------------------------------
@ -140,12 +136,4 @@ structure—but that's an ugly and potentially dangerous trick, and we'll
see a better approach next.)
![](images/15-01.jpg)\
**Figure 15.1**  *The basic concept of a linked list.*
------------------------ --------------------------------- --------------------
[Previous](14-06.html) [Table of Contents](index.html) [Next](15-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
**Figure 15.1**  *The basic concept of a linked list.*

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](15-01.html) [Table of Contents](index.html) [Next](15-03.html)
------------------------ --------------------------------- --------------------
**LISTING 15.1 L15-1.C**
/* Deletes the node in a linked list that follows the indicated node.
@ -151,12 +147,4 @@ themselves to sentinels, but the performance benefits are considerable
for those that do.
![](images/15-03.jpg)\
**Figure 15.3**  *Representing an empty list.*
------------------------ --------------------------------- --------------------
[Previous](15-01.html) [Table of Contents](index.html) [Next](15-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
**Figure 15.3**  *Representing an empty list.*

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](15-02.html) [Table of Contents](index.html) [Next](15-04.html)
------------------------ --------------------------------- --------------------
**LISTING 15.5 L15-5.C**
/* Finds the first node in a value-sorted linked list that
@ -139,11 +135,3 @@ before you write a single line of code.
NodePtr->NextNode = NodeToInsert;
return(NodePtr);
}
------------------------ --------------------------------- --------------------
[Previous](15-02.html) [Table of Contents](index.html) [Next](15-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](15-03.html) [Table of Contents](index.html) [Next](16-01.html)
------------------------ --------------------------------- --------------------
**LISTING 15.7 L15-7.ASM**
; C near-callable assembly function for inserting a new node in a
@ -205,12 +201,4 @@ reads closely enough.
Before I end this chapter, let me say that I get a lot of feedback from
my readers, and it'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's doing these days....
------------------------ --------------------------------- --------------------
[Previous](15-03.html) [Table of Contents](index.html) [Next](16-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
her drop me a line and let me know how she's doing these days....

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](15-04.html) [Table of Contents](index.html) [Next](16-02.html)
------------------------ --------------------------------- --------------------
Chapter 16\
There Ain't No Such Thing as the Fastest Code {#Heading1}
----------------------------------------------
@ -179,12 +175,3 @@ Table 16.1 Word count timings.
printf("\nTotal words in file: %lu\n", WordCount);
return(0);
}
------------------------ --------------------------------- --------------------
[Previous](15-04.html) [Table of Contents](index.html) [Next](16-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](16-01.html) [Table of Contents](index.html) [Next](16-03.html)
------------------------ --------------------------------- --------------------
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
@ -174,12 +170,4 @@ 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—who likes to wait? On an 8088, the improvement in
word-counting a large file could easily be 10 or 20 seconds, which is
*definitely* significant.
------------------------ --------------------------------- --------------------
[Previous](16-01.html) [Table of Contents](index.html) [Next](16-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
*definitely* significant.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](16-02.html) [Table of Contents](index.html) [Next](16-04.html)
------------------------ --------------------------------- --------------------
**LISTING 16.4 L16-4.ASM**
; Assembly subroutine for Listing 16.2. Scans through Buffer, of
@ -158,12 +154,4 @@ 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're almost up to an order of magnitude
faster. You are, of course, entitled to your own opinion, but *I*
consider an order of magnitude to be significant.
------------------------ --------------------------------- --------------------
[Previous](16-02.html) [Table of Contents](index.html) [Next](16-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
consider an order of magnitude to be significant.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](16-03.html) [Table of Contents](index.html) [Next](16-05.html)
------------------------ --------------------------------- --------------------
Truth to tell, I didn'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'd expect, if you think about it long enough and
@ -129,12 +125,4 @@ 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's winning entry, so you can see that David, Dave, and Mick
attained a rarefied level of optimization indeed.
------------------------ --------------------------------- --------------------
[Previous](16-03.html) [Table of Contents](index.html) [Next](16-05.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
attained a rarefied level of optimization indeed.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](16-04.html) [Table of Contents](index.html) [Next](16-06.html)
------------------------ --------------------------------- --------------------
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
@ -254,11 +250,3 @@ Table 16.2 The top four word-counting entries.
.fardata WordTable
include qscan3.inc ;built by MAKETAB
end
------------------------ --------------------------------- --------------------
[Previous](16-04.html) [Table of Contents](index.html) [Next](16-06.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](16-05.html) [Table of Contents](index.html) [Next](16-07.html)
------------------------ --------------------------------- --------------------
### Levels of Optimization {#Heading9}
Three levels of optimization were evident in the word-counting entries I
@ -80,12 +76,4 @@ 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).
------------------------ --------------------------------- --------------------
[Previous](16-05.html) [Table of Contents](index.html) [Next](16-07.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
most programmers).

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](16-06.html) [Table of Contents](index.html) [Next](16-08.html)
------------------------ --------------------------------- --------------------
**Listing 16.6 OPT2.ASM**
;
@ -160,12 +156,4 @@ were really looking at an edge triggered device we want to count each
time the I'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."*
------------------------ --------------------------------- --------------------
[Previous](16-06.html) [Table of Contents](index.html) [Next](16-08.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
triggers every time a word begins or ends."*

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](16-07.html) [Table of Contents](index.html) [Next](17-01.html)
------------------------ --------------------------------- --------------------
**Listing 16.7 L16-7.ASM**
ScanLoop:
@ -163,12 +159,4 @@ that calculates the theoretical maximum performance of native 386
word-counting code at 5.5 cycles/byte, which would be significantly
faster than David's code. Terry, alas, didn't bother to implement his
design, but maybe I'll take a shot at it someday. It'd be fun, for
sure—but jeez, I've got *real* work to do!
------------------------ --------------------------------- --------------------
[Previous](16-07.html) [Table of Contents](index.html) [Next](17-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
sure—but jeez, I've got *real* work to do!

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](16-08.html) [Table of Contents](index.html) [Next](17-02.html)
------------------------ --------------------------------- --------------------
Chapter 17\
The Game of Life {#Heading1}
-----------------
@ -90,12 +86,4 @@ we're done using it to calculate the next generation.
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.
------------------------ --------------------------------- --------------------
[Previous](16-08.html) [Table of Contents](index.html) [Next](17-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
we could stop right here.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](17-01.html) [Table of Contents](index.html) [Next](17-03.html)
------------------------ --------------------------------- --------------------
**LISTING 17.1 L17-1.CPP**
/* C++ Game of Life implementation for any mode for which mode set
@ -257,11 +253,3 @@
gotoxy(TEXT_X_OFFSET + x, y);
puts(text);
}
------------------------ --------------------------------- --------------------
[Previous](17-01.html) [Table of Contents](index.html) [Next](17-03.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](17-02.html) [Table of Contents](index.html) [Next](17-04.html)
------------------------ --------------------------------- --------------------
### Where Does the Time Go? {#Heading5}
How slow is Listing 17.1? Table 17.1 shows that even on a 486, Listing
@ -157,12 +153,4 @@ with eight completely independent operations, requiring eight calls to
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.
------------------------ --------------------------------- --------------------
[Previous](17-02.html) [Table of Contents](index.html) [Next](17-04.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
shifts once the address and mask of any one is known.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](17-03.html) [Table of Contents](index.html) [Next](17-05.html)
------------------------ --------------------------------- --------------------
There's a kicker here, though, and that'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
@ -203,11 +199,3 @@ improvement.
}
}
}
------------------------ --------------------------------- --------------------
[Previous](17-03.html) [Table of Contents](index.html) [Next](17-05.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](17-04.html) [Table of Contents](index.html) [Next](17-06.html)
------------------------ --------------------------------- --------------------
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
@ -153,12 +149,4 @@ possible that way.
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *Once you've reached the point of fine-tuning pointer usage and register variables and the like in C or C++, you've become compiler-dependent; you therefore might as well go to assembly and get the real McCoy.*
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------ --------------------------------- --------------------
[Previous](17-04.html) [Table of Contents](index.html) [Next](17-06.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](17-05.html) [Table of Contents](index.html) [Next](17-07.html)
------------------------ --------------------------------- --------------------
We're still not ready for assembly, though; what we need is a new
perspective that lends itself to vastly better performance in C++. The
Life program in the next section is *three to seven times* faster than
@ -117,12 +113,4 @@ 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—getting a four times speed-up while
switching from the small model to the large model!
------------------------ --------------------------------- --------------------
[Previous](17-05.html) [Table of Contents](index.html) [Next](17-07.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
switching from the small model to the large model!

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](17-06.html) [Table of Contents](index.html) [Next](17-08.html)
------------------------ --------------------------------- --------------------
**LISTING 17.5 L17-5.CPP**
/* C++ Game of Life implementation for any mode for which mode set
@ -277,11 +273,3 @@
}
} while (—init_length);
}
------------------------ --------------------------------- --------------------
[Previous](17-06.html) [Table of Contents](index.html) [Next](17-08.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](17-07.html) [Table of Contents](index.html) [Next](18-01.html)
------------------------ --------------------------------- --------------------
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't fit in a single segment.
@ -75,12 +71,4 @@ for adherence to the rules, read, compiled, linked, run, and judged. I
learned a lot—about a lot of things, not the least of which was the
process (or maybe the wisdom) of laying down challenges to readers.
Who won? What did I learn? To find out, read on.
------------------------ --------------------------------- --------------------
[Previous](17-07.html) [Table of Contents](index.html) [Next](18-01.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash
Who won? What did I learn? To find out, read on.

View file

@ -1,7 +1,3 @@
------------------------ --------------------------------- --------------------
[Previous](17-08.html) [Table of Contents](index.html) [Next](18-02.html)
------------------------ --------------------------------- --------------------
Chapter 18\
It's a plain Wonderful Life {#Heading1}
----------------------------
@ -102,11 +98,3 @@ specific "you" may or may not be quite up to the optimizing level of the
specific "David Stafford" or "Peter Klerings.")
Onward to the code.
------------------------ --------------------------------- --------------------
[Previous](17-08.html) [Table of Contents](index.html) [Next](18-02.html)
------------------------ --------------------------------- --------------------
* * * * *
Graphics Programming Black Book © 2001 Michael Abrash

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