寄存器山分析——CSAPP discuss

解读所附 mountain 程序,并将该 mountain 程序在本组内不同(品牌/配置)PC 的 linux 系统上运行它。尝试绘制自己的存储器 山三维图(或两张二维图),并解读该存储器山,根据结果分析该系统上的高速缓存的大小。建议可在组内不同配置机器上运行,比较不 同机器上高速缓存的设置。

一. 解读 mountain 程序:

int main()
{
    int size;        /* Working set size (in bytes) 工作集*/
    int stride;      /* Stride (in array elements) 步长*/
    double Mhz;      /* Clock frequency 时钟频率,主频*/

    init_data(data, MAXELEMS); /* Initialize each element in data 初始化数据中的每个元素*/
    Mhz = mhz(0);              /* Estimate the clock frequency 估计时钟频率*/
    /* $end mountainmain */
    /* Not shown in the text */
    printf("Clock frequency is approx. %.1f MHz\n", Mhz);
    printf("Memory mountain (MB/sec)\n");

    printf("\t");
    for (stride = 1; stride <= MAXSTRIDE; stride++)
    printf("s%d\t", stride);
    printf("\n");

    /* $begin mountainmain */
    for (size = MAXBYTES; size >= MINBYTES; size >>= 1) {   //遍历size工作集,cache(1 << 27) 128M--->(1<<14) 16k
        /* $end mountainmain */
        /* Not shown in the text */
        if (size > (1 << 20))
            printf("%dm\t", size / (1 << 20));
        else
            printf("%dk\t", size / 1024);

        /* $begin mountainmain */
        for (stride = 1; stride <= MAXSTRIDE; stride++) {   //遍历步长stride,1--->15
            printf("%.1f\t", run(size, stride, Mhz));
            
        }
        printf("\n");
    }
    exit(0);
}
int test(int elems, int stride) /* The test function 测试程序*/
{
    int i;
    long result = 0; 
    volatile long sink; 

    for (i = 0; i < elems; i += stride) {
    result += data[i];  
    }
    sink = result; /* So compiler doesn't optimize away the loop 所以编译器不会优化循环*/
    return sink;
}
double run(int size, int stride, double Mhz)
{   
    double cycles;
    int elems = size / sizeof(double);       

    test(elems, stride);                     /* warm up the cache */       //line:mem:warmup    预热缓存
    cycles = fcyc2(test, elems, stride, 0);  /* call test(elems,stride) */ //line:mem:fcyc
    return (size / stride) / (cycles / Mhz); /* convert cycles to MB/s */  //line:mem:bwcompute number/time
}

① 如果一个程序在 s 秒的时间段内读 n 个字节,那么这段时间内的读吞吐量就 等于n/s,典型地是以兆字节每秒 (MB/s) 为单位的
② run函数内部又一重循环,通过以步长 stride 扫描整数数组的头 elems 个元素来产生读序列,那么测量出的读吞吐量能让我们看到对于这个读序列来说的存储系统的性能。
③ 这个run程序运行的时间通过fcyc2函数来测量,以 CPU 周期为单位。
④ 而读次数n=size/stride,运行时间为s=cycle/Mhz(CPU主频),利用公式n/s即计算出读吞吐量
⑤ 我们已经具备了测量读吞吐量,接下来我们就要产生足够多的序列数据,通过双重循环遍历/遍历步长stride1—>64,workSize (1 << 25) 32M—>(1<<11) 2k从而生成足够多的数据

二. 数据分析

1.编译运行

linux>gcc -c clock.c -o clock.o
linux> gcc -c fcyc2.c -o fcyc2.o
linux> gcc -c mountain.c -o mountain.o
linux> gcc clock.o fcyc2.o mountain.o -o run
linux>./run
  • 用 lscpu指令查看cache大小:

在这里插入图片描述

  • 数据分析:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    (1)整体分析:
    ① size 从 2KB 变到 32MB, stride 从 1 变到 64 个元素,每个元素是一个 8 个字节的 double
    整体趋势:我们看到随着workSetSize的增大读吞吐率反而减小;随着随着stride的增大读吞吐率也呈现减小的趋势;因此整个Corei5的都吞吐量的趋势是:size 的值越小,得到的工作集越小,因此时间局部性越好。 stride 的值越小,得到的空间局部性越好。
    ② 垂直于 size 轴的是四条山脊,分别 对应于工作集完全在 Ll 高速缓存、 L2 高速缓存、 L3 高速缓存和主存内的时间局部性区城。
    ③ 在 L1,L2、 L3 和主存山脊上随着步长的增加有一个空间局部性的斜坡,空间局部性下降。

(2)取出一个片段,保持步长为常数stride=16
在这里插入图片描述
工作集完全能放进统一的 L3 高速缓 存中。更大的工作集大小主要由主存来服务。
① 在吞吐量峰值 4213MB/s 处,读都是由 L1 来服务的,大小最大为 256KB 的工作 集完全能放进统一的 L2 高速缓存中,对于大小最大为 8M, 工作集完全能放进统一的 L3 高速缓 存中。更大的工作集大小主要由主存来服务。
② 由此估计出本机器的数据L1-d-cache大致为32KB,L2-cache=256kb,L3通用cache=8M
③ L3 高速缓存区域最左边的边缘上读吞吐量的下降很有可能是 由其他数据和代码块造成的,这些数据和代码块使得不可能将整个数组都装进相应的高速缓存中。

(3)保持工作集大小不变,size=256kb,空间局部性斜坡如下:
在这里插入图片描述
① 在256kb 山脊,L2中的读不命中会导致一个块从 L3 传送到 L2。后面在 L2 中这个块上会有一定数量的 命中,这是取决于步长的。随着步长的增加, L2 不命中与 L2 命中的比值也增加了。所以说吞吐量呈现下降的趋势。

机器2:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
① size 从 2KB 变到 32MB, stride 从 1 变到 64 个元素,每个元素是一个 8 个字节的 double
整体趋势:我们看到随着workSetSize的增大读吞吐率反而减小;随着随着stride的增大读吞吐率也呈现减小的趋势;因此整个Corei5的都吞吐量的趋势是:size 的值越小,得到的工作集越小,因此时间局部性越好。 stride 的值越小,得到的空间局部性越好。
② 垂直于 size 轴的是四条山脊,分别 对应于工作集完全在 Ll 高速缓存、 L2 高速缓存、 L3 高速缓存和主存内的时间局部性区城。
④ 在 L1,L2、 L3 和主存山脊上随着步长的增加有一个空间局部性的斜坡,空间局部性下降。

(2)取出一个片段,保持步长为常数stride=16
在这里插入图片描述
工作集完全能放进统一的 L3 高速缓 存中。更大的工作集大小主要由主存来服务。
④ 在吞吐量峰值 3158.3MB/s 处,读都是由 L1 来服务的,大小最大为 256KB 的工作 集完全能放进统一的 L2 高速缓存中,对于大小最大为 6M, 工作集完全能放进统一的 L3 高速缓 存中。更大的工作集大小主要由主存来服务。
⑤ 由此估计出本机器的数据L1-d-cache大致为32KB,L2-cache=256kb,L3通用cache=6M左右
⑥ L3 高速缓存区域最左边的边缘上读吞吐量的下降很有可能是 由其他数据和代码块造成的,这些数据和代码块使得不可能将整个数组都装进相应的高速缓存中。

(3)保持工作集大小不变,size=256kb,空间局部性斜坡如下:
在这里插入图片描述
① 在256kb 山脊,L2中的读不命中会导致一个块从 L3 传送到 L2。后面在 L2 中这个块上会有一定数量的 命中,这是取决于步长的。随着步长的增加, L2 不命中与 L2 命中的比值也增加了。所以说吞吐量呈现下降的趋势。

三.结论

① 机器1的数据L1-d-cache大致为32KB,L2-cache=256kb,L3通用cache=8M左右,机器2的数据L1-d-cache大致为32KB,L2-cache=256kb,L3通用cache=6M左右。
② 我们看到随着workSetSize的增大读吞吐率反而减小;随着随着stride的增大读吞吐率也呈现减小的趋势;因此整个Corei5的都吞吐量的趋势是:size 的值越小,得到的工作集越小,因此时间局部性越好。 stride 的值越小,得到的空间局部性越好。
③ 存储器系统的性能是一座时间和空间局部性的山,这座山的上升高度差别可以超过一个数量级。在编写我们的程序时,应该尽量使得程序运行在山峰而不是低谷。目标就是利用时间局部性,使得频繁使用的字、字从 Ll 中取出,还要利用空间局部性,使得尽可能多的字从一个 Ll 高速缓存行中访问到。

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: Age of Ai 设计师: meimeiellie
应支付0元
点击重新获取
扫码支付

支付成功即可阅读