gpt4 book ai didi

c - 与 clang 相比,gcc 的具有一定字节数的 __builtin_memcpy 性能很糟糕

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

我想在做任何其他事情之前先在这里分享这个以征求您的意见。我在设计算法时发现,与 clang 相比,gcc 编译一些简单代码的代码性能是灾难性的。

如何重现

创建一个包含此代码的 test.c 文件:

#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

int main(int argc, char *argv[]) {
const uint64_t size = 1000000000;
const size_t alloc_mem = size * sizeof(uint8_t);
uint8_t *mem = (uint8_t*)malloc(alloc_mem);
for (uint_fast64_t i = 0; i < size; i++)
mem[i] = (uint8_t) (i >> 7);

uint8_t block = 0;
uint_fast64_t counter = 0;
uint64_t total = 0x123456789abcdefllu;
uint64_t receiver = 0;

for(block = 1; block <= 8; block ++) {
printf("%u ...\n", block);
counter = 0;
while (counter < size - 8) {
__builtin_memcpy(&receiver, &mem[counter], block);
receiver &= (0xffffffffffffffffllu >> (64 - ((block) << 3)));
total += ((receiver * 0x321654987cbafedllu) >> 48);
counter += block;
}
}

printf("=> %llu\n", total);
return EXIT_SUCCESS;
}

海湾合作委员会

编译运行:

gcc-7 -O3 test.c
time ./a.out
1 ...
2 ...
3 ...
4 ...
5 ...
6 ...
7 ...
8 ...
=> 82075168519762377

real 0m23.367s
user 0m22.634s
sys 0m0.495s

信息:

gcc-7 -v
Using built-in specs.
COLLECT_GCC=gcc-7
COLLECT_LTO_WRAPPER=/usr/local/Cellar/gcc/7.3.0/libexec/gcc/x86_64-apple-darwin17.4.0/7.3.0/lto-wrapper
Target: x86_64-apple-darwin17.4.0
Configured with: ../configure --build=x86_64-apple-darwin17.4.0 --prefix=/usr/local/Cellar/gcc/7.3.0 --libdir=/usr/local/Cellar/gcc/7.3.0/lib/gcc/7 --enable-languages=c,c++,objc,obj-c++,fortran --program-suffix=-7 --with-gmp=/usr/local/opt/gmp --with-mpfr=/usr/local/opt/mpfr --with-mpc=/usr/local/opt/libmpc --with-isl=/usr/local/opt/isl --with-system-zlib --enable-checking=release --with-pkgversion='Homebrew GCC 7.3.0' --with-bugurl=https://github.com/Homebrew/homebrew-core/issues --disable-nls
Thread model: posix
gcc version 7.3.0 (Homebrew GCC 7.3.0)

所以我们得到大约 23 秒的用户时间。现在让我们对 cc(macOS 上的 clang)做同样的事情:

clang

cc -O3 test.c
time ./a.out
1 ...
2 ...
3 ...
4 ...
5 ...
6 ...
7 ...
8 ...
=> 82075168519762377

real 0m9.832s
user 0m9.310s
sys 0m0.442s

信息:

Apple LLVM version 9.0.0 (clang-900.0.39.2)
Target: x86_64-apple-darwin17.4.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

快 2.5 倍 !!有什么想法吗?

我用 memcpy 替换了 __builtin_memcpy 函数来测试结果,这一次编译后的代码在双方大约 34 秒内运行 - 与预期一致且速度较慢。

看起来 __builtin_memcpy 和位掩码的组合被两个编译器解释得非常不同。我查看了汇编代码,但由于我不是 asm 专家,所以看不到任何可以解释性能下降的突出内容。


编辑 03-05-2018 :发布了这个错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84719


最佳答案

我怀疑您为 memcpy 和 __builtin_memcpy 获得了不同的代码。我认为这不应该发生,事实上我无法在我的 (linux) 系统上重现它。

如果在 for 循环之前添加 #pragma GCC unroll 16(在 gcc-8+ 中实现),gcc 将获得与 clang 相同的性能(使 block 成为常量是优化代码所必需的),所以基本上 llvm 的展开比 gcc 的展开更积极,这可能是好是坏取决于情况。尽管如此,请随时向 gcc 报告它,也许他们有一天会调整展开的启发式方法,额外的测试用例可能会有所帮助。

一旦处理好展开,gcc 对于某些值(block 尤其等于 4 或 8)确实没问题,但对于其他一些值就更糟了,尤其是 3。但是最好用 block 上没有循环的较小测试用例。 Gcc 似乎对 memcpy(,,3) 有问题,如果你总是读取 8 个字节(下一行已经处理了额外的字节 IIUC),它会工作得更好。另一件可以报告给 gcc 的事情。

关于c - 与 clang 相比,gcc 的具有一定字节数的 __builtin_memcpy 性能很糟糕,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49098453/

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