Unsolved Optimum strategy for efficient updating of high frequency data in QML
-
Hi,
I'm pondering the optimum approach for handling QML GUI updating, given high frequency c++ data model changes. Binding the QML to a given c++ class and updating the QML element with the c++ variable's NOTIFY signal works perfectly, but when you have many (dozens) variables, each emitting their own NOTIFY update signal, ranging from less than once a second to (potentially) over a 1000 times a second, it doesn't seem like the best approach given the QML GUI is limited to a 60Hz refresh frequency. Even though the actual redrawing of the QML is limited by design, you're still firing (potentially) thousands of signals unnecessarily.
This SO post happens to ask the exact same question, and details some options. Unfortunately the answer doesn't provide much input or discussion, so I'm hoping to explore this topic in a little more detail here. I will note that the QML oscilloscope example, which can be considered a reasonable example of a 'high frequency' data model, makes use of a 60Hz QML-based timer update (option 2 in the linked SO post).
The options listed in the SO post are as follows:
-
Bind the data as property of the model to the view, and emit a dataChanged() signal on every update of the data:
Pro: Elegant code, lowest resource usage in case of low data update rates.
Con: High signal frequency will spam the GUI and maximize resource utilization, potentially rendering the system unresponsive. -
Use a QML-Timer and poll the model at a specific interval (e.g. 10 - 60 Hz):
Pro: Upper limit on resource utilization, steady rate
Con: Timer itself consumes resources; not as elegant as data binding; if data generation/callback rate is lower than timer rate, unnecessary polling calls have to be made. -
Use data binding as in 1. but throttle the signal emitting frequency inside the C++ model using a QTimer (or another timer like boost's), i.e., only emit the dataChanged() signal at specific intervals:
Pro: Same as 2.
Con: Same as 2. -
Combine Timer from 3. with some kind of check whether the data actually changed, prior to emitting the signal, thus avoiding unnecessary signal emitting if data has not changed:
Pro: Same as 3.
Con: same as 3. but even less elegant; increased risk to induce a bug because logic is more complicated; model is harder to reuse as the data changed check highly depends on the nature of the data
As mentioned earlier, option 1 is the option with which I'm most familiar. I've implemented option 3 (a QTimer in c++ which emits the NOTIFY signal every (1/60) seconds), which works as intended, but the question that then arises is, do you emit a single NOTIFY signal (encapsulating all the data model elements), or emit a NOTIFY signal for each element, or does it not matter?
I'd been keen to get some input on this!
-
-
@jars121 Hi, yes massive data exchange between C++ <=> QML can be a performance bottleneck.
I've seen for a couple of month a talk from Simon Davydov at Qt World Summit 2019 called Fast C++ to QML Properties.
Sources available at github ==> https://github.com/samdavydov/propertymap
But without taking a look at the presentation, it is hard to understand ;)Hope this will help you.
-
Thanks @KroMignon much appreciated.
I hadn't come across that presentation or concept before. I've now watched the presentation and have been through the github source. I've not used the QQmlPropertyMap approach before, I've always used the Q_OBJECT Q_PROPERTY method. The QuickPropertyMap certainly seems like a high-performance option, I'm just wondering what the 'standard' approach to high frequency data is within Qt, given that the QuickPropertyMap is currently a standalone third party capability.