在《内存随机也比程序拜访慢,带你深刻了解内存IO过程》一文中,咱们了解了内存IO的外部实现过程,晓得了内存的随机IO比程序IO要慢,并对延迟时间进行了大略的估算。那么咱们明天来用代码的形式来工夫一下,看看在咱们的我的项目工程中,内存拜访的在不同的拜访场景下延时到底是个什么体现。
先测程序状况
测试原理就是定义一个指定大小的double(8字节)数组,而后以指定的步长去循环。这外面的变量有两个。外围代码如下:
void init_data(double *data, int n){
int i;
for (i = 0; i < n; i++) {
data[i] = i;
}
}
void seque_access(int elems, int stride) {
int i;
double result = 0.0;
volatile double sink;
for (i = 0; i < elems; i += stride) {
result += data[i];
}
sink = result;
}
在这个外围代码的根底上,咱们有两个可调节变量:
- 一是数组大小,数组越小,高速缓存命中率越高,均匀延时就会越低。
- 二是循环步长,步长越小,程序性越好,同样也会减少缓存命中率,均匀延时也低。
咱们再测试的过程中采取的方法是,固定其中一个变量,而后动静调节另外一个变量来查看成果。
另外阐明一下,这个代码测试中思考的几个额定的开销的解决状况。
1.加法开销:因为加法指令简略,一个CPU周期就可实现,CPU周期比内存周期要快,所以暂且疏忽它。
2.耗时统计:这波及到高开销的零碎调用,本试验通过跑1000次取一次耗时的形式来升高影响。
场景一: 固定数组大小2K,调节步长
步长 | 1 | 9 | 17 | 25 | 33 | 41 | 49 | 57 |
---|---|---|---|---|---|---|---|---|
延时ns | 1.28 | 1.28 | 1.33 | 1.30 | 1.30 | 1.41 | 1.45 | 1.4 |
数组足够小的时候,L1 cache全副都能装的下。内存IO产生较少,大部分都是高效的缓存IO,所以我这里看到的内存延时只有1ns左右,这其实只是虚拟地址转换+L1拜访的延时。
场景二: 固定步长为8,数组从32K到64M
数组大小 | 32K | 64K | 256K | 512K | 2M | 8M | 16M | 64M |
---|---|---|---|---|---|---|---|---|
延时ns | 1.27 | 1.73 | 2.03 | 2.62 | 2.62 | 2.88 | 5.17 | 5.84 |
当数组越来越大,Cache装不下,导致穿透高速缓存,到内存理论IO的次数就会变多,均匀耗时就减少
场景三: 步长为32,数组从32K到64M
数组大小 | 32K | 64K | 256K | 512K | 2M | 8M | 16M | 64M |
---|---|---|---|---|---|---|---|---|
延时ns | 1.25 | 1.74 | 2.03 | 2.47 | 2.47 | 3.29 | 7.73 | 8.89 |
和场景二相比,步长变大当前,局部性变差,穿透的内存IO进一步减少。尽管数据量一样大,然而均匀耗时就会持续有所上涨。不过尽管穿透减少,但因为拜访地址依然绝对比拟间断,所以即便产生内存IO也绝大部分都是行地址不变的程序IO状况。所以耗时在9ns左右,和之前估算大抵相符!
另外留神一个细节,就是随着数组从64M到32M变动的过程中。耗时有几个显著的降落点,别离是8M,256K和32K。这是因为本机的CPU的L1大小是32K,L2是256K,L3是12M。在数据集32K的时候,L1全能装的下,所有根本都是高速缓存IO。256K的时候、8M的时候,尽管L1命中率降落,然而L2、L3访问速度依然比真正的内存IO快。然而超过12M当前越多,真正的内存IO就越来越多了。
再测随机IO状况
在程序的试验场景里,数组的下标拜访都是比拟有法则地递增。在随机IO的测试中,咱们要彻底打乱这个法则,提前随机好一个下标数组,试验时不停地拜访数组的各个随机地位。
void init_data(double *data, int n){
int i;
for (i = 0; i < n; i++) {
data[i] = i;
}
}
void random_access(int* random_index_arr, int count) {
int i;
double result = 0.0;
volatile double sink;
for (i = 0; i < count; i++) {
result += data[*(random_index_arr+i)];
}
sink = result;
}
这理论比下面的试验多了一次内存IO,但因为对random\_index\_arr的拜访时程序的,而且该数组也比拟小。咱们假如它全副能命中高速缓存,所以暂且疏忽它的影响。
随机试验场景: 数组从32K到64M
数组大小 | 32K | 64K | 256K | 512K | 2M | 8M | 16M | 64M |
---|---|---|---|---|---|---|---|---|
延时ns | 2.4 | 2.4 | 2.4 | 4.8 | 4.8 | 19.2 | 24 | 38.4 |
这次的数组拜访就没有步长的概念了,全副打乱,随机拜访。当数据集比拟小的时候、L1、L2、L3还能抗一抗。但当减少到16M、64M当前,穿透到内存的IO状况会变多,穿透过来当前极大可能行地址也会变。在64M的数据集中,内存的延时居然降落到了38.4ns,和咱们估算的也基本一致。
论断
有了试验数据的佐证,进一步证实了上一文《深刻了解内存IO的理论过程!》的论断。内存也存在随机拜访比程序拜访慢的多的状况,大略是4:1的关系。所以不要感觉内存很快,就用起来太随性了!
开发内功修炼之内存篇专辑:
- 1.带你深刻了解内存对齐最底层原理
- 2.内存随机也比程序拜访慢,带你深刻了解内存IO过程
- 3.从DDR到DDR4,内存外围频率其实基本上就没太大的提高
- 4.理论测试内存在程序IO和随机IO时的拜访延时差别
- 5.揭穿内存厂家“谎话”,实测内存带宽实在体现
- 6.NUMA架构下的内存拜访提早区别!
- 7.PHP7内存性能优化的思维精华
- 8.一次内存性能晋升的我的项目实际
- 9.挑战Redis单实例内存最大极限,“遭逢”NUMA陷阱!
我的公众号是「开发内功修炼」,在这里我不是单纯介绍技术实践,也不只介绍实践经验。而是把实践与实际联合起来,用实际加深对实践的了解、用实践进步你的技术实际能力。欢送你来关注我的公众号,也请分享给你的好友~~~
发表回复