这是测试代码 .
元组测试:
using namespace std;
int main(){
vector<tuple<int,int>> v;
for (int var = 0; var < 100000000; ++var) {
v.push_back(make_tuple(var, var));
}
}
配对测试:
#include <vector>
using namespace std;
int main(){
vector<pair<int,int>> v;
for (int var = 0; var < 100000000; ++var) {
v.push_back(make_pair(var, var));
}
}
我通过Linux time命令进行了时间测量 . 结果是:
| | -O0 | -O2 |
|:------|:-------:|:--------:|
| Pair | 8.9 s | 1.60 s |
| Tuple | 19.8 s | 1.96 s |
我想知道,为什么O0中的这两个数据结构之间存在如此大的差异,因为它们应该非常相似 . 02中只有一点不同 .
为什么O0的差异如此之大,为什么会有任何差异?
编辑:
v.resize()的代码
对:
#include <vector>
using namespace std;
int main(){
vector<pair<int,int>> v;
v.resize(100000000);
for (int var = 0; var < 100000000; ++var) {
v[var] = make_pair(var, var);
}
}
元组:
#include<tuple>
#include<vector>
using namespace std;
int main(){
vector<tuple<int,int>> v;
v.resize(100000000);
for (int var = 0; var < 100000000; ++var) {
v[var] = make_tuple(var, var);
}
}
结果:
| | -O0 | -O2 |
|:------|:-------:|:--------:|
| Pair | 5.01 s | 0.77 s |
| Tuple | 10.6 s | 0.87 s |
编辑:
我的系统
g++ (GCC) 4.8.3 20140911 (Red Hat 4.8.3-7)
GLIBCXX_3.4.19
2 回答
您缺少一些重要信息:您使用什么编译器?你用什么来衡量微基准的性能?您使用什么标准库实现?
我的系统:
无论如何,我运行你的例子,但首先保留适当大小的向量,以摆脱内存分配开销 . 有了它,我有趣地观察到相反的东西 - 与你看到的相反:
与:
正如您所看到的,在我的情况下,原因是在前端和后端都有更多的停滞周期 .
现在它来自哪里?我打赌它归结为一些失败的内联,类似于这里解释的:std::vector performance regression when enabling C++11
确实,启用
-flto
为我 balancer 结果:和元组:
所以请记住,
-flto
是你的朋友,失败的内联可能会在严格模板化的代码上产生极端的结果 . 使用perf stat
找出发生了什么 .milianw没有解决
-O0
与-O2
,所以我想补充说明 .完全可以预期
std::tuple
在未经优化时将比std::pair
慢,因为它是更复杂的对象 . 一对只有两个成员,所以它的方法很容易定义 . 但是元组有任意数量的成员,迭代模板参数列表的唯一方法是使用递归 . 因此,元组的大多数函数处理一个成员然后递归以处理其余成员,因此对于2元组,您有两倍的函数调用 .现在,当它们被优化时,编译器将内联递归并且不应存在显着差异 . 哪些测试明确证实 . 这适用于一般的模板化程度很高的东西 . 可以编写模板以提供没有或很少运行时开销的抽象,但是依赖于优化来内联所有简单的函数 .