x86中"非暂时"内存访问的含义是什么?

Nat*_*man 111 x86 assembly sse

这是一个有点低级别的问题.在x86程序集中有两个SSE指令:

MOVDQA xmmi, m128

MOVNTDQA xmmi, m128

IA-32软件开发人员手册说MOVNTDQA 中的NT代表非时间性,否则它与MOVDQA相同.

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

Esp*_*spo 136

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

当生成数据而不是(立即)再次使用数据时,内存存储操作首先读取完整的高速缓存行然后修改高速缓存的数据这一事实对性能是有害的.此操作将数据从缓存中推出,这可能需要再次使用,以支持不会很快使用的数据.对于大型数据结构(如矩阵)尤其如此,这些数据结构经过填充后再使用.在填充矩阵的最后一个元素之前,绝对大小驱逐第一个元素,使得写入的缓存无效.

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

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

  • 很好的答案,我只想指出在具有NT指令的处理器类型上,即使使用非非时间指令(即正常指令),行缓存也不会"读取然后修改".对于写入不在高速缓存中的行的正常指令,在高速缓存中保留一行,并且掩码指示该行的哪些部分是最新的.这个网页称它为"商店没有摊位":http://www.ptlsim.org/Documentation/html/node30.html.我找不到更精确的参考资料,我只是从那些工作是实现处理器模拟器的人那里听说过这个. (13认同)
  • 实际上http://www.ptlsim.org/是一个关于周期精确的处理器模拟器的网站,与那些告诉我"商店没有停顿"的人正在做的事情完全相同.如果他们看到这个评论我也最好提一下:http://unisim.org/ (2认同)
  • @SergeRogatch 这取决于您所谈论的场景,但是是的,在某些场景中,NT 商店需要 `sfence`,而普通商店从来不需要它。NT 存储不是相对于其他存储(NT 与否)排序的,_如其他线程所见_,没有 `sfence`。但是,对于从执行存储的同一线程中读取的内容,您永远不需要 `sfence`:一个给定的线程将始终按照程序顺序查看自己的存储,无论它们是否是 NT 存储。 (2认同)

Pra*_*mod 36

Espo对目标非常感兴趣.只是想加我的两分钱:

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

我对使用缓存控制指令的手动编码程序集持怀疑态度.根据我的经验,这些东西导致比任何有效的性能提升更多的邪恶错误.

  • 毫无疑问,知识渊博的低级程序员可以胜过小内核的编译器.这对于发表论文和博客文章非常有用,我已经完成了这两项工作.它们也是很好的教学工具,有助于理解"真正"发生的事情.根据我的经验,在实践中,如果你有一个真正的系统,许多程序员正在研究它,正确性和可维护性很重要,低级编码的好处几乎总是被风险所抵消. (4认同)
  • 不应该利用问题域,算法或应用程序的已知局部性(或缺乏局部性)。避免缓存污染确实是一项非常有吸引力且有效的优化任务。另外,为什么不喜欢装配呢?编译器无法利用大量机会获得收益 (3认同)
  • @Pramod,相同的论点很容易概括为最优化,而实际上不在讨论范围之内-显然,鉴于我们已经在谈论非时间指令,因此已经考虑了折衷或以其他方式认为不相关 (3认同)

chu*_*hus 9

根据 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内存的减少污染的负载

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

使用非临时提示将源操作数(第二个操作数)中的压缩整数移动到目标操作数(第一个操作数),以防止在写入内存期间缓存数据。

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

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

最后,回顾John McAlpin 关于非临时存储的注释可能会很有趣。

  • SSE4.1 `MOVNTDQA` 只对 WC(不可缓存的写入组合)内存区域执行任何特殊操作,例如视频 RAM。它在当前硬件上的普通 WB(回写)内存上根本没有用,NT 提示被忽略,并且完全强序加载语义适用。不过,`prefetchnta` 可以用作从 WB 内存中减少污染*减少*负载。[当前的 x86 架构是否支持非临时加载(来自“正常”内存)?](/sf/ask/2806782611/)。 (4认同)
  • 没错,NT 存储在 WB 内存上运行良好,并且是弱排序的,通常是*写入*大内存区域的不错选择。但 NT 负载不是。纸上的 x86 手册允许 NT 提示为来自 WB 内存的负载做一些事情,但在当前的 CPU 中它*什么都不做*。(可能是因为没有支持 NT 的硬件预取器。) (2认同)
  • @LewisKelsey:NT *stores* 确实会覆盖内存类型。这就是为什么它们可以在 WB 内存上弱排序的原因。主要效果是避免 RFO(显然它们会发送无效消息,甚至在到达内存时清除其他脏行)。它们也可以乱序可见,因此它们不必等到较早的缓存未命中(常规)存储提交之后,或者直到较早的缓存未命中 *load* 获取数据。即在[在多处理器系统中每个内核外的内存在概念上是否总是平坦/统一/同步?](//stackoverflow.com/q/56268226)中询问的瓶颈类型。 (2认同)