加速浮点数5x5矩阵*使用SSE的向量乘法

问题描述 投票:12回答:8

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

  1. 我担心算术运算的数量与所涉及的存储器运算的数量相比太少。您认为我可以得到一些明显的改善(例如> 20%)吗?

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

  3. 您能指出一些参考吗?

c++ vectorization matrix-multiplication sse simd
8个回答
9
投票

用于向量,矩阵等的Eigen C ++模板库同时具有

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

  • 使用SSE优化的优化代码

所以您应该尝试一下。


4
投票

[如果使用的是GCC,请注意-O3选项将启用自动矢量化,在许多情况下,它将自动生成SSE或AVX指令。通常,如果只是将其编写为简单的for循环,则GCC会将其向量化。有关更多信息,请参见http://gcc.gnu.org/projects/tree-ssa/vectorization.html


4
投票

原则上,使用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,使用SSE的速度应接近16倍(假设有四个物理内核)。我认为这是使用SSE最好的方法。
编辑:由于指令级并行性(ILP),您可以在加速方面获得另外2倍的结果,因此,使用四核(64x AVX)可以使SSE的加速达到32倍,而由于FMA3,Haswell的获得2倍。

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

这应该很容易,尤其是在使用Core 2或更高版本时:您需要5 * _mm_dp_ps,一个_mm_mul_ps,两个_mm_add_ps,一个普通的乘法,以及一些随机播放,装入和存储(如果矩阵是固定的,如果不需要它们,您可以将其大部分保留在SSE寄存器中。]

关于内存带宽:当内存带宽以一位数千兆字节/秒为单位时,我们谈论的是2.4兆字节的向量。

有关该载体的知识是什么?由于矩阵是固定的,并且如果向量可以接受的值数量有限,那么我建议您预先计算并使用表查找来访问它们。

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

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

[如果您确实想自己实现某些功能,则在某些情况下,使用(可用)SSE..SSE4AVX指令集可以显着提高性能,尽管这正是一个良好的BLAS库所要做的。您还需要考虑很多有关缓存友好的数据访问模式的问题。

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

希望这会有所帮助。

[如果您事先知道矢量(例如一次完成所有240k的操作),则通过并行化循环比使用SSE可获得更快的加速。如果您已经采取了这一步骤,或者您一次也不了解它们,那么SSE可能会带来很大的好处。

如果内存是连续的,则不必过多担心内存操作。如果您有一个链表或其他内容,那么您会遇到麻烦,但是它应该能够保持正常运行而不会造成太大问题。

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


3
投票
[我建议使用英特尔®IPP并抽象出对技术的依赖

2
投票
这应该很容易,尤其是在使用Core 2或更高版本时:您需要5 * _mm_dp_ps,一个_mm_mul_ps,两个_mm_add_ps,一个普通的乘法,以及一些随机播放,装入和存储(如果矩阵是固定的,如果不需要它们,您可以将其大部分保留在SSE寄存器中。]

1
投票
有关该载体的知识是什么?由于矩阵是固定的,并且如果向量可以接受的值数量有限,那么我建议您预先计算并使用表查找来访问它们。

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

0
投票
[如果您事先知道矢量(例如一次完成所有240k的操作),则通过并行化循环比使用SSE可获得更快的加速。如果您已经采取了这一步骤,或者您一次也不了解它们,那么SSE可能会带来很大的好处。
© www.soinside.com 2019 - 2024. All rights reserved.