Normal quotes

This commit is contained in:
James Gregory 2013-12-30 18:34:31 +11:00
commit 18011c595a
352 changed files with 6040 additions and 6040 deletions

View file

@ -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:
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *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.)*
![](images/i.jpg) *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.)
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *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!*
![](images/i.jpg) *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!*
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------ --------------------------------- --------------------