一、Simpleperf 介绍
Simpleperf 是一个通用的命令行 CPU 性能剖析工具,包含在面向 Mac、Linux 和 Windows 的 NDK 中。详细内容请参看官方文档,本文的第一部分主要来自源码中 simpleperf 的介绍 PPT 。
| 概览 | |
|---|---|
| 源码位置 | android.googlesource.com/platform/sy… |
| 适用进程 | android 进程/native 进程 |
| 适用语言 | JAVA/C++ |
| 执行程序要求 | >= L |
| python 脚本要求 | >= N |
| 组成 | linux kernel 支持 + PMU(performance monitor unit) 硬件支持 |
下载工具:
$ git clone https://android.googlesource.com/platform/system/extras ~/extras
$ cd ~/extras/simpleperf/scripts
1.1 simpleperf 工作原理
1.2 ARM PMU
- ARM 手册中有介绍,D7 性能监测扩展
- PMU 计数器:每个 cpu 核有若干个 PMU 计数器。每个计数器占 32-bit,可以监测一个 PMU 事件。当被监测的事件发生时,计数器的值就加1。当一个计数器溢出时,它会触发一次中断。
- PMU 事件:像 CPU_CYCLES,BR_PRED(预测的分支),L1D_CACHE(1级数据缓存访问)等。ARM 展示通用的事件以及如何中断它们。并且时间可以用来获取间接的信息,像缓存命中率 = 缓存计数重填计数 / 缓存访问计数。
- 一般新架构中会新增更多 PMU 事件。
1.3 kernel 支持
perf 事件驱动
- 作为用户空间和 pmu 驱动之间的桥梁,位于 kernel/events
- 将 pmu 事件映射到 perf 事件类型,位于 include/uapi/linux/perf_event.h
- 提供sysfs 接口显示支持的 perf 事件,位于 /sys/bus/event_source
- 提供 perf_event_open 系统调用监测选中的线程性能
pmu 驱动
- 通过 perf_pmu_register() 注册 perf 事件驱动。
- cpu pmu 驱动,操作 ARM PMU,位于 drivers/perf。
- 软件 pmu 驱动,像 cpu 时钟、页错误事件,完整列表位于 perf_sw_ids。
- 跟踪点 pmu 驱动,像 sched:sched_switch 事件,完整列表位于 /sys/kernel/tracing/events。
- 设备指定 pmu 驱动。
二、 simpleperf 指令
- simpleperf 是一个运行在设备上的可执行文件,位于 /system/bin。
- simpleperf 将其功能划分到子命令中。
- list 指令:展示设备上可用的 perf 事件
- stat 指令:监测线程,并打印 perf 事件计数器的值
- record 指令:监测线程,并生成采样的分析数据
- report 指令:汇报由 record 指令生成的分析数据
- simpleperf 也提供运行在主机上的 python 脚本
- 帮助 record
- 帮助 report
list 指令:展示可用的事件
$ simpleperf list
List of hw-cache events:
# More cache events are available in `simpleperf list raw`.
branch-load-misses
branch-loads
dTLB-load-misses
dTLB-loads
iTLB-load-misses
iTLB-loads
L1-dcache-load-misses
L1-dcache-loads
L1-icache-load-misses
L1-icache-loads
LLC-load-misses
LLC-loads
List of coresight etm events:
List of hardware events:
branch-misses
bus-cycles
cache-misses
...
stat 指令:获取 perf 事件计数器的值
stat 指令:选项
simpleperf stat -h
Usage: simpleperf stat [options] [command [command-args]]
Gather performance counter information of running [command].
选项:
-p pid1,pid2,... Stat events on existing processes.
-t tid1,tid2,... Stat events on existing threads.
-a Collect system-wide information.
--cpu cpu_item1,cpu_item2,...
Collect information only on the selected cpus. cpu_item can
-e event1[:modifier1],event2[:modifier2],...
Select a list of events to count.
--duration time_in_sec Monitor for time_in_sec seconds instead of running
[command].
stat 指令:例子
# simpleperf stat -e cache-references,cache-misses -a --duration 1
Performance counter statistics:
# count event_name # count / runtime, runtime / enabled_time
34,724,046 cache-references # 4.306 M/sec (100%)
620,325 cache-misses # 1.786442% miss rate (100%)
Total test time: 1.001952 seconds.
record 指令:生成采样的分析数据
record 指令:选项
# simpleperf record -h
Usage: simpleperf record [options] [--] [command [command-args]]
Gather sampling information of running [command].
选项:
-p pid1,pid2,... Record events on existing processes.
-t tid1,tid2,... Record events on existing threads.
-a System-wide collection.
--cpu cpu_item1,cpu_item2,...
Collect samples only on the selected cpus.
-e event1[:modifier1],event2[:modifier2],...
Select a list of events to record.
-f freq Set event sample frequency.It means recording at most [freq]
samples every second.
--duration time_in_sec Monitor for time_in_sec seconds
-o record_file_name Set record file name, default is perf.data.
-g Same as '--call-graph dwarf'.
record 指令:例子
$ simpleperf record -g sleep 1
simpleperf I cmd_record.cpp:696] Recorded for 1.01908 seconds. Start post processing.
simpleperf I cmd_record.cpp:771] Samples recorded: 56. Samples lost: 0.
record 指令:采样格式
分析数据包含一个采样列表。 每个采样可以包含以下信息(完整列表在此):
time - CLOCK_MONOTONIC 中的时间戳
pid,tid - 进程 id,线程id
cpu - cpu
period - 自上次采样后发生了多少事件
ips[] - 调用栈(基于调用栈的栈帧指针)
regs[] - 用户空间寄存器值
stack[] - 用户栈数据最多 64kb
基于 dwarf 的调用栈是由堆栈展开生成
report 指令:汇报分析数据
$ simpleperf report
Cmdline: /system/bin/simpleperf record -g sleep 1
Arch: arm64
Event: cpu-cycles (type 0, config 0)
Samples: 56
Event count: 13885436
Overhead Command Pid Tid Shared Object Symbol
9.61% sleep 14852 14852 [kernel.kallsyms] vma_link
8.97% sleep 14852 14852 linker64 soinfo_do_lookup_impl
6.42% sleep 14852 14852 linker64 BionicAllocator::alloc_impl
6.11% sleep 14852 14852 [kernel.kallsyms] __follow_mount_rcu
5.83% sleep 14852 14852 [kernel.kallsyms] clear_page
在主机上汇报分析数据
将记录文件拉到主机上并使用多汇报方法(脚本位置在此)
二、工具使用
虽然 simpleperf 既有设备上的可执行文件也有 python 脚本,但相对来说 python 脚本使用更便捷。
Python 脚本使用
脚本路径:/AOSP/system/extras/simpleperf/script
常用脚本:
- app_profiler.py:用于录制,在主机上执行 simpleperf。
- run_simpleperf_on_device.py:用于录制,在手机上执行 simpleperf。
- gecko_profile_generator.py:用于转换 perf.data 文件用于可视化工具解析。
操作步骤
- record 录制;
- 使用 run_simpleperf_on_device.py:
./run_simpleperf_on_device.py record --app <包名> -g --duration <时间> -o /data/local/tmp/perf.data
- 使用 app_profiler.py:
./app_profiler.py --pid <应用PID> -r "-e cpu-clock -g --duration <时间> -o /data/local/tmp/perf.data"
# native 进程
./app_profiler.py --np <进程名> -r "-e cpu-clock -g --duration <时间> -o /data/local/tmp/perf.data"
- 拉出生成的分析数据文件;
- report 转换 perf.data 成 UI 工具可以解析的格式;
./gecko_profile_generator.py -i ./perf.data | gzip > perf.json.gz
使用 UI 工具查看分析数据文件
例子:
三、常见问题
- “Can't create output file in directory .: Read-only file system”
$ simpleperf record -p 9643 -e cpu-clock -g --duration 5
simpleperf E cmd_record.cpp:532] Can't create output file in directory .: Read-only file system
使用 “-o” 指令重定向目标文件位置。
$ simpleperf record -p 9643 -e cpu-clock -g --duration 5 -o sdcard/perf.data
simpleperf I cmd_record.cpp:798] Recorded for 5.01924 seconds. Start post processing.
simpleperf I cmd_record.cpp:891] Samples recorded: 0. Samples lost: 0.
- 运行 simpleperf 的 Python 脚本需要 Python3.9及以上版本,如果不想升级可以使用3.8并修改 simpleperf_utils.py。
参考文档: