gpt4 book ai didi

c - GCC 生成的 64 位代码比 32 位代码慢 3 倍

转载 作者:太空狗 更新时间:2023-10-29 17:00:54 26 4
gpt4 key购买 nike

我注意到我的代码在 64 位 Linux 上运行比在 32 位 Linux 或 64 位 Window 或 64 位 Mac 上运行慢得多。这是最小的测试用例。

#include <stdlib.h>

typedef unsigned char UINT8;

void
stretch(UINT8 * lineOut, UINT8 * lineIn, int xsize, float *kk)
{
int xx, x;

for (xx = 0; xx < xsize; xx++) {
float ss = 0.0;
for (x = 0; x < xsize; x++) {
ss += lineIn[x] * kk[x];
}
lineOut[xx] = (UINT8) ss;
}
}

int
main( int argc, char** argv )
{
int i;
int xsize = 2048;

UINT8 *lineIn = calloc(xsize, sizeof(UINT8));
UINT8 *lineOut = calloc(xsize, sizeof(UINT8));
float *kk = calloc(xsize, sizeof(float));

for (i = 0; i < 1024; i++) {
stretch(lineOut, lineIn, xsize, kk);
}

return 0;
}

它是如何运行的:

$ cc --version
cc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
$ cc -O2 -Wall -m64 ./tt.c -o ./tt && time ./tt
user 14.166s
$ cc -O2 -Wall -m32 ./tt.c -o ./tt && time ./tt
user 5.018s

如您所见,32 位版本的运行速度几乎快了 3 倍(我在 32 位和 64 位 Ubuntu 上都进行了测试,结果相同)。更奇怪的是什么性能取决于 C 标准:

$ cc -O2 -Wall -std=c99 -m32 ./tt.c -o ./tt && time ./tt
user 15.825s
$ cc -O2 -Wall -std=gnu99 -m32 ./tt.c -o ./tt && time ./tt
user 5.090s

怎么可能呢?我该如何解决这个问题以加速 GCC 生成的 64 位版本。

更新 1

我比较了快速 32 位(默认和 gnu99)和慢速(c99)生成的汇编器,发现如下:

.L5:
movzbl (%ebx,%eax), %edx # MEM[base: lineIn_10(D), index: _72, offset: 0B], D.1543
movl %edx, (%esp) # D.1543,
fildl (%esp) #
fmuls (%esi,%eax,4) # MEM[base: kk_18(D), index: _72, step: 4, offset: 0B]
addl $1, %eax #, x
cmpl %ecx, %eax # xsize, x
faddp %st, %st(1) #,
fstps 12(%esp) #
flds 12(%esp) #
jne .L5 #,

快速情况下没有fstpsflds 命令。所以 GCC 在每一步都从内存中存储和加载值。我试过 register float 类型,但这没有用。

更新 2

我已经在 gcc-4.9 上进行了测试,看起来它可以为 64 位生成最佳代码。 -ffast-math(@jch 建议)修复了两个 GCC 版本的 -m32 -std=c99。我仍在寻找适用于 gcc-4.8 的 64 位解决方案,因为它是目前比 4.9 更常见的版本。

最佳答案

旧版 GCC 生成的代码中存在部分依赖性停顿。

movzbl (%rsi,%rax), %r8d
cvtsi2ss %r8d, %xmm0 ;; all upper bits in %xmm0 are false dependency

xorps 可以打破依赖。

#ifdef __SSE__
float __attribute__((always_inline)) i2f(int v) {
float x;
__asm__("xorps %0, %0; cvtsi2ss %1, %0" : "=x"(x) : "r"(v) );
return x;
}
#else
float __attribute__((always_inline)) i2f(int v) { return (float) v; }
#endif

void stretch(UINT8* lineOut, UINT8* lineIn, int xsize, float *kk)
{
int xx, x;

for (xx = 0; xx < xsize; xx++) {
float ss = 0.0;
for (x = 0; x < xsize; x++) {
ss += i2f(lineIn[x]) * kk[x];
}
lineOut[xx] = (UINT8) ss;
}
}

结果

$ cc -O2 -Wall -m64 ./test.c -o ./test64 && time ./test64
./test64 4.07s user 0.00s system 99% cpu 4.070 total
$ cc -O2 -Wall -m32 ./test.c -o ./test32 && time ./test32
./test32 3.94s user 0.00s system 99% cpu 3.938 total

关于c - GCC 生成的 64 位代码比 32 位代码慢 3 倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26585977/

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