【发布时间】:2012-07-01 01:56:56
【问题描述】:
今天我决定对 std::vector 和 std::array 的 gcc 可优化性进行基准测试并比较一些差异。一般来说,我发现了我的预期:在每个短数组集合上执行任务比在集合等效向量上执行任务要快得多。
但是,我发现有些意外:使用std::vector 存储数组集合比使用std::array更快。以防它是堆栈上大量数据的某些工件的结果,我还尝试将其分配为堆上的数组和堆上的 C 样式数组(但结果仍然类似于堆栈上的数组和数组的向量)。
知道为什么std::vector 会胜过std::array(编译器有更多的编译时信息)吗?
我使用gcc-4.7 -std=c++11 -O3 编译(gcc-4.6 -std=c++0x -O3 也应该导致这个难题)。运行时间是使用bash-native time 命令(用户时间)计算的。
代码:
#include <array>
#include <vector>
#include <iostream>
#include <assert.h>
#include <algorithm>
template <typename VEC>
double fast_sq_dist(const VEC & lhs, const VEC & rhs) {
assert(lhs.size() == rhs.size());
double result = 0.0;
for (int k=0; k<lhs.size(); ++k) {
double tmp = lhs[k] - rhs[k];
result += tmp * tmp;
}
return result;
}
int main() {
const std::size_t K = 20000;
const std::size_t N = 4;
// declare the data structure for the collection
// (uncomment exactly one of these to time it)
// array of arrays
// runtime: 1.32s
std::array<std::array<double, N>, K > mat;
// array of arrays (allocated on the heap)
// runtime: 1.33s
// std::array<std::array<double, N>, K > & mat = *new std::array<std::array<double, N>, K >;
// C-style heap array of arrays
// runtime: 0.93s
// std::array<double, N> * mat = new std::array<double, N>[K];
// vector of arrays
// runtime: 0.93
// std::vector<std::array<double, N> > mat(K);
// vector of vectors
// runtime: 2.16s
// std::vector<std::vector<double> > mat(K, std::vector<double>(N));
// fill the collection with some arbitrary values
for (std::size_t k=0; k<K; ++k) {
for (std::size_t j=0; j<N; ++j)
mat[k][j] = k*N+j;
}
std::cerr << "constructed" << std::endl;
// compute the sum of all pairwise distances in the collection
double tot = 0.0;
for (std::size_t j=0; j<K; ++j) {
for (std::size_t k=0; k<K; ++k)
tot += fast_sq_dist(mat[j], mat[k]);
}
std::cout << tot << std::endl;
return 0;
}
NB 1:所有版本都打印相同的结果。
注意 2: 并且只是为了证明 std::array<std::array<double, N>, K>、std::vector<std::array<double, N> > 和 std::vector<std::vector<double> > 之间的运行时差异不仅仅是分配时的分配/初始化,简单分配的运行时集合(即注释掉tot 的计算和打印)分别为 0.000s、0.000s 和 0.004s。
注意 3: 每个方法都是单独编译和运行的(不是在同一个可执行文件中背靠背地计时),以防止缓存中的不公平差异。
注意 4:
数组数组的汇编:http://ideone.com/SM8dB
数组向量的组装:http://ideone.com/vhpJv
向量集合:http://ideone.com/RZTNE
注意 5: 绝对清楚,我绝不打算批评 STL。一个绝对喜欢的 STL,而且我不仅经常使用它,而且有效使用的细节教会了我很多 C++ 微妙而伟大的特性。相反,这是一种智力追求:我只是在安排时间来学习高效 C++ 设计的原则。
此外,责怪 STL 是不合理的,因为很难解开运行时差异的病因:启用优化后,编译器优化可能会减慢而不是加快代码时间>。在关闭优化的情况下,它可能来自不必要的复制操作(将被优化并且永远不会在生产代码中执行),这可能比其他数据类型更偏向某些数据类型。
如果您像我一样好奇,我希望您能帮助解决这个问题。
【问题讨论】:
-
尝试以类似 1000 的迭代次数运行它,以查看更准确的值。这些看起来可能只是延迟值。
-
@ColeJohnson 你的意思是
N=1000还是K=1000?如果您的意思是N=1000,则数组向量与向量向量几乎相同(因为不展开循环的开销非常高)。使用N=1会导致数组向量和向量向量之间的差异更大,因为数组向量本质上应该转换为双精度向量。所以比较数组数组和数组向量最有趣的例子是K << N(数学意义上的<<,而不是位移意义上的)。 -
如果交换两个测试会发生什么?
-
@Oliver:就像,在
vector测试之后 进行array测试。或者等等,你是在完全不同的程序上测试它们吗?如果是这样,那我就误会了。 -
它们各自的内部表示方式过于相似,以至于在性能上没有任何差异。这不是一个真正有效的测试,您需要更大的数据集。
标签: c++ optimization stl c++11