- 主题:std::vector中初始化与否导致性能差异巨大
最近碰到一个奇怪的问题, 一个简单的R3对象, 存放在std::vector中.
费解的一幕出现了, 如果vv定义的时候, 为每个元素指定初值, 那么后面对vv进行写操作就飞快.
而如果vv定义的时候, 不指定初值, 那么后面对vv写操作的时候, 就花费大约前一种3倍的时间.
大家知道这是什么原因引起的?
ps1. 后来我不用vector, 直接用new : R3* vv = new R3[POPULATION], 发现也有类似的情况. 如果new 了之后, 直接使用这个数组, 第一次访问的时候肯定慢, 第二次访问就快了. 太神奇了.
ps2. 我曾经怀疑, 是否是第一次使用这片内存后, 这片内存以某种机制被缓存了, 于是就在第一次访问和第二次访问之间, 插入了许多读写其他内存的代码, 可是发现第二次访问, 仍然非常块, 还是很神奇.
下面是代码
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <vector>
namespace {
struct R3
{
R3() {}
R3(double x, double y, double z)
{
m_data[0] = x; m_data[1] = y; m_data[2] = z;
}
double m_data[3];
};
static int const POPULATION = 10000000;
inline void time_report (const char* title, clock_t& latest_value)
{
clock_t now = clock();
printf("time elapsed for %s : %.8f(s)\n",
title, (double(now) - double(latest_value)) /CLOCKS_PER_SEC );
latest_value = now;
};
static const bool FILL_WITH_COMP = true;
}
void test_R3_performance()
{
clock_t latest_value = clock();
//std::vector<R3> vv(POPULATION); // <--- uninitialized vector
std::vector<R3> vv(POPULATION , R3{ 0, 0, 0 });
time_report("allocation finished", latest_value);
for (int i = 0; i<POPULATION; ++i)
{
vv[i] = {(double)i*2, (double)i + 4, (double)i + 6};
}
time_report("assignment finished", latest_value);
}
int main()
{
test_R3_performance();
return 0;
}
--
FROM 120.244.224.*
gcc执行结果(带初值):
time elapsed for allocation finished : 0.04800000(s)
time elapsed for assignment finished : 0.01400000(s)
如果不带初值定义vv, 结果如下
time elapsed for allocation finished : 0.00000000(s)
time elapsed for assignment finished : 0.05200000(s)
--
FROM 120.244.224.*
你应该把测试写成两个独立的程序做测试
否则你之前的测试用的内存页
还在操作系统里的页缓存里
【 在 xieyf 的大作中提到: 】
: gcc执行结果(带初值):
: time elapsed for allocation finished : 0.04800000(s)
: time elapsed for assignment finished : 0.01400000(s)
: ...................
--
FROM 205.220.129.*
我在linux下也测出了同样的现象。
我搞成两个独立程序试一试。
【 在 mvtec (mvtec) 的大作中提到: 】
: 你应该把测试写成两个独立的程序做测试
: 否则你之前的测试用的内存页
: 还在操作系统里的页缓存里
: ...................
--
FROM 120.244.224.*
还是这个效果, 现象太稳定了。
???@localhost:~/ttest> ./strange_init && ./strange_uninit
time elapsed for allocation finished : 0.01931500(s) <---初始化
time elapsed for assignment finished : 0.01334200(s)
time elapsed for allocation finished : 0.00000200(s) <---未初始化
time elapsed for assignment finished : 0.01982100(s)
【 在 mvtec 的大作中提到: 】
: 你应该把测试写成两个独立的程序做测试
: 否则你之前的测试用的内存页
: 还在操作系统里的页缓存里
--
修改:xieyf FROM 120.244.224.*
FROM 120.244.224.*
如果先测试未初始化
再测试初始化什么结果
另外vector是先malloc再用placement new
【 在 xieyf 的大作中提到: 】
: 还是这个效果, 现象太稳定了。
: ???@localhost:~/ttest> ./strange_init && ./strange_uninit
: time elapsed for allocation finished : 0.01931500(s) <---初始化
: ...................
--
FROM 205.220.129.*
你看下编译出来的机器码,我猜是初始化的时候因为assigment,所以m_data[3]全部进入缓存了,类似pre-fetch,后面访问起来就快。如果用default ctor初始化(并不是没有初始化,是用default ctor初始化),default ctor里并没有访问m_data[3],所以没有进入缓存
--
FROM 115.199.99.*
我现在怀疑new出来的内存是没有commit的。
访问一遍后, vv中所有内容都是commited, 所以访问起来就快了。
这只是一种猜测.
【 在 ziqin (子青|会挽雕弓如满月|西北望|射天狼) 的大作中提到: 】
: 你看下编译出来的机器码,我猜是初始化的时候因为assigment,所以m_data[3]全部进入缓存了,类似pre-fetch,后面访问起来就快。如果用default ctor初始化(并不是没有初始化,是用default ctor初始化),default ctor里并没有访问m_data[3],所以没有进入缓存
--
FROM 120.244.224.*
改动了一下测试函数, 搞成初始化一半的空间.
居然性能真的介于 初始化和不初始化之间. 我严重怀疑这是 uncommited memory搞得鬼。
void test_R3_performance()
{
clock_t latest_value = clock();
std::vector<R3> vv(POPULATION); // <--- uninitialized vector
//std::vector<R3> vv(POPULATION , R3{ 0, 0, 0 });
for (int i = 0; i<POPULATION/2; ++i) // <-------- key code!
vv[i] = {0, 0, 0};
time_report("allocation finished", latest_value);
for (int i = 0; i<POPULATION; ++i)
{
vv[i] = {(double)i*2, (double)i + 4, (double)i + 6};
}
time_report("assignment finished", latest_value);
}
【 在 ziqin 的大作中提到: 】
: 你看下编译出来的机器码,我猜是初始化的时候因为assigment,所以m_data[3]全部进入缓存了,类似pre-fetch,后面访问起来就快。如果用default ctor初始化(并不是没有初始化,是用default ctor初始化),default ctor里并没有访问m_data[3],所以没有进入缓存
--
FROM 120.244.224.*
你把你机器的配置贴一下
【 在 xieyf 的大作中提到: 】
: 改动了一下测试函数, 搞成初始化一半的空间.
: 居然性能真的介于 初始化和不初始化之间. 我严重怀疑这是 uncommited memory搞得鬼。
:
: ...................
--
FROM 107.77.207.*