作者:in冷霜天 | 来源:互联网 | 2023-02-03 17:56
在x64上,如果您首先在短时间内在先前未缓存的地址上写入完整缓存行的内容,然后在再次从该地址读取后不久,CPU是否可以避免必须从内存读取该地址的旧内容?
同样有效的是,先前的内存内容并不重要,因为全部高速缓存行中的数据已被完全覆盖?我可以理解,如果这是对未缓存地址的部分缓存行写入,然后是读取,则将产生必须与主内存等同步的开销。
从文档方面看,写分配,写合并和监听使我对此事有些困惑。目前,我认为x64 CPU无法做到这一点?
1> BeeOnRope..:
通常,后续读取应该很快-只要存储到装载转发能够工作。实际上,它根本与写入整个缓存行无关:即使对于较小的写入,它也应该工作(具有相同的警告)!
基本上,在正常(即WB内存区域)映射的内存上发生的事情是,存储将向CPU 的存储缓冲区添加多个条目。由于关联的内存当前未缓存,因此这些条目将保留一段时间,因为将发生RFO请求,以将该行拉入缓存以进行写入。
同时,您发出了一些针对刚刚写入的相同内存的负载,并且通常由存储到负载转发来满足这些负载,这几乎只是注意到存储已经在相同地址和使用的存储缓冲区中它是加载的结果,而无需进入内存。
现在,商店转发并不总是有效。特别是,当负载仅部分重叠最近涉及的存储时,它将永远无法在任何Intel(或可能是AMD)CPU上运行。也就是说,如果您向地址10写入4个字节,然后从地址9读取4个字节,则只有3个字节来自该写入,而9处的字节必须来自其他地方。在这种情况下,所有Intel CPU只需等待所有涉及的存储区被写入,然后解决负载。
过去,还有许多其他情况也会失败,例如,如果您发布了一个较小的读取,而该读取已完全包含在较早的存储中,则该读取通常会失败。例如,给定地址10的4字节写入,从地址12的2字节读取完全包含在较早的写入中-但由于硬件不够复杂,无法检测到这种情况,因此通常不转发。
但是,最近的趋势是,除了上面提到的“未完全包含读取”的情况以外,所有情况都可以在现代CPU上成功转发。血腥的细节在stuffedcow上有很多漂亮的图片,而且Agner在他的微体系结构指南中也很好地涵盖了细节。
在上面的链接文档中,这是Agner关于Skylake上的商店转发的评价:
在某些情况下,Skylake处理器可以将内存写入转发给来自同一地址的后续读取。存储转发比以前的处理器快一个时钟周期。对于32或64位的操作数,在最佳情况下,写存储器后再从同一地址进行读取需要4个时钟周期,而对于其他操作数大小,则需要5个时钟周期。
当128或256位的操作数未对齐时,存储转发将增加多达3个时钟周期的损失。
当任何大小的操作数越过高速缓存行边界(即可被64字节整除的地址)时,存储转发通常会额外花费4-5个时钟周期。
写入后再从相同地址进行较小的读取几乎不会造成任何损失。
当读偏移量但完全包含在写所覆盖的地址范围内时,写64位或更少的位,然后进行较小的读,将产生1-3个时钟的损失。
对齐写入128或256位,然后读取两个半部或四个四分之一等中的一个或两个,等等,几乎没有损失。不适合两半或四分之一的部分读取可能会额外花费11个时钟周期。
大于写入的读取,或覆盖写入和未写入字节的读取,大约需要11个时钟周期。
最后一种情况是读大于写,这肯定是商店转发停止的情况。11个周期的报价可能适用于所有涉及的字节都在L1中的情况-但是某些字节根本没有缓存(在您的情况下)的情况当然可以采取DRAM未命中的顺序,这可以是数百个周期。
最后,请注意,上述所有内容都与写入整个缓存行无关-如果先写入1个字节然后读取相同的字节,而保持缓存行中的其他63个字节不变,它的工作原理也一样。
还有就是类似于你提什么以饱满的高速缓存行的效果,但它所处理的写结合写,这些都可以或者通过标记内存为写结合(而不是通常的回写)或使用非临时存储指令。NT指令的主要目标是写入不会很快被后续读取的内存,从而跳过了RFO开销,并且可能不会转发给后续加载。