有谁有_mm256_stream_load_si256(非临时加载绕过缓存)实际上提高性能的示例吗?

zx-*_*-81 5 performance x86 hpc cpu-architecture avx

考虑对大量浮点数据(数百 GB)进行大规模 SIMD 矢量化循环,理论上,这些数据应该受益于非时间(“流”,即绕过缓存)加载/存储。

使用非临时存储 (_mm256_stream_ps) 实际上确实比普通存储 (_mm256_store_ps) 显着提高了约 25% 的吞吐量

但是,当使用 _mm256_stream_load 而不是 _mm256_load_ps 时,我无法测量到任何差异。

有谁有一个可以使用 _mm256_stream_load_si256 来实际提高性能的示例?

(指令集和硬件是 AMD Zen2 上的 AVX2,64 核)

for(size_t i=0; i < 1000000000/*larger than L3 cache-size*/; i+=8 )
{
  #ifdef USE_STREAM_LOAD
  __m256 a = _mm256_castsi256_ps (_mm256_stream_load_si256((__m256i *)source+i));
  #else
  __m256 a = _mm256_load_ps( source+i );
  #endif

   a *= a;

  #ifdef USE_STREAM_STORE
  _mm256_stream_ps (destination+i, a);
  #else
  _mm256_store_ps (destination+i, a);
  #endif
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*des 9

stream_load( vmovntdqa) 只是正常加载的较慢版本(额外的 ALU uop),除非您在 WC 内存区域(不可缓存、写组合)上使用它。

\n

当前 CPU 会忽略非时间提示,因为与 NT 存储不同,该指令不会覆盖内存排序语义。我们知道这在 Intel CPU 上是正确的,并且您的测试结果表明在 AMD 上也是如此。

\n

其目的是从视频 RAM 复制回主内存,如英特尔白皮书中所述。除非您从某种不可缓存的设备内存中进行复制,否则它是无用的。(在当前的 CPU 上)。

\n

另请参见MOVDQA 和 MOVNTDQA 以及 WB/WC 标记区域的 VMOVDQA 和 VMOVNTDQ 之间有什么区别?更多细节。正如我的回答所指出的,如果针对您的硬件和工作负载进行仔细调整,NT预取有时会有所帮助,以减少缓存污染。但是调整预取距离是相当脆弱的;太远了,当您读取数据时,数据将被完全驱逐,而不是仅仅丢失 L1 并命中 L2。

\n

无论如何,带宽增益不会有太多。普通存储在每个缓存行的逐出时花费一次读取和最终写入。读取所有权 (RFO) 是高速缓存一致性所必需的,也是因为回写式高速缓存的工作方式仅跟踪整行的脏状态。NT 存储可以通过避免这些负载来增加带宽。

\n

但是普通加载不会浪费任何东西,唯一的缺点是,如果您无法更改算法以具有任何局部性,那么当您循环遍历巨大的数组时,会产生大量缓存未命中,从而驱逐其他数据。

\n
\n

如果您的算法可以实现缓存阻塞,那么您可以从中获得更多好处,因此您不仅仅会成为 DRAM 带宽的瓶颈。例如,对数据的子集执行多个步骤,然后继续下一步。

\n

另请参阅\xe2\x80\x98每位程序员应该了解的内存\xe2\x80\x99 有多少仍然有效?- 大部分;去读一下 Ulrich Drepper 的论文吧。

\n

任何可以增加计算强度的方法都会有所帮助(每次将数据加载到 L1d 缓存或寄存器中时,ALU 都会工作)。

\n

更好的是,创建一个自定义循环,结合您要对每个元素执行的多个步骤。避免诸如for(i) A[i] = sqrt(B[i])是否有较早或较晚的步骤也对同一数组的每个元素执行简单操作之类的事情。

\n

如果您正在使用 NumPy 或其他东西,并且只是将在大型数组上运行的优化构建块粘合在一起,那么您可能会遇到低计算强度算法的内存带宽瓶颈(例如 STREAM add 或三合会类型的事物)。

\n

如果您将 C 与内在函数一起使用,那么您应该设定更高的目标。您可能仍然存在内存带宽瓶颈,但您的目标应该是使 ALU 饱和,或者至少是 L2 缓存带宽瓶颈。

\n

有时这很困难,或者您还没有抽出时间来进行您能想到的 TODO 列表上的所有优化,因此如果没有任何东西会随时重新读取此数据,NT 存储可能有利于内存带宽很快。但请考虑这是失败的标志,而不是成功的标志。 CPU 有大量快速缓存,请使用它们。

\n
\n

进一步阅读:

\n
    \n
  • memcpy 的增强型 REP MOVSB - RFO 与无 RFO 存储(包括 NT 存储),以及在给定将缓存线移交给较低级别​​的延迟和 LFB 数量的情况下,如何将每核内存带宽限制为延迟带宽乘积来追踪他们。尤其是在英特尔服务器芯片上。

    \n
  • \n
  • 非临时加载和硬件预取器,它们可以一起工作吗?- 不,NT 加载仅在 WC 内存上有用,其中硬件预取不起作用。它们的存在就是为了填补这一空白。

    \n
  • \n
\n

  • @zx-81:干杯。发完这篇文章后,我意识到我还有更多话要说;查看我的更新。 (2认同)
  • @zx-81:很高兴听到你不需要关于提高计算强度的解释,但希望它能让一些未来的读者受益。 (2认同)
  • @zx-81:谢谢,是的,这正是我的目标。:) 如今,其他一些人写了一些足够技术性的 CPU 架构答案(尽管 BeeOnRope 在 SO 上不再非常活跃),但是大部分旧的性能相关问题都有非常笼统的答案,如果细节经常错误,存在于所有。多年来,我已经能够改进一些,并用好东西支持一些现有的旧答案。 (2认同)

归档时间:

查看次数:

617 次

最近记录:

3 年,1 月 前