C

Qt Quick Ultralite 性能日志

本主题重点介绍如何获取 Qt Quick Ultralite 应用程序的性能指标和内存占用信息。

Qt Quick Ultralite 性能日志

Qt Quick Ultralite 可以收集重要的性能指标,如下:

  • CPU 空闲时间,
  • 堆栈和堆的使用情况,
  • 帧率,
  • 缓存使用情况,
  • 渲染上花费时间的有用信息,
  • 以及文本布局。

这些日志通过板卡的串行端口输出,可以使用主机上的串行终端观察。要启用和查看性能日志

  • 要收集性能指标,Qt Quick Ultralite 核心库必须使用启用 QUL_ENABLE_PERFORMANCE_LOGGING CMake 选项构建。自 Qt for MCUs 2.6 以来,这是发货库的默认设置。
  • 要同时启用性能日志输出到串行控制台,请启用 QUL_ENABLE_PERFORMANCE_CONSOLE_OUTPUT CMake 选项,并重新构建 Qt Quick Ultralite 核心库。
  • 要查看支持它的平台的 CPU 使用情况,必须使用 QUL_ENABLE_HARDWARE_PERFORMANCE_LOGGING CMake 选项构建 Qt Quick Ultralite 平台库。自 Qt for MCUs 2.6 以来,这是发货库的默认设置。有关更多信息,请参阅 CPU 使用情况
  • 性能日志通过串行连接发送到主机计算机。
  • 使用您选择的串行终端查看性能日志输出。

注意:自 Qt for MCUs 2.6 以来,Qt Quick Ultralite Core 和 Platform 库随 QUL_ENABLE_PERFORMANCE_LOGGINGQUL_ENABLE_HARDWARE_PERFORMANCE_LOGGING 默认启用发货。虽然这对于分析应用程序很有用,但性能指标收集会给生产就绪的应用程序增加不必要的开销。要移除它,请使用 QUL_ENABLE_PERFORMANCE_LOGGINGQUL_ENABLE_HARDWARE_PERFORMANCE_LOGGING 禁用 重新构建 Qt Quick Ultralite 库

以下步骤将详细介绍。

启用性能日志

要启用 Qt Quick Ultralite 性能日志功能,请使用 -DQUL_ENABLE_PERFORMANCE_LOGGING=on CMake 选项(在默认启用情况下,Qt for MCU 2.6 已经包括该选项)重新构建 Qt Quick Ultralite Core 库。你可以使用 -DQUL_ENABLE_PERFORMANCE_CONSOLE_OUTPUT=on CMake 选项与前面的选项一起将日志输出重定向到串行控制台。

如果启用了性能日志,你可以使用 QulPerf QML 类型在 UI 中直接显示指标。

注意:在构建你的应用程序时指定这些选项是不够的。Qt Quick Ultralite 库需要按照 从源代码构建 Qt Quick Ultralite 页面中描述的方式进行构建。

查看性能日志

使用类似于 minicom、gtkterm、PuTTY 或 hyperterm 的串行终端连接到启用了性能日志功能的应用程序运行的设备。

假设设备通过 USB 连接到主设备时使用虚拟 COM 端口提供串行端口,以下是如何查看性能日志的方法。

注意:性能日志只在没有屏幕内容变化时可用。如果没有活动动画,你应该与应用程序进行一些交互,以看到性能日志。

Linux

在 Linux 上,注意目标设备连接到主机器时哪个 /dev/ttyACM*/dev/ttyUSB* 端口出现。如果你使用 minicom,使用以下命令连接到设备

minicom -D /dev/ttyACM2

在某些板子上(如 Infineon TRAVEO™ T2G),可能需要显式地将回车符添加到日志输出中。在 minicom 终端中,你可以通过按 Ctrl+'a' 然后按 'u' 键将回车符添加到传入的文本中。

Windows

以下是如何在 Windows 上使用 PuTTY 终端查看性能日志的步骤。首先,检查设备管理器以查看目标设备连接时出现的哪个设备

相应地配置 PuTTY

  • 使用串行连接类型
  • 使用设备管理器识别的串行行
  • 以及 115200 的速度

你也可以找到目标设备的正确波特率,并相应地调整速度。

此时应该可以看到从 QML 应用程序输出的控制台日志和性能日志。

注意:串行终端方法不适用于 RH850 D1M1A 引用板。相反,使用 MULTI 项目管理器的调试菜单中的“调试其他可执行文件”选项,闪存应用程序 .elf 文件。然后应在调试视图中看到控制台和性能日志。在 RH850 上,日志速度非常慢,所以你应该考虑暂时启用该功能以收集性能指标。

示例日志

以下是在启用 QUL_ENABLE_PERFORMANCE_CONSOLE_OUTPUT 的情况下从性能日志功能产生的示例输出

Memory usage:
Heap: 61596/67820 (in-use/total)
Stack: 13132 (peak)
Resource cache for allocation type 1: 3 texture(s), 1620 KB used / 2160 KB total
Text cache: 31481 bytes used out of 32768 bytes max
Monotype spark cache: 35056 bytes used out of 200000 bytes max
refresh intervals: 1: 7, 2: 18, 3: 6,
10 fps (last 31 frames)
animation tick: 0.1% (avg: 0.1 ms, worst: 0 ms)
flush: 4.9% (avg: 5.0 ms, worst: 6 ms)
repaint: 7.2% (avg: 7.3 ms, worst: 42 ms)
  prepare: 0.5% (avg: 0.5 ms, worst: 1 ms)
  region compute: 0.0% (avg: 0.0 ms, worst: 0 ms)
  paint: 6.5% (avg: 6.6 ms, worst: 41 ms)
    spark scale change: 0.1% (avg: 0.1 ms, worst: 3 ms)
    spark glyph retrieval: 0.1% (avg: 0.1 ms, worst: 2 ms)
    text layout: 0.8% (avg: 0.8 ms, worst: 14 ms)
    text blend: 0.8% (avg: 0.8 ms, worst: 4 ms)
    rect blend: 1.8% (avg: 1.8 ms, worst: 9 ms)
    rect fill: 1.0% (avg: 1.1 ms, worst: 3 ms)
    image blend: 1.3% (avg: 1.3 ms, worst: 9 ms)
      alpha w/color: 0.3% (avg: 0.3 ms, worst: 0 ms)
      alpha: 0.9% (avg: 0.9 ms, worst: 8 ms)
      opaque: 0.1% (avg: 0.1 ms, worst: 1 ms)

前三行显示应用程序的堆和堆栈使用情况。

然后是当前使用情况和资源(图像)、文本和 Monotype Spark 字体引擎缓存的总量。

接下来是关于需要多少个帧才能在一个、两个或三个刷新(vsync)间隔内渲染的信息。为了一致地以每秒 60 帧的速度渲染,所有帧必须在一个刷新间隔内渲染完成。

“10 fps”行(最后 31 帧)表示这些统计信息是针对上一个 31 帧,平均每秒 10 帧。

最后,这里有 Qt Quick Ultralite 渲染管道各部分的计时统计。平均 (avg) 值表示某些帧的平均耗时,而最坏 (worst) 值表示单个帧的最大耗时。以下是在日志中可能会看到的不同计时统计概述:

入口描述
动画计时器在 QML 动画中推进所有 QML 动画所花费的时间,例如 NumberAnimation
刷新Qul::Platform::PlatformContext 的成员函数 beginFrame()presentFrame() 上花费的时间。它主要指示等待垂直刷新的时间。在这里花费大量时间并不表示应用程序性能不好,而是意味着有很多空闲时间,没有用来准备或渲染帧。
重绘动画中变化的区域准备和绘制所花费的时间。
准备准备 QML 项渲染节点所花费的时间。这包括标识当前可见的 QML 项的边界矩形。
区域计算基于可见项的边界矩形为每帧计算脏区域的耗时。
不透明度计算计算不透明区域以尽可能减少过度绘制所花费的时间。
绘制绘制所有可见项的总耗时。
Spark 放大缩放变化在 Monotype Spark 字体引擎中为像素大小变化做准备所花费的时间。
Spark 字形检索在 Monotype Spark 字体引擎中光栅化字形,然后将其保留在字体引擎缓存中。
CPU 访问同步使用后备绘图引擎时,同步 CPU 访问所花费的时间。
文本布局布局文本所花费的时间,然后将文本直接绘制到帧缓冲区或文本缓存中。
文本混合对文本混合所花费的时间,要么是逐个字形地混合,要么是使用文本缓存进行混合。
矩形混合混合半透明矩形(矩形 QML 类型)所花费的时间。
矩形填充填充不透明矩形(矩形 QML 类型)所花费的时间。
矩形圆角混合圆角矩形(带有半径设置的矩形 QML 类型)所花费的时间。
图像变换混合变换后的(缩放、旋转、倾斜和投影)图像的总耗时。
图像混合混合非变换图像的总耗时。
alpha w/颜色混合使用 PixelFormat_Alpha8 格式以及颜色(例如使用 ColorizedImage)的图像所花费的时间。
alpha混合具有 alpha 通道(PixelFormat_ARGB32、PixelFormat_ARGB4444 等)的图像所花费的时间。
不透明混合具有 alpha 通道(PixelFormat_ARGB32、PixelFormat_ARGB4444 等)的图像所花费的时间。
路径混合混合来自 QML Shape API 或使用矢量轮廓的文本所花费的时间。

CPU 使用率

要查看支持该功能的平台的 Qt Quick Ultralite CPU 使用率,请使用具有 -DQUL_ENABLE_HARDWARE_PERFORMANCE_LOGGING=on CMake 选项重新构建 Qt Quick Ultralite 平台库。

CPU 负载信息如下所示

CPU Load: 44.47

此示例表示 CPU 负载为 44.47 %。CPU 大约有一半的时间是空闲的。

注意:在支持此功能的参考平台上,CPU 使用率是根据 CPU 空闲时间估计的。

内存占用

当确定应用程序需要多少RAM和闪存,或在尝试减小二进制文件大小时,足迹信息非常重要。您可以使用受支持的工具链和资源缓存应用程序提供的工具来获取Qt Quick Ultralite应用程序的足迹信息。

工具

工具链特定的工具可以用来确定应用程序二进制的内存消耗。这些工具具有不同的标志并产生不同的输出。以下小节列出了Qt为MCU支持的三种工具链提供的工具:ARM GCC、IAR和GHS。

ARM GCC

ARM GCC包括两个单独的工具,可用于确定应用程序的内存消耗:sizereadelf。这些工具可以在ARM GCC安装目录下的bin目录中找到。二进制文件以arm-none-eabi-为前缀,例如size二进制文件命名为arm-none-eabi-size。它们也包含在GNU Binutils软件包中,可在大多数Linux发行版中找到。

size是一个实用程序,它列出了二进制或存档的节的大小。节的大小可以以各种格式显示

  • SystemV格式(《a class="plink" href="#systemv" title="直接链接到此标题">或-A--format=sysv)这种格式显示所有节及其大小列表。建议使用SystemV格式来获取二进制文件中包含的节及其大小和地址的良好概述。
  • Berkeley格式(-B或《a class="plink" href="#berkeley" title="直接链接到此标题">或--format=berkeley)GNU size的默认格式。Berkeley格式在text列中计算只读数据,而不是在data列中,dechex列分别以十进制和十六进制形式显示textdatabss列的总和。
  • GNU格式(-G--format=gnu)GNU格式在data列中计算只读数据,而不是在text列中,并将textdatabss列的总和在total列中只显示一次。可以使用--radix选项来更改所有列的数值基。

readelf是一个用于显示关于ELF格式对象文件信息的工具。它可以从二进制文件中收集广泛的多种信息,例如节的大小、程序头部和符号。要测量应用程序的足迹,请使用标志-S--section-headers--sections以获取有关所有节、它们的大小和其他有用信息。

此外,可以使用编译器标志-Wl,--print-memory-usage。然后链接器将打印出链接器脚本中配置的所有内存区域、它们的实际大小以及以字节数和百分比表示的使用大小。

注:使用-Wl,--print-memory-usage不会显示节的大小,因此不能用于显示例如QulResourceData节的大小。

IAR

IAR工具链提供ielfdumparm,该工具用于创建ELF文件内容的文本表示。它位于IAR安装目录的arm/bin中。要获取有关二进制文件中包含的扇区和段的信息,请运行ielfdumparm <input>

获取有关不同节的信息的另一种方法是使用链接器中的--map标志。这将生成一个链接器内存映射文件,其中包含有关节及其在内存中位置的详细信息。

注意:qul_add_target Qt Quick Ultralite CMake 宏会自动将 --map 添加到目标链接器选项中。生成的内存映射可以在与目标二进制相同的目录中找到。映射文件的名称为 <target>.map

有关 ielfdumparm 或使用 --map 链接器选项的更多信息,请参阅 IAR C/C++ 开发指南

GHS

GHS 工具链具有用于测量段大小的 gsize 实用工具。它位于 GHS 编译器安装目录下。gsize 分析二进制文件并输出段及其大小。如果提供 -all 标志,它还会列出所有大小为 0 的段。

GHS 链接器 elxr 提供了 -map 选项,可以将单独的 <target>.map 文件输出到生成目标二进制文件的同一位置。此文件包含有关目标二进制文件的大量信息,包括包含在二进制文件中的段及其大小。此链接器选项默认启用,但可以通过指定 -map=<filename> 甚至 -nomap 来更改。这些选项允许更改映射文件的输出位置或彻底禁用映射文件生成。

有关 gsize 或使用 -map 链接器选项的更多信息,请参阅 MULTI: 构建基于 ARM 的嵌入式应用程序(或根据目标架构相似的内容)文档。

闪存使用情况

默认情况下,Qt Quick Ultralite 在闪存中有三个资源段。这些段分别用于存储字体资产、图像资产和 Qt Quick Ultralite 内部资源,名称为 QulFontResourceDataQulResourceDataQulModuleResourceData。有关这些段的信息,请参阅内存中的资源放置链接器脚本设置

要获得这些段的大小,请使用工具部分中提到的工具。这些工具的输出应类似于 size -A minimal.elf 的输出。

section                     size         addr
.flash_config                512    805307392
.ivt                        1336    805310464
.interrupts                 1024    805314560
.text                     347552    805315584
CodeQuickAccess               56    805663136
.ARM                           8    805663192
.init_array                    8    805663200
.fini_array                    8    805663208
.data                        236   2147483648
.ncache.init                   0   2197815296
.ncache                  2097152   2197815296
.bss                       13104   2147483888
QulFontResourceData        21736    805663456
QulModuleResourceData          0   2147496992
QulResourceData                0    805685192
QulPreprocessCache        524288   2147496992
.heap                          0   2148021280
.ARM.attributes               46            0
.debug_info              5402684            0
.debug_abbrev             253660            0
.debug_loc                871154            0
.debug_aranges             12520            0
.debug_ranges             100040            0
.debug_line               908143            0
.debug_str               3705172            0
.comment                      73            0
.debug_frame               51112            0
.debug_macro              570227            0
.stab                         60            0
.stabstr                     118            0
Total                   14882029

注意:段名称可能取决于使用的链接器脚本。

估计 RAM 使用量

Qt Quick Ultralite 应用程序需要以下 RAM:

  • 帧缓冲区
  • 缓存(用于文本、字体引擎和图像)
  • 资源
  • Qul 项数据

以下部分将解释如何估算或收集这些项目的内存占用信息。

帧缓冲区

矩形屏幕的帧缓冲区大小可以用以下公式估算

Framebuffer size in bytes = width x height x bytes per pixel x number of buffers

其中

  • width 是屏幕的宽度(像素)
  • height 是屏幕的高度(像素)
  • 每像素的字节数是每个像素使用的字节数。如果已知比特深度,可以将比特深度除以 8 来计算每像素的字节数。对于 32bpp 帧缓冲区,每像素的字节数是 32 / 8 = 4
  • number of buffers 取决于使用的缓冲区策略。对于单缓冲区,该值应为 1,对于双缓冲区,该值应为 2。

如果用于屏幕的帧缓冲区不是矩形的,则此大小估算可能会有所不同。在这种情况下,可以将先前的公式中的 width x height 替换为帧缓冲区中的总像素数。

有关帧缓冲区及其要求的更多信息,请参阅 帧缓冲区要求

堆栈和堆

Qt Quick Ultralite(平台)提供了两个打印堆栈和堆统计信息的功能:Qul::Platform::printStackStatsQul::Platform::printHeapStats。要使用这些函数,它们必须在平台代码中实现。有关如何实现这些函数的更多信息,请参阅 内存统计信息

资源缓存

典型的 Qt Quick Ultralite 应用程序可以有以下几种类型的缓存

为了在内存使用和性能之间取得最佳平衡,调整这些缓存的大小可能很重要。以下是估算它们适当大小的指南,以适应您的应用程序

文本缓存

对于文本缓存,理想的大小取决于屏幕上文本的多少以及文本的像素大小。例如,在 Qt Quick Ultralite 最小示例 中,像素大小为 30 的 "Qt for MCUs" 文本消耗了 6899 字节。绘制文本项所需的字形边界框宽度为 183 像素,高度为 37 像素。

由于您需要一个字节来表示每个像素的透明度,因此它的alpha图所需字节数可以计算如下

183 x 37 = 6771 字节

此外,每个缓存条目还包括一小部分元数据,这就是为什么最终所需数量略高的原因。

为了理想性能,单页应用程序至少应该有一个足够大的文本缓存,可以容纳该页上的所有文本。如果页面的10%被文本覆盖,并且屏幕分辨率为800x480,则需要38.4 Kb的文本缓存。

如果有两个或更多页面,并且存在它们之间的淡入淡出过渡动画,则理想的文本缓存大小应该能够容纳两个页面上的文本。

可以使用较小的文本缓存来牺牲一些性能以换取较低的内存使用,但这可能意味着在动画或过渡期间需要重新生成某些文本缓存条目。使用 Monotype Spark 字体引擎时,生成文本缓存条目的成本将高于使用静态字体引擎,因此如果在性能问题上特别重要,则可能需要保持文本缓存大小足够。

另外要注意的是,如果销毁了文本项并重新创建了它们,相关的文本缓存条目也将随时自动重新生成,一旦文本项可见。更改文本或任何其他影响其外观的属性,也将使文本缓存条目无效。

请参阅有关文本缓存大小的更多信息文本渲染和字体页面。

可以通过查看Qt Quick Ultralite 性能日志来查看应用程序使用的文本缓存大小。

字体引擎缓存

Monotype Spark 字体引擎使用字体引擎缓存存储每个光栅化的字形的alpha图。如果缓存足够大,则字形只绘制一次,而不是每次绘制(无论是文本缓存还是禁用文本缓存时绘制到帧缓冲区)。

例如,在 Qt Quick Ultralite Thermostat 示例 中,至少需要50 Kb的字体引擎缓存才能在一个 800x480 分辨率下保持单一语言的全部alpha图。

拥有足够大的文本缓存时,字体引擎缓存将在首次显示文本项或文本变更时被访问。然而,当动画运行时,文本缓存可能在每一渲染帧中被访问。因此,为了性能考虑,通常较好的做法是为文本缓存分配比字体引擎缓存更多的内存。另一方面,由于字形缓存是按字形进行的,同一个字形可能在不同文本项中出现多次,所以字体引擎缓存更节内存。

如果启用了MCU.Config.fontVectorOutlinesDrawing,则字体引擎缓存仅用于CMAP和Advance缓存,而不用于矢量轮廓。因此,它可以保持相对较小,而文本缓存应保持较大,以避免重新生成矢量轮廓。

有关字体引擎缓存大小的更多信息,请参阅文本渲染和字体页面。

应用程序使用的字体引擎缓存大小可以通过查看Qt Quick Ultralite性能日志来查看。

图像缓存

图像缓存应足够大,以便能够容纳屏幕上同时可见的所有图像(使用OnDemand 缓存策略)。否则,大图像可能在一帧中被反复载入和卸载到RAM中,显著影响性能。特别是如果启用了ImageFiles.MCU.resourceCompression,它会在将图像加载到图像缓存之前添加额外的解压缩开销。

例如,一个在两页之间切换的应用程序,一页包含两个200x200的图像,另一页包含一个320x200的图像。如果图像的颜色深度为每像素32位(4字节),那么理想图像缓存大小的计算如下

缓存大小(带过渡)= 2 x 200 x 200 x 4 + 320 x 200 x 4 = 576000字节

这确保了两页之间的过渡动画平滑。如果没有过渡动画,可以使用尺寸要求最大的页面

缓存大小(不带过渡)= 2 x 200 x 200 x 4 = 320000字节

有关图像缓存大小的更多信息,请参阅图像缓存页面。

应用程序使用的图像缓存大小可以通过查看Qt Quick Ultralite性能日志来查看。

预加载资源占用的RAM

预加载资源占用的RAM量取决于你在项目中如何配置资源预加载。默认情况下,所有图像、字体和Qt Quick Ultralite项数据资源都在应用程序启动时预加载到RAM中。使用此选项,预加载资源的RAM使用量可能会很高,对于所有Qt Quick Ultralite资源部分的总和(没有ImageFiles.MCU.resourceCompression)。有关如何获得Qt Quick Ultralite资源部分的大小,请参阅闪存使用情况

可以通过设置 QmlProject 属性来控制行为 ImageFiles.MCU.resourceCachePolicy。如果定义在 ImageFiles 中,也可以为单个资源设置,如果定义在 MCU.Config 中,则可以设置所有资源的预加载。有关 ImageFiles.MCU.resourceCachePolicy 以及变量取可能值得信息,请参阅 ImageFiles.MCU.resourceCachePolicy

在特定 Qt 许可证下提供。
了解更多。