Some time ago, I noted that There is a std::, but no low_.
The Visual C++ library treats std:: as an alias for std::, which uses QueryÂPerformanceÂCounter() to retrieve the current time, and the multiplies it by the reciprocal of QueryÂPerformanceÂFrequency() to convert it to a clock tick count. So you are paying for a multiplication after QueryÂPerformanceÂCounter() returns.
But there’s a lot going on inside QueryÂPerformanceÂCounter() itself, too. It has to use a different algorithm depending on things like whether the timestamp counter (such as RDTSC on x86 or CNTVCT_EL0 on AArch64) is reliable, whether the system is running inside a virtual machine, whether the process is running under emulation, and various other conditions. In the worst case, it needs to make a system call into the kernel.
On the other hand, GetÂTickÂCount64() merely reads two 64-bit values from memory and multiplies them. One is a raw value that is updated by the kernel at each system timer interrupt (worst case), and the other is a conversion factor calculated at system startup to convert the raw value into milliseconds.
These two 64-bit values come from a special page that is mapped into user mode from kernel mode that contains handy values, including the current tick count. As it turns out, this is significantly faster than going through all the logic of QueryÂPerformanceÂCounter. It’s a great choice if you do not need high resolution.
And deciding how long to sleep a thread is a case where you do not need high resolution. Most of the functions for sleeping a thread already operate in milliseconds, so getting the value in milliseconds saves you a lot of conversions. Calculating values with sub-millisecond accuracy is pointless if the result is going to be converted to milliseconds anyway. And the accuracy of most (all?) of these sleep functions is only as good as the system timer anyway, so really they are good to only 10 or 50 milliseconds.¹
It’s like doing precise calculations to determine that you need to set your phone alarm to wake you in exactly 32 minutes, 21.1315 seconds. Your phone alarm can’t wake you to sub-second resolution, so all that work to calculate those extra .1315 seconds was wasted.
Now, I didn’t know all of these details when I originally wrote that article. But it stands to reason that GetÂTickÂCount64 is a lot cheaper than QueryÂPerformanceÂCounter because GetÂTickÂCount64 asks for less. Even if GetÂTickÂCount64 ends up not being faster than QueryÂPerformanceÂCounter, it surely won’t be slower.
¹ Or one millisecond if your process has called timeBeginPeriod(1) to ask that the system timer be sped up to 1 millisecond.
Does original GetTickCount (32 not 64) do a multiplication? I always thought of it as a straight-up atomic read of a DWORD from the TEB ..
I also (maybe mistakenly) thought it was updated by the kernel thread scheduler any time control was being given to a thread .. so eg. in response to waking a WaitForSingleObject() or ResumeThread() .. or returning from Sleep() or executing an APC or whatever else.
I realize now I have so many questions .. assumptions I never tested. Do all threads in a process have a coherent view of the tick-count?...
I’ve looked into it before, and timeBeginPeriod doesn’t affect modern wait APIs like WaitOnAddress or SRWLock, which always maintain a wait precision between 10 and 15 milliseconds. Another significant drawback of timeBeginPeriod is that it is not thread-bound, so if multiple threads use it simultaneously, the results can lead to unexpected outcomes. Therefore, I believe it should no longer be used.
I’d never heard of timeBeginPeriod before so I looked it up. Alongside a general error it can also return TIMERR_NOCANDO which seems like a huge i18n fail to me. I mean, it’s not quite TIMERR_BOTTOM_OF_THE_NINTH_BASES_LOADED but how many non-US-English speakers are going to know what NOCANDO means? Why not just TIMERR_RESOLUTION_UNAVAILABLE?
So I looked this up and figured out "no can do" is actually a recognized slang, instead of pure grammar error. My take on this (as a non-US non-English-native-speaker English speaker): if one is unaware of "no can do" as a slang, one will recognize it as an erroneous form of "cannot do" and understand it; if one is aware of the slang, then of course one knows what it means.
My confusion about multimedia API is why most of its flat API (function exports instead of COM) are camelCase instead of PascalCase as is often the case in Windows. The...