C++向量数组运算符的计算成本高吗?

Gea*_*phy 8 c++ linux profiling g++

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

令我非常不安的是,我发现矢量实现几乎是标准阵列实现的3倍.在通过大量选择的编译器优化进行置换而没有任何成功之后,我决定咬紧牙关并直接观察汇编代码以尝试查看导致时间损失的原因.我包含了一些汇编指令,这些指令允许我精确地确定数组索引操作发生的位置并详细检查代码.令我完全困惑的是,我发现向量实现和数组实现之间的区别是完全无关紧要的.汇编代码可以在这里找到.

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

g++ -O3 vectorArrayOp.cpp -o vectorArrayOp
Run Code Online (Sandbox Code Playgroud)

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

g++ -O3 -DTAGASM vectorArrayOp.cpp -S -o vectorArrayOp.s
Run Code Online (Sandbox Code Playgroud)

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

gmurphy@interloper:Reference$ ./vectorArrayOp 
Duration 0.027678
Duration 0.090212
Run Code Online (Sandbox Code Playgroud)

当您在stdout流中包含计算值时,结果不会更改,为清楚起见,我删除了它们.我的系统规格如下(我在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
Run Code Online (Sandbox Code Playgroud)

代码如下,如果有人能够让我深入了解为什么在装配如此相似时时序如此不同,我将不胜感激.

#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 ;
}
Run Code Online (Sandbox Code Playgroud)

Omn*_*ity 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
Run Code Online (Sandbox Code Playgroud)

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

  • 顺便说一句,我想知道wtf在这个测试中正在进行铿锵声. (3认同)