关于linux:实际测试内存在顺序IO和随机IO时的访问延时差异

在《内存随机也比程序拜访慢,带你深刻了解内存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陷阱!

我的公众号是「开发内功修炼」,在这里我不是单纯介绍技术实践,也不只介绍实践经验。而是把实践与实际联合起来,用实际加深对实践的了解、用实践进步你的技术实际能力。欢送你来关注我的公众号,也请分享给你的好友~~~

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理