High resolution replacement for Sleep
#2
Comments here http://pump.richheimer.de/showthread.php?tid=74

SleepX() was ported from FreeBASIC. The class A amplifier analogy uses Timer because FreeBASIC's Timer is linked to the Performance Counter. PowerBASIC's Timer is linked to the System Clock with a resolution of 15.625 milliseconds so that is of no use for a high resolution Sleep. Even using SetHiRes it is too grainy and why the Performance Counter is used.

A FreeBASIC member's Performance Counter is 2.532753 MHz, so his accuracy was less than mine with Windows 10 at 10MHz.

I suggested enabling HPET. He is now getting 14.31818MHz. However, the overhead of getting the Performance Counter with HPET enabled is expensive compared with not enabling HPET. Nonetheless, his accuracy is better with HPET enabled. The consensus of opinion is not to have HPET enabled if you play games but that depends upon how old your machine is.

On my machine, enabling HPET reduces the accuracy so I stayed with FreeBASIC's Timer.

There is a higher resolution counter: the Time Stamp Counter. We could use RDTSC, but an easier way is to use PowerBASIC's TIX which FreeBASIC does not have.

With SleepX() a common result is of the form x.0001/x.0002. With SleepXX, using TIX, a common result is of the form x.0000x; a factor of 10 better than SleepX.

The SleepXX code and EXAMPLE USAGE does not use the Performance Counter at all. We do, however, need to know the CPU base frequency. My machine has a base frequency of 3.5GHz and 3.9GHz with Turbo, so I use 3.5GHz with 'MACRO CPUBaseFreq =  3.5*10^9'.

There is an overhead using TIX but it is negligible on my machine so I ignore it. That is also true using the Performance Counter.

The following code has the SleepXX() code and a usage example.

This is a typical output.
Code:
Quarter of a millisecond: 0.250063 ms

2 seconds:2000.000295 ms

Silly:1234.000299 ms

1  1.000118 ms
2  2.000035 ms
3  3.000062 ms
4  4.000162 ms
5  5.000051 ms
6  6.000068 ms
7  7.000059 ms
8  8.000058 ms
9  9.000058 ms
10  10.000071 ms
11  11.000063 ms
12  12.000072 ms
13  13.000066 ms
14  14.00007 ms
15  15.000066 ms
16  16.000069 ms
17  17.000071 ms
18  18.000076 ms
19  19.000068 ms
20  20.000073 ms
21  21.000074 ms
22  22.000077 ms
23  23.000079 ms
24  24.000072 ms
25  25.000102 ms
26  26.000071 ms
27  27.000081 ms
28  28.000147 ms
29  29.00008 ms
30  30.000085 ms
SleepXX
Code:
#COMPILE EXE
#DIM ALL
#break on
#INCLUDE "win32api.inc"

' SOURCE CODE:

MACRO CPUBaseFreq =  3.5*10^9

Macro SetHiRes
  MacroTemp Time
  Dim Time As TIMECAPS
  TimeGetDevCaps( Time, SizeOf(Time) )
  TimeBeginPeriod(Time.wPeriodMin)
  'Sleep 16 ' Pre Windows 10
End Macro

Macro RevokeHiRes
  MacroTemp Time
  Dim Time As TIMECAPS
  TimeGetDevCaps( Time, SizeOf(Time) )
  TimeEndPeriod(Time.wPeriodMin)
End Macro

Sub SleepXX( ByVal n As Double )
  Local qTarget, qTimeNow As Quad
  Tix qTimeNow
  qTarget = qTimeNow + n*CPUBaseFreq*0.001
  If n <= 3 then
    Do : Tix qTimeNow : Loop Until qTimeNow >= qTarget ' Class A amplifier analogy
  Else
    ' Class B amplifier analogy followed by Classs A amplifier analogy
    Sleep ( n-3 ) : Do : Tix qTimeNow  : Loop Until qTimeNow >= qTarget
  End If
End Sub

' ====================

' EXAMPLE USAGE:

FUNCTION PBMAIN () AS LONG
local i as Long
lOCAL qTime As Quad

  SetHiRes

  Tix qTime
    SleepXX(0.25)
  Tix End qTime
  Print "Quarter of a millisecond:";format$(qTime/CPUBaseFreq/10^15," ####.######");" ms"
  Print

  Tix qTime
    SleepXX(2000)
  Tix End qTime
  Print "2 seconds:";Format$(qTime/CPUBaseFreq/10^15, "####.######");" ms"
  Print

  Tix qTime
    SleepXX(1234)
  Tix End qTime
  Print "Silly:";ForMat$(qTime/CPUBaseFreq/10^15, "####.######");" ms"
  Print

  For i = 1 to 30
    Tix qTime
      SleepXX(i)
    Tix End qTime
    Print i;" ";Format$(qTime/CPUBaseFreq/10^15, "####.######");" ms"
  Next

  RevokeHiRes

  WaitKey$

END FUNCTION
Reply


Messages In This Thread
RE: High resolution replacement for Sleep - by David Roberts - 13.09.2025, 11:43 PM

Forum Jump:


Users browsing this thread: 1 Guest(s)