c++ - 为什么单独编译并链接时,函数的性能会有所不同?

标签 c++ windows performance build

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

首先,代码
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;
}

ma​​in.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++ 和 Microsoft 的“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 和 @Tomasz Kłak 的回答,问题已解决。我现在正在使用命令进行编译

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

/GL 标志执行链接时间优化。我可以单独编译文件并仍然获得内联。

最佳答案

我想到了两件事。

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

现在许多编译器都有一个链接时间优化标志,让您鱼与熊掌兼得。这可能对您的情况有利

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

关于c++ - 为什么单独编译并链接时,函数的性能会有所不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21243293/

相关文章:

javascript - 哪种方法最适合删除删除后可能访问的对象键?

c++ - 如何在 C++ 中使用 utf8 字符数组?

java - 启动程序时遇到 .bat 问题

java - 从头开始编写 win32 安装程序

c++ - 有没有更好的方法可以编写这个程序?

python - 在 NumPy 中快速检查 NaN

c++ - 使用派生类型的C++ Mixin

php - 从基于 REST 的 Web 服务调用 C++ 函数

C++ 段错误(核心转储)错误 - 将指针转换为线程/将函数值返回给线程

Python 手动/独立/可移植 Windows 安装