Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. QML Application slowly increases CPU usage over time to 100% and becomes unresponsive
Qt 6.11 is out! See what's new in the release blog

QML Application slowly increases CPU usage over time to 100% and becomes unresponsive

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
12 Posts 4 Posters 2.6k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • E egbiomated

    I've got a QML based application that runs fine for about 12 hours but when I leave it to run overnight the application's UI is no longer responsive to the touchscreen. If i SSH in i can see that on one thread the CPU load is 100%. However the Application still shows updating values on the UI. I have the application polling a sensor in a separate worker thread every ~5s and that appears to be working no issue.

    When I profiled the QML app I saw that a lot of the time ~60% was spent servicing events related to the Keyboard.
    3882b66a-1d40-4fe4-83e0-dbd36b5678e6-image.png
    576e4d9a-5b97-4db4-9b41-788306f717eb-image.png

    I'm a bit new to Embedded GUI development and Qt so i was hoping to get some pointers in the right direction. I can't really post the source code unfortunately. Below are screenshots of HTOP output

    HTOP: Start of Application
    d5f79ca6-bacf-43ae-bdab-6f21bde978d5-image.png

    HTOP: End of Application
    e3b114d2-e0a2-4ea8-bed7-7c21714f64e6-image.png

    J.HilkJ Online
    J.HilkJ Online
    J.Hilk
    Moderators
    wrote on last edited by
    #2

    @egbiomated are you sure, you're not creating new objects or at the very least new/additional bindings with each poll from the worker?

    Seems like the app is super busy with property signals and updates 31.9% each


    Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


    Q: What's that?
    A: It's blue light.
    Q: What does it do?
    A: It turns blue.

    1 Reply Last reply
    0
    • E Offline
      E Offline
      egbiomated
      wrote on last edited by egbiomated
      #3

      @J-Hilk said in QML Application slowly increases CPU usage over time to 100% and becomes unresponsive:

      are you sure, you're not creating new objects or at the very least new/additional bindings with each poll from the worker?
      Seems like the app is super busy with property signals and updates 31.9% each

      Sorry but I don't think i fully understand how iI would be doing that. Are you referring to the main thread where my application is running my worker passes a qobject to my ApplicationData class slot which then updates it's own private variables that are in a list [QObject]. In terms of the QML:

      Isn't all that CPU time associated with the Keyboard?

      import QtQuick 2.15
      import QtQuick.Window 2.15
      import QtQuick.Controls 2.15
      import QtQuick.Controls.Material 2.15
      import QtQuick.Layouts 1.3
      
      import "."
      import QtQuick.VirtualKeyboard 2.2
      import "./lib.js" as Lib
      
      
      ApplicationWindow {
          id: window
          width: Style.windowWidth
          height: Style.windowHeight
          visible: true
      
          contentOrientation: Qt.LandscapeOrientation
          property int headerState: 0
          Timer {
              interval: 5000;
              running: true;
              repeat: true
              onTriggered: {
                  switch(headerState)
                  {
                      case 0:
                          titleLabel.text = Lib.getAuthState()
                          headerState += 1
                          break;
                      case 1:
                          titleLabel.text = applicationData.getDateTime().toString().split(' ').slice(0,5).join(' ')
                          headerState += 1
                          break;
                      case 2:
                          headerState += 1
                          break;
                      default:
                          headerState = 0
                          titleLabel.text = stackView.currentItem.title
                  }
      
              }
          }
      
          Shortcut {
              sequences: ["Esc", "Back"]
              enabled: stackView.depth > 1
              onActivated: {
                  stackView.pop()
                  listView.currentIndex = -1
              }
          }
      
          Shortcut {
              sequence: "Menu"
              onActivated: optionsMenu.open()
          }
      
          header: ToolBar {
              contentHeight: toolButton.implicitHeight
      
              transform: Rotation {
                  id: rotation
                  angle: 90
                  origin.x: 400
                  origin.y: 400
              }
      
              RowLayout {
                  // spacing: 20
                  anchors.fill: parent
                  // width: 480
      
                  ToolButton {
                      id: toolButton
                      text: stackView.depth > 1 ? "\u25C0" : "\u2630"
                      font.pixelSize: Qt.application.font.pixelSize * 1.6
                      onClicked: {
                          if (stackView.depth > 1) {
                              stackView.pop()
                          } else {
                              drawer.open()
                          }
                      }
                  }
      
                  Label {
                      id: titleLabel
                      height: parent.height
                      Layout.alignment: horizontalCenter
                      font.pixelSize: 20
                      elide: Label.ElideRight
                      horizontalAlignment: Qt.AlignHCenter
                      verticalAlignment: Qt.AlignVCenter
                      text: Lib.getAuthState()
                  }
      
                  ToolButton {
                      id: menuButton
                      text: "\u2606"
                      font.pointSize: Style.h3
                      font.bold: true
                  }
              }
          }
      
          ListModel {
              id: menuModel
              ListElement {
                  title: "Home";
                  source: "qrc:/pages/SensorList.qml";
              }
              ListElement {
                  title: "Sensor Setup";
                  source: "qrc:/pages/SensorsSetup.qml";
                  section: "Setup";
              }
              ListElement {
                  title: "Calibration";
                  source: "qrc:/pages/Calibration.qml";
                  section: "Setup";
              }
              ListElement {
                  title: "Alarm Setup";
                  source: "qrc:/pages/AlarmSetup.qml";
                  section: "Setup";
              }
              ListElement {
                  title: "Analog Outputs";
                  source: "qrc:/pages/AnalogOutputs.qml";
                  section: "Configuration" ;
              }
              ListElement {
                  title: "Relay Outputs";
                  source: "qrc:/pages/AlarmOutputs.qml";
                  section: "Configuration";
              }
              ListElement {
                  title: "Address Setup";
                  source: "qrc:/pages/SetAddress.qml";
                  section: "Configuration";
              }
              ListElement {
                  title: "Device Setup";
                  source: "qrc:/pages/DeviceSetup.qml";
                  section: "Configuration";
              }
      
      
          }
      
      
          StackView {
              width: Style.windowWidth
              height: Style.windowHeight
              id: stackView
              initialItem: "/pages/SensorList.qml"
          }
      
          //ABOUT Dialog
          Dialog {
              id: aboutDialog
              modal: true
              focus: true
              title: "Device Information"
              x: (window.width - width) / 2
              y: window.height / 6
              width: Math.min(window.width, window.height) * .9
              contentHeight: aboutColumn.height
              font.pointSize: Style.h1
              font.bold: true
              background: Rectangle {
                  width: parent.width
                  height: parent.height
                  color: "white"
              }
      
              Column {
                  id: aboutColumn
                  spacing: 20
      
                  Text {
                      width: aboutDialog.availableWidth
                      text: "Device S/N: 123209"
                      font.pixelSize: Style.h2
                  }
      
                  Text {
                      width: aboutDialog.availableWidth
                      text: "Device Uptime: 5D 3H 33M"
                      font.pixelSize: Style.h2
                  }
              }
          }
      
      
          InputPanel {
              id: inputPanel
              width: 480
              active: true
              rotation: 90
              y: 165
              x: Qt.inputMethod.visible ? -180 : -180 - inputPanel.height
          }
      
      
      }
      

      Is there something you see here that would lead you to any conclusion.

      1 Reply Last reply
      0
      • KH-219DesignK Offline
        KH-219DesignK Offline
        KH-219Design
        wrote on last edited by KH-219Design
        #4

        I have encountered performance problems with StackView in the past.

        Full disclosure: I do think that some of my struggles with StackView stem from my neglecting to actually study it properly and understand the various ways to use it.

        For my applications, it has just become easier to avoid StackView. In your case, you will need to choose whether to avoid it or whether instead to learn about it further.

        I have been able to avoid it because I was using it simply to manage a single foregrounded full-screen item at a time.

        If all you need is to create a "conceptual stack" of equally-sized items (like "pages" in your app), such that only one of them is ever visible at a time, then you can do this without a StackView. Just create each "page" to be the same size and location, but link the visible boolean to a custom expression that ensures that it only becomes true for one of the pages at a time.

        It will turn into something like the following:

            Item {
              id: front
              anchors.fill: parent
        
              property int whichScreen: 0
        
              MainMenu {
                anchors.fill: parent
                visible: front.whichScreen == 0
                onGotoPitchTrain: {
                  front.whichScreen = 1
                }
                onGotoKeySigTrain: {
                  front.whichScreen = 2
                }
              }
        
              PitchTrain {
                id: pt
                anchors.fill: parent
                visible: front.whichScreen == 1
              }
        
              KeySigTrain {
                id: ks
                anchors.fill: parent
                visible: front.whichScreen == 2
              }
            }
        
        

        www.219design.com
        Software | Electrical | Mechanical | Product Design

        E 1 Reply Last reply
        0
        • KH-219DesignK KH-219Design

          I have encountered performance problems with StackView in the past.

          Full disclosure: I do think that some of my struggles with StackView stem from my neglecting to actually study it properly and understand the various ways to use it.

          For my applications, it has just become easier to avoid StackView. In your case, you will need to choose whether to avoid it or whether instead to learn about it further.

          I have been able to avoid it because I was using it simply to manage a single foregrounded full-screen item at a time.

          If all you need is to create a "conceptual stack" of equally-sized items (like "pages" in your app), such that only one of them is ever visible at a time, then you can do this without a StackView. Just create each "page" to be the same size and location, but link the visible boolean to a custom expression that ensures that it only becomes true for one of the pages at a time.

          It will turn into something like the following:

              Item {
                id: front
                anchors.fill: parent
          
                property int whichScreen: 0
          
                MainMenu {
                  anchors.fill: parent
                  visible: front.whichScreen == 0
                  onGotoPitchTrain: {
                    front.whichScreen = 1
                  }
                  onGotoKeySigTrain: {
                    front.whichScreen = 2
                  }
                }
          
                PitchTrain {
                  id: pt
                  anchors.fill: parent
                  visible: front.whichScreen == 1
                }
          
                KeySigTrain {
                  id: ks
                  anchors.fill: parent
                  visible: front.whichScreen == 2
                }
              }
          
          
          E Offline
          E Offline
          egbiomated
          wrote on last edited by
          #5

          @KH-219Design Do you think that the stack view would still be an issue even when the device is idling the CPU run's high when the device IDLE's over night i'm not switching between the screens that the stack view is loading all of the time. But like you said I don't have a solid understanding of its internals.

          1 Reply Last reply
          1
          • fcarneyF Offline
            fcarneyF Offline
            fcarney
            wrote on last edited by
            #6

            What is that timer for? Does speeding it up cause the problem to happen faster? Are there C++ objects being allocated as a result of things changing?

            C++ is a perfectly valid school of magic.

            E 1 Reply Last reply
            1
            • KH-219DesignK Offline
              KH-219DesignK Offline
              KH-219Design
              wrote on last edited by
              #7

              @egbiomated said in QML Application slowly increases CPU usage over time to 100% and becomes unresponsive:

              i'm not switching between the screens that the stack view is loading

              It has been over a year (possibly more than 2) since I have used StackView, so my memory has faded regarding the exact unwanted symptoms I observed and the exact triggering scenarios.

              However, if no methods on the StackView are being called and no properties on the StackView are being mutated when you encounter the unwanted CPU usage, then it does seem improbable to blame StackView in that case.

              www.219design.com
              Software | Electrical | Mechanical | Product Design

              E 1 Reply Last reply
              1
              • fcarneyF fcarney

                What is that timer for? Does speeding it up cause the problem to happen faster? Are there C++ objects being allocated as a result of things changing?

                E Offline
                E Offline
                egbiomated
                wrote on last edited by
                #8

                @fcarney
                The timer is just switching a banner in the Header of the Page from a Text String to a Date Object. The date object is generated in C++ and passed through the context

                1 Reply Last reply
                0
                • KH-219DesignK KH-219Design

                  @egbiomated said in QML Application slowly increases CPU usage over time to 100% and becomes unresponsive:

                  i'm not switching between the screens that the stack view is loading

                  It has been over a year (possibly more than 2) since I have used StackView, so my memory has faded regarding the exact unwanted symptoms I observed and the exact triggering scenarios.

                  However, if no methods on the StackView are being called and no properties on the StackView are being mutated when you encounter the unwanted CPU usage, then it does seem improbable to blame StackView in that case.

                  E Offline
                  E Offline
                  egbiomated
                  wrote on last edited by
                  #9

                  @KH-219Design Properties are being updated on the item that is displayed on the StackView but the stackview itself is not changing. The page displayed.

                  Each Page in the stack view consists of a page like this there are a fixed number of sensors that I am dealing with that can be on or off at any given time so i use a listview to render all the components so the updates do happen with a fair degree of nesting

                  import QtQuick 2.12
                  import QtQuick.Window 2.12
                  import QtQuick.Controls 2.12
                  import QtQuick.Controls.Material 2.12
                  import QtQuick.Layouts 1.3
                  import "../"
                  import "../lib.js" as Lib
                  import "../components" as Components
                  
                  Page {
                     // width: window.width
                     // height: window.height
                     width: Style.windowWidth
                     height: Style.windowHeight
                     // title: qsTr("Sensors")
                     id: sensorSetupPage
                     title: qsTr("Home")
                  
                     transform: Rotation {
                         id: pageRotation
                         angle: 90
                         origin.x: 400
                         origin.y: 352.5
                     }
                  
                     Component.onCompleted: {
                         applicationData.setDeviceState(0)
                     }
                  
                     ListView {
                         id: sensorListView
                         width: parent.width
                         height: parent.height
                         model: Lib.getAvailableSensor(applicationData.sensor_list).length
                         delegate: Components.DynamicSensor {
                             width: parent.width
                             height: Math.ceil((sensorListView.height-50)/(Lib.getAvailableSensor(applicationData.sensor_list).length))
                             sensorData: applicationData.sensor_list[Lib.getAvailableSensorIndex(index)]
                             numAvailable: Lib.getAvailableSensor(applicationData.sensor_list).length
                             MouseArea {
                                 anchors.fill: parent
                                 onClicked: {
                                     // applicationData.sInFocus = Lib.getAvailableSensorIndex(index)
                                     applicationData.setSensorInfocus(Lib.getAvailableSensorIndex(index))
                                     stackView.push("qrc:/pages/SensorDetail.qml")
                                 }
                             }
                         }
                     }
                  }
                  
                  
                  import QtQuick 2.12
                  import QtQuick.Controls 2.12
                  import QtQuick.Controls.Material 2.12
                  import Qt.labs.settings 1.0
                  import "../"
                  import "../lib.js" as Lib
                  
                  Rectangle {
                      id: dynamicSensor
                      width: parent.width
                      height: parent.height
                      property var sensorData
                  
                      function getSensorUnits() {
                          if (sensorData.sensorUnits === 0)
                          {
                             return "PPM"
                          }
                          else if (sensorData.sensorUnits === 1)
                          {
                             return "PPB"
                          }
                          else
                          {
                             return "% 0<sub>2</sub>"
                  
                          }
                      }
                  
                      function parseO2Data() {
                          var units = getSensorUnits();
                          if (sensorData.o2Level > 0)
                          {
                              if (units === "PPM")
                              {
                                  return sensorData.o2Level.toFixed(3)
                              }
                              else if (units === "PPB")
                              {
                                  return sensorData.o2Level.toFixed(1)
                              }
                              else
                              {
                                  return sensorData.o2Level.toFixed(2)
                              }
                          }
                          else
                          {
                              return 0.00
                          }
                      }
                  
                      function getColor() {
                          if (sensorData.alarmTripped && !sensorData.standby && !applicationData.alarm_list[Lib.getAvailableSensorIndex(index)].ack)
                          {
                             return "#ff5252"
                          }
                          else if (sensorData.pulseCount > 900000) {
                  
                              return "yellow"
                          }
                          else
                          {
                              return "transparent"
                          }
                      }
                  
                      property string sensorName: "Sensor 1: Condensate Pump"
                      property string sensorUnits: getSensorUnits()
                      property int numAvailable: Lib.getAvailableSensor()
                      property int sensorIndex: Lib.getAvailableSensorIndex(index)
                      property bool isLast: numAvailable === (sensorIndex) ? true : false
                      property real rowSpacers: (numAvailable < 3 ? 24 : 16)
                      // color: (sensorData.alarmTripped && !sensorData.standby && !applicationData.alarm_list[Lib.getAvailableSensorIndex(index)].ack) ? "#ff5252" : "transparent"
                      color: getColor()
                  
                      function getFontSize() {
                          var baseSize =  Style.h1 + (numAvailable < 3 ? 30 : 15)
                          // if (getSensorUnits() === "PPM") {
                          //     baseSize -= 30
                          //}
                          return baseSize
                      }
                  
                      Column {
                          width: (parent.width - (Style.gutter*2))
                          leftPadding: Style.gutter
                          // height: parent.height
                          topPadding: 10
                          // spacing: 1
                  
                          Text {
                              id: sensorNameRow
                              width: parent.width
                              height: (Style.h3 + rowSpacers)
                              horizontalAlignment: Text.AlignLeft
                              verticalAlignment: Text.AlignVCenter
                              font.bold: true
                              font.underline: true
                              font.pointSize: Style.h3
                              // text: sensorName
                              text: "Sensor " + (sensorIndex + 1) + ": " + sensorData.sensorName
                              // bottomPadding: 10
                              // toPadding: 10
                          }
                  
                          Row {
                              id: oxygenUnitRow
                              width: parent.width
                              height: (Style.h3 + rowSpacers)
                              Text {
                                  width: parent.width/2
                                  height: parent.height
                                  horizontalAlignment: Text.AlignLeft
                                  verticalAlignment: Text.AlignVCenter
                                  font.bold: true
                                  font.pointSize: Style.h3
                                  text: "Dissolved 0<sub>2</sub>"
                              }
                  
                              Text {
                                  width: parent.width/2
                                  height: parent.height
                                  rightPadding: Style.gutter
                                  horizontalAlignment: Text.AlignRight
                                  verticalAlignment: Text.AlignVCenter
                                  font.bold: true
                                  font.pointSize: Style.h3
                                  text: sensorUnits
                              }
                          }
                  
                          Text {
                                  width: parent.width
                                  height: dynamicSensor.height - (sensorNameRow.height + oxygenUnitRow.height + temperatureRow.height + 10)
                                  topPadding: 5
                                  bottomPadding: 5
                                  horizontalAlignment: Text.AlignHCenter
                                  verticalAlignment: Text.AlignVCenter
                                  font.bold: true
                                  // font.pointSize: Style.h1 + (numAvailable < 3 ? 30 : 15)
                                  font.pointSize: getFontSize()
                                  text: sensorData.standby ? "--.--" : parseO2Data()
                          }
                  
                          Row {
                              id: temperatureRow
                              width: parent.width
                              height: (Style.h3 + rowSpacers)
                  
                              Text {
                                  width: parent.width/3
                                  height: parent.height
                                  horizontalAlignment: Text.AlignLeft
                                  verticalAlignment: Text.AlignBottom
                                  font.bold: true
                                  font.pointSize: Style.h3
                                  text: !sensorData.standby ? "Online" : "Standby"
                              }
                  
                              Text {
                                  width: parent.width/3
                                  height: parent.height
                                  horizontalAlignment: Text.AlignHCenter
                                  verticalAlignment: Text.AlignBottom
                                  font.bold: true
                                  font.pointSize: Style.h3
                                  text: !applicationData.alarm_list[sensorIndex].ack ? "" : "Alarm Ack."
                              }
                  
                              Text {
                                  width: parent.width/3
                                  height: parent.height
                                  rightPadding: Style.gutter
                                  horizontalAlignment: Text.AlignRight
                                  verticalAlignment: Text.AlignVCenter
                                  font.bold: true
                                  font.pointSize: Style.h3
                                  text: sensorData.standby ? "--.--" : (sensorData.temp).toFixed(2) + (sensorData.tempUnits === 0 ? " \xB0C" : " \xB0F")
                              }
                          }
                  
                          Rectangle {
                              width: parent.width
                              height: isLast ? 0 : 2
                              border.width: isLast ? 0 : 2
                              border.color: "black"
                          }
                      }
                  }
                  
                  1 Reply Last reply
                  0
                  • fcarneyF Offline
                    fcarneyF Offline
                    fcarney
                    wrote on last edited by
                    #10

                    You are going to have to create a minimal program that no longer exhibits the problem and slowly add things until you find what is causing this. Or start taking out chunks and testing that. You will have to do process of elimination. I would start with removing the virtual keyboard since you have a bunch of stuff having to do with keyboard processing. Also, make sure there is not a cat sleeping on a wireless keyboard somewhere.

                    C++ is a perfectly valid school of magic.

                    1 Reply Last reply
                    1
                    • KH-219DesignK Offline
                      KH-219DesignK Offline
                      KH-219Design
                      wrote on last edited by
                      #11

                      You could also run dmesg to look at the kernel log, to see if there are any strange messages related to input drivers. (I have nothing in mind that I would expect to find, I'm just continuing along the lines of the keyboard and touchscreen investigation.)

                      In addition to keyboard, I'm looking at the flame diagram again and seeing filterLocaleIndices and onLocaleChanged near the middle of both the two main "mountains". Could there be some cron job or something that runs overnight and updates/adds/removes locales? or switches the user's locale?

                      @fcarney 's suggestion about process of elimination makes sense.

                      I wonder if you really have to run it overnight, or if perhaps you can force the device to "sleep" or to go to the lock screen a couple times, and maybe that is all it takes to trigger it?

                      www.219design.com
                      Software | Electrical | Mechanical | Product Design

                      1 Reply Last reply
                      1
                      • E Offline
                        E Offline
                        egbiomated
                        wrote on last edited by
                        #12

                        That flame graph is just from the first 4 minutes of operation not the entire 24 hours sorry should've said that before. dmesg doesn't turn up anything that would make me think there is an issue and cron doesn't exist on the machine it's the stock boot2qt image

                        1 Reply Last reply
                        1

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved