Mar*_*own 5 floating-point gcc mingw avx x87
我在从 Intel 2023 和 MSC Visual C++ 2022 移植工作数字代码时遇到一个奇怪的问题。使用 GCC 编译的代码非常准确(太准确),因为某些库调用以完整的 80 位浮点精度工作 - 特别是 sqrt、sin 和 cos。我可以通过使用 TUI 跟踪 gdb 的库调用来反汇编库代码执行来验证这一点。
它也出现在基准计时中,因为 x87 atan2、cos、exp 和 sin 都约为 100 个周期,而 sqrt 约为 80 个周期。SSE/AVX2 代码的相应时序低于 50 个周期,大部分在 20-30 个周期左右。
奇怪的是 tan、atan是使用 AVX2 编译的。但 cos、sin、sqrt 和 atan2 在 GCC 系统库中使用旧版 x87 代码。我已经在 32 位端口和 64 位版本上尝试过此操作,并且都遇到了相同的问题。我是海湾合作委员会的新手,所以我可能忽略了一些事情。我在 Windows 上使用默认的 MinGW 端口版本 13.1.0 (MinGW-W64 i686-ucrt-posix-dwarf),它可能有其自身的特点。
顺便说一句,我刚刚注意到 MSC 2022 有时会编码 x87 sqrt,即使启用了所有 gofaster 优化和 AVX2 代码,因为这也是我之前没有注意到的基准计时中的异常值。Intel 将其编译为本机 sqrtsd,因此速度要快得多。我回到 MSC x86 进行内联汇编,以确认 x87 trig 指令的基准计时。
编译器选项有:
gcc -c -O3 -Ofast -march=native -mavx2 -mfpmath=sse benchmark.cpp
链接正在采用 GCC 默认系统库,这似乎是问题所在 - 我的代码或任何内联生成 SSE 或 AVX2 代码的系统代码,以便 tan 和 atan 都可以,但任何生成库调用的都正在执行 x87 指令全 80 位精度的超越函数。我认为这可能与我能找到的最接近的线程有关:
为什么 MinGW-w64 浮点精度取决于 winpthreads 版本?
我想强制它使用完全 AVX2 或 SSE2 代码的不同 FP 库,或者使用 和 之类的东西重新编译现有的-march=native -mavx2库-Ofast。在这里,速度比精确的标准合规性更重要。这涉及到很多三角函数。
我完全有可能在 GCC 中链接了错误的默认库。我有一种基于合并 BSD trig 库函数源代码的解决方法,但这并不优雅。
如果有人想在他们的系统上尝试一下,我可以发布一个基准测试代码示例,但它会比这里正常的情况要长一些。我希望有人已经知道答案......
这些是使用 AVX2 代码生成 MSC 2022 与 GCC 13.0.1 进行原始三角运算的机器周期基准。它在 Intel i5-12600 上运行,对两个编译器都进行了最大优化。
| MSC | 海湾合作委员会 | |
|---|---|---|
| 晒黑 | 12 | 13 |
| 阿坦2 | 27 | 122 |
| 日志 | 11 | 76 |
| 经验值 | 11 | 136 |
| 罪 | 14 | 115 |
| 因斯 | 13 | 117 |
| 正科斯 | 19 | 127 |
| 晒黑 | 18 | 20 |
与应有的水平相比,使用 x87 代码的代码脱颖而出了约 100 个周期。
我想在编译时使用正确的浮点库获取代码-O3 -Ofast -mavx2
这是显示我的问题的最小示例代码以及 GDB 中反汇编的快照,其中显示了 sin 如何变成 x87 FSIN 等。测试您是否遇到类似问题的另一种方法是对 sin(x) 和 tan(x) 进行基准测试如果 tan 计时约为 20 个周期,sin 约为 40,那么你最喜欢的分析器就可以了(tan 比 sin 快 2 倍)。任何三角函数都需要 100+ 个周期,并且是缓慢的 x87 代码。
#include "stdio.h"
#include "math.h"
// Toy use of sin & tan to see if they compile using SSE2 or x87
int main(int argc, char* argv[]){
double x, y;
if (argc>1) x = atof(argv[1]); else x = 3.1415926535/2;
y = sin(x);
printf("sin of %g is %18.10g\n", x, y);
x = x/2;
y = tan(x);
printf("tan of %g is %18.10g\n", x, y);
}
Run Code Online (Sandbox Code Playgroud)
使用 GDB 中的 x87 代码反汇编 sin 例程(tan 即可)
<__sinl_internal> fldt (%rdx)
<__sinl_internal+2> fsin
<__sinl_internal+4> fnstsw %ax
<__sinl_internal+6> test $0x400,%eax
<__sinl_internal+11> jne 0x7ff656332e6b
<__sinl_internal+13> mov %rcx,%rax
<__sinl_internal+16> movq $0x0,0x8(%rcx)
<__sinl_internal+24> fstpt (%rcx)
<__sinl_internal+26> ret
Run Code Online (Sandbox Code Playgroud)
我现在相当确信 @emacsdrivesmenuts 是对的,我必须在 Mingw 下使用正确的 FP 优化来重建默认的系统数学库来解决这个问题,但我不知道该怎么做!
感谢您的任何启发!
| 归档时间: |
|
| 查看次数: |
80 次 |
| 最近记录: |