processEvents slows down USB communication?
-
I am writing an application to program an SPI flash over a FTDI USB-to-serial chip. The USB frames are created by the ftdi dll that I load dynamically on startup.
I am using QCoreApplication::processEvents() to update my user interface while in the loop of writing new data to the flash. I added time measurments with QElapsedTimer to debug the slow writing speed. I noticed that the first 1-2 seconds in the loop the subroutines to write 256 bytes are quite fast with 7 ms run time. After that the speed drops to 43 ms execution time.
I confirmed this behavior with my oscilloscope. In the fast case individual SPI commands are spaced with a delay of 2 ms (which is a quirk of FTDI when controlling the chip-select signal). In the slow case the SPI commands are spaced 12-15ms apart so there are at least 10ms extra delay.
Than I noticed a really strange phenomenon: when I move the cursor over an element in my UI like buttons or scroll bars the speed increases for about 1 second and then it gets slow again. If I shake my cursor the whole time over the UI I can keep the transfer speed high for minutes! Of course the time measurement does not include the run time of QCoreApplication::processEvents(), just the FTDI/SPI related lines. I can confirm this "workaround" by oscilloscope observations.
I tried to reduce the call of processEvents to every 100th spi-subroutine. It will start fast but than drop to the slow speed again. And just to be clear: every spi-subroutine is slow, not just the one before or after the processEvents call but all 100 in between.
When I delete the call of QCoreApplication::processEvents() my loop will finish writing the flash with high speed but the my UI freezes for minutes!So to me it seems like Qt has an issue with calling the library or maybe handling callbacks or some other threading stuff.
I tried to use the QEventLoop::ExcludeSocketNotifiers flag and setting a time limit for processing of the events but that hasn't changed anything.
Are there some alternatives to QCoreApplication::processEvents() that I can try which will keep my UI responsive but maybe solve the issue?
I know I can move the ftdi handling to a separate process but this would take a whole lot of rewriting because I have different classes for different flash types and I would need to load the dll in these classes if I want move them to another thread but I need the dll to identify the flash before I can create an object of the flash class. And than I would have to do ugly unloading and reloading and reconnecting to the ftdi... basically I would start from the scratch.
I have tested it with Qt 5.15, 5.14, 5.12 (MinGW-32).
-
@Scarab
As a general comment. Yes, frequent calls toprocessEvents()
do/can significantly slow down Qt UI performance.The simple answer is: don't use it! Design your application to use signals & slots within the normal paradigm of the provided top-level event loop. In general it should not be needed.
If you have a non-UI time-consuming/blocking operation to perform --- which I believe is what you are saying --- put it into its own non-UI thread. That keeps the UI thread "responsive". If you need to update the UI in response to data from the processing thread as it progresses, have it send a signal at appropriate points and have the UI thread with a slot for that signal which does UI updates when it is invoked.
-
yet people still try to shoehorn realtime tasks into desktop frameworks...[sighs and rolls eyes]
Never never never, (and did I mention never?) try to drive SPI from a userland application! SPI driver should always be a kernel module so that it can maintain a stable IO frequency. and FTDI serial in the middle greatly exaserbates the situation.