【发布时间】:2014-11-29 03:16:56
【问题描述】:
我在对循环缓冲区进行基准测试时偶然发现了这一点。谁能解释一下 std::vector 在这种情况下如何胜过普通数组?
#include <iostream>
#include <vector>
struct uint_pair {
unsigned int a, b;
uint_pair (unsigned int x = 0, unsigned int y = 0) : a(x), b(y) {}
};
struct container {
unsigned int pos;
#ifdef USE_VECTOR
std::vector<uint_pair> data;
container() : pos(0) { data.resize(16); }
#else
uint_pair data[16];
container() : pos(0) {}
#endif
void add(uint_pair val) {
data[++pos % 16] = val;
}
};
int main() {
container c;
for (unsigned int i = 0; i < 1000000000; i++) c.add(uint_pair{i, i});
std::cout << c.data[0].a << " " << c.data[0].b << std::endl;
}
这些是我使用 GCC 得到的结果(与 Clang 类似):
g++ -o bench -std=c++0x -Os main.cpp -D'USE_VECTOR'
real 0m8.757s
user 0m8.750s
sys 0m0.002s
g++ -o bench -std=c++0x -Os main.cpp
real 0m9.215s
user 0m9.209s
sys 0m0.002s
【问题讨论】:
-
可能只是分配与缓存中的其他数据对齐的方式。附言你想要
resize而不是reserve。 -
@MarkRansom 谢谢,更新了代码。结果仍然成立。
-
GCC 4.8 带来了更大的不同。我看到向量为 0.6s,数组为 1.8s。优化级别很重要,-O3 为向量获得 0.9 秒。
-
有一个半对的答案,刚刚被删除,但观察得很好。数组元素位于
container结构中,而向量元素位于其他位置并通过指针访问。这对优化也有一些影响。您可以通过将数组更改为uint_pair*并在构造函数中分配它来缩小差距。在我的测试中,它的性能翻了一番,但它仍然比向量慢一点。 -
用另一个编译器试过,反汇编显示问题。问题是数组与循环变量存储在同一类内存中,编译器对别名假设保守,并将循环变量视为易失性。向量不是问题,它存储在堆而不是堆栈上。使用 uint_pair* 数据而不是 uint_pair 数据[16] 消除了差异。
标签: c++ performance c++11 vector stl