155 lines
No EOL
7.8 KiB
Markdown
155 lines
No EOL
7.8 KiB
Markdown
Listing 3.3 is used by naming it TESTCODE, assembling both Listing 3.2
|
|
(which includes TESTCODE) and Listing 3.1 with TASM or MASM, and linking
|
|
the two resulting OBJ files together by way of the Borland orMicrosoft
|
|
linker. Listing 3.4 shows a batch file, PZTIME.BAT, which does all that;
|
|
when run, this batch file generates and runs the executable file
|
|
PZTEST.EXE. PZTIME.BAT (Listing 3.4) assumes that the file PZTIMER.ASM
|
|
contains Listing 3.1, and the file PZTEST.ASM contains Listing 3.2. The
|
|
command-line parameter to PZTIME.BAT is the name of the file to be
|
|
copied to TESTCODE and included into PZTEST.ASM. (Note that Turbo
|
|
Assembler can be substituted for MASM by replacing "masm" with "tasm"
|
|
and "link" with "tlink" in Listing 3.4. The same is true of Listing
|
|
3.7.)
|
|
|
|
**LISTING 3.4 PZTIME.BAT**
|
|
|
|
echo off
|
|
rem
|
|
rem *** Listing 3.4 ***
|
|
rem
|
|
rem ***************************************************************
|
|
rem * Batch file PZTIME.BAT, which builds and runs the precision *
|
|
rem * Zen timer program PZTEST.EXE to time the code named as the *
|
|
rem * command-line parameter. Listing 3.1 must be named *
|
|
rem * PZTIMER.ASM, and Listing 3.2 must be named PZTEST.ASM. To *
|
|
rem * time the code in LST3-3, you'd type the DOS command: *
|
|
rem * *
|
|
rem * pztime lst3-3 *
|
|
rem * *
|
|
rem * Note that MASM and LINK must be in the current directory or *
|
|
rem * on the current path in order for this batch file to work. *
|
|
rem * *
|
|
rem * This batch file can be speeded up by assembling PZTIMER.ASM *
|
|
rem * once, then removing the lines: *
|
|
rem * *
|
|
rem * masm pztimer; *
|
|
rem * if errorlevel 1 goto errorend *
|
|
rem * *
|
|
rem * from this file. *
|
|
rem * *
|
|
rem * By Michael Abrash *
|
|
rem ***************************************************************
|
|
rem
|
|
rem Make sure a file to test was specified.
|
|
rem
|
|
if not x%1==x goto ckexist
|
|
echo ***************************************************************
|
|
echo * Please specify a file to test. *
|
|
echo ***************************************************************
|
|
goto end
|
|
rem
|
|
rem Make sure the file exists.
|
|
rem
|
|
:ckexist
|
|
if exist %1 goto docopy
|
|
echo ***************************************************************
|
|
echo * The specified file, "%1," doesn't exist. *
|
|
echo ***************************************************************
|
|
goto end
|
|
rem
|
|
rem copy the file to measure to TESTCODE.
|
|
rem
|
|
:docopy
|
|
copy %1 testcode
|
|
masm pztest;
|
|
if errorlevel 1 goto errorend
|
|
masm pztimer;
|
|
if errorlevel 1 goto errorend
|
|
link pztest+pztimer;
|
|
if errorlevel 1 goto errorend
|
|
pztest
|
|
goto end
|
|
:errorend
|
|
echo ***************************************************************
|
|
echo * An error occurred while building the precision Zen timer. *
|
|
echo ***************************************************************
|
|
:end
|
|
|
|
Assuming that Listing 3.3 is named LST3-3.ASM and Listing 3.4 is named
|
|
PZTIME.BAT, the code in Listing 3.3 would be timed with the command:
|
|
|
|
pztime LST3-3.ASM
|
|
|
|
which performs all assembly and linking, and reports the execution time
|
|
of the code in Listing 3.3.
|
|
|
|
When the above command is executed on an original 4.77 MHz IBM PC, the
|
|
time reported by the Zen timer is 3619 µs, or about 3.62 µs per load of
|
|
AL from memory. (While the exact number is 3.619 µs per load of AL, I'm
|
|
going to round off that last digit from now on. No matter how many
|
|
repetitions of a given instruction are timed, there's just too much
|
|
noise in the timing process—between dynamic RAM refresh, the prefetch
|
|
queue, and the internal state of the processor at the start of
|
|
timing—for that last digit to have any significance.) Given the test
|
|
PC's 4.77 MHz clock, this works out to about 17 cycles per **MOV**,
|
|
which is actually a good bit longer than Intel's specified 10-cycle
|
|
execution time for this instruction. (See the MASM or TASM
|
|
documentation, or Intel's processor reference manuals, for official
|
|
execution times.) Fear not, the Zen timer is right—**MOV AL,[MEMVAR]**
|
|
really does take 17 cycles as used in Listing 3.3. Exactly why that is
|
|
so is just what this book is all about.
|
|
|
|
In order to perform any of the timing tests in this book, enter Listing
|
|
3.1 and name it PZTIMER.ASM, enter Listing 3.2 and name it PZTEST.ASM,
|
|
and enter Listing 3.4 and name it PZTIME.BAT. Then simply enter the
|
|
listing you wish to run into the file *filename* and enter the command:
|
|
|
|
pztime <filename>
|
|
|
|
In fact, that's exactly how I timed each of the listings in this book.
|
|
Code fragments you write yourself can be timed in just the same way. If
|
|
you wish to time code directly in place in your programs, rather than in
|
|
the test-bed program of Listing 3.2, simply insert calls to **ZTimerOn,
|
|
ZTimerOff**, and **ZTimerReport** in the appropriate places and link
|
|
PZTIMER to your program.
|
|
|
|
### The Long-Period Zen Timer {#Heading12}
|
|
|
|
With a few exceptions, the Zen timer presented above will serve us well
|
|
for the remainder of this book since we'll be focusing on relatively
|
|
short code sequences that generally take much less than 54 ms to
|
|
execute. Occasionally, however, we will need to time longer intervals.
|
|
What's more, it is very likely that you will want to time code sequences
|
|
longer than 54 ms at some point in your programming career. Accordingly,
|
|
I've also developed a Zen timer for periods longer than 54 ms. The
|
|
long-period Zen timer (so named by contrast with the precision Zen timer
|
|
just presented) shown in Listing 3.5 can measure periods up to one hour
|
|
in length.
|
|
|
|
The key difference between the long-period Zen timer and the precision
|
|
Zen timer is that the long-period timer leaves interrupts enabled during
|
|
the timing period. As a result, timer interrupts are recognized by the
|
|
PC, allowing the BIOS to maintain an accurate system clock time over the
|
|
timing period. Theoretically, this enables measurement of arbitrarily
|
|
long periods. Practically speaking, however, there is no need for a
|
|
timer that can measure more than a few minutes, since the DOS time of
|
|
day and date functions (or, indeed, the DATE and TIME commands in a
|
|
batch file) serve perfectly well for longer intervals. Since very long
|
|
timing intervals aren't needed, the long-period Zen timer uses a
|
|
simplified means of calculating elapsed time that is limited to
|
|
measuring intervals of an hour or less. If a period longer than an hour
|
|
is timed, the long-period Zen timer prints a message to the effect that
|
|
it is unable to time an interval of that length.
|
|
|
|
For implementation reasons, the long-period Zen timer is also incapable
|
|
of timing code that starts before midnight and ends after midnight; if
|
|
that eventuality occurs, the long-period Zen timer reports that it was
|
|
unable to time the code because midnight was crossed. If this happens to
|
|
you, just time the code again, secure in the knowledge that at least you
|
|
won't run into the problem again for 23-odd hours.
|
|
|
|
You should not use the long-period Zen timer to time code that requires
|
|
interrupts to be disabled for more than 54 ms at a stretch during the
|
|
timing interval, since when interrupts are disabled the long-period Zen
|
|
timer is subject to the same 54 ms maximum measurement time as the
|
|
precision Zen timer. |