Initial conversion to markdown
This commit is contained in:
parent
a96a114403
commit
5e10794a24
362 changed files with 67353 additions and 0 deletions
122
19-02.md
Normal file
122
19-02.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
------------------------ --------------------------------- --------------------
|
||||
[Previous](19-01.html) [Table of Contents](index.html) [Next](19-03.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
 *The Pentium, on the other hand, has two separate 8K caches, one for code and one for data, so code prefetches can never collide with data fetches; the prefetch queue can stall only when the code being fetched isn’t in the internal code cache.*
|
||||
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
(And yes, self-modifying code still works; as with all Pentium changes,
|
||||
the dual caches introduce no incompatibilities with 386/486 code.) Also,
|
||||
because the code and data caches are separate, code can’t be driven out
|
||||
of the cache in a tight loop that accesses a lot of data, unlike the
|
||||
486. In addition, the Pentium expands the 486’s 32-byte prefetch queue
|
||||
to 128 bytes. In conjunction with the branch prediction feature
|
||||
(described next), which allows the Pentium to prefetch properly at most
|
||||
branches, this larger prefetch queue means that the Pentium’s two pipes
|
||||
should be better fed than those of any previous x86 processor.
|
||||
|
||||
#### Crossing Cache Lines {#Heading5}
|
||||
|
||||
There are three other characteristics of the Pentium that make for a
|
||||
healthy supply of instruction bytes. One is that the Pentium can
|
||||
prefetch instructions across cache lines. Unlike the 486, where there is
|
||||
a 3-cycle penalty for branching to an instruction that spans a cache
|
||||
line, there’s no such penalty on the Pentium. The second is that the
|
||||
cache line size (the number of bytes fetched from the external cache or
|
||||
main memory on a cache miss) on the Pentium is 32 bytes, twice the size
|
||||
of the 486’s cache line, so a cache miss causes a longer run of
|
||||
instructions to be placed in the cache than on the 486. The third is
|
||||
that the Pentium’s external bus is twice as wide as the 486’s, at 64
|
||||
bits, and runs twice as fast, at 66 MHz, so the Pentium can fetch both
|
||||
instruction and data bytes from the external cache four times as fast as
|
||||
the 486.
|
||||
|
||||
------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
 *Even when the Pentium is running flat-out with both pipes in use, it can generally consume only about twice as many bytes as the 486; so the ratio of external memory bandwidth to processing power is much improved, although real-world performance is heavily dependent on the size and speed of the external cache.*
|
||||
------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
The upshot of all this is that at the same clock speed, with code and
|
||||
data that are mostly in the internal caches, the Pentium maxes out
|
||||
somewhere around twice as fast as a 486. (When the caches are missed a
|
||||
lot, the Pentium can get as much as three to four times faster, due to
|
||||
the superior external bus and bigger caches.) Most of this won’t affect
|
||||
how you program, but it is useful to know that you don’t have to worry
|
||||
about instruction fetching. It’s also useful to know the sizes of the
|
||||
caches because a high cache hit rate is crucial to Pentium performance.
|
||||
Cache misses are vastly slower than cache hits (anywhere from two to 50
|
||||
or more times as slow, depending on the speed of the external cache and
|
||||
whether the external cache misses as well), and the Pentium can’t use
|
||||
the V-pipe on code that hasn’t already been executed out of the cache at
|
||||
least once. This means that it is *very* important to get the working
|
||||
sets of critical loops to fit in the internal caches.
|
||||
|
||||
One change in the Pentium that you definitely do have to worry about is
|
||||
superscalar execution. Utilization of the V-pipe can range from near
|
||||
zero percent to 100 percent, depending on the code being executed, and
|
||||
careful rearrangement of code can have amazing effects. Maxing out
|
||||
V-pipe use is not a trivial task; I’ll spend all of the next chapter
|
||||
discussing it so as to have time to cover it properly. In the meantime,
|
||||
two good references for superscalar programming and other Pentium
|
||||
information are Intel’s *Pentium Processor User’s Manual: Volume 3:
|
||||
Architecture and Programming Manual* (ISBN 1-55512-195-0; Intel order
|
||||
number 241430-001), and the article “Optimizing Pentium Code” by Mike
|
||||
Schmidt, in *Dr. Dobb’s Journal* for January 1994.
|
||||
|
||||
#### Cache Organization {#Heading6}
|
||||
|
||||
There are two other interesting changes in the Pentium’s cache
|
||||
organization. First, the cache is two-way set-associative, whereas the
|
||||
486 is four-way set-associative. The details of this don’t matter, but
|
||||
simply put, this, combined with the 32-byte cache line size, means that
|
||||
the Pentium has somewhat coarser granularity in both space and time than
|
||||
the 486 in terms of packing bytes into the cache, although the total
|
||||
cache space is now bigger. There’s nothing you can do about this, but it
|
||||
may make it a little harder to get a loop’s working set into the cache.
|
||||
Second, the internal cache can now be configured (by the BIOS or OS; you
|
||||
won’t have to worry about it) for write-back rather than write-through
|
||||
operation. This means that writes to the internal data cache don’t
|
||||
necessarily get propagated to the external bus until other demands for
|
||||
cache space force the data out of the cache, making repeated writes to
|
||||
memory variables such as loop counters cheaper on average than on the
|
||||
486, although not as cheap as registers.
|
||||
|
||||
As a final note on Pentium architecture for this chapter, the pipeline
|
||||
stalls (what Intel calls AGIs, for *Address Generation Interlocks*) that
|
||||
I discussed earlier in this book (see Chapter 12) are still present in
|
||||
the Pentium. In fact, they’re there in spades on the Pentium; the two
|
||||
pipelines mean that an AGI can now slow down execution of an instruction
|
||||
that’s *three* instructions away from the AGI (because four instructions
|
||||
can execute in two cycles). So, for example, the code sequence
|
||||
|
||||
add edx,4 ;U-pipe cycle 1
|
||||
mov ecx,[ebx] ;V-pipe cycle 1
|
||||
add ebx,4 ;U-pipe cycle 2
|
||||
mov [edx],ecx ;V-pipe cycle 3
|
||||
; due to AGI
|
||||
; (would have been
|
||||
; V-pipe cycle 2)
|
||||
|
||||
takes three cycles rather than the two cycles it should take, because
|
||||
EDX was modified on cycle 1 and an attempt was made to use it on cycle
|
||||
two, before the AGI had time to clear—even though there are two
|
||||
instructions between the instructions that are actually involved in the
|
||||
AGI. Rearranging the code like
|
||||
|
||||
mov ecx,[ebx] ;U-pipe cycle 1
|
||||
add ebx,4 ;V-pipe cycle 1
|
||||
mov [edx+4],ecx ;U-pipe cycle 2
|
||||
add edx,4 ;V-pipe cycle 2
|
||||
|
||||
makes it functionally identical, but cuts the cycles to 2—a 50 percent
|
||||
improvement. Clearly, avoiding AGIs becomes a much more challenging and
|
||||
rewarding game in a superscalar world, one to which I’ll return in the
|
||||
next chapter.
|
||||
|
||||
------------------------ --------------------------------- --------------------
|
||||
[Previous](19-01.html) [Table of Contents](index.html) [Next](19-03.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
* * * * *
|
||||
|
||||
Graphics Programming Black Book © 2001 Michael Abrash
|
||||
Loading…
Reference in a new issue