Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

231 lines
6.1 KiB

  1. /*+ pentime.h
  2. *
  3. * pentium specific high precision timer functions for 16 or 32 bit apps
  4. * (16 bit also needs pentime.asm)
  5. *
  6. *-======================================================================*/
  7. #ifndef PENTIME_H
  8. #define PENTIME_H
  9. typedef struct {
  10. DWORD dwlo;
  11. DWORD dwhi;
  12. } PENTIMER, NEAR * PPENTIMER;
  13. void FAR PASCAL pentimeInitTimer (
  14. PPENTIMER pptimer);
  15. DWORD FAR PASCAL pentimeGetMicrosecs (
  16. PPENTIMER pptimer);
  17. DWORD FAR PASCAL pentimeGetMicrosecDelta (
  18. PPENTIMER pptimer);
  19. DWORD FAR PASCAL pentimeGetMillisecs (
  20. PPENTIMER pptimer);
  21. struct _pentime_global {
  22. DWORD dwTimerKhz;
  23. BOOL bActive;
  24. PENTIMER base;
  25. DWORD dwCpuMhz;
  26. DWORD dwCpuKhz;
  27. };
  28. extern struct _pentime_global pentime;
  29. //
  30. // macros to make whether to use pentium timers or not a runtime option
  31. //
  32. #ifdef _X86_
  33. #define pentimeGetTime() pentime.bActive ? pentimeGetMillisecs(&pentime.base) : timeGetTime()
  34. #define pentimeGetTicks() pentime.bActive ? pentimeGetMicrosecs(&pentime.base) : timeGetTime()
  35. #define pentimeBegin() pentime.bActive ? (pentimeInitTimer(&pentime.base), 0l) : (void)(pentime.base.dwlo = timeGetTime())
  36. #define pentimeGetTickRate() (pentime.bActive ? (pentime.dwTimerKhz * 1000) : 1000l)
  37. #define pentimeGetDeltaTicks(ppt) pentime.bActive ? pentimeGetMicrosecDelta(ppt) : \
  38. ((ppt)->dwhi = (ppt)->dwlo, (ppt)->dwlo = timeGetTime(), (ppt)->dwlo - (ppt)->dwhi)
  39. #else
  40. #define pentimeGetTime() timeGetTime()
  41. #define pentimeGetTicks() timeGetTime()
  42. #define pentimeBegin() (pentime.base.dwlo = timeGetTime())
  43. #define pentimeGetTickRate() (1000l)
  44. #define pentimeGetDeltaTicks(ppt) \
  45. ((ppt)->dwhi = (ppt)->dwlo, (ppt)->dwlo = timeGetTime(), (ppt)->dwlo - (ppt)->dwhi)
  46. #endif
  47. #if (defined _INC_PENTIME_CODE_) && (_INC_PENTIME_CODE_ != FALSE)
  48. #undef _INC_PENTIME_CODE_
  49. #define _INC_PENTIME_CODE_ FALSE
  50. struct _pentime_global pentime = {1, 0};
  51. #ifdef _WIN32
  52. #ifdef _X86_
  53. static BYTE opGetP5Ticks[] = {
  54. 0x0f, 0x31, // rtdsc
  55. 0xc3 // ret
  56. };
  57. static void (WINAPI * GetP5Ticks)() = (LPVOID)opGetP5Ticks;
  58. #pragma warning(disable:4704)
  59. #pragma warning(disable:4035)
  60. void FAR PASCAL pentimeInitTimer (
  61. PPENTIMER pptimer)
  62. {
  63. GetP5Ticks();
  64. _asm {
  65. mov ebx, pptimer
  66. mov [ebx], eax
  67. mov [ebx+4], edx
  68. };
  69. }
  70. DWORD FAR PASCAL pentimeGetCpuTicks (
  71. PPENTIMER pptimer)
  72. {
  73. GetP5Ticks();
  74. _asm {
  75. mov ebx, pptimer
  76. sub eax, [ebx]
  77. sbb edx, [ebx+4]
  78. };
  79. }
  80. DWORD FAR PASCAL pentimeGetMicrosecs (
  81. PPENTIMER pptimer)
  82. {
  83. GetP5Ticks();
  84. _asm {
  85. mov ebx, pptimer
  86. sub eax, [ebx]
  87. sbb edx, [ebx+4]
  88. and edx, 31 // to prevent overflow
  89. mov ecx, pentime.dwCpuMhz
  90. div ecx
  91. };
  92. }
  93. DWORD WINAPI pentimeGetMicrosecDelta (
  94. PPENTIMER pptimer)
  95. {
  96. GetP5Ticks();
  97. _asm {
  98. mov ebx, pptimer
  99. mov ecx, eax
  100. sub eax, [ebx]
  101. mov [ebx], ecx
  102. mov ecx, edx
  103. sbb edx, [ebx+4]
  104. mov [ebx+4], ecx
  105. and edx, 31
  106. mov ecx, pentime.dwCpuMhz
  107. div ecx
  108. };
  109. }
  110. DWORD FAR PASCAL pentimeGetMillisecs (
  111. PPENTIMER pptimer)
  112. {
  113. GetP5Ticks();
  114. _asm {
  115. mov ebx, pptimer
  116. sub eax, [ebx]
  117. sbb edx, [ebx+4]
  118. and edx, 0x7fff // to prevent overflow
  119. mov ecx, pentime.dwCpuKhz
  120. div ecx
  121. };
  122. }
  123. #endif
  124. void FAR PASCAL pentimeSetMhz (
  125. DWORD dwCpuMhz)
  126. {
  127. pentime.dwCpuMhz = dwCpuMhz;
  128. pentime.dwCpuKhz = dwCpuMhz * 1000;
  129. }
  130. #else // 16 bit - set mhz is in ASM file
  131. void FAR PASCAL pentimeSetMhz (
  132. DWORD dwCpuMhz);
  133. #endif
  134. void FAR PASCAL pentimeInit (
  135. BOOL bIsPentium,
  136. DWORD dwCpuMhz)
  137. {
  138. if (pentime.bActive = bIsPentium)
  139. {
  140. pentimeSetMhz (dwCpuMhz);
  141. pentime.dwTimerKhz = 1000;
  142. }
  143. else
  144. pentime.dwTimerKhz = 1;
  145. pentimeBegin();
  146. }
  147. #ifdef _WIN32
  148. VOID WINAPI pentimeDetectCPU ()
  149. {
  150. SYSTEM_INFO si;
  151. static DWORD MS_INTERVAL = 500; // measure pentium cpu clock for this
  152. // many millisec. the larger this number
  153. // the more accurate our Mhz measurement.
  154. // numbers less than 100 are unlikely
  155. // to be reliable because of the slop
  156. // in GetTickCount
  157. #ifdef _X86_
  158. GetSystemInfo(&si);
  159. if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL &&
  160. si.wProcessorLevel == 5
  161. )
  162. {
  163. DWORD dw;
  164. PENTIMER qwTicks;
  165. DWORD dwTicks;
  166. pentime.bActive = TRUE;
  167. pentime.dwTimerKhz = 1000;
  168. timeBeginPeriod(1);
  169. dw = timeGetTime ();
  170. pentimeInitTimer (&qwTicks);
  171. Sleep(MS_INTERVAL);
  172. dw = timeGetTime() - dw;
  173. dwTicks = pentimeGetCpuTicks (&qwTicks);
  174. timeEndPeriod(1);
  175. // calculate the CPU Mhz value and Khz value
  176. // to use as millisec and microsec divisors
  177. //
  178. pentime.dwCpuMhz = (dwTicks + dw*500)/dw/1000;
  179. pentime.dwCpuKhz = pentime.dwCpuMhz * 1000;
  180. }
  181. else
  182. #endif
  183. {
  184. pentime.bActive = FALSE;
  185. pentime.dwTimerKhz = 1;
  186. }
  187. }
  188. #else // win16
  189. VOID WINAPI pentimeDetectCPU ()
  190. {
  191. pentimeInit (FALSE, 33);
  192. }
  193. #endif
  194. #endif // _INC_PENTIME_CODE_
  195. #endif // PENTIME_H