What QueryPerformanceCounter actually does is up to the HAL (with some help from ACPI). The performance folks tell me that, in the worst case, you might get it from the rollover interrupt on the programmable interrupt timer. This in turn may require a PCI transaction, which is not exactly the fastest thing in the world. It's better than GetTickCount, but it's not going to win any speed contests. In the best case, the HAL may conclude that the RDTSC counter runs at a constant frequency, so it uses that instead. Things are particularly exciting on multiprocessor machines, where you also have to make sure that the values returned from RDTSC on each processor are consistent with each other! And then, for good measure, throw in a handful of workarounds for known buggy hardware.
I've haven't worked with any of the performance counters before, but had always thought they dealt with 'timing' functions until I ran across the reference below:
Dim m1 As Currency, m2 As Currency
If m_TimerOK Then
QueryPerformanceFrequency m_Frequency
QueryPerformanceCounter m1
QueryPerformanceCounter m2
Else
m1 = GetTickCount()
m2 = GetTickCount()
End If
m_Overhead = m2 - m1
(iii) In the subroutine "GetTimeElapse", validate the result a bit, e.g.
Dim mDiff As Double
If m_TimerOK Then
QueryPerformanceCounter m_End
mDiff = (m_End - m_Start - m_Overhead) / m_Frequency
GetTimeElapse = mDiff
Else
m_End = GetTickCount
GetTimeElapse = (m_End - m_Start - m_Overhead) / 1000
End If
If GetTimeElapse < 0 Then
m_End = m_Start
GetTimeElapse = 0
Else
GetTimeElapse = Round(GetTimeElapse, inRound)
End If
dilettante's OldNewThing link is great, but be sure to note the date of publication. After reading it (it's short and good!), I'd recommend this MSDN article to fill the gap between 2005 and now:
That article provides painstaking details on how Windows handles timing measurements, including changes across Windows versions. Assuming you're running Windows 7 or later, the situation is much better than it used to be (e.g. QPC functions have much lower latency). As the article says:
QPC is typically the best method to use to time-stamp events and measure small time intervals that occur on the same system or virtual machine
dilettante - Thanks for the Precision and accuracy link. Man, I didn't even know there was a animation / multimedia timer available, I'm gonna have to check that out and possibly go back to some of my code and make some changes.
Brenker, I appreciate the code example, but I've got that voice in the back of my head saying things like just executing a few extra lines of code seems like it would upset the precision of these PerformanceCounters.
Tanner, that's some link on time-stamps! I've had to re-read parts of it a couple of times. I had no idea timing got so involved.
Perhaps I should take a step back here and explain what's going on.
The project is a Data Acquisition System collecting real-time measurements through custom hardware. The data is being processed / filtered before written to disk. Standard disks couldn't keep up and were replaced with pricey high-performance versions, and then just recently upgraded to Solid State Drives.
The data is buffered before stored, but this only helps with sporadic bursts of data, consistently high data rates are overflowing the buffers and data is being lost.
Nobody seems to have any reliable or accurate numbers when it comes to the true I/O rates when one includes the OS overhead, Mother board I/O bus speeds, SATA I/O rates and finally the SSD I/O speed. There are bottle necks here and there depending on motherboards, disk architecture & interface. I'm planning on swapping out the current SATA SSD with a BUS interfaced SSD.
Before I even got started with trying to calculate any numbers, I wanted to know the best method for setting up accurate timers. When it comes to the disk I/O, the numbers aren't nearly as fast or critical as the speed of the raw data coming in during peek I/O periods. This is where accurate timers are going to be needed, however the disk will most likely always be the ultimate bottle neck.
To track the DAQ I/O rate I'll be needing an accurate timer and this is where I thought of using the PerformanceCounters, but I wasn't sure if this was overkill.
To track the DAQ I/O rate I'll be needing an accurate timer and this is where I thought of using the PerformanceCounters, but I wasn't sure if this was overkill.
I would definitely use timeGetTime / multimedia timers for measuring real world data.
I'm not sure that there's anything "overkill" about QPC timers, stuck-in-past. They are very simple API calls. They also don't suffer the resolution or rollover issues of timeGetTime(), or require you to mess with system-wide settings (like timeBeginPeriod() does). timeGetTime() has a primary benefit of being very regular/predictable, not necessarily very accurate, which as dilettante said makes them a good fit for animation. See also Larry Osterman's blog about this, and perhaps this related post.
But those multimedia timers were built in a different era (pre-XP!), when QPC was unreliable because hardware didn't report timing in a standard way. On modern hardware, these concerns no longer exist. As Larry says in that blog post linked above:
The time* APIs are a set of 7 APIs built into the windows multimedia extensions (winmm.dll). They provide a rudimentary set of timer functions for Windows applications. At this point, except for two of the APIs, they exist only for historical purposes, the core OS now provides significantly higher quality APIs for timers.
If you need timing measurements that are synchronized to some "absolute" source, the MSDN page on high-resolution timers suggests GetSystemTimePreciseAsFileTime() as an alternative. Note that it does require Win 8 or later, however.
Thanks for all of the help, I'm getting some good numbers tracking the raw input data, but have questions about the file sub-system and when if flushes it's internal buffers.
I seem to be getting confusing numbers which are not always consistent when dealing with disk I/O. I need to clarify things here just a bit, as I'm being extremely 'picky' attempting to get some very exact values. My first thought was that the system is flushing buffers at different times depending on the flow of data being saved as the I/O rates happen to be fluctuating here and there.
I started looking into writing to the disk using different API's, attempting to flush buffers on my own when I ran across the DeviceIoControl function using the IOCTL_DISK_PERFORMANCE parameter. It looked like this might do some of the work for me, as it's tracking I/O data rates, it should be aware of when it's own buffers are being flushed resulting in more accurate numbers then what I would be able to come up with. But I can't seem to get the code to work.
It's not all that complicated consisting of two main calls, CreateFile which is working, and then the call to DeviceIoControl, which is failing. It returns with a DLL error code of 31 with the unusual description of: "A device attached to the system is not functioning."
I've made calls to CreateFile before, but it's my first encounter with DeviceIoControl and I don't seem to be able to get it working.
Last edited by stuck-n-past; Nov 17th, 2017 at 08:38 AM.