为什么__builtin_prefetch在这里没有任何效果

Why doesn’t __builtin_prefetch have any effect here?

本文关键字:任何效 在这里 builtin prefetch 为什么      更新时间:2023-10-16

我正在编写一个解析文件的程序。它由一个主循环组成,该循环逐字符解析并处理它们。这是主循环:

char c;
char * ptr;
for( size_t i = 0; i < size ; ++i )
{
ptr = ( static_cast<char*>(sentenceMap) + i );
c = *ptr;
__builtin_prefetch( ptr + i + 1 );
// some treatment on ptr and c   
}

正如您所看到的,我添加了一条builtin_prefetch指令,希望在循环的下一次迭代中放入缓存。我尝试了不同的值:ptr+i+1ptr+i+2ptr+i+10,但似乎什么都没有改变。

为了衡量性能,我使用valgrind的工具cachegrind,它可以指示缓存未命中的数量。在线路c = *ptr上,当未设置__builtin_prefetch时,cachegrind记录632378 DLmr(L3高速缓存未命中)。然而,奇怪的是,不管我将参数设置为__builtin_prefetch,这个值都不会改变。

对此有什么解释吗?

这是因为硬件比您领先几年。:)

有一些硬件预取器设计用于识别简单模式并为您进行预取。在这种情况下,您有一个简单的顺序访问模式,这对于硬件预取器来说是微不足道的。

只有当硬件无法预测访问模式时,手动预取才会派上用场。

这里有一个这样的例子:预取示例?

首先,缓存处理的最小单元被称为cache line,缓存行可以是64字节长,但永远不会像1字节那么小。因此,当你要求预取时,你需要在你当前感兴趣的位置之前问很多。您需要知道缓存行的大小,所以不应该询问位于同一缓存行中的地址。您还需要不要多次调用预取,因为这也可能会收回即将使用的缓存线,并在执行指令时产生性能命中。

现代架构也有硬件预取器的概念,它可以根据您的访问模式提前为您预取数据。这应该是大部分时间创建的数据访问时间与您的简单预取一样好。如今,软件预取只能帮助你,如果你能找到一个如此明显的地方来预取数据,而不是在代码中随机扩展。例如,在开始处理一段数据之前,但如果您只是调用预取并立即访问数据,这对您没有帮助。您需要尽早完成此操作,并在访问数据之前进行其他设置工作。

我建议任何对这个话题感兴趣的人阅读《软件优化食谱》。我通常处理ARM体系结构,但我发现这本书非常宝贵。网上也有一些与这个问题有关的摘录;参见#1和#2。

正确的答案是:预取不能改变缓存未命中的数量,它只是迫使它们更早发生:)