优化QML应用程序以编译到C++

Optimizing your QML application for compilation to C++

优化QML应用程序以编译到C++

Thursday May 19, 2022 by Ulf Hermann | Comments

​2022年5月19日,星期四,乌尔夫·赫尔曼 评论

This is the start of a series of posts where I'm going to share some insights on how to adjust a QML application to get the most out of qmlsc, the QML Script Compiler. In contrast to previous posts, I won't talk about the abstract architecture or the high level picture. You can read up on that in my previous posts. Rather, I'm going to show concrete pieces of code with concrete suggestions on how to change them.

​这是一系列文章的开始,我将分享一些关于如何调整QML应用程序以充分利用qmlsc(QML脚本编译器)的见解。与之前的帖子相比,我不会谈论抽象的架构或高层次的图片。你可以在我之前的帖子中读到这一点。相反,我将展示具体的代码片段,以及关于如何更改它们的具体建议。

Currently planned are posts on:

目前计划的内容有:

  1. Type Annotations for JavaScript functions JavaScript函数的类型注释
  2. Visibility of types at compile time 编译时类型的可见性
  3. Alternatives to Duck Typing Duck类型的替代方法
  4. Untangling Dependencies 解开依赖项
  5. QtQuick.Controls and its Optional Imports QtQuick.Controls及其可选导入
  6. The QML Import Path QML导入路径
  7. Unqualified Access to members of component root objects 对组件根对象成员的非限定访问

The list may grow. I'm using the cutting edge features of Qt. Some of those may not even have been released, yet. In any case, I will always state the minimum version of Qt needed to apply the given techniques.

名单可能会增加。我正在使用Qt的最新功能。其中一些甚至可能尚未发布。在任何情况下,我都会声明应用给定技术所需的Qt的最低版本。

As mentioned above, we're going to get our hands dirty here. In order to do so, we first need to find a piece of software that provides sufficient dirt.

如上所述,我们将在这里弄脏我们的手。为了做到这一点,我们首先需要找到一个提供足够污垢的软件。

Qt Creator's QML Profiler has been around for a while and some may have forgotten about it. Let me assure you, it still does its job as it always has. You can measure the performance of your application, and crucially, it will measure any speedup gained by ahead of time compilation just fine. However, as a rather old QML application, the QML profiler GUI doesn't yet compile nicely to C++. Let's fix that. While we're at it, we can also use the QML Profiler itself to watch the effect of our improvements on the performance of binding evaluation.

Qt Creator的QML Profiler已经存在了一段时间,有些人可能已经忘记了它。让我向你保证,它仍然像往常一样工作。您可以衡量应用程序的性能,至关重要的是,它可以很好地衡量提前编译所获得的任何加速。然而,作为一个相当旧的QML应用程序,QML profiler GUI还不能很好地编译到C++。让我们来解决这个问题。在这一过程中,我们还可以使用QML探查器本身来观察我们的改进对绑定评估性能的影响。

I'm doing this with Qt Creator because that's a convenient target for such improvements. The techniques showcased here can be applied to any application, though. We won't achieve incredible performance gains on QML profiler because QML profiler's performance is limited either by I/O or by the internal data transformations implemented in C++, depending on the workload. However, I will still show how to directly observe the performance impact of any changes you make to your QML code.

我使用Qt Creator进行此操作,因为这是此类改进的方便目标。不过,这里展示的技术可以应用于任何应用程序。我们无法在QML profiler上获得令人难以置信的性能提升,因为QML profiler的性能受到I/O或在C++中实现的内部数据转换的限制,这取决于工作负载。然而,我仍将展示如何直接观察对QML代码所做的任何更改对性能的影响。

First, let's set up our environment. What follows is a short guide on how to build Qt Creator and use QML profiler on itself.

首先,让我们设置环境。下面是关于如何构建Qt Creator并在其自身上使用QML profiler的简短指南。

How to start

如何开始

The first step is simple: Install Qt and qmlsc from your Qt Maintenance Tool, clone the Qt Creator git repository, including its submodules.

​第一步很简单:从Qt维护工具安装Qt和qmlsc,克隆Qt Creator git存储库,包括其子模块。

You may checkout the master branch in order to avoid Qt compatibility-related compile problems, but mind that some of the changes we're going to do are already integrated in master. You can look at an older branch, for example 6.0, to see the original code.

您可以切换到master分支以避免与Qt兼容性相关的编译问题,但请记住,我们将要做的一些更改已经集成到master中。您可以查看较旧的分支,例如6.0,以查看原始代码。

Now open the CMakeLists.txt in Qt Creator. Choose a release-with-debuginfo configuration for the kit with the Qt version you have just installed. You should not try to build qml2puppet as that needs to be adjusted for every new version of Qt. We don't need it for what we are going to do here. In src/tools/CMakeLists.txt, remove the following line:

现在在Qt Creator中,打开CMakeLists.txt。为您刚刚安装的Qt版本的工具包选择一个带有debuginfo配置的版本。您不应该尝试构建qml2uppet,因为它需要针对每个新版本的Qt进行调整。我们在这里不需要它。在src/tools/CMakeLists.txt中,删除以下行:

add_subdirectory(qml2puppet)

Now you need to enable QML debugging and profiling. The default application templates provided by Qt Creator do this automatically for debug and release-with-debuginfo configurations, but the Qt Creator build system is not created from such a template. To enable QML debugging and profiling, switch to the Projects mode and set the "QML debugging and profiling" dropdown to "Enable".

现在需要启用QML调试和分析。Qt Creator提供的默认应用程序模板会自动执行此操作,以便使用debuginfo配置进行调试和发布,但Qt Creator构建系统不是从此类模板创建的。要启用QML调试和分析,请切换到项目模式,并将“QML调试和分析”下拉列表设置为“启用”。

 

Then build. This already outputs some helpful warnings. In fact quite many. For example:

然后构建。这已经输出了一些有用的警告。事实上相当多。例如:

Warning: TimeMarks.qml:93:32: Unqualified access
                anchors.right: scaleArea.right

This is exactly what we want. We will look at them in detail, but first let's do a test run of the QML profiler and save an example trace. This is not a trace we're going to compare with other traces, but rather test data we will load back into the QML profiler in order to trigger the code we optimize.

这正是我们想要的。我们将详细研究它们,但首先让我们对QML探查器进行一次测试运行,并保存一个示例跟踪。这不是我们将要与其他跟踪进行比较的跟踪,而是我们将加载回QML探查器的测试数据,以便触发我们优化的代码。

Starting the profiler and saving a trace

启动探查器并保存跟踪

Select the Debug view in Qt Creator, and "QML Profiler" in the dropdown.

在Qt Creator中选择调试视图,并在下拉列表中选择“QML Profiler”。

 

Press the green triangular "Start" button in the toolbar next to the dropdown. This will start another instance of Qt Creator, with QML Profiler recording a trace. You will notice that the "Elapsed" time starts ticking in the toolbar and all the views display a label that says "Profiling Application". Close the extra instance of Qt Creator. As a result, the timeline view will show a fairly boring trace with just a few events.

按下下拉菜单旁边工具栏中的绿色三角形“开始”按钮。这将启动Qt Creator的另一个实例,QML Profiler记录跟踪。您会注意到工具栏中的“已用”时间开始滴答作响,所有视图都显示一个标签,上面写着“分析应用程序”。关闭Qt Creator的额外实例。因此,时间线视图将显示一个相当枯燥的跟踪,只有几个事件。

This is good enough for now. Right click in the time line view and, from the dropdown menu, choose "Save QML Trace". Choose a location and a file name for the trace. We will load it back later.

这就足够了。在时间线视图中单击鼠标右键,然后从下拉菜单中选择“保存QML跟踪”。为跟踪选择位置和文件名。我们稍后再加载它。

Finding your way around in QML Profiler

在QML探查器中查找您的方法

In quite a few places we get warnings like this:

在相当多的地方,我们会收到这样的警告:

Warning: ButtonsBar.qml:41:5: Could not compile function updateLockButton: Functions without type annotations won't be compiled
    function updateLockButton(locked) {

ButtonsBar.qml is the row of buttons in the upper left of the timeline view in QML profiler and Performance Analyzer. You can step through individual events and zoom the view with those. The function it complains about here is triggered when the "view event information on mouseover" button is toggled and the hover selection is enabled or disabled. Let's see how long that takes.

ButtonsBar.qml是qml profiler和Performance Analyzer中时间线视图左上角的一行按钮。您可以单步浏览各个事件并使用这些事件缩放视图。当切换“在鼠标悬停上查看事件信息”按钮并且启用或禁用悬停选择时,会触发它在此处的功能。让我们看看需要多长时间。

Start profiling Qt Creator as before, and switch to the new instance of Qt Creator that opens. Open the QML Profiler, right click in the timeline and "Load QML Trace" our example trace. Then toggle the "view event information on mouseover" button in the top left a few times.

像以前一样开始分析Qt Creator,并切换到打开的Qt Creator的新实例。打开QML探查器,右键单击时间线并“加载QML跟踪”我们的示例跟踪。然后切换左上角的“鼠标悬停查看事件信息”按钮几次。

 Finally close the instance of Qt Creator being traced and switch back to the instance of Qt Creator that records the trace. There, you see a few more events in the timeline.

最后关闭正在跟踪的Qt Creator实例,并切换回记录跟踪的Qt Creator实例。在这里,您可以在时间线中看到更多的事件。

We're interested in the last part of the timeline. You can scroll the timeline using the overview on the bottom.

我们对时间线的最后一部分很感兴趣。您可以使用底部的概述滚动时间线。

What we see there is a direct expression of our previous interaction with the application. The mouse clicks toggling the button are recorded as input events, and some of those trigger a cascade of bindings and JavaScript evaluation. (Note: You can re-order the event categories using drag-and-drop on the labels to the left of the timeline view.)

我们看到的是我们之前与应用程序交互的直接表现。鼠标点击切换按钮被记录为输入事件,其中一些事件会触发绑定和JavaScript评估的级联。(注意:您可以通过拖放时间线视图左侧的标签来重新排序事件类别。)

You can click the events to see information about them in a little information window. Qt Creator will also jump to the relevant source code if you do so. In a simple trace like this, the function we're looking for is easily found by just inspecting events in the timeline. It's the bottom-most JavaScript function at each of the input events. Clicking it gives you information on that specific invocation of updateLockButton(). You can see an aggregation of all events of the same kind, in this case all calls to updateLockButton(), in the Statistics view. The selections in all the views are synchronized. Therefore, just switching to the Statistics view takes you to the correct row already.

您可以单击这些事件,在一个小信息窗口中查看有关它们的信息。如果您这样做,Qt Creator也将跳转到相关的源代码。在这样一个简单的跟踪中,只需检查时间线中的事件,就可以轻松找到我们要查找的函数。它是每个输入事件中最底层的JavaScript函数。单击它可以提供有关updateLockButton()的特定调用的信息。您可以在统计视图中看到所有同类事件的聚合,在本例中是对updateLockButton()的所有调用。所有视图中的选择都是同步的。因此,只要切换到Statistics视图,就可以找到正确的行。

 On my computer, the eight times I toggled the button took a cumulative time of 61.4µs, with each call taking 7.67µs on average. This is not a statistically significant measurement, of course. Yet, for demonstration purposes it's good enough.

在我的电脑上,我切换按钮的八次累计时间为61.4µs,每次通话平均耗时7.67µs。当然,这不是一个具有统计意义的衡量标准。然而,出于演示目的,它已经足够好了。

Let's keep this number in mind until the next post in this series. Now that we have refreshed our memory on QML profiler, we can proceed to change the code and watch the effects achieved this way. In the next post I'm going to show what to do about those functions without type annotations.

在本系列的下一篇文章之前,让我们记住这个数字。现在,我们已经在QML事件探查器上刷新了内存,我们可以继续更改代码并观察以这种方式实现的效果。在下一篇文章中,我将展示如何处理那些没有类型注释的函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值