GetInterruptTime(), Win NT, x86 & x64

Share your advanced PureBasic knowledge/code with the community.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

GetInterruptTime(), Win NT, x86 & x64

Post by Rescator »

This is kinda hard to explain easily so if your confused please look at http://www.dcl.hpi.uni-potsdam.de/research/WRK/?p=34
The interrupt time is the only Windows clock that guarantees to be monotonous that is, its value only increases over timer. Its value represents the time in units of 100 ns since the system was booted. The interrupt time is the base clock for all timers in Windows (see my recent article A Bug in Windows Timer Management). It is updated every clock interrupt.
So on my system the example below returns 156000 (15.6ms) and 156001, and if I un-comment the timeBeginPeriod and timeEndPeriod lines the timer/interrupt resolution increases and I get 10000 (1ms) and 10001. On NT the max value (lowest reslution) is around 15.6ms, the min value (highest resolution) is 0.976ms. timeBeginPeriod_() affect the resolution of the system clock and timer ticks.

Since it's a 64bit value, despite being 1/10000th of a ms, it'll still take around 58454 years before it wraps around to 0 again, nobody have yet to reach a system uptime of that long. :P
(and even if it does, as long as you use the good old "stop-start" to get your delta value like you'd usually do, even that is not an issue)

For reference 10000 = 1ms. The behavior is similar to GetTickCount_() and timeGetTime_() but with higher precision, and falls between those and QueryPerformanceCounter_()
but as you see, other than the procedure itself, no system calls are used at all, the interrupt time is read directly from KUSER_SHARED_DATA memory which resides at $7FFE0000 and is exposed in the addressable memory of all processes. If your a speed freak I guess you could inline this stuff in your loops etc.

Note! The order of the MOV's and the loop is vital, the reason for this is that the values are fetched in the reverse order that the ISR (clock interrupt service routine) updates them,
comparing the high part with the duplicate high part ensure that we did not read during an interrupt and if we did the loop repeats until we read between interrupts instead.

I have no idea how useful this is to anyone, but it sure was interesting to "discover" it :) I guess it's of some interest for certain timing tests as GetTickCount_() timeGetTime_() ElapsedMilliseconds() would get 15.6ms as either 15ms or 16ms while my routines would get them as 156000 (15.6ms) so that extra precision itself might make this worth using.

Just to reiterate! GetInterruptTime() will return the value that basically every timer in Windows is based on or uses in one way or another, directly or indirectly, even GetTickCount_(), timeGetTime_(), and ElapsedMilliseconds() is derived or synced in some way from this value. (Except QueryPerformanceCounter_() which is based on a different counter and may be CPU or crystal based or some other source)

Warning! As far as I know this is available on NT (4+?), i have not tried on Win9x but it'll most likely crash there. So use this only on Windows 5.x/6.x and later.

PS! Fred, I hope the x64 code is ok, I was a bit unsure if the rbx register was ok to use or not as the PB manual do not mention which x64 registers that are safe to use.

Code: Select all

;Public domain, created by Rescator.
;Based on info found at http://www.dcl.hpi.uni-potsdam.de/research/WRK/?p=34
CompilerIf #PB_Compiler_Processor=#PB_Processor_x86
 Procedure.q GetInterruptTime()
  !_GetInterruptTime_Repeat_Start:
   !MOV edx,dword [2147352584+4]
   !MOV eax,dword [2147352584]
   !MOV ecx,dword [2147352584+8]
   !CMP edx,ecx
   !JNE _GetInterruptTime_Repeat_Start
  ProcedureReturn
 EndProcedure
CompilerElse
 Procedure.q GetInterruptTime()
  !MOV qword rdx,2147352584
  !_GetInterruptTime_Repeat_Start:
   !MOVSXD rax,dword [rdx+4]
   !MOVSXD rbx,dword [rdx]
   !MOVSXD rcx,dword [rdx+8]
   !CMP rax,rcx
   !JNE _GetInterruptTime_Repeat_Start
  !SAL rax,32
  !ADD rax,rbx
  ProcedureReturn
 EndProcedure
CompilerEndIf

;timeBeginPeriod_(1)
Define n.i,start.q,stop.q
For n=1 To 10
 start=GetInterruptTime()
 Delay(1)
 stop=GetInterruptTime()
 Debug stop-start
Next
;timeEndPeriod_(1)
milan1612
Addict
Addict
Posts: 894
Joined: Thu Apr 05, 2007 12:15 am
Location: Nuremberg, Germany
Contact:

Re: GetInterruptTime(), Win NT, x86 & x64

Post by milan1612 »

Just for fun, here is my output:
78125
78125
78125
78125
78125
78125
78125
78125
78125
78125
Pretty accurate :)
Windows 7 & PureBasic 4.4
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: GetInterruptTime(), Win NT, x86 & x64

Post by SFSxOI »

Works here on Windows 7 x86 (32 bit) and PB 4.31. Are you saying this is for 64 bit?

This is what i get:

156000
156000
156001
156000
156000
156001
156000
156000
156000
156001

Have absolutly no idea where I would ever use something like this, but i'll put it with my collection of snippets. This is kinda like one of those things you keep stuffed away in the closet forever thinking "I'll use that some day." :)

Thank You :)
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

GetTimerResolution() and SetTimerResolution()

Post by Rescator »

Here is an interesting one, same source as above but with two extra procedures: GetTimerResolution() and SetTimerResolution()

SetTimerResolution(resolution) kinda behaves like timeBeginPeriod_() the range is 5000 to 15600.
To restore default just use SetTimerResolution(0) kinda behaves like timeEndPeriod_()

GetTimerResolution() returns the current resolution of the timer.

Test the following source to see if it has any impact on your system.
Here I got:
0.5001 ms.
0.5001 ms.
0.5000 ms.
0.5000 ms.
0.5001 ms.
0.5001 ms.
0.5000 ms.
0.5001 ms.
0.5001 ms.
0.5001 ms.

There reason I'm not updating the first post with this is that we're kinda abusing the system here. With 0.5ms timings everything in the system moves like 300% faster than normally (default is 15.6ms), so there is a lot of things being triggered but nothing to do. Wasting resources in other words.
Also, Delay() cant' be used since the smallest it can go is 1ms, so instead Delay(0) is used which is basically task witching, and a busy loop is done to manually check if the value has changed. Not exactly CPU friendly is it? (looks to me like system CPU use jumped a couple % with 0.5ms, basically doubling compared to 1ms)

Still though...it's kinda cool seeing Windows with 0.5ms timing resolution, who'd have thunk Windows could go sub millisec on us? :P

Code: Select all

;Public Domain, created by Rescator.
EnableExplicit

Procedure.l GetTimerResolution()
 Protected MinimumResolution.l,MaximumResolution.l,CurrentResolution.l
 NtQueryTimerResolution_(@MinimumResolution,@MaximumResolution,@CurrentResolution)
 ProcedureReturn CurrentResolution
EndProcedure

Procedure.l SetTimerResolution(resolution.l)
 Protected MinimumResolution.l,MaximumResolution.l
 Static CurrentResolution.l
 If resolution
  If NtQueryTimerResolution_(@MinimumResolution,@MaximumResolution,@CurrentResolution)=#S_OK
   If resolution>MinimumResolution
    resolution=MinimumResolution
   ElseIf resolution<MaximumResolution
    resolution=MaximumResolution
   EndIf
   If NtSetTimerResolution_(resolution,#True,@CurrentResolution)<>#S_OK
    CurrentResolution=0
   EndIf
  Else
   CurrentResolution=0
  EndIf
 Else
  NtSetTimerResolution_(#Null,#False,@CurrentResolution)
 EndIf
 ProcedureReturn CurrentResolution
EndProcedure

;Based on info found at http://www.dcl.hpi.uni-potsdam.de/research/WRK/?p=34
CompilerIf #PB_Compiler_Processor=#PB_Processor_x86
 Procedure.q GetInterruptTime()
  !_GetInterruptTime_Repeat_Start:
   !MOV edx,dword [2147352584+4]
   !MOV eax,dword [2147352584]
   !MOV ecx,dword [2147352584+8]
   !CMP edx,ecx
   !JNE _GetInterruptTime_Repeat_Start
  ProcedureReturn
 EndProcedure
CompilerElse
 Procedure.q GetInterruptTime()
  !MOV qword rdx,2147352584
  !_GetInterruptTime_Repeat_Start:
   !MOVSXD rax,dword [rdx+4]
   !MOVSXD rbx,dword [rdx]
   !MOVSXD rcx,dword [rdx+8]
   !CMP rax,rcx
   !JNE _GetInterruptTime_Repeat_Start
  !SAL rax,32
  !ADD rax,rbx
  ProcedureReturn
 EndProcedure
CompilerEndIf

Define systime.q
SetTimerResolution(5000)
;timeBeginPeriod_(1)
Delay(16)
Define n.i,start.q,stop.q
For n=1 To 10
 Repeat
  start=GetInterruptTime()
  Delay(0)
  stop=GetInterruptTime()
 Until (stop-start)>0
 Debug StrD((stop-start)/10000.0,4)+" ms."
Next
SetTimerResolution(0)
;timeEndPeriod_(1)
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4945
Joined: Sun Apr 12, 2009 6:27 am

Re: GetInterruptTime(), Win NT, x86 & x64

Post by RASHAD »

@Rescator
You are crazy you know that
But keep digging and come back with your weird informations
And as SFSxOI said and we will find some use of it

Here is my findings:
Intel Cpu
1- XP x32 156250
2- Win 7 x32/x64 156000
3- Vista x32 10000

Now if milan1612 can give us more detail @ his findings it will help

have fun
Egypt my love
milan1612
Addict
Addict
Posts: 894
Joined: Thu Apr 05, 2007 12:15 am
Location: Nuremberg, Germany
Contact:

Re: GetInterruptTime(), Win NT, x86 & x64

Post by milan1612 »

RASHAD wrote:Now if milan1612 can give us more detail @ his findings it will help
I compiled with PB 4.4 x86 on my Windows 7 x64 machine (Core2Duo 3.6GHz).
Windows 7 & PureBasic 4.4
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4945
Joined: Sun Apr 12, 2009 6:27 am

Re: GetInterruptTime(), Win NT, x86 & x64

Post by RASHAD »

1- milan1612 interrupt timing @ 0.5 of XP & windows 7 78125 = 0.5 * 156250
Is that mean that the code can not differs bet. CPU type ?

2- Ms came back to XP interrupt timing
is that give us some idea why Vista is very slow?
Vista interrupt timing 10000 while win 7 156000
Egypt my love
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: GetInterruptTime(), Win NT, x86 & x64

Post by Rescator »

Hmm. your Vista x32 has 10000 res? That would mean 1ms timings, something in the system must have used timeBeginPeriod_() as Windows 5.x/6.x has 156xxx as default.
Media Player on Vista seems to use timeBeginPeriod_(5) which would be a res of 50000.
PS! Make sure you don't hae a browser open with Flash in it, Adobe's flash has a bad habit of setting timeBeginPeriod_(1) always forcing the entire system into 1ms timing and thus 10000 res timer. Despite just displaying a Flash based menu or ad. *sigh*

Take a Look at Larry Ostermans's blog post: http://blogs.msdn.com/larryosterman/arc ... ttime.aspx
A bit down you'll find:
Thursday, September 03, 2009 9:33 AM by LarryOsterman

Adam: calling timeBeginPeriod increases the accuracy of GetTickCount as well.

using timeBeginPeriod is a hideously bad idea in general - we've been actively removing all of the uses of it in Windows because of the power consumption consequences associated with using it.

There are better ways of ensuring that your thread runs in a timely fashion.
:shock:
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4945
Joined: Sun Apr 12, 2009 6:27 am

Re: GetInterruptTime(), Win NT, x86 & x64

Post by RASHAD »

Yes you are right it could be CD virtual drive
Now the timing is 156000
Egypt my love
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: GetInterruptTime(), Win NT, x86 & x64

Post by SFSxOI »

So heres a stupid question; is 156000 better then 10000 and how do you know what your seeing is correct? Then which configuration of the code is correct for use? Rescator got different timings by rearranging the code where he said > "So on my system the example below returns 156000 (15.6ms) and 156001, and if I un-comment the timeBeginPeriod and timeEndPeriod lines the timer/interrupt resolution increases and I get 10000 (1ms) and 10001." so how do you know which one is correct?
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: GetInterruptTime(), Win NT, x86 & x64

Post by Rescator »

Lower value means more frequent interrupt.
15600=15.6ms and 10000=1ms, rather simple really.
As to the flutter with the +1 it's probably due to my system, if I use CPU-Z I can see the CPU GHz timings slightly fluctuate, maybe there is 1/100 nanosec drift in the RTC, or the CPU updated the memory value inbetween timer cycles (or something) I got no idea really.

As to how do I know what I see is correct? Because Windows and a ton of kernel drivers read the exact same value the way I do :P
You can find info about the user shared memory in the um.. NTDDK (NT Driver Development Kit I believe it's called) the kernel driver SDK.

This is BTW the tightest code possible to get a timer value:

Code: Select all

Global *GetInterruptTime.Quad=$7FFE0008
Macro GetInterruptTime()
 *GetInterruptTime\q
EndMacro

Define s1.q,s2.q,s.q

;s will equal aprox 10000000 which is the same as 1 second. And 10000 is the same as 1ms.
s1=GetInterruptTime()
Delay(1000)
s2=GetInterruptTime()
s=s2-s1
Debug s
Note! As mentioned previously this will only work on NT (4.x, 5.x and 6.x) so don't use this on Win9x.
PS! If you do timings narrower than 4minutes apart you could even get away with changing the .Quad and \q to .Long and \l
(a long can hold around 3.8minutes of interrupts at 0.5ms period smallest timer resolution possible on NT, but using the full quad is safer and more convenient, lasts 30000+ years before wrapping too :P )
This timer value is also unaffected by system time/clock changes, unaffected by the number of cores, unaffected by power savings as far as I know. This is as good as it gets besides hitting the RealTimeClock hardware directly.

For those interested info on the SHARED_USER_DATA structure can be found in the WDK at:
http://www.microsoft.com/downloads/deta ... 5b52da3d00
Here's the structure converted for PureBasic (I think I managed to convert it ok, it was rather messy with all those unions)

Code: Select all

#MM_SHARED_USER_DATA_VA=$7FFE0000

Structure KSYSTEM_TIME
 LowPart.l
 High1Time.l
 High2Time.l
EndStructure

#PROCESSOR_FEATURE_MAX=64
#MAX_WOW64_SHARED_ENTRIES=16
#MAXIMUM_XSTATE_FEATURES=64

Structure XSTATE_FEATURE
 Offset.l
 Size.l
EndStructure

Structure XSTATE_CONFIGURATION
 ;Mask of enabled features
 EnabledFeatures.q
 ;Total size of the save area
 Size.l
 OptimizedSave.l
 ;List of features
 Features.XSTATE_FEATURE[#MAXIMUM_XSTATE_FEATURES]
EndStructure

Structure KUSER_SHARED_DATA
 ;Current low 32-bit of tick count and tick count multiplier.
 ;N.B. The tick count is updated each time the clock ticks.
 TickCountLowDeprecated.l
 TickCountMultiplier.l
 ;Current 64-bit interrupt time in 100ns units.
 InterruptTime.KSYSTEM_TIME
 ;Current 64-bit system time in 100ns units.
 SystemTime.KSYSTEM_TIME
 ;Current 64-bit time zone bias.
 TimeZoneBias.KSYSTEM_TIME
 ;Support image magic number range for the host system.
 ;N.B. This is an inclusive range.
 ImageNumberLow.w
 ImageNumberHigh.w
 ;Copy of system root in unicode.
 NtSystemRoot.w[260]
 ;Maximum stack trace depth if tracing enabled.
 MaxStackTraceDepth.l
 ;Crypto exponent value.
 CryptoExponent.l
 ;Time zone ID.
 TimeZoneId.l
 LargePageMinimum.l
 Reserved2.l[7]
 ;Product type.
 NtProductType.l
 ProductTypeIsValid.b
 ;three bytes of padding here -- offsets 0x269, 0x26A, 0x26B
 ProductTypeIsValidPad.b[3]
 ;The NT Version.
 ;N. B. Note that each process sees a version from its PEB, but if the
 ;      process is running with an altered view of the system version,
 ;      the following two fields are used to correctly identify the
 ;      version
 NtMajorVersion.l
 NtMinorVersion.l
 ;Processor features.
 ProcessorFeatures.b[#PROCESSOR_FEATURE_MAX]
 ;Reserved fields - do not use.
 Reserved1.l
 Reserved3.l
 ;Time slippage while in debugger.
 TimeSlip.l
 ;Alternative system architecture, e.g., NEC PC98xx on x86.
 AlternativeArchitecture.l
 ;four bytes of padding here -- offsets 0x2c4, 0x2c5, 0x2c6, 0x2c7
 AltArchitecturePad.l[1]
 ;If the system is an evaluation unit, the following field contains the
 ;date and time that the evaluation unit expires. A value of 0 indicates
 ;that there is no expiration. A non-zero value is the UTC absolute time
 ;that the system expires.
 SystemExpirationDate.q
 ;Suite support.
 SuiteMask.l
 ;TRUE if a kernel debugger is connected/enabled.
 KdDebuggerEnabled.b
 ;NX support policy.
 NXSupportPolicy.b
 ;two bytes of padding here -- offsets 0x2d6, 0x2d7
 Padding1.b[2]
 ;Current console session Id. Always zero on non-TS systems.
 ActiveConsoleId.l
 ;Force-dismounts cause handles to become invalid. Rather than always
 ;probe handles, a serial number of dismounts is maintained that clients
 ;can use to see if they need to probe handles.
 DismountCount.l
 ;This field indicates the status of the 64-bit COM+ package on the
 ;system. It indicates whether the Itermediate Language (IL) COM+
 ;images need to use the 64-bit COM+ runtime or the 32-bit COM+ runtime.
 ComPlusPackage.l
 ;Time in tick count for system-wide last user input across all terminal
 ;sessions. For MP performance, it is not updated all the time (e.g. once
 ;a minute per session). It is used for idle detection.
 LastSystemRITEventTickCount.l
 ;Number of physical pages in the system. This can dynamically change as
 ;physical memory can be added or removed from a running system.
 NumberOfPhysicalPages.l
 ;True if the system was booted in safe boot mode.
 SafeBootMode.b
 ;The following byte is consumed by the user-mode performance counter
 ;routines to improve latency when the source is the processor's cycle
 ;counter.
 TscQpcData.b
 ;two bytes of padding here -- offsets 0x2ee, 0x2ef
 TscQpcPad.b[2]
 ;This is a packed bitfield that contains various flags concerning
 ;the system state. They must be manipulated using interlocked
 ;operations.
 SharedDataFlags.l
 DataFlagsPad.l[1]
 ;Depending on the processor, the code for fast system call will differ,
 ;Stub code is provided pointers below to access the appropriate code.
 ;N.B. The following two fields are only used on 32-bit systems.
 TestRetInstruction.q
 SystemCall.l
 SystemCallReturn.l
 SystemCallPad.q[3]
 ;The 64-bit tick count.
 TickCountQuad.q
 TickCountPad.l[2]
 ;Cookie for encoding pointers system wide.
 Cookie.l
 CookiePad.l[1]
 ;Client id of the process having the focus in the current
 ;active console session id.
 ConsoleSessionForegroundProcessId.q
 ;Shared information for Wow64 processes.
 Wow64SharedInformation.l[#MAX_WOW64_SHARED_ENTRIES]
 ;The following field is used for ETW user mode global logging
 ;(UMGL).
 UserModeGlobalLogger.w[16]
 ;Settings that can enable the use of Image File Execution Options
 ;from HKCU in addition to the original HKLM.
 ImageFileExecutionOptions.l
 ;Generation of the kernel structure holding system language information
 LangGenerationCount.l
 ;Reserved.
 Reserved5.q
 ;Current 64-bit interrupt time bias in 100ns units.
 InterruptTimeBias.q
 ;Current 64-bit performance counter bias in processor cycles.
 TscQpcBias.q
 ;Number of active processors and groups.
 ActiveProcessorCount.l
 ActiveGroupCount.w
 Reserved4.w
 ;This value controls the AIT Sampling rate.
 AitSamplingValue.l
 AppCompatFlag.l
 ;Relocation diff for ntdll (native and wow64).
 SystemDllNativeRelocation.q
 SystemDllWowRelocation.l
 ;Extended processor state configuration
 XStatePad.l[1]
 XState.XSTATE_CONFIGURATION
EndStructure

Define *KUSER_SHARED_DATA.KUSER_SHARED_DATA=#MM_SHARED_USER_DATA_VA

Debug "NT "+Str(*KUSER_SHARED_DATA\NtMajorVersion)+"."+Str(*KUSER_SHARED_DATA\NtMinorVersion)
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: GetInterruptTime(), Win NT, x86 & x64

Post by Rescator »

Just to round off all this timing madness, and kinda show why I think all this is so damn cool:
Why don't we roll our very own Do It Yourself timeGetTime_() and GetTickCount_() ?

I'm gonna show you how those two API's fetch and present their time.

Code: Select all

Procedure.l DIY_timeGetTime()
Protected result.q,*GetInterruptTimer.Quad=$7FFE0008
 result=(*GetInterruptTimer\q/10000)
 ProcedureReturn result
EndProcedure

Procedure.l DIY_GetTickCount()
Protected result.q,*GetTickCount.Long=$7FFE0320,MinimumResolution.l,MaximumResolution.l,CurrentResolution.l
 NtQueryTimerResolution_(@MinimumResolution,@MaximumResolution,@CurrentResolution)
 result=(*GetTickCount\l*MinimumResolution)/10000
 ProcedureReturn result
EndProcedure

Procedure.q DIY_GetTickCount64()
Protected result.q,*GetTickCount.Quad=$7FFE0320,MinimumResolution.l,MaximumResolution.l,CurrentResolution.l
 NtQueryTimerResolution_(@MinimumResolution,@MaximumResolution,@CurrentResolution)
 result=(*GetTickCount\q*MinimumResolution)/10000
 ProcedureReturn result
EndProcedure

start.l=DIY_timeGetTime()
Delay(1000)
stop.l=DIY_timeGetTime()
Debug stop-start

start.l=DIY_GetTickCount()
Delay(1000)
stop.l=DIY_GetTickCount()
Debug stop-start

;Don't believe it? Check this out...
Debug ""
api.l=timeGetTime_()
ours.l=DIY_timeGetTime()
Debug ours
Debug api

Debug ""
api.l=GetTickCount_()
ours.l=DIY_GetTickCount()
Debug ours
Debug api
;Ok it may not have been a perfect match, but it should be damn close.
;Obviously I have no idea how the source of the API is, and I didn't try to dissassemble Windows :)
;I'm a bit unsure if GetTickCount retrieve the resolution modifier the way I do it here.
;But in any case, now you know where these two API's get their numbers ;)
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: GetInterruptTime(), Win NT, x86 & x64

Post by SFSxOI »

Rescator wrote:Lower value means more frequent interrupt.
15600=15.6ms and 10000=1ms, rather simple really.
As to the flutter with the +1 it's probably due to my system, if I use CPU-Z I can see the CPU GHz timings slightly fluctuate, maybe there is 1/100 nanosec drift in the RTC, or the CPU updated the memory value inbetween timer cycles (or something) I got no idea really.

As to how do I know what I see is correct? Because Windows and a ton of kernel drivers read the exact same value the way I do :P
You can find info about the user shared memory in the um.. NTDDK (NT Driver Development Kit I believe it's called) the kernel driver SDK.

Well, yes, of course, but thats not what I really meant, I just didn't say it correctly. sorry :)

What I mean is; the differences between the two times you got as a result of either commenting or uncommenting the code like you did, how do you know that what your seeing as a result of doing that which value is correct for some type of use (where ever such a thing might be used)? How do you determine when and where one rendition/form of the code is, or would be, used over another?
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: GetInterruptTime(), Win NT, x86 & x64

Post by Rescator »

timeBeginPeriod_()
http://msdn.microsoft.com/en-us/library ... 85%29.aspx

http://msdn.microsoft.com/en-us/library ... 85%29.aspx
Wait Functions and Time-out Intervals

The accuracy of the specified time-out interval depends on the resolution of the system clock. The system clock "ticks" at a constant rate. If the time-out interval is less than the resolution of the system clock, the wait may time out in less than the specified length of time. If the time-out interval is greater than one tick but less than two, the wait can be anywhere between one and two ticks, and so on.

To increase the accuracy of the time-out interval for the wait functions, 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.
And as for NtSetTimerResolution and NtGetTimerResolution they are Native NT functions, mostly used by Windows internally and other some services as well I guess.
More info here: http://technet.microsoft.com/en-us/sysi ... 97569.aspx
As far as experts go Mark is one of "the" experts on Windows internals ;)

And about the "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."
best practice these days is to only use these when you need them. Take Foorbar2000, it uses timeBeginPeriod (or Vista triggers it) when it starts playback, and then does timeEndPeriod whhen playback is stopped. Changing the timer resolution from "normal" 15.6xx ms to 1 ms.

Then again Larry Osterman says that they are working hard to get rid of any timeBeginPeriod and timeEndPeriod from within Windows.

So for example in my project GridStream Player I'm currently tossing out any use of that, I've reduced the amount of Delay() used throughout the program,
and I'm using PB 4.40's new Timers only and thus able to use a WaitWindowEvent() without any timeout at all, making the bulk of the program event or pull driven instead of poll driven.
The only polling left is the graphic updating of the Loudness meter which is limited to the monitor refresh rate as max and user adjustable down to about 20FPS.
And instead of using timeGetTime to fetch the timercycle I now use my tiny macro seen in the post a little further above, it takes around 800% less time to execute vs timeGetTime, and it's accuracy or precision is the same as or slightly better. Only downside is it's NT only, but since I only support NT 5.x and later anyway this is not an issue.

Windows 7 introduces pull behavior, where the audio driver/hardware/card asks the system and thereby the application to provide more audio, it's mandatory in Win7 certified drivers, in Vista it's optional if I recall. I'm hoping that Ian (programmer of BASS audio library) will be able to utilize this on Win7 fully. In which case it would be possible to make a fully event and pull driven app which is the ideal goal.
User avatar
Demivec
Addict
Addict
Posts: 4257
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: GetInterruptTime(), Win NT, x86 & x64

Post by Demivec »

Rescator wrote:I'm gonna show you how those two API's fetch and present their time.
In your example code DIY_timeGetTime() returns good results but DIY_GetTickCount() always returns 0. I'm using Windows XP.
Post Reply