我是否更愿意使用一次内存访问来进行读写?

时间:2012-01-26 15:53:12

标签: performance optimization memory matrix blas

众所周知,以一种跨步方式访问内存最适合性能。

的情况下
  • 我必须访问一个内存区域才能阅读,
  • 我必须访问另一个地区进行写作,
  • 我只能以一种大步的方式访问这两个地区中的一个,

我应该更喜欢阅读一个步骤还是写一个步幅?

一个简单,具体的例子是类似BLAS的复制和置换操作,如y := P x。置换矩阵P完全由一些置换向量q(i)定义。它具有相应的逆置换向量qinv(i)。可以将所需的循环编码为y[qinv(i)] = x[i]y[i]=x[q(i)],其中前者从x读取一个,后者写入y一步。

理想情况下,人们总是可以编码两种可能性,在代表性条件下对其进行分析,并选择更快的版本。假设您只能编写一个版本 - 根据现代内存架构的行为,您总是期望哪种访问模式更快?在线程环境中工作是否会改变您的响应?

2 个答案:

答案 0 :(得分:6)

您命名为“写一个跨步”(y[i]=x[q(i)])的访问模式通常更快。

如果内存被缓存且数据块小于缓存行,则此访问模式需要较少的内存带宽。

现代处理器通常拥有比存储单元更多的加载执行单元。下一个名为Haswell的英特尔架构仅支持GATHER指令,而SCATTER尚未纳入其计划。所有这些都支持“写一步”模式。

在线程环境中工作不会改变这种情况。

答案 1 :(得分:1)

我想分享我的简单基准测试的结果。假设我们有两个NxN的{​​{1}}和A的两个正方形B矩阵,并且我们希望通过转置来执行复制:

double

算法:

  1. 两个嵌套循环,使得读取是连续的,而写入则是跨步的。
  2. 两个嵌套循环,使读跨大步,写连续。
  3. 顺序MKL的A = transpose(B)

不进行转置的副本用作基准。将mkl_domatcopy的值设为N,以减轻缓存的关联性影响。

具有GCC 8.3.0(2^K + 1)和英特尔MKL 2019.0.1的英特尔酷睿i7-4770:

Intel Core i7-4770

具有GCC 7.3.0(-O3 -m64 -march=native)和英特尔MKL 2017.0.1的英特尔至强E5-2650 v3:

Intel Xeon E5-2650 v3

Numbers and C++ source code