【发布时间】:2012-07-25 20:06:25
【问题描述】:
下面的代码(从我的较大代码中减少,在我惊讶于它的速度与 std::vector 相比显得苍白之后)有两个独特的特点:
-
当我对源代码进行非常微小的修改(始终使用 Visual C++ 2010 使用
/O2编译它)时,它的运行速度超过 三倍。注意:为了让这更有趣,我在最后给出了修改的提示,这样你就可以花一些时间自己找出改变。原始代码大约 500 行,所以我花了很长时间才确定它,因为修复看起来与性能无关。
/MTd的运行速度比/MT快 20%快,即使输出循环看起来相同!!!
tiny-modification 情况的汇编代码的区别是:
-
循环没有修改(~300 ms):
00403383 mov esi,dword ptr [esp+10h] 00403387 mov edx,dword ptr [esp+0Ch] 0040338B mov dword ptr [edx+esi*4],eax 0040338E add dword ptr [esp+10h],ecx 00403392 add eax,ecx 00403394 cmp eax,4000000h 00403399 jl main+43h (403383h) -
循环与
/MTd(看起来相同!但约270毫秒):00407D73 mov esi,dword ptr [esp+10h] 00407D77 mov edx,dword ptr [esp+0Ch] 00407D7B mov dword ptr [edx+esi*4],eax 00407D7E add dword ptr [esp+10h],ecx 00407D82 add eax,ecx 00407D84 cmp eax,4000000h 00407D89 jl main+43h (407D73h) -
循环修改(~100 ms!!):
00403361 mov dword ptr [esi+eax*4],eax 00403364 inc eax 00403365 cmp eax,4000000h 0040336A jl main+21h (403361h)
现在我的问题是,为什么上述更改会产生它们的效果?这完全是奇怪的!
尤其是第一个 - 它根本不应该影响任何东西(一旦你看到代码中的差异),但它会显着降低速度。
对此有解释吗?
#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);
}
提示(将鼠标悬停在下方):
它与分配器有关。
回答:
将
Allocator &a_更改为Allocator a_。
【问题讨论】:
-
什么小修改?这应该是一个谜题还是一个真正的问题?
-
关于循环1和2之间的时间差;您是否进行了大量时间测量并计算了平均值? (您可能已经知道,即使是完全相同的代码,每次运行的时间也会有很大差异。)
-
@ManofOneWay:是的,我有,非常一致。
-
显然编译器对可能的别名很保守,但我仍然不确定你的问题到底是什么。
-
出于某种奇怪的原因,如果您删除
std::swap(n_, n);行,那么您总是会得到快速循环。另请注意,在vector构造函数中,您有两个名为n的变量:成员和参数!这很令人困惑。
标签: c++ performance visual-c++ code-generation