QT timing accuracy
-
I have a GUI application which display values as recieved from three serial ports (multithread)
these values are logged into a file, the function that responsible of logging the file is called every time the timer (QTimer) timeouts (timer is set to 40ms)when the function is ran alone the timing between entries is accurate with a +/-2ms difference
but when all the serial ports are working then the timing between the entries varies ALOT and its not
even constant with a 30 to 60ms difference!!!by the way the function is called from the GUI thread itself
-
Hi,
a timer just creates an "event" in the event loop and this will be handled if the thread returns to the event loop. It will not interrupt anything and will not change the loop entries. So if the main loop is busy and 5 events are waiting, and then the timer emits then the timer is the 6. event in the queue and will be handled after the 5 others.
SO if your serial ports put a lot of work to the main thread, it's clear why it is not accurate.
-
See also "this":http://developer.qt.nokia.com/forums/viewthread/5904/ and "this":http://developer.qt.nokia.com/forums/viewthread/8098 thread.
-
I suggest you start by re-evaluating the requirements you started this topic with: do you really need to write out a file at precise 40ms intervals? Also: considder the disk might be bussy for another process (it is a shared resource, after all): how do you expect to handle that case?
-
Andre is right, the largest bottle-neck will be i/o, you may need to create another thread that writes buffered logs to the file. only problem with this solution is that if the process crashes you will lose the buffered log waiting to be written to the disk.
I know under Windows you can use Windows Management Instrumentation (WMI) to write logs to the disk, the OS will buffer for you and if the process crashes the OS will make sure all buffered logs are saved to file. However this is not a QT solution and I am not sure what similar solutions exist for other OSes.
-
And timer are never accurate on desktop OSes, they might be more or less accurate regarding event trigger but they are often just added to the event queue as the thread iscurrently working. The only other chance would be to have a thread for the timer which does nothing other then waiting for the timer. But even then, it is a thread that must be waken up, which is never accurate...
-
Understanding of multithreading is a key to solve this problem.
Operational system is the first to handle every running thread, and user/programmer - only the second. OS adjusts priority for each thread, processor core to run and piece of processor core time to run this process.
And what does it mean for current problem? Timer you adjusted is running within a thread (it's not a some type of OS kernel features). And this thread (and timer!) is running within OS-defined pieces of time. You can't maintain needed resolution for timer if OS gives only a few ms for your process.
The solution here is to monopolize a processor time for this task. You can
- shift process priority to higher/highest one (but in my cases it haven't been working in windows)
- make something like this (winapi, but i hope you'll understand the main idea of using sleep 0):
@LARGE_INTEGER liFrequency, liTickCount, liDiffTickCount;
QueryPerfomanceFrequecy(&liFrequency);
...
QueryPerfomanceCounter(&liTickCount);
liDiffTickCount.QuadPart = liTickCount.QuadPart + liTickCount / TIMER_DELAY;
do {
QueryPerfomanceCounter(&liTickCount);
Sleep(0);
} while (liDiffTickCount.QuadPart > liTickCount.QuadPart )
...@ -
On Windows (and other non-hard-realtime kernels) there will be always jitter, no matter how sophisticated your multithreaded design is.
I have to disagree with the example in the previous post. Combine the polling approach with highest thread priority and your application will massivly burn CPU time (which could have been spent doing some useful work). You might get slightly more accuracy but querying the performance counter doesn't help much if your thread is suspended anyways.
I think the best approach would be to store the values in memory instead. This will provide the most accurate timestamps as it is the fastest and most exclusive storage available. Transfer the data from memory to disk at reasonable intervals (I think of seconds here, not milliseconds). If you want to make sure your data has been written to disk don't forget to flush.
If you need failsafe logging or guaranteed response times for generating exact timestamps Windows is not the way how to do it anyways.