Qt5 hanging/crashing problems when window is not active (on MacOS)
-
We are using a QT5 program (most of which we inherited from other authors). We are encountering hangs with communications to this program if the window is not topmost. Even if it is on top, we have problems if their is too long an interval without any mouse movements on that machine. This is on a Mac running Mojave. We have turned off AppNap, and disabled all the display/cpu power saving and sleeping options. We need this program to not require user interactions for our use case. In some cases the program just hangs, and will restart once we move the mouse; at other times, we get the spinning wheel, and have to kill the program. The activity monitor may report the CPU time to be at (or above) 100%.
In this forum, I have found references to people reporting somewhat similar symptoms. Some seem to imply that this may be due to calling update repeatedly when the window is not active, so that a massive number of repaint events are being queued until the window is active again. Can anyone indicate whether detecting the loss of window focus, and disabling updates until once more active is likely to remedy this? (and I would greatly appreciate a code fragment for trapping the appropriate events (which I think may be from the QFocusEvent class - or do I want applicationStateChanged?).
Many thanks.
-
@aeszym Did you write this application? If so try to debug to see where it hangs or crashes, if not ask the developers of that application. There is clearly something wrong with the application. Also, you can try to search on Qt bug tracker https://bugreports.qt.io/secure/Dashboard.jspa
-
Any update on whether you resolved? I am having the same issue on MacOS Catalina with a C++ Qt5 application. It's also drawing a lot on the screen and after a long time of no mouse activity or losing top-level focus it hangs. Sometimes it recovers and sometimes it does not. Your theory about queueing internal events seems plausible - just curious if you confirmed and found a remedy. Thanks!
-
I have this same issue. Annecdotely, it seems to be exacerbated by having deeply nested UI elements (text element inside of horizontal layout inside of grid layout inside of...). Even after vastly simplifying my application and removing qCustomPlot objects and non-Qt libraries, I still see a major slow down and hang after the application is put in the background for a few minutes. The hang gets progressively longer the more time the app spends out of focus.
This issue occurs with and without AppNap disabled. When it occurs, macOS does not report the application is in AppNap mode. This issue is not seen on Windows or Linux, only macOS. I can reproduce it on:
macOS 10.15 (Catalina)
macOS 10.14 (Mojave)
macOS 10.13 (High Sierra)I have reproduced it on macOS 10.15 using Qt: 5.11.3, 5.13.2, 5.15.0.
I've made a slimmed down application based on my open source application. You can download the source here
The original application source (which includes qcustomplot, which you can test with as well) can be found hereSteps to reproduce:
- Compile source and run in release mode
- De-focus (ideally keep the refresh rate text visible) the application for several minutes (go watch some cat videos)
- Notice that the refresh rate has drastically dropped.
- Return focus to the app; it will hang for a few second (depending on how long it was de-focused).
-
Hi and welcome to devnet,
Which version of XCode are you using to build the application ?
-
@aeszym Like @jlgregg said I immediately thought of the app going into AppNap. I found that disabling options for app nap were no use for my issue. I needed to keep my code running in the background with code. The following worked for me...
[[NSProcessInfo processInfo] beginActivityWithOptions:NSActivityBackground reason:@"cos my app gets bruk in the background"];
-
Here's a quick look at Activity Monitor's sample process output while the app is hanging. Please note that I have not seen consistent sample output; that is, there seems be multiple places in Qt/QCore that are hanging.
Call graph: 2787 Thread_4621518 DispatchQueue_1: com.apple.main-thread (serial) + 2787 start (in libdyld.dylib) + 1 [0x7fff729d7cc9] + 2787 main (in HubTool) + 216 [0x104116c68] + 2787 QCoreApplication::exec() (in QtCore) + 130 [0x1056e1452] + 2787 QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) (in QtCore) + 431 [0x1056dc50f] + 2787 ??? (in libqcocoa.dylib) load address 0x104a5e000 + 0x33ccb [0x104a91ccb] + 2787 -[NSApplication run] (in AppKit) + 658 [0x7fff35ba358e] + 2787 -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] (in AppKit) + 3848 [0x7fff35bb2240] + 2787 objc_autoreleasePoolPop (in libobjc.A.dylib) + 175 [0x7fff71824dba] + 2787 AutoreleasePoolPage::releaseUntil(objc_object**) (in libobjc.A.dylib) + 134 [0x7fff71840054] + 2781 -[NSBitmapGraphicsContext dealloc] (in AppKit) + 59 [0x7fff35d40a8e] + ! 2781 -[NSCGSContext dealloc] (in AppKit) + 25 [0x7fff35d40aae] + ! 2780 -[NSCGSContext _invalidate] (in AppKit) + 44 [0x7fff35d40aff] + ! : 2778 _CFRelease (in CoreFoundation) + 189 [0x7fff38a0e568] + ! : | 2777 context_reclaim (in CoreGraphics) + 37 [0x7fff38d7482d] + ! : | + 2776 _CFRelease (in CoreFoundation) + 189 [0x7fff38a0e568] + ! : | + ! 2776 CGContextDelegateFinalize (in CoreGraphics) + 59 [0x7fff38d748c0] + ! : | + ! 2773 ripc_Finalize (in CoreGraphics) + 237 [0x7fff38d74a41] + ! : | + ! : 2773 RIPRemoveContextFromContextList (in CoreGraphics) + 40 [0x7fff38d7504e] + ! : | + ! : 2773 x_list_remove (in CoreGraphics) + 32,56,... [0x7fff38d74dec,0x7fff38d74e04,...] + ! : | + ! 1 free (in libsystem_malloc.dylib) + 0 [0x7fff72b8e9b1] + ! : | + ! 1 ripc_Finalize (in CoreGraphics) + 106 [0x7fff38d749be] + ! : | + ! : 1 free_tiny (in libsystem_malloc.dylib) + 459 [0x7fff72b92d8b] + ! : | + ! : 1 tiny_free_no_lock (in libsystem_malloc.dylib) + 1018 [0x7fff72b93279] + ! : | + ! : 1 tiny_free_list_remove_ptr (in libsystem_malloc.dylib) + 519 [0x7fff72b93fd6] + ! : | + ! 1 ripc_Finalize (in CoreGraphics) + 115 [0x7fff38d749c7] + ! : | + ! 1 _CFRelease (in CoreFoundation) + 460 [0x7fff38a0e677] + ! : | + ! 1 color_transform_retain_count (in CoreGraphics) + 93 [0x7fff38d60751] + ! : | + ! 1 color_transform_finalize (in CoreGraphics) + 87 [0x7fff38d74c73] + ! : | + ! 1 CGColorTransformBaseCacheRelease (in CoreGraphics) + 115 [0x7fff38d74d2b] + ! : | + ! 1 matches_space (in CoreGraphics) + 62 [0x7fff38d5a59c]
-
As for the AppNap topic, I have tried calling beginActivityWithOptions with NSActivityBackground, NSActivityUserInitiated, and NSActivityUserInitiated | NSActivityLatencyCritical at the start of the program and also around the various signals for updating the GUI thread with no effect on the hang. Any and all of these prevent actual AppNap, but as I noted, the program is not being napped when this hang occurs. The attached source (above) includes appNap.mm which sets NSActivityUserInitiated but calls to the "napper" object are commented out. You are welcome to experiment with those calls.
-
What value should the refresh rate have in normal execution ?
-
Short answer: the default is 20ms delay between calls to StemWorker::pollStemForChanges() which signals the GUI thread with updates. There are 100s of signals that get fired from this call at a rate of ~1 per millisecond. That is, almost every GUI element gets updated with signals from this function. So, the average update rate is around 10-15Hz, but there are spikes of calls which signal into GUI elements.
Longer answer: This GUI is a tool to interface with USB hardware. Most customers want "as fast as possible" refresh rates. There are multiple interactions with the USB hardware. Each interaction takes 1-2ms and result in the firing of 1-8 signals from the StemWorker thread to the GUI (HubTool) thread. In total, the hardware interactions take ~50ms total (this is for the function StemWorker::pollStemForChanges() to complete). The default setting is for the StemWorker::pollStemForChanges() to be triggered 20ms after the previous completion (see pollingTimer and HubTool::handlePollingFinished()). This delay is configurable by the user in the GUI as the "Polling Delay".
Reading into your question a bit, do you think it be better to "smooth out" the GUI update rate? That is, make it so the signals hit the GUI thread at a more consistent (and slower) rate? Since I'm not directly forcing an update() call in GUI thread, shouldn't Qt queue these updates and effectively smooth the update rate for me?
-
My question came because I did not notice a big drop so I did not know what I should be watching for.
As for the update, repainting will also depend on the hardware you use. You can't get faster than what your graphics card/screen combo allows. And you also have to think that the human eye still works at around 24fps so trying to update your numbers at high speed will not really make them more visible. Triggering meaningful updates will always be better, you'll perform well on a wider range of hardware.
-
The drop in refresh rate isn't the big concern, but it is a helpful indicator that something is getting "gummed up". The big concern is the hang on re-activating the app. After launching and backgrounding the application, wait for 10-15 minutes. I notice that the refresh rate slowly drops over this time. Then bring the application back to the foreground. You will get a beachball hang for several seconds. The length of the hang seems correlated to the amount of time in the app was in the background (not active).
I completely understand and agree with the reasonable limit on GUI update rate. The longer answer above mentions that there is hardware in the loop for this application. As such, the fastest average update rate to the GUI is about 20Hz (1/50ms). Most systems are closer to 10-15Hz average update rate to the GUI. The hang that occurs after the app is backgrounded/foregrounded does not seem to be impacted by this update rate; it only seems to depend on the amount of time the app is inactive.
Another thing to note is that I've purposely stripped down this application to aide in debugging this hang. While the update rate to the GUI shouldn't need to be faster than 10-15Hz, one use case for this app is as a simple data logger. As such, some users want to log data "as fast as possible". To do this, the signals coming from StemWorker::pollStemForChanges() are also connected to some plots via qCustomPlot objects. I originally suspected qCustomPlot the source of the hang, which is how I started to move towards the stripped down version of the app posted here. You can run the full version (even without the associated hardware) which is available in compiled binaries here with source here.
(and thanks for your input on this so far)
-
I am also facing this type of issue.
core dump is also there.
https://forum.qt.io/topic/120710/qml-c-crash-when-dialog-window-is-getting-opened-on-pressing-button-in-qt-application -
@btse Since there was no link to a bug report posted somewhere I would guess no one at TQtC knows about this. So provide a minimal, compilable example and create a bug report.