Lars Knoll

Qt Quick Performance Improvements with Qt 5.12 LTS (Updated for Qt 5.12.3)

Published Friday May 3rd, 2019
7 Comments on Qt Quick Performance Improvements with Qt 5.12 LTS (Updated for Qt 5.12.3)
Posted in Biz Circuit & Dev Loop, Performance, Qt Quick

We are continuously working on improving the performance and optimizing the memory consumption of Qt. One focus area for Qt 5.12 has been to reduce the memory consumption of the QML engine and tuning the JavaScript performance. Qt 5.12.3 provides further improvements especially for QML engine performance. 

This is an update for the earlier Qt 5.12 performance blog post from last November. Measurements have been done with Qt 5.12.3 release, which contains further improvements to Qt Quick and QML performance compared to the Qt 5.12 beta used in the previous post.

Qt 5.9 LTS already shows a great improvement of the overall performance compared to the previous long-term supported Qt 5.6 LTS release. These are summarized in a blog post about Performance Improvements with Qt 5.9 LTS and Qt Quick Performance Improvements on 64-bit ARM. With Qt 5.12 LTS we have continued to tune these further and taken a deeper look into the areas of QML engine memory consumption and JavaScript performance. In addition to Qt 5.6 LTS no longer supported, the performance of the Qt 5.12 LTS is a solid reason to upgrade.

QML Memory usage

Applications use memory for multiple things and to optimize the overall memory usage a good start is typically to look into the graphics assets, leveraging asset conditioning, the Qt Lite feature system to remove unused functionality and other techniques to optimize the memory usage. As it is very difficult for an application developer to affect the memory used by the QML engine itself, we have taken a deep look into how it can be reduced.

One important optimization done with Qt 5.12 LTS are to the data structures used in conjunction with compiled QML. The QML engine creates cache files that contain a dump of internal data structures on the fly when loading a .qml or .js file at run-time (named .qmlc and .jsc). If found, these files are mapped into the application process and used directly without requiring a compilation step. We have an option to create those cache files ahead of time while compiling the application. In that case, we don’t have quite the same degree of visibility into the type system as the QML engine has at run-time. This leads to a staged approach where we can’t resolve quite as much as when generating the data structures at run time, requiring us to do some additional work on top of the pre-generated cache files.

In Qt 5.12 LTS two changes are done to reduce the memory consumption when using such ahead-of-time generated cache files:

  • Avoid the re-creation of the indexed string table for the in-memory generated compilation unit and instead fall back to the memory mapped string table provided from the cache file.
  • Reduce the size of data structures so that the size of the files as well as their memory consumption is reduced.

In addition to the changes described above, we have done also multiple smaller improvements to reduce the memory consumption of the QML engine, while still keeping the performance on a good level (and actually improving quite a bit in some areas).

Actual memory usage of a Qt Quick applications depends a lot upon the application itself. In the comparison chart below, we have measured the QML engine related memory consumption for two different applications. We have used the Qt Quick Controls example to represent a Qt Quick application.

qml_engine_ram_use

For the example application we can see that Qt 5.6.3 uses 36.3 MB, Qt 5.9.7 uses 18.5 MB and Qt 5.12.3 uses 13.0 MB RAM (using pre-compiled QML). This means that memory usage with Qt 5.12 is 30% lower than Qt 5.9 and 64% lower than Qt 5.6 with the example application. These savings are available for all users of Qt. For commercial users Qt 5.6 and 5.9 offered a separate tool called Qt Quick Compiler that can be used for pre-compiling QML. Using the Qt Quick Compiler, the memory usage of Qt 5.6 drops to 14.4 MB (60% lower RAM usage than without). So even when using the Qt Quick Compiler with 5.6, upgrading to Qt 5.12 will lead to a very nice 10% improvement in memory usage.

As all applications are different it is best to check how big the benefit is for your application. We compared the QML engine memory use of Qt 5.6 and 5.9 using Qt Quick Compiler and Qt 5.12 using the pre-generated QML with a rather complex real-life Qt Quick application. In this measurement Qt 5.9 used 1.1 MB less RAM than Qt 5.6 (both with Qt Quick Compiler), and Qt 5.12 used a whopping 9.8 MB less RAM than Qt 5.6 (with Qt Quick Compiler). Especially for embedded systems with constrained resources or ones that run multiple applications this type of RAM savings in the QML engine, with no changes to the application code, are very beneficial.

JavaScript Performance

A major difference of Qt 5.12 LTS compared to Qt 5.9 LTS and Qt 5.6 LTS is the completely new compiler architecture of the QML engine introduced with Qt 5.11. The new pipeline has also enabled making some of the memory use optimizations described earlier in this post. With the new pipeline, we get a significant improvement in JavaScript performance, even with the addition of ECMAScript 7 support in Qt 5.12.

To compare the JavaScript performance for different Qt versions, we have run the same JavaScript benchmark with Qt 5.6.3, Qt 5.9.7 and Qt 5.12.3. The benchmark is run on 64-bit ARM processors using Linux operating system.

qt_5_12_3_js_comparison

To highlight the improvement with Qt 5.9 and 5.12 we have normalized the result of Qt 5.6 to 100.

Overall improvement (TotalScore) of Qt 5.9.7 compared to Qt 5.6.3 is 1785% and Qt 5.12.3 compared to Qt 5.6.3 the improvement is 2138%. Compared to Qt 5.6.3, the biggest performance improvement is seen due to supporting JIT on 64-bit ARMv8 architecture used in many modern embedded processors. With Qt 5.6 JIT is not supported on 64-bit ARM.

Qt 5.9 and Qt 5.12 both support JIT, so between these the improvements are mainly due to the new compiler architecture. Compared to Qt 5.9.7 the overall JavaScript performance improvement of Qt 5.12.3 is 19%.

Overall Qt Quick Performance

Because it is so easy to break performance, we regularly run several different kinds of performance tests. These also help in analyzing how the various optimizations work across different platforms and to make sure feature development and error corrections do not have unintended side effects to performance. Some of these results are visible at testsresults.qt.io, for example the QML Bench tests.

To compare the effect of Qt versions, we have run the full QML Bench test set with Qt 5.6.3, Qt 5.9.7 and Qt 5.12.3. To improve the comparability of results, we are running Qt Quick Controls 1 tests on Qt 5.6.3, as it does not have Qt Quick Controls 2 functionality. Otherwise the functionality tested by the QML Bench is same between these Qt versions. For these tests, QML Bench was run on an Nvidia Jetson TX1 development board (64-bit ARM processor) running the Nvidia supported Linux for Tegra Ubuntu 16.04.

Due to the very large performance improvement in Javascript and Qt Quick Controls, we have presented those separately to make the charts below more readable (JavaScript earlier in this post and Qt Quick Controls in an earlier blog). We have again normalized the Qt 5.6.3 result to be 100 in order to better highlight the improvements with Qt 5.9.7 and Qt 5.12.3.

qt_5_12_3_qml_comparison

For the overall QML Bench test the performance with Qt 5.9.7 is over double compared Qt 5.6.3 (109% better than Qt 5.6.3), and the performance of Qt 5.12.3 is even slightly higher (113% better than Qt 5.6.3). The improvements in areas other than JavaScript and Qt Quick Controls are smaller, typically between 15 to 25%. Comparing Qt 5.9.7 and Qt 5.12.3 shows overall improvement of 7%. This has improved since the first Qt 5.12 releases as the performance regressions in a few tests have been fixed. Those using Qt 5.12 LTS, should update to Qt 5.12.3 or later in order to get this increase in Qt Quick performance.

QML Bench has been developed with typical application use cases in mind, trying to cover as many of those as possible in a comprehensive suite. But as with any benchmark, this still means that the improvements in your application might vary depending on how QML is being used there – so it is always recommended to gather performance data with your own application to see how much its performance improves.

Other improvements

In this post the focus was in the Qt Quick performance, where we have improved the performance of Qt 5.12 LTS significantly compared to the earlier LTS releases of Qt in three important areas:

  • QML memory usage
  • Overall Qt Quick performance
  • JavaScript performance

In addition to these, Qt 5.12 LTS provides many other performance improvements as well. One important improvement in Qt 5.12 LTS is the possibility to use pre-generated distance fields of fonts. Earlier Qt has created the distance fields during the application startup, which can consume a lot of CPU cycles especially for non-latin fonts (that have many glyphs) and complex latin fonts (that have a lot of different shapes). With Qt 5.12 LTS, we release a tool called “Qt Distance Field Generator”, which allows you to pregenerate the distance fields for either a selection of the glyphs in a font or all of them.

Other areas where we have been improving performance include, for example, Qt 3D CPU usage and Qt 3D memory consumption (especially beneficial for Qt 3D Studio applications). Qt 5.12 LTS also introduces a completely re-designed TableView, which takes the performance of large tables to completely different level than the old TableView implementation of Qt Quick Controls 1. Of course, Qt 5.12 LTS also benefits from the compressed texture support introduced with Qt 5.10 and improved with Qt 5.11, as well as multiple other improvements done since the previous LTS release of Qt.

If you have not yet looked into Qt 5.12 LTS, please take it for a spin.

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in Biz Circuit & Dev Loop, Performance, Qt Quick

7 comments

Niels Mayer says:

S/sing/using: “even when sing the Qt Quick “

Roland Wolf says:

QML is always getting better but I wondered several times if the initial QML productivity gains are worth the pain you face in large scale projects. Notable problems are interactions between three type systems (C++/QML/JavaScript), resource tracking (CPU, Memory), missing a viable type safe dependency injection in QML, interpreting call stacks that point to QML stuff. May I draw your attention to https://github.com/uwerat/qskinny, a brave attempt to use the cool Qt scene graph technology without QQmlEngine.
Are there any plans of the Qt company to provide a C++ way to write scene graph apps? Of course the scene graph has a public API but there are no items like ScrollArea Rectangle or MouseArea with a supported public API and no dependencies to QML. Using C++ only you would loose the expressiveness of QML but get leaner apps with better testability and scalability.

Petar says:

After working with QML for 5 years on large scale IPTV projects it’s the only thing now in the market that successfully tackles complexity and performance. What is the issue with QML, C++ and Javascript in the mix? It’s perfect to separate your layers which should be done anyway.
Sure, it can always be better (especially the stability) but just look at the alternatives. QSkinny is nice but has no value compared to QML imho. It’s removing features for sake of simplicity or performance.
Try to use QSkinny for a large project, then you will again need to add features which you are missing and then you maintain your own mess.
Just look at all the HTML frameworks to see what you get with separating the styling and everything they are trying to fix with the like of CSS in JS. And, just looking at the QSkinny code example I don’t know why you would want that for something serious, it’s crazy to read for such basic examples.

The obvious benefit would be to have all QML controls/elements accessible in C++ but you would actually need to go a declarative API route if you want benefit of QML imho (ala https://github.com/nlohmann/json)
The code needs to be expressive as well, not

auto rectangle = new Rectangle;
rectangle.setWidth(10)

but
Rectangle({ width: 10});

Something that Flutter seems to make right.

And we again have to wait for C++20 to have some proper C++ modules to make it a sane language while JavaScript benefits will always be there.

Uwe says:

Comparing QSkinny with a regular Qt/Quick doesn’t make much sense at this point as QSkinny is far from being complete – you might have noticed, that there is not even an alpha version released. But QSkinny is playing with a lot of ideas – some work already pretty well, others not – and sooner or later it will grow into something I might be able to recommend as an realistic option for everyone. Actually all I want to reach is a state, where its potential becomes obvious for others and it gets enough momentum to gain contributions.

For the modules offered by the Qt Company it seems to be the opposite – they are there and usable, but unfortunately the development seems to be stuck in the QML corner without being able to move on. Keep in mind, that Controls 1 has failed because of too much QML and Controls 2 is doing more of C++ for a reason. And even coming from this experience the decision was made not to offer any public C++ API at all !

Finally: a statement like “QSkinny is nice but has no value compared to QML” totally misses the point as QSkinny allows QML in the same way as the modules offered by the Qt company. But you also have the option to do things in C++. Combinations are of course also possible – f.e. I would always write my custom controls in C++ even if your application code could be QML.

jason says:

I am really appreciating ECMA Script 7… There is one errata that I keep running into though, that’s not even ECMA Script 7. The issue at https://bugreports.qt.io/browse/QTBUG-50275 (XHR timeouts are not supported) and is still unresolved after over 3 years.

Ola says:

Do you still recommend using the quick compiler in certain situations (example: commercial user, imx6 embedded target), or is it completely deprecated by now?

I’d prefer it because of not having the plain Qml code bundled in the binary (as with qrc), as well as maybe a few more compile-time checks, but if the performance is worse now then it might not be worth it?

@Ola: With Qt 5.6 LTS and Qt 5.9 LTS Qt Quick Compiler is available for commercial license holders and recommended to be used. With Qt 5.12 LTS it is no longer available as a separate tool, but pre-compiled QML brings the same (and even slightly better) performance effect as can be seen from the diagram in this post.

Commenting closed.

Get started today with Qt Download now