次级cacheline预取的成本

Cost of a sub-optimal cacheline prefetch

本文关键字:预取 cacheline 次级      更新时间:2023-10-16

__builtin_prefetch(..., 1) intinsic完成的晚期预取的成本是多少(准备写的准备)?也就是说,在需求加载或需要写入之前,预摘要不会到达L1缓存?

例如

void foo(std::uint8_t* line) {
    __builtin_prefetch(line + std::hardware_constructive_interference_size, 1);
    auto next_line = calculate_address_of_next_line(line);
    auto result = transform(line);
    write(next_line, result)
}

在这种情况下,如果transform的成本低于预取的成本,那么该代码最终会比没有预取的效率低吗?Wikipedia关于缓存预取的文章谈论了A For A循环的最佳步伐,但在这种情况下没有提及亚次优先取回的影响(例如,如果K太低,会发生什么?)。

这是否足够管道,以至于次优的预摘要无关紧要?出于这个问题的目的,我只考虑Intel X86(也许是Broadwell时期的处理器)。

让我们调用您所引用的预取的类型行以完全隐藏缓存失误的延迟。这与A 相反,预摘要过于预摘要,在距离访问之前,预摘要远离需求访问,至少在访问访问之前被驱逐出来。

与完全不进行预取相比,这种晚期预取的成本很可能很小,零或负数。

让我们专注于负面部分:即,即使迟到了,预摘要也有所帮助。如果我正确理解您的问题,您会考虑需要在需要"错过"或无效的负载之前到达的预购。但是,情况并非如此:一旦预摘要请求开始,时钟就会开始滴定以完成内存访问,并且如果需求负载发生在完成之前,则该工作不会丢失。例如,如果您的内存访问需要100 ns,但是在预摘要之后仅出现需求访问,则预摘要为"太晚",因为整个100 ns延迟并不隐藏,但20 ns在预取仍然有用:它将需求访问延迟减少到约80 ns。

也就是说,晚期预摘要不是二进制条件:它范围较晚(例如,预摘要在访问延迟之前发行的90 ns或100 ns)或真的很晚(几乎在消费访问之前)。在大多数情况下,甚至相当晚期的预摘要可能会有所帮助,假设记忆潜伏期首先是您的算法的瓶颈。

费用

现在考虑一下完全无用的预取(即在访问之前发行的,因此如果不存在预购,就可以将访问权限得出) - 费用是多少?在大多数现实的情况下,成本可能很小:处理的额外指导,对琼斯的额外压力,以及与随后的访问与机上的预求匹配 2 。

由于该假设是由于错过了缓存或DRAM的外部级别而采用预摘要,并且transform功能中的工作足以隐藏某些延迟,这一附加指令的相对成本是可能很小。

当然,这全都是假设附加的预摘要是一项指令。在某些情况下,您可能不得不在某种程度上组织您的代码,以允许预摘要或执行一些重复的计算,以便在适当的位置进行预取。在这种情况下,成本方面可能相应地更高。

m和e状态

最后,关于写入访问和以写意的预摘要还有另一种行为,这意味着在某些情况下,即使是完全无用的预取(即,在第一个访问之前,在第一个访问之前)很有用 - 当第一个访问是一个访问权限时阅读。

如果首先读取给定的行,则以后书面,核心可能会在E(Xclusive)连贯状态中获取行,然后首先需要将另一个往返往返以某种级别的缓存以将其获取以将其获取M州。在第一次访问之前,请在第一次访问之前使用书面图的预取,因为第一次将与M状态一起使用该行。这种优化的效果通常很难量化,这通常是因为写入通常是缓冲的,并且不构成依赖链的一部分(在商店转发之外)。


2 我在这里使用故意含糊的术语"浪费的努力",因为这尚不清楚这是否具有性能或电源成本,或者只是一些额外的工作,而这些工作并不添加操作延迟。一种可能的成本是,触发初始L1失误的负载具有特殊的状态,并且可以在无需再往返L1的情况下获得其结果。在预取的情况下,立即进行负载,负载可能无法获得特殊状态,这可能会稍微增加成本。但是,这个问题是关于商店不加载的。