【问题标题】:What is the meaning of "non temporal" memory accesses in x86x86中“非临时”内存访问的含义是什么
【发布时间】:2010-09-07 09:57:45
【问题描述】:

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

MOVDQA <i><em>xmmi, m128</em></i>

MOVNTDQA <i><em>xmmi, m128</em></i>

IA-32 软件开发人员手册说 MOVNTDQA 中的 NT 代表 Non-Temporal,否则与 MOVDQA 相同。

我的问题是,Non-Temporal 是什么意思?

【问题讨论】:

  • 请注意,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 loads 除了在大多数 CPU(例如 Intel SnB 系列)上的 UCSW 内存区域外,可能不会做任何有用的事情。不过,NT/流媒体存储肯定可以在正常内存上工作。
  • @Peter:你是说 USWC 内存吧?我以前从未听说过 UCSW 或 USWC 内存。谷歌搜索错误的首字母缩写词没有帮助:-)
  • @AndrewBainbridge:是的,WC 内存类型属性。不可缓存的推测性写入组合。我想我在大写 UnCacheable 并记住它应该是 4 个字母长。 :P

标签: x86 sse assembly


【解决方案1】:

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

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

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

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

【讨论】:

  • 不错的答案,我只想指出,在具有 NT 指令的处理器上,即使是非非临时指令(即普通指令),行高速缓存也不是“阅读然后修改”。对于写入不在高速缓存中的行的正常指令,在高速缓存中保留一行,并且掩码指示该行的哪些部分是最新的。该网页称其为“商店没有摊位”:ptlsim.org/Documentation/html/node30.html。我找不到更准确的参考资料,我只是从从事处理器模拟器工作的人那里听说过。
  • 实际上ptlsim.org 是一个关于周期精确处理器模拟器的网站,与那些告诉我“商店没有停顿”的人正在做的事情完全一样。我最好也提一下他们,以防他们看到这条评论:unisim.org
  • stackoverflow.com/questions/44864033/…这里的答案和cmets看来SFENCE可能不需要。至少在同一个线程中。你也看看吗?
  • @SergeRogatch 这取决于您在谈论什么场景,但是在某些场景中,NT 商店需要sfence,而普通商店从来不需要它。没有sfence如其他线程所见,不针对其他商店(NT 与否)对 NT 商店进行排序。但是,对于从执行存储的同一线程的读取,您永远不需要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 不允许内存重新排序?
【解决方案2】:

Espo 非常符合目标。只是想加我两分钱:

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

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

【讨论】:

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

根据英特尔® 64 和 IA-32 架构软件开发人员手册,第 1 卷:基本架构, “使用英特尔流 SIMD 扩展(英特尔 SSE)进行编程”一章:

时态数据与非时态数据的缓存

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

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

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

如果内存源是 WC(写入组合)内存类型,则使用非临时提示将双四字从源操作数(第二个操作数)加载到目标操作数(第一个操作数)[...]

[...] 处理器不会将数据读入缓存层次结构,也不会将相应的缓存行从内存中提取到缓存层次结构中。

请注意,正如 Peter Cordes cmets 一样,它在当前处理器上的普通 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(不可缓存的写入组合)内存区域上执行任何特殊操作,例如视频内存。它在当前硬件上的普通 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;那时执行已经过去了。
猜你喜欢
  • 2018-06-22
  • 2017-05-02
  • 1970-01-01
  • 1970-01-01
  • 2017-02-27
  • 2012-09-11
  • 1970-01-01
  • 2016-02-26
  • 2019-04-04
相关资源
最近更新 更多