110 lines
7.4 KiB
Markdown
110 lines
7.4 KiB
Markdown
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
 *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.
|