Initial conversion to markdown
This commit is contained in:
parent
a96a114403
commit
5e10794a24
362 changed files with 67353 additions and 0 deletions
135
03-10.md
Normal file
135
03-10.md
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
------------------------ --------------------------------- --------------------
|
||||
[Previous](03-09.html) [Table of Contents](index.html) [Next](04-01.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
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.)
|
||||
|
||||
\
|
||||
**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
|
||||
|
||||
\
|
||||
**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.
|
||||
|
||||
------------------------ --------------------------------- --------------------
|
||||
[Previous](03-09.html) [Table of Contents](index.html) [Next](04-01.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
* * * * *
|
||||
|
||||
Graphics Programming Black Book © 2001 Michael Abrash
|
||||
Loading…
Reference in a new issue