13

我需要每秒运行 240000 次矩阵向量乘法。矩阵是 5x5 并且始终相同,而向量在每次迭代时都会发生变化。数据类型是float。我正在考虑使用一些 SSE(或类似)指令。

  1. 我担心算术运算的数量与所涉及的内存操作的数量相比太少了。你认为我能得到一些切实的(例如> 20%)改进吗?

  2. 我需要英特尔编译器吗?

  3. 你能指出一些参考资料吗?

4

8 回答 8

9

向量、矩阵等的Eigen C++ 模板库...

  • 针对小型固定大小矩阵(以及动态大小的矩阵)的优化代码

  • 使用 SSE 优化的优化代码

所以你应该试一试。

于 2011-07-07T22:17:04.307 回答
5

原则上,SSE 的加速可以是 4 倍(AVX 是 8 倍)。让我解释。

让我们称您的固定 5x5 矩阵M。将 5D 向量的分量定义为 (x,y,z,w,t)。现在从前四个向量 形成一个 5x4 矩阵U。

U =
xxxx
yyyy
zzzz
wwww
tttt

接下来,做矩阵乘积MU = V。矩阵V包含M和前四个向量的乘积。唯一的问题是,对于 SSE,我们需要读取U的行,但在内存中U存储为xyzwtxyzwtxyzwtxyzwt,因此我们必须将其转置为xxxxyyyyzzzzwwwwtttt。这可以通过 SSE 中的洗牌/混合来完成。一旦我们有了这种格式,矩阵乘积就非常有效。

而不是使用标量代码进行 O(5x5x4) 操作,它只需要 O(5x5) 操作,即 4 倍加速。使用 AVX,矩阵U将是 5x8,因此它不需要 O(5x5x8) 操作,它只需要 O(5x5),即 8 倍加速。

然而,矩阵V将采用xxxxyyyyzzzzwwwwtttt格式,因此根据应用程序,它可能必须转换为xyzwtxyzwtxyzwtxyzwt格式。

对接下来的四个向量(AVX 为 8 个)重复此操作,依此类推,直到完成。

如果您可以控制向量,例如,如果您的应用程序动态生成向量,那么您可以以xxxxyyyyzzzzwwwwtttt格式生成它们并避免数组的转置。在这种情况下,您应该使用 SSE 获得 4 倍的加速,使用 AVX 获得 8 倍的加速。如果您将其与线程(例如 OpenMP)结合使用,您的加速应该接近 16 倍(假设四个物理内核)与 SSE。我认为这是你可以用 SSE 做的最好的事情。

编辑:由于指令级并行性(ILP),您可以获得另一个 2 倍的加速,因此 SSE 的加速可以通过四个内核(64x AVX)提高 32 倍,并且由于 FMA3,Haswell 的加速可以再次提高 2 倍。

于 2013-03-17T16:59:44.390 回答
4

我建议使用英特尔 IPP 并抽象出对技术的依赖

于 2011-07-07T22:23:01.163 回答
4

如果您使用 GCC,请注意 -O3 选项将启用自动矢量化,这将在许多情况下自动生成 SSE 或 AVX 指令。一般来说,如果你只是把它写成一个简单的 for 循环,GCC 会将它向量化。有关更多信息,请参阅http://gcc.gnu.org/projects/tree-ssa/vectorization.html

于 2011-07-08T01:04:47.893 回答
2

这应该很容易,尤其是当您使用 Core 2 或更高版本时:您需要 5* _mm_dp_ps、 one _mm_mul_ps、 two _mm_add_ps、 one 普通乘法,以及一些随机播放、加载和存储(如果矩阵是固定的,您可以保留大部分在 SSE 寄存器中,如果您不需要它们用于其他任何事情)。

至于内存带宽:我们说的是 2.4 MB 的向量,而内存带宽是每秒个位数千兆字节。

于 2011-07-07T23:38:14.283 回答
1

对向量有什么了解?由于矩阵是固定的,并且如果向量可以采用的值数量有限,那么我建议您预先计算计算并使用表格查找来访问它们。

用内存换周期的经典优化技术...

于 2011-07-07T22:24:36.310 回答
0

我建议查看优化的 BLAS 库,例如 Intel MKL 或 AMD ACML。根据您的描述,我假设您将在SGEMV2 级矩阵向量例程之后进行y = A*x样式操作。

如果你真的想自己实现一些东西,使用(可用的)SSE..SSE4AVX指令集可以在某些情况下提供显着的性能改进,尽管这正是一个好的 BLAS 库要做的事情。您还需要仔细考虑缓存友好的数据访问模式。

我不知道这是否适用于您的情况,但是您可以一次对向量的“块”进行操作吗?因此,y = A*x您可以对[y1 y2 ... yn] = A * [x1 x2 ... xn]. 如果是这样,这意味着您可以使用优化的矩阵矩阵例程,例如SGEMM. 由于数据访问模式,这可能比重复调用更有效SGEMV。如果是我,我会尝试走这条路……

希望这可以帮助。

于 2011-07-07T22:41:55.243 回答
0

如果您事先知道向量(例如,一次完成所有 240k),那么通过并行化循环比通过 SSE 获得更好的加速。如果您已经迈出了这一步,或者您不是一下子了解所有这些,那么 SSE 可能会带来很大的好处。

如果内存是连续的,那么不要太担心内存操作。如果你有一个链表或其他东西,那么你就有麻烦了,但它应该能够跟上而没有太多问题。

5x5 是一个有趣的大小,但您可以在一条 SSE 指令中至少执行 4 次翻转,并尝试减少算术开销。您不需要英特尔编译器,但它可能会更好,我听说过关于它如何使用算术代码更好的传说。Visual Studio 具有处理 SSE2 的内在函数,我认为最多 SSE4 取决于您的需要。当然,你必须自己滚动它。抓住图书馆可能是这里的明智之举。

于 2011-07-07T22:45:27.233 回答