ARM 性能优化实战(五):工具篇——QEMU 交叉编译、perf 与 valgrind

前面四篇的 ARM 用例,都是在 x86_64 机器上交叉编译成 aarch64、再用 QEMU 跑出来的。工欲善其事,必先利其器——这一篇把这条「工具链」拆开讲清楚:QEMU 交叉编译环境怎么搭、perf 怎么用、valgrind 怎么用,并给出可以直接照抄的命令。

一、QEMU 交叉编译环境搭建

1. 为什么用 QEMU

开发机通常是 x86,但目标跑在 ARM(手机 / 单板 / 服务器)。qemu-aarch64 是用户态模拟器,能直接在 x86 上运行 aarch64 二进制,不用真机就能验证 ARM 代码、跑分对比。这是本项目「ARM 一列实测数据」的来源。

2. 装交叉编译器(免 root)

在没 sudo 的环境里,可以用 apt-get download 把包下下来、再用 dpkg -x 解压到本地目录:

# 交叉编译器 + aarch64 的 glibc/头文件
apt-get download gcc-aarch64-linux-gnu libc6-dev-arm64-cross linux-libc-dev-arm64-cross
mkdir -p toolchain && for d in *.deb; do dpkg -x "$d" toolchain/; done

3. 装 qemu-aarch64-static

apt-get download qemu-user-static
dpkg -x qemu-user-static_*.deb qemu/
cp qemu/usr/bin/qemu-aarch64-static toolchain/qemu-aarch64-static

⚠️ 踩坑:GitHub 上 multiarch 仓库的 qemu-aarch64-static 老版本(v7.2.0)在本机一启动就段错误,改用 Ubuntu 官方包里的 qemu-aarch64-static 8.2.2 才正常。所以优先用发行版自带的包。

4. 编译 + 运行

# 静态链接,省去在 QEMU 里配动态链接器和 libc 路径的麻烦
aarch64-linux-gnu-gcc -static -O2 test.c -o test.aarch64
./qemu-aarch64-static test.aarch64

5. 一键脚本

这套流程我固化到了 arm-perf 项目里:

scripts/fetch-toolchain.sh   # 自动下载交叉编译器 + qemu(幂等)
scripts/aarch64-cc.sh        # 交叉编译 wrapper(自动带 sysroot/binutils)
make aarch64                 # 交叉编译全部用例
make run-arm                 # 用 qemu-aarch64 批量跑分

二、perf 性能分析

perf 是 Linux 内核自带的性能分析工具,基于 PMU 硬件计数器,能看整体指标、也能定位热点函数。

1. perf stat:整体计数

perf stat -e cycles,instructions,cache-misses,branch-misses ./a.out

重点看 IPC = instructions / cycles(越高越好)和 cache-misses(访存瓶颈)。

2. perf record + report:找热点函数

perf record -g ./a.out      # -g 记录调用栈
perf report                 # 交互式查看热点函数占比

3. perf top:实时观察

perf top                    # 像 top 一样实时显示热点

4. 火焰图(可选,最直观)

perf record -g ./a.out
perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg

5. 权限问题(高频坑)

如果报 Access to performance monitoring ... is limited,是 perf_event_paranoid 在限制:

cat /proc/sys/kernel/perf_event_paranoid   # 4 = 完全禁用
sudo sysctl kernel.perf_event_paranoid=1   # 需要 root 放开

在容器 / 无 sudo 环境(比如本项目)perf 会被锁死,此时退回到进程内高精度计时(clock_gettime(CLOCK_MONOTONIC))兜底——这也是 arm-perf 用例的计时方式。

三、valgrind 分析

valgrind 是动态二进制分析工具,无需重新编译,但需要先安装:sudo apt install valgrind。

1. memcheck:内存错误 / 泄漏

valgrind --leak-check=full ./a.out

2. callgrind:函数调用耗时

valgrind --tool=callgrind ./a.out
callgrind_annotate callgrind.out.<pid>

3. cachegrind:缓存命中率

valgrind --tool=cachegrind ./a.out
cg_annotate cachegrind.out.<pid>

看 D1mr / DLmr(一级/末级缓存读未命中率),判断访存是否友好。

4. massif:堆内存占用

valgrind --tool=massif ./a.out
ms_print massif.out.<pid>

四、小结:工具怎么选

目标 工具
整体指标(cycles / IPC / cache-miss) perf stat
找热点函数 perf record + report
缓存行为 / 访存友好度 cachegrind / perf stat -e cache-misses
内存泄漏 / 越界 valgrind memcheck
函数调用耗时 callgrind
ARM 代码在 x86 上验证 qemu-aarch64 + 交叉编译

一句话:先 perf stat 看整体有没有瓶颈,再 perf record 定位热点函数,访存问题用 cachegrind,内存问题用 memcheck,ARM 验证用 QEMU。


本系列回到《传统ARM优化的思考》看总述,或翻「性能优化」分类下的其他文章。

Leave a Comment

您的邮箱地址不会被公开。 必填项已用 * 标注

Scroll to Top