程序整体跑 10 秒、热循环只占 0.5 秒时,即使把热循环优化一倍,time 命令上的变化也只有 2.5%,完全被噪声淹没。要测出微优化是否真的生效,只能在代码内部打时间戳。
AArch64 的虚拟计数器 cntvct_el0 可以在用户态直接读,一条 mrs 指令,频率由 cntfrq_el0 给出且固定不变。内核读取时的写法是 isb 前缀加 mrs:isb 是指令同步屏障,防止读计数器与相邻指令被乱序重排,否则量出的区间会包含本不该计入的指令。最容易踩的坑是把它的频率当成 CPU 主频——cntfrq_el0 通常是 24MHz 或 50MHz 的固定值,不随 CPU 变频变化,用它算周期数或每周期指令数会得到荒谬结果;要读真实周期数应当用 perf stat -e cycles,instructions。
基准测试的通用做法是取 10 次重复里最快的一次而不是平均值,最快值受干扰最小。测试数据规模直接决定结论:数组放大到 64MB 远超 L3 后,瓶颈从计算转移到内存带宽,向量化带来的计算加速会被带宽掩盖,呈现「看起来该快但没快」;想看纯计算性能要把数组缩到能装进 L1。取数组时用 16 字节对齐分配,可以避免非对齐访问带来的额外损失。
同一个标量加法对 NEON 向量加法的实验,只加一个 -fno-tree-vectorize 选项,结论就从「没差别」变成「差很多」——因为 -O2 已经自动向量化了标量循环。任何性能结论都必须连同编译命令一起报告,脱离编译选项谈性能没有意义。虚拟机环境下 cntvct_el0 的读取可能因陷入 hypervisor 而变慢,关键测量应优先放在物理机,或至少在同一宿主机上跑对照组。