ChatGPT解决这个技术问题 Extra ChatGPT

x86中“非临时”内存访问的含义是什么

这是一个有点低级的问题。在 x86 汇编中有两条 SSE 指令:

MOVDQA xmmi, m128

MOVNTDQA xmmi, m128

IA-32 Software Developer's Manual 说 MOVNTDQA 中的 NT 代表 Non-Temporal,否则它与 MOVDQA 相同。

我的问题是,非时间是什么意思?

请注意,SSE4.1 MOVNTDQA xmmi, m128 是 NT 加载,而所有其他 NT 指令都是存储,除了 prefetchnta。这里接受的答案似乎只是在谈论商店。 This is what I've been able to turn up about NT loads。 TL:DR: 希望 CPU 对 NT 提示做一些有用的事情以最小化缓存污染,但它们不会覆盖“正常”WB 内存的强排序语义,因此它们必须使用缓存。
更新:NT 加载可能不会做任何有用的事情,除了在大多数 CPU(例如 Intel SnB 系列)上的 UCSW 内存区域。不过,NT/流媒体存储肯定可以在普通内存上工作。
@Peter:你的意思是 USWC 记忆对吗?我以前从未听说过 UCSW 或 USWC 内存。谷歌搜索错误的首字母缩写词没有帮助:-)
@AndrewBainbridge:是的,WC 内存类型属性。不可缓存的推测性写入组合。我想我在大写 UnCacheable 并记住它应该是 4 个字母长。 :P

E
Espo

非临时 SSE 指令(MOVNTI、MOVNTQ 等)不遵循正常的缓存一致性规则。因此,非临时存储必须后跟 SFENCE 指令,以便其他处理器及时看到它们的结果。

当数据产生而不(立即)再次消耗时,内存存储操作首先读取完整的缓存行然后修改缓存数据的事实对性能不利。此操作将可能再次需要的数据从缓存中推出,以支持不会很快使用的数据。对于大型数据结构尤其如此,例如矩阵,它们会被填充然后稍后使用。在填充矩阵的最后一个元素之前,绝对大小会驱逐第一个元素,从而使写入缓存无效。

对于这种情况和类似情况,处理器提供对非临时写操作的支持。在这种情况下,非临时性意味着数据不会很快被重用,因此没有理由缓存它。这些非临时写操作不会读取缓存行然后对其进行修改;相反,新内容直接写入内存。

来源:http://lwn.net/Articles/255364/


很好的答案,我只想指出,在具有 NT 指令的处理器上,即使是非临时指令(即普通指令),行高速缓存也不是“读取然后修改”的。对于写入不在高速缓存中的行的正常指令,在高速缓存中保留一行,并且掩码指示该行的哪些部分是最新的。该网页称其为“商店没有摊位”:ptlsim.org/Documentation/html/node30.html。我找不到更精确的参考资料,我只从那些负责实现处理器模拟器的人那里听说过。
实际上 ptlsim.org 是一个关于周期精确的处理器模拟器的网站,与那些告诉我“商店没有摊位”的人正在做的事情完全一样。我最好也提一下他们,以防他们看到这条评论:unisim.org
从这里的答案和评论stackoverflow.com/questions/44864033/…看来,可能不需要SFENCE。至少在同一个线程中。你也能看看吗?
@SergeRogatch 这取决于您在谈论什么场景,但是是的,在某些情况下,NT 商店需要 sfence,而普通商店永远不需要它。 NT 商店不是相对于其他商店(NT 与否)排序的,如其他线程所见,没有 sfence。但是,对于从执行存储的同一线程的读取,您永远不需要 sfence:给定线程将始终按程序顺序查看其自己的存储,无论它们是否是 NT 存储。
Therefore non-temporal stores must be followed by an SFENCE instruction in order for their results to be seen by other processors in a timely fashion. 我不知道为什么non-temporal stores must be followed by an SFENCE。那么 non-temporal stores 不允许内存重新排序?
P
Pramod

Espo 的目标几乎是爆炸式的。只是想加我的两分钱:

“非时间”短语意味着缺乏时间局部性。缓存利用两种局部性——空间性和时间性,并且通过使用非时间性指令,您向处理器发出信号,表明您不希望在不久的将来使用数据项。

我对使用缓存控制指令的手工编码程序集有点怀疑。根据我的经验,这些事情会导致比任何有效的性能提升更多的邪恶错误。


关于“使用缓存控制指令的手工编码程序集”的问题。我知道您明确说过“手动编码”诸如 JavaVM 之类的东西。这是一个更好的用例吗? JavaVM/编译器分析了程序的静态和动态行为,并使用了这些非临时指令。
不应回避利用问题域、算法或应用程序的已知位置属性(或缺乏)。避免缓存污染确实是一项非常有吸引力和有效的优化任务。另外,为什么厌恶组装?编译器无法利用的大量收益机会
一个知识渊博的低级程序员确实可以胜过小型内核的编译器。这对于发表论文和博文非常有用,我已经做到了。它们也是很好的教学工具,有助于理解“真正”发生的事情。但根据我的经验,在实践中,如果你有一个真正的系统,有许多程序员在使用它,并且正确性和可维护性很重要,那么低级编码的好处几乎总是被风险所抵消。
@Pramod,同样的论点很容易概括为一般的优化,并不真正在讨论的范围内——显然,考虑到我们已经在谈论非时间指令,权衡已经被考虑或被认为是无关紧要的
C
Community

根据 Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 1: Basic Architecture, "Programming with Intel Streaming SIMD Extensions (Intel SSE)" 章节:

缓存时间数据与非时间数据

程序引用的数据可以是临时的(数据将被再次使用)或非临时的(数据将被引用一次并且不会在不久的将来重用)。例如,程序代码通常是临时的,而多媒体数据,例如 3-D 图形应用程序中的显示列表,通常是非临时的。为了有效利用处理器的缓存,通常需要缓存临时数据而不是缓存非临时数据。用非临时数据重载处理器的缓存有时被称为“污染缓存”。 SSE 和 SSE2 可缓存性控制指令使程序能够以最小化缓存污染的方式将非临时数据写入内存。

非临时加载和存储指令的描述。资料来源:英特尔 64 和 IA-32 架构软件开发人员手册,第 2 卷:指令集参考

LOAD(MOVNTDQA—加载双四字非时间对齐提示)

如果内存源是 WC(写组合)内存类型 [...] [...] 处理器,则使用非临时提示将双四字从源操作数(第二个操作数)加载到目标操作数(第一个操作数)不会将数据读入缓存层次结构,也不会将相应的缓存行从内存中提取到缓存层次结构中。

请注意,正如 Peter Cordes 评论的那样,它在当前处理器上的普通 WB(回写)内存上没有用,因为 NT 提示被忽略(可能是因为没有 NT 感知硬件预取器)并且适用完整的强排序加载语义. prefetchnta 可用作 WB 内存的减少污染负载

STORE(MOVNTDQ - 使用非临时提示存储压缩整数)

使用非临时提示将源操作数(第二个操作数)中的压缩整数移动到目标操作数(第一个操作数),以防止在写入内存期间缓存数据。 [...] 处理器不会将数据写入缓存层次结构,也不会将相应的缓存行从内存中提取到缓存层次结构中。

使用 Cache Write Policies and Performance 中定义的术语,它们可以被认为是 write-around (no-write-allocate, no-fetch-on-write-miss)。

最后,回顾一下 John McAlpin notes about non-temporal stores 可能会很有趣。


SSE4.1 MOVNTDQA 只对 WC(不可缓存的写入组合)内存区域(例如视频 RAM)执行任何特殊操作。它在当前硬件上的普通 WB(回写)内存上根本没有用,NT 提示被忽略,并且应用了完整的强排序加载语义。不过,prefetchnta 作为 WB 内存的污染减少负载可能很有用。 Do current x86 architectures support non-temporal loads (from "normal" memory)?
没错,NT 存储在 WB 内存上工作正常,并且是弱排序的,通常是写入大内存区域的好选择。但 NT 负载不是。纸上的 x86 手册允许 NT 提示为从 WB 内存加载做一些事情,但在当前的 CPU 中它什么也不做。 (可能是因为没有支持 NT 的硬件预取器。)
我已将相关信息添加到答案中。非常感谢。
@LewisKelsey:NT stores 确实会覆盖内存类型。这就是为什么它们可以在 WB 内存上弱排序的原因。主要效果是避免 RFO(显然它们发送无效,甚至在到达内存时清除其他脏行)。它们也可以乱序可见,因此它们不必等到较早的缓存未命中(常规)存储提交之后,或者直到较早的缓存未命中 load 获取数据。即Is memory outside each core always conceptually flat/uniform/synchronous in a multiprocessor system?中所问的那种瓶颈。
@LewisKelsey:如果有必要,内存排序机器清除可能会在 UC 商店之后杀死不应该提前完成的任何负载。除此之外,直到商店从乱序后端退出后,提交顺序才会发挥作用。直到执行了存储地址 uop 之后才会发生这种情况,此时可以检查地址的内存类型。存储地址 uop 在执行时检查 TLB;这就是 CPU 在退役之前可以检测到故障存储的方式。它不能等到 SB 条目准备好提交到 L1d;那时执行已经过去了。