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
运行速度快约20%,即使输出循环看起来相同/MT
- 未经修改的回路(约300 ms):
- 带有
的循环(看起来相同!但约270毫秒):/MTd
- 修改后的循环(~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)