简易采样性能分析器
本节介绍如何使用简易采样性能分析器(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 探针时,会枚举到以下设备:
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
参数传入合适的设备,如下所示:
./poor-mans-profiler.sh --elf=build/px4_fmu-v4_default/px4_fmu-v4_default.elf --nsamples=30000
运行
在火焰图上,水平方向表示堆叠帧,而每个帧的宽度与采样次数成正比。 例如,以下命令为 px4_fmu-v4pro 目标构建并分析 10000 个样本(根据需要获取 火焰图(FlameGraph) 并将其添加到路径中)。
./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)。
./poor-mans-profiler.sh --elf=build/px4_fmu-v4_default/px4_fmu-v4_default.elf --nsamples=30000
请注意,每次启动脚本都会覆盖旧的堆栈。 如果你想将新的堆栈追加到旧堆栈上而不是覆盖它们,请使用 --append
选项:
./poor-mans-profiler.sh --elf=build/px4_fmu-v4_default/px4_fmu-v4_default.elf --nsamples=30000 --append
正如人们可能猜到的那样,使用 --append
选项并将 --nsamples=0
将指示脚本仅重新生成 SVG 文件,而根本不访问目标设备。
请阅读该脚本以更深入地了解其工作原理。