9

我一直都知道 C++ 的丰富抽象会带来一定的计算开销,但我的印象是,一旦应用了正确的编译器优化,这种开销几乎可以忽略不计。我很好奇这个开销到底有多大,所以我写了一个简单的测试来确定这一点。测试是一个模板函数,它接受一个容器变量,为容器中的每个元素分配一个值,然后在一个单独的循环中对容器中的值求和。该过程重复预设数量的循环。

令我相当不安的是,我发现向量实现花费了标准数组实现的近 3 倍。在对大量编译器优化进行了排列但没有任何成功之后,我决定硬着头皮直接观察汇编代码,看看是什么导致了时间损失。我包含了一些汇编指令,这些指令使我能够准确定位数组索引操作发生的位置并详细检查代码。令我完全困惑的是,我发现向量实现和数组实现之间的区别完全无关紧要。汇编代码可以在这里找到。

这是我用来构建二进制文件的命令:

g++ -O3 vectorArrayOp.cpp -o vectorArrayOp

这是我用来构建程序集的命令:

g++ -O3 -DTAGASM vectorArrayOp.cpp -S -o vectorArrayOp.s

这是我在运行二进制文件时观察到的输出:

gmurphy@interloper:Reference$ ./vectorArrayOp 
Duration 0.027678
Duration 0.090212

当您在标准输出流中包含计算值时,结果不会改变,为了清楚起见,我删除了它们。我的系统规格如下(我在我的 AMD 上也看到了相同的结果):

Linux 3.2.0-32-generic x86_64 GNU/Linux
Intel(R) Xeon(R) CPU X5550  @ 2.67GH
g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3

代码如下,如果有人可以让我了解为什么当程序集如此相似时时间如此不同,我将不胜感激。

#include <vector>
#include <iostream>
#include <sys/time.h>
#ifdef TAGASM
#define ASMTAG(X) asm(X)
#else
#define ASMTAG(X)
#endif 
enum { DataSize=1024, NumTests=(1<<16) } ;
struct ReturnValue {ReturnValue(float _d, int _t):d(_d), t(_t){} float d; int t;} ;
template <typename Container, typename Type>
ReturnValue runTest(Container &c, Type value)
{
    int tagValue(0);
    timeval startTime;
    gettimeofday(&startTime, NULL);
    for(int i=0; i<NumTests; i++)
    {
        for(int j=0; j<DataSize; j++)
        {
            ASMTAG("preassign");
            c [j] = value ;
            ASMTAG("postassign");
        }
        for(int j=0; j<DataSize; j++)
        {
            ASMTAG("preadd");
            tagValue += c [j] ;
            ASMTAG("postadd");
        }
    }
    timeval endTime;
    gettimeofday(&endTime, NULL);
    float duration((endTime.tv_sec-startTime.tv_sec)+
                   (endTime.tv_usec-startTime.tv_usec)/1000000.0);
    //tagValue is returned in case the optimising compiler might try to remove the loops
    return ReturnValue(duration, tagValue) ;
}
int main()
{
    int *arrayData = new int [DataSize];
    std::vector <int> vectorData(DataSize, 0) ;
    ReturnValue ad = runTest(arrayData, 1);
    ReturnValue vd = runTest(vectorData, 1);
    std::cout<<"Duration "<<ad.d<<std::endl;
    std::cout<<"Duration "<<vd.d<<std::endl;
    delete [] arrayData;
    return 0 ;
}
4

1 回答 1

11
% g++-4.4 -O3 vectorArrayOp.cpp -o vectorArrayOp
% ./vectorArrayOp
Duration 0.008581
Duration 0.008775
% g++-4.5 -O3 vectorArrayOp.cpp -o vectorArrayOp
% ./vectorArrayOp
Duration 0.008634
Duration 0.008588
% g++-4.6 -O3 vectorArrayOp.cpp -o vectorArrayOp
% ./vectorArrayOp
Duration 0.01731
Duration 0.081696
% g++-4.7 -O3 vectorArrayOp.cpp -o vectorArrayOp
% ./vectorArrayOp
Duration 0.008618
Duration 0.008612
% clang++ -O3 vectorArrayOp.cpp -o vectorArrayOp
% ./vectorArrayOp
Duration 0.066484
Duration 0.066435

基于这些结果,这可能是 g++ 4.6 中特定于编译器的性能回归。

于 2012-11-05T18:57:23.580 回答