x86 - 什么特别地将 x86 缓存行标记为脏 - 任何写入,还是需要显式更改?

标签 x86 x86-64 cpu-architecture cpu-cache memory-bandwidth

这个问题是具体针对现代 x86-64 缓存一致性架构 - 我很欣赏其他 CPU 上的答案可能会有所不同。
如果我写入内存,MESI 协议(protocol)要求先将缓存行读入缓存,然后在缓存中修改(将值写入缓存行,然后将其标记为脏)。在较旧的 write-though 微架构中,这将触发缓存行被刷新,在回写下,被刷新的缓存行可能会延迟一段时间,并且在两种机制下都可能发生一些写组合(更可能是写回) .而且我知道这如何与访问同一数据缓存行的其他内核交互 - 缓存监听等。
我的问题是,如果存储与缓存中已经存在的值完全匹配,如果没有翻转一个位,任何英特尔微架构是否会注意到这一点和 不是 将该行标记为脏,从而可能使该行免于被标记为独占,以及在某些时候会出现写回内存开销?
当我对更多循环进行矢量化时,我的矢量化操作组合原语不会显式检查值的变化,并且在 CPU/ALU 中这样做似乎很浪费,但我想知道底层缓存电路是否可以在没有显式编码的情况下做到这一点(例如存储微操作或缓存逻辑本身)。随着跨多个内核的共享内存带宽越来越成为资源瓶颈,这似乎是一个越来越有用的优化(例如,重复对同一内存缓冲区进行归零——如果它们已经从 RAM 中重新读取值,我们就不会重新读取它们)在缓存中,但强制写回相同的值似乎很浪费)。写回缓存本身就是对此类问题的一种认可。
我可以礼貌地要求保留“理论上”或“它真的没关系”的答案吗?我知道内存模型是如何工作的,我正在寻找的是关于如何编写相同值的确凿事实(而不是避免存储)将影响内存总线的争用,您可以放心地假设这是一台运行多个工作负载的机器,这些工作负载几乎总是受内存带宽的限制。另一方面,对芯片不这样做的确切原因的解释(我悲观地假设他们不这样做)将是有启发性的......
更新:这里有一些符合预期的答案https://softwareengineering.stackexchange.com/questions/302705/are-there-cpus-that-perform-this-possible-l1-cache-write-optimization但仍然有很多猜测“它一定很难,因为它没有完成”,并说在主 CPU 内核中这样做会很昂贵(但我仍然想知道为什么它不能成为实际缓存逻辑的一部分本身)。
更新(2020 年): Travis Downs 发现了硬件商店消除的证据,但似乎只针对零,并且仅在数据未命中 L1 和 L2 的情况下,即便如此,并非在所有情况下都如此。
强烈推荐他的文章,因为它更详细....
https://travisdowns.github.io/blog/2020/05/13/intel-zero-opt.html
更新(2021 年): Travis Downs 现在发现证据表明这种零存储优化最近已在微码中被禁用……更多细节来自源头本人
https://travisdowns.github.io/blog/2021/06/17/rip-zero-opt.html

最佳答案

我发现有证据表明,英特尔的一些现代 x86 CPU,包括 Skylake 和 Ice Lake 客户端芯片,可以在至少一种特定情况下优化冗余(静默)存储:

  • 全零高速缓存行被更多零完全或部分覆盖。

  • 也就是说,“零对零”的场景。
    例如,此图表显示了在 Ice Lake 上使用 0 或 1 的 32 位值归档的情况下的性能(圆圈,在左轴上测量)和相关性能计数器:
    Ice Lake Fill Performance
    一旦该区域不再适合 L2 缓存,写入零就有一个明显的优势:填充吞吐量几乎提高了 1.5 倍。在零的情况下,我们还看到来自 L2 的驱逐几乎都不是“静默”的,这表明不需要写出脏数据,而在另一种情况下,所有驱逐都是非静默的。
    有关此优化的一些杂项细节:
  • 它优化了脏缓存行的回写,而不是仍然需要发生的 RFO(实际上,可能需要读取来决定可以应用优化)。
  • 它似乎发生在 L2 或 L2 <-> L3 接口(interface)周围。也就是说,对于适合 L1 或 L2 的负载,我没有找到这种优化的证据。
  • 因为优化在缓存层次结构的最内层之外的某个点生效,所以不必只写零来利用:仅当行写回 L3 时才包含全零就足够了。因此,从全零行开始,您可以执行任意数量的非零写入,然后是整个 line1 的最终零写入,只要该行在此期间不逃逸到 L3。
  • 优化具有不同的性能影响:有时优化是基于对相关性能计数的观察进行的,但几乎没有增加吞吐量。其他时候影响可能非常大。
  • 我没有在 Skylake 服务器或更早的英特尔芯片中找到效果的证据。

  • 我写的更详细here ,并且有一个关于冰湖的附录,它更强烈地表现出这种效果here .
    2021 年 6 月更新:出于安全原因 (details),英特尔提供的最新 CPU 微码版本已禁用此优化。

    1 或者,至少用零覆盖行的非零部分。

    关于x86 - 什么特别地将 x86 缓存行标记为脏 - 任何写入,还是需要显式更改?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47417481/

    相关文章:

    x86 ASM : DD Being Used as an "Instruction"?

    c - 使用 rdmsr/rdpmc 提高分支预测精度

    c - 调用 glibc 时的 x86-64 ELF 初始堆栈布局

    c - GCC汇编代码在64位机器上显示32位寄存器

    x86 - 为什么 IRET 指令会将 EIP 加 4?

    assembly - 为什么80x87指令集采用 "stack-based"设计?

    cpu-architecture - 本地 CPU 可能会降低远程 CPU 的数据包接收性能

    c - 函数调用是否与 %rax 以外的其他寄存器混淆?

    汇编 (x86) 和进程切换的 C 回调函数

    c - 汇编指令阅读,leaq