127 lines
No EOL
5.8 KiB
Markdown
127 lines
No EOL
5.8 KiB
Markdown
Moreover, because it uses an undocumented feature, the timer-stop
|
||
approach could conceivably cause erratic 8253 operation, which could in
|
||
turn seriously affect your computer's operation until the next reboot.
|
||
In non-8253-compatible systems, I've observed not only wildly incorrect
|
||
timing results, but also failure of a diskette drive to operate properly
|
||
after the long-period Zen timer with **PS2** set to 0 has run, so be
|
||
alert for signs of trouble if you do set **PS2** to 0.
|
||
|
||
Rebooting should clear up any timer-related problems of the sort
|
||
described above. (This gives us another reason to reboot at the end of
|
||
each code-timing session.) You should *immediately* reboot and set the
|
||
**PS2** equate to 1 if you get erratic or obviously incorrect results
|
||
with the long-period Zen timer when **PS2** is set to 0. If you want to
|
||
set **PS2** to 0, it would be a good idea to time a few of the listings
|
||
in this book with **PS2** set first to 1 and then to 0, to make sure
|
||
that the results match. If they're consistently different, you should
|
||
set **PS2** to 1.
|
||
|
||
While the the non-PS/2 version is more dangerous than the PS/2 version,
|
||
it also produces more accurate results when it does work. If you have a
|
||
non-PS/2 PC-compatible computer, the choice between the two timing
|
||
approaches is yours.
|
||
|
||
If you do leave the **PS2** equate at 1 in Listing 3.5, you should
|
||
repeat each code-timing run several times before relying on the results
|
||
to be accurate to more than 54 ms, since variations may result from the
|
||
possible lack of synchronization between the timer 0 count and the BIOS
|
||
time-of-day count. In fact, it's a good idea to time code more than once
|
||
no matter which version of the long-period Zen timer you're using, since
|
||
interrupts, which must be enabled in order for the long-period timer to
|
||
work properly, may occur at any time and can alter execution time
|
||
substantially.
|
||
|
||
Finally, please note that the *precision* Zen timer works perfectly well
|
||
on both PS/2 and non-PS/2 computers. The PS/2 and 8253 considerations
|
||
we've just discussed apply *only* to the longZen timer.
|
||
|
||
### Example Use of the Long-Period Zen Timer {#Heading14}
|
||
|
||
The long-period Zen timer has exactly the same calling interface as the
|
||
precision Zen timer, and can be used in place of the precision Zen timer
|
||
simply by linking it to the code to be timed in place of linking the
|
||
precision timer code. Whenever the precision Zen timer informs you that
|
||
the code being timed takes too long for the precision timer to handle,
|
||
all you have to do is link in the long-period timer instead.
|
||
|
||
Listing 3.6 shows a test-bed program for the long-period Zen timer.
|
||
While this program is similar to Listing 3.2, it's worth noting that
|
||
Listing 3.6 waits for a few seconds before calling **ZTimerOn**, thereby
|
||
allowing any pending keyboard interrupts to be processed. Since
|
||
interrupts must be left on in order to time periods longer than 54 ms,
|
||
the interrupts generated by keystrokes (including the upstroke of the
|
||
Enter key press that starts the program)—or any other interrupts, for
|
||
that matter—could incorrectly inflate the time recorded by the
|
||
long-period Zen timer. In light of this, resist the temptation to type
|
||
ahead, move the mouse, or the like while the long-period Zen timer is
|
||
timing.
|
||
|
||
**LISTING 3.6 LZTEST.ASM**
|
||
|
||
; Program to measure performance of code that takes longer than
|
||
; 54 ms to execute. (LZTEST.ASM)
|
||
;
|
||
; Link with LZTIMER.ASM (Listing 3.5). LZTIME.BAT (Listing 3.7)
|
||
; can be used to assemble and link both files. Code to be
|
||
; measured must be in the file TESTCODE; Listing 3.8 shows
|
||
; a sample file (LST3-8.ASM) which should be named TESTCODE.
|
||
;
|
||
; By Michael Abrash
|
||
;
|
||
mystack segment para stack ‘STACK'
|
||
db 512 dup(?)
|
||
mystack ends
|
||
;
|
||
Code segment para public ‘CODE'
|
||
assume cs:Code, ds:Code
|
||
extrn ZTimerOn:near, ZTimerOff:near, ZTimerReport:near
|
||
Startproc near
|
||
push cs
|
||
pop ds ;point DS to the code segment,
|
||
; so data as well as code can easily
|
||
; be included in TESTCODE
|
||
;
|
||
; Delay for 6-7 seconds, to let the Enter keystroke that started the
|
||
; program come back up.
|
||
;
|
||
mov ah,2ch
|
||
int 21h ;get the current time
|
||
mov bh,dh ;set the current time aside
|
||
DelayLoop:
|
||
mov ah,2ch
|
||
push bx ;preserve start time
|
||
int 21h ;get time
|
||
pop bx ;retrieve start time
|
||
cmp dh,bh ;is the new seconds count less than
|
||
; the start seconds count?
|
||
jnb CheckDelayTime ;no
|
||
add dh,60 ;yes, a minute must have turned over,
|
||
; so add one minute
|
||
CheckDelayTime:
|
||
sub dh,bh ;get time that's passed
|
||
cmp dh,7 ;has it been more than 6 seconds yet?
|
||
jb DelayLoop ;not yet
|
||
;
|
||
include TESTCODE ;code to be measured, including calls
|
||
; to ZTimerOn and ZTimerOff
|
||
;
|
||
; Display the results.
|
||
;
|
||
call ZTimerReport
|
||
;
|
||
; Terminate the program.
|
||
;
|
||
mov ah,4ch
|
||
int 21h
|
||
Start endp
|
||
Code ends
|
||
end Start
|
||
|
||
As with the precision Zen timer, the program in Listing 3.6 is used by
|
||
naming the file containing the code to be timed TESTCODE, then
|
||
assembling both Listing 3.6 and Listing 3.5 with MASM or TASM and
|
||
linking the two files together by way of the Microsoft or Borland
|
||
linker. Listing 3.7 shows a batch file, named LZTIME.BAT, which does all
|
||
of the above, generating and running the executable file LZTEST.EXE.
|
||
LZTIME.BAT assumes that the file LZTIMER.ASM contains Listing 3.5 and
|
||
the file LZTEST.ASM contains Listing 3.6. |