Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;如何强制预取数据到缓存?(数组循环)_C++_Cpu Cache_Prefetch - Fatal编程技术网

C++ C++;如何强制预取数据到缓存?(数组循环)

C++ C++;如何强制预取数据到缓存?(数组循环),c++,cpu-cache,prefetch,C++,Cpu Cache,Prefetch,我有一个这样的循环 start = __rdtsc(); unsigned long long count = 0; for(int i = 0; i < N; i++) for(int j = 0; j < M; j++) count += tab[i][j]; stop = __rdtsc(); time = (stop - start) * 1/3; start=u rdtsc(); 无符号长计数=0; 对于(int i=0;i

我有一个这样的循环

start = __rdtsc();
unsigned long long count = 0;
for(int i = 0; i < N; i++)
    for(int j = 0; j < M; j++)
        count += tab[i][j];
stop = __rdtsc();
time = (stop - start) * 1/3;
start=u rdtsc();
无符号长计数=0;
对于(int i=0;i
需要检查预取数据对效率的影响。如何在计算某些值之前将其从内存强制预取到缓存中?

仅适用于GCC:

__builtin_prefetch((const void*)(prefetch_address),0,0);

预取地址可能无效,不会出现SEGFULT。如果
预取_地址
和当前位置之间的差异太小,则可能不会产生任何影响,甚至会减速。试着把它至少提前1公里

最简单/最可移植的方法是只需每隔缓存线字节读取一些数据。假设tab是一个合适的二维数组,您可以:

char *tptr = (char *)&tab[0][0];
tptr += 64;
char temp;
volatile char keep_temp_alive;
for(int i = 0; i < N; i++)
{
    temp += *tptr;
    tptr += 64;
    for(j = 0; j < M; j++)
        count += tab[i][j];
}
keep_temp_alive = temp;
char*tptr=(char*)&tab[0][0];
tptr+=64;
焦炭温度;
挥发性炭使温度保持活力;
对于(int i=0;i
差不多吧。然而,这取决于: 1.您不会在分配的内存之外读取(太多)。 2.J循环并没有比64字节大多少。如果是,您可能需要添加更多步骤
temp+=*tptr;tptr+=64

循环后的
保持\u temp\u处于活动状态
对于防止编译器将temp作为不必要的负载完全删除至关重要


不幸的是,我写泛型代码太慢了,无法推荐内置指令,关键在于Leonid

首先,我假设
tab
是一个大的2D数组,例如静态数组(例如
int-tab[1024*1024][1024*1024]
)或动态分配的数组(例如
int**tab
和后面的
malloc
s)。这里,您希望将一些数据从
选项卡
预取到缓存,以减少执行时间

简单地说,我认为您不需要手动将任何预取插入到代码中,在代码中对2D数组执行简单的缩减。如果有必要并且有利可图,现代CPU将进行自动预取


对于这个问题,您应该知道两个事实:

(1) 您已经在利用最内层循环中的
选项卡
的空间位置。读取
tab[i][0]
后(在缓存未命中或页面错误后),从
tab[i][0]
tab[i][15]
的数据将位于CPU缓存中,假设缓存线大小为64字节

(2) 但是,当代码在行中遍历时,即
tab[i][M-1]
tab[i+1][0]
,很可能发生冷缓存未命中,特别是当
tab
是一个动态分配的数组,其中每一行都可以以碎片方式分配时。但是,如果数组是静态分配的,则每一行都将连续地位于内存中


因此,只有在提前读取(1)下一行的第一项和(2)
j+CACHE\u LINE\u SIZE/sizeof(tab[0][0])
时,预取才有意义

您可以通过在上部循环中插入预取操作(例如,
\u内置预取
)来完成此操作。然而,现代编译器可能并不总是发出这样的预取指令。如果你真的想这样做,你应该检查生成的二进制代码

但是,正如我所说的,我不建议您这样做,因为现代CPU大多会自动执行预取,而自动预取的性能通常会优于手动代码。例如,对于像常春藤桥处理器这样的英特尔CPU,有多个数据预取器,如对一级、二级或三级缓存的预取。(但我不认为移动处理器有一个奇特的数据预取器)。某些预取器将加载相邻的缓存线



如果在大型2D阵列上执行更昂贵的计算,则有许多对缓存更友好的替代算法。一个显著的例子是分块(有标题的)矩阵乘法。朴素的矩阵乘法会遭受大量缓存未命中,但阻塞算法通过计算适合缓存的小子集,显著减少了缓存未命中。请参阅一些参考资料,如。

内置预取指令非常有用,但它是特定于clang/gcc的。如果您要编译多个编译器目标,我很幸运地将x86内部
\u mm_prefetch
与clang和MSVC一起使用


只需检查您的档案器即可。如果切换for循环,缓存可能会更糟糕。大多数现代CPU都可以自动处理预取。只有在不明显的情况下,你才应该发布自己的指示。另外,预取指令也不是完全可移植的;每个编译器都有自己的内部函数。您所做的是流处理。我有充分的理由相信,在单个缓存线中求和数据所需的时间比从主内存中填充数据所需的时间要少,而且实际上您受到可用内存带宽的限制。我不知道预取(手动或自动)如何提高效率。