caching - 为什么 MASKMOVDQU 没有扩展到 256 位和 512 位存储?

标签 caching x86 intel cpu-architecture

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

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

The MASKMOVQ instruction can be used to improve performance for algorithms that need to merge data on a byteby-byte basis. It should not cause a read for ownership; doing so generates unnecessary bandwidth since data is to be written directly using the byte-mask without allocating old data prior to the store.



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

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

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

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

最佳答案

MASKMOVDQU确实很慢,而且可能永远不是一个好主意,例如 Skylake 每 6 个周期吞吐量 1 个或 Zen2/Zen3 每 18c 一个。
我怀疑掩码 NT 向量存储不再适用于多核 CPU,因此,如果完整的 64 字节行中有任何未修改的字节,那么即使是 128 位版本也可能在现代 x86 上进行掩码写入。
常规(不是 NT)掩码矢量存储在 AVX512 中大受欢迎。似乎可以有效地支持对 L1d 缓存的掩码提交,并且对于使用 AVX1 的 dword/qword 掩码 vmaskmovps/pd和 Intel CPU 上的整数等价物。 (虽然不是 AMD:AMD 只有有效的屏蔽 AVX1/2 加载,而不是存储。https://uops.info/table.html 显示 Zen3 上的 VPMASKMOVD M256, YMM, YMM 是 42 uops,12c 吞吐量,与 Zen2 大致相同。对比 Skylake 上的 3 uops,1c 延迟。掩码负载在 AMD 上很好,1 uop 0.5c 吞吐量,所以实际上比 AVX2 版本的 Skylake 更好。可能 Skylake 在内部做了一个比较掩码并使用为 AVX-512 设计的硬件。)
AVX512F 使具有 dword/qword 粒度的掩码成为一等公民,对加载和存储都提供非常有效的支持。 AVX512BW 添加了 8 位和 16 位元素大小,包括屏蔽加载/存储,如 vmovdqu8 英特尔硬件也有效支持;单 uop 甚至商店。

SDRAM 总线协议(protocol)确实支持字节屏蔽写入(每字节 1 个屏蔽线作为缓存线突发传输的一部分)。 This Intel doc (关于 FPGA 或其他内容)包括对 DM 的讨论(数据掩码)信号,确认 DDR4 仍然具有它们,其功能与维基百科上描述的 SDRAM 的 DQM 线相同 https://en.wikipedia.org/wiki/Synchronous_dynamic_random-access_memory#SDR_SDRAM . (DDR1 将其更改为仅写掩码,而不是读掩码。)
因此,硬件功能就在那里,例如,大概现代 x86 CPU 使用它来对不可缓存的内存进行单字节写入。
(更新:字节屏蔽 may 只有 optional in DDR4 ,与一些早期的 SDRAM/DDR 版本不同。在这种情况下,存储可以以屏蔽形式到达内存 Controller ,但内存 Controller 必须读取/修改/使用单独的突发读取和突发写入命令将包含的 8 字节块写入实际的 DIMM。对于仅影响 64 字节 DDR 突发大小的一部分的存储,可以将突发缩短,从而节省一些数据带宽,但仍然存在命令开销并在内存 Controller 中占用更长的缓冲区空间。)

如果我们写一个完整的行 无 RFO 商店很棒:我们只是使该行的其他副本无效并存储到内存中。
John "Dr. Bandwidth" McCalpin says正常的 NT 存储在填充完整的 64 字节行后刷新 甚至会使脏的行无效,而不会导致脏数据的写回。
所以被屏蔽的 NT 存储需要使用不同的机制,因为任何被屏蔽的字节都需要从另一个内核的脏行中获取它们的值,而不是从 DRAM 中的任何内容中获取。
如果部分行 NT 存储的机制效率不高 ,添加创建它的新指令是不明智的。我不知道它是否比对生产线的一部分进行普通商店效率更高或更低,或者这是否取决于情况和 uarch。

它不必完全是一个 RFO,但这意味着当这样的存储到达内存 Controller 时,它必须获得监听过滤器以确保行同步,或者可能与来自的旧内容合并在刷新到 DRAM 之前缓存。
或者 CPU 内核可以在发送全行记下之前执行 RFO 和合并
内存层次结构。
在回收尚未写入所有 64 字节的 LFB 时,CPU 确实需要某种机制来刷新部分行 NT 存储,我们知道这效率不高。 (但我忘记了细节。)但也许这就是 maskmovdqu总是在现代 CPU 上执行,或者如果您保留任何未修改的字节。
一个实验可能会发现。

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

关于caching - 为什么 MASKMOVDQU 没有扩展到 256 位和 512 位存储?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54931225/

相关文章:

c - 从C/C++程序执行二进制(INTEL FSP)文件的最简单方法

python-3.x - 输出文件为空,在Docker容器中的ubuntu16.04中未进行任何编码(检查-ss/-t/-frames参数(如果使用))

java - 是否可以使用 JAX-RS 设置 ETag 而无需求助于 Response 对象?

linux - 是否可以在 64 位 Linux 的同一个可执行文件中同时使用 64 位和 32 位指令?

c# - LINQ To SQL 忽略唯一约束异常并继续

c++ - 上证所该向上舍入时向下舍入

x86 - 使用 iret 切换到用户模式

windows - 全局描述符表

sql-server - Redis缓存及整体流程

java - 多键值对搜索