关于缓存:Write-combining:避免在写入之前读取哪个缓存行?

Write-combining: which cache line is avoided to be read before written?

关于非时间写入和写入组合技术,我有以下代码

1
2
3
4
5
6
7
8
9
10
11
void setbytes(char *p, int c)
{
__m128i i = _mm_set_epi8(c, c, c, c,
c, c, c, c,
c, c, c, c,
c, c, c, c);
_mm_stream_si128((__m128i *)&p[0], i);
_mm_stream_si128((__m128i *)&p[16], i);
_mm_stream_si128((__m128i *)&p[32], i);
_mm_stream_si128((__m128i *)&p[48], i);
}

取自这里

据说

To summarize, this code sequence not only avoids reading the cache
line before it is written, it also avoids polluting the cache with
data which might not be needed soon. This can have huge benefits in
certain situations.

我的问题是:避免写入哪个缓存行?存储 i 变量内容的缓存行或 p 指针指向的缓存行(之后会被修改)?


about: "避免在写入之前读取缓存行"

该语句指的是用于处理未命中缓存的写入的\\'写入分配\\' 策略。所有现代 x86 处理器都这样做。它是这样的:软件使用普通的 mov 指令写入内存。如果该地址已被缓存,则缓存被更新并且根本没有 DRAM 访问。但是,如果数据不在缓存中,则处理器从 DRAM 中读取该缓存行。然后将来自 mov 指令的数据合并到缓存中的数据中。处理器将尽可能推迟将该数据写回 DRAM。最终结果是违反直觉的:软件执行写入 (mov) 指令,结果是单个 DRAM 读取 (突发)。如果这种模式重复,缓存最终会变满,需要驱逐来为读取腾出空间。在这种情况下,将有一个不相关的缓存行地址的 DRAM 写入突发,然后是读取软件正在写入的地址。这解释了为什么非临时存储在填充大缓冲区时提供大约 2 倍的性能。与使用 mov 填充缓冲区相比,仅发生一半的 DRAM 访问。


如果目标地址不在缓存中,流式传输可防止缓存污染,否则它只会根据需要使用写入该缓存行支持的地址的新值更新缓存。

所以在你的例子中,如果你没有从 p 读取(或者你已经用 CLFLUSH 从缓存中刷新了它),流存储将阻止数据被写入 p 指向的位置被加载到p 指向的地址的缓存(即:不会为写入的地址创建缓存线)。