abrash-black-book/04-10.md
2013-12-30 20:26:41 +11:00

117 lines
No EOL
8.1 KiB
Markdown

------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](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.*
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
In addition, code that accesses display memory infrequently tends to
suffer only about half of the maximum display memory wait states,
because on average such code will access display memory halfway between
one available display memory access slot and the next. As a result, code
that accesses display memory less intensively than the code in Listing
4.11 will on average lose 4 or 5 rather than 8-plus cycles to the
display adapter cycle-eater on each memory access.
Nonetheless, the display adapter cycle-eater always takes its toll on
graphics code. Interestingly, that toll becomes much higher on ATs and
80386 machines because while those computers can execute many more
instructions per microsecond than can the 8088-based PC, it takes just
as long to access display memory on those computers as on the 8088-based
PC. Remember, the limited speed of access to a graphics adapter is an
inherent characteristic of the adapter, so the fastest computer around
can't access display memory one iota faster than the adapter will allow.
#### What to Do about the Display Adapter Cycle-Eater? {#Heading22}
What can we do about the display adapter cycle-eater? Well, we can
minimize display memory accesses whenever possible. In particular, we
can try to avoid read/modify/write display memory operations of the sort
used to mask individual pixels and clip images. Why? Because
read/modify/write operations require two display memory accesses (one
read and one write) each time display memory is manipulated. Instead, we
should try to use writes of the sort that set all the pixels in a given
byte of display memory at once, since such writes don't require
accompanying read accesses. The key here is that only half as many
display memory accesses are required to write a byte to display memory
as are required to read a byte from display memory, mask part of it off
and alter the rest, and write the byte back to display memory. Half as
many display memory accesses means half as many display memory wait
states.
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *Moreover, 486s and Pentiums, as well as recent Super VGAs, employ write-caching schemes that make display memory writes considerably faster than display memory reads.*
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Along the same line, the display adapter cycle-eater makes the popular
exclusive-OR animation technique, which requires paired reads and writes
of display memory, less-than-ideal for the PC. Exclusive-OR animation
should be avoided in favor of simply writing images to display memory
whenever possible.
Another principle for display adapter programming on the 8088 is to
perform multiple accesses to display memory very rapidly, in order to
make use of as many of the scarce accesses to display memory as
possible. This is especially important when many large images need to be
drawn quickly, since only by using virtually every available display
memory access can many bytes be written to display memory in a short
period of time. Repeated string instructions are ideal for making
maximum use of display memory accesses; of course, repeated string
instructions can only be used on whole bytes, so this is another point
in favor of modifying display memory a byte at a time. (On faster
processors, however, display memory is so slow that it often pays to do
several instructions worth of work between display memory accesses, to
take advantage of cycles that would otherwise be wasted on the wait
states.)
It would be handy to explore the display adapter cycle-eater issue in
depth, with lots of example code and execution timings, but alas, I
don't have the space for that right now. For the time being, all you
really need to know about the display adapter cycle-eater is that on the
8088 you can lose more than 8 cycles of execution time on each access to
display memory. For intensive access to display memory, the loss really
can be as high as 8cycles (and up to 50, 100, or even more on 486s and
Pentiums paired with slow VGAs), while for average graphics code the
loss is closer to 4 cycles; in either case, the impact on performance is
significant. There is only one way to discover just how significant the
impact of the display adapter cycle-eater is for any particular graphics
code, and that is of course to measure the performance of that code.
#### Cycle-Eaters: A Summary {#Heading23}
We've covered a great deal of sophisticated material in this chapter, so
don't feel bad if you haven't understood everything you've read; it will
all become clear from further reading, especially once you study, time,
and tune code that you have written yourself. What's really important is
that you come away from this chapter understanding that on the 8088:
- The 8-bit bus cycle-eater causes each access to a word-sized operand
to be 4 cycles longer than an equivalent access to a byte-sized
operand.
- The prefetch queue cycle-eater can cause instruction execution times
to be as much as four times longer than the officially documented
cycle times.
- The DRAM refresh cycle-eater slows most PC code, with performance
reductions ranging as high as 8.33 percent.
- The display adapter cycle-eater typically doubles and can more than
triple the length of the standard 4-cycle access to display memory,
with intensive display memory access suffering most.
This basic knowledge about cycle-eaters puts you in a good position to
understand the results reported by the Zen timer, and that means that
you're well on your way to writing high-performance assembler code.
#### What Does It All Mean? {#Heading24}
There you have it: life under the programming interface. It's not a
particularly pretty picture for the inhabitants of that strange realm
where hardware and software meet are little-known cycle-eaters that sap
the speed from your unsuspecting code. Still, some of those cycle-eaters
can be minimized by keeping instructions short, using the registers,
using byte-sized memory operands, and accessing display memory as little
as possible. None of the cycle-eaters can be eliminated, and dynamic RAM
refresh can scarcely be addressed at all; still, aren't you better off
knowing how fast your code *really* runs—and why—than you were reading
the official execution times and guessing? And while specific
cycle-eaters vary in importance on later x86-family processors, with
some cycle-eaters vanishing altogether and new ones appearing, the
concept that understanding these obscure gremlins is a key to
performance remains unchanged, as we'll see again and again in later
chapters.