手记

揭穿内存厂家“谎言”,实测内存带宽真实表现

带宽是存储系统一个的一个非常重要的衡量指标,内存带宽指的是CPU从内存读取或写入数据到内存的速率。我们今天来思考一个问题,在你的应用程序里内存的访问带宽能够达到多少?

各代内存带宽规格

理论上内存带宽的计算公式是:Band Width = Speed * Data Width。在这个公式的基础上,我们来看一下各代规格的内存带宽表现。

从上图来看,DDR3代的内存 DDR3代1066MHz的带宽都已经达到了8.5GB/s, DDR4代3200MHz更是达到了惊人的25.6G。 厂家在进行销售的时候也都是用这个公式来算,言外之意就是告诉你:“我家的产品非常快,大家赶快来买啊!”

厂家这么宣传似乎也不算错,但是有诱导性的谎言在其中。 厂家这个数据的基础是内存严格以顺序IO的方式工作,而且把传输的内存地址也当数据来看,进而计算出的结果。但我们在《内存随机访问也比顺序慢,带你深入理解内存IO过程》中明白了的是,内存在并一定是所有的Data Speed周期都在源源不断往外吐数据。在CPU传入了行地址后,内存打开一行需要tRCD+tRP个时钟周期的延迟。输入列地址后,又需要等待CL个时钟周期。而内存作为易失性存储元器件,又需要定时对所有的行进行充电,来保证数据不丢失。所以,在实践中,我们并不是总是能够达到厂家宣传的理论带宽值。

>注意:理论带宽值计算时采用的是内存的Speed,也就是其数据频率。而内存的延迟呢,用的是时钟周期。现代的内存在时钟周期的上沿和下沿都可以传输数据,所以数据频率比Speed又慢了一半。对于笔者Speed为1067MHz的内存条,其时钟频率是553MHz。

邓爷爷说过,实践是检验真理的唯一标准。我们今天就来进行一下实际的测试,看看内存的到底每秒能给我们吐出多少的数据。和前文《实际测试内存在顺序IO和随机IO时的访问延时差异》的测试方法类似,我们今天对方法进行下小改动,用它来测试带宽。

顺序IO情况核心测试方法

测试代码主体上和延迟测试差不多,定义一个指定大小的数组,然后以指定步长对其进行访问。

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;  
}

考虑到内存对齐能提高性能,所以公平起见,我们每次都是按内存位宽去取的(一个double 8个字节,正好是一个内存位宽)。带宽就是一秒内访问过的字节总数,所以我们通过如下代码进行计算。

result = total_accessed_bytes * 1000  / used_microseconds;

顺序IO情况带宽测试结果

笔者的服务器上的内存条是DDR3,1067MHz,延迟参数为7-7-7-24。我们进行了多场景的测试。

场景一: 固定数组大小2K,调节步长

步长 1 9 17 25 33 41 49 57 64
带宽MB 6185 6263 6001 5930 6116 5660 5523 5682 6316

数组为2k,足够小到L1 cache全部都能装的下。这时候其实基本实际内存IO发生的很少,大部分都是更高效的L1 cache的IO,在CPU内部就完成了。但最高值也才6G而已,也没有达到厂家宣称的8GB。

场景二: 固定步长为8,数组从32K到64M

数组大小 8K 32K 64K 256K 512K 2M 8M 16M 64M
带宽MB 6066 6314 4577 3960 3059 3047 2769 1551 1386

数组越大,Cache越装不下,数据访问的IO会更多地往后穿透到L2、L3和内存。L1、L2、L3和内存IO的性能依次递减,因此数组越大,平均带宽就会越低。

场景三: 步长为32,数组从32K到64M

数组大小 8K 32K 64K 256K 512K 2M 8M 16M 64M
带宽MB 6376 6394 4647 3735 3193 3179 1481 1002 902

步长增加后,穿透到内存的次数进一步增加,带宽进一步下降。这个时候,我们应用程序视角看到的数据带宽已经下降到1GB以下了。

再测随机IO情况

前面的测试情况,虽然步长也在变化,但都是有序递增。这样内存的连续两次IO之间,虽然列地址会变,但是行地址极有可能不发生变化,因此效率还是算比较高。 我们这次是来彻底随机进行访问,再来看一下。

** 随机访问,数组从8K到64M **

数组大小 8K 32K 64K 256K 512K 2M 8M 16M 64M
带宽MB 6378 5850 4764 3405 3193 2948 967 749 474

当数组比较小的时候,虽然乱序访问,但是cache能兜住,因此内存IO实际上发生的很少。但当数组增加到64M的时候,再加上哪一级Cache都兜不住了。再加上访问又足够随机,因此都穿透到了内存,而且行的行地址也极大可能发生变化。这时,内存带宽竟然下降到了474M。

结论

厂家在宣传的内存带宽数据的时候,用的是严格顺序IO情况下的数据,而且把地址的传输也当数据算了。但是厂家不会告诉你,在实际中内存的带宽并没有你想象的那么快,在随机IO工作模式的情况下,带宽只有474M而已。 现在SSD固态硬盘顺序IO也差不多能达到这个数量级了。所以,我们以后不要鲁莽地说内存比硬盘要快很多。快不快,关键取决于你怎么用!


在这里我不是单纯介绍技术理论,也不只介绍实践经验。而是把理论与实践结合起来,用实践加深对理论的理解、用理论提高你的技术实践能力。欢迎你来关注我的公众号,也请分享给你的好友~~~

0人推荐
随时随地看视频
慕课网APP