3. perf 工具安装与配置:在嵌入式目标板上交叉编译、安装与内核事件源配置

在嵌入式 Linux 启动性能分析场景中,目标板通常资源受限(无完整开发工具链、存储空间小),无法直接在板上运行 apt install perf 或 yum install perf。正确的做法是在 宿主机(Host) 上使用交叉编译工具链为 目标板(Target) 构建 perf 二进制,再将其部署到目标板文件系统中。同时,需要确保内核开启了 perf_event_open 系统调用及相关事件源,否则 perf 无法采集任何数据。

3.1 交叉编译 perf:从内核源码树中构建

perf 工具的源码位于 Linux 内核源码树的 tools/perf/ 目录下。它不依赖复杂的 autotools,而是使用 make 配合内核构建系统。交叉编译的关键在于指定正确的 交叉编译工具链前缀 和 目标架构。

前置条件:宿主机已安装目标架构的交叉编译工具链(如 arm-linux-gnueabihf-gcc、aarch64-linux-gnu-gcc),且内核源码版本与目标板运行的内核版本一致或非常接近。

3.1.1 编译步骤

  1. 进入 perf 源码目录
    cd <kernel-source>/tools/perf
  2. 配置交叉编译环境变量
    export CROSS_COMPILE=arm-linux-gnueabihf-
    export ARCH=arm

    对于 64 位 ARM 平台:

    export CROSS_COMPILE=aarch64-linux-gnu-
    export ARCH=arm64
  3. 执行 make 编译
    make -j$(nproc)

    编译完成后,当前目录下会生成 perf 可执行文件。使用 file perf 命令确认其架构是否正确。

  4. 精简二进制(可选)

    嵌入式环境存储空间有限,可使用 strip 工具去除符号表:

    ${CROSS_COMPILE}strip perf

3.1.2 常见编译选项与依赖

选项 / 依赖 说明 嵌入式建议
NO_LIBELF=1 禁用 ELF 解析(影响符号解析) 若不需要符号翻译,可开启以减小体积
NO_NEWT=1 禁用 TUI 界面 嵌入式通常不需要图形界面,建议开启
NO_LIBUNWIND=1 禁用 unwind 库(影响调用链) 若只需采样,可关闭;若需调用链则需开启
NO_LIBNUMA=1 禁用 NUMA 支持 单核或非 NUMA 系统建议开启
NO_SLANG=1 禁用 slang 库(影响报表显示) 建议开启,减少依赖

示例:最小化编译命令:

make -j$(nproc) \
  NO_LIBELF=1 \
  NO_NEWT=1 \
  NO_LIBUNWIND=1 \
  NO_LIBNUMA=1 \
  NO_SLANG=1 \
  NO_LZMA=1 \
  NO_BACKTRACE=1

3.2 安装 perf 到目标板

将编译好的 perf 二进制部署到目标板,通常有两种方式:

  • 直接拷贝到根文件系统: 将 perf 放入目标板的 /usr/bin/ 或 /usr/local/bin/,并赋予执行权限:
    cp perf /path/to/rootfs/usr/bin/
    chmod +x /path/to/rootfs/usr/bin/perf
  • 通过 NFS 挂载: 在开发阶段,可将宿主机上的 perf 路径通过 NFS 共享给目标板,直接运行。
验证安装: 在目标板上执行 perf --version,确认输出与内核版本匹配。执行 perf list 可查看目标板支持的事件列表。

3.3 配置内核事件源:perf_event_open 系统调用

perf 工具的核心依赖于内核的 perf_event_open 系统调用。如果内核编译时未开启相关配置,perf 将无法工作,典型错误为:No permission to enable perf_event_open syscall 或 perf_event_open failed: Operation not permitted。

3.3.1 内核配置选项

确保内核 .config 中包含以下选项(通常位于 General setup —> Kernel Performance Events And Counters 菜单下):

配置项 含义 推荐值
CONFIG_PERF_EVENTS 性能事件核心支持 y
CONFIG_HW_PERF_EVENTS 硬件性能计数器支持(如 PMU) y
CONFIG_SOFT_EVENTS 软件事件支持(如 context-switches) y
CONFIG_TRACEPOINTS tracepoint 事件支持(如 sched/sched_switch) y
CONFIG_FTRACE Ftrace 支持(perf 依赖其基础设施) y
CONFIG_KALLSYMS 内核符号表(用于符号解析) y

3.3.2 用户空间权限配置

即使内核支持 perf_event_open,非 root 用户也可能无法使用。可通过以下方式调整:

  • 临时方案: 在目标板上以 root 用户运行 perf。
  • 永久方案: 设置 kernel.perf_event_paranoid 内核参数。该参数值含义如下:
    值 含义
    2 只允许 root 用户使用(默认值)
    1 允许非 root 用户使用,但禁用某些高精度事件
    0 允许非 root 用户使用所有事件
    -1 完全无限制(不推荐)

    在目标板上执行:

    echo 1 > /proc/sys/kernel/perf_event_paranoid

    或通过 sysctl 永久配置:

    sysctl -w kernel.perf_event_paranoid=1

3.4 perf_event_open 系统调用流程

perf 工具通过 perf_event_open 系统调用与内核交互。下图展示了从用户态 perf 命令到内核事件采集的完整路径:

perf_event_open 系统调用流程 perf 命令(用户态) perf_event_open() 内核 syscall 入口 perf_event_alloc() PMU / tracepoint 注册 ring buffer 分配 硬件 PMU 计数器 软件事件(软计数) tracepoint 事件 说明:perf_event_open 返回一个文件描述符,后续通过 read() / mmap() 读取事件数据

3.5 验证配置是否成功

在目标板上执行以下命令,快速验证 perf 工具和内核事件源是否正常工作:

# 查看 perf 版本
perf --version

# 列出所有可用事件(若输出大量事件列表,说明 tracepoint 和 PMU 正常)
perf list

# 执行一个简单的采样测试(采集 5 秒,统计 CPU 时钟事件)
perf stat -e cycles,instructions,cache-misses sleep 1
常见问题:
  • perf: not found — 二进制未正确部署或路径未包含在 $PATH 中。
  • perf_event_open failed: Operation not permitted — 内核 perf_event_paranoid 值过高,或未以 root 运行。
  • perf_event_open failed: No such device — 内核未开启 CONFIG_HW_PERF_EVENTS,或当前 CPU 不支持 PMU。
  • WARNING: perf not found for kernel x.x.x — perf 版本与内核版本不匹配,建议重新编译。

3.6 本章小结

嵌入式 Linux 启动阶段性能分析的第一步,是确保 perf 工具能够正确运行并采集数据。本章涵盖了从交叉编译、部署安装到内核配置的完整流程。关键要点包括:

  • 使用内核源码树中的 tools/perf/ 进行交叉编译,通过 CROSS_COMPILE 和 ARCH 环境变量指定目标平台。
  • 根据嵌入式资源限制,通过 NO_* 选项裁剪不必要的依赖,减小 perf 二进制体积。
  • 内核必须开启 CONFIG_PERF_EVENTS 及其子选项,并正确设置 perf_event_paranoid 权限。
  • 通过 perf list 和 perf stat 快速验证配置是否生效。