美文网首页开发者内功修炼
内存延迟实际测试

内存延迟实际测试

作者: yanfeizhang | 来源:发表于2019-05-21 09:37 被阅读0次

    在前面的文章你能估算出你的内存的访问延时吗?中,我们对内存的访问延迟进行了理论上的研究。那么今天我们实际编写代码进行一下测试。 看一下实践能否和理论匹配的上。
    为了衡量各种情况下的内存带宽情况。我们用c写了一个double类型的数组,然后用for循环对其进行遍历,然后统计其每次访问内存平均耗时情况。核心代码如下:

    /*
     * 初始化一个指定大小的数组
     * 通过对内存大小不断变化,逐步制造出一级、二级、三级溢出、最后穿透到内存IO的case。
     */
    void init_data(double *data, int n){
        int i;
        for (i = 0; i < n; i++) {
            data[i] = i;
        }
    }
    
    /*
     * 对内存以指定步长执行顺序访问
     * 这块测试代码有个加法额外开销。算术运算是以CPU周期来计算的,比内存周期要快。
     * 所以本测试中忽略这个算术运算带来的额外开销。
     */
    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; 
    }
    /*
     * 对内存执行随机访问,其中random_index_arr是提前随机好的数组下标。  
     * 这实际比顺序多了一次内存IO,但由于对random_index_arr的访问时顺序的,而且数组要相对小很多。
     * 所以它绝大部分情况下都能命中高速缓存,可以忽略这个小内存IO对主测试过程的影响。
     */
    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; 
    }
    

    实验结果数据

    注意,不同的机器的实验数据会略有差异。越新的机器数据表现越好,因为硬件参数不一样,但是偏差不会太大。

    case 1: 内存2k,步长从1到64

    步长(字节) 延迟(ns)
    1 1.28
    9 1.28
    17 1.33
    25 1.35
    33 1.30
    41 1.41
    49 1.45
    57 1.40
    64 1.27

    结论:内存足够小的时候,一级高速缓存完全能装的下,因此绝大部分的请求都是一级缓存IO,内存IO并没有怎么进行。所以无论步长怎么变化,延迟基本都在1ns左右。

    case2:内存从8k到64M,步长固定8

    内存大小 延迟(ns)
    8k 1.32
    32k 1.27
    64k 1.73
    256k 2.03
    512k 2.62
    2m 2.62
    8m 2.88
    16m 5.17
    64m 5.84

    结论:内存越来越大,CPU的高速缓存逐渐hold不住了,越来越多的请求穿透到了内存。延迟已经逐步接近真实的内存IO了

    case3:内存从8k到64M,步长固定64

    内存大小 延迟(ns)
    8k 1.25
    32k 1.25
    64k 1.74
    256k 2.03
    512k 2.47
    2m 2.47
    8m 3.29
    16m 7.73
    64m 8.89

    结论:步长从case2的8增加到了本case的64以后,空间局部性进一步被打乱。内存在2m以下的时候,延迟没有太大变化。因为虽然局部性乱,但CPU缓存都能hold住,穿透到内存的情况不多。但当内存编程8m或者64m的情况下,高速缓存命中率就会降低,因此平均延迟也增加到了9ns左右。这个数字其实就是内存在顺序IO时的大概耗时。

    case4 内存8k到64m,彻底随机访问

    内存大小 延迟(ns)
    8k 2.40
    32k 2.40
    64k 2.40
    256k 2.40
    512k 4.80
    2m 4.80
    8m 19.20
    16m 24.0
    64m 38.40

    结论:当彻底随机访问以后,不光是穿透到内存的IO变多了,而且穿透到内存的IO也增大了行地址变化的概率。也就是说内存IO也不能以高效的顺序IO进行了,更多的请求进行的是行列地址都变了的随机IO。因此64m的情况下,内存IO延迟增加到了将近40ns

    最终结论

    • 内存顺序IO延迟在9ns左右
    • 内存随机IO延迟在40ns左右
    • 如果程序局部性写的足够好,操作系统会帮你用CPU缓存访问减少低效的内存IO。

    个人公众号“开发内功管理”,打通理论与实践的任督二脉。

    相关文章

      网友评论

        本文标题:内存延迟实际测试

        本文链接:https://www.haomeiwen.com/subject/tgtnaqtx.html