SIMD 内在和内存总线大小 - CPU 如何在单个内存读取中获取所有 128/256 位?
Posted
技术标签:
【中文标题】SIMD 内在和内存总线大小 - CPU 如何在单个内存读取中获取所有 128/256 位?【英文标题】:SIMD intrinsic and memory bus size - How CPU fetches all 128/256 bits in a single memory read? 【发布时间】:2018-05-10 18:51:36 【问题描述】:你好论坛 - 我有一些关于 SIMD 内在函数的类似/相关问题,我在网上搜索了这些问题,包括 ***,但没有找到好的答案,因此请求您的帮助。
基本上,我试图了解 64 位 CPU 如何在一次读取中获取所有 128 位,以及这种操作的要求是什么。
-
CPU 会在一次内存操作中从内存中获取所有 128 位,还是会执行两次 64 位读取?
CPU 制造商是否需要特定大小的内存总线,例如,对于 64 位 CPU,英特尔是否需要 128 位总线来进行 SSE 内存绑定操作?
这些操作是否取决于内存总线大小、通道数和内存模块数?
【问题讨论】:
【参考方案1】:加载/存储不会直接进入内存(除非您在不可缓存的内存区域上使用它们)。甚至 NT 存储也进入写入组合填充缓冲区。
加载/存储在执行单元和 L1D 缓存之间进行。 CPU 内部具有从缓存到执行单元以及从 L1D 到外部缓存的宽数据路径。请参阅electronics.SE 上的How can cache be that fast?,了解英特尔IvyBridge。
例如IvB 在执行单元和 L1D 之间有 128b 的数据路径。 Haswell 将其扩大到 256 位。只要不跨越缓存线边界,未对齐的加载/存储就具有完整的性能。 Skylake-AVX512 将其扩展到 512 位,因此它可以在单个时钟周期内执行 2 个 64 字节加载和 64 字节存储。 (只要数据在 L1D 缓存中是热的)。
包括 Ryzen 在内的 AMD CPU 在 128b 块中处理 256b 向量(即使在执行单元中,与 Pentium M 之后的 Intel 不同)。较旧的 CPU(例如 Pentium III 和 Pentium-M)将 128b 加载/存储(和向量 ALU)分成两半 64 位,因为它们的加载/存储执行单元只有 64 位宽。
内存控制器为 DDR2/3/4。总线为 64 位宽,但使用突发模式,突发大小为 64 字节(并非巧合,缓存线的大小。)
作为“64 位”CPU 与任何内部或外部数据总线的宽度无关。该术语过去确实用于其他 CPU,但即使是 P5 Pentium 也有 64 位数据总线。 (aligned 8-byte load/store is guaranteed atomic as far back as P5, e.g. x87 or MMX.) this 中的 64 位是指指针和整数寄存器的宽度。
进一步阅读:
What Every Programmer Should Know About Memory(但请注意,许多软件预取的东西已经过时,现代 CPU 的硬件预取器比 Pentium4 更好)。仍然是必不可少的阅读材料,尤其是如果您想了解 CPU 是如何连接到 DDR2/3/4 内存的。
x86 tag wiki中的其他性能链接。
Enhanced REP MOVSB for memcpy 了解有关 x86 内存带宽的更多信息。请特别注意,单线程带宽可能受到 max_concurrency / 延迟的限制,而不是 DRAM 控制器的限制,尤其是在多核 Xeon 上(L3 / 内存的延迟更高)。
【讨论】:
Ice Lake 应该添加一个“Fast Short REP MOV”——不管它是什么意思。 @Mysticial:很好!据推测,向量循环优于rep movsb
的收支平衡阈值将低于 Skylake(对齐指针可能为 128 或 256 字节)。
@PeterCordes - 感谢您的详细回答和指示,我有一个后续问题:如果总线是 64 位宽,那么为什么数据应该对齐 16 字节边界,为什么不对齐 8 字节?
@ForumMember - 因为彼得提到没有单一的“公共汽车”。至少在现代 CPU 上,内存路径的早期部分是 256 或 128 位宽。除此之外,还有许多超出总线宽度的对齐问题。 @Peter - 关于您的评论,是否有任何阈值高于/低于rep movsb
比矢量循环快?我的印象是,显式代码在各种规模下都更快,尤其是在 Skylake 和最近几代(尽管您的代码需要 NT 存储以实现大尺寸)。您的评论似乎暗示 rep movsb
对于较大的循环可以更快?
@BeeOnRope:我认为rep movsb
至少值得使用,一旦考虑到 I-cache 对程序其余部分的影响。我认为 glibc 在某些 CPU 上将它用于足够大的副本。它当然有一个代码路径,但我忘记了它是否真的被设置为使用它。 (顺便说一句,在 Haswell/Skylake Pentium/Celeron 上,AVX 不可用,但 rep movsb
可能仍然是 32 字节,所以它比最小尺寸更胜一筹。)以上是关于SIMD 内在和内存总线大小 - CPU 如何在单个内存读取中获取所有 128/256 位?的主要内容,如果未能解决你的问题,请参考以下文章
有没有一种有效的方法来使用 SIMD 内在函数来获取 SIMD 寄存器中的第一个非零元素?
Cython 和 SIMD 内在函数:防止 SIMD 内在函数的参数转换为 python 对象