Qt Quick Performance Improvements with Qt 5.12 LTS

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.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.

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 Beta 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 sing 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 Beta. The benchmark is run on 64-bit ARM processors using Linux operating system.

js_benchmark

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 compared to Qt 5.6 is 1785% and Qt 5.12 compared to Qt 5.6 the improvement is 2187%. Compared to Qt 5.6, 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 the overall JavaScript performance improvement of Qt 5.12 is 21%.

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 Beta. To improve the comparability of results, we are running Qt Quick Controls 1 tests on Qt 5.6, 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 improvement in JavaScript as well as Qt Quick Controls performance is so big, we have presented those separately (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 and Qt 5.12.

qml_bench_other

For the overall QML Bench test the performance with Qt 5.9 is double compared Qt 5.6 (109% better than Qt 5.6), and the performance of Qt 5.12 is on the same level (98% better than Qt 5.6). The improvements in areas other than JavaScript and Qt Quick Controls are smaller, typically between 15 to 25%. Comparing Qt 5.9 and Qt 5.12 gives a bit more of a mixed picture. While there are quite some areas where performance is better with Qt 5.12, we are also seeing performance regressions in a couple of test cases. Those regressions are things we will have examine closer over the next couple of months and want to improve upon in patch level release for Qt 5.12.

Note that QML Bench is not directly representative of the real-life application performance. Each application uses different QML functions, typically some multiple times. QML Bench on the other hand uses all of the functionality rather equally and does not weight results according to frequency of use in the real world – 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.

Qt 5.12 LTS is currently in Beta phase and we are working hard to get the Qt 5.12.0 release out at the end of November. If you have not yet looked into Qt 5.12 LTS, please take it for a spin.

 

 


Blog Topics:

Comments

?
Louis
0 points
78 months ago

Thanks for the report and for your work, this is very interesting.

One point that would be missing on the comparison graph of the section "QML Memory usage" would be Qt 5.12 --without-- pre-compiled QML (happens when qmlc/jsc are disabled through an environment variable or during the first run of the application, I believe?).

?
Tham
0 points
78 months ago

Thanks for sharing. However I would stick to c++ If I need to develop complicated app, not only I am more familiar with it, but I find out compile time error checking is very useful, the bigger the project become, the more important. Last time I tried to use qml to develop sophisticated ui, and I regret about my decision. It is very easy to commit bug when you want to change the name of the file or property, no compile time warning, many bugs only found out when the apps run, things become worse if you need to cooperate qml with c++. The other issue is the model and view of QtQuick is quite raw compare with QWidgets, it is fine if you don't need to handle(present + manipulation) complex data by table view or tree view, when you need to, it need lots of workaround.

qml, good if you want to develop simple, fluent ui, not a good choice if you want to develop complicated ui, better stick with QWidgets and QGraphicsView.

?
ekke
0 points
78 months ago

I'm developing very complex mobile business apps running on Android, iOS (some also on Windows10)
Apps are built using QtQuickControls2 for UI and business logic, network, ... in C++
Customers are very satisfied with speed and UX

?
R Kh
0 points
78 months ago

Will users of LGPL Qt benefit from these memory usage improvements? Is precompiled QLM/JS compatible with LGPL?
I am not sure because end users are not able to replace the QML/JS compiler used by the app with their own custom/improved version. Also, it is not clear if the patched LGPL Qt will still be compatible with precompiled code…

?
Jakub
0 points
78 months ago

As we already on performance subject... Could someone tell me why QmlProfiler shows Compiling even when I use QtQuickCompiler? What is strange that main.qml takes always the same amount of 'Compiling' time no matter if using compiler or not.

More info about my problem/questions here: https://forum.qt.io/topic/9....

?
Ulf
0 points
77 months ago

The QML engine still needs to generate the platform-specific machine code, even if you load the precompiled bytecode from the cache. The problem may be that this second compile stack vastly dominates the total compilation time in your case, or that the cached bytecode somehow doesn't match your QML files and the engine decides to recompile each time. You may want to open a bug report about this.

?
Alex
0 points
78 months ago

It would be interesting to see a comparison of JavaScript performance of Qt 5.6 with Qt Quick Compiler with 5.12.

It is clear that JIT support significantly improves performance, but how does it compare to Qt Quick Compiler?

?
Wil
0 points
78 months ago

So.. According to you statistics Qt 5.6 is 100% faster than Qt 5.6?

?
Tuukka Turunen
0 points
78 months ago

@Wil: For the whole QML Bench test set we tested Qt 5.9.7 to perform 109% faster than Qt 5.6.3. However, the actual performance of your application depends upon what functionality you use. If your app uses heavily the areas that have improved a lot, you will see much bigger improvement - and smaller if you use areas that have improved less. But typically every app using Qt 5.9 or 5.12 runs faster and with less memory than with Qt 5.6.

?
dtech
0 points
78 months ago

I notice quite a few performance regressions vs 5.9.7. Are those gonna get addressed in the final 5.12 release?

?
Tuukka Turunen
0 points
78 months ago

@dtech: There are a few tests that have regressed and a few that have improved, so on average the tested Qt 5.12 Beta has equal performance to Qt 5.9.7. We will look into the regressed tests and fix these within Qt 5.12.x patch releases, because none of the regressions is very big. However, as there are a few test cases with 10-15% regressions, we expect the performance of Qt 5.12 to be slightly better after these have been fixed. We do not want to delay Qt 5.12.0 release due to these. Note that sometimes a regression in test can be intentional (unavoidable) due to added functionality.

?
Uwe
0 points
78 months ago

Actually QML hurts the memory footprint in 3 ways:

a) the runtime engine

This is the part where your blog is about. It is good to see improvements here, but when being in the camp that prefers C++ over JavaScript the only acceptable number for a runtime engine is probably 0 MB.

b) limitations of the language

QML allows to write certain things in a very compact way, but is also limited compared to a OO language like C++. The consequence is that you often end up in doing compositions of heavy objects ( QQuickItem/QObject ).

The fact that the main idea behind QQuick Controls 2 (QC2 ) is to implement more in C++ is related to this.

c) language bridge

A Qt/Quick application is always a combination of C++ and QML, simply because many things can't be done in QML. To be able to access classes being written in C++ from QML you need to have a specific type of C++ API, that often requires additional heavy classes.

A good example is a gradient, where not only the class itself is a QObject, but also every color stop.

--

But the original sin behind this all is not QML - it is the decision to make QML mandatory. Having a proper C++ API with some extra code on top to make objects being accessible from QML would be the design I am looking for. This way the user is free to decide, where to start with QML - of course including the option not to use QML at all.

It would be interesting to compare your numbers with an application written in pure C++ - f.e using QWidgets ( what is also not being known as light ) or maybe with my library ( https://github.com/uwerat/q... ) .

?
Sandro F
0 points
77 months ago

Hm, a lot of QtQuick Controls are already implemented in pure C++. So what is the difference to your self-implemented skinny classes?

?
Uwe
0 points
77 months ago

Sure, everything that matters is implemented in C++ including all basic Qt controls. But none of the Qt controls has a public C++ API. And the C++ APIs, that are accessible as private headers are made as bridge for the QML use case - not a good one for being used from C++.

That means that application code has to be QML code and you start with compositing stuff in QML. Consider having a large application where 70% of the GUI code is application code and only 30% belongs to the controls. Then all optimizations for the controls won't affect the other 70%. Actually it is hard it is hard to understand, why more C++ has not been made possible for application code, when it had been identified as the solution for making QC2 less heavy.

We made a presentation at the Qt conn 2016 about what that means f.e for a simple push button with text and icon. IIRC a push button of QC1 was made from > 30 QObjects, a button from QC 2 was better, but still needed 7 (might be more depending on the background ). The one from QSkinny needs 1.
Or take the PageIndicator of QC2: each bullet is a rectangle item with ...

In general: QSkinny allows to do scenegraph Node composition, what means you can create way more complex controls without having the overhead of many QQuickItems/QObjects. If you like you can build the QSkinny examples and start the listbox example: it is made from 2 items, where one of them is the root item of the window.

But QSkinny is not yet another set of controls: it is intended to offer a different framework on top of only a few core classes of Qt/Quick. This covers code for creating scene graph nodes, a smarter way of handling the lifetime of scane graph nodes, a layout system that can compete with the one from widgets, its own animation and theming systems, specific support for using vector graphics ...

Actually the Qt company seems to be stuck in the QML corner and at some point we realized, that if we want to have a different system we have to start working on it on our own: that is what QSkinny is about.

?
Olivier Corrio
0 points
77 months ago

I agree with that. It is too complex, too heavy to mix data from C++ to QML

?
MN
0 points
77 months ago

Good to see people are keeping the spirit of C++ in Qt alive. I like the scene graph, but I will never have JavaScript running alongside my application and I will never depend on a proprietary language.

?
Vladimir Kraus
0 points
77 months ago

I do not understand the last chart and especially the very last bar. According to it, 5.12 Beta looks worse than 5.6. Or am I reading it wrong?

?
Jason
0 points
77 months ago

I for one, will very much appreciate ECMA Script 7! This is huge for me!

Now I won't feel like I'm writing in a 20-year old language. :-)