122 lines
8 KiB
Markdown
122 lines
8 KiB
Markdown
------------------------ --------------------------------- --------------------
|
||
[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
|