Solved What causes QSGRenderThread to have constant CPU usage on a static scene?
-
Hi.
I'm experiencing weird occurences of constant CPU usage by theQSGRenderThread
even when the scene is static. It uses about 22~25% of one of the 4 cores.It seems to happen after the first scene update following the presentation of the default stack item to the user.
It occurs more often than not, but not always, and sometimes goes away for some reason, maybe by pushing and popping some other item on the
StackView
.I tried to confirm that the QSG is not constantly rendering by adding the following debug messages in my
main.qml
:Connections { target: mainWindow function onBeforeSynchronizing() { console.debug("onBeforeSynchronizing") } function onAfterSynchronizing() { console.debug("onAfterSynchronizing") } }
But that seems to work as expected: the debug messages are only printed when the scene changes.
What is happening here?
I found the old bug report about this situation, but got none the wiser, as it was closed and marked as solved with no explanation.Thanks for any insights you may provide on how to tackle this problem ~
-
Hi,
Sorry I do not have an answer for that but you might want to give more information about your hardware and Qt version.
-
Thanks, @SGaist
I have isolated the problem.
As for:you might want to give more information about your hardware and Qt version.
It is on Pi OS Lite
Linux raspberrypi 5.4.72-v7l+
onPi 4B
with Qt5.15.2
but also can be reproduced on Debian Buster:Linux buster 4.19.0-9-amd64 #1 SMP Debian 4.19.118-2 (2020-04-29) x86_64 GNU/Linux
The problem lies with the use of
BusyIndicator
when the interval between settingrunning
totrue
then tofalse
again is too short.The following minimal example reproduces the problem, both on my Pi and my Debian Buster VM build host (in my app, the
running
property is controlled by the status of aFolderListModel
):import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Window 2.15 Window { id: root visible: true property int winWidth: 640 property int winHeight: 480 width: winWidth height: winHeight title: qsTr("Minimal QML") Button { width: 300 height: 100 anchors.centerIn: parent text: "Start/Stop" font.pixelSize: 48 onClicked: { //Forcing running to false only does work to stop //the high cpu usage. It must be started/stopped here. busyIndicator.running = !busyIndicator.running } } BusyIndicator { id: busyIndicator width: 170 height: 170 running: false anchors.centerIn: parent anchors.verticalCenterOffset: -35 clip: false property string color: "blue" palette.dark: color onRunningChanged: { busyText.text = running ? "running" : "" console.debug("BusyIndicator: ", running) } Text { id: busyText visible: busyIndicator.running font.pixelSize: 64 color: busyIndicator.color anchors.horizontalCenter: parent.horizontalCenter anchors.top: busyIndicator.bottom anchors.topMargin: 10 } } Timer { id: timer interval: 5 repeat: false onTriggered: busyIndicator.running = false } Component.onCompleted: { busyIndicator.running = true timer.start() } }
At program startup, we get the following debug output:
qml: BusyIndicator: true qml: BusyIndicator: false
But from then on,
QGSRenderThread
cpu usage stays high:The only way to stop it is to press the button twice to start/stop it;
setting onlyrunning = false
upon button press does not work to stop the high CPU usage.I suspect that in the above use case non-interactive case, the interval between the start/stop states is too short to display anything, and somehow messes up the state of the
BusyIndicator
animation or so. It only seems to work correctly if the animation has effectively been shown on-screen for some time, as achieved with theStart/Stop
button.Setting the timer
interval
to e.g. 50 briefly flashes the busy indicator, and thenQSGRenderThread
reverts back to 0 activity.EDIT: Apparently, this is a reported bug.
https://bugreports.qt.io/browse/QTBUG-85860?jql=text ~ "BusyIndicator"If I use a custom
BusyIndicator
such as the following, the problem does not occur, even for
running
intervals as short as 1ms.//BusyIndicator.qml //This is essentially what the Controls 1 version of BusyIndicator does: import QtQuick 2.15 Item { id: root property bool running: true Image { id: image anchors.fill: parent opacity: root.running ? 1 : 0 Behavior on opacity { OpacityAnimator { duration: 250 } } source: "busyindicator.png" RotationAnimator on rotation { from: 0 to: 360 duration: 6000 loops: Animation.Infinite running: image.visible && (root.running || image.opacity > 0) } } }