当我单独编译和链接时,为什么函数的性能会有所不同?

时间:2014-01-20 20:14:52

标签: c++ windows performance build

问题:当我单独编译并链接时,为什么函数的性能会有所不同?

首先, 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标志执行链接时间优化。我可以单独编译文件,但仍然可以进行内联。

3 个答案:

答案 0 :(得分:1)

如果函数在定义它的同一翻译单元中使用,则可以内联该用法,从而消除函数调用的开销。

答案 1 :(得分:1)

这是因为内联。因为在编译main.cpp时,编译器会看到函数 definitions ,它可以在调用站点内联它们,而不是为实际函数调用生成代码 - 保存在调用帧上。

答案 2 :(得分:1)

有两件事情浮现在脑海中。

首先,内联可能会受到影响(通过在编译调用站点TU时使主体不可用,编译器无法内联代码)。在现代C ++中,内联是一种 巨大的 优化潜力(因为它经常会内联多个级别的调用,并且生成的主体经常会产生更有趣的优化)。

现在很多编译器都有一个 链接时间优化 标志,让你有蛋糕,也吃掉它。这可能会使您的情况受益

  • 以增加链接时间为代价
  • 只要静态链接的对象包含相关定义(即:不与动态链接等)