Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
执行GCC和Clang之间的性能差距_C_Gcc_Clang - Fatal编程技术网

执行GCC和Clang之间的性能差距

执行GCC和Clang之间的性能差距,c,gcc,clang,C,Gcc,Clang,我有以下简单的代码,当我在GCC和Clang中编译它们时,它们的执行时间之间存在巨大的性能差异,正如您可以看到的结果和下面编译器的版本一样 char*strchr\ux(寄存器常量char*s,int c){ 做{ 如果(*s==c){ 返回(字符*)s; } }而(*s++); 返回0; } char*get(char*value,常量字符分隔符){ int separator_index=strhr(值,分隔符)-值; char*result=malloc(分隔符索引); memcpy(结

我有以下简单的代码,当我在GCC和Clang中编译它们时,它们的执行时间之间存在巨大的性能差异,正如您可以看到的结果和下面编译器的版本一样

char*strchr\ux(寄存器常量char*s,int c){
做{
如果(*s==c){
返回(字符*)s;
}
}而(*s++);
返回0;
}
char*get(char*value,常量字符分隔符){
int separator_index=strhr(值,分隔符)-值;
char*result=malloc(分隔符索引);
memcpy(结果、值、分隔符和索引);
结果[分隔符索引]='\0';
返回结果;
}
intmain(){
常量字符分隔符=',';
时钟t=时钟();
对于(尺寸i=0;i<100000000;++i){
免费(获取(“127.0.0.1127.0.0.2:1111”,分隔符));
}
浮点经过的秒数=((双精度)(时钟()-t))/CLOCKS\u/SEC);
printf(“%f秒。\n”,已用\u秒);
返回0;
}
此外,“strchr_x”实现与原始GCC实现完全相同。你可以在

当我在标准库中使用'strchr'方法时;GCC的运行时间减少到0.015625秒

因此,我的问题是:

  • 为什么在GCC中我的'strchr_x'和标准库的'strchr'之间存在巨大的性能差异
  • 为什么在GCC和Clang之间存在巨大的性能差距

  • 如果您将代码插入其中,您可以看到Clang将优化整个for循环,这解释了为什么它在0秒内执行。它可能会这样做,因为get的唯一副作用是malloc,结果会立即被释放

    编辑: GCC确实不能很好地处理您的代码,似乎。。。 我再次检查了生成的汇编程序,这不仅是因为它无法删除空for循环(对于strchr()),而且它无法删除循环体中的函数调用(对于strchr\u x())


    所以最后,这一切归结为一些非常奇怪的优化行为,而你最慢的例子实际上是唯一一个做任何事情的例子。我不知道为什么GCC在你的例子中失败得如此之难,但我绝对同意你应该将其作为一个bug进行归档(甚至可能是两个单独的bug,因为它在使用strchr()时已经很难失败,而在使用strchr_x()时更难失败,尽管两者应该是相同的)

    关于问题二的简短回答-
    clang
    (LLVM)在运行时具有更好的代码和链接优化

    现在,我先从经验中举出一个例子。该项目适合我在raspberry pi-3设备上进行必要的测试。当我使用
    clang++
    编译时,大约需要15分钟,而使用
    gcc
    编译时,经过40多分钟的长时间等待编译,就在链接的最后,构建的内存就用完了!为什么?同样,
    clang
    提供了更好的编译时代码优化和后台链接

    然而,这取决于,在不同的Ox水平下,你可能不会得到相同的差异(试试O2,你会看到)。为了更多的参考,我认为这两篇文章提供了一些详细的解释


    似乎
    gcc
    无法删除循环,即使它删除了循环中的调用。以下是指向godbolt的链接,代码如下:

    main:
    推送rbx
    呼叫钟
    mov-rbx,rax
    mov eax,100000000
    .L5:
    
    sub-rax,1//clang显然优化了/*no-effect*/for循环。看看反汇编。当时间为零时,这意味着编译器完全优化了您试图测试的代码。它可以这样做,因为代码没有任何可观察的效果。您有未定义的行为(在
    result
    末尾写入)。这可能不是导致性能差异的原因,但是.gcc将循环减少为
    for(无符号长x=10000000;x!=0;--x)则无法删除此空循环。请在gcc的bugzilla中提交错误报告。在main上添加
    \uuuu attribute\uuuu((flatte))
    ,使gcc能够进行优化,但它确实能够在不作弊的情况下进行优化。实际上,我想知道这是否是gcc方面的错误,但@marc glisse已经回答了这个问题。你能回答我的第一个问题吗@felix-g?我已经再次检查了汇编程序,并相应地扩展了我的答案
    gcc version 8.1.0 (Ubuntu 8.1.0-5ubuntu1~16.04)
    # gcc main.c -O3 -o gcc-main
    # 1.968750 seconds.
    
    clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
    # clang main.c -O3 -o clang-main
    # 0.000000 seconds.
    
    main:
            push    rbx
            call    clock
            mov     rbx, rax
            mov     eax, 100000000
    .L5:
            sub     rax, 1 // <<-------- loop which does nothing.
            jne     .L5
            call    clock