2015-03-21 22 views
5

Đây là mã mà tôi thử nghiệm:Tại sao gcc tạo ra một chương trình nhanh hơn so với tiếng kêu trong mã nguồn đệ quy này?

#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; 
} 

Tất nhiên, có những cách nhanh hơn nhiều tính số Fibonacci, nhưng đây là một thử nghiệm căng thẳng chút tốt mà tập trung vào việc gọi hàm đệ quy. Không có gì khác với mã, ngoài việc sử dụng chrono để đo thời gian.

Trước tiên, tôi chạy thử nghiệm một vài lần trong Xcode trên OS X (vì vậy đó là tiếng kêu vang), sử dụng tối ưu hóa -O3. Phải mất khoảng 9 giây để chạy.

Sau đó, tôi đã biên dịch cùng mã với gcc (g ++) trên Ubuntu (sử dụng -O3 một lần nữa), và phiên bản đó chỉ mất khoảng 6,3 giây để chạy! Ngoài ra, tôi đã chạy Ubuntu bên trong VirtualBox trên mac của tôi, mà chỉ có thể ảnh hưởng đến hiệu suất tiêu cực, nếu có.

Vì vậy, có bạn đi:

Clang trên OS X -> ~ 9 giây

gcc trên Ubuntu trong VirtualBox -> ~ 6,3 giây.

Tôi biết rằng đây là những trình biên dịch hoàn toàn khác nhau nên chúng thực hiện các công việc khác nhau, nhưng tất cả các bài kiểm tra tôi thấy có gcc và clang chỉ cho thấy ít khác biệt hơn, và trong một số trường hợp, sự khác biệt là cách khác (tiếng kêu nhanh hơn).

Vậy là có bất kỳ lời giải thích hợp lý tại sao nhịp đập gcc Clang và đấm trong ví dụ cụ thể không?

+0

Bạn có kiểm tra đầu ra của cụm không? Và phiên bản của Clang và gcc là gì? –

+0

Không sử dụng các định nghĩa này.Đó là những gì 'sử dụng' chỉ thị cho:' bằng cách sử dụng chrono_time_point = chrono :: high_resolution_clock :: time_point; ' – Cubic

+2

nhìn vào mã được tạo ra, đó là một hàm đơn giản –

Trả lời

3

Tôi sẽ không nói rằng nhịp đập gcc Clang bởi dặm. Theo tôi, sự khác biệt hiệu suất (6,3 giây so với 9 giây) là khá nhỏ. Trên hệ thống FreeBSD của tôi, clang yêu cầu 26,12 giây và gcc yêu cầu 10,55 giây.

Tuy nhiên, cách gỡ lỗi này là sử dụng g ++ -S và clang ++ -S để lấy đầu ra lắp ráp.

Tôi đã thử nghiệm điều này trên hệ thống FreeBSD của mình. Các tập tin ngôn ngữ lắp ráp quá dài để đăng ở đây, nhưng có vẻ như gcc thực hiện nhiều cấp độ nội tuyến trong hàm tính toán mã hóa (có 20 lệnh gọi fib) trong khi chỉ cần gọi hàm fib (n-1) và fib (n-2) không có mức nội tuyến.

Nhân tiện, phiên bản gcc của tôi là 4.2.1 20070831 vá [FreeBSD] và phiên bản tiếng kêu là 3.1 (chi nhánh/release_31 156863) 20120523. Đây là các phiên bản đi kèm với hệ thống cơ sở FreeBSD 9.1-RELEAESE. CPU là bộ xử lý lõi kép AMD Turion II Neo N40L (1497.54-MHz).

+0

Vì vậy, về cơ bản nó đi xuống để nội tuyến , ít nhất là với một số lượng nhất định "chiều sâu". Thú vị ... – adam10603

+7

Một yếu tố 1.4 không phải là nhỏ, đó là rất lớn. – harold

6

Tôi không có GCC sẵn nhưng GCC 4.9.2 trong gcc godbolt thực sự unrolls rất nhiều các chức năng cuộc gọi trong khi Clang gọi fib hai lần mỗi lần lặp mà không cần tối ưu hóa cuộc gọi thậm chí đuôi như dưới đây

fibonacci(int):       # @fibonacci(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 fibonacci(int) 
    mov ebp, eax 
    add ebx, -2 
    mov edi, ebx 
    call fibonacci(int) 
    add eax, ebp 
.LBB0_3: 
    add rsp, 8 
    pop rbx 
    pop rbp 
    ret 

http://goo.gl/SFPWsr

Trong phiên bản GCC, chỉ có một cuộc gọi duy nhất có hơn 20 nhãn để gạch chân cuộc gọi

Các vấn đề liên quan