C++ visualc++;,对于几乎相同的代码;3倍速度差

C++ visualc++;,对于几乎相同的代码;3倍速度差,c++,performance,visual-c++,code-generation,C++,Performance,Visual C++,Code Generation,下面的代码(在我惊讶于它的速度与std::vector相比相形见绌之后,从我的大代码中缩减)有两个独特的特性: 当我对源代码做了一个非常微小的修改时,它运行的速度超过强>三倍(总是用VisualC++ 2010编写 /O2 < /代码>)。 注意:为了让这更有趣一点,我在最后给出了一个修改提示,这样您就可以自己花一些时间来弄清楚更改了。最初的代码大约有500行,所以我花了很长时间才确定下来,因为修复看起来与性能无关 使用/MTd比使用/MT运行速度快约20%,即使输出循环看起来相同 微小修改

下面的代码(在我惊讶于它的速度与
std::vector
相比相形见绌之后,从我的大代码中缩减)有两个独特的特性:

    当我对源代码做了一个非常微小的修改时,它运行的速度超过<>强>三倍(总是用VisualC++ 2010编写<代码> /O2 < /代码>)。

    注意:为了让这更有趣一点,我在最后给出了一个修改提示,这样您就可以自己花一些时间来弄清楚更改了。最初的代码大约有500行,所以我花了很长时间才确定下来,因为修复看起来与性能无关

  • 使用
    /MTd
    比使用
    /MT
    运行速度快约20%,即使输出循环看起来相同

微小修改情况下的组装代码差异为:

  • 未经修改的回路(约300 ms):

  • 带有
    /MTd
    的循环(看起来相同!但约270毫秒):

  • 修改后的循环(~100毫秒!!):

现在我的问题是,为什么上面的更改会产生影响?这太奇怪了

特别是第一个——它不应该影响任何东西(一旦您看到代码中的差异),但它会显著降低速度

对此有何解释

#include <cstdio>
#include <ctime>
#include <algorithm>
#include <memory>
template<class T, class Allocator = std::allocator<T> >
struct vector : Allocator
{
    T *p;
    size_t n;
    struct scoped
    {
        T *p_;
        size_t n_;
        Allocator &a_;
        ~scoped() { if (p_) { a_.deallocate(p_, n_); } }
        scoped(Allocator &a, size_t n) : a_(a), n_(n), p_(a.allocate(n, 0)) { }
        void swap(T *&p, size_t &n)
        {
            std::swap(p_, p);
            std::swap(n_, n);
        }
    };
    vector(size_t n) : n(0), p(0) { scoped(*this, n).swap(p, n); }
    void push_back(T const &value) { p[n++] = value; }
};
int main()
{
    int const COUNT = 1 << 26;
    vector<int> vect(COUNT);
    clock_t start = clock();
    for (int i = 0; i < COUNT; i++) { vect.push_back(i); }
    printf("time: %d\n", (clock() - start) * 1000 / CLOCKS_PER_SEC);
}
#包括
#包括
#包括
#包括
模板
结构向量:分配器
{
T*p;
尺寸;
结构作用域
{
T*p_;
大小;
分配器&a;
~scoped(){if(p_){a_.deallocate(p_,n_);}
作用域(分配器&a,大小n):a(a),n(n),p(a.allocate(n,0)){
无效掉期(T*&p、大小T&n)
{
标准::交换(p_up);
标准::交换(n,n);
}
};
向量(size_t n):n(0),p(0){作用域(*this,n).swap(p,n);}
void push_back(T const&value){p[n++]=value;}
};
int main()
{

int const COUNT=1值得一提的是,我对
/MT
/MTd
之间区别的推测是,
/MTd
堆分配将为调试目的绘制堆内存,使其更有可能被分页-这发生在启动时钟之前

如果对矢量分配进行“预热”,则会得到与
/MT
/MTd
相同的编号:

vector<int> vect(COUNT);

// make sure vect's memory is warmed up
for (int i = 0; i < COUNT; i++) { vect.push_back(i); }
vect.n = 0; // clear the vector

clock_t start = clock();
for (int i = 0; i < COUNT; i++) { vect.push_back(i); }
printf("time: %d\n", (clock() - start) * 1000 / CLOCKS_PER_SEC);
向量向量(计数);
//确保vect的内存已预热
对于(int i=0;i
很奇怪,分配器&会破坏别名链,而分配器不会

你可以试试

for(int i=vect.n; i<COUNT;++i){
    ...
}
for(inti=vect.n;iemm…“最快”的代码

在这个循环中,vect.n完全被忽略了。。。 如果循环中发生异常,vect.n将无法正确更新

所以答案可能是:当您使用分配器时,vc发现vect.n将不再使用,
所以它可以被忽略。这很令人惊讶,但一般来说它没有那么有用和危险。

什么微小的修改?这应该是一个谜题还是一个真正的问题?关于回路1和2之间的时差,你做了大量的时间测量并计算了平均值吗?(正如你可能已经知道的那样,即使运行完全相同的代码,时间也可能会有很大的不同。)@Manofonway:是的,我知道,它是非常一致的。显然编译器对可能出现的别名持保守态度,但我仍然不确定你的问题到底是关于什么的。出于某种奇怪的原因,如果你删除
std::swap(n,n)
行,那么您总是会得到快速循环。还要注意,在
向量
构造函数中,您有两个名为
n
的变量:成员和参数!这非常令人困惑。+1个奇妙的答案,似乎很正确。这确实起到了作用。:)Lenx,我不确定我是否明白你的意思--这如何解释分配程序的问题?(同样,这有点随机,但是…我们彼此认识吗?!)嗨,Mehrdad,很高兴在这里见到你:)哦,我明白你的问题了。对于vc2010来说真的很奇怪。分配器&使vc无法识别n与I同步。也许你可以试试:for(int I=vect.n;I#include <cstdio> #include <ctime> #include <algorithm> #include <memory> template<class T, class Allocator = std::allocator<T> > struct vector : Allocator { T *p; size_t n; struct scoped { T *p_; size_t n_; Allocator &a_; ~scoped() { if (p_) { a_.deallocate(p_, n_); } } scoped(Allocator &a, size_t n) : a_(a), n_(n), p_(a.allocate(n, 0)) { } void swap(T *&p, size_t &n) { std::swap(p_, p); std::swap(n_, n); } }; vector(size_t n) : n(0), p(0) { scoped(*this, n).swap(p, n); } void push_back(T const &value) { p[n++] = value; } }; int main() { int const COUNT = 1 << 26; vector<int> vect(COUNT); clock_t start = clock(); for (int i = 0; i < COUNT; i++) { vect.push_back(i); } printf("time: %d\n", (clock() - start) * 1000 / CLOCKS_PER_SEC); }
vector<int> vect(COUNT);

// make sure vect's memory is warmed up
for (int i = 0; i < COUNT; i++) { vect.push_back(i); }
vect.n = 0; // clear the vector

clock_t start = clock();
for (int i = 0; i < COUNT; i++) { vect.push_back(i); }
printf("time: %d\n", (clock() - start) * 1000 / CLOCKS_PER_SEC);
for(int i=vect.n; i<COUNT;++i){
    ...
}
00403361  mov         dword ptr [esi+eax*4],eax 
00403364  inc         eax  
00403365  cmp         eax,4000000h 
0040336A  jl          main+21h (403361h)