1 /****************************************************************************
3 * SciTech OS Portability Manager Library
5 * ========================================================================
7 * The contents of this file are subject to the SciTech MGL Public
8 * License Version 1.0 (the "License"); you may not use this file
9 * except in compliance with the License. You may obtain a copy of
10 * the License at http://www.scitechsoft.com/mgl-license.txt
12 * Software distributed under the License is distributed on an
13 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * rights and limitations under the License.
17 * The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
19 * The Initial Developer of the Original Code is SciTech Software, Inc.
20 * All Rights Reserved.
22 * ========================================================================
27 * Description: Module to implement high precision timing on each OS.
29 ****************************************************************************/
35 /*---------------------------- Global variables ---------------------------*/
37 static LZTimerObject LZTimer;
38 static ulong start,finish;
40 static long cpuSpeed = -1;
41 static ibool haveRDTSC = false;
44 /*----------------------------- Implementation ----------------------------*/
46 /* External Intel assembler functions */
49 void _ASMAPI _CPU_readTimeStamp(CPU_largeInteger *time);
51 ulong _ASMAPI _CPU_diffTime64(CPU_largeInteger *t1,CPU_largeInteger *t2,CPU_largeInteger *t);
53 ulong _ASMAPI _CPU_calcMicroSec(CPU_largeInteger *count,ulong freq);
56 #if defined(__SMX32__)
57 #include "smx/ztimer.c"
58 #elif defined(__RTTARGET__)
59 #include "rttarget/ztimer.c"
60 #elif defined(__REALDOS__)
61 #include "dos/ztimer.c"
62 #elif defined(__NT_DRIVER__)
63 #include "ntdrv/ztimer.c"
64 #elif defined(__WIN32_VXD__)
65 #include "vxd/ztimer.c"
66 #elif defined(__WINDOWS32__)
67 #include "win32/ztimer.c"
68 #elif defined(__OS2_VDD__)
69 #include "vdd/ztimer.c"
70 #elif defined(__OS2__)
71 #include "os2/ztimer.c"
72 #elif defined(__LINUX__)
73 #include "linux/ztimer.c"
74 #elif defined(__QNX__)
75 #include "qnx/ztimer.c"
76 #elif defined(__BEOS__)
77 #include "beos/ztimer.c"
79 #error Timer library not ported to this platform yet!
82 /*------------------------ Public interface routines ----------------------*/
84 /****************************************************************************
86 Initializes the Zen Timer library (extended)
89 accurate - True of the speed should be measured accurately
95 This function initializes the Zen Timer library, and /must/ be called before
96 any of the remaining Zen Timer library functions are called. The accurate
97 parameter is used to determine whether highly accurate timing should be
98 used or not. If high accuracy is needed, more time is spent profiling the
99 actual speed of the CPU so that we can obtain highly accurate timing
100 results, but the time spent in the initialisation routine will be
101 significantly longer (on the order of 5 seconds).
102 ****************************************************************************/
103 void ZAPI ZTimerInitExt(
106 if (cpuSpeed == -1) {
109 cpuSpeed = CPU_getProcessorSpeedInHZ(accurate);
110 haveRDTSC = CPU_haveRDTSC() && (cpuSpeed > 0);
115 /****************************************************************************
117 Initializes the Zen Timer library.
123 This function initializes the Zen Timer library, and /must/ be called before
124 any of the remaining Zen Timer library functions are called.
125 ****************************************************************************/
126 void ZAPI ZTimerInit(void)
128 ZTimerInitExt(false);
131 /****************************************************************************
133 Starts the Long Period Zen Timer counting.
139 tm - Timer object to start timing with
142 Starts the Long Period Zen Timer counting. Once you have started the timer,
143 you can stop it with LZTimerOff or you can latch the current count with
146 The Long Period Zen Timer uses a number of different high precision timing
147 mechanisms to obtain microsecond accurate timings results whenever possible.
148 The following different techniques are used depending on the operating
149 system, runtime environment and CPU on the target machine. If the target
150 system has a Pentium CPU installed which supports the Read Time Stamp
151 Counter instruction (RDTSC), the Zen Timer library will use this to
152 obtain the maximum timing precision available.
154 Under 32-bit Windows, if the Pentium RDTSC instruction is not available, we
155 first try to use the Win32 QueryPerformanceCounter API, and if that is not
156 available we fall back on the timeGetTime API which is always supported.
158 Under 32-bit DOS, if the Pentium RDTSC instruction is not available, we
159 then do all timing using the old style 8253 timer chip. The 8253 timer
160 routines provide highly accurate timings results in pure DOS mode, however
161 in a DOS box under Windows or other Operating Systems the virtualization
162 of the timer can produce inaccurate results.
164 Note: Because the Long Period Zen Timer stores the results in a 32-bit
165 unsigned integer, you can only time periods of up to 2^32 microseconds,
166 or about 1hr 20mins. For timing longer periods use the Ultra Long
170 LZTimerOff, LZTimerLap, LZTimerCount
171 ****************************************************************************/
172 void ZAPI LZTimerOnExt(
177 _CPU_readTimeStamp(&tm->start);
184 /****************************************************************************
186 Returns the current count for the Long Period Zen Timer and keeps it
193 tm - Timer object to do lap timing with
196 Count that has elapsed in microseconds.
199 Returns the current count that has elapsed since the last call to
200 LZTimerOn in microseconds. The time continues to run after this function is
201 called so you can call this function repeatedly.
204 LZTimerOn, LZTimerOff, LZTimerCount
205 ****************************************************************************/
206 ulong ZAPI LZTimerLapExt(
210 CPU_largeInteger tmLap,tmCount;
213 _CPU_readTimeStamp(&tmLap);
214 _CPU_diffTime64(&tm->start,&tmLap,&tmCount);
215 return _CPU_calcMicroSec(&tmCount,cpuSpeed);
219 return __LZTimerLap(tm);
222 /****************************************************************************
224 Stops the Long Period Zen Timer counting.
230 tm - Timer object to stop timing with
233 Stops the Long Period Zen Timer counting and latches the count. Once you
234 have stopped the timer you can read the count with LZTimerCount. If you need
235 highly accurate timing, you should use the on and off functions rather than
236 the lap function since the lap function does not subtract the overhead of
237 the function calls from the timed count.
240 LZTimerOn, LZTimerLap, LZTimerCount
241 ****************************************************************************/
242 void ZAPI LZTimerOffExt(
247 _CPU_readTimeStamp(&tm->end);
254 /****************************************************************************
256 Returns the current count for the Long Period Zen Timer.
262 tm - Timer object to compute the elapsed time with.
265 Count that has elapsed in microseconds.
268 Returns the current count that has elapsed between calls to
269 LZTimerOn and LZTimerOff in microseconds.
272 LZTimerOn, LZTimerOff, LZTimerLap
273 ****************************************************************************/
274 ulong ZAPI LZTimerCountExt(
278 CPU_largeInteger tmCount;
281 _CPU_diffTime64(&tm->start,&tm->end,&tmCount);
282 return _CPU_calcMicroSec(&tmCount,cpuSpeed);
286 return __LZTimerCount(tm);
289 /****************************************************************************
291 Starts the Long Period Zen Timer counting.
297 Obsolete function. You should use the LZTimerOnExt function instead
298 which allows for multiple timers running at the same time.
299 ****************************************************************************/
300 void ZAPI LZTimerOn(void)
301 { LZTimerOnExt(&LZTimer); }
303 /****************************************************************************
305 Returns the current count for the Long Period Zen Timer and keeps it
312 Count that has elapsed in microseconds.
315 Obsolete function. You should use the LZTimerLapExt function instead
316 which allows for multiple timers running at the same time.
317 ****************************************************************************/
318 ulong ZAPI LZTimerLap(void)
319 { return LZTimerLapExt(&LZTimer); }
321 /****************************************************************************
323 Stops the Long Period Zen Timer counting.
329 Obsolete function. You should use the LZTimerOffExt function instead
330 which allows for multiple timers running at the same time.
331 ****************************************************************************/
332 void ZAPI LZTimerOff(void)
333 { LZTimerOffExt(&LZTimer); }
335 /****************************************************************************
337 Returns the current count for the Long Period Zen Timer.
343 Count that has elapsed in microseconds.
346 Obsolete function. You should use the LZTimerCountExt function instead
347 which allows for multiple timers running at the same time.
348 ****************************************************************************/
349 ulong ZAPI LZTimerCount(void)
350 { return LZTimerCountExt(&LZTimer); }
352 /****************************************************************************
354 Starts the Ultra Long Period Zen Timer counting.
360 Starts the Ultra Long Period Zen Timer counting. Once you have started the
361 timer, you can stop it with ULZTimerOff or you can latch the current count
364 The Ultra Long Period Zen Timer uses the available operating system services
365 to obtain accurate timings results with as much precision as the operating
366 system provides, but with enough granularity to time longer periods of
367 time than the Long Period Zen Timer. Note that the resolution of the timer
368 ticks is not constant between different platforms, and you should use the
369 ULZTimerResolution function to determine the number of seconds in a single
370 tick of the timer, and use this to convert the timer counts to seconds.
372 Under 32-bit Windows, we use the timeGetTime function which provides a
373 resolution of 1 millisecond (0.001 of a second). Given that the timer
374 count is returned as an unsigned 32-bit integer, this we can time intervals
375 that are a maximum of 2^32 milliseconds in length (or about 1,200 hours or
378 Under 32-bit DOS, we use the system timer tick which runs at 18.2 times per
379 second. Given that the timer count is returned as an unsigned 32-bit integer,
380 this we can time intervals that are a maximum of 2^32 * (1/18.2) in length
381 (or about 65,550 hours or 2731 days!).
384 ULZTimerOff, ULZTimerLap, ULZTimerCount, ULZElapsedTime, ULZReadTime
385 ****************************************************************************/
386 void ZAPI ULZTimerOn(void)
387 { start = __ULZReadTime(); }
389 /****************************************************************************
391 Returns the current count for the Ultra Long Period Zen Timer and keeps it
398 Count that has elapsed in resolution counts.
401 Returns the current count that has elapsed since the last call to
402 ULZTimerOn in microseconds. The time continues to run after this function is
403 called so you can call this function repeatedly.
406 ULZTimerOn, ULZTimerOff, ULZTimerCount
407 ****************************************************************************/
408 ulong ZAPI ULZTimerLap(void)
409 { return (__ULZReadTime() - start); }
411 /****************************************************************************
413 Stops the Long Period Zen Timer counting.
419 Stops the Ultra Long Period Zen Timer counting and latches the count. Once
420 you have stopped the timer you can read the count with ULZTimerCount.
423 ULZTimerOn, ULZTimerLap, ULZTimerCount
424 ****************************************************************************/
425 void ZAPI ULZTimerOff(void)
426 { finish = __ULZReadTime(); }
428 /****************************************************************************
430 Returns the current count for the Ultra Long Period Zen Timer.
436 Count that has elapsed in resolution counts.
439 Returns the current count that has elapsed between calls to
440 ULZTimerOn and ULZTimerOff in resolution counts.
443 ULZTimerOn, ULZTimerOff, ULZTimerLap, ULZTimerResolution
444 ****************************************************************************/
445 ulong ZAPI ULZTimerCount(void)
446 { return (finish - start); }
448 /****************************************************************************
450 Reads the current time from the Ultra Long Period Zen Timer.
456 Current timer value in resolution counts.
459 Reads the current Ultra Long Period Zen Timer and returns it
\92s current
460 count. You can use the ULZElapsedTime function to find the elapsed time
461 between two timer count readings.
464 ULZElapsedTime, ULZTimerResolution
465 ****************************************************************************/
466 ulong ZAPI ULZReadTime(void)
467 { return __ULZReadTime(); }
469 /****************************************************************************
471 Compute the elapsed time between two timer counts.
477 start - Starting time for elapsed count
478 finish - Ending time for elapsed count
481 Elapsed timer in resolution counts.
484 Returns the elapsed time for the Ultra Long Period Zen Timer in units of the
485 timers resolution (1/18th of a second under DOS). This function correctly
486 computes the difference even if a midnight boundary has been crossed
487 during the timing period.
490 ULZReadTime, ULZTimerResolution
491 ****************************************************************************/
492 ulong ZAPI ULZElapsedTime(
495 { return __ULZElapsedTime(start,finish); }
497 /****************************************************************************
499 Returns the resolution of the Ultra Long Period Zen Timer.
505 resolution - Place to store the timer in microseconds per timer count.
508 Returns the resolution of the Ultra Long Period Zen Timer as a 32-bit
509 integer value measured in microseconds per timer count.
512 ULZReadTime, ULZElapsedTime, ULZTimerCount
513 ****************************************************************************/
514 void ZAPI ULZTimerResolution(
516 { *resolution = ULZTIMER_RESOLUTION; }