这是我测试过的代码:
#include <iostream>
#include <chrono>
using namespace std;
#define CHRONO_NOW chrono::high_resolution_clock::now()
#define CHRONO_DURATION(first,last) chrono::duration_cast<chrono::duration<double>>(last-first).count()
int fib(int n) {
if (n<2) return n;
return fib(n-1) + fib(n-2);
}
int main() {
auto t0 = CHRONO_NOW;
cout << fib(45) << endl;
cout << CHRONO_DURATION(t0, CHRONO_NOW) << endl;
return 0;
}
当然,有更快的方法来计算斐波纳契数,但这是一个很好的小压力测试,专注于递归函数调用。 除了使用计时器测量时间之外,代码没有别的了。
首先,我使用-O3优化在OS X上的Xcode中进行了几次测试(这样就是铿锵声)。跑了大约9秒钟。
然后,我在Ubuntu上用gcc(g ++)编译了相同的代码(再次使用-O3),该版本只用了大约6.3秒就可以运行了!另外,我在我的Mac上运行Ubuntu 在VirtualBox 中,这只会对性能产生负面影响(如果有的话)。
所以你去了:
在OS X上打字 - &gt; ~9秒
Uccntu上的gcc
我知道这些是完全不同的编译器,所以他们做的事情不同,但我看到的所有gcc和clang的测试只显示出更少的差异,在某些情况下,差异是另一种方式(铿锵快。)
有没有合理的解释为什么gcc在这个特定的例子中以英里为单位击败?
答案 0 :(得分:8)
compiler explorer中的GCC 4.9.2实际上是循环展开并且内联大量函数调用,而Clang 3.5.1每次迭代调用fib
两次,甚至没有{{ 3}}如下所示
fib(int): # @fib(int)
push rbp
push rbx
push rax
mov ebx, edi
cmp ebx, 2
jge .LBB0_1
mov eax, ebx
jmp .LBB0_3
.LBB0_1:
lea edi, dword ptr [rbx - 1]
call fib(int) # fib(ebx - 1)
mov ebp, eax
add ebx, -2
mov edi, ebx
call fib(int) # fib(ebx - 2)
add eax, ebp
.LBB0_3:
add rsp, 8
pop rbx
pop rbp
ret
GCC版本的时间延长了10倍以上,只有一个fib
来电和20多个用于内联通话的标签,这也意味着最后一次通话是优化到jmp
或者它已经将一些递归转换为迭代(因为它分配了一个大数组来存储中间值)
我也提到了ICC,令人惊讶的是它在call
内有10条fib
条指令,并且{strong>内联fib
在main
内调用了9次} ,但它不会将递归代码转换为迭代
请注意,您可以像这样修改代码以使输出更易于阅读
int fib(int n) {
if (n<2) return n;
int t = fib(n-1);
return t + fib(n-2);
}
现在编译器资源管理器将突出显示汇编输出中的指令与不同颜色对应的源代码行,并且您将很容易看到这两个调用是如何进行的。行return t + fib(n-2)
由GCC编译为
.L3:
mov eax, DWORD PTR [rsp+112] # n, %sfp
add edx, DWORD PTR [rsp+64] # D.35656, %sfp
add DWORD PTR [rsp+60], edx # %sfp, D.35656
sub DWORD PTR [rsp+104], 2 # %sfp,
答案 1 :(得分:3)
我不会说gcc比几英里更胜一筹。在我看来,性能差异(6.3秒对9秒)相当小。在我的FreeBSD系统上,clang需要26.12秒,gcc需要10.55秒。
但是,调试方法是使用g ++ -S和clang ++ -S来获取程序集输出。
我在FreeBSD系统上测试了这个。汇编语言文件太长了,不能在这里发布,但似乎gcc在fibonacci计算函数中执行多个内联级别(那里有20个fib()调用!)而clang只是调用fib(n-1)和fib (n-2)没有内联级别。
顺便说一句,我的gcc版本是4.2.1 20070831补丁[FreeBSD],而clang版本是3.1(branches / release_31 156863)20120523。这些是FreeBSD 9.1-RELEAESE基本系统附带的版本。 CPU是AMD Turion II Neo N40L双核处理器(1497.54-MHz)。