功能对齐在现代处理器上究竟有多重要?

当我使用amd64或x86系统上的最新编译器编译C代码时,函数对齐为16个字节的倍数。 现代处理器上这种对齐方式究竟有多重要? 调用未对齐的函数会带来巨大的性能损失吗?

基准

我运行了以下microbenchmark( call.S ):

// benchmarking performance penalty of function alignment.
#include <sys/syscall.h>

#ifndef SKIP
# error "SKIP undefined"
#endif

#define COUNT 1073741824

        .globl _start
        .type _start,@function
_start: mov $COUNT,%rcx
0:      call test
        dec %rcx
        jnz 0b
        mov $SYS_exit,%rax
        xor %edi,%edi
        syscall
        .size _start,.-_start

        .align 16
        .space SKIP
test:   nop
        rep
        ret
        .size test,.-test

使用以下shell脚本:

#!/bin/sh

for i in `seq 0 15` ; do
        echo SKIP=$i
        cc -c -DSKIP=$i call.S
        ld -o call call.o
        time -p ./call
done

在根据/proc/cpuinfo标识自己为Intel(R)Core(TM)i7-2760QM CPU @ 2.40GHz的CPU上。 偏移对我来说没有什么不同,基准测试运行了1.9秒。

另一方面,在另一个CPU自我报告为Intel(R)Core(TM)i7 CPU L 640 @ 2.13GHz的系统上,基准测试需要6.3秒,除非您的偏移量为14或15,其中该代码需要7.2秒。 我认为这是因为函数开始跨越多个缓存行。


TL; DR :高速缓存对齐很重要。 你不想要你不会执行的字节。

至少,您会希望在执行第一个指令之前避免提取指令。 由于这是一个微基准测试,所以很可能看不出任何区别,但想象一下在完整的程序中,如果因为第一个字节未与高速缓存对齐而对一堆函数有额外的缓存未命中,行,并且最终必须为函数的最后N个字节(其中N <=缓存但未使用的函数之前的字节数)获取新的缓存行。

英特尔的优化手册说:

3.4.1.5代码对齐

仔细安排代码可以增强缓存和内存的局部性。 内存中可能连续排列基本块的可能序列。 这可能涉及从序列中删除不太可能的代码,例如处理错误条件的代码。 关于优化指令预取器,请参见第3.7节“预取”。

3-8汇编/编译器编码规则12.(M影响,H通用性)所有分支目标应该是16字节对齐的。

汇编/编译器编码规则13.(M影响,H一般性)如果条件的主体不可能被执行,它应该被放置在程序的另一部分。 如果它不太可能被执行并且代码局部性是一个问题,它应该被放置在不同的代码页上。

它也有助于解释为什么你没有注意到你的程序有任何不同。 所有的代码都被缓存一次,永远不会离开缓存(当然,模数上下文切换)。

链接地址: http://www.djcxy.com/p/19271.html

上一篇: How much does function alignment actually matter on modern processors?

下一篇: Translations: display translation for dynamically found translation key