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

62次阅读

共计 2394 个字符,预计需要花费 6 分钟才能阅读完成。

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

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

正文完
 0