Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Limit to the number of connections qml can have to a c++ interface object



  • I have a pretty large GUI application that runs on a ARM Based QNX platform. It uses QT 4.8 c++ as a back end and QML as the front end. Most of the UI state is determined by an interface QDeclarativeItem QObject which has MANY Q_PROPERTYs(~1500!). Lets call this interface object xfaceObject. The only purpose for the xfaceObject is to pass data from c++ to QML. The xfaceObject is passed to QML by calling the setContextProperty() function.

    I am running into an issue where the QML Engine appears to be crashing(I see a full white screen) any time I add 1 additional reference to the xfaceObject in ANY of my QML files.

    One thing to keep in mind is that the entire GUI application references Q_PROPERYs defined in the xfaceObject.

    Is there an limit to the number of connections a QML gui application can have to a c++ defined interface object?


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    I cannot comment on any known limit but 1500 properties on a single object ? That sounds like a design issue.



  • CAVEAT: I have only used Qt 5. I have zero experience with Qt 4. So I apologize if my answer contains any ideas that are impossible to apply in Qt 4. Forgive my ignorance in that regard.

    It could be undue obsessiveness on my part, but when I hear "crash" my mind goes straight to the situation of segfault and core dump.

    But that doesn't seem to be your usage of crashing. The app is still running? But the screen goes all white?

    I would immediately be checking the console (stdout/stderr) for any qml "warnings".

    I've expressed my belief in this forum before: qml "warnings" are best treated as errors. Since QML is running inside a QML/Javascript interpreter hosted in your executable, QML doesn't have the right (the luxury?) to abort the application. So QML's best attempt to get your attention is by printing warnings, which are exceedingly easy to miss. The problem is made worse because QML warnings can appear when there is no user-facing bug happening, so we get lulled into ignoring the warnings as a matter of course. But usually when something finally causes a user-facing bug, there should be a QML warning that is relevant.

    I have gone to great lengths to squash all QML warnings. (see: https://forum.qt.io/post/585598)

    Another question that comes to mind:

    • What happens if you add 1 additional reference, but then "compensate" by removing some preexisting one somewhere else?

    You mention that xfaceObject has 1500 properties. One other number I am now curious about is:

    • How many references to xfaceObject exist in your QML code?

    (Sidenote: I have seen hundreds of Q_PROPERTYs on an object, and it wasn't necessarily what I would call a design smell. It was manageable in the project in question because the header was generated by a script. None of that large header needed maintaining by hand. And it mapped to a real-life object that had hundreds of qualities we were measuring, so...)



  • @KH-219Design Thanks for the response!

    The stdout/stderr was the first place I looked because usually, you are right, there is some QML warning that is causing the white screen. But for this problem there is no QML warning in the logs.(Which is why this is so frustrating)

    To your second point, If I remove 1 reference to ANY c++ object that is passed to QML then add a new one, then the "White screen" does not occur. My GUI application has several c++ objects accessible to it and I found out(after making this post) that the "White screen" occurs by making any additional reference to ANY of the c++ objects.

    To your 3rd point , this application if very large and has many modules. Each module makes many references to the xfaceObject(I could go through and count but this object is the main source of state information for the entire project so that number would be rather large). Do you think that the problem is the shear NUMBER of references? The way it is organized is that each module creates their own property for state information, even if the property has already been created in a higher level module. To reduce the number of references to the xfaceObject, should I create common properties at the topmost module and reference the property that exists in the parent module within the child module?

    @SGaist Thanks for the response!
    ThexfaceObject is a result of some auto-generation so overtime it has grown rather large. My first thought was to refactor this to be more modular instead of monolithic but it doesn't seem like that is the problem I am facing here.



  • I don't know if this is the same as creating properties on a C++ object and exposing to QML. But this creates thousands of properties on a QML object and exposes those properties to a list:

            property var propobject
        
            ListView {
                height: 400
                width: 400
        
                anchors.top: otheritem.bottom
        
                clip: true
        
                model: repeatCompParent.children
        
                delegate: Text {
                    height: 20
                    width: 200
        
                    //text: propobject === undefined ? "" : propobject[modelData.data_string].data_string
                    text: propobject[modelData.data_string].data_string
                }
        
                ScrollBar.vertical: ScrollBar {
                    policy: ScrollBar.AlwaysOn
                }
        
                Rectangle {
                    anchors.fill: parent
                    color: "pink"
                    opacity: 0.25
                }
            }
        
            Item {
                id: repeatCompParent
            }
        
            Item {
                id: otherCompParent
            }
        
            function createPropertyObject(numberprops=5000){
                var objheader = 'import QtQuick 2.0\nItem{\n'
                var propstring = 'propstring'
                var objmeat = '    property var %1%2\n'
                var objclose = '}\n'
                var objmeats = ''
        
                for(var count=0; count<numberprops;++count){
                    objmeats = objmeats + objmeat.arg(propstring).arg(count)
                }
        
                var objstr = objheader + objmeats + objclose
        
                var newobj = Qt.createQmlObject(objstr, otherCompParent, 'propertyobject');
                propobject = newobj
        
                for(var prop in newobj){
                    if(prop.includes(propstring) && !prop.includes('Changed')){
                        newobj[prop] = repeatComp.createObject(repeatCompParent, {data_string:prop})
                    }
                }
        
                return newobj
            }
        
            Component {
                id: repeatComp
        
                Item {
                    property string data_string
                }
            }
    

    I get all sorts of cannot assign undefined warnings. I assume this is a byproduct of it being children on an Item instead of a proper model. Not the best way to access properties. But I can set this to create 10K properties and it takes a long time to load, but it does load each property in a ListView. This is also Qt5. So your mileage may vary in Qt4. This only illustrates that at least in Qt5 there is no hard and fast limit on properties except maybe memory. I also don't know if this can be adapted to test in Qt4.

    Is there any indication that you are running out of memory?

    Edit: I was not properly exercising the properties. Now the ListView accesses each property of the object when building the list. I also got rid of all the errors.



  • Ha! What an interesting result.

    The fact that you can "compensate" by removing something in one spot, and this then allows you to succeed at just one more reference inserted somewhere else... ... that really does "hint" at some limit (but not prove it).

    The reason I asked for the total number of references is to see if it was something like:

    65536
    2,147,483,648
    4,294,967,296

    You know? One of those "well known" numbers in computing?

    If you had answered with a number like that, then I would be further inclined to think that some buffer was maxxed out, and any new reference was overflow.

    If you haven't done so, then I think a logical next step would be to make sure you have debug symbols for Qt, and run this under a debugger and see what Qt is doing during these white screen events.

    If you have done so, then tell us what you see? How many threads running? What code is each Qt thread busy running?



  • @KH-219Design I went through and did a count of ALL the references to c++ objects that were passed to QML and that number came out to around ~4500. Doesn't seem to be remotely close to those "special numbers" :P

    I am currently trying to setup QNX Momentics IDE to debug the application on target. The desktop compile seems to be working just fine(which is frustrating). Is there a way that I can deploy the application to my target using Qtcreator?

    I also tried separating the Monolithic xfaceObject into several smaller QObjects and updating all of the references accordingly...the white screen was still present :(

    @fcarney I would say that should be the same as creating properties in c++ and passing them to QML. That is a good proof of concept for sure but I am not familiar enough with the inner workings of QT to say whether the QML Engine treats those properties the same?



  • @wagner2x said in Limit to the number of connections qml can have to a c++ interface object:

    to say whether the QML Engine treats those properties the same?

    Yeah, I don't know. I also don't know if Qt4 treats them the same as Qt5 either.



  • Ooooo QNX. You did mention that previously, but I overlooked it.

    I don't have direct experience with QNX. (I was once on a project that used it, but the code I wrote ran on another PC and only communicated with the QNX box over the network.)

    I have not used Momentics nor (gasp!) Qt Creator. I invoke qmake directly (rather than let Qt Creator do it). I'm very controlling that way :)

    Can you just use gdb directly? I think QNX has a version of gdb. If you try it, see if their flavor supports gdb -tui and you'll have a nicer screen to look at that way.

    Another way to get a call stack could be to just send the running program a signal and get a core file. But then you'd still need gdb (or equivalent) to read the core file.

    More about sending signals:

    https://stackoverflow.com/questions/6561194/force-a-core-to-dump-from-an-active-normally-running-program-on-freebsd
    https://stackoverflow.com/questions/18354686/why-coredump-files-is-not-generating-here



  • @KH-219Design

    So I have successfully set up QNX Momentics to single step through the code however.....I can't get it to step into the qapp.exec() call. When I try I lose connection to the target :( . I can see the other threads spawn but I don't get any information with Momentics when I click on them.

    I have a .core file that got generated when I killed the process. I will try to use gdb to open it.



  • When I have an executable that is paused in gdb, this is the command I use to get all stack traces of all threads at once:

    thread apply all bt

    I'm not sure if that will work on a core file, but I am optimistic that it would.

    As for stepping into the exec()....

    Are you literally using the "step" command? "s" or "step"? I would think you could just tell the program to "run" (no stepping). Then pause/break the debugger when the white screen occurs. But that might be what you tried and I am misunderstanding.

    The helpfulness of the stack traces is going to depend on whether your Qt libraries contain symbols.

    Anyhow, sorry to say it, but I'm about run out of ideas. It does seem like a "clue" that your application still works in the desktop edition and is only misbehaving in the QNX edition. Are there any "knobs you can turn" in QNX? Give the program more memory or more cores/threads? Loosen the program's timing goals/constraints? (Again, I have no direct experience with QNX).

    Maybe there are QNX system tools that would be instructive? Ways to ask QNX to tell you information about the running app? Maybe QNX would report that the app has been frozen by the kernel for some reason?


Log in to reply