2014-01-20 39 views
2

問題:爲什麼功能的性能不同,當我分別編譯和鏈接?爲什麼功能的性能不同,當我分別編譯和鏈接?

首先,在CODE
randoms.hpp

int XORShift(); 
int GameRand(); 

randoms.cpp

static unsigned int x = 123456789; 
static unsigned int y = 362436069; 
static unsigned int z = 521288629; 
static unsigned int w = 88675123; 
int XORShift() 
{ 
    unsigned int t = x^(x << 11); 
    x = y; 
    y = z; 
    z = w; 
    return w = w^(w >> 19)^(t^(t >> 8)); 
} 

static unsigned int high = 0xDEADBEEF; 
static unsigned int low = high^0x49616E42; 
int GameRand() 
{ 
    high = (high << 16) + (high >> 16); 
    high += low; 
    low += high; 
    return high; 
} 

的main.cpp

#include <iostream> 
#include <windows.h> 
#include "randoms.hpp" 
using namespace std; 

//Windows specific performance tracking 
long long milliseconds_now() { 
    static LARGE_INTEGER s_frequency; 
    static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency); 
    LARGE_INTEGER now; 
    QueryPerformanceCounter(&now); 
    return (1000LL * now.QuadPart)/s_frequency.QuadPart; 
} 

void main() { 
    const int numCalls = 100000000; //100 mil 
    { 
     cout << "XORShift..." << endl; 
     long long start = milliseconds_now(); 
     for(int i=0; i<numCalls; i++) 
      XORShift(); 
     long long elapsed = milliseconds_now() - start; 
     cout << "\tms: " << elapsed << endl; 
    } 
    { 
     cout << "GameRand..." << endl; 
     long long start = milliseconds_now(); 
     for(int i=0; i<numCalls; i++) 
      GameRand(); 
     long long elapsed = milliseconds_now() - start; 
     cout << "\tms: " << elapsed << endl; 
    } 
    { 
     cout << "std::rand..." << endl; 
     long long start = milliseconds_now(); 
     for(int i=0; i<numCalls; i++) 
      std::rand(); 
     long long elapsed = milliseconds_now() - start; 
     cout << "\tms: " << elapsed << endl; 
    } 
} 

詳細信息
我正在使用C++和Microsofts「cl」編譯器。我正在測試3個僞隨機函數的性能。它們是XORShift,GameRand和std :: rand()。

建築的main.cpp和randoms.cpp單獨和與所述命令

cl /O2 /Oi main.cpp randoms.cpp 

產生以下性能結果鏈接:

XORShift... 
    ms: 520 
GameRand... 
    ms: 2056 
std::rand... 
    ms: 3800 

然而如果忘記了報頭和直接通過包括的功能

#include "randoms.cpp" 

並編譯時沒有任何鏈接

cl /O2 /Oi main.cpp 

我得到非常不同的表現:

XORShift... 
    ms: 234 
GameRand... 
    ms: 135 
std::rand... 
    ms: 3823 

兩個XORShift和GameRand得到顯着的速度提升。 GameRand的速度比XORShift的速度慢,這很奇怪。我怎樣才能得到2cd測試的速度,但仍然分別編譯random.cpp和鏈接?

** 編輯 **:
由於@sehe的評論以及@Oswald和@TomaszKłak的回答,問題已解決。我正在使用命令編譯

cl /O2 /Oi /GL main.cpp randoms.cpp 

/GL標誌執行鏈接時間優化。我可以單獨編譯文件,仍然可以獲得內聯。

+1

谷歌和內聯LTO – sehe

+0

LTO將鏈接單獨的目標文件時生效,這裏我們看到包含實現內聯功能時性能會有所提高。 – tumdum

+0

@sehe。感謝LTO的建議。我將/ GL標誌包含在cl編譯器中。單獨編譯的性能現在匹配單個編譯。如果您將您的評論翻譯成答案,我會接受它。 – mike

回答

1

想到兩件事。

首先,內聯可能會受到影響(通過在編譯調用站點TU時不能使用主體,編譯器不能內聯代碼)。在現代C++內聯是一個巨大優化潛力(因爲它會調用頻繁直列幾個層次和所產生的身體經常會產生更加有趣的優化)。

許多編譯器現在有一個鏈路時間Optimzation標誌,讓你有你的蛋糕的,和熊掌兼得。這可以在增加鏈接時成本效益的情況

  • 只要靜態鏈接的對象包含了相關的定義(即:不與動態鏈接等)
1

如果函數在定義它的同一翻譯單元中使用,則可以內聯該用法,從而消除函數調用的開銷。

1

這是因爲內聯。由於在編譯main.cpp時,編譯器會看到函數定義它可以在呼叫站點內聯它們,而不是爲實際函數調用生成代碼 - 您可以節省調用幀。

相關問題