c 中的 x64 内联汇编以对齐指令
x64 inline assembly in c to align instructions
我有一个非常热的指令循环,需要在 32 字节边界上正确对齐以最大化 Intel's Instruction Fetcher 有效性。
此问题特定于英特尔不太旧的 CPU 系列(从 Sandy Bridge 开始)。未能正确对齐循环的开头会导致高达 20% 的速度损失,这绝对是太明显了。
这个问题很少见,需要一组高度优化的指令才能使指令获取器成为瓶颈。但幸运的是,这不是个案。下面是 nice article explaining in details 如何检测此类问题。
问题是,gcc 和 clang 都不会关心正确对齐这个指令循环。它使编译此代码成为产生随机结果的噩梦,这取决于 "good" 热循环如何偶然对齐。这也意味着修改一个完全不相关的函数 none 会严重影响热循环的性能。
已经尝试了几个编译器标志,其中 none 个给出了令人满意的结果。
[编辑] 尝试过的编译标志的更详细描述:
-falign-functions=32
:无影响或负面影响
-falign-jumps=32
:无影响
-falign-loops=32
:当热循环被隔离成一小段测试代码时工作正常。但在正常构建中,编译标志应用于整个源代码,在这种情况下它是有害的:在 32 字节上对齐 all 循环不利于性能。只有非常热门的人才能从中受益。
- 还试图在函数声明中使用
__attribute__((optimize("align-loops=32")))
。不产生任何影响(生成相同的二进制文件,就好像该语句不存在一样)。后来被 gcc
支持团队确认为有效忽略。 编辑:@Jester 在评论中指出该语句适用于 gcc 5+。不幸的是,我的开发站主要使用 gcc 4.8.4,这更多是一个可移植性问题,因为我不控制构建过程中使用的最终编译器。
只有使用 PGO 构建才能可靠地产生预期的性能,但 PGO 不能作为解决方案被接受,因为这段代码将使用自己的构建链集成到其他程序中。
所以,我正在考虑内联汇编。
这将特定于 x64 指令集,因此不需要可移植性。
如果我的理解是正确的,像 NASM 这样的汇编允许使用诸如 ALIGN 32
这样的语句,这将强制下一条指令在 32 字节边界上对齐。
由于目标源代码是用C语言编写的,因此有必要包含此语句。例如,类似 asm("ALIGN 32");
(这当然行不通)。
我希望这主要是了解正确的编写指令的问题,而不是诸如 "it's impossible" 之类的更深层次的问题。
与NASM类似,GNU汇编器支持.align
伪OP对齐:
volatile asm (".align 32");
对于非汇编解决方案,您可以尝试提供 -falign-loops=32
,并可能根据需要提供 -falign-functions=32
、-falign-jumps=32
。
我有一个非常热的指令循环,需要在 32 字节边界上正确对齐以最大化 Intel's Instruction Fetcher 有效性。
此问题特定于英特尔不太旧的 CPU 系列(从 Sandy Bridge 开始)。未能正确对齐循环的开头会导致高达 20% 的速度损失,这绝对是太明显了。 这个问题很少见,需要一组高度优化的指令才能使指令获取器成为瓶颈。但幸运的是,这不是个案。下面是 nice article explaining in details 如何检测此类问题。
问题是,gcc 和 clang 都不会关心正确对齐这个指令循环。它使编译此代码成为产生随机结果的噩梦,这取决于 "good" 热循环如何偶然对齐。这也意味着修改一个完全不相关的函数 none 会严重影响热循环的性能。
已经尝试了几个编译器标志,其中 none 个给出了令人满意的结果。
[编辑] 尝试过的编译标志的更详细描述:
-falign-functions=32
:无影响或负面影响-falign-jumps=32
:无影响-falign-loops=32
:当热循环被隔离成一小段测试代码时工作正常。但在正常构建中,编译标志应用于整个源代码,在这种情况下它是有害的:在 32 字节上对齐 all 循环不利于性能。只有非常热门的人才能从中受益。- 还试图在函数声明中使用
__attribute__((optimize("align-loops=32")))
。不产生任何影响(生成相同的二进制文件,就好像该语句不存在一样)。后来被gcc
支持团队确认为有效忽略。 编辑:@Jester 在评论中指出该语句适用于 gcc 5+。不幸的是,我的开发站主要使用 gcc 4.8.4,这更多是一个可移植性问题,因为我不控制构建过程中使用的最终编译器。
只有使用 PGO 构建才能可靠地产生预期的性能,但 PGO 不能作为解决方案被接受,因为这段代码将使用自己的构建链集成到其他程序中。
所以,我正在考虑内联汇编。 这将特定于 x64 指令集,因此不需要可移植性。
如果我的理解是正确的,像 NASM 这样的汇编允许使用诸如 ALIGN 32
这样的语句,这将强制下一条指令在 32 字节边界上对齐。
由于目标源代码是用C语言编写的,因此有必要包含此语句。例如,类似 asm("ALIGN 32");
(这当然行不通)。
我希望这主要是了解正确的编写指令的问题,而不是诸如 "it's impossible" 之类的更深层次的问题。
与NASM类似,GNU汇编器支持.align
伪OP对齐:
volatile asm (".align 32");
对于非汇编解决方案,您可以尝试提供 -falign-loops=32
,并可能根据需要提供 -falign-functions=32
、-falign-jumps=32
。