Qt 5.12 LTS中Qt Quick的性能改进

作者:Richard Lin | Dec 3, 2018 6:53:46 AM

本文翻译自Qt Quick Performance Improvements with Qt 5.12 LTS

原文作者:Lars Knoll,Qt公司CTO兼Qt开源项目维护官

校审:Richard Lin

我们一直致力于提高Qt的性能和优化其内存消耗。Qt 5.12的一个重点关注是在于减少QML引擎的内存消耗和优化JavaScript性能。

与上一个长期支持版Qt 5.6 LTS相比,Qt 5.9 LTS总体性能已经发生了明显改善。这都在一篇博客中进行了总结,它在64-bit ARM基础上分析Qt 5.9 LTS版本中的Qt Quick 性能提升。在Qt 5.12 LTS中,我们更深入研究了QML引擎、内存消耗和JavaScript性能,并进一步调整和优化这些内容。

QML内存使用

应用程序中的各个部分都会消耗内存,要总体优化内存的使用,一般来说是通过缩减图形素材,优化元件(实例、素材)的使用时机、使用Qt Lite来裁剪掉不用的功能以及利用其它的内存优化技术等。由于应用开发者很难控制QML引擎本身的内存消耗,因此我们深入研究了如何减少其内存消耗。

Qt 5.12 LTS的一个重要优化是在于和编译后QML一起使用的数据结构。QML引擎在运行加载 .qml或 .js文件时,会动态创建缓存文件(名为 .qmlc和 .jsc),其中就包含动态dump的内部数据结构。启动时如果找到这些文件,则将这些文件加载到应用程序进程中,并直接使用,而不需要编译过程。我们可以选择在编译应用程序时提前创建这些缓存文件。在这种情况下,我们对类型系统的能见性不如QML引擎动态解析时那么高。这会导致分阶段处理的方式,因为我们不能像运行时动态生成数据结构那样解析内容,这就要求我们在预生成的缓存文件之上做一些额外的处理。

在Qt 5.12 LTS中,为了减少使用这些预编译缓存文件时的内存消耗,实施了两个改进:

  • 避免为内存中生成的编译单元重新创建索引字符串表,而是返回从缓存文件中提供的内存映射字符串表。
  • 减少数据结构的大小,以减少文件的大小和它们的内存消耗。

除了上面描述的改进之外,我们还做了多项较小的改进,以减少QML引擎的内存消耗,同时仍然保持良好的性能(实际上在其他一些方面也有许多改进)。

Qt Quick Application的实际内存使用在很大程度上取决于应用程序本身。在下面的比较图中,我们测量了两个不同应用程序中与QML引擎有关的内存消耗。我们使用Qt Quick Controls示例来代表Qt Quick应用程序。

示例应用程序中,我们可以看到Qt 5.6.3使用36.3 MB内存,Qt 5.9.7使用18.5 MB内存,Qt 5.12 Beta使用13.0MB 内存(使用预编译的QML)。这意味着Qt 5.12的内存使用率比Qt 5.9低30%,比Qt 5.6的示例应用程序低64%。所有的Qt用户都可以从这些内存节省中收益。对于商业用户,Qt 5.6和5.9提供了一个单独的可以预编译QML的工具Qt Quick Compiler。使用Qt Quick Compiler,Qt 5.6的内存使用量下降到14.4MB(比不使用它时的内存使用量低60%)。因此,即使在Qt 5.6环境下使用 Qt Quick Compiler,升级到Qt5.12也会使内存使用达到10%的惊人改善。

由于应用程序各不相同,所以最好先检查一下升级后对应用程序的提升有多大。我们基于一个相当复杂的实际Qt Quick应用程序,对QML引擎在Qt 5.6和5.9中使用Qt Quick Compiler和Qt 5.12使用预编译QML条件下的内存使用情况作比较。在这次测试中,Qt 5.9使用的RAM比Qt 5.6少1.1MB(都使用了Qt Quick Compiler),而Qt 5.12使用量比Qt 5.6(使用Qt Quick Compiler)少了惊人的9.8MB。特别是对于资源受限的嵌入式系统或运行多个应用程序的嵌入式系统,QML引擎节省的RAM (在不更改应用程序代码前提下)非常有价值。

JavaScript性能

与Qt 5.9 LTS和Qt 5.6 LTS相比,Qt 5.12 LTS的一个主要区别是从Qt 5.11开始在QML引擎中加入的全新编译器体系结构。新版管道中还启用了一些前文描述的内存优化。即使在Qt 5.12中增加了ECMAScript 7支持,新版管道中的JavaScript性能也有了显著提高。

为了比较不同Qt版本的JavaScript性能,我们使用Qt 5.6.3、Qt 5.9.7和Qt 5.12 Beta运行了相同的JavaScript基准测试。 基准测试在64位ARM处理器上运行,使用Linux操作系统。

为了突出Qt 5.9到5.12的改进,我们将Qt 5.6测试结果进行了归一化。

Qt 5.9相对于Qt 5.6的总改善率(总得分)为1785%而Qt 5.12与Qt 5.6相比,改善率为2187%。与Qt 5.6相比,最大的性能改进是因为在64位ARMv 8架构上支持了JIT,这可以在许多现代嵌入式处理器中使用。在Qt 5.6中,64位ARM不支持JIT。

Qt 5.9和Qt 5.12都支持JIT,因此这两者之间的提升主要是由于新的编译器架构。与Qt 5.9相比,Qt 5.12的JavaScript整体性能提高了21%。

Qt Quick整体性能

因为性能很容易受到各种影响,所以我们会定期运行几种不同类型的性能测试。这些测试还有助于分析各种优化在不同平台上的效果,并确保新特性和错误补丁不会无意间对性能产生副作用。其中一些结果可以在testresults.qt.io中看到,例如QML Bench 测试

为了比较Qt版本的影响,我使用Qt 5.6.3、Qt 5.9.7和Qt 5.12 Beta运行了完整的QML Bench 中的测试集合。为了提高结果的可对比性,我们在Qt5.6上运行Qt Quick Controls 1测试,因为它没有Qt Quick Controls 2。除此之外,QML Bench的功能在这些Qt版本之间是相同的。QML Bench是运行在Nvidia Jetson TX1开发板(64位ARM处理器)上,操作系统是Nvidia定制支持的Tegra Ubuntu 16.04的Linux 。

由于JavaScript和Qt Quick Controls的性能有了很大的提高,我们已经分别介绍了这些特性(前文描述的JavaScript和早期的博客中的Qt Quick Controls)。我们再次将Qt 5.6.3的结果完全进行了归一化,以便更好地突出Qt 5.9和Qt 5.12的改进。

Qt 5.9与Qt 5.6相比,Qt 5.9经QML Bench测试后,其总体性能提高了一倍(比Qt 5.6提高了109%),Qt 5.12的性能达到了同样的水平(98%优于Qt 5.6)。除了JavaScript和Qt Quick Control之外,其他方面的改进都比较小,通常在15%到25%之间。比较Qt 5.9和Qt 5.12对比测试的图像结果可以看出更多的东西来。虽然Qt 5.12在某些方面性能更好,但我们也看到了一些测试用例中的性能回退。在接下来的几个月里,我们将更仔细地研究这些绘图,并希望在Qt 5.12版本的补丁上有所改进。

请注意,QML Bench并不直接代表实际应用程序的性能。每个应用程序使用不同的QML函数,通常多次使用。另一方面,QML Bench使用所有的功能都是相当平等的,并不根据实际使用的频率来衡量结果-所以建议您通过自己的应用程序收集性能数据,看看它的性能提高了多少。

其他的改进

在这篇文章中,我们的重点放在Qt Quick 性能上,与Qt 5.12 LTS的早期版本相比,我们在三个重要方面有了显著的改进:

  • QML内存使用情况
  • Qt Quick 总体性能
  • JavaScript性能

除此之外,Qt 5.12 LTS还提供了许多其他性能改进。Qt 5.12 LTS的一个重要改进是使用预先生成的字体距离属性的可能性。早期的Qt已经在应用程序启动期间创建了字体距离,它会消耗大量的CPU资源,特别是对于非拉丁字体(有许多符号)和复杂的拉丁字体(有很多不同的形状)。在Qt 5.12 LTS中,我们发布了一个名为“Qt Distance Field Generator”的工具,它允许您为字体中的选定字形或所有字形预生成字体距离属性。

我们一直在改进性能的其他领域包括,例如Qt 3D的CPU消耗和Qt 3D的内存消耗(对Qt 3D Studio应用程序特别有利)。Qt 5.12 LTS还引入了一个完全重新设计的TableView,它大幅提升了大型表格控件的性能,与Qt Quick Controls 1中原有的TableView完全不可同日而语。当然,QT5.12LTS还得益于Qt5.10引入的压缩纹理支持和Qt 5.11的改进,以及自上一次Qt发布以来所做的多项其它改进。

Qt 5.12 LTS目前正处于Beta阶段,我们正在努力在11月底发布Qt 5.12.0版本。如果您还不知道Qt 5.12 LTS,请使用它试试吧。