Normal quotes
This commit is contained in:
parent
5e10794a24
commit
18011c595a
352 changed files with 6040 additions and 6040 deletions
40
07-01.md
40
07-01.md
|
|
@ -8,16 +8,16 @@ Chapter 7\
|
|||
|
||||
### Optimizing Halfway between Algorithms and Cycle Counting {#Heading2}
|
||||
|
||||
You might not think it, but there’s much to learn about performance
|
||||
You might not think it, but there's much to learn about performance
|
||||
programming from the Great Buffalo Sauna Fiasco. To wit:
|
||||
|
||||
The scene is Buffalo, New York, in the dead of winter, with the snow
|
||||
piled several feet deep. Four college students, living in typical
|
||||
student housing, are frozen to the bone. The third floor of their house,
|
||||
uninsulated and so cold that it’s uninhabitable, has an ancient
|
||||
uninsulated and so cold that it's uninhabitable, has an ancient
|
||||
bathroom. One fabulously cold day, inspiration strikes:
|
||||
|
||||
“Hey—we could make that bathroom into a *sauna!*”
|
||||
"Hey—we could make that bathroom into a *sauna!*"
|
||||
|
||||
Pandemonium ensues. Someone rushes out and buys a gas heater, and at
|
||||
considerable risk to life and limb hooks it up to an abandoned but still
|
||||
|
|
@ -29,7 +29,7 @@ benches along the sides of the bathroom. *Voila*—instant sauna!
|
|||
|
||||
They crank up the gas heater, put the bucket of rocks in front of it,
|
||||
close the door, take off their clothes, and sit down to steam
|
||||
themselves. Mind you, it’s not yet 50 degrees Fahrenheit in this room,
|
||||
themselves. Mind you, it's not yet 50 degrees Fahrenheit in this room,
|
||||
but the gas heater is roaring. Surely warmer times await.
|
||||
|
||||
Indeed they do. The temperature climbs to 55 degrees, then 60, then 63,
|
||||
|
|
@ -66,51 +66,51 @@ program is worth bothering with only in the context of a good design.
|
|||
------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
So, drawing fortitude from the knowledge that our quest is a pure and
|
||||
worthy one, let’s resume our exploration of assembly language
|
||||
worthy one, let's resume our exploration of assembly language
|
||||
instructions with hidden talents and instructions with well-known
|
||||
talents that are less than they appear to be. In the process, we’ll come
|
||||
talents that are less than they appear to be. In the process, we'll come
|
||||
to see that there is another, very important optimization level between
|
||||
the algorithm/design level and the cycle-counting/individual instruction
|
||||
level. I’ll call this middle level *local optimization;* it involves
|
||||
level. I'll call this middle level *local optimization;* it involves
|
||||
focusing on optimizing sequences of instructions rather than individual
|
||||
instructions, all with an eye to implementing designs as efficiently as
|
||||
possible given the capabilities of the x86 family instruction set.
|
||||
|
||||
And yes, in case you’re wondering, the above story is indeed true. Was I
|
||||
there? Let me put it this way: If I were, I’d never admit it!
|
||||
And yes, in case you're wondering, the above story is indeed true. Was I
|
||||
there? Let me put it this way: If I were, I'd never admit it!
|
||||
|
||||
#### When LOOP Is a Bad Idea {#Heading3}
|
||||
|
||||
Let’s examine first an instruction that is less than it appears to be:
|
||||
**LOOP**. There’s no mystery about what **LOOP** does; it decrements CX
|
||||
and branches if CX doesn’t decrement to zero. It’s so beautifully suited
|
||||
Let's examine first an instruction that is less than it appears to be:
|
||||
**LOOP**. There's no mystery about what **LOOP** does; it decrements CX
|
||||
and branches if CX doesn't decrement to zero. It's so beautifully suited
|
||||
to the task of counting down loops that any experienced x86 programmer
|
||||
instinctively stuffs the loop count in CX and reaches for **LOOP** when
|
||||
setting up a loop. That’s fine—**LOOP** does, of course, work as
|
||||
setting up a loop. That's fine—**LOOP** does, of course, work as
|
||||
advertised—but there is one problem:
|
||||
|
||||
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
 *On half of the processors in the x86 family, **LOOP** is slower than **DEC CX** followed by **JNZ**. (Granted, **DEC CX/JNZ** isn’t precisely equivalent to **LOOP,** because **DEC** alters the flags and LOOP doesn’t, but in most situations they’re comparable.)*
|
||||
 *On half of the processors in the x86 family, **LOOP** is slower than **DEC CX** followed by **JNZ**. (Granted, **DEC CX/JNZ** isn't precisely equivalent to **LOOP,** because **DEC** alters the flags and LOOP doesn't, but in most situations they're comparable.)*
|
||||
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
How can this be? Don’t ask me, ask Intel. On the 8088 and 80286,
|
||||
How can this be? Don't ask me, ask Intel. On the 8088 and 80286,
|
||||
**LOOP** is indeed faster than **DEC CX/JNZ** by a cycle, and **LOOP**
|
||||
is generally a little faster still because it’s a byte shorter and so
|
||||
is generally a little faster still because it's a byte shorter and so
|
||||
can be fetched faster. On the 386, however, things change; **LOOP** is
|
||||
two cycles *slower* than **DEC/JNZ,** and the fetch time for one extra
|
||||
byte on even an uncached 386 generally isn’t significant. (Remember that
|
||||
byte on even an uncached 386 generally isn't significant. (Remember that
|
||||
the 386 fetches four instruction bytes at a pop.) **LOOP** is three
|
||||
cycles slower than **DEC/JNZ** on the 486, and the 486 executes
|
||||
instructions in so few cycles that those three cycles mean that
|
||||
**DEC/JNZ** is nearly *twice* as fast as **LOOP**. Then, too, unlike
|
||||
**LOOP, DEC** doesn’t require that **CX** be used, so the **DEC/JNZ**
|
||||
**LOOP, DEC** doesn't require that **CX** be used, so the **DEC/JNZ**
|
||||
solution is both faster and more flexible on the 386 and 486, and on the
|
||||
Pentium as well. (By the way, all this is not just theory; I’ve timed
|
||||
Pentium as well. (By the way, all this is not just theory; I've timed
|
||||
the relative performances of **LOOP** and **DEC CX/JNZ** on a cached
|
||||
386, and LOOP really is slower.)
|
||||
|
||||
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
 *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!*
|
||||
 *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!*
|
||||
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
|
|
|||
Loading…
Reference in a new issue