首页 > 解决方案 > 为什么 MASKMOVDQU 没有扩展到 256 位和 512 位存储?

问题描述

MASKMOVDQU 1在 x86 存储指令是特殊的,因为原则上,它允许您将单个字节存储在高速缓存行中,而无需先将整个高速缓存行一直加载到内核,以便写入的字节可以与未写入的字节合并-覆盖现有字节。

它似乎使用与 NT 存储相同的机制工作:在不先执行 RFO 的情况下将缓存行向下推。根据英特尔软件开发手册(强调我的):

MASKMOVQ 指令可用于提高需要逐字节合并数据的算法的性能。它不应该导致读取所有权;这样做会产生不必要的带宽,因为数据将直接使用字节掩码写入,而不在 store 之前分配旧数据

然而,与其他 NT 存储不同,您可以使用掩码来指定实际写入的字节。

如果您想在不太可能适合任何级别的缓存的大区域进行稀疏的字节粒度写入,那么这条指令似乎是个好主意。

与几乎所有其他有用的指令不同,英特尔没有将指令扩展到 AVX/AVX2 或 AVX-512 中的 256 或 512 位。这是否表明不再推荐使用该指令,可能无法在当前或未来的架构上有效实现?


1 ...及其在 MMX MASKMOVQ中的 64 位前身。

标签: cachingx86intelcpu-architecture

解决方案


MASKMOVDQU确实很慢,而且可能永远不是一个好主意,例如 Skylake 上每 6 个周期吞吐量 1 或 Zen2 / Zen3 上每 18c 一个。

我怀疑屏蔽 NT 向量存储不再适用于多核 CPU,因此,如果在完整的 64 字节行中有任何未修改的字节,即使是 128 位版本也可能只是在现代 x86 上进行屏蔽写入。

常规(不是 NT)掩码向量存储在 AVX512 中卷土重来。为此,似乎有效地支持了对 L1d 缓存的屏蔽提交,以及vmaskmovps/pd在英特尔 CPU 上使用 AVX1 和整数等效的 dword / qword 屏蔽。(虽然不是 AMD:AMD 仅具有有效的屏蔽 AVX1/2 负载,而不是存储 。https: //uops.info/table.html 在 Zen3 上显示VPMASKMOVD M256, YMM, YMM为 42 uops,12c 吞吐量,与 Zen2 大致相同。与 3 uops, Skylake 的延迟为 1c。在 AMD 上屏蔽负载很好,1 uop 0.5c 吞吐量,因此实际上比 AVX2 版本的 Skylake 更好。可能 Skylake 内部做了一个比较掩码并使用为 AVX-512 设计的硬件。)

AVX512F 使使用 dword/qword 粒度的掩码成为一等公民,对加载和存储都提供非常有效的支持。AVX512BW 增加了 8 位和 16 位元素大小,包括vmovdqu8在英特尔硬件上也有效支持的屏蔽加载/存储;单 uop 甚至适用于商店。


SDRAM 总线协议确实支持字节屏蔽写入(每个字节有 1 条屏蔽线作为高速缓存线突发传输的一部分)。 该英特尔文档(关于 FPGA 或其他内容)包括对DM(数据掩码)信号的讨论,确认 DDR4 仍然具有它们,其功能与 Wikipedia for SDRAM https://en.wikipedia.org/wiki上描述的 DQM 行相同/Synchronous_dynamic_random-access_memory#SDR_SDRAM。(DDR1 将其更改为仅写入掩码,而不是读取掩码。)

因此,硬件功能就在那里,例如,现代 x86 CPU 可能将其用于对不可缓存内存的单字节写入。

(更新:字节屏蔽可能在 DDR4 中是可选的,这与一些早期的 SDRAM / DDR 版本不同。在这种情况下,存储可以以屏蔽形式到达内存控制器,但内存控制器必须读取/修改/写入包含 8 字节块,对实际 DIMM 使用单独的突发读取和突发写入命令。对于仅影响部分 64 字节 DDR 突发大小的存储,可以将突发缩短,从而节省一些数据带宽,但仍然存在命令开销,并且在内存控制器中占用缓冲区空间的时间更长。)


如果我们写一个完整的行,那么无 RFO 存储非常好:我们只是使该行的其他副本无效并存储到内存中。

John “Dr. Bandwidth” McCalpin 说,在填充完整的 64 字节行后刷新的普通 NT 存储即使是脏的行也会无效,而不会导致脏数据的写回。

所以被屏蔽的 NT 存储需要使用不同的机制,因为任何被屏蔽的字节都需要从另一个内核的脏行中获取它们的值,而不是从 DRAM 中的任何内容中获取它们的值。

如果部分行 NT 存储的机制效率不高,那么添加创建它的新指令是不明智的。我不知道它是否比在生产线的一部分上进行普通商店更有效率,或者这是否取决于情况和 uarch。


它不必完全是 RFO,但这意味着当这样的存储到达内存控制器时,它必须获取 snoop 过滤器以确保行同步,或者可能与来自的旧内容合并在刷新到 DRAM 之前缓存。

或者 CPU 内核可以执行 RFO 并合并,然后将全行写入内存层次结构。

在回收尚未写入所有 64 字节的 LFB 时,CPU 确实需要某种机制来刷新部分行 NT 存储,而且我们知道这效率不高。(但我忘记了细节。)但也许这就是maskmovdqu现代 CPU 上的执行方式,无论是始终还是如果您不修改任何字节。

一个实验可能会发现。


所以 TL:DRmaskmovqdu可能只在单核 CPU 中有效实施。它起源于带有 MMX 的 Katmai Pentium III maskmovq mm0, mm1;SMP 系统存在,但在设计该指令时,它可能不是主要考虑因素。SMP 系统没有共享最后一级缓存,但它们在每个套接字上仍然有私有回写 L1d 缓存。


推荐阅读