2. Perf 环境搭建:Android NDK 环境配置、交叉编译 Perf、在 Android 设备上部署 Perf 二进制
在 Android 驱动开发与调优场景中,目标设备通常运行精简的 Linux 内核,且不包含完整的 perf 工具链。因此,我们需要在主机端使用 Android NDK 提供的交叉编译工具链,为特定架构(如 arm64)编译 perf 二进制,并将其部署到 Android 设备上。本章将详细拆解这一流程,确保你能够搭建一个可复用的 Perf 交叉编译环境。
git、flex、bison、libelf-dev、libssl-dev。
2.1 Android NDK 环境配置
Android NDK 提供了针对不同目标架构的独立工具链。我们使用 NDK 自带的 make_standalone_toolchain.py 脚本或直接使用 CMake 工具链文件来配置交叉编译环境。以下步骤基于 NDK r25c 进行说明。
- 下载并解压 NDK: 从 Google 官方渠道下载
android-ndk-r25c-linux.zip,解压至/opt/android-ndk。 - 设置环境变量: 将 NDK 路径加入
PATH,并导出ANDROID_NDK_HOME。 - 验证工具链: 使用
aarch64-linux-android21-clang++ --version确认交叉编译器可用。
export ANDROID_NDK_HOME=/opt/android-ndk-r25c
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
# 验证
aarch64-linux-android21-clang --version
下表总结了不同 Android 架构对应的 NDK 工具链前缀,编译 Perf 时需根据目标设备选择正确的架构。
| 目标架构 | NDK 工具链前缀 | API 级别示例 | 常见设备 |
|---|---|---|---|
| arm64-v8a | aarch64-linux-android | 21 | Pixel 6/7/8, 高通 SM8550 |
| armeabi-v7a | armv7a-linux-androideabi | 16 | 老旧设备或 IoT 模块 |
| x86_64 | x86_64-linux-android | 21 | Android 模拟器 |
2.2 交叉编译 Perf
Perf 源码位于 Linux 内核树的 tools/perf 目录下。我们不需要完整的内核源码,只需克隆内核仓库并进入该目录即可。交叉编译的核心在于指定正确的 CC、AR、LD 等变量,并禁用本地依赖。
gcc 编译的 Perf 无法在 Android 设备上运行(ABI 不兼容)。必须使用 NDK 的 clang 编译器,并链接 Android 的 libc 与 libm。
以下是针对 arm64 架构的编译步骤:
- 获取内核源码:
git clone --depth=1 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git - 进入 Perf 目录:
cd linux/tools/perf - 配置交叉编译环境: 设置
CC、AR、LD为 NDK 工具链版本。 - 执行 make: 使用
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-android-进行编译。
#!/bin/bash
export NDK=/opt/android-ndk-r25c
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64
export TARGET=aarch64-linux-android
export API=21
export CC=$TOOLCHAIN/bin/${TARGET}${API}-clang
export AR=$TOOLCHAIN/bin/${TARGET}-ar
export LD=$TOOLCHAIN/bin/${TARGET}-ld
cd linux/tools/perf
make ARCH=arm64 CROSS_COMPILE=${TARGET}- \
CC=$CC AR=$AR LD=$LD \
NO_LIBELF=1 NO_LIBUNWIND=1 NO_LIBAUDIT=1 NO_LIBNUMA=1 \
NO_LIBPERL=1 NO_LIBPYTHON=1 NO_LIBBABELTRACE=1 \
-j$(nproc)
编译成功后,会在 linux/tools/perf 目录下生成 perf 可执行文件。使用 file perf 命令确认其架构为 ELF 64-bit LSB executable, ARM aarch64。
2.3 在 Android 设备上部署 Perf 二进制
将编译好的 Perf 二进制推送到 Android 设备,并赋予可执行权限。推荐放置在 /data/local/tmp 目录下,该目录具有可执行权限且重启后不会丢失(但可能被系统清理)。
- 连接设备: 使用
adb devices确认设备已连接。 - 推送二进制:
adb push perf /data/local/tmp/ - 赋予权限:
adb shell chmod 755 /data/local/tmp/perf - 验证运行:
adb shell /data/local/tmp/perf --version
CONFIG_PERF_EVENTS 且 perf_event_paranoid 设置为 1 或更低,普通应用即可使用 Perf。若遇到权限错误,可尝试 adb shell setprop security.perf_harden 0(需要 root 权限)。
部署完成后,建议执行一次简单的 perf list 来验证硬件事件和软件事件是否被正确枚举。如果输出为空或报错,说明内核配置或权限存在问题。
# 推送
adb push perf /data/local/tmp/perf
adb shell chmod 755 /data/local/tmp/perf
# 验证
adb shell /data/local/tmp/perf --version
adb shell /data/local/tmp/perf list 2>&1 | head -20
2.4 交叉编译与部署流程总览
下图展示了从主机环境配置到 Android 设备上运行 Perf 的完整流程,包含关键决策点与验证环节。
2.5 常见问题与排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
perf: not found |
二进制未推送或路径错误 | 使用 adb shell ls -l /data/local/tmp/perf 确认文件存在 |
perf: error while loading shared libraries |
缺少 Android 运行时库或链接错误 | 使用 NDK 的 aarch64-linux-android-readelf -d perf 检查动态库依赖 |
perf: permission denied |
未赋予可执行权限 | 执行 adb shell chmod 755 /data/local/tmp/perf |
perf list 输出为空 |
内核未开启 CONFIG_PERF_EVENTS |
检查 /proc/config.gz 或重新编译内核 |
编译时 fatal error: 'stddef.h' not found |
NDK 工具链路径未正确设置 | 确认 CC 变量指向正确的 clang 二进制 |
perf_event_paranoid 或 SELinux 策略。