Simpleperf 三部曲 (三)
本文是对性能分析工具 Simpleperf 使用文档总结, 也可以看作是文档翻译.
本篇原文见 Scripts reference.
记录分析数据
app_profiler.py
app_profiler.py
用于记录 Android 应用程序和本地可执行文件的分析数据.
1 | # 记录一个 Android 应用程序. |
从应用程序启动时进行分析
有时我们想分析应用程序的启动时间. 为支持这一点, 我们在 record 命令中添加了 --app 选项. --app 选项设置要分析的 Android 应用程序的包名. 如果应用程序尚未运行, record 命令将以 1 毫秒的间隔轮询应用程序进程. 因此, 要从应用程序启动时开始分析, 我们可以先使用 --app 启动 record 命令, 然后再启动应用程序. 下面是一个示例.
1 | $ ./run_simpleperf_on_device.py record --app simpleperf.example.cpp \ |
为了方便使用, app_profiler.py 支持使用 -a
选项在记录开始后启动一个 Activity.
1 | ./app_profiler.py -p simpleperf.example.cpp -a .MainActivity |
binary_cache_builder.py
binary_cache
目录是一个保存分析数据文件所需二进制文件的目录. 这些二进制文件应为未剥离版本, 包含调试信息和符号表. report 脚本使用 binary_cache
目录读取二进制文件的符号, report_html.py
也使用该目录生成带注释的源代码和反汇编代码.
默认情况下, app_profiler.py
在记录后构建 binary_cache
目录. 但我们也可以使用 binary_cache_builder.py
为现有的分析数据文件构建 binary_cache
. 这在您直接使用 simpleperf record
进行系统范围的分析或在未连接 USB 线缆的情况下记录数据时非常有用.
binary_cache_builder.py
可以从 Android 设备中拉取二进制文件, 或在主机上的目录中查找二进制文件 (通过 -lib 选项) .
1 | # Generate binary_cache for perf.data, by pulling binaries from the device. |
run_simpleperf_on_device.py
这个脚本将 simpleperf 可执行文件推送到设备上, 并在设备上运行 simpleperf 命令. 它比手动运行 adb 命令更方便.
查看分析数据
本节中的脚本用于查看分析结果或将分析数据转换为外部 UI 使用的格式. 有关推荐的 UI, 请参见 view_the_profile.md.
report.py
report.py
是主机上 report 命令的包装器. 它接受 report 命令的所有选项.
1 | # 报告调用图 |
report_html.py
report_html.py
根据分析数据生成 report.html
. 然后 report.html
可以在不依赖其他文件的情况下显示分析结果. 因此, 它可以在本地浏览器中显示或传输到其他机器上. 根据使用的命令行选项, report.html
的内容可以包括: 图表统计, 样本表, 火焰图, 每个函数的注释源代码, 每个函数的注释反汇编.
1 | # 基于 perf.data 生成图表统计, 样本表和火焰图. |
下面是为 SimpleperfExampleCpp 生成 html 分析结果的示例.
1 | ./app_profiler.py -p simpleperf.example.cpp |
在浏览器中打开生成的 report.html 后, 有几个标签页:
第一个标签页是 "Chart Statistics". 您可以点击饼图以显示每个进程, 线程, 库和函数所消耗的时间.
第二个标签页是 "Sample Table". 它显示每个函数所花费的时间. 通过点击表格中的一行, 我们可以跳转到一个名为"Function"的新标签页.
第三个标签页是 "Flamegraph". 它显示了由 inferno 生成的图表.
第四个标签页是 "Function". 只有当用户点击 "Sample Table" 标签页中的一行时才会出现. 它显示一个函数的信息, 包括:
- 显示该函数调用的函数的火焰图.
- 显示调用该函数的函数的火焰图.
- 该函数的注释源代码. 只有在该函数有源代码文件时才会出现.
- 该函数的注释反汇编. 只有在包含该函数的二进制文件存在时才会出现.
inferno
inferno 是一个用于在 HTML 文件中生成火焰图的工具.
1 | # 基于 perf.data 生成火焰图. |
purgatorio
purgatorio 是一个可视化工具, 用于按时间顺序显示样本.
pprof_proto_generator.py
它将分析数据文件转换为 pprof.proto 格式, 该格式由 pprof 使用.
1 | # 将当前目录中的 perf.data 转换为 pprof.proto 格式. |
gecko_profile_generator.py
将 perf.data 转换为 Gecko Profile 格式, 该格式可被 https://profiler.firefox.com/ 读取.
Firefox Profiler 是一个功能强大的通用分析器 UI, 可以在任何浏览器 (不仅仅是 Firefox) 本地运行, 具有:
- 每线程轨迹
- 火焰图
- 搜索, 聚焦于特定的堆栈
- 时间序列视图, 以时间戳顺序查看样本
- 按线程和持续时间过滤
使用方法:
1 | # 记录应用程序的分析数据 |
然后在 https://profiler.firefox.com/ 中打开 gecko-profile.json.gz.
report_sample.py
report_sample.py 将分析数据文件转换为 linux-perf-tool 输出的 perf 脚本文本格式.
这种格式可以导入到:
- FlameGraph
- Flamescope
- Firefox Profiler, 但更推荐使用 gecko_profile_generator.py.
- Speedscope
1 | # 将分析数据记录到 perf.data |
stackcollapse.py
stackcollapse.py 将分析数据文件 (perf.data) 转换为 Brendan Gregg 的 "折叠堆栈" 格式.
折叠堆栈是以分号分隔的堆栈帧 (从根到叶) , 后跟在该堆栈中采样的事件计数的行, 例如:
1 | BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run 17889729 |
所有相似的堆栈都被聚合, 样本时间戳不被使用.
折叠堆栈格式可被以下工具读取:
- The FlameGraph toolkit
- Inferno (FlameGraph 的 Rust 移植版)
- Speedscope
示例:
1 | # 将分析数据记录到 perf.data |
一些工具库
simpleperf_report_lib.py
simpleperf_report_lib.py 是一个用于解析由 record 命令生成的分析数据文件的 Python 库. 内部它使用 libsimpleperf_report.so 来完成工作. 通常, 对于每个分析数据文件, 我们创建一个 ReportLib 实例, 传递文件路径 (通过 SetRecordFile) . 然后我们可以通过 GetNextSample() 读取所有样本. 对于每个样本, 我们可以读取其事件信息 (通过 GetEventOfCurrentSample) , 符号信息 (通过 GetSymbolOfCurrentSample) 和调用链信息 (通过 GetCallChainOfCurrentSample) . 我们还可以获取一些全局信息, 如记录选项 (通过 GetRecordCmd) , 设备架构 (通过 GetArch) 和元信息字符串 (通过 MetaInfo) .
使用 simpleperf_report_lib.py 的示例可以在 report_sample.py, report_html.py, pprof_proto_generator.py 和 inferno/inferno.py 中找到.
ipc.py
ipc.py 捕获系统在指定持续时间内的每周期指令数 (IPC) .
示例:
1 | ./ipc.py |
结果如下所示:
1 | K_CYCLES K_INSTR IPC |
sample_filter.py
sample_filter.py 根据 sample_filter.md 中的文档生成样本过滤器文件. 运行报告脚本时, 可以通过 --filter-file
选项传递过滤器文件.
例如, 它可以用于将一个大型记录文件拆分为多个报告文件.
1 | $ sample_filter.py -i perf.data --split-time-range 2 -o sample_filter |