Skip to content

简易采样性能分析器

本节介绍如何使用简易采样性能分析器(PMSP)shell 脚本评估 PX4 的性能。 这是对最初由马克·卡拉汉(Mark Callaghan)和多马斯·米图扎斯(Domas Mituzas)发明的一种已知方法的实现。

方法

PMSP 是一种 shell 脚本,它通过定期中断固件的执行来运行,以便对当前堆栈跟踪进行采样。 采样的堆栈跟踪将追加到文本文件中。 一旦采样完成(通常需要大约一个小时或更长时间),收集到的堆栈跟踪将被“折叠”。 “折叠”的结果是另一个文本文件,其中包含相同的堆栈跟踪,不同之处在于所有相似的堆栈跟踪(即在程序中同一点获取的那些堆栈跟踪)都合并在一起,并记录它们出现的次数。 然后将折叠后的堆栈输入到可视化脚本中,为此我们使用了火焰图(FlameGraph)—— 一个开源的堆栈跟踪可视化工具

基本用法

系统必备组件

该分析器的基本用法可在生成系统上使用。 例如,下面的命令为 px4_fmu-v4pro 目标生成并分析 10000 个样本(获取 火焰图(FlameGraph) 并根据需要将其添加到路径中)。 然后,你将需要一个调试探针(例如 DroneCode 探针),来运行 GDB 服务器并与开发板进行交互。

确定调试器设备

如果你将 poor-mans-profiler.sh 脚本与 DroneCode 探针配合使用,它会自动检测并使用正确的 USB 设备。 如果你使用的是其他类型的探针,可能需要传入调试器所在的特定 “设备”。 在 Ubuntu 系统上,你可以使用 bash 命令 ls -alh /dev/serial/by-id/ 来枚举可能的设备。 例如,当通过 USB 连接了 Pixhawk 4 和 DroneCode 探针时,会枚举到以下设备:

sh
user@ubuntu:~/PX4-Autopilot$ ls -alh /dev/serial/by-id/
total 0
drwxr-xr-x 2 root root 100 Apr 23 18:57 .
drwxr-xr-x 4 root root  80 Apr 23 18:48 ..
lrwxrwxrwx 1 root root  13 Apr 23 18:48 usb-3D_Robotics_PX4_FMU_v5.x_0-if00 -> ../../ttyACM0
lrwxrwxrwx 1 root root  13 Apr 23 18:57 usb-Black_Sphere_Technologies_Black_Magic_Probe_BFCCB401-if00 -> ../../ttyACM1
lrwxrwxrwx 1 root root  13 Apr 23 18:57 usb-Black_Sphere_Technologies_Black_Magic_Probe_BFCCB401-if02 -> ../../ttyACM2

在这种情况下,脚本会自动选取名为 *Black_Magic_Probe*-if00 的设备。 但如果你使用的是其他设备,可以从上面的列表中找到合适的设备 ID。

然后使用 --gdbdev 参数传入合适的设备,如下所示:

sh
./poor-mans-profiler.sh --elf=build/px4_fmu-v4_default/px4_fmu-v4_default.elf --nsamples=30000

运行

在火焰图上,水平方向表示堆叠帧,而每个帧的宽度与采样次数成正比。 例如,以下命令为 px4_fmu-v4pro 目标构建并分析 10000 个样本(根据需要获取 火焰图(FlameGraph) 并将其添加到路径中)。

sh
./poor-mans-profiler.sh --elf=build/px4_fmu-v4_default/px4_fmu-v4_default.elf --nsamples=30000 --append

如需对构建过程进行更多控制,包括设置样本数量,请参阅实现部分

理解输出

下面提供了一个示例输出的截图(请注意,此处截图并非交互式的):

火焰图示例

PMSP 使用 GDB 收集堆栈跟踪。 目前,它使用 arm-none-eabi-gdb,未来可能会添加其他工具链。

可能的问题

为了能够将内存地址映射到符号,脚本需要引用当前在目标设备上运行的可执行文件。 这是通过 --elf=<文件> 选项来实现的,该选项需要一个指向当前正在执行的 ELF 文件位置的路径(相对于存储库的根目录)。

  • 如果 GDB 出现故障,脚本可能无法检测到该问题,并会继续运行。 在这种情况下,显然不会生成可用的堆栈。 为了避免这种情况,用户应定期检查文件 /tmp/pmpn-gdberr.log,该文件包含最近一次调用 GDB 时的标准错误输出。 将来,应修改脚本,使其在安静模式下调用 GDB,在安静模式下,GDB 将通过其退出代码指示问题。

  • 有时 GDB 会在采样堆栈跟踪时一直运行。 在这种失败情况下,目标设备将无限期停止。 解决方法是手动中止脚本,然后使用 --append 选项重新启动它。 将来,应修改脚本,对每次 GDB 调用强制执行超时。

  • 不支持多线程环境。 这不会影响单个核心嵌入式目标,因为它们总是在单个线程中执行,但这一限制使该分析器与许多其他应用程序不兼容。 将来,应修改堆栈折叠部分,以支持每个样本的多个堆栈跟踪。

实现

该脚本位于 /platforms/nuttx/Debug/poor-mans-profiler.sh 一旦启动,它将按照指定的时间间隔执行指定数量的采样。 收集到的样本将存储在系统临时目录(通常是 /tmp)中的一个文本文件中。 采样完成后,脚本将自动调用堆栈折叠程序,其输出将存储在临时目录中的相邻文件中。 如果堆栈折叠成功,脚本将调用 火焰图(FlameGraph) 脚本,并将结果存储在一个交互式 SVG 文件中。 请注意,并非所有图像查看器都支持交互式图像; 建议在 Web 浏览器中打开生成的 SVG 文件。

火焰图脚本必须位于 PATH 环境变量中,否则 PMSP 将拒绝启动。

PMSP 使用 GDB 收集堆栈跟踪。 目前它使用 arm-none-eabi-gdb,未来可能会添加其他工具链。

为了能够将内存位置映射到符号,脚本需要引用当前在目标设备上运行的可执行文件。 这是通过 --elf=<文件> 选项来实现的,该选项需要一个路径(相对于存储库的根目录),指向当前正在执行的 ELF 文件的位置。

这个想法的功劳归属于 马克·卡拉汉(Mark Callaghan)和多马斯·米图扎斯(Domas Mituzas)

sh
./poor-mans-profiler.sh --elf=build/px4_fmu-v4_default/px4_fmu-v4_default.elf --nsamples=30000

请注意,每次启动脚本都会覆盖旧的堆栈。 如果你想将新的堆栈追加到旧堆栈上而不是覆盖它们,请使用 --append 选项:

sh
./poor-mans-profiler.sh --elf=build/px4_fmu-v4_default/px4_fmu-v4_default.elf --nsamples=30000 --append

正如人们可能猜到的那样,使用 --append 选项并将 --nsamples=0 将指示脚本仅重新生成 SVG 文件,而根本不访问目标设备。

请阅读该脚本以更深入地了解其工作原理。