Click here to Skip to main content
15,885,980 members
Home / Discussions / C / C++ / MFC
   

C / C++ / MFC

 
GeneralMessage Closed Pin
14-Mar-13 19:19
Robert Inventor14-Mar-13 19:19 
AnswerRe: timeGetTime() is unreliable on my computer too, not monotonic! Pin
Robert Inventor19-Mar-13 7:31
Robert Inventor19-Mar-13 7:31 
QuestionQueryPerformanceCounter inaccurate timing even with use of SetThreadAffinityMask Pin
Robert Inventor14-Mar-13 15:50
Robert Inventor14-Mar-13 15:50 
AnswerRe: QueryPerformanceCounter inaccurate timing even with use of SetThreadAffinityMask Pin
Robert Inventor14-Mar-13 18:07
Robert Inventor14-Mar-13 18:07 
GeneralRe: QueryPerformanceCounter inaccurate timing even with use of SetThreadAffinityMask Pin
dusty_dex15-Mar-13 0:24
dusty_dex15-Mar-13 0:24 
GeneralRe: QueryPerformanceCounter inaccurate timing even with use of SetThreadAffinityMask Pin
Robert Inventor18-Mar-13 14:44
Robert Inventor18-Mar-13 14:44 
GeneralRe: QueryPerformanceCounter inaccurate timing even with use of SetThreadAffinityMask Pin
dusty_dex18-Mar-13 22:08
dusty_dex18-Mar-13 22:08 
AnswerRe: QueryPerformanceCounter inaccurate timing even with use of SetThreadAffinityMask Pin
Robert Inventor19-Mar-13 6:19
Robert Inventor19-Mar-13 6:19 
Thanks that does explain one glitch I got with GetTickCount and timeGetTime.

With the HPC though after dealing with the core changing issues, then it wasn't doing any sudden big jumps. Just measuring the time wrong.

I'm doing this to measure musical notes. But I've found a solution at last Smile | :) .

The key was discovery of yet another MS Windows timing routine, KeQueryUnbiasedInterruptTime which looked like the type of precise timing I need, but unfortunately only accessible in kernel mode
KeQueryUnbiasedInterruptTime[^]

However, then I found, that there is a little known structure called KUSER_SHARED_DATA which is added to the process address space of every user mode process at the address 0x7FFE0000 which is a system wide shared memory location. It is volatile, and gets updated with the kernel interrupt time continuously. This means that to check the kernel interrupt time, all you need to do is to look at the correct address location in your process address space.

This apparently is a hardware timer, not affected by changes in cycle rate of the processor cores. It might be using either the RTC or the HPET though I don't know which it is. And since it is just a memory look up then there is far less overhead involved than in any of the other timers used in Windows.

Combining this with the code I have already, which does a sleep that stops slightly short of the desired time followed by a busy wait time checking loop at real time time critical mode until the time is reached - and you get sub microsecond "sample perfect" timing of midi in Windows.

Here is the code:

C++
// Code modifed from  http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/base/md/i386/sim/_glue.c.htm

typedef struct _KSYSTEM_TIME 
{
 UINT32 LowPart;
 INT32 High1Time;
 INT32 High2Time;
} KSYSTEM_TIME, *PKSYSTEM_TIME;

typedef struct _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.
 */
 volatile ULONG TickCountLow;
 UINT32 TickCountMultiplier;

 /* Current 64-bit interrupt time in 100ns units. */
 volatile KSYSTEM_TIME InterruptTime;

 /* Current 64-bit system time in 100ns units. */
 volatile KSYSTEM_TIME SystemTime;

 /* Current 64-bit time zone bias. */
 volatile KSYSTEM_TIME TimeZoneBias;
} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA;

// NOTE the KUSER_SHARED_DATA structure has many extra fields which have been added over time.
// see http://uninformed.org/index.cgi?v=2&a=2&p=15
// So the declaration of the structure here is incomplete but is maximally backwards compatible.

#define MM_SHARED_USER_DATA_VA      0x7FFE0000
#define USER_SHARED_DATA ((KUSER_SHARED_DATA * const)MM_SHARED_USER_DATA_VA)


double dInterruptTimer(void)
{
 // returns the interrupt time in ms - time since the operating system was last started.
 // not including times in sleep or hibernation. I think this is probably the same
 // time as the time returned by KeQueryUnbiasedInterruptTime 
 // See http://msdn.microsoft.com/en-gb/library/windows/hardware/ff553077(v=vs.85).aspx
 union 
 {
  KSYSTEM_TIME SysTime;
  __int64 CurrTime;
 } ts;
 ts.SysTime.High1Time = USER_SHARED_DATA->InterruptTime.High1Time;
 ts.SysTime.LowPart   = USER_SHARED_DATA->InterruptTime.LowPart;
 return ts.CurrTime/(double)10000;
}


I got this by modifying source code available here

_glue.c[^]

which is part of Microsoft's "Invisible computing" real time operating system also known as MMLite. Microsoft Invisible Computing[^]

So it is documented Microsoft code and not just a hack using undocumented structures. It requires Windows NT or later.

This is an actual recording made in real time using my program to play the notes via midi on the Microsoft GS Wavetable synth:

This is a test of the use of the Windows interrupt timer to time notes in Bounce Metronome.[^]

Here is a screen shot of the recording where you can see the sample precise alignment of the notes. You can tell it is sample precise because all the details of the waveform are exactly the same - all the irregularities that you get which will look slightly different if you move the waveform by a sample or so and then look at it zoomed out like this.

screen shot of recording with sample precise timing[^]

This also seems like a great way to do performance testing too, without all that averaging we are used to, and with almost no overhead.
GeneralRe: QueryPerformanceCounter inaccurate timing even with use of SetThreadAffinityMask Pin
dusty_dex19-Mar-13 8:34
dusty_dex19-Mar-13 8:34 
GeneralRe: QueryPerformanceCounter inaccurate timing even with use of SetThreadAffinityMask Pin
Robert Inventor20-Mar-13 10:10
Robert Inventor20-Mar-13 10:10 
GeneralRe: QueryPerformanceCounter inaccurate timing even with use of SetThreadAffinityMask Pin
Robert Inventor20-Mar-13 11:12
Robert Inventor20-Mar-13 11:12 
GeneralRe: QueryPerformanceCounter inaccurate timing even with use of SetThreadAffinityMask Pin
dusty_dex20-Mar-13 11:18
dusty_dex20-Mar-13 11:18 
GeneralRe: QueryPerformanceCounter inaccurate timing even with use of SetThreadAffinityMask Pin
Robert Inventor20-Mar-13 12:15
Robert Inventor20-Mar-13 12:15 
QuestionHelp in Win32 programming with c++ Pin
naseer86114-Mar-13 8:44
naseer86114-Mar-13 8:44 
AnswerRe: Help in Win32 programming with c++ Pin
NotPolitcallyCorrect14-Mar-13 8:50
NotPolitcallyCorrect14-Mar-13 8:50 
GeneralRe: Help in Win32 programming with c++ Pin
naseer86118-Mar-13 9:41
naseer86118-Mar-13 9:41 
AnswerRe: Help in Win32 programming with c++ Pin
Maximilien14-Mar-13 8:54
Maximilien14-Mar-13 8:54 
AnswerRe: Help in Win32 programming with c++ Pin
Captain Price16-Mar-13 2:55
professionalCaptain Price16-Mar-13 2:55 
QuestionNeed a free image library, png, Visual Studio 6.0 Pin
Andrlage14-Mar-13 5:52
Andrlage14-Mar-13 5:52 
AnswerRe: Need a free image library, png, Visual Studio 6.0 Pin
Richard MacCutchan14-Mar-13 6:22
mveRichard MacCutchan14-Mar-13 6:22 
AnswerRe: Need a free image library, png, Visual Studio 6.0 Pin
_Flaviu14-Mar-13 21:19
_Flaviu14-Mar-13 21:19 
QuestionMSCOWRKS.DLL ? Pin
ForNow13-Mar-13 3:10
ForNow13-Mar-13 3:10 
AnswerRe: MSCOWRKS.DLL ? Pin
Richard MacCutchan13-Mar-13 3:53
mveRichard MacCutchan13-Mar-13 3:53 
GeneralRe: MSCOWRKS.DLL ? Pin
ForNow13-Mar-13 4:12
ForNow13-Mar-13 4:12 
AnswerRe: MSCOWRKS.DLL ? Pin
Albert Holguin13-Mar-13 5:33
professionalAlbert Holguin13-Mar-13 5:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.