gpt4 book ai didi

c++ - 使用 Intel 编译器 : looking at the assembly 的 Windows 和 Linux 之间的性能差异

转载 作者:IT老高 更新时间:2023-10-28 12:13:53 28 4
gpt4 key购买 nike

我正在 Windows 和 Linux (x86-64) 上运行一个程序。它使用相同的编译器(Intel Parallel Studio XE 2017)和相同的选项编译,Windows 版本比 Linux 版本快 3 倍。罪魁祸首是调用std::erf这两种情况都在英特尔数学库中得到解决(默认情况下,它在 Windows 上是动态链接,在 Linux 上是静态链接,但在 Linux 上使用动态链接可以获得相同的性能)。

这是一个重现问题的简单程序。

#include <cmath>
#include <cstdio>

int main() {
int n = 100000000;
float sum = 1.0f;

for (int k = 0; k < n; k++) {
sum += std::erf(sum);
}

std::printf("%7.2f\n", sum);
}

当我使用 vTune 分析这个程序时,我发现程序集在 Windows 和 Linux 版本之间有点不同。这是 Windows 上的调用站点(循环)

Block 3:
"vmovaps xmm0, xmm6"
call 0x1400023e0 <erff>
Block 4:
inc ebx
"vaddss xmm6, xmm6, xmm0"
"cmp ebx, 0x5f5e100"
jl 0x14000103f <Block 3>

以及在 Windows 上调用的 erf 函数的开头

Block 1:
push rbp
"sub rsp, 0x40"
"lea rbp, ptr [rsp+0x20]"
"lea rcx, ptr [rip-0xa6c81]"
"movd edx, xmm0"
"movups xmmword ptr [rbp+0x10], xmm6"
"movss dword ptr [rbp+0x30], xmm0"
"mov eax, edx"
"and edx, 0x7fffffff"
"and eax, 0x80000000"
"add eax, 0x3f800000"
"mov dword ptr [rbp], eax"
"movss xmm6, dword ptr [rbp]"
"cmp edx, 0x7f800000"
...

在 Linux 上,代码有点不同。调用地点是:

Block 3
"vmovaps %xmm1, %xmm0"
"vmovssl %xmm1, (%rsp)"
callq 0x400bc0 <erff>
Block 4
inc %r12d
"vmovssl (%rsp), %xmm1"
"vaddss %xmm0, %xmm1, %xmm1" <-------- hotspot here
"cmp $0x5f5e100, %r12d"
jl 0x400b6b <Block 3>

而被调用函数(erf)的开头是:

"movd %xmm0, %edx"
"movssl %xmm0, -0x10(%rsp)" <-------- hotspot here
"mov %edx, %eax"
"and $0x7fffffff, %edx"
"and $0x80000000, %eax"
"add $0x3f800000, %eax"
"movl %eax, -0x18(%rsp)"
"movssl -0x18(%rsp), %xmm0"
"cmp $0x7f800000, %edx"
jnl 0x400dac <Block 8>
...

我已经展示了在 Linux 上浪费时间的 2 点。

有没有人足够了解汇编来解释这两个代码的区别以及为什么 Linux 版本慢了 3 倍?

最佳答案

根据 Windows 和 GNU/Linux 上各自的调用约定,在这两种情况下,参数和结果在寄存器中传递。

在 GNU/Linux 变体中,xmm1 用于累积总和。由于它是一个 call-clobbered 寄存器(又名 caller-saved),它在每次调用时存储(并恢复)在调用者的堆栈帧中。

在 Windows 变体中,xmm6 用于累积总和。此寄存器在 Windows 调用约定中是被调用者保存的(但不是在 GNU/Linux 中)。

因此,总而言之,GNU/Linux 版本保存/恢复 xmm0(在被调用者 [1] 中)和 xmm1(在调用者中),而Windows 版本仅保存/恢复 xmm6(在被调用者中)。

[1] 需要查看 std::errf 找出原因。

关于c++ - 使用 Intel 编译器 : looking at the assembly 的 Windows 和 Linux 之间的性能差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40522841/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com