I had a need for a small delay and tried Sleep 1 but the delay was far too long. I then remembered that Sleep wasn't too good with small values but had forgotten why. Isn't old age wonderful. 
Anyway, I had a quick look at what PB did with Sleep m&. m& is pushed onto the stack and then the Sleep function in Kernel32 is invoked. My SDK docs didn't say much so I went to MSDN. Of course, it is linked to the system clock - now I remember.
With a frequency of 64Hz we have a resolution of 15.625ms.
I then saw this:
"To increase the accuracy of the sleep interval, call the timeGetDevCaps function to determine the supported minimum timer resolution and the timeBeginPeriod function to set the timer resolution to its minimum. Use caution when calling timeBeginPeriod, as frequent calls can significantly affect the system clock, system power usage, and the scheduler. If you call timeBeginPeriod, call it one time early in the application and be sure to call the timeEndPeriod function at the very end of the application."
I'm sure that I hadn't seen that before.
With
I get Time.wPeriodMin = 1ms
With the standard Sleep the following
gives
On removing the comment tags I got
That is better.
Depending upon the application the above may do without further ado.
On the other hand it may not.
For very small values QueryPerformanceCounter is unrivalled.
Enter HiResPause(n)
With
I get
In practice we would not use use InitializeTimer but simply 'QueryPerformanceFrequency qFreq' and then use HiResPause.
There is a major difference between Sleep and HiResPause, which is why I did not use HiResSleep, and that is whilst Sleep "causes a thread to relinquish the remainder of its time slice and become unrunnable for an interval based on the value of" m&, HiResPause, on the contrary, opens the throttle wide open pushing the CPU to the limit. However, this will not be problematic if we restrict HiRespause to small values of m&.
We could implement the following.
so that HiResPause is only invoked with m& < 20ms.
Of course, HiResPause may be used for intervals less than 1ms.
Here are some examples.
(250) 0.250ms
(100) 0.100ms
(50) 0.051ms
(10) 0.011ms
There is a small error in the last two but we are looking at very small intervals here. (10) is 10 millionth of a second.

Anyway, I had a quick look at what PB did with Sleep m&. m& is pushed onto the stack and then the Sleep function in Kernel32 is invoked. My SDK docs didn't say much so I went to MSDN. Of course, it is linked to the system clock - now I remember.

I then saw this:
"To increase the accuracy of the sleep interval, call the timeGetDevCaps function to determine the supported minimum timer resolution and the timeBeginPeriod function to set the timer resolution to its minimum. Use caution when calling timeBeginPeriod, as frequent calls can significantly affect the system clock, system power usage, and the scheduler. If you call timeBeginPeriod, call it one time early in the application and be sure to call the timeEndPeriod function at the very end of the application."
I'm sure that I hadn't seen that before.
With
Code:
Local Time As TIMECAPS TimeGetDevCaps( Time, SizeOf(Time) )
With the standard Sleep the following
Code:
#Compile Exe #Register None #Dim All #TOOLS OFF %NOMMIDS = 1 %NOGDI = 1 #Include "WIN32API.INC" '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Global qFreq, qOverhead, qStart, qStop As Quad Global f As String Macro InitializeTimer f = "#####.###" QueryPerformanceFrequency qFreq QueryPerformanceCounter qStart ' Intel suggestion. First use may be suspect QueryPerformanceCounter qStart ' So, wack it twice <smile> QueryPerformanceCounter qStop qOverhead = qStop - qStart ' Relatively small End Macro Macro StartTimer = QueryPerformanceCounter qStart Macro StopTimer = QueryPerformanceCounter qStop Macro sTimeTaken = Using$(f,(qStop - qStart - qOverhead)*1000/qFreq) + "ms" Macro nTimeTaken = (qStop - qStart - qOverhead)*1000/qFreq '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Function PBMain() As Long Local Time As TIMECAPS Local n As Long InitializeTimer 'TimeGetDevCaps( Time, SizeOf(Time) ) 'TimeBeginPeriod(Time.wPeriodMin) For n = 50 To 1 Step -1 StartTimer Sleep n StopTimer Print n;" ";sTimeTaken Next 'TimeEndPeriod(Time.wPeriodMin) Waitkey$ End Function
Code:
50 53.006ms 49 62.330ms 48 62.390ms 47 62.392ms 46 46.781ms 45 46.709ms 44 46.751ms 43 46.751ms 42 46.609ms 41 46.708ms 40 46.742ms 39 46.748ms 38 46.763ms 37 46.755ms 36 46.772ms 35 46.759ms 34 46.761ms 33 46.752ms 32 46.767ms 31 31.131ms 30 31.081ms 29 31.100ms 28 31.147ms 27 31.118ms 26 31.146ms 25 31.120ms 24 31.138ms 23 31.140ms 22 31.155ms 21 31.130ms 20 31.148ms 19 31.143ms 18 31.149ms 17 31.126ms 16 31.142ms 15 15.439ms 14 15.518ms 13 15.503ms 12 15.531ms 11 15.507ms 10 15.568ms 9 15.407ms 8 15.568ms 7 15.524ms 6 15.550ms 5 15.532ms 4 15.538ms 3 15.547ms 2 15.550ms 1 15.536ms
Code:
50 49.233ms 49 49.613ms 48 48.756ms 47 47.773ms 46 46.786ms 45 45.828ms 44 44.847ms 43 43.876ms 42 42.902ms 41 40.943ms 40 39.967ms 39 38.973ms 38 38.015ms 37 37.043ms 36 36.062ms 35 35.087ms 34 34.115ms 33 33.099ms 32 32.158ms 31 31.185ms 30 30.210ms 29 29.231ms 28 28.257ms 27 27.270ms 26 26.298ms 25 25.298ms 24 24.345ms 23 23.367ms 22 22.397ms 21 21.413ms 20 20.441ms 19 19.451ms 18 18.486ms 17 17.508ms 16 16.536ms 15 15.561ms 14 14.587ms 13 13.626ms 12 12.603ms 11 11.652ms 10 10.683ms 9 9.729ms 8 8.695ms 7 7.749ms 6 6.773ms 5 5.798ms 4 4.818ms 3 3.846ms 2 2.870ms 1 1.892ms
Depending upon the application the above may do without further ado.

On the other hand it may not.
For very small values QueryPerformanceCounter is unrivalled.
Enter HiResPause(n)
Code:
Macro HiResPause(n) MacroTemp ts, te Dim ts As Quad, te As Quad QueryPerformanceCounter ts Do QueryPerformanceCounter te Loop Until (te - ts )*1000000 >= n * qFreq End Macro
Code:
#Compile Exe #Register None #Dim All #TOOLS OFF %NOMMIDS = 1 %NOGDI = 1 #Include "WIN32API.INC" '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Global qFreq, qOverhead, qStart, qStop As Quad Global f As String Macro InitializeTimer f = "#####.###" QueryPerformanceFrequency qFreq QueryPerformanceCounter qStart ' Intel suggestion. First use may be suspect QueryPerformanceCounter qStart ' So, wack it twice <smile> QueryPerformanceCounter qStop qOverhead = qStop - qStart ' Relatively small End Macro Macro StartTimer = QueryPerformanceCounter qStart Macro StopTimer = QueryPerformanceCounter qStop Macro sTimeTaken = Using$(f,(qStop - qStart - qOverhead)*1000/qFreq) + "ms" Macro nTimeTaken = (qStop - qStart - qOverhead)*1000/qFreq '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macro HiResPause(n) MacroTemp ts, te Dim ts As Quad, te As Quad QueryPerformanceCounter ts Do QueryPerformanceCounter te Loop Until (te - ts )*1000000 >= n * qFreq End Macro '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Function PBMain() As Long Local n As Long InitializeTimer For n = 20 To 1 Step -1 StartTimer HiResPause(n*1000) StopTimer Print n;" ";sTimeTaken Next Waitkey$ End Function
Code:
20 20.000ms 19 19.000ms 18 18.000ms 17 17.000ms 16 16.000ms 15 15.000ms 14 14.000ms 13 13.000ms 12 12.000ms 11 11.000ms 10 10.000ms 9 9.000ms 8 8.000ms 7 7.000ms 6 6.000ms 5 5.000ms 4 4.000ms 3 3.000ms 2 2.000ms 1 1.000ms
There is a major difference between Sleep and HiResPause, which is why I did not use HiResSleep, and that is whilst Sleep "causes a thread to relinquish the remainder of its time slice and become unrunnable for an interval based on the value of" m&, HiResPause, on the contrary, opens the throttle wide open pushing the CPU to the limit. However, this will not be problematic if we restrict HiRespause to small values of m&.
We could implement the following.
Code:
If n >= 20 Then Sleep n Else HiResPause(n*1000) End If
Of course, HiResPause may be used for intervals less than 1ms.
Here are some examples.
(250) 0.250ms
(100) 0.100ms
(50) 0.051ms
(10) 0.011ms
There is a small error in the last two but we are looking at very small intervals here. (10) is 10 millionth of a second.

Comment