abrash-black-book/03-10.md
2013-12-30 20:26:41 +11:00

123 lines
No EOL
5.7 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

when declaring the timer routines **extern**, so that name-mangling
doesn't occur, and the linker can find the routines' C-style names.)
That's all it takes; after doing this, you'll be able to use the Zen
timer from C, as, for example, in:
ZTimerOn():
for (i=0, x=0; i<100; i++)
x += i;
ZTimerOff();
ZTimerReport();
(I'm talking about the precision timer here. The long-period
timer—Listing 3.5—requires the same modifications, but to different
lines.)
![](images/03-02.jpg)\
**Figure 3.2**  *Changes for use with small code model C.*
Altering the Zen timer for use in C's large code model is a tad more
complex, because in addition to the above changes, all functions,
including the internal reference timing routines that are used to
calculate overhead so it can be subtracted out, must be converted to
far. Figure 3.3 shows the line numbers and new states of all lines from
Listing 3.1 that must be changed in order to call the Zen timer from
large code model C. Again, the line numbers are specific to the
precision timer, but the long-period timer is very similar.
The full listings for the C-callable Zen timers are presented in Chapter
K on the companion CD-ROM.
#### Watch Out for Optimizing Assemblers! {#Heading16}
One important safety tip when modifying the Zen timer for use with large
code model C code: Watch out for optimizing assemblers! TASM actually
replaces
call far ptr ReferenceZTimerOn
with
push cs
call near ptr ReferenceZTimerOn
(and likewise for **ReferenceZTimerOff** ), which works because
**ReferenceZTimerOn** is in the same segment as the calling code. This
is normally a great optimization, being both smaller and faster than a
far call. However, it's not so great for the Zen
![](images/03-03.jpg)\
**Figure 3.3**  *Changes for use with large code model C.*
timer, because our purpose in calling the reference timing code is to
determine exactly how much time is taken by overhead code—including the
far calls to **ZTimerOn** and **ZTimerOf**f! By converting the far calls
to push/near call pairs within the Zen timer module, TASM makes it
impossible to emulate exactly the overhead of the Zen timer, and makes
timings slightly (about 16 cycles on a 386) less accurate.
What's the solution? Put the **NOSMART** directive at the start of the
Zen timer code. This directive instructs TASM to turn off all
optimizations, including converting far calls to push/near call pairs.
By the way, there is, to the best of my knowledge, no such problem with
MASM up through version 5.10A.
In my mind, the whole business of optimizing assemblers is a mixed
blessing. In general, it's nice to have the assembler shortening jumps
and selecting sign-extended forms of instructions for you. On the other
hand, the benefits of tricks like substituting push/near call pairs for
far calls are relatively small, and those tricks can get in the way when
complete control is needed. Sure, complete control is needed very
rarely, but when it is, optimizing assemblers can cause subtle problems;
I discovered TASM's alteration of far calls only because I happened to
view the code in the debugger, and you might want to do the same if
you're using a recent version of MASM.
I've tested the changes shown in Figures 3.2 and 3.3 with TASM and
Borland C++ 4.0, and also with the latest MASM and Microsoft C/C++
compiler.
#### Further Reading {#Heading17}
For those of you who wish to pursue the mechanics of code measurement
further, one good article about measuring code performance with the 8253
timer is "Programming Insight: High-Performance Software Analysis on the
IBM PC," by Byron Sheppard, which appeared in the January, 1987 issue of
*Byte*. For complete if somewhat cryptic information on the 8253 timer
itself, I refer you to Intel's *Microsystem Components Handbook*, which
is also a useful reference for a number of other PC components,
including the 8259 Programmable Interrupt Controller and the 8237 DMA
Controller. For details about the way the 8253 is used in the PC, as
well as a great deal of additional information about the PC's hardware
and BIOS resources, I suggest you consult IBM's series of technical
reference manuals for the PC, XT, AT, Model 30, and microchannel
computers, such as the Models 50, 60, and 80.
For our purposes, however, it's not critical that you understand exactly
how the Zen timer works. All you really need to know is what the Zen
timer can do and how to use it, and we've accomplished that in this
chapter.
#### Armed with the Zen Timer, Onward and Upward {#Heading18}
The Zen timer is not perfect. For one thing, the finest resolution to
which it can measure an interval is at best about 1µs, a period of time
in which a 66 MHz Pentium computer can execute as many as 132
instructions (although an 8088-based PC would be hard-pressed to manage
two instructions in a microsecond). Another problem is that the timing
code itself interferes with the state of the prefetch queue and
processor cache at the start of the code being timed, because the timing
code is not necessarily fetched and does not necessarily access memory
in exactly the same time sequence as the code immediately preceding the
code under measurement normally does. This prefetch effect can introduce
as much as 3 to 4 µ of inaccuracy. Similarly, the state of the prefetch
queue at the end of the code being timed affects how long the code that
stops the timer takes to execute. Consequently, the Zen timer tends to
be more accurate for longer code sequences, since the relative magnitude
of the inaccuracy introduced by the Zen timer becomes less over longer
periods.
Imperfections notwithstanding, the Zen timer is a good tool for
exploring C code and x86 family assembly language, and it's a tool we'll
use frequently for the remainder of this book.