您的位置:首页 > 编程语言

Intel 平台编程总结----缓存优化之数据预取

2014-03-27 21:59 295 查看
数据预取指的是在实际访问数据之前就预先把该数据读取到缓存中。

Intel处理器从P3开始支持软件预取,这是通过在合适的时候预取指令来加载数据完成的。从P4开始,后面的处理器都支持硬解预取,到导致两个连续的缓存缺失的内存地址之间的距离在给定的阈值(128B或者256B)之内时,处理器就会触发数据预取。另外,那些步长为常量(包括向前步长和向后步长)的流式访问也可能触发硬件预取,预取单元可以同时支持多个独立的数据流的预取。

基于Netburst体系结构的处理器要求每个流必须属于不同的4KB的页,同时预取也不会超越4KB的边界到另外一个页,因此,硬件预取对于那些小步长切不会超过4KB的数据访问最为有效。基于Core系统结构的处理器允许跨越页的边界,但是仍然对在页内的访问有比较好的性能。硬件预取是自动进行的,而软件预取则可以通过编译器自动或者自己在代码中加入预取指令。Intel编译器的/Qprefetch选项告诉编译器支持软件预取,要使用这个选项,需要和/O3一起使用,但是要注意,由于P4和Core
Duo处理器支持硬件预取,如果编译器特别针对这些处理器进行优化,则/Qprefetch不起作用。

除了通过编译器选项来使用软件预取之外,也可以通过prefectch directive来来告诉在访问某些内存时是否进行软件预取;

(1)#pragma noprefetch 指示编译器不进行软件预取

(2)#pragma prefetch 指示编译器进行软件预取

(3)#pragma prefetch a,b 指示编译器对于变量a,b的访问进行软件预取。

#pragma noprefetch b
#pragma prefetch a

for(i=0;i<m;ii++)
a[i] = b[i] + 1;


上面的循环中通过表达式a[j]访问数组,编译器会插入软件预取指令来把a[j+d]加载进缓存中,其中d由编译器分析后决定。

还可以通过SSE Intrinsics来支持软件预取,当然,这必须是在支持SSE扩展的处理器上才发挥作用;

void _mm_prefetch(char const *a,int sel);


它对应着 PREFETCH 指令,告诉处理器把地址 a 对应的缓存加载到更高速的缓存中,sel 给出了预取操作的类型,如下所示:

PREFETCHINTA _MM_HINT_NTA 采用非临时预取,减少缓存行的污染

PREFETCH0 _MM_HINT_T0 预取数据到所有缓存

PREFETCH1 _MM_HINT_T1 预取到L2,L3缓存,但是不到L1缓存

PREFETCH2 _MM_HINT_T2 仅预取数据到L3缓存

如果预取的数据仅仅使用一次,一般应该采用非临时预取,如果要进行写操作或者访问该缓存行多次,一般采用预取数据到所有缓存。

for(i=0;i<MAX;i+=512)
{
if((i&2047==0))
{
_mm_prefetch((char *)&arrar[i+2048],_MM_HNT_T0);
}
Func(&array[i]);
}


上面这个循环,由于步长太大,硬件自动预取无法有效工作。而通过软件预取则可以完成数据预取到缓存行的功能。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: