CPU预取与性能简介

随着计算机硬件的发展,CPU主频已由过去 MHz 发展到了现在的 GHz,而常用硬盘的存取速率还是几百MB每秒,虽然现在SSD卡也可以达到几个GB,但是还是太慢了。
处理器的速度的不停发展,导致磁盘 I/O是整个性能的瓶颈,而且磁盘的访问速率与 CPU 的速度差距还在持续扩大。 

而存储介质从光盘、磁盘、内存到高速缓存,速度越来越快,但是成本也越来越高。为了在成本和性能之间进行平衡,现代计算机体系架构往往选择使用少量性能高但成本也高的存储器作为速度慢而成本也低的存储器的缓存。 就出现了存储层次。
1.png
但是即便如此,CPU的一次访存失败也会带来巨大的时钟周期开销,如何减少访存失败就成了一个关键的问题。而预取就是为此而出现。

  1. 预取

    缓存技术利用局部性原理,使速度更快的上层存储器成为下层存储器的缓冲。基于技术的限制及成本的考虑,上层存储器的容量要比下层存储器小得多。数据如果存在于上层存储器中,就可以直接对其进行读写, 这种情形叫做命中,命中的统计概率叫做命中率;如果未命中就必须涉及到访问下层存储器,这种情形也叫失效。
    但是随着应用规模的不断扩大缓存失效所占的比例越来越大,成为影响缓存性能的主要因素。为了提高缓存的命中率,
    预取技术通过计算和访存的重叠,在Cache可能会发生失效之前发出预取请求以便在该数据真正被使用到时己提前将数据块取入Cache,从而避免Cache失效造成的处理器停顿。

  2. 关于cache预取

    cache预取是将内存中的指令和数据提前存放到本地内存(cache memory),从而加快处理器执行速度。这里分为指令预取和数据预取,数据预取相比指令语句更具有挑战性,因为数据预取规律更少一点。
    指令预取在INTEL 8086和Motorla 68000就开始了。

  3. Cache预取分类

    Cache预取可以通过硬件或者软件实现,也就是分为硬件预取和软件预取两类。
    硬件预取,是通过处理器中专门的硬件来实现的,该硬件监控正在执行程序中请求的指令或数据,识别下一个程序需要的流然后预取到处理器中。
    软件预取,是通过编译器分析代码然后在程序编译的过程中插入prefetech。这样在执行过程中在指定位置就会进行预取的动作。

  4. 硬件预取

    硬件预取中有Stream buffers方法,由Alan Jay Smith建议,基于"one block lookahead (OBL) scheme"。
    Stream buffers是硬件预取中最常用的方法。最早在1990年由Norman jouppi提出。
    Stream buffers是独立于cache的buffer。
    CPU发生Cache miss后,如果在stream buffer中查到了相应的数据,则处理器把这个cache block取到cache中。
    与二级cache对比,streambuffer的硬件逻辑很少,访问stream buffer比访问二级cache快。如果不快那还不如直接访问二级cache。
    当在预取机制在内存中找到了块A,那么会预取连续的A+1,A+2,A+3,A+4。因为处理器消耗完A+1后会接着消耗A+2的,预取连续的块也叫做顺序预取。这个顺序预取在预取指令集的时候非常有有用,如下图。
    2.png
    这个方法可以通过增加stream buffer来放大,对于每个访问失败,都会分配一个新的stream buffer。
    而stream buffer的深度则取决于压测模型和微架构。
    指令的另一个预取方式是提前S个地址进行预取,叫做步幅预取。

  5. 软件预取

    编译器指定预取,在大量迭代中非常常用。编译器预测未来cache miss然后插入预取指令。
    这种预取不会阻塞内存操作,不会改变处理器状态或导致页错误。软件预取减少了强制的cache miss。
    例如有循环如下:
    for (int i=0; i<1024; i++) { array1[i] = 2 * array1[i]; }
    每次迭代,i变量会增加,这样可以提前让i进行增加,通过编译器加入prefetch代码如下:
    for (int i=0; i<1024; i++) { prefetch (array1 [i + k]); array1[i] = 2 * array1[i]; }
    这的预取步幅k,取决于两个因素,1个迭代的时间(假设为7个时钟周期)和cache miss迭代的时间(假设为49个时钟周期),那么k=49/7=7。表示预取7个元素。

  6. 软硬件预取对比

    软件预取需要程序员或编译器,硬件预取需要硬件机构。
    软件预取在有规律的循环中实现预取指令,硬件预取可以基于程序的动态运行来工作。
    硬件预取相比软件预取消耗更少的CPU。
    预取的覆盖率计算:由于预取消除的cache miss除以总的cache miss就是预取的覆盖率。如下图:
    3.png
    预取的精确性,计算方法为预取消除的cache miss除以(无效的预取加上预取消除的cache miss),公式如下图:
    4.png

  7. 预取对应用影响

    通过以上分析介绍,我们知道预取对程序肯定是会有影响的。但并非所有业务在开启预取条件都是性能增益的,预取对那些有规律的数据采集和指令执行过程中才会发挥最大功效,而在随机业务红预取反而是有害的,因为随机事务业务中的数据都是随机的,预取进来的数据在接下去的业务中并不能有效利用只是白白浪费了CACHE空间和资源。
    以JVM性能测试为例子,使用SPECJbb 2005 测试套件。在同一台SKL机器上进行压测,我们发现,当ENABLE Prefetch选项后性能是比Disable要低的。

  8. 参考

Intel 平台编程总结----缓存优化之数据预取:
http://blog.chinaunix.net/uid-20385936-id-3902562.html
Cache_prefetching
https://en.wikipedia.org/wiki/Cache_prefetching
stream buffer
http://blog.csdn.net/qianlong4526888/article/details/41517303
Optimizing Application Performance on Intel® Core™ Microarchitecture Using Hardware-Implemented Prefetchers
https://software.intel.com/en-us/articles/optimizing-application-performance-on-intel-coret-microarchitecture-using-hardware-implemented-prefetchers

标签: none

添加新评论